Bundle.main.path forResource will return nil in a MacOS screen saver

May 3, 2020, 5:10 am

I thought it might be worth writing a quick post on something that had me stuck building a screen saver for MacOS in Swift.

If you have a file you include in your build target (like a SQLite database of map tiles) and need to open that file you might try something like this:

let stringPath: String? = Bundle.main.path(forResource: "satellite-lowres-v1.2-z0-z5", ofType: "mbtiles")

Because I am debugging my application in a regular MacOS app (that just shows my ScreenSaverView) this code worked fine when I was debugging. As soon as I built and deployed the actual screen saver bundle everything broke.

So at that point you might spend quite a bit of time trying to debug entirely unrelated tile loading code before realising that bundle.main.path forResource was returning nil, but only in the screen saver application.

The reasons for this is that MacOS screen savers are bundles loaded by the system screen saver application, so the path you get will be something like:

/Applications/System Preferences.app/Contents/Resources

So to get this to work (in both the test app and the screen saver app) you need to get the bundle via a class in that bundle:

let stringPath: String? = Bundle(for: type(of: self)).path(forResource: "satellite-lowres-v1.2-z0-z5", ofType: "mbtiles")

I am just using the ScreenSaverView class which works fine.

This all took a little longer than it should have to find because, this being my first MacOS app, I wasn't sure where debug logging was ending up. Turns out it all appears in the Mac Console application ("Console" in Spotlight). I also struggled a bit because the Console app, or something in the MacOS logging framework was making decisions about the sensitivity of variables I was logging. So logging something like this:

os_log("Location was ---> %s", stringPath ?? "We got nil for our stringPath")

Ends up in the logs like this "Location was ---> " which isn't very helpful. To tell the logging framework that you want to see those variables you can supply it to the format string:

os_log("Location was ---> %{public}s", stringPath ?? "We got nil for our stringPath")

Permalink - Comments - Tags: Development, Swift

All This Started Four Years Ago - By a Special Correspondent

March 8, 2019, 9:53 pm

This article by "A Special Correspondent" was in my grandfather's papers, along with other letters written at the time on what I believe is the same typewriter (something I'd love to be able to confirm). I haven't been able to find this text elsewhere so I am publishing it here.

Chilling given the recent resurgence of Nationalist rhetoric.

Late in the afternoon on Friday, 11th March, 1938, I was listening in to my radio in Vienna, waiting for a speech by one of the political leaders in Austria on the occasion of the plebiscite which Dr. Schuschnigg, chancellor of Austria, had ordered to be held on the following Sunday. The Austrian people were called upon to decide whether they wanted to remain independent, or become part of Nazi Germany.

While I was wondering why the speech did not start at the appointed time, the radio speaker suddenly said: "The chancellor, Dr. Schuschnigg, is going to make an important announcement. Then I heard Schuschnigg's voice through the loudspeaker, saying "The German Government have requested my Government to cancel the plebiscite which we had decided to hold the day after to-morrow, and to hand over the Government of Austria to nominees of the German Government. Failing this, the German Government would order German troops ready for that purpose to cross the Austrian border at 8 p.m. to-night. According to reports received, German troops are already on Austrian soil. As our troops are far inferior in numbers and equipment to the invading forces, I have, in order to avoid needless bloodshed, ordered our troops not to resist, and tendered my and my Government's resignation to the President. God save Austria!"

I shall never forget Haydn's variations on the Austrian National Anthem that were played after this. Then the announcer introduced the new chancellor of Austria, Seiss-Inquardt, an Austrian, the first of the long line of men whom we have become used to call Quislings for their betrayal of their own country to the Nazis. Yet, Quisling won his doubtful fame long after Seiss-Inquardt had committed the same infamy.

The world knows now that Hitler resorted to his first act of using military force against another country because he had to prevent at all costs the plebiscite in Austria, which would have plainly shown what a big majority of the Austrian population was opposed to the Anschluss. It also has been revealed in the meantime that he had by no means been certain of the success of his threats, and that a firm stand by the western powers by Austria's side would have prevented the occupation of the country. When at that time I made up my mind immediately to leave Austria and go to Australia, it was because of the certain knowledge that the events of those days were the start of an avalanche from which you could expect to be safe only in the place farthest away. Yet, with all my pessimism at that time I - and probably nobody - would not have imagined that only four years later even the great Australia, 13000 miles distant would be threatened similarly.

It is strange and interesting to think how many things - apart from the names - were similar in Australia and Austria. Like Australia, Austria was a federation of states, and there was a federal government and parliament as well as state governments and parliaments. The same problems of overpopulated cities with many unemployed, and lack of farm labour in the country existed. Austria, like Australia, had gone through a terrific depression after the last war. The Austrian population was reputed in Europe for friendliness and a free and easy way of life. When they saw the pest of Nazism developing in the neighbouring country of Germany, on a stone's throw over the border (oh God, why the stone to destroy the monster never thrown?), they also used to say: "It can't happen here!"

