{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "Taylor&#39;s Notes",
  "language": "en",
  "home_page_url": "https://eth0fox.net/notes",
  "feed_url": "https://eth0fox.net/notes/feed.json",
  "description": "",
  "authors": [
    {
      "name": "Taylor",
      "url": "mailto:fox@boxfox.es"
    }
  ],
  "items": [
    {
      "id": "https://eth0fox.net/notes/2026-04-06-objc-js/",
      "url": "https://eth0fox.net/notes/2026-04-06-objc-js/",
      "title": "Apple, apparently, lets you write macOS ObjC code in JavaScript.",
      "content_html": "<p>I like JavaScript (well, TypeScript, but close enough), and I have primarily been using macOS for about 10 years at this point, and as someone who has a penchant for writing the most cursed &amp; evil code possible, I have had multiple attempts to interact with macOS' native APIs from JavaScript. Now, being on macOS makes this interesting, because of ObjC (which to clarify, I use to refer to the runtime &amp; C API exposed by <code>libobjc.dylib</code>, not the Objective-C language it is intended to be used with), which allows almost all APIs on the system to be interfaced with with only a handful of C functions, primarily <a href=\"https://developer.apple.com/documentation/objectivec/objc_msgsend\"><code>objc_msgSend</code></a>, which is what Objective-C's... distinctive <code>[]</code> notation is actually syntactic sugar for. The only problem is that a bunch of FFI implementations in JS have bad support for things like varargs, and there wasn't really a good way to write a abstraction layer that let you use different ones without having to touch the code of the library, so after not being able to get much further than displaying a single empty window, those projects got shelved.</p>\n<p>Another interesting thing about macOS, is <a href=\"https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/HowMacScriptingWorks.html\">AppleScript and the OSA</a>, which for the uninitiated, the Open Scripting Architecture (OSA) is a standard that macOS applications can adopt to expose an interface so that other applications &amp; scripts can retrieve information from &amp; perform actions in those apps, with AppleScript being a &quot;natural language&quot; (or as much of that as you can expect for a language introduced in 1993) programming language that allows you to write scripts to interface with OSA supporting applications. It is a really nice idea which, like a lot of the nice things about macOS, I don't think any modern developer would implement if they were building the OS today, and as such almost any app that doesn't have a lineage that dates back at least 10 years is almost guaranteed to have absolutely no support.</p>\n<p>Problem is, as someone who's used to modern, C-like programming languages, AppleScript is not exactly familliar. No worries though, in OS X 10.10 (2014), Apple introduced JavaScript for Automation (JXA, where the 'X' came from, I have no idea.), which allowed you to harness the OSA with a more modern, actively developed language, and unlike the Windows equivilent (Windows Script Host/WSH), isn't stuck in the 90's and uses the same JavaScriptCore framework thats used by the Safari web browser. But, due the lack of documentation &amp; non-standard behaviour of the OSA objects, I generally stuck with AppleScript due to it being much more documented with code samples on forums for example, or upgrading full fledged C# with it's mostly-fully-featured bindings to the macOS SDK (which are still called Xamarin in some places despite Xamarin being discontinued, and the actual package being absurdly named <code>Microsoft.macOS</code>), which combined with <a href=\"https://developer.apple.com/documentation/scriptingbridge/sbapplication?language=objc\"><code>ScriptingBridge</code></a> which provides an ObjC interface for OSA.</p>\n<h2 id=\"the-nerd-snipe-of-the-century\">The Nerd Snipe of the Century</h2>\n<p>That was, until I reread the docs today and saw this:</p>\n<blockquote>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">var</span> fileManager <span class=\"token operator\">=</span> $<span class=\"token punctuation\">.</span>NSFileManager<span class=\"token punctuation\">.</span>defaultManager\n<span class=\"token punctuation\">[</span><span class=\"token operator\">...</span><span class=\"token punctuation\">]</span>\n<span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>fileManager<span class=\"token punctuation\">.</span><span class=\"token function\">fileExistsAtPathIsDirectory</span><span class=\"token punctuation\">(</span>item<span class=\"token punctuation\">.</span><span class=\"token function\">toString</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> isDir<span class=\"token punctuation\">)</span> <span class=\"token operator\">&amp;&amp;</span> isDir<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span></code></pre>\n<p><a href=\"https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/ProcessDroppedFilesandFolders.html#//apple_ref/doc/uid/TP40016239-CH53-SW1\">Mac Automation Scripting Guide: Processing Dropped Files and Folders</a></p>\n</blockquote>\n<p>which I recognised that as looking awfully like a ObjC API. And after checking, found it matched the <a href=\"https://developer.apple.com/documentation/foundation/filemanager/fileexists(atpath:isdirectory:)?language=objc\">NSFileManager <code>fileExistsAtPath:isDirectory:</code></a> function.</p>\n<p>This was the nerdsnipe of the century.</p>\n<p>I quickly tried to find the documentation mentioning this <code>$</code> global, and found it. In the JavaScript for Automation release notes for OS X 10.10, there it was, the documentation for an <a href=\"https://developer.apple.com/library/archive/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/Articles/OSX10-10.html#//apple_ref/doc/uid/TP40014508-CH109-SW17\">Objective-C bridge</a>.</p>\n<p>When you give someone like me this information, I will immediately go to drop everything I was working on, and I <strong>MUST</strong> figure this out and spend hours trying until I do figure it out. The thing I knew I needed to figure out was display a window, and then put a web view in there, because Electron is disgustingly sensible and I must figure out ways to take the least sensible option.</p>\n<p>And after a while I figured it out. After much trial and error (mainly because trying to search for how to do anything with AppKit gives you results for SwiftUI, and when you exclude those gives you results for UIKit, which is the just-similar-enough-to-be-confusing iOS UI framework, and excluding those gives you a barren search results page with only things you've already tried).</p>\n<pre class=\"language-js\"><code class=\"language-js\">ObjC<span class=\"token punctuation\">.</span><span class=\"token function\">import</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Cocoa'</span><span class=\"token punctuation\">)</span>\nObjC<span class=\"token punctuation\">.</span><span class=\"token function\">import</span><span class=\"token punctuation\">(</span><span class=\"token string\">'WebKit'</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\">// Create a window</span>\n<span class=\"token keyword\">var</span> win <span class=\"token operator\">=</span> $<span class=\"token punctuation\">.</span>NSWindow<span class=\"token punctuation\">.</span>alloc<span class=\"token punctuation\">.</span><span class=\"token function\">initWithContentRectStyleMaskBackingDefer</span><span class=\"token punctuation\">(</span>\n\t$<span class=\"token punctuation\">.</span><span class=\"token function\">NSMakeRect</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span><span class=\"token number\">600</span><span class=\"token punctuation\">,</span><span class=\"token number\">500</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n\t$<span class=\"token punctuation\">.</span>NSWindowStyleMaskTitled <span class=\"token operator\">|</span> $<span class=\"token punctuation\">.</span>NSWindowStyleMaskClosable <span class=\"token operator\">|</span> $<span class=\"token punctuation\">.</span>NSWindowStyleMaskResizable<span class=\"token punctuation\">,</span>\n\t$<span class=\"token punctuation\">.</span>NSBackingStoreBuffered<span class=\"token punctuation\">,</span>\n\t<span class=\"token boolean\">false</span>\n<span class=\"token punctuation\">)</span>\n\n\n<span class=\"token comment\">// Create a webview</span>\n<span class=\"token keyword\">var</span> config <span class=\"token operator\">=</span> $<span class=\"token punctuation\">.</span>WKWebViewConfiguration<span class=\"token punctuation\">.</span>alloc<span class=\"token punctuation\">.</span>init<span class=\"token punctuation\">;</span>\nconfig<span class=\"token punctuation\">.</span>applicationNameForUserAgent <span class=\"token operator\">=</span> <span class=\"token string\">\"Version/26.4 Safari/605.1.15\"</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// prevents sites (like google) from assuming we're using an old crusty browser. update as needed.</span>\n<span class=\"token keyword\">var</span> webview <span class=\"token operator\">=</span> $<span class=\"token punctuation\">.</span>WKWebView<span class=\"token punctuation\">.</span>alloc<span class=\"token punctuation\">.</span><span class=\"token function\">initWithFrameConfiguration</span><span class=\"token punctuation\">(</span>win<span class=\"token punctuation\">.</span>contentView<span class=\"token punctuation\">.</span>frame<span class=\"token punctuation\">,</span> config<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\nwebview<span class=\"token punctuation\">.</span><span class=\"token function\">loadHTMLStringBaseURL</span><span class=\"token punctuation\">(</span>\n\t<span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">&lt;meta http-equiv=\"refresh\" content=\"0; url=https://google.com/\"></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">,</span> \n\t$<span class=\"token punctuation\">.</span><span class=\"token constant\">NSURL</span><span class=\"token punctuation\">.</span>alloc<span class=\"token punctuation\">.</span><span class=\"token function\">initWithString</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"about:blank\"</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token comment\">// replace the entire window content with the webview, filling the window even when resized</span>\nwin<span class=\"token punctuation\">.</span>contentView <span class=\"token operator\">=</span> webview\n\n\n<span class=\"token comment\">// Register notification handler for updating the window title</span>\nObjC<span class=\"token punctuation\">.</span><span class=\"token function\">registerSubclass</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">name</span><span class=\"token operator\">:</span> <span class=\"token string\">'TitleUpdateReciever'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">superclass</span><span class=\"token operator\">:</span> <span class=\"token string\">'NSObject'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token literal-property property\">methods</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n\t    <span class=\"token string-property property\">'observeValueForKeyPath:ofObject:change:context:'</span><span class=\"token operator\">:</span> <span class=\"token keyword\">function</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">keyPath<span class=\"token punctuation\">,</span> ofObject<span class=\"token punctuation\">,</span> change<span class=\"token punctuation\">,</span> context</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n            win<span class=\"token punctuation\">.</span>title <span class=\"token operator\">=</span> webview<span class=\"token punctuation\">.</span>title\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\nwebview<span class=\"token punctuation\">.</span><span class=\"token function\">addObserverForKeyPathOptionsContext</span><span class=\"token punctuation\">(</span>\n\t$<span class=\"token punctuation\">.</span>TitleUpdateReciever<span class=\"token punctuation\">.</span>alloc<span class=\"token punctuation\">.</span>init<span class=\"token punctuation\">,</span>\n\t<span class=\"token string\">\"title\"</span><span class=\"token punctuation\">,</span>\n\t$<span class=\"token punctuation\">.</span>NSKeyValueObservingOptionNew<span class=\"token punctuation\">,</span>\n\t<span class=\"token keyword\">null</span>\n<span class=\"token punctuation\">)</span>\n\n\n\n<span class=\"token comment\">// and finally focus the window</span>\nwin<span class=\"token punctuation\">.</span><span class=\"token function\">makeKeyAndOrderFront</span><span class=\"token punctuation\">(</span>win<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<p>Important thing to note is that if you try and run a JS app that creates a window from the script editor, it will fail due to not being on the primary thread. You need to save the script as an application (with 'Stay open after run handler' checked) and then use Cmd+Opt+R to run the application, and you have to use Cmd+Q to quit the script application first or your code won't rerun when you try to Cmd+Opt+R.</p>\n<p>Is this code amazing? No. Will some veteran OS X developer blow up my email inbox telling me how stupid I am? Maybe. (if you are said developer, maybe do get in touch, but don't be <em>too</em> harsh plskthx 🥺)</p>\n<p>But it works. And also I have spent way longer on this than I wished and I was planning to do other things (remember how I started this by actually needing to write an AppleScript for something?)</p>\n<h2 id=\"conclusion\">Conclusion</h2>\n<p>Is this useful? Maybe. You still have to keep in mind, that just because it's JavaScript, that doesn't mean it's the Web, or Node. You don't get <code>require()</code> or ES Modules. You don't get the DOM, Fetch, <code>fs.readFileSync()</code>. You have to use the functions supplied by macOS' SDK (like NSURLRequest instead of Fetch) to do anything. Which means my initial idea of allowing you to interface with OSA from Node/Deno/Bun still isn't dead. Which I am <em>oh so pleased</em> to hear.</p>\n",
      "date_published": "2026-04-06T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2026-01-07-nanokvm-update/",
      "url": "https://eth0fox.net/notes/2026-01-07-nanokvm-update/",
      "title": "Updating the Sipeed NanoKVM without internet access.",
      "content_html": "<p>A while ago I purchased one of the Sipeed NanoKVM devices, after previously using a Raspberry Pi 4 with a HDMI-CSI bridge running Pi-KVM,\nbut while the formfactor &amp; price was much nicer (I paid about £33 at the end of 2024), given that at the time atleast,\nthe software was closed source, it was slightly too cheap to be true &amp; from a company I had never heard of before<sup class=\"footnote-ref\"><a href=\"https://eth0fox.net/notes/2026-01-07-nanokvm-update/#fn1\" id=\"fnref1\">[1]</a></sup>, based in China\n(a country I'll assume you know has a less than spectacular data privacy track record), and also, the fact I'll be giving this device full,\nunattended, 24/7 access to my home server, which has access to a lot of my sensitive information, and using said device to type in my root\npassword, I decided to put it on its own VLAN with no access to the internet, because well, it doesn't need it anyway. This comes with a\nlittle bit of a problem, in that, you can't software update the thing. Now, in version 2.3.1 (the latest at time of writing), they did add\nan offline update functionality, but, that only works if you're already running 2.3.1, which would defeat the need to upgrade the thing in\nthe first place.</p>\n<h2 id=\"steps\">Steps</h2>\n<ol>\n<li>\n<p>Get https://cdn.sipeed.com/nanokvm/latest.json. Copy the <code>name</code> field, put the name field on the end of <code>https://cdn.sipeed.com/nanokvm/</code>, and download that file.</p>\n  <!-- hope they don't try and XSS me -->\n<ol>\n<li>Alternatively, just click this</li>\n</ol>\n<div id=\"sipeed_update_fetch\"><button onclick=\"fetch('https://cdn.sipeed.com/nanokvm/latest.json').then(r => r.json()).then(({name, sha512}) => document.getElementById('sipeed_update_fetch').innerHTML = `<a href='https://cdn.sipeed.com/nanokvm/${name}'>${name}</a> (SHA512: <kbd>${sha512}</kbd>)`).catch(e => alert('Sorry, error! ' + e))\">Do it for me</button> </div>\n</li>\n<li>\n<p>Optional: Validate the SHA512 sum.</p>\n<ol>\n<li><strong>*nixes:</strong> <code>openssl sha512 -binary -- nanokvm_2.3.1.tar.gz | base64</code></li>\n<li><strong>PowerShell:</strong> <code>[System.Convert]::ToBase64String(@(((Get-FileHash -Algorithm SHA512 | Select -ExpandProperty hash)  -split '([A-F0-9]{2})') | foreach-object { if ($_) {[System.Convert]::ToByte($_,16)}}))</code> (enter path when it asks, just hit enter second time)</li>\n</ol>\n</li>\n<li>\n<p>Copy the file to your NanoKVM with <code>scp Downloads/nanokvm_2.3.1.tar.gz root@NANOKVM_IP:/tmp/update.tar.gz</code> (default root password is <code>root</code>)</p>\n</li>\n<li>\n<p>Log in via SSH as root</p>\n</li>\n<li>\n<p>Run the following:</p>\n<ol>\n<li><code>rm -rf /root/old/</code> (don't worry if this fails)</li>\n<li><code>mkdir -p /root/.kvmcache; cd /root/.kvmcache</code> (make temporary directory)</li>\n<li><code>gunzip -c /tmp/update.tar.gz | tar xv</code> (unpack archive)</li>\n<li><code>mv /kvmapp/ /root/old</code> (backup old version)</li>\n<li><code>mv nanokvm_* /kvmapp</code> (install new version)</li>\n<li><code>chmod -R 755 /kvmapp</code> (set permissions)</li>\n<li><code>reboot</code></li>\n</ol>\n</li>\n</ol>\n<hr class=\"footnotes-sep\">\n<section class=\"footnotes\">\n<ol class=\"footnotes-list\">\n<li id=\"fn1\" class=\"footnote-item\"><p>FWIW: I don't think Sipeed have any malicious intent, just have limited resources &amp; are a bit careless.\nWhich isn't ideal, hanlon's razor &amp; all that, but I think they're trying to get better, even if their documentation &amp; transparency\n(ie. around the onboard microphone) has been really bad historically, and still isn't great. <a href=\"https://eth0fox.net/notes/2026-01-07-nanokvm-update/#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n",
      "date_published": "2026-01-07T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2025-02-09-bsb-hid/",
      "url": "https://eth0fox.net/notes/2025-02-09-bsb-hid/",
      "title": "Bigscreen Beyond HID Protocol",
      "content_html": "<blockquote>\n<h2 id=\"caution\">Caution!</h2>\n<p>Everything in this document was obtained through reverse engineering.\nThe information has not been reviewed by Bigscreen or any of its employees.\nIf you choose to use any of the information below, I do not accept <strong>any</strong> respnsibility.\nIf you break your expensive headset, thats on you.\nFurthermore, all the information in here was tested on <em>my</em> BSB1. There may be differences between the BSB1 and the BSB2/2e. If you would like me to look into the BSB2e, get in touch regarding getting my face scan ;)</p>\n</blockquote>\n<h2 id=\"protocol-basics\">Protocol Basics</h2>\n<p>Most of the features implemented in the BeyondHID application (the little ImGUI utility that comes with the drivers) use\nUSB HID Feature Reports with report ID 0, sent to a specific 'Beyond' USB device.</p>\n<p>All commands are sent in a 64-byte buffer, the first of which is a command ID, followed by 63-bytes of data.\nMost of which will usually be zero.</p>\n<h3 id=\"device-id\">Device ID</h3>\n<ul>\n<li><strong>Bigscreen Beyond:</strong> <code>35bd:0101</code></li>\n</ul>\n<h2 id=\"commands\">Commands</h2>\n<h3 id=\"0x26-get-serial-number\"><code>0x26</code> - Get serial number</h3>\n<p>Example: <code>26</code></p>\n<p>Response: <code>26 42 53 31 33 33 37 36 39 34 32 30 36 39</code> (ASCII: 'BS13376942069')</p>\n<h3 id=\"0x2a-get-firmware-version\"><code>0x2a</code> - Get firmware version</h3>\n<p>Example: <code>2a</code></p>\n<p>Response: <code>2a 30 2e 32 2e 32 32</code> (ASCII: '0.2.22')</p>\n<h3 id=\"0x46-set-fan-speed\"><code>0x46</code> - Set Fan Speed</h3>\n<p>Example: <code>f6 64</code> sets to 100%.</p>\n<p>Response: <code>24</code></p>\n<p>Official application does not allow setting below 0x28 (40%)</p>\n<h3 id=\"0x49-set-display-brightness\"><code>0x49</code> - Set Display Brightness</h3>\n<p>Example: <code>49 00 06</code> sets to lowest brightness.</p>\n<p>Response: <code>24</code></p>\n<p>Official application keeps values in range: 0x006 - 0x21E.</p>\n<h3 id=\"0x4c-set-led-color\"><code>0x4c</code> - Set LED Color</h3>\n<p>Example: <code>4c ff 00 ff</code> sets to <code>#ff00ff</code> (magenta)</p>\n<p>Response: <code>24</code></p>\n<h3 id=\"0x5a-get-usage-stats\"><code>0x5a</code> - Get Usage stats</h3>\n<p>Example: <code>5a 00</code> (???)\nResponse: <code>5a 7f 46</code> (???)</p>\n<p>Example: <code>5a 01</code> (get total usage time)\nResponse: <code>5a 18 01</code> (0x118 = 280 = 2800 minutes = 46h40m)</p>\n<p>Example: <code>5a 02</code> (get longest session)\nResponse: <code>5a 0e</code> (0x0e = 14 = 140 minutes, 2h20m)</p>\n<h2 id=\"notifications\">Notifications</h2>\n<h3 id=\"0x23-status-report\"><code>0x23</code> - Status report</h3>\n<p><strong>This, unlike the other commands is sent <em>automatically</em> from the headset to the PC every 5 seconds. It does not need to be requested</strong></p>\n<p>I'm not entirely sure what the output format is on this. I think it's related to the 'log.txt' file placed next to BeyondHID. Here's a few examples</p>\n<pre><code>2314000000d00000021faefc9f430038a6bc0038a6bc000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n2314000000d80000021eaefc9f430038a6bc0038a6bc000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n2314173400200000022ddfa9a34385222e420f8f3942000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n231417340808000002280fd2a34385222e42a7fd3042000000000000000000000000000000000000000000000000000000000000000000000000000000000000\n</code></pre>\n<p>The format seems to have changed over time with firmware updates. On firmware 0.3.18 it looks like this</p>\n<pre><code>23181eb43a9000000229682fa243b3ff1c4291241a42010a431b0200000000000000000000000000000000000000000000000000000000000000000000000000\n                                                  ^^ (appears to be 18 if not on head, 1b or 1c if on head)\n</code></pre>\n<h2 id=\"example-code\">Example code</h2>\n<p>Set the headset RGB LED to #FF0000 (full red)</p>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">let</span> <span class=\"token punctuation\">[</span>dev<span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> navigator<span class=\"token punctuation\">.</span>hid<span class=\"token punctuation\">.</span><span class=\"token function\">requestDevice</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token literal-property property\">filters</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n        <span class=\"token punctuation\">{</span>\n            <span class=\"token literal-property property\">vendorId</span><span class=\"token operator\">:</span> <span class=\"token number\">0x35bd</span><span class=\"token punctuation\">,</span> <span class=\"token comment\">// Bigscreen, Inc. </span>\n            <span class=\"token literal-property property\">productId</span><span class=\"token operator\">:</span> <span class=\"token number\">0x0101</span>  <span class=\"token comment\">// Beyond</span>\n        <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\nconsole<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span>dev<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">await</span> dev<span class=\"token punctuation\">.</span><span class=\"token function\">open</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">let</span> data <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Uint8Array</span><span class=\"token punctuation\">(</span><span class=\"token number\">64</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\ndata<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token number\">0x4c</span><span class=\"token punctuation\">;</span>\ndata<span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token number\">0xFF</span><span class=\"token punctuation\">;</span>\ndata<span class=\"token punctuation\">[</span><span class=\"token number\">2</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token number\">0x00</span><span class=\"token punctuation\">;</span>\ndata<span class=\"token punctuation\">[</span><span class=\"token number\">3</span><span class=\"token punctuation\">]</span> <span class=\"token operator\">=</span> <span class=\"token number\">0x00</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">await</span> dev<span class=\"token punctuation\">.</span><span class=\"token function\">sendFeatureReport</span><span class=\"token punctuation\">(</span><span class=\"token number\">0</span><span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n<h1 id=\"display-mode-switching\">Display mode switching</h1>\n<p>Switching between 90/75hz involves multiple steps, of which I've been able to figure out is:</p>\n<ul>\n<li>it changes the Lighthouse configuration of the built in Tundra Tracker. You can do this using the lighthouse_console included with SteamVR</li>\n<li>it changes the EDID passed to the PC to add an additional <code>5088x2544@75</code> display mode that becomes preferred (as the 90hz display mode is still present in the EDID)</li>\n</ul>\n<h2 id=\"example-90hz\">Example, 90hz</h2>\n<p>EDID: <code>00ffffffffffff0009273412d2040000ff200104a5000078007875aa553bb22910505400000001010101010101010101010101010101000000100000000000000000000000000000000000100000000000000000000000000000000000100000000000000000000000000000000000fc004265796f6e640a202020202020015b70207907002209141ef50a88ff0eff003f801f007f071b000e8001007e00073a029281000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008690</code></p>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"manufacturer\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Bigscreen\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"model_number\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Beyond\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"revision\"</span><span class=\"token operator\">:</span> <span class=\"token number\">0.12</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"device\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">\"eye_target_height_in_pixels\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1920</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"eye_target_width_in_pixels\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1920</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"first_eye\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"eEYE_LEFT\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"last_eye\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"eEYE_RIGHT\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"num_windows\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">[</span>...<span class=\"token punctuation\">]</span></code></pre>\n<h2 id=\"example-75hz\">Example, 75hz</h2>\n<p>EDID: <code>00ffffffffffff0009273412d2040000ff200104a5000078007875aa553bb22910505400000001010101010101010101010101010101000000100000000000000000000000000000000000100000000000000000000000000000000000100000000000000000000000000000000000fc004265796f6e640a202020202020015b702079070022092839540f88df137f003f801f00ef0917000e8001001ef50a08ff0eff003f801f007f071b000e8001007e00073a0292810008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e190</code></p>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"manufacturer\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Bigscreen\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"model_number\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Beyond\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"revision\"</span><span class=\"token operator\">:</span> <span class=\"token number\">0.12</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"device\"</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">\"eye_target_height_in_pixels\"</span><span class=\"token operator\">:</span> <span class=\"token number\">2544</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"eye_target_width_in_pixels\"</span><span class=\"token operator\">:</span> <span class=\"token number\">2544</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"first_eye\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"eEYE_LEFT\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"last_eye\"</span><span class=\"token operator\">:</span> <span class=\"token string\">\"eEYE_RIGHT\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"num_windows\"</span><span class=\"token operator\">:</span> <span class=\"token number\">1</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">[</span>...<span class=\"token punctuation\">]</span></code></pre>\n<p>See also: https://github.com/ValveSoftware/openvr/wiki/The-JSON-File-(Lighthouse-Devices)</p>\n",
      "date_published": "2025-02-09T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2024-05-05-raspberry-pi-debug-probe/",
      "url": "https://eth0fox.net/notes/2024-05-05-raspberry-pi-debug-probe/",
      "title": "Raspberry Pi Debug Probe Test Point Pinout",
      "content_html": "<h2 id=\"intro\">Intro</h2>\n<p>The <a href=\"https://www.raspberrypi.com/documentation/microcontrollers/debug-probe.html\">Raspberry Pi Debug Probe</a> is a nice little device for interfacing with UART/SWD devices through USB.\nSure, at £10 it's relatively expensive to the £4 UART probes you can get off Amazon, but those don't come with SWD, a nice little case, or a much nicer cabling situation. (though I wish they included multiple of each, so you could use UART &amp; SWD at the same time, or just leave the cables connected to a device).</p>\n<h2 id=\"test-point-pinout\">Test Point Pinout</h2>\n<p>The Debug Probe has a set of test points on the bottom and holes for a 3 pin connector connected to internal points on the board. The problem is they're not documented very well.</p>\n<p><img src=\"https://github.com/eth0fox/notes/assets/74316107/081be4cf-1d6a-4c64-809e-b92333ef6fd4\" alt=\"lrg\"></p>\n<h3 id=\"3-pin-connector\">3 pin connector</h3>\n<p>There's a unsoldered space for a 3 pin connector. From top to bottom, they're connected to:</p>\n<table>\n<thead>\n<tr>\n<th>Shape</th>\n<th>TP#</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Square</td>\n<td>23</td>\n</tr>\n<tr>\n<td>Round</td>\n<td>24</td>\n</tr>\n<tr>\n<td>Round</td>\n<td>25</td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"test-points\">Test Points</h3>\n<table>\n<thead>\n<tr>\n<th>TP#</th>\n<th>Interface</th>\n<th>GPIO</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>1</td>\n<td>Power</td>\n<td>GND</td>\n<td></td>\n</tr>\n<tr>\n<td>8</td>\n<td>Power</td>\n<td>GND</td>\n<td></td>\n</tr>\n<tr>\n<td>11</td>\n<td>Power</td>\n<td>GND</td>\n<td></td>\n</tr>\n<tr>\n<td>16</td>\n<td>Power</td>\n<td>GND</td>\n<td></td>\n</tr>\n<tr>\n<td>20</td>\n<td>Power</td>\n<td>GND</td>\n<td></td>\n</tr>\n<tr>\n<td>24</td>\n<td>Power</td>\n<td>GND</td>\n<td></td>\n</tr>\n<tr>\n<td>19</td>\n<td>Power</td>\n<td>VBUS</td>\n<td>5V (from USB)</td>\n</tr>\n<tr>\n<td>26</td>\n<td>Power</td>\n<td>IOVDD</td>\n<td>3.3V</td>\n</tr>\n<tr>\n<td>27</td>\n<td>Power</td>\n<td>DVDD</td>\n<td>1.1V</td>\n</tr>\n<tr>\n<td>2</td>\n<td>USB</td>\n<td>USB_DM</td>\n<td>USB Data -</td>\n</tr>\n<tr>\n<td>3</td>\n<td>USB</td>\n<td>USB_DP</td>\n<td>USB Data +</td>\n</tr>\n<tr>\n<td>5</td>\n<td>LED</td>\n<td>GPIO2</td>\n<td>Connected to GPIO2 via 470 resistor (for red power LED)</td>\n</tr>\n<tr>\n<td>17</td>\n<td>LED</td>\n<td>GPIO7</td>\n<td>Connected to GPIO7 via 470 resistor (for green <code>UART_RX</code> LED)</td>\n</tr>\n<tr>\n<td>18</td>\n<td>LED</td>\n<td>GPIO15</td>\n<td>Connected to GPIO15 via 470 resistor (for green <code>DAP_CONNECTED</code> LED)</td>\n</tr>\n<tr>\n<td>21</td>\n<td>LED</td>\n<td>GPIO8</td>\n<td>Connected to GPIO8 via 470 resistor (for ywllow <code>UART_TX</code> LED)</td>\n</tr>\n<tr>\n<td>22</td>\n<td>LED</td>\n<td>GPIO16</td>\n<td>Connected to GPIO16 via 470 resistor (for yellow <code>DAP_TARGET_CONNECTED</code> LED)</td>\n</tr>\n<tr>\n<td>6</td>\n<td>System</td>\n<td>QSPI_SS</td>\n<td>Connected to the BOOTSEL button, in turn, connected to QSPI_SS via 1K resistor (forces the 2040 to boot from USB)</td>\n</tr>\n<tr>\n<td>13</td>\n<td>System</td>\n<td>RUN</td>\n<td>Reset pin</td>\n</tr>\n<tr>\n<td>7</td>\n<td>UART1</td>\n<td>GPIO4</td>\n<td>UART1 TX (connected directly to U connector)</td>\n</tr>\n<tr>\n<td>9</td>\n<td>UART1</td>\n<td>GPIO5</td>\n<td>UART1 RX (connected directly to U connector). Connected via <code>74AUP1T17GW</code> to GPIO5, connected directly to GPIO6.</td>\n</tr>\n<tr>\n<td>10</td>\n<td>SWD</td>\n<td>GPIO10</td>\n<td>SWCLK (connected directly to D connector)</td>\n</tr>\n<tr>\n<td>12</td>\n<td>SWD</td>\n<td>GPIO13</td>\n<td>SWDIO (connected directly to D connector) Connected via <code>74AUP1T17GW</code> to GPIO13, connected directly to GPIO14.</td>\n</tr>\n<tr>\n<td>14</td>\n<td>SWD (probe)</td>\n<td>SWDIO</td>\n<td>for the debug probe itsself</td>\n</tr>\n<tr>\n<td>15</td>\n<td>SWD (probe)</td>\n<td>SWCLK</td>\n<td>for the debug probe itsself</td>\n</tr>\n<tr>\n<td>23</td>\n<td>GPIO</td>\n<td>GPIO0</td>\n<td></td>\n</tr>\n<tr>\n<td>25</td>\n<td>GPIO</td>\n<td>GPIO1</td>\n<td></td>\n</tr>\n</tbody>\n</table>\n",
      "date_published": "2024-05-05T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/",
      "url": "https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/",
      "title": "Uninstall the Nightowl App, now.",
      "content_html": "<h3 id=\"edit\">Edit</h3>\n<p>It seems that Apple has now revoked the app's signing certificate, meaning that the application can no longer be launched.\n<img src=\"https://github.com/eth0fox/notes/assets/74316107/6dd3f310-04f8-44bd-9a84-d81c571f51b0\" alt=\"image\"></p>\n<h2 id=\"intro\">Intro</h2>\n<p>The NightOwl application has existed since 2018 and is used to automatically switch between light/dark modes on the operating system. It is an alternative to the built in macOS automatic mode which only switches when the user steps away from the computer.</p>\n<p>However, the application has been bought out by &quot;TPE.FYI LLC&quot; in late 2022<sup class=\"footnote-ref\"><a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fn1\" id=\"fnref1\">[1]</a></sup> that forcibly joins your devices into a botnet for use of market research, without your knowledge (other than the TOS in small text on the download page) or express consent (this feature cannot be turned off, even when the app is quit). This is documented in their terms of service<sup class=\"footnote-ref\"><a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fn2\" id=\"fnref2\">[2]</a></sup>:</p>\n<blockquote>\n<p>•WHEREAS, NightOwl app enables Users to share internet traffic by modifying their device's network settings to be used as a gateway for internet traffic. Additionally, the User's device acts as a gateway for NightOwl app's Clients, including companies that specialize in web and market research, SEO, brand protection, content delivery, cybersecurity, etc.</p>\n</blockquote>\n<h2 id=\"removal\">Removal:</h2>\n<p>Run these commands in Terminal, if you have the app installed <strong>at all</strong>, even if you don't have it running.</p>\n<p>sudo killall NightOwl\nlaunchctl unload ~/Library/LaunchAgents/NightOwlUpdater.plist\nsudo killall AutoUpdate\nsudo rm -rf /Applications/NightOwl.app/ ~/Library/LaunchAgents/NightOwlUpdater.plist\nsudo zsh -c &quot;rm /Users/*/Library/LaunchAgents/NightOwlUpdater.plist&quot;</p>\n<h2 id=\"technical-details\">Technical Details</h2>\n<p>The application, on install registers a launch agent named <code>org.nightowl.autoupdater.com</code><sup class=\"footnote-ref\"><a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fn3\" id=\"fnref3\">[3]</a></sup>. This is used to daemonize the process <code>/Applications/NightOwl.app/Contents/Helpers/AutoUpdate</code>, which runs as root, at boot, and cannot be disabled through the application. This happens silently, without the users knowledge or consent other than the following notice<sup class=\"footnote-ref\"><a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fn4\" id=\"fnref4\">[4]</a></sup></p>\n<blockquote>\n<p>In order to <strong>improve the App</strong>, NightOwl uses <strong>Google Analytics</strong> to collect Statistics. The tracked data helps to enhance NightOwl by analysing how <strong>features</strong> are used and which <strong>bugs</strong> appear.<br>\nWe initialize Google Analytics with the setting &quot;anonymizeIp&quot;. This guarantees <strong>anonymized data collection</strong> by masking the last part of your IP address.<br>\nYou are able to <strong>Opt-out</strong> of the tracking by <strong>unchecking &quot;Send Statistics&quot;</strong> in the <strong>settings</strong> section of NightOwl.</p>\n</blockquote>\n<p>Turning off send statistics does not disable the launch agent.</p>\n<p>The 'autoupdater' does three things,</p>\n<ul>\n<li>check the app for updates (using Sparkle)</li>\n<li>report any crashes (using Sentry)</li>\n<li>start a local HTTP proxy on port <code>40701</code> (this can be changed using the configuration json file in the app bundle).</li>\n</ul>\n<p>The latter is of course, not to be expected of any app on the machine, especially not one that just claims to be an auto updater.</p>\n<p>The daemon uses 'sudo' to switch from running as the root user, to the main user account, and then starts an instance of <code>nightowl_t.dylib</code> (which is actually a copy of <a href=\"https://github.com/tinyproxy/tinyproxy\">tinyproxy</a>, which is licensed under GPLv2, and does not contain the GPL license notice, so this might actually be a violation!), which acts as a HTTP(S) proxy and runs on port , It opens up a SSH connection (using autossh, renamed <code>nightowl_a.dylib</code>, which doesn't have a license) to <code>testconnectuser2023@proxy-gw1-europe.squidyproxy.com</code> on port <code>2043</code>, using a public key it drops in <code>/tmp</code> (it has a <code>.uu</code> extension), using the <code>-R</code> port to tunnel a port on the remote machine to the local machine. (it retrieves this by making a request to proxy-api1.squidyproxy.com over HTTPS). This domain was registered with GoDaddy in April 2022, and the IP address is hosted by Microsoft.</p>\n<p>For reference, this SSH server has shell access enabled. (I didn't try anything though). After the connection succeeds, it forwards HTTP traffic down to you, which gets proxied out of your internet connection. I saw it trying to access . It also tries to open a UPnP port forward on your router, but fails on mine because the key names are jumbled:</p>\n<pre class=\"language-http\"><code class=\"language-http\"><span class=\"token request-line\"><span class=\"token method property\">POST</span> <span class=\"token request-target url\">/ctl/IPConn</span> <span class=\"token http-version property\">HTTP/1.1</span></span>\n<span class=\"token header\"><span class=\"token header-name keyword\">Host</span><span class=\"token punctuation\">:</span> <span class=\"token header-value\">192.168.1.1:5000</span></span>\n<span class=\"token header\"><span class=\"token header-name keyword\">User-Agent</span><span class=\"token punctuation\">:</span> <span class=\"token header-value\">Go-http-client/1.1</span></span>\n<span class=\"token header\"><span class=\"token header-name keyword\">Content-Length</span><span class=\"token punctuation\">:</span> <span class=\"token header-value\">526</span></span>\n<span class=\"token header\"><span class=\"token header-name keyword\">CONTENT-TYPE</span><span class=\"token punctuation\">:</span> <span class=\"token header-value\">text/xml; charset=\"utf-8\"</span></span>\n<span class=\"token header\"><span class=\"token header-name keyword\">SOAPACTION</span><span class=\"token punctuation\">:</span> <span class=\"token header-value\">\"urn:schemas-upnp-org:service:WANIPConnection:1#AddPortMapping\"</span></span>\n<span class=\"token header\"><span class=\"token header-name keyword\">Accept-Encoding</span><span class=\"token punctuation\">:</span> <span class=\"token header-value\">gzip</span></span>\n\n&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?>\n&lt;s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">&lt;s:Body>&lt;u:AddPortMapping xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">&lt;BznVVp_>&lt;/BznVVp_>&lt;A8Lx50LV3wS>50276&lt;/A8Lx50LV3wS>&lt;SOkiBsutQ>TCP&lt;/SOkiBsutQ>&lt;C7V6rYTZpovv>50276&lt;/C7V6rYTZpovv>&lt;S8pOPFbT13z>192.168.3.102&lt;/S8pOPFbT13z>&lt;AQBzrw>1&lt;/AQBzrw>&lt;O9hZpuXGWURb>ip royal paws&lt;/O9hZpuXGWURb>&lt;BBYmUz7H>2592000&lt;/BBYmUz7H>&lt;/u:AddPortMapping>&lt;/s:Body>&lt;/s:Envelope></code></pre>\n<p>The application also seems to use the <a href=\"https://pawns.app/\">Pawns</a> SDK<sup class=\"footnote-ref\"><a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fn3\" id=\"fnref3:1\">[3:1]</a></sup>, which is an app offers to pay users $0.20 per GB of their internet shared<sup class=\"footnote-ref\"><a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fn5\" id=\"fnref5\">[5]</a></sup>. This service is operated by <a href=\"https://iproyal.com/\">IPRoyal</a><sup class=\"footnote-ref\"><a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fn6\" id=\"fnref6\">[6]</a></sup>, a proxy company that will sell you residential proxy connections for $1.75/GB, and advertises &quot;100% ethically sourced IPs&quot;<sup class=\"footnote-ref\"><a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fn7\" id=\"fnref7\">[7]</a></sup>.</p>\n<hr class=\"footnotes-sep\">\n<section class=\"footnotes\">\n<ol class=\"footnotes-list\">\n<li id=\"fn1\" class=\"footnote-item\"><p><a href=\"https://www.kramser.xyz/\">https://www.kramser.xyz/</a> <a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fnref1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn2\" class=\"footnote-item\"><p><a href=\"https://nightowlapp.co/imprint\">https://nightowlapp.co/imprint</a> <a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fnref2\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn3\" class=\"footnote-item\"><p><a href=\"https://www.virustotal.com/gui/file/840fd039b2509fb50b328c0b5ada8c7300608e57bce8ce1bce822ee34b23fa52/behavior\">https://www.virustotal.com/gui/file/840fd039b2509fb50b328c0b5ada8c7300608e57bce8ce1bce822ee34b23fa52/behavior</a> <a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fnref3\" class=\"footnote-backref\">↩︎</a> <a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fnref3:1\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn4\" class=\"footnote-item\"><p><a href=\"https://nightowlapp.co/\">https://nightowlapp.co/</a> <a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fnref4\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn5\" class=\"footnote-item\"><p><a href=\"https://pawns.app/\">https://pawns.app/</a> <a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fnref5\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn6\" class=\"footnote-item\"><p><a href=\"https://pawns.app/blog/iproyal-pawns-is-now-pawns-app/\">https://pawns.app/blog/iproyal-pawns-is-now-pawns-app/</a> <a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fnref6\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n<li id=\"fn7\" class=\"footnote-item\"><p><a href=\"https://iproyal.com/\">https://iproyal.com/</a> <a href=\"https://eth0fox.net/notes/2023-06-28-uninstall-the-nightowl-app-now/#fnref7\" class=\"footnote-backref\">↩︎</a></p>\n</li>\n</ol>\n</section>\n",
      "date_published": "2023-06-28T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2023-02-16-bettertouchtool-mediakeys/",
      "url": "https://eth0fox.net/notes/2023-02-16-bettertouchtool-mediakeys/",
      "title": "Force macOS to send media key events to Apple Music/Spotify",
      "content_html": "<p>If you're like me, and the worst thing an application can do is override the system media keys with no option to turn it off, (talking to you, Discord, Safari), you really need a way to force all media keys to be routed to the music app of your choice.</p>\n<p>For this, we can use BetterTouchTool, simply open the main window, select the below code and paste it in!</p>\n<h2 id=\"apple-music\">Apple Music</h2>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">[</span>\n  <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"BTTTriggerType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTTriggerClass\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"BTTTriggerTypeKeyboardShortcut\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTPredefinedActionType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">172</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTPredefinedActionName\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"Run Apple Script (blocking)\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTInlineAppleScript\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"tell application \\\"Music\\\" to playpause\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAdditionalConfiguration\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"0\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTEnabled2\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTKeyboardShortcutKeyboardType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">9578</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTRepeatDelay\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTUUID\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"50161BC2-6EF7-44D5-9B7A-07CD8D489F0D\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTTriggerOnDown\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTNotesInsteadOfDescription\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTLayoutIndependentChar\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTEnabled\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTModifierMode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTShortcutKeyCode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1016</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTShortcutModifierKeys\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTDisplayOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAutoAdaptToKeyboardLayout\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"BTTTriggerType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTTriggerClass\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"BTTTriggerTypeKeyboardShortcut\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTPredefinedActionType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">172</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTPredefinedActionName\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"Run Apple Script (blocking)\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTInlineAppleScript\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"tell application \\\"Music\\\" to next track\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAdditionalConfiguration\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"0\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTEnabled2\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTKeyboardShortcutKeyboardType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">9578</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTRepeatDelay\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTUUID\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"7B8BF1E6-6B35-46D7-93CB-25F1827A74F3\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTTriggerOnDown\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTNotesInsteadOfDescription\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTLayoutIndependentChar\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"娨\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTEnabled\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTModifierMode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTShortcutKeyCode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1017</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTShortcutModifierKeys\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTDisplayOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAutoAdaptToKeyboardLayout\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"BTTTriggerType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTTriggerClass\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"BTTTriggerTypeKeyboardShortcut\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTPredefinedActionType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">172</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTPredefinedActionName\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"Run Apple Script (blocking)\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTInlineAppleScript\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"tell application \\\"Music\\\" to previous track\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAdditionalConfiguration\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"0\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTEnabled2\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTKeyboardShortcutKeyboardType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">9578</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTRepeatDelay\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTUUID\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"023225C7-9067-4A62-A636-34358A99B1C4\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTTriggerOnDown\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTNotesInsteadOfDescription\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTLayoutIndependentChar\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"宨\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTEnabled\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTModifierMode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTShortcutKeyCode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1018</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTShortcutModifierKeys\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTDisplayOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAutoAdaptToKeyboardLayout\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">]</span></code></pre>\n<h2 id=\"spotify\">Spotify</h2>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">[</span>\n  <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"BTTTriggerType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTTriggerClass\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"BTTTriggerTypeKeyboardShortcut\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTPredefinedActionType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">172</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTPredefinedActionName\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"Run Apple Script (blocking)\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTInlineAppleScript\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"tell application \\\"Spotify\\\" to playpause\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAdditionalConfiguration\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"0\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTEnabled2\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTKeyboardShortcutKeyboardType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">9578</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTRepeatDelay\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTUUID\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"061C22C1-121C-4BB0-B955-03046088A48D\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTTriggerOnDown\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTNotesInsteadOfDescription\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTLayoutIndependentChar\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTEnabled\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTModifierMode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTShortcutKeyCode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1016</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTShortcutModifierKeys\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTDisplayOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAutoAdaptToKeyboardLayout\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"BTTTriggerType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTTriggerClass\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"BTTTriggerTypeKeyboardShortcut\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTPredefinedActionType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">172</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTPredefinedActionName\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"Run Apple Script (blocking)\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTInlineAppleScript\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"tell application \\\"Spotify\\\" to next track\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAdditionalConfiguration\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"0\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTEnabled2\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTKeyboardShortcutKeyboardType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">9578</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTRepeatDelay\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTUUID\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"4A39E12F-6381-42DB-BB30-E5BF6CAE4276\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTTriggerOnDown\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTNotesInsteadOfDescription\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTLayoutIndependentChar\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"娨\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTEnabled\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTModifierMode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTShortcutKeyCode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1017</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTShortcutModifierKeys\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTDisplayOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAutoAdaptToKeyboardLayout\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"BTTTriggerType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTTriggerClass\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"BTTTriggerTypeKeyboardShortcut\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTPredefinedActionType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">172</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTPredefinedActionName\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"Run Apple Script (blocking)\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTInlineAppleScript\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"tell application \\\"Spotify\\\" to previous track\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAdditionalConfiguration\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"0\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTEnabled2\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTKeyboardShortcutKeyboardType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">9578</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTRepeatDelay\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTUUID\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"227DE82E-86E5-4F4B-BEA6-E988875A5489\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTTriggerOnDown\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTNotesInsteadOfDescription\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTLayoutIndependentChar\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"宨\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTEnabled\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTModifierMode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTShortcutKeyCode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1018</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTShortcutModifierKeys\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTDisplayOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAutoAdaptToKeyboardLayout\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">]</span></code></pre>\n<h2 id=\"bonus-conditional-music-player-choice\">Bonus: Conditional Music Player Choice</h2>\n<p>If you use both Spotify &amp; Apple Music, you can set BetterTouchTool to, for example, route all keys to Spotify, but only if it's open, otherwise, route to Apple Music.</p>\n<p>To do this, paste <strong>both</strong> the Apple Music code from above, and this code here.</p>\n<pre class=\"language-json\"><code class=\"language-json\"><span class=\"token punctuation\">[</span>\n  <span class=\"token punctuation\">{</span>\n    <span class=\"token property\">\"BTTActivationGroupName\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"Spotify\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAppName\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"Spotify\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAppAutoInvertIcon\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTAppProcessMatchMode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">3</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTActivationGroupCondition\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGvEBYLDBMYICorLjU5Pj9CRkpPUFNZXWFjVSRudWxs0w0ODxAREl8QF05TQ29tcG91bmRQcmVkaWNhdGVUeXBlXxAPTlNTdWJwcmVkaWNhdGVzViRjbGFzcxACgAKAFdIUDxUXWk5TLm9iamVjdHOhFoADgBTUDxkaGxwdHh9fEBFOU1JpZ2h0RXhwcmVzc2lvbl8QEE5TTGVmdEV4cHJlc3Npb25fEBNOU1ByZWRpY2F0ZU9wZXJhdG9ygBOADoAEgBHVISIjJA8lJicoKVlOU09wZXJhbmReTlNTZWxlY3Rvck5hbWVfEBBOU0V4cHJlc3Npb25UeXBlW05TQXJndW1lbnRzgAaABRADgAiADVx2YWx1ZUZvcktleTrSIw8sLRABgAfSLzAxMlokY2xhc3NuYW1lWCRjbGFzc2VzXxAQTlNTZWxmRXhwcmVzc2lvbqMxMzRcTlNFeHByZXNzaW9uWE5TT2JqZWN00hQPNjihN4AJgAzTDyM6Ozw9WU5TS2V5UGF0aIALEAqACl8QEHJ1bm5pbmdQcm9jZXNzZXPSLzBAQV8QHE5TS2V5UGF0aFNwZWNpZmllckV4cHJlc3Npb26jQDM00i8wQ0ReTlNNdXRhYmxlQXJyYXmjQ0U0V05TQXJyYXnSLzBHSF8QE05TS2V5UGF0aEV4cHJlc3Npb26kR0kzNF8QFE5TRnVuY3Rpb25FeHByZXNzaW9u00sjD0xNTl8QD05TQ29uc3RhbnRWYWx1ZYAPEACAEFdTcG90aWZ50i8wUVJfEBlOU0NvbnN0YW50VmFsdWVFeHByZXNzaW9uo1EzNNQPVFVWV01NWFpOU01vZGlmaWVyV05TRmxhZ3NeTlNPcGVyYXRvclR5cGWAEhBj0i8wWltfEBVOU0luUHJlZGljYXRlT3BlcmF0b3KjWlw0XxATTlNQcmVkaWNhdGVPcGVyYXRvctIvMF5fXxAVTlNDb21wYXJpc29uUHJlZGljYXRlo15gNFtOU1ByZWRpY2F0ZdIvMEViokU00i8wZGVfEBNOU0NvbXBvdW5kUHJlZGljYXRlo2RgNAAIABEAGgAkACkAMgA3AEkATABRAFMAbAByAHkAkwClAKwArgCwALIAtwDCAMQAxgDIANEA5QD4AQ4BEAESARQBFgEhASsBOgFNAVkBWwFdAV8BYQFjAXABdQF3AXkBfgGJAZIBpQGpAbYBvwHEAcYByAHKAdEB2wHdAd8B4QH0AfkCGAIcAiECMAI0AjwCQQJXAlwCcwJ6AowCjgKQApICmgKfArsCvwLIAtMC2wLqAuwC7gLzAwsDDwMlAyoDQgNGA1IDVwNaA18DdQAAAAAAAAIBAAAAAAAAAGYAAAAAAAAAAAAAAAAAAAN5\"</span><span class=\"token punctuation\">,</span>\n    <span class=\"token property\">\"BTTTriggers\"</span> <span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n      <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">\"BTTTriggerType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTTriggerClass\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"BTTTriggerTypeKeyboardShortcut\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTPredefinedActionType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">172</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTPredefinedActionName\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"Run Apple Script (blocking)\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTInlineAppleScript\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"tell application \\\"Spotify\\\" to next track\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTAdditionalConfiguration\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"0\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTEnabled2\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTKeyboardShortcutKeyboardType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">9578</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTRepeatDelay\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTUUID\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"4A39E12F-6381-42DB-BB30-E5BF6CAE4276\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTTriggerOnDown\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTNotesInsteadOfDescription\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTLayoutIndependentChar\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"娨\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTEnabled\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTModifierMode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTShortcutKeyCode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1017</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTShortcutModifierKeys\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTDisplayOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTAutoAdaptToKeyboardLayout\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">\"BTTTriggerType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTTriggerClass\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"BTTTriggerTypeKeyboardShortcut\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTPredefinedActionType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">172</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTPredefinedActionName\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"Run Apple Script (blocking)\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTInlineAppleScript\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"tell application \\\"Spotify\\\" to playpause\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTAdditionalConfiguration\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"0\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTEnabled2\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTKeyboardShortcutKeyboardType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">9578</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTRepeatDelay\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTUUID\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"061C22C1-121C-4BB0-B955-03046088A48D\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTTriggerOnDown\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTNotesInsteadOfDescription\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTLayoutIndependentChar\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTEnabled\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTModifierMode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTShortcutKeyCode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1016</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTShortcutModifierKeys\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTDisplayOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTAutoAdaptToKeyboardLayout\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span>\n      <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n      <span class=\"token punctuation\">{</span>\n        <span class=\"token property\">\"BTTTriggerType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTTriggerClass\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"BTTTriggerTypeKeyboardShortcut\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTPredefinedActionType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">172</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTPredefinedActionName\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"Run Apple Script (blocking)\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTInlineAppleScript\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"tell application \\\"Spotify\\\" to previous track\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTAdditionalConfiguration\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"0\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTEnabled2\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTKeyboardShortcutKeyboardType\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">9578</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTRepeatDelay\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTUUID\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"227DE82E-86E5-4F4B-BEA6-E988875A5489\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTTriggerOnDown\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTNotesInsteadOfDescription\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTLayoutIndependentChar\"</span> <span class=\"token operator\">:</span> <span class=\"token string\">\"宨\"</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTEnabled\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTModifierMode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTShortcutKeyCode\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">1018</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTShortcutModifierKeys\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTDisplayOrder\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token property\">\"BTTAutoAdaptToKeyboardLayout\"</span> <span class=\"token operator\">:</span> <span class=\"token number\">0</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">]</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">]</span></code></pre>\n",
      "date_published": "2023-02-16T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2022-04-30-haxe-speed-comparison/",
      "url": "https://eth0fox.net/notes/2022-04-30-haxe-speed-comparison/",
      "title": "how fast is Haxe?",
      "content_html": "<p>Haxe for those who don't know is a programming language that doesn't commonly run as itself. It usually gets transpiled to other languages such as C++, JavaScript or C#.</p>\n<p>Of course, different targets will have different speeds, so I wanted to test that, so <a href=\"https://github.com/eth0fox/HaxePrimeSieve\">I ported davepl's prime sieve to Haxe</a>. Here's the results from my MacBook Pro M1.</p>\n<table>\n<thead>\n<tr>\n<th>Target</th>\n<th>Runs</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>C++</td>\n<td>588</td>\n</tr>\n<tr>\n<td>Javascript</td>\n<td>548</td>\n</tr>\n<tr>\n<td>JavaBytecode</td>\n<td>387</td>\n</tr>\n<tr>\n<td>Java</td>\n<td>373</td>\n</tr>\n<tr>\n<td>C#</td>\n<td>340</td>\n</tr>\n<tr>\n<td>PHP</td>\n<td>34</td>\n</tr>\n<tr>\n<td>Cppia</td>\n<td>23</td>\n</tr>\n<tr>\n<td>HaxeEval</td>\n<td>15</td>\n</tr>\n<tr>\n<td>Python</td>\n<td>9</td>\n</tr>\n<tr>\n<td>Neko</td>\n<td>5</td>\n</tr>\n</tbody>\n</table>\n<p>Compare these results to other programming languages on a 5950x (HxCPP got a score of 723) <a href=\"https://plummerssoftwarellc.github.io/PrimeView/report?id=davepl-1650451626.json\">here</a></p>\n",
      "date_published": "2022-04-30T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2022-01-31-fix-greyed-out-files-macos/",
      "url": "https://eth0fox.net/notes/2022-01-31-fix-greyed-out-files-macos/",
      "title": "How to fix &quot;Copying x has paused&quot;/greyed out folders on macOS Finder.",
      "content_html": "<p>macOS will handily let you resume a failed/interrupted copy operation, however, if you want to just stop it and get access to the folder. macOS doesn't let you do this, even if the files are there on disk.</p>\n<p>You'll need to open the Terminal to do this and run 2 commands. Copy and paste them and then drag the folder into the Terminal window after them, leaving a trailing space.</p>\n<pre><code># Remove the copy in progress attribute from the file.\nxattr -c \n# Reset the file creation date (this command will complaining about missing file but it does work!)\nSetFile -d\n</code></pre>\n<p>If all went well, you should see the following:</p>\n<pre><code>taylor@vulpes ~ % xattr -c /Volumes/Backups/2018install/\ntaylor@vulpes ~ % SetFile -d /Volumes/Backups/2018install\nERROR: File Not Found. (-43)  on file: -d \n</code></pre>\n",
      "date_published": "2022-01-31T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2022-01-16-how-to-commit-identity-duplication/",
      "url": "https://eth0fox.net/notes/2022-01-16-how-to-commit-identity-duplication/",
      "title": "How to commit as multiple identities on macOS",
      "content_html": "<h3 id=\"working-title-how-not-to-deadname-yourself-on-git\">working title: how not to deadname yourself on git.</h3>\n<p>As a trans individual, it is essential (at least for me) to have multiple identities, and because one of my things I know how to do is write code, and sometimes I like to put said code on GitHub, and all git commits are linked to a name and an email address (which gets resolved to a GitHub account) I’d rather not cross the streams (most of the time ;) ifykyk) and put code attributed to Taylor on my ‘original’ GH acc, and vice versa.</p>\n<p>There are other reasons why you might want 2 (or more) separate identities on Git (such as for work, and for personal), but that’s my reasoning.</p>\n<h2 id=\"why-not-just-use-gitkraken-tower-g\">Why not just use <code>/gitkraken|tower/g</code> ?</h2>\n<p>Yes, there are visual clients that do this, however, they’re not perfect. If you use those clients, and it works for you, that’s great. But mainly:</p>\n<ul>\n<li><strong>Tower</strong>’s UI is confusing to my dumb brain, and iirc only one account per service</li>\n<li><strong>GitKraken</strong>’s multi account feature is paid exclusive, which is great because I have the GitHub Education Pack, but not so great when you realise you can only use this when your subscription is on a Axosoft account, and you cannot unlink a GitHub account from an identity if that account is what your paid account is registered under.</li>\n</ul>\n<p>This guide takes the nuclear approach of creating multiple operating system users for each identity, and using GitHub Desktop to manage said identities.</p>\n<h2 id=\"why-github-desktop\">Why GitHub Desktop?</h2>\n<ul>\n<li>it’s easy</li>\n</ul>\n<p>You could use any other Git client, however, I like GitHub Desktop for it’s simplicity and it works fine.</p>\n<h2 id=\"actually-doing-the-thing\">Actually doing the thing.</h2>\n<p>This guide will show you how to do it on macOS, however the steps should be similar for Linux, and the concepts should be similar for Windows (i.e. using <code>PsExec</code> or similar to exec as another user instead of <code>su</code>.</p>\n<ol>\n<li>Install GitHub Desktop</li>\n<li>Create a seperate macOS user account</li>\n<li>Move your source code to a shared directory (i.e. external drive, /Users/Shared) give new user to access to that folder</li>\n<li>Switch to the new user account (Apple Menu, lock, switch user) and complete OOBE (this creates keychains, required configs, etc)</li>\n<li>Log that user out and switch back to your regular user account</li>\n<li>Run 'su TheUsernameOfYourNewUserAccountHere' in a terminal (sudo will NOT work)</li>\n<li>Run <code>/Applications/GitHub\\ Desktop.app/Contents/MacOS/GitHub\\ Desktop &amp;</code></li>\n<li>Sign into GitHub Desktop (this will open Safari as your new user)</li>\n<li>From here you can clone, create a new repo, or open an existing repo  (you may need to enter the path instead of browsing, the open file dialog was broken for me)</li>\n<li>Publish to GitHub! 🥳</li>\n</ol>\n<h2 id=\"caveats\">Caveats</h2>\n<ul>\n<li>This solution is the nuclear method, other than actually logging into using a separate user account for your coding fully, this provides the most secure way of keeping two identities private</li>\n<li>Some things don’t work when running as the wrong user, for example,\n<ul>\n<li>Finder &amp; it’s dialogs</li>\n<li>Apps will refuse to open unless you call their binaries from a terminal</li>\n<li>File permissions can get wacky. For example, if you use the GUI to clone to a folder in the new user’s home folder, the user that’s running everything else can’t access it, and vice versa.</li>\n</ul>\n</li>\n</ul>\n",
      "date_published": "2022-01-16T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2021-12-24-fetch-user-theme-and-other-preferences-on-macos-terminal/",
      "url": "https://eth0fox.net/notes/2021-12-24-fetch-user-theme-and-other-preferences-on-macos-terminal/",
      "title": "Reading macOS Preferences (such as theme) from the Terminal",
      "content_html": "<h2 id=\"read-light-dark-mode-preference\">Read light/dark mode preference:</h2>\n<pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token operator\">></span> plutil <span class=\"token parameter variable\">-extract</span> AppleInterfaceStyle raw ~/Library/Preferences/.GlobalPreferences.plist <span class=\"token parameter variable\">-o</span> -\nDark</code></pre>\n<h2 id=\"dump-all-global-preferences-as-xml\">Dump all global preferences as XML:</h2>\n<pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token operator\">></span> plutil <span class=\"token parameter variable\">-convert</span> xml1 ~/Library/Preferences/.GlobalPreferences.plist <span class=\"token parameter variable\">-o</span> -\n<span class=\"token operator\">&lt;</span>?xml <span class=\"token assign-left variable\">version</span><span class=\"token operator\">=</span><span class=\"token string\">\"1.0\"</span> <span class=\"token assign-left variable\">encoding</span><span class=\"token operator\">=</span><span class=\"token string\">\"UTF-8\"</span>?<span class=\"token operator\">></span>\n<span class=\"token operator\">&lt;</span><span class=\"token operator\">!</span>DOCTYPE plist PUBLIC <span class=\"token string\">\"-//Apple//DTD PLIST 1.0//EN\"</span> <span class=\"token string\">\"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"</span><span class=\"token operator\">></span>\n<span class=\"token operator\">&lt;</span>plist <span class=\"token assign-left variable\">version</span><span class=\"token operator\">=</span><span class=\"token string\">\"1.0\"</span><span class=\"token operator\">></span>\n<span class=\"token operator\">&lt;</span>dict<span class=\"token operator\">></span>\n\t<span class=\"token operator\">&lt;</span>key<span class=\"token operator\">></span>AKLastEmailListRequestDateKey<span class=\"token operator\">&lt;</span>/key<span class=\"token operator\">></span>\n\t<span class=\"token operator\">&lt;</span>date<span class=\"token operator\">></span><span class=\"token number\">2021</span>-12-23T20:10:20Z<span class=\"token operator\">&lt;</span>/date<span class=\"token operator\">></span>\n\t<span class=\"token operator\">&lt;</span>key<span class=\"token operator\">></span>AKLastIDMSEnvironment<span class=\"token operator\">&lt;</span>/key<span class=\"token operator\">></span>\n\t<span class=\"token operator\">&lt;</span>integer<span class=\"token operator\">></span><span class=\"token operator\"><span class=\"token file-descriptor important\">0</span>&lt;</span>/integer<span class=\"token operator\">></span>\n\t<span class=\"token operator\">&lt;</span>key<span class=\"token operator\">></span>AppleAntiAliasingThreshold<span class=\"token operator\">&lt;</span>/key<span class=\"token operator\">></span>\n\t<span class=\"token operator\">&lt;</span>integer<span class=\"token operator\">></span><span class=\"token operator\"><span class=\"token file-descriptor important\">4</span>&lt;</span>/integer<span class=\"token operator\">></span>\n\t<span class=\"token operator\">&lt;</span>key<span class=\"token operator\">></span>AppleAquaColorVariant<span class=\"token operator\">&lt;</span>/key<span class=\"token operator\">></span>\n\t<span class=\"token operator\">&lt;</span>integer<span class=\"token operator\">></span><span class=\"token operator\"><span class=\"token file-descriptor important\">1</span>&lt;</span>/integer<span class=\"token operator\">></span>\n\t<span class=\"token operator\">&lt;</span>key<span class=\"token operator\">></span>AppleInterfaceStyle<span class=\"token operator\">&lt;</span>/key<span class=\"token operator\">></span>\n\t<span class=\"token operator\">&lt;</span>string<span class=\"token operator\">></span>Dark<span class=\"token operator\">&lt;</span>/string<span class=\"token operator\">></span>\n<span class=\"token punctuation\">[</span><span class=\"token punctuation\">..</span>.<span class=\"token punctuation\">]</span></code></pre>\n",
      "date_published": "2021-12-24T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2021-12-18-files-on-the-time-machine-drive/",
      "url": "https://eth0fox.net/notes/2021-12-18-files-on-the-time-machine-drive/",
      "title": "putting files on the time machine drive on Monterey",
      "content_html": "<h2 id=\"the-part-you-actually-care-about\">The part you actually care about:</h2>\n<ol>\n<li>Open Disk Utility</li>\n<li>Select &quot;Show all disks&quot; from the view menu</li>\n<li>Ensure the drive is formatted as APFS</li>\n<li>Select the &quot;Container&quot; inside the drive</li>\n<li>Click the '+' icon where it says &quot;Volume&quot; in the top right</li>\n<li>Give it a name and create.\na. Now those of you familiar with drive partitioning, but less with APFS volumes, this won't create a partition. You'll have the entire drive space available to both volumes (you can assign a minimum &amp; maximum size to both volumes however)</li>\n</ol>\n<h2 id=\"the-wtf-moment\">The &quot;wtf?&quot; moment:</h2>\n<p>Time Machine backups on Monterey are weird. First of all, they show up as Finder weirdly, and you cant copy files to and from it, not even with Terminal!</p>\n<pre><code>cp: /Volumes/Time Machine 1/Screenshot 2021-12-18 at 00.43.12.png: Operation not permitted\n</code></pre>\n<p>In <code>df</code> each drive connected to your PC shows up as a seperate TimeMachine Local Snapshot mountpoint??</p>\n<pre><code>/dev/disk4s3                                                 7813627488  136564136 4805111360     3%        357 24025556800    0%   /Volumes/Time Machine 1\ncom.apple.TimeMachine.2021-12-18-011118.local@/dev/disk5s1    976363488  333586496  642462768    35%       9030  3212313840    0%   /Volumes/com.apple.TimeMachine.localsnapshots/Backups.backupdb/Vulpes (340)/2021-12-18-011118/500g\ncom.apple.TimeMachine.2021-12-18-011118.local@/dev/disk4s1   7813627488 2871004304 4805111360    38%    8912213 24025556800    0%   /Volumes/com.apple.TimeMachine.localsnapshots/Backups.backupdb/Vulpes (340)/2021-12-18-011118/Backups\ncom.apple.TimeMachine.2021-12-18-011118.local@/dev/disk3s1   1953115488 1275711672  642863760    67%    4834960  3214318800    0%   /Volumes/com.apple.TimeMachine.localsnapshots/Backups.backupdb/Vulpes (340)/2021-12-18-011118/macOS Montero - Data\n</code></pre>\n<p>Very strange.</p>\n",
      "date_published": "2021-12-18T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2021-10-04-fixing-apt-on-the-chip/",
      "url": "https://eth0fox.net/notes/2021-10-04-fixing-apt-on-the-chip/",
      "title": "fixing apt on the C.H.I.P.",
      "content_html": "<p>Since NTC thing went bust years ago, there have been no official builds of the C.H.I.P. OS, which runs a modified version of Debian Jessie, and due to time being a thing, this isn't very great.</p>\n<p>If you have a fresh C.H.I.P. install, you can do this to get APT working again.</p>\n<ol start=\"0\">\n<li>Use the USB serial to setup instead of the not great keyboard of the PocketC.H.I.P.</li>\n</ol>\n<ul>\n<li>On a Mac (&amp; probably Linux), open Terminal and <code>screen /dev/tty.usbmodem*</code>.</li>\n<li>Unsure about Windows, but PuTTY is probably what you're after.</li>\n</ul>\n<ol>\n<li>Download the <code>armhf</code> versions of the following packages packages: (visit the linked pages, ctrl+f for the package name, and copy the url, and then run <code>wget [URL]</code>)</li>\n</ol>\n<ul>\n<li><a href=\"http://ftp.us.debian.org/debian//pool/main/a/apt/\"><code>apt-transport-https</code></a></li>\n<li><a href=\"http://ftp.us.debian.org/debian/pool/main/c/ca-certificates/\"><code>ca-certificates</code></a></li>\n<li><a href=\"http://ftp.us.debian.org/debian/pool/main/d/debian-archive-keyring\"><code>debian-archive-keyring</code></a></li>\n</ul>\n<ol start=\"2\">\n<li>Install all the listed packages with the following command <code>sudo dpkg -i *.deb</code></li>\n<li>Edit <code>/etc/apt/sources.list</code> to have the following contents.</li>\n</ol>\n<pre><code>deb http://archive.debian.org/debian/ jessie main contrib non-free\ndeb-src http://archive.debian.org/debian/ jessie main contrib non-free\n\ndeb http://security.debian.org/ jessie/updates main contrib non-free\ndeb-src http://security.debian.org/ jessie/updates main contrib non-free\n\ndeb http://archive.debian.org/debian jessie-backports main contrib non-free \ndeb-src http://archive.debian.org/debian jessie-backports main contrib non-free\n\ndeb http://chip.jfpossibilities.com/chip/debian/repo jessie main\n\ndeb http://chip.jfpossibilities.com/chip/debian/pocketchip jessie main\n</code></pre>\n<ol start=\"4\">\n<li>Edit <code>/etc/apt/apt.conf.d/99-no-ssl.conf</code> to be the following:</li>\n</ol>\n<pre><code>Acquire {\n        https::Verify-Peer false;\n        Check-Valid-Until false;\n}\nAPT:Get::AllowUnauthenticated true;\n</code></pre>\n<p>:warning: This will disable security measures to validate the integrity of the software installed on the device. If you trust that Debian isn't gonna get hacked, and that you only connect to trusted WiFi, this shouldn't be an issue though.</p>\n<ol start=\"5\">\n<li>With any luck, <code>sudo apt update</code> should now work 🎉</li>\n<li><code>sudo apt upgrade</code> to update all the installed packages to the latest versions.\n<ul>\n<li>This will take <strong>a while</strong>.</li>\n</ul>\n</li>\n</ol>\n",
      "date_published": "2021-10-04T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2021-09-10-reading-macos-notifications-in-python/",
      "url": "https://eth0fox.net/notes/2021-09-10-reading-macos-notifications-in-python/",
      "title": "Reading macOS Notifications in Python",
      "content_html": "<p>Python code snippet for reading notifications in Python3. Works on Big Sur.</p>\n<pre class=\"language-py\"><code class=\"language-py\"><span class=\"token comment\"># Read macOS Notifications</span>\n<span class=\"token comment\"># pip3 install bpylist</span>\n\n<span class=\"token keyword\">import</span> sqlite3\n<span class=\"token keyword\">import</span> os\n<span class=\"token keyword\">from</span> bpylist <span class=\"token keyword\">import</span> bplist\n\nuserDir <span class=\"token operator\">=</span> os<span class=\"token punctuation\">.</span>popen<span class=\"token punctuation\">(</span><span class=\"token string\">\"getconf DARWIN_USER_DIR\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>read<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>strip<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token builtin\">file</span> <span class=\"token operator\">=</span> userDir <span class=\"token operator\">+</span> <span class=\"token string\">\"com.apple.notificationcenter/db2/db\"</span>\n<span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"Opening\"</span><span class=\"token punctuation\">,</span><span class=\"token builtin\">file</span><span class=\"token punctuation\">)</span>\n\ndb <span class=\"token operator\">=</span> sqlite3<span class=\"token punctuation\">.</span>connect<span class=\"token punctuation\">(</span><span class=\"token string-interpolation\"><span class=\"token string\">f'file:</span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span><span class=\"token builtin\">file</span><span class=\"token punctuation\">}</span></span><span class=\"token string\">?mode=ro'</span></span><span class=\"token punctuation\">,</span> uri<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">)</span>\n\nnotifs <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">{</span>\n    <span class=\"token string\">\"rec_id\"</span><span class=\"token punctuation\">:</span> row<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"app_id\"</span><span class=\"token punctuation\">:</span> row<span class=\"token punctuation\">[</span><span class=\"token number\">1</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"uuid\"</span><span class=\"token punctuation\">:</span> row<span class=\"token punctuation\">[</span><span class=\"token number\">2</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"data\"</span><span class=\"token punctuation\">:</span> bplist<span class=\"token punctuation\">.</span>parse<span class=\"token punctuation\">(</span>row<span class=\"token punctuation\">[</span><span class=\"token number\">3</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"request_date\"</span><span class=\"token punctuation\">:</span> row<span class=\"token punctuation\">[</span><span class=\"token number\">4</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"request_last_date\"</span><span class=\"token punctuation\">:</span> row<span class=\"token punctuation\">[</span><span class=\"token number\">5</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"delivered_date\"</span><span class=\"token punctuation\">:</span> row<span class=\"token punctuation\">[</span><span class=\"token number\">6</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"presented\"</span><span class=\"token punctuation\">:</span> row<span class=\"token punctuation\">[</span><span class=\"token number\">7</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"style\"</span><span class=\"token punctuation\">:</span> row<span class=\"token punctuation\">[</span><span class=\"token number\">8</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">\"snooze_fire_date\"</span><span class=\"token punctuation\">:</span> row<span class=\"token punctuation\">[</span><span class=\"token number\">9</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span> <span class=\"token keyword\">for</span> row <span class=\"token keyword\">in</span> db<span class=\"token punctuation\">.</span>execute<span class=\"token punctuation\">(</span><span class=\"token string\">\"SELECT * FROM record\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>fetchall<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span>\n\n<span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span>notifs<span class=\"token punctuation\">[</span><span class=\"token number\">0</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"data\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">for</span> notif <span class=\"token keyword\">in</span> notifs<span class=\"token punctuation\">:</span>\n    data <span class=\"token operator\">=</span> notif<span class=\"token punctuation\">[</span><span class=\"token string\">\"data\"</span><span class=\"token punctuation\">]</span>\n    app <span class=\"token operator\">=</span> data<span class=\"token punctuation\">[</span><span class=\"token string\">\"app\"</span><span class=\"token punctuation\">]</span> <span class=\"token keyword\">if</span> <span class=\"token string\">\"app\"</span> <span class=\"token keyword\">in</span> data <span class=\"token keyword\">else</span> <span class=\"token string\">\"Unknown App\"</span>\n    title <span class=\"token operator\">=</span>  data<span class=\"token punctuation\">[</span><span class=\"token string\">\"req\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"titl\"</span><span class=\"token punctuation\">]</span> <span class=\"token keyword\">if</span> <span class=\"token string\">\"titl\"</span> <span class=\"token keyword\">in</span> data<span class=\"token punctuation\">[</span><span class=\"token string\">\"req\"</span><span class=\"token punctuation\">]</span> <span class=\"token keyword\">else</span> <span class=\"token string\">\"\"</span> \n    body <span class=\"token operator\">=</span> data<span class=\"token punctuation\">[</span><span class=\"token string\">\"req\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"body\"</span><span class=\"token punctuation\">]</span> <span class=\"token keyword\">if</span> <span class=\"token string\">\"body\"</span> <span class=\"token keyword\">in</span> data<span class=\"token punctuation\">[</span><span class=\"token string\">\"req\"</span><span class=\"token punctuation\">]</span> <span class=\"token keyword\">else</span> <span class=\"token string\">\"\"</span>\n    <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string-interpolation\"><span class=\"token string\">f\"</span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>app<span class=\"token punctuation\">}</span></span><span class=\"token string\">: </span><span class=\"token interpolation\"><span class=\"token punctuation\">{</span>title<span class=\"token punctuation\">}</span></span><span class=\"token string\">\"</span></span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"\\t\"</span> <span class=\"token operator\">+</span> body<span class=\"token punctuation\">.</span>replace<span class=\"token punctuation\">(</span><span class=\"token string\">\"\\n\"</span><span class=\"token punctuation\">,</span><span class=\"token string\">\"\"</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">if</span> <span class=\"token string\">'scat'</span> <span class=\"token keyword\">in</span> data<span class=\"token punctuation\">[</span><span class=\"token string\">'req'</span><span class=\"token punctuation\">]</span> <span class=\"token keyword\">and</span> <span class=\"token string\">'acts'</span> <span class=\"token keyword\">in</span> data<span class=\"token punctuation\">[</span><span class=\"token string\">\"req\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"scat\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">for</span> act <span class=\"token keyword\">in</span> data<span class=\"token punctuation\">[</span><span class=\"token string\">\"req\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"scat\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">[</span><span class=\"token string\">\"acts\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"\\t [\"</span><span class=\"token punctuation\">,</span> act<span class=\"token punctuation\">,</span> <span class=\"token string\">\"]\"</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">print</span><span class=\"token punctuation\">(</span><span class=\"token string\">\"\"</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token comment\"># Example notification object</span>\n<span class=\"token punctuation\">{</span>\n    <span class=\"token string\">'styl'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'intl'</span><span class=\"token punctuation\">:</span> <span class=\"token boolean\">True</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'app'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'_SYSTEM_CENTER_:com.apple.DiskArbitration.DiskArbitrationAgent'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'uuid'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'(binary string)'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'resp'</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">'act'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'for'</span><span class=\"token punctuation\">:</span> <span class=\"token boolean\">True</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'srce'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'(binary string)'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'req'</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">'atta'</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">{</span>\n            <span class=\"token string\">'pur'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'fam'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'uti'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'public.image'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'nsst'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'pat'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/FinderIcon.icns'</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'body'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'Eject “Install macOS Mojave” before disconnecting or turning it off.'</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'nsdict'</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">'nsper'</span><span class=\"token punctuation\">:</span> <span class=\"token boolean\">False</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'ddac'</span><span class=\"token punctuation\">:</span> <span class=\"token boolean\">False</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'scat'</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">'id'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'LEGACY'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'opt'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">132</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'un_ha'</span><span class=\"token punctuation\">:</span> <span class=\"token boolean\">False</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'titl'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'Disk Not Ejected Properly'</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'date'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">631718723.800089</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'orig'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">4</span>\n<span class=\"token punctuation\">}</span> \n\n<span class=\"token punctuation\">{</span>\n    <span class=\"token string\">'styl'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">1</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'intl'</span><span class=\"token punctuation\">:</span> <span class=\"token boolean\">True</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'app'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'com.apple.Music'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'uuid'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'binary string'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'resp'</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">'act'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'for'</span><span class=\"token punctuation\">:</span> <span class=\"token boolean\">True</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'srce'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'binary string'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'req'</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n        <span class=\"token string\">'atta'</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">{</span>\n            <span class=\"token string\">'data'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'(png)'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'fam'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">0</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'uti'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'public.image'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'pur'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">0</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'usda'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'(bplist)'</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'ddac'</span><span class=\"token punctuation\">:</span> <span class=\"token boolean\">False</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'scat'</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">{</span>\n            <span class=\"token string\">'id'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'LEGACY'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'opt'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">148</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'acts'</span><span class=\"token punctuation\">:</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">{</span>\n                <span class=\"token string\">'id'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'ACTION'</span><span class=\"token punctuation\">,</span>\n                <span class=\"token string\">'ti'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'Skip'</span>\n            <span class=\"token punctuation\">}</span><span class=\"token punctuation\">]</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'titl'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'Where I Belong'</span><span class=\"token punctuation\">,</span>\n        <span class=\"token string\">'subt'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'Protostar &amp; Emma McGann — Monstercat Instinct Vol. 5'</span>\n    <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'date'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">652922977.088903</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'orig'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">4</span>\n<span class=\"token punctuation\">}</span></code></pre>\n",
      "date_published": "2021-09-10T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2021-09-10-hello-world/",
      "url": "https://eth0fox.net/notes/2021-09-10-hello-world/",
      "title": "Hello, world!",
      "content_html": "<p>I intend to put notes, random code snippets, whatever here.</p>\n",
      "date_published": "2021-09-10T00:00:00Z"
    }
    ,
    {
      "id": "https://eth0fox.net/notes/2021-08-19-discord-rpc-documentation/",
      "url": "https://eth0fox.net/notes/2021-08-19-discord-rpc-documentation/",
      "title": "Discord RPC Protocol Documentation",
      "content_html": "<p>This is an unofficial documentation on the Discord IPC format. It was made byadding numerous console.log statements to the NPM module discord-rpc.</p>\n<h2 id=\"data-types\">Data types</h2>\n<h3 id=\"packets\">Packets</h3>\n<p>Packets are sent in a simple format, an 8-byte header, consisting of 2 32-bit unsigned ints (little-endian), first one being the opcode, second being the length of the JSON string, then the JSON string.</p>\n<p>An example HANDSHAKE packet is:</p>\n<pre><code>00000000  28000000 7B2276223A312C22 (trimmed)\n^^^^^^^^  ^^^^^^^^ ^^^^^^^^^^^^^^^^\nOPCODE 0   Length     JSON Data\nHANDSHAKE 40bytes  { &quot; v &quot; : 1 , &quot; \n</code></pre>\n<h3 id=\"opcodes\">Opcodes</h3>\n<p>Valid opcodes are</p>\n<table>\n<thead>\n<tr>\n<th>Value</th>\n<th><strong>Name</strong></th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code>0x0000</code></td>\n<td><code>HANDSHAKE</code></td>\n<td>This should be sent immediately after connecting. See the <strong>Connecting to IPC</strong> section for more information.</td>\n</tr>\n<tr>\n<td><code>0x0001</code></td>\n<td><code>FRAME</code></td>\n<td>This is the main payload for indicating most types of data you will send back and forth. The JSON data will be a command.</td>\n</tr>\n<tr>\n<td><code>0x0002</code></td>\n<td><code>CLOSE</code></td>\n<td>This is sent when the Discord client is asking you to leave, or you want to gracefully disconnect.</td>\n</tr>\n<tr>\n<td><code>0x0003</code></td>\n<td><code>PING</code></td>\n<td>This acts as an echo command. If you send this, you will recieve the data supplied with it back from the Discord client.<br>If the Discord client sends this to you, you should reply with a <code>PONG</code> of the same data</td>\n</tr>\n<tr>\n<td><code>0x0004</code></td>\n<td><code>PONG</code></td>\n<td>See <code>PING</code></td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"commands\">Commands</h3>\n<p>Commands are mostly request/response based, however some events (such as READY) do not have an originating request, sent with a <code>FRAME</code> packet. They are a JSON string in the following format:</p>\n<pre class=\"language-typescript\"><code class=\"language-typescript\"><span class=\"token comment\">// This defines a message sent from your app to Discord.</span>\n<span class=\"token keyword\">interface</span> <span class=\"token class-name\">DiscordIPCCommandOutgoing</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// The command ID of this request.</span>\n    cmd<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n    <span class=\"token comment\">// The unique ID of this request, a response will be sent with the matching ID.</span>\n    nonce<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n    <span class=\"token comment\">// The arguments of this request.</span>\n    args<span class=\"token operator\">:</span> object<span class=\"token punctuation\">;</span>\n    <span class=\"token comment\">// Events with 'cmd' 'SUBSCRIBE' will have an 'event' parameter defining the name of the event (e.g. MESSAGE_CREATE)</span>\n    evt<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token comment\">// This defines a message coming from Discord into your app.</span>\n<span class=\"token keyword\">interface</span> <span class=\"token class-name\">DiscordIPCCommandIncoming</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token comment\">// The command ID of this response.</span>\n    cmd<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n    <span class=\"token comment\">// The unique ID of the request that triggered this response.</span>\n    nonce<span class=\"token operator\">:</span> <span class=\"token builtin\">string</span> <span class=\"token operator\">|</span> <span class=\"token keyword\">null</span><span class=\"token punctuation\">;</span>\n    <span class=\"token comment\">// The arguments of the request that triggered this response.</span>\n    args<span class=\"token operator\">?</span><span class=\"token operator\">:</span> object<span class=\"token punctuation\">;</span>\n    <span class=\"token comment\">// The payload of this response</span>\n    data<span class=\"token operator\">:</span> object<span class=\"token punctuation\">;</span>\n    <span class=\"token comment\">// The type of event this is.</span>\n    evt<span class=\"token operator\">?</span><span class=\"token operator\">:</span> <span class=\"token builtin\">string</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre>\n<p>Valid <code>cmd</code>s are: <code>DISPATCH</code>,  <code>AUTHORIZE</code>,  <code>AUTHENTICATE</code>,  <code>GET_GUILD</code>,  <code>GET_GUILDS</code>,  <code>GET_CHANNEL</code>,  <code>GET_CHANNELS</code>,  <code>CREATE_CHANNEL_INVITE</code>,  <code>GET_RELATIONSHIPS</code>,  <code>GET_USER</code>,  <code>SUBSCRIBE</code>,  <code>UNSUBSCRIBE</code>,  <code>SET_USER_VOICE_SETTINGS</code>,  <code>SET_USER_VOICE_SETTINGS_2</code>,  <code>SELECT_VOICE_CHANNEL</code>,  <code>GET_SELECTED_VOICE_CHANNEL</code>,  <code>SELECT_TEXT_CHANNEL</code>,  <code>GET_VOICE_SETTINGS</code>,  <code>SET_VOICE_SETTINGS_2</code>,  <code>SET_VOICE_SETTINGS</code>,  <code>CAPTURE_SHORTCUT</code>,  <code>SET_ACTIVITY</code>,  <code>SEND_ACTIVITY_JOIN_INVITE</code>,  <code>CLOSE_ACTIVITY_JOIN_REQUEST</code>,  <code>ACTIVITY_INVITE_USER</code>,  <code>ACCEPT_ACTIVITY_INVITE</code>,  <code>INVITE_BROWSER</code>,  <code>DEEP_LINK</code>,  <code>CONNECTIONS_CALLBACK</code>,  <code>BRAINTREE_POPUP_BRIDGE_CALLBACK</code>,  <code>GIFT_CODE_BROWSER</code>,  <code>GUILD_TEMPLATE_BROWSER</code>,  <code>OVERLAY</code>,  <code>BROWSER_HANDOFF</code>,  <code>SET_CERTIFIED_DEVICES</code>,  <code>GET_IMAGE</code>,  <code>CREATE_LOBBY</code>,  <code>UPDATE_LOBBY</code>,  <code>DELETE_LOBBY</code>,  <code>UPDATE_LOBBY_MEMBER</code>,  <code>CONNECT_TO_LOBBY</code>,  <code>DISCONNECT_FROM_LOBBY</code>,  <code>SEND_TO_LOBBY</code>,  <code>SEARCH_LOBBIES</code>,  <code>CONNECT_TO_LOBBY_VOICE</code>,  <code>DISCONNECT_FROM_LOBBY_VOICE</code>,  <code>SET_OVERLAY_LOCKED</code>,  <code>OPEN_OVERLAY_ACTIVITY_INVITE</code>,  <code>OPEN_OVERLAY_GUILD_INVITE</code>,  <code>OPEN_OVERLAY_VOICE_SETTINGS</code>,  <code>VALIDATE_APPLICATION</code>,  <code>GET_ENTITLEMENT_TICKET</code>,  <code>GET_APPLICATION_TICKET</code>,  <code>START_PURCHASE</code>,  <code>GET_SKUS</code>,  <code>GET_ENTITLEMENTS</code>,  <code>GET_NETWORKING_CONFIG</code>,  <code>NETWORKING_SYSTEM_METRICS</code>,  <code>NETWORKING_PEER_METRICS</code>,  <code>NETWORKING_CREATE_TOKEN</code>,  <code>SET_USER_ACHIEVEMENT</code>,  <code>GET_USER_ACHIEVEMENTS</code>.</p>\n<p>Valid  <code>evt</code>s are: <code>CURRENT_USER_UPDATE</code>,  <code>GUILD_STATUS</code>,  <code>GUILD_CREATE</code>,  <code>CHANNEL_CREATE</code>,  <code>RELATIONSHIP_UPDATE</code>,  <code>VOICE_CHANNEL_SELECT</code>,  <code>VOICE_STATE_CREATE</code>,  <code>VOICE_STATE_DELETE</code>,  <code>VOICE_STATE_UPDATE</code>,  <code>VOICE_SETTINGS_UPDATE</code>,  <code>VOICE_SETTINGS_UPDATE_2</code>,  <code>VOICE_CONNECTION_STATUS</code>,  <code>SPEAKING_START</code>,  <code>SPEAKING_STOP</code>,  <code>GAME_JOIN</code>,  <code>GAME_SPECTATE</code>,  <code>ACTIVITY_JOIN</code>,  <code>ACTIVITY_JOIN_REQUEST</code>,  <code>ACTIVITY_SPECTATE</code>,  <code>ACTIVITY_INVITE</code>,  <code>NOTIFICATION_CREATE</code>,  <code>MESSAGE_CREATE</code>,  <code>MESSAGE_UPDATE</code>,  <code>MESSAGE_DELETE</code>,  <code>LOBBY_DELETE</code>,  <code>LOBBY_UPDATE</code>,  <code>LOBBY_MEMBER_CONNECT</code>,  <code>LOBBY_MEMBER_DISCONNECT</code>,  <code>LOBBY_MEMBER_UPDATE</code>,  <code>LOBBY_MESSAGE</code>,  <code>CAPTURE_SHORTCUT_CHANGE</code>,  <code>OVERLAY</code>,  <code>OVERLAY_UPDATE</code>,  <code>ENTITLEMENT_CREATE</code>,  <code>ENTITLEMENT_DELETE</code>,  <code>USER_ACHIEVEMENT_UPDATE</code>,  <code>READY</code>,  <code>ERROR</code>.</p>\n<h2 id=\"connecting-to-ipc\">Connecting to IPC</h2>\n<h3 id=\"but-where-do-i-connect\">But where do I connect?</h3>\n<p>First of all, you need to find the place where Discord is listening.</p>\n<p>If you're on Windows, named pipes are used, so it is always kept in: <code>\\\\?\\pipe\\</code></p>\n<p>On macOS &amp; Linux, it'll be kept in the folder indicated by the <code>XDG_RUNTIME_DIR</code>, <code>TMPDIR</code>, <code>TMP</code> or <code>TEMP</code> envvars. If none of those exist, use <code>/tmp/</code></p>\n<p>Then, you'll need to find the socket, each Discord client running on the local machine creates it's own socket, with the name 'discord-rpc-' followed by a number, X, from 0-9. You should start with <code>0</code> and increment until you find a working socket, or you exceed 9.</p>\n<p>For example, on my machine the IPC socket is kept at <code>/var/folders/0k/0hsf3q_d7yg94xs01lp9jkbr0000gn/T/discord-ipc-0</code></p>\n<h3 id=\"connecting\">Connecting</h3>\n<p>Connect to the socket and send a packet with opcode <code>0x0001</code>, and data <code>{&quot;v&quot;:1,&quot;client_id&quot;:&quot;XXXXXXXXXXXXXXXXXX&quot;}</code> . The <code>client_id</code> is the numeric Application ID you obtained from https://discord.com/developers/applications. This will authenticate you to the Discord client. You will then recieve a command with <code>{evt: &quot;READY&quot;,  command: &quot;DISPATCH&quot;}</code>. with information about the current User.</p>\n<h1 id=\"error-handling\">Error handling</h1>\n<p>Critical errors (such as protocol or handshake) will be sent as a <code>CLOSE</code> packet, with a JSON object with a numeric code, and human friendly message.<code>{&quot;code&quot;:4000,&quot;message&quot;:&quot;Invalid Client ID&quot;}</code>.</p>\n<p>Critical error codes are:</p>\n<pre><code>  CLOSE_NORMAL: 1000,\n  CLOSE_UNSUPPORTED: 1003,\n  CLOSE_ABNORMAL: 1006,\n  INVALID_CLIENTID: 4000,\n  INVALID_ORIGIN: 4001,\n  RATELIMITED: 4002,\n  TOKEN_REVOKED: 4003,\n  INVALID_VERSION: 4004,\n  INVALID_ENCODING: 4005,\n</code></pre>\n<p>Non-critical errors will be sent as a regular response, but with an evt of <code>ERROR</code> and the data being an object with a numeric code, and human friendly message, such as <code>{&quot;code&quot;:4000,&quot;message&quot;:&quot;Invalid Client ID&quot;}</code>.</p>\n<p>Non critical error codes are:</p>\n<pre><code>  CAPTURE_SHORTCUT_ALREADY_LISTENING: 5004,\n  GET_GUILD_TIMED_OUT: 5002,\n  INVALID_ACTIVITY_JOIN_REQUEST: 4012,\n  INVALID_ACTIVITY_SECRET: 5005,\n  INVALID_CHANNEL: 4005,\n  INVALID_CLIENTID: 4007,\n  INVALID_COMMAND: 4002,\n  INVALID_ENTITLEMENT: 4015,\n  INVALID_EVENT: 4004,\n  INVALID_GIFT_CODE: 4016,\n  INVALID_GUILD: 4003,\n  INVALID_INVITE: 4011,\n  INVALID_LOBBY: 4013,\n  INVALID_LOBBY_SECRET: 4014,\n  INVALID_ORIGIN: 4008,\n  INVALID_PAYLOAD: 4000,\n  INVALID_PERMISSIONS: 4006,\n  INVALID_TOKEN: 4009,\n  INVALID_USER: 4010,\n  LOBBY_FULL: 5007,\n  NO_ELIGIBLE_ACTIVITY: 5006,\n  OAUTH2_ERROR: 5000,\n  PURCHASE_CANCELED: 5008,\n  PURCHASE_ERROR: 5009,\n  RATE_LIMITED: 5011,\n  SELECT_CHANNEL_TIMED_OUT: 5001,\n  SELECT_VOICE_FORCE_REQUIRED: 5003,\n  SERVICE_UNAVAILABLE: 1001,\n  TRANSACTION_ABORTED: 1002,\n  UNAUTHORIZED_FOR_ACHIEVEMENT: 5010,\n  UNKNOWN_ERROR: 1000,\n</code></pre>\n",
      "date_published": "2021-08-19T00:00:00Z"
    }
    
  ]
}