How does one programmatically delete a preference from the NSGlobalDomain? - swift

This is a simple task from the terminal:
defaults delete -g <key>
I'd like to do this in Swift using NSUserDefaults. The documentation says:
If you want to change the value of a preference in the global domain, write that same preference to the application domain with the new value.
This simply sets a new value for the same key in the application domain so that when NSUserDefaults retrieves the value for the key in the future, it will find the new value in the application domain before it searches the global domain.
Is there some way to either:
delete the key from the NSGlobalDomain, or
set a new value for the key in NSGlobalDomain
using NSUserDefaults?
I know I can use NSTask, for example, to run defaults delete -g <key>, but I consider that a workaround (a valid one).

You can try this, but it's not really a good idea:
var defaults = NSUserDefaults.standardUserDefaults()
var globalDomain = defaults.persistentDomainForName(NSGlobalDomain)
globalDomain.removeObjectForKey(someKey)
defaults.setPersistentDomain(globalDomain, forName:NSGlobalDomain)
The main problem is a race condition with other processes or threads. If something changes the global domain between the time you read it and when you write it back, you undo those changes, even if they didn't involve the key you were manipulating. Also, you're potentially reading and writing a large dictionary, doing a lot more work than actually necessary.
Probably better to drop down to the CFPreferences API:
CFPreferencesSetValue(someKey, nil, kCFPreferencesAnyApplication,
kCFPreferencesCurrentUser, kCFPreferencesCurrentHost)

Related

Gatling session variable gets overwritten for multiple users. How to fix this?