The way it did happen might possibly teach us a lesson. In Austria there existed great political differences between the various groups of the population, just like elsewhere. This, accompanied by lack of restraint on the part of the elected representatives of the people in the various legislative bodies, weakness of the government because of a very small majority in the parliament and different political tendencies of various state governments, paralysed public life to a great extend and led to widespread distrust in politicians. The Nazis made clever use of these conditions. Their propaganda against "politicians" made the ordinary man believe that he could do better without any of them, forgetting the fact that a country with democratic institutions, even if the politicians are not the best, is infinitely better of than one without any, but Nazi chiefs instead. The Nazi methods of propaganda were most interesting to watch. They posed as Austrian super-patriots, with Austria first and everything else only a long way afterwards The Nazi methods of propaganda were most interesting to watch. They posed as Austrian super-patriots, with Austria first and everything else only a long way afterwards. The of course thundered against all sorts of "isms", parliamentarism, capitalism, socialism, communism, against democracy and British and Jewish world domination. Those poor Jewish refugees from Germany in 1933 to 1937 who had believed to find a haven of security in Austria were their special targets. And for the small man it was so immensely relieving to be told that all his every-day troubles were only due to one or several of those isms, and particularly to the Jews and the refugees; with himself, he heard, there was never anything wrong whatsoever; he was of Aryan descent, and that alone made him ever so far superior to anyone else. It was cleverly done, and many simpletons fell for it.

To-day, only four years after all this happened on the other side of the world, we in Australia are confronted by similar dangers. It might not be inappropriate to look back and try to guard against mistakes that led to the start of all this four years ago.

Permalink - Comments - Tags: World War Two,Misc

Aggregate deeply nested JSONField data in Django

October 24, 2018, 6:19 am

I ran across this problem the other day and it seems there aren't useful answers on this particular issue.

A combination of Django and Postgres makes it very easy to persist JSON data in your models. I think generally when building an application data schema storing JSON data is usually a bad idea. In fact this post and its partial solution is an example of issues you can have expecting JSON fields to behave predictably (in ORM terms).

In this case I wanted to store responses from a third party API and didn't think I would need to query data in those responses (hence no formal schema for the values within). Of course a requirement eventuated that required querying and then aggregation on values in the JSON I was storing and that is where I hit the problem described below.

(N.B. As I write this, with some hindsight, I think the correct solution is actually to migrate the values out of the JSON and store them in dedicated fields in the model, but anyway).

So if you want to filter by deeply nested values in a JSONField that part is fine. It actually works nicely with query_set syntax that matches doing joins across reverse relationships or foreign keys.

class ThingResponse(TimeStampedModel):
user = models.ForeignKey(User, on_delete=models.PROTECT, related_name="thing_responses")
    data = JSONField(_('The actual response from thing'))

If an example data looks like:

{
  "house": {
    "name": "Lannister",
    "seat": "Casterly Rock",
    "scion": "Tywin",
    "heir": "Jaime",
    "chapter_introduced": 5
  },
  "name" : "Tyrion Lannister",
  "age" : 24
}

and you want to find all the Lannisters, you could write a queryset like this:

ThingResponse.objects.filter(data__house__name="Lannister")

Things get tricky when you want to aggregate data in the JSONField. Aggregating on a value at the top level is fine (as described in this SO answer):

from django.db.models.functions import Cast
from django.db.models import Min, IntegerField
from django.contrib.postgres.fields.jsonb import KeyTextTransform

ThingResponse.objects.annotate(age_value=Cast(KeyTextTransform('age', 'data'), IntegerField())).aggregate(Min('age_value'))

You can annotate the queryset with nested values by nesting the KeyTextTransform like this:

ThingResponse.objects.annotate(chapter=Cast(KeyTextTransform('chapter_introduced', KeyTextTransform('house', 'data')), IntegerField()))

So this works fine and will annotate your result with a 'chapter' property with the nested value in it. Problem happens when you try and aggregate on that nested value:

ThingResponse.objects.annotate(chapter=Cast(KeyTextTransform('chapter_introduced', KeyTextTransform('house', 'data')), IntegerField())).aggregate(Min('chapter_introduced'))

You'll get an error like this:

File "[env path]/lib/python3.6/site-packages/django/db/models/sql/compiler.py", line 128, in get_group_by if (sql, tuple(params)) not in seen: TypeError: unhashable type: 'list'

I think what is happening here is the KeyTextTransform hasn't been resolved by this time so instead of a value it is getting a list of arguments.

So this is as far as I got with this and ended up implementing the aggregation in memory. If you do have a similar issue and find a solution to the issue with aggregating on nested JSON values I would love to hear from you.

Permalink - Comments - Tags: Development

Writing Great Fiction - Lecture Three Exercise

September 17, 2018, 12:32 pm

The writing for this lecture was to take the styles in the following three novels and apply them to a passage from the others:

  • - The Great Gatsby - First person account.
  • - Mrs Dalloway - Third person stream of consciousness.
  • - The Maltese Falcon - Third person, literal observation.
