<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Blog - Binary Sky</title><description/><link>https://binarysky.se/</link><language>en-us</language><item><title>Why is the app slow on Pixel 7?</title><link>https://binarysky.se/blog/2026/01/why-is-the-app-slow-on-pixel-7/</link><guid isPermaLink="true">https://binarysky.se/blog/2026/01/why-is-the-app-slow-on-pixel-7/</guid><pubDate>Mon, 26 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;So a collegue comes over to me one day to ask what changes we did since the last release, reason being: &quot;The app is very slow on Pixel 7 running on &lt;em&gt;&amp;lt;cloud-based emulator service&amp;gt;&lt;/em&gt;&quot;.&lt;/p&gt;
&lt;p&gt;As I, too, am &lt;a href=&quot;https://www.seangoedecke.com/addicted-to-being-useful/&quot;&gt;addicted to being useful&lt;/a&gt;, I get curious and sympathetic to their call for help. I suggest we should try a debug build instead to get a profile trace. But instead, we get... a crash? Cannot locate symbol &lt;code&gt;_ZTVNSt6__ndk118basic_stringstreamIcNS_11char_traitsIcEENS_9allocatorIcEEEE&lt;/code&gt; in &lt;code&gt;libc++_shared.so&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;After a while of looking through the logs and trying bumping different versions without having any effect on the issue we read something at the start of the log that really has been staring us in the face this whole time... the emulator is running on x86_64.  Suddenly a lot of things start to click. The emulated &quot;Pixel 7&quot; device isn&apos;t really anything like the actual physical device. Now we have some actual technical reason that could begin to give an explanation to the symptoms of the bug.&lt;/p&gt;
&lt;p&gt;Looking into the actual APK file, we can see that the only provided .so files are for ARM-v7 and ARM64. This is because we recently worked on optimizing the APK file size and removed support for architectures other than ARM. So I figured all problems would be solved by just re-enabling x86, but no luck - the crash was still there even though we now have included specific libs for x86_64. Maybe there was some difference between them? But regardless from all this: &lt;strong&gt;how did the app even launch at all if the native files for the architecture was missing?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Together with Claude we made a shell script that inspects the symbol table inside &lt;code&gt;libc++_shared.so&lt;/code&gt; artifacts and searches for the specific symbol name that was missing. All intermediary files matche, but some of our vendors provide prebuilt &lt;code&gt;.so&lt;/code&gt; files inside of  &lt;code&gt;.aar&lt;/code&gt; (Android library archives) files - let&apos;s check those as well... And &lt;em&gt;bingo&lt;/em&gt;, we finally found where the outdated &lt;code&gt;libc++_shared.so&lt;/code&gt; file comes from!&lt;/p&gt;
&lt;p&gt;During the APK assembly step, there can only be one of each native artifacts, and for reasons unbeknownst to man, gradle consistently picks the prebuilt one that is outdated instead of using any of the freshly built ones. I didn&apos;t have any luck configuring gradle to skip this one or to prefer any other artifact, and another teammate informed me that our vendor fixed this in a later release by letting us providing &lt;code&gt;libc++_shared.so&lt;/code&gt; and not embedding it within the archive.&lt;/p&gt;
&lt;p&gt;So finally we are back to debugging the original issue, the slowness. But when we start the app again, not only is there no crash at startup — the app is fast! &lt;em&gt;...what?&lt;/em&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Somewhere in this debugging rabbit hole we actually solved the original bug? This is where we go though and cherry-pick all the changes one by one to a new branch, and it turns out that the relevant change was... enabling x86_64 support?&lt;/p&gt;
&lt;p&gt;Claude helped me to connect the dots, I gave it all the symptoms and details of the debugging session this was the short answer:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Android emulators use ARM-to-x86 translation technology (sometimes referred to as libhoudini in the community) that allows ARM apps to run on x86 hardware, though with &lt;strong&gt;significant performance overhead&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Finally we had a solution to both and which also answered how the app even worked on x86 to begin with: &lt;em&gt;The app was emulated through an additional translation layer&lt;/em&gt;. I also found &lt;a href=&quot;https://android-developers.googleblog.com/2020/03/run-arm-apps-on-android-emulator.html&quot;&gt;this blogpost by Google&lt;/a&gt; that mentions this being a thing.&lt;/p&gt;
&lt;p&gt;All in all, sometimes it really pays off to dive deep into issues that only happens on an esoteric configuration of a Pixel 7 device. I learned a lot on this journey where what seemed to be a bug was actually a feature.&lt;/p&gt;
</content:encoded></item><item><title>My Advent of Code in Roc 2023</title><link>https://binarysky.se/blog/2024/02/my-advent-of-code-in-roc-2023/</link><guid isPermaLink="true">https://binarysky.se/blog/2024/02/my-advent-of-code-in-roc-2023/</guid><pubDate>Fri, 02 Feb 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It starts like it always does. Everything is fun and games before they hit you with the algorithm-heavy days. And then you can&apos;t muster up the strength to keep up anymore. And then you give up. But I still mostly scraped by until day 20 (skipping 14 and 17, which I keep telling myself &lt;em&gt;I will get back to anytime&lt;/em&gt; before next December).&lt;/p&gt;
&lt;p&gt;At least my language of choice gave me an interesting extra challenge of solving the task in a way that the compiler likes. I.e. doesn&apos;t panic or crash without giving any output. — Jokes aside, as December went on I learned the tricks to work around the compiler bugs and crashes, and I’m sure the Roc language developers got a fair share of bugs to squash until next year.&lt;/p&gt;
&lt;h2&gt;Recursive mindset&lt;/h2&gt;
&lt;p&gt;Roc doesn&apos;t even have iterative loop constructs like &lt;code&gt;for&lt;/code&gt; or &lt;code&gt;while&lt;/code&gt;, instead it relies on recursion, which can be a bit getting used to. But Roc promises the same benefits in terms of runtime performance and memory usage using a combination of different strategies — sometimes the compiler can just replace the recursive call with a loop, and in more advanced cases you are encouraged to use tail-recursion. The upside of being forced into thinking in terms of recursive algorithms is that they can sometimes be a bit easier to understand and implement when reading Wikipedia’s pseudocode.&lt;/p&gt;
&lt;p&gt;Aside from recursion, I also learned a bunch of useful stuff, like the &lt;a href=&quot;https://en.wikipedia.org/wiki/Shoelace_formula&quot;&gt;Shoelace formula&lt;/a&gt;, which calculates the total area of a polygon from the set of points, &lt;a href=&quot;https://en.wikipedia.org/wiki/Karger%27s_algorithm&quot;&gt;Karger&apos;s algorithm&lt;/a&gt;, which can be used to &quot;min-cut&quot; a graph, and of course our old pal Dijkstra made some appearances.&lt;/p&gt;
&lt;h1&gt;What’s next?&lt;/h1&gt;
&lt;p&gt;Roc is implemented in part with Zig which piqued my interest and I would enjoy investigating it further, but in another project.&lt;/p&gt;
&lt;p&gt;My month of Roc got me into making a (slow as molasses) &lt;a href=&quot;https://github.com/lindskogen/roc-raytracer&quot;&gt;Ray tracing renderer&lt;/a&gt; while following along the &lt;a href=&quot;https://raytracing.github.io/books/RayTracingInOneWeekend.html&quot;&gt;Ray tracing in one weekend&lt;/a&gt; e-book. Both &lt;a href=&quot;https://youtube.com/playlist?list=PLlrATfBNZ98edc5GshdBtREv5asFW3yXl&quot;&gt;The Cherno&lt;/a&gt; and &lt;a href=&quot;https://youtu.be/Qz0KTGYJtUk&quot;&gt;Sebastian Lague&lt;/a&gt; were great resources along the way with great visualizations to help further my understanding. Maybe I should try making a renderer using Ray marching next?&lt;/p&gt;
&lt;p&gt;I just finished my third week as an independent consultant, and next week I&apos;m going skiing which right now feels like a much-needed break from everything.&lt;/p&gt;
</content:encoded></item><item><title>Val.town</title><link>https://binarysky.se/blog/2023/11/val-town/</link><guid isPermaLink="true">https://binarysky.se/blog/2023/11/val-town/</guid><pubDate>Thu, 30 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you&apos;re like me, you&apos;ve probably run into the case that you need to run &lt;em&gt;scripts&lt;/em&gt; every week, day or every hour. Maybe you want to monitor the daily scoreboard of Advent of Code. Maybe you want to post the status of the Strava running challenge to a Slack channel each week.&lt;/p&gt;
&lt;p&gt;I found &lt;a href=&quot;https://www.val.town/&quot;&gt;val.town&lt;/a&gt; on hacker news some time ago and have since ported all my &lt;em&gt;scripts&lt;/em&gt; to use it.&lt;/p&gt;
&lt;p&gt;In this post I have collected some example use-cases:&lt;/p&gt;
&lt;h2&gt;Monitor Advent of Code score board&lt;/h2&gt;
&lt;p&gt;Every day in December (at 12, to give everyone a chance to solve the puzzle), we post the scoreboard to the &lt;code&gt;#aoc&lt;/code&gt; work Slack channel. First there is the time challenge - and later the total stars.&lt;/p&gt;
&lt;p&gt;Advent of Code does provide an API which just requires cookie authentication. - Easily achiveable with val.town.&lt;/p&gt;
&lt;h2&gt;Summarize the Strava challenge&lt;/h2&gt;
&lt;p&gt;Every week, we post the current leaderboard of the local running group to a Slack channel.&lt;/p&gt;
&lt;p&gt;This is slightly more involved, since Strava does not provide an API anymore. We have to scrape the website and parse the HTML to provide a plaintext representation of the current standing.&lt;/p&gt;
&lt;p&gt;This integration also needs to store state, since we want to know if someone has improved their score since last week.&lt;/p&gt;
&lt;p&gt;Val.town provides a simple key-value store which can be used for this.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { blob } from &quot;https://esm.town/v/std/blob?v=3&quot;;