So i am an absolute newbie to gatling and the documentation on their site is pretty meh. My scenario is that i have different users which execute one scenario each and during these scenarios they make requests and save the answer in a session variable which they need as a parameter for a following request during the same scenario. My problem is that i have multiple users running at the same time and these overwrite the session variable so that a user which started earlier refers to the wrong value in the session variable. my idea was to set up a global counter which increments as soon as a new user is initialized and starts with his scenario and to append this counter to the session variable. is this possible and if so how do i do it? i bet there is a way better way to fix this behaviour but as i said i have zero experience with gatling and how its working.
my users look like this
user("singleUpload")
.behavior {
feed(applicationCredentials)
.exec(USingleUpload.singleUpload)
the scenarios like this
val singleUpload = exec(RUpload.post)
.exec(RShare.get)
.exec(RDownload.get)
.doIfEquals("${attachmentSingleUpload}", "attachment.jpg") {
exec(RThumbnailDownload.get)
}
.doIfEquals("${attachmentSingleUpload}", "attachment.png") {
exec(RThumbnailDownload.get)
}
.exec(RDelete.delete)
and the request like this:
val attachment = ("attachment", "${attachmentSingleUpload}")
val post = http("RUpload")
.post("/attachment/upload/")
.queryParam("share", "true")
.formUpload("attachment", s"attachments/${attachment._2}")
.header("x-api-key", "${apiKey}")
.header("x-app-id", "${appId}")
.check(status.is(200))
.check(jsonPath("$..pkey").exists.saveAs("pkey"))
val get = http("RShare")
.get("/attachment/share")
.queryParam("pkey", "${pkey}")
.header("x-api-key", "${apiKey}")
.header("x-app-id", "${appId}")
.check(status.is(200))
.check(jsonPath("$..skey").exists.saveAs("skey"))
for example: i make an upload and save the pkey which i then use in the request to get an skey. if user #2 is fast enough with his upload to overwritter the pkey variable in the session then user #1 uses a wrong pkey in his request.
user("singleUpload")
.behavior {
There's neither user nor behavior methods in Gatling's API. If you really have this in your code, these are private customizations. Can't say what they do or if they're correct.
My problem is that i have multiple users running at the same time and these overwrite the session variable so that a user which started earlier refers to the wrong value in the session variable.
if user #2 is fast enough with his upload to overwritter the pkey variable in the session then user #1 uses a wrong pkey in his request.
This is absolutely impossible. Each virtual user has its own Session, isolated from the others'. You cannot store something in a given virtual user's Session and have another virtual user overwrite it. And there's absolutely zero chance of a bug in there.
I recommend that you reconsider how you came to this erroneous conclusion and investigate other possible explanations. This small piece you provided looks correct. Maybe you've simply uncovered a bug in your application and Gatling is just the messenger.
"the documentation on their site is pretty meh"
That's neither nice nor constructive. Maybe explaining what you think is lacking in the documentation? Have you gone through all of it? Have you checked the online courses?
Gatling sessions are isolated so overwritting is not really possible.
I am using saveAs in many simulations without any problems. The issue is somewhere else.

Azure DevOps - Can we reuse the value of a key in the same variable group?

I have lots of URL values and their keys. But there is no way to batch import the variables and the "value" controls are also not text boxes in the Variables Group page to perform chrome browser extensions assisted find and replace.
If this is possible, what is the syntax to refer to the key?
As in, I have a variable App.URL : www.contoso.com.
I am using the key to substitute value in my next variable like this Login.URL : $(App.URL)\Login and this doesn't work.
GitHub link : https://github.com/MicrosoftDocs/vsts-docs/issues/3902#issuecomment-489694654
This isn't currently available, not sure if it will be. Can you create a task early in your pipeline that sets the variables you need in subsequent tasks/steps? This gives you more control as you can store the script along with your source. You could then use a pipeline variable for the environment you're in and let your script use that to set values appropriately.
See Set variables in scripts in the MS docs.
If it's not possible to re-architect your app to concatenate the url strings in the application, what the previous commenter said about creating a simple script to do that for you would be the way to go. Ie:
#!/bin/bash
#full login url
fullLoginUrl=$APP.URL\$LOGINSUFFIX
echo "##vso[task.setvariable variable=Login.URL]$fullLoginUrl
Otherwise, perhaps playing around with the run time vs compile time variables in YAML pipelines might be worth trying.
https://learn.microsoft.com/en-us/azure/devops/pipelines/process/variables?view=azure-devops&tabs=yaml%2Cbatch#understand-variable-syntax

Swift - How to modify file metadata like kMDItemDisplayName?

I'm trying to find a way to change a file's metadata attributes (those with the prefix of "kMDItem", listed by mdls), but I didn't find any solution for it. ToT
At first, I've tried using FileManager.default.setAttributes(_attributes:ofItemAtPath:), but this method only gives me few options, it only gives me ability to modify a file's modification date, creation date and posix permissions etc., which is not enough.
Then, I tried using NSMetadataItem with setValue(_value:forKey:) function to change the metadata value, this is my code:
var attributes = NSMetadataItem(url: URL(fileURLWithPath: "/path/to/file")
if let metadata = attributes {
metadata.setValue(newValue, forKey: kMDItemDisplayName as String)
metadata.setValue(newValue, forKey: NSMetadataItemDisplayNameKey)
// I've tried both of them from above (different keys), they both does not work at all
}
I noticed that setValue(_value:forKey:) does not do anything here by repeatedly getting this returning error: error: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0).
Finally, I red this post on StackOverflow, which led my way to this code:
_ = setxattr("/path/to/file".cString(using: .utf8), "kMDItemDisplayName", newValue.cString(using: .utf8), newValue.lengthOfBytes(using: .utf8), 0, 0)
After executing it, I used mdls and xattr -l to check the result, I realized that this is only the solution for adding extended attributes to a file, the metadata didn't change, only the extended attribute with the name of "kMDItemDisplayName" is successfully added.
The result is not what I want (I'm just using kMDItemDisplayName as an example for my question), I do not just want to find a way to add extended attributes to a file, but a way to edit the attributes listed by mdls. Maybe there is no solution for this? Or maybe I should do it in a completely different way?
Not all metadata can be changed. Much of it is not stored directly, it's derived or computed based on other metadata.
The display name for a simple file is derived from its name on disk and the system settings, like whether extensions are hidden or shown. The display name for a bundle (like an app) is slightly more complicated, but, assuming you don't find changing the contents of the bundle (which would break its code signature) acceptable, amounts to the same thing. Those are subject to the system language(s).
There are also certain folders whose names can be localized for display, but that's still based on their on-disk name.
So, to change a file's display name, change its actual name on disk.
For other properties, you can look at URL.setResourceValues(_:) and URLResourceValues to see which properties are settable. You can also look at URLResourceKey to see which are documented as "read-write".

Parametrized forms in Yesod

I'm trying to create a pair of forms in a (scaffolded) Yesod setup where:
form 1 allows a user to choose a file. That file is parsed into a set of records and then the user is given
form 2 which has a selectFieldList for choosing a record.
So I have
form2::[(Text,Record)]->Form Record
form2 recordInfo = ...
which is fine for when I generate it (generateFormPost $ form2 recordInfo) . But to process the result, I will be in a different handler and I no longer have the list of (Text,Record) pairs to give to the form2 function in order to execute runFormPost (runFormPost $ form2 ??). So I can't get the data from the form.
I realize this is a consequence of the statelessness of the RESTful web. And I realize there are some ways out of this. I could use persistent and hand some sort of key to the handler so it knows where to get the (Text,Record) data. Or I could use session somehow? Or cookies?
This web stuff is new to me so before I launch in a silly direction, I was wondering if there is a simple answer I am missing and, if not, what is the "right" way to handle forms that depend on dynamic data in this way?

Zend Lucene with symfony and i18n

I've went through the Jobeet Tutorial for integrating Zend Lucene into a symfony (1.4.8) project in order to add search capabilities into my frontend of my site (through indexing). Among others, the key concept is to use updateLuceneIndex during model's save action (needs to be overridden) in order to create/update the index of the specific entry.
My model has i18n fields, some of which (i,e name, title) I want to be inserted in the index. Everything works as expected but when it comes to save the i18n fields into the index all I get is blank values ($this->getName() returns empty string). I'm inspecting the created index with the Luke.
I ended up that this has nothing to do with the Zend Lucene but with symfony. It seems that during save the information for i18n fields isn't available (or is it?). I've also tried hook up the update during preSave(), postSave() but no avail.
So I want to ask how am I supposed to get my model's i18n field values during the save action in order to update the index accordingly?
Important note: This happens only during doctrine:data-load task. If I manually insert or update a record the index gets updated accordingly.
One last related question. It would be nice if I could save different keywords for each of the languages of the field of the model. How can I get the different values for each field's language inside the model?
The reason of this strange behaviour of Symfony is that when you are loading fixtures via cli, it has no context loaded (for instance when you try to get context instance sfContext::getInstance(), youll get "context instance does not exists" error exception).
With no context instance available, there is no "current culture" and with no current culture, there is no value of i18n fields.
The symfony context actualy supports all I18N functionalities with current User culture ($currentUserCulture = sfContext::getInstance()->getUser->getCulture()).
This all means 2 things:
You cant use symfony "current user culture" capabilities while you are
in cli session
If you needs to have sfContext::getInstance() somewhere in your
code (especialy in the models), you have to close it into condition to avoid any troubles with unexpected and hard to find exceptions while in cli
Example of getting current culture in model class (it will not pass condition while in cli):
if (sfContext::hasInstance()) {
sfContext::getInstance()->getUser()->getCulture();
}
So when you cant use Symfony i18n shortcuts (like $record->getName()), you have to work around it.
In Your symfony1-doctrine models you always have $this->Translation object available.
So you can access your translation values object via something like $this->Translation[$culture].
Its up to you to work with that, you can use your default culture $this->Translation[sfConfig::get('sf_default_culture')], or interate trough all your supported cultures from some global configuration (i recommends you to set it in one of your configuration files globaly accross of all apps - maybe /config/app.yml).
Example of getting $record Translation object in any situations:
if (sfContext::hasInstance()) {
$translation = $this->Translation[sfContext::getInstance()->getUser()->getCulture()];
}
else {
$translation = $this->Translation->getFirst();
// or: $translation = $this->Translation[$yourPreferedCulture];
}
// you can access to modified fields of translation object
$translationModified = $translation->getModified();