My first attempt was to re-write this Great Gatsby scene using something like the third person stream of consciousness from Mrs Dalloway.

Original Scene

“Now, don’t think my opinion on these matters is final,” he seemed to say, “just because I’m stronger and more of a man than you are.” We were in the same senior society, and while we were never intimate I always had the impression that he approved of me and wanted me to like him with some harsh, defiant wistfulness of his own.

We talked for a few minutes on the sunny porch.

“I’ve got a nice place here,” he said, his eyes flashing about restlessly.

Turning me around by one arm, he moved a broad flat hand along the front vista, including in its sweep a sunken Italian garden, a half acre of deep, pungent roses, and a snub-nosed motor-boat that bumped the tide offshore.

“It belonged to Demaine, the oil man.” He turned me around again, politely and abruptly. “We’ll go inside.”

My Version

“I’ve got a nice place here,” Tom said as his eyes enumerated each feature of garden, lawn and shore, pleased how the magnificent view was presented in the afternoon glow. He liked to impress his guests, but wondered at his eagerness for the admiration of this particular man. Nick was unimpressive in almost every way, at least in Tom's estimation, and yet he found he valued his company, perhaps even his friendship?

Nick watched the restless display with some comprehension and allowed himself to be guided, not impolitely, though certainly forcefully, through a conversation on the virtues of Tom's domain.

Tom, satisfied he had established his preemminance, abruptly turned and guided the two of them inside.

"It belonged to Demaine, the oil man." Tom said before passing into the high ceilinged hallway. Nick assumed he should know who that was and nodded.

My second attempt was taking the third person stream of consciousness of Mrs Dalloway and attempting the impersonal third person literal style from the Maltese Falcon:

Original Scene

She would have been, in the first place, dark like Lady Bexborough, with a skin of crumpled leather and beautiful eyes. She would have been, like Lady Bexborough, slow and stately; rather large; interested in politics like a man; with a country house; very dignified, very sincere. Instead of which she had a narrow pea-stick figure; a ridiculous little face, beaked like a bird's. That she held herself well was true; and had nice hands and feet; and dressed well, considering that she spent little. But often now this body she wore (she stopped to look at a Dutch picture), this body, with all its capacities, seemed nothing--nothing at all. She had the oddest sense of being herself invisible; unseen; unknown; there being no more marrying, no more having of children now, but only this astonishing and rather solemn progress with the rest of them, up Bond Street, this being Mrs. Dalloway; not even Clarissa any more; this being Mrs. Richard Dalloway.

Bond Street fascinated her; Bond Street early in the morning in the season; its flags flying; its shops; no splash; no glitter; one roll of tweed in the shop where her father had bought his suits for fifty years; a few pearls; salmon on an iceblock.

"That is all," she said, looking at the fishmonger's. "That is all," she repeated, pausing for a moment at the window of a glove shop where, before the War, you could buy almost perfect gloves. And her old Uncle William used to say a lady is known by her shoes and her gloves. He had turned on his bed one morning in the middle of the War. He had said, "I have had enough." Gloves and shoes; she had a passion for gloves; but her own daughter, her Elizabeth, cared not a straw for either of them.

Not a straw, she thought, going on up Bond Street to a shop where they kept flowers for her when she gave a party. Elizabeth really cared for her dog most of all.

My Version

A thin, dignified woman moved from shopfront to shopfront along Bond Street. The grandure of the flags that adorned each was not reflected in the shops themselves. The lady, for that is clearly what she was, upright and deliberate as she moved up the street, considered a roll of tailor's tweed as she passed. Despite her careful manner she was clearly enjoying herself, her pointed face moving quickly to take in each modest display.

Glancing from the fishmongers, with its forlone salmon presented on a block of ice, towards a glove shop. She paused and looked, slightly wistful, on the pitiful spread of gloves, much diminished after four years of war. Her composure seemed to slip and she muttered to herself 'That is all ... that is all', barely audible over the noise of the street.

Permalink - Comments - Tags: Stories

Writing Great Fiction - Lecture Two Exercise

September 9, 2018, 9:38 am

Lecture two from Writing Great Fiction: Storytelling Tips and Techniques is about evocation.

Based on an exercise from John Gardner's The Art of Fiction we are supposed to write a passage describing a building, a landscape or an object from the point of view of a parent who's child has just died. All you're allowed to do is describe the object without mentioning the child, the parent or death. Invoke the feeling of loss and grief without mentioning either.

After a couple of abortive tries where I eventually mentioned one or all, I came up with this:

The swingset was tiny. Much too small for an adult. The worn rubber seat had two leg holes and a pink plastic strap across the front. The purple metal frame was faded and chipped, but you could still make out capering, grinning figures along its length. Under the seat was a muddy puddle, the center of a trail of scuff marks. Footprints staggered and skipped at the edge of the puddle and into the dust beyond. A gust of wind rippled the water and the hinges squeaked as the rubber harness twisted slowly. The wind died and there was silence.

Exercise from Lecture Three >>

Permalink - Comments - Tags: Stories