await blob.setJSON(&quot;stateExample1&quot;, { foo: &quot;bar&quot; });

await blob.getJSON(&quot;stateExample1&quot;);
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Find available online booking times&lt;/h2&gt;
&lt;p&gt;It all started when I got a gift card from my parents for a barber shop. -- I wanted to book an appointment, but no times were available for the next 2 months.&lt;/p&gt;
&lt;p&gt;Using the browser devtools I inspected the JSON API and wrote a &lt;em&gt;script&lt;/em&gt; that calls the API every hour, and send a push notification to my phone when an earlier time would appear.&lt;/p&gt;
&lt;p&gt;I ended up getting a time in about a week.&lt;/p&gt;
</content:encoded></item><item><title>Advent of Code 2023!</title><link>https://binarysky.se/blog/2023/11/advent-of-code/</link><guid isPermaLink="true">https://binarysky.se/blog/2023/11/advent-of-code/</guid><pubDate>Fri, 24 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It&apos;s almost time! Just one week left to Dec 1st: &lt;a href=&quot;https://adventofcode.com/2023&quot;&gt;adventofcode.com/2023&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My goal this year is to learn a new programming language, if not only because then I can put the blame on something else when I inevitably crash and burn somewhere around day 15 given my current track record:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;2015      12
2016      10
2017      11
2018       8
2019      10
2020      22
2021      15
2022      22
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can follow me along on GitHub where I will be posting my solutions: &lt;a href=&quot;https://github.com/lindskogen/advent-of-code-2023&quot;&gt;lindskogen/advent-of-code-2023&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;For myself, I haven&apos;t decided what language to use yet, but I usually go with &lt;a href=&quot;https://www.rust-lang.org/&quot;&gt;Rust&lt;/a&gt; or &lt;a href=&quot;https://kotlinlang.org/&quot;&gt;Kotlin&lt;/a&gt;. But this year I might try something else, like &lt;a href=&quot;https://gleam.run/&quot;&gt;Gleam&lt;/a&gt; or &lt;a href=&quot;https://roc-lang.org/&quot;&gt;Roc&lt;/a&gt;. Both of them are functional languages and I find that the functional style of programming is well suited for AoC.&lt;/p&gt;
&lt;h2&gt;Gleam&lt;/h2&gt;
&lt;p&gt;The main selling point of Gleam — as well as Elixir — is making the Erlang VM + Ecosystem accessible to more users and without them having to learn the &lt;em&gt;absolute travesty&lt;/em&gt; that is the Erlang syntax.&lt;/p&gt;
&lt;p&gt;I&apos;ve had some time to play around with Gleam and the syntax is a bit verbose but it&apos;s not too bad. It&apos;s also similar to Rust, which I like.&lt;/p&gt;
&lt;h2&gt;Roc&lt;/h2&gt;
&lt;p&gt;I appreciate languages that try to make them accessible for beginners. The prime example of this is Elm. Roc claims to do the same and I&apos;m excited to try it out! It&apos;s a bit intimidating to learn all the new syntax but I enjoy exploring new ways of thinking about programming.&lt;/p&gt;
&lt;p&gt;Roc is more in the vein of Haskell, and like Haskell, it handles arbitrarily large integers out of the box. Sometimes that gives you an edge in the AoC puzzles.&lt;/p&gt;
&lt;p&gt;There also seems to be a story for &quot;async in Roc&quot; from the start. I feel that this is almost a requirement for new languages these days, since most applications needs to call out to external systems or do some other async task.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; For anyone else looking to try Roc for AoC, &lt;a href=&quot;https://twitter.com/rtfeldman&quot;&gt;@rtfeldman&lt;/a&gt; posted a guide here: &lt;a href=&quot;https://gist.github.com/rtfeldman/f48c9a9f557f71db7728d9e7322fa4c5&quot;&gt;Link to GitHub Gist&lt;/a&gt;&lt;/p&gt;
</content:encoded></item><item><title>CSS Grid – force columns to be the same width</title><link>https://binarysky.se/blog/2023/11/css-grid-force-columns-same-width/</link><guid isPermaLink="true">https://binarysky.se/blog/2023/11/css-grid-force-columns-same-width/</guid><pubDate>Mon, 20 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We used to do a lot of column-based layouts at work — which I implemented with CSS Grid.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example can be customized to any number of columns by changing the &lt;code&gt;3&lt;/code&gt; in &lt;code&gt;repeat(3, 1fr)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;All was fine initially, but designers complained of inconsistent column widths on certain screen sizes.&lt;/p&gt;
&lt;p&gt;After some research, I stumbled over &lt;a href=&quot;https://stackoverflow.com/a/61240964/823725&quot;&gt;this solution&lt;/a&gt; and it works great!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As stated in the answer, the &lt;code&gt;minmax(0, 1fr)&lt;/code&gt; function makes the columns be between &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1fr&lt;/code&gt; and forces the columns to be the same width.&lt;/p&gt;
&lt;h2&gt;Bonus tip!&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;----------------------
|      |      |      |
|      |      |      |
|      |      |      |
----------------------
|      |      |      |
|      |      |      |
|      |      |      |
----------------------
|      |      |      |
|      |      |      |
|      |      |      |
----------------------

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For a grid that needs single-pixel borders between the columns and/or rows, you can use the &lt;code&gt;gap&lt;/code&gt; property together with &lt;code&gt;background-color&lt;/code&gt; and it will keep working even if wrapping occurs.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background-color: black;
}

.grid &amp;gt; * {
  background-color: white;
}
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item><item><title>Today I quit my job and started working as an independent consultant</title><link>https://binarysky.se/blog/2023/11/today-i-quit-my-job-and-started-working-as-an-independent-consultant/</link><guid isPermaLink="true">https://binarysky.se/blog/2023/11/today-i-quit-my-job-and-started-working-as-an-independent-consultant/</guid><pubDate>Tue, 14 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Many old colleagues wished me luck with my future plans.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I cooked!&lt;/em&gt; Today I made &lt;a href=&quot;https://www.ica.se/recept/korvstroganoff-med-ris-533512/&quot;&gt;Korv stroganoff&lt;/a&gt; — it is one of my favorite dishes and I like to keep improving my cooking skills.&lt;/p&gt;
&lt;p&gt;We also did some budgeting to make sure that we could pay rent and survive for the months I wouldn&apos;t get any salary.&lt;/p&gt;
&lt;p&gt;Also, I did something probably many other people did this week — I switched my coding font to a &lt;a href=&quot;https://monaspace.githubnext.com/&quot;&gt;Monaspace&lt;/a&gt; variant. For my editor I used Neon, and for a bit of fun, I used Argon for iTerm.&lt;/p&gt;
&lt;h2&gt;TWIL&lt;/h2&gt;
&lt;p&gt;If you want to pack up an entire git repository (just the staged and committed files) as a zip file, you can use the following command:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;git archive -o output.zip HEAD
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Apparently, you are allowed to put &lt;code&gt;@media&lt;/code&gt;-queries inside svg style elements. Combine this with the &lt;code&gt;prefers-color-scheme&lt;/code&gt; media query and you can make svgs with built-in support for dark mode!&lt;/p&gt;
&lt;p&gt;Very useful for text!&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;svg viewBox=&quot;0 0 100 100&quot;&amp;gt;
  &amp;lt;style&amp;gt;
    @media (prefers-color-scheme: dark) {
      circle {
        fill: white;
      }
    }
  &amp;lt;/style&amp;gt;
  &amp;lt;circle cx=&quot;50&quot; cy=&quot;50&quot; r=&quot;40&quot; /&amp;gt;
&amp;lt;/svg&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And it even works inside img tags: &lt;code&gt;&amp;lt;img src=&quot;icon.svg&quot;/&amp;gt;&lt;/code&gt;!&lt;/p&gt;
</content:encoded></item><item><title>GraphQL Subscriptions with Apollo Supergraph</title><link>https://binarysky.se/blog/2023/11/graphql-subscriptions-with-apollo-supergraph/</link><guid isPermaLink="true">https://binarysky.se/blog/2023/11/graphql-subscriptions-with-apollo-supergraph/</guid><pubDate>Fri, 10 Nov 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Together with a colleague, I set up an Apollo Supergraph that includes support for GQL subscriptions.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;graph TD
    A[Gateway &amp;amp; Websocket Proxy] --&amp;gt; HTTP --&amp;gt; B(GraphQL Server)
    A --&amp;gt; WebSocket --&amp;gt; C(Subscriptions Server)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Details of the supergraph&lt;/h2&gt;
&lt;p&gt;We put the old GraphQL server and the subscriptions server behind the gateway server, and then we set up a WebSocket proxy server to proxy the connections to the subscriptions server.&lt;/p&gt;
&lt;p&gt;This is the base of the gateway server:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import { ApolloServer } from &quot;@apollo/server&quot;;
import { ApolloGateway } from &quot;@apollo/gateway&quot;;
import { createServer } from &quot;http&quot;;
import express from &quot;express&quot;;
import { createServer as createProxy } from &quot;http-proxy&quot;;

const proxy = createProxy({
  target: &quot;ws://localhost:4002/subscriptions&quot;,
  ws: true,
  changeOrigin: true,
});

const app = express();
const httpServer = createServer(app);

const supergraphSdl = new IntrospectAndCompose({
  subgraphs: [
    {
      name: &quot;gql&quot;,
      url: &quot;http://localhost:4001/graphql&quot;,
    },
    {
      name: &quot;sub&quot;,
      url: &quot;http://localhost:4002/graphql&quot;,
    },
  ],
});

const gateway = new ApolloGateway({
  supergraphSdl,
});

const server = new ApolloServer({
  gateway,
});

httpServer.on(&quot;upgrade&quot;, (req, socket, head) =&amp;gt; {
  proxy.ws(req, socket, head);
});

httpServer.listen(4000, () =&amp;gt; {
  console.log(`🚀 Server ready at http://localhost:4000/graphql`);
});
&lt;/code&gt;&lt;/pre&gt;
</content:encoded></item></channel></rss>