{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "bumblehead",
  "home_page_url": "https://bumblehead.com",
  "feed_url": "https://bumblehead.com/feed.json",
  "description": "Updates and news about creative works, usually involving software programs and web-friendly mediums such as video and image art. Many javascript products featured here run directly in the browser from this site.",
  "icon": "https://bumblehead.com/favicon.ico",
  "favicon": "https://bumblehead.com/favicon.ico",
  "language": "en-US",
  "authors": [{
    "name": "bumble"
  }],
  "items": [{
    "id": "/media/2026-04-04-thu.sh/",
    "url": "https://bumblehead.com/media/2026-04-04-thu.sh/",
    "title": "thu.sh",
    "summary": "thu.sh renders images from audio, font, video, pdf, epub, svg and other files --supporting both kitty and sixel formats.",
    "content_html": "<p><a href=\"assets/img/thu.sh.demo.gif\" title=\"vifm\"><img src=\"assets/img/thu.sh.demo.525.gif\" alt=\"thu.sh\" title=\"vifm\"></a></p>\n<p><a href=\"https://github.com/iambumblehead/thu.sh\" title=\"thu.sh src\">thu.sh</a> renders images from audio, font, video, pdf, epub, svg and other files --supporting both kitty and sixel formats. It detects and uses system commands such as ffmpeg to do this.</p>\n<p>It can be used vifm to provide image previews,</p>\n<p><a href=\"assets/img/thu.sh.vifm.gif\" title=\"vifm+thu.sh\"><img src=\"assets/img/thu.sh.vifm.320.gif\" alt=\"thu.sh+vifm\" title=\"vifm+thu.sh\"></a><a href=\"assets/img/thu.sh.vifm.miller.png\" title=\"vifm+thu.sh, miller\"><img src=\"assets/img/thu.sh.vifm.miller.320.png\" alt=\"thu.sh+vifm+miller\" title=\"vifm+thu.sh, miller\"></a></p>\n",
    "date_published": "2026-04-04T20:59:59-08:00",
    "tags": ["javascript"]
  }, {
    "id": "/blog/2024-10-11-whats-faster/",
    "url": "https://bumblehead.com/blog/2024-10-11-whats-faster/",
    "title": "what's faster",
    "summary": "Interesting benchmarks for writing performance-sensitive javascript. Benchmark's here can be used with node's official benchmark.js scripts.",
    "content_html": "<p><strong>Interesting benchmarks for writing performance-sensitive javascript.</strong> Benchmark&#39;s here can be used with node&#39;s official <a href=\"https://github.com/nodejs/node/blob/main/doc/contributing/writing-and-running-benchmarks.md#basics-of-a-benchmark\">benchmark.js scripts.</a> <strong>The last number is the rate of operations measured in ops/sec (higher is better).</strong></p>\n<p><em>note: node&#39;s common.js benchmark file uses one or two commonjs-specific things and those must be updated before the benchmark will run successfully</em></p>\n<hr>\n<h3>Checking for primitives, use strict equality</h3>\n<details>\n  <summary>primitives-regexp-test-vs-strict-equality</summary><pre><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import</span> common <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">&#x27;../node-v22.9.0/benchmark/common.js&#x27;</span>\n\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">TYPEREGEXPLOOSE</span> = <span class=\"hljs-string\">&#x27;regexp loose&#x27;</span>\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">TYPEREGEXPSTRICT</span> = <span class=\"hljs-string\">&#x27;regexp strict&#x27;</span>\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">TYPEEQUALITY</span> = <span class=\"hljs-string\">&#x27;equality&#x27;</span>\n\n<span class=\"hljs-keyword\">const</span> bench = common.<span class=\"hljs-title function_\">createBenchmark</span>(main, {\n  <span class=\"hljs-attr\">n</span>: [<span class=\"hljs-number\">2000</span>],\n  <span class=\"hljs-attr\">mod</span>: <span class=\"hljs-number\">3</span>,\n  <span class=\"hljs-attr\">type</span>: [\n    <span class=\"hljs-variable constant_\">TYPEREGEXPLOOSE</span>,\n    <span class=\"hljs-variable constant_\">TYPEREGEXPSTRICT</span>,\n    <span class=\"hljs-variable constant_\">TYPEEQUALITY</span>\n  ]\n})\n\n<span class=\"hljs-keyword\">async</span> <span class=\"hljs-keyword\">function</span> <span class=\"hljs-title function_\">main</span>(<span class=\"hljs-params\">conf</span>) {\n  <span class=\"hljs-comment\">// save then return this obj to try bypassing any</span>\n  <span class=\"hljs-comment\">// runtime optimisation identifying this code as unused</span>\n  <span class=\"hljs-keyword\">let</span> obj = <span class=\"hljs-string\">&#x27;&#x27;</span>\n\n  <span class=\"hljs-keyword\">const</span> type = conf.<span class=\"hljs-property\">type</span>\n  <span class=\"hljs-keyword\">const</span> mod = conf.<span class=\"hljs-property\">mod</span>\n  <span class=\"hljs-keyword\">const</span> regexpLooseRe = <span class=\"hljs-regexp\">/string|boolean|number/</span>\n  <span class=\"hljs-keyword\">const</span> regexpStrictRe = <span class=\"hljs-regexp\">/^(string|boolean|number)$/</span>\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-variable constant_\">TYPEREGEXPLOOSE</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>()\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">let</span> i = conf.<span class=\"hljs-property\">n</span>; i--;) {\n      <span class=\"hljs-keyword\">let</span> n = (mod ? i % mod : i)\n      <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">1</span>) n = <span class=\"hljs-literal\">true</span>\n      <span class=\"hljs-keyword\">else</span> <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">2</span>) n = i\n      <span class=\"hljs-keyword\">else</span> n = <span class=\"hljs-string\">&#x27;value&#x27;</span> + i\n\n      obj += regexpLooseRe.<span class=\"hljs-title function_\">test</span>(n)\n    }\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-variable constant_\">TYPEREGEXPSTRICT</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>()\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">let</span> i = conf.<span class=\"hljs-property\">n</span>; i--;) {\n      <span class=\"hljs-keyword\">let</span> n = (mod ? i % mod : i)\n      <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">1</span>) n = <span class=\"hljs-literal\">true</span>\n      <span class=\"hljs-keyword\">else</span> <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">2</span>) n = i\n      <span class=\"hljs-keyword\">else</span> n = <span class=\"hljs-string\">&#x27;value&#x27;</span> + i\n\n      obj += regexpStrictRe.<span class=\"hljs-title function_\">test</span>(<span class=\"hljs-keyword\">typeof</span> n)\n    }\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-variable constant_\">TYPEEQUALITY</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>()\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">let</span> i = conf.<span class=\"hljs-property\">n</span>; i--;) {\n      <span class=\"hljs-keyword\">let</span> n = (mod ? i % mod : i)\n      <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">1</span>) n = <span class=\"hljs-literal\">true</span>\n      <span class=\"hljs-keyword\">else</span> <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">2</span>) n = i\n      <span class=\"hljs-keyword\">else</span> n = <span class=\"hljs-string\">&#x27;value&#x27;</span> + i\n\n      <span class=\"hljs-keyword\">const</span> t = <span class=\"hljs-keyword\">typeof</span> n\n      obj += (t === <span class=\"hljs-string\">&#x27;string&#x27;</span> || t === <span class=\"hljs-string\">&#x27;boolean&#x27;</span> || t === <span class=\"hljs-string\">&#x27;number&#x27;</span>)\n    }\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">return</span> obj\n}\n</code></pre></details><pre><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">isPrimitiveEquality</span> = t =&gt;\n  t === <span class=\"hljs-string\">&#x27;string&#x27;</span> || t === <span class=\"hljs-string\">&#x27;boolean&#x27;</span>\n  || t === <span class=\"hljs-string\">&#x27;number&#x27;</span>\n\n<span class=\"hljs-comment\">// note: tests reuse memoized RegExp</span>\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">isPrimitiveRegExpLoose</span> = t =&gt;\n  <span class=\"hljs-regexp\">/string|boolean|number/</span>.<span class=\"hljs-title function_\">test</span>(t)\n\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">isPrimitiveRegExpStrict</span> = t =&gt;\n  <span class=\"hljs-regexp\">/^(string|boolean|number)$/</span>.<span class=\"hljs-title function_\">test</span>(t)\n</code></pre><table>\n<thead>\n<tr>\n<th>Test</th>\n<th>Ops/sec</th>\n</tr>\n</thead>\n<tbody><tr>\n<td><strong>is primitive equality</strong></td>\n<td><strong>5,455,715.95</strong></td>\n</tr>\n<tr>\n<td>is primitive RegExp, loose</td>\n<td>3,841,802.27</td>\n</tr>\n<tr>\n<td>is primitive RegExp, strict</td>\n<td>3,429,425.85</td>\n</tr>\n</tbody></table>\n<hr>\n<h3>Checking for plain object, use loose strict equality</h3>\n<details>\n  <summary>object-loose-test-vs-strict-equality</summary><pre><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import</span> common <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">&#x27;../node-v22.9.0/benchmark/common.js&#x27;</span>\n\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">TYPEOBJLOOSE</span> = <span class=\"hljs-string\">&#x27;object loose&#x27;</span>\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">TYPEOBJSTRICT</span> = <span class=\"hljs-string\">&#x27;object strict&#x27;</span>\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">TYPEOBJPROTO</span> = <span class=\"hljs-string\">&#x27;object proto&#x27;</span>\n\n<span class=\"hljs-keyword\">const</span> bench = common.<span class=\"hljs-title function_\">createBenchmark</span>(main, {\n  <span class=\"hljs-attr\">n</span>: [<span class=\"hljs-number\">2000</span>],\n  <span class=\"hljs-attr\">mod</span>: <span class=\"hljs-number\">3</span>,\n  <span class=\"hljs-attr\">type</span>: [\n    <span class=\"hljs-variable constant_\">TYPEOBJLOOSE</span>,\n    <span class=\"hljs-variable constant_\">TYPEOBJSTRICT</span>,\n    <span class=\"hljs-variable constant_\">TYPEOBJPROTO</span>\n  ]\n})\n\n<span class=\"hljs-keyword\">async</span> <span class=\"hljs-keyword\">function</span> <span class=\"hljs-title function_\">main</span>(<span class=\"hljs-params\">conf</span>) {\n  <span class=\"hljs-comment\">// save then return this obj to try bypassing any</span>\n  <span class=\"hljs-comment\">// runtime optimisation identifying this code as unused</span>\n  <span class=\"hljs-keyword\">let</span> obj = <span class=\"hljs-string\">&#x27;&#x27;</span>\n\n  <span class=\"hljs-keyword\">const</span> getproto = <span class=\"hljs-title class_\">Object</span>.<span class=\"hljs-property\">getPrototypeOf</span>\n  <span class=\"hljs-keyword\">const</span> proto = <span class=\"hljs-title class_\">Object</span>.<span class=\"hljs-title function_\">getPrototypeOf</span>({})\n  <span class=\"hljs-keyword\">const</span> type = conf.<span class=\"hljs-property\">type</span>\n  <span class=\"hljs-keyword\">const</span> mod = conf.<span class=\"hljs-property\">mod</span>\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-variable constant_\">TYPEOBJLOOSE</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>()\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">let</span> i = conf.<span class=\"hljs-property\">n</span>; i--;) {\n      <span class=\"hljs-keyword\">let</span> n = (mod ? i % mod : i)\n      <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">1</span>) n = { <span class=\"hljs-attr\">anobj</span>: <span class=\"hljs-literal\">true</span> }\n      <span class=\"hljs-keyword\">else</span> <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">2</span>) n = [<span class=\"hljs-string\">&#x27;array&#x27;</span>]\n      <span class=\"hljs-keyword\">else</span> n = <span class=\"hljs-string\">&#x27;value&#x27;</span> + i\n\n      obj += n &amp;&amp; <span class=\"hljs-keyword\">typeof</span> n === <span class=\"hljs-string\">&#x27;object&#x27;</span>\n        &amp;&amp; !<span class=\"hljs-title class_\">Array</span>.<span class=\"hljs-title function_\">isArray</span>(n)\n    }\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-variable constant_\">TYPEOBJSTRICT</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>()\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">let</span> i = conf.<span class=\"hljs-property\">n</span>; i--;) {\n      <span class=\"hljs-keyword\">let</span> n = (mod ? i % mod : i)\n      <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">1</span>) n = { <span class=\"hljs-attr\">anobj</span>: <span class=\"hljs-literal\">true</span> }\n      <span class=\"hljs-keyword\">else</span> <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">2</span>) n = [<span class=\"hljs-string\">&#x27;array&#x27;</span>]\n      <span class=\"hljs-keyword\">else</span> n = <span class=\"hljs-string\">&#x27;value&#x27;</span> + i\n\n      obj += n &amp;&amp; <span class=\"hljs-keyword\">typeof</span> n === <span class=\"hljs-string\">&#x27;object&#x27;</span>\n        &amp;&amp; !<span class=\"hljs-title class_\">Array</span>.<span class=\"hljs-title function_\">isArray</span>(n)\n        &amp;&amp; n <span class=\"hljs-keyword\">instanceof</span> <span class=\"hljs-title class_\">Date</span> === <span class=\"hljs-literal\">false</span>\n        &amp;&amp; n <span class=\"hljs-keyword\">instanceof</span> <span class=\"hljs-title class_\">RegExp</span> === <span class=\"hljs-literal\">false</span>\n    }\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-variable constant_\">TYPEOBJPROTO</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>()\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">let</span> i = conf.<span class=\"hljs-property\">n</span>; i--;) {\n      <span class=\"hljs-keyword\">let</span> n = (mod ? i % mod : i)\n      <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">1</span>) n = { <span class=\"hljs-attr\">anobj</span>: <span class=\"hljs-literal\">true</span> }\n      <span class=\"hljs-keyword\">else</span> <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">2</span>) n = [<span class=\"hljs-string\">&#x27;array&#x27;</span>]\n      <span class=\"hljs-keyword\">else</span> n = <span class=\"hljs-string\">&#x27;value&#x27;</span> + i\n\n      obj += (<span class=\"hljs-title function_\">getproto</span>(n) === proto)\n    }\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">return</span> obj\n}\n</code></pre></details><pre><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">isObjLoose</span> = n =&gt; n\n  &amp;&amp; <span class=\"hljs-keyword\">typeof</span> n === <span class=\"hljs-string\">&#x27;object&#x27;</span>\n  &amp;&amp; !<span class=\"hljs-title class_\">Array</span>.<span class=\"hljs-title function_\">isArray</span>(n)\n\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">isObjStrict</span> = n =&gt; <span class=\"hljs-title function_\">isObjLoose</span>(n)\n  &amp;&amp; n <span class=\"hljs-keyword\">instanceof</span> <span class=\"hljs-title class_\">Date</span> === <span class=\"hljs-literal\">false</span>\n  &amp;&amp; n <span class=\"hljs-keyword\">instanceof</span> <span class=\"hljs-title class_\">RegExp</span> === <span class=\"hljs-literal\">false</span>\n\n<span class=\"hljs-keyword\">const</span> isObjProto = (<span class=\"hljs-function\">(<span class=\"hljs-params\">getp, p = getp({})</span>) =&gt;</span>\n  <span class=\"hljs-function\"><span class=\"hljs-params\">obj</span> =&gt;</span> obj &amp;&amp; (<span class=\"hljs-title function_\">getp</span>(obj) === p)\n)(<span class=\"hljs-title class_\">Object</span>.<span class=\"hljs-property\">getPrototypeOf</span>) <span class=\"hljs-comment\">// slowest</span>\n\n<span class=\"hljs-keyword\">const</span> isObjProtoStr = (<span class=\"hljs-function\">(<span class=\"hljs-params\">toString, str = toString.({})</span>) =&gt;</span>\n  <span class=\"hljs-function\"><span class=\"hljs-params\">obj</span> =&gt;</span> obj &amp;&amp; (<span class=\"hljs-title function_\">toString</span>(obj) === str)\n)(<span class=\"hljs-title class_\">Object</span>.<span class=\"hljs-property\"><span class=\"hljs-keyword\">prototype</span></span>.<span class=\"hljs-property\">toString</span>)\n</code></pre><table>\n<thead>\n<tr>\n<th>Test</th>\n<th>Ops/sec</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>is object, loose</td>\n<td>2,709,289.20</td>\n</tr>\n<tr>\n<td><strong>is object, strict</strong></td>\n<td><strong>2,751,311.69</strong></td>\n</tr>\n<tr>\n<td>is object, proto</td>\n<td>2,631,139.27</td>\n</tr>\n<tr>\n<td>is object, proto str</td>\n<td>2,313,421.13</td>\n</tr>\n</tbody></table>\n<hr>\n<h3>Replacing a matched end character, use endsWith</h3>\n<details>\n  <summary>remove-endslash-regexp-vs-char</summary><pre><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import</span> common <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">&#x27;../node-v22.9.0/benchmark/common.js&#x27;</span>\n\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">TYPEREGEXP</span> = <span class=\"hljs-string\">&#x27;regexp&#x27;</span>\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">TYPEENDSWITH</span> = <span class=\"hljs-string\">&#x27;endsWith&#x27;</span>\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">TYPECHARAT</span> = <span class=\"hljs-string\">&#x27;charAt&#x27;</span>\n\n<span class=\"hljs-keyword\">const</span> bench = common.<span class=\"hljs-title function_\">createBenchmark</span>(main, {\n  <span class=\"hljs-attr\">n</span>: [<span class=\"hljs-number\">2000</span>],\n  <span class=\"hljs-attr\">mod</span>: <span class=\"hljs-number\">3</span>,\n  <span class=\"hljs-attr\">type</span>: [\n    <span class=\"hljs-variable constant_\">TYPEREGEXP</span>,\n    <span class=\"hljs-variable constant_\">TYPEENDSWITH</span>,\n    <span class=\"hljs-variable constant_\">TYPECHARAT</span>\n  ]\n})\n\n<span class=\"hljs-keyword\">async</span> <span class=\"hljs-keyword\">function</span> <span class=\"hljs-title function_\">main</span>(<span class=\"hljs-params\">conf</span>) {\n  <span class=\"hljs-comment\">// save then return this obj to try bypassing any</span>\n  <span class=\"hljs-comment\">// runtime optimisation identifying this code as unused</span>\n  <span class=\"hljs-keyword\">let</span> obj = <span class=\"hljs-string\">&#x27;&#x27;</span>\n\n  <span class=\"hljs-keyword\">const</span> type = conf.<span class=\"hljs-property\">type</span>\n  <span class=\"hljs-keyword\">const</span> mod = conf.<span class=\"hljs-property\">mod</span>\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-variable constant_\">TYPEREGEXP</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>()\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">let</span> i = conf.<span class=\"hljs-property\">n</span>; i--;) {\n      <span class=\"hljs-keyword\">let</span> n = (mod ? i % mod : i)\n      <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">1</span>) n = <span class=\"hljs-string\">&#x27;stringwith/&#x27;</span>\n      <span class=\"hljs-keyword\">else</span> <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">2</span>) n = <span class=\"hljs-string\">&#x27;stringwithout&#x27;</span>\n      <span class=\"hljs-keyword\">else</span> n = <span class=\"hljs-string\">&#x27;value&#x27;</span> + i\n\n      obj += n.<span class=\"hljs-title function_\">replace</span>(<span class=\"hljs-regexp\">/\\/$/</span>, <span class=\"hljs-string\">&#x27;&#x27;</span>)\n    }\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-variable constant_\">TYPECHARAT</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>()\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">let</span> i = conf.<span class=\"hljs-property\">n</span>; i--;) {\n      <span class=\"hljs-keyword\">let</span> n = (mod ? i % mod : i)\n      <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">1</span>) n = <span class=\"hljs-string\">&#x27;stringwith/&#x27;</span>\n      <span class=\"hljs-keyword\">else</span> <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">2</span>) n = <span class=\"hljs-string\">&#x27;stringwithout&#x27;</span>\n      <span class=\"hljs-keyword\">else</span> n = <span class=\"hljs-string\">&#x27;value&#x27;</span> + i\n\n      obj += n.<span class=\"hljs-title function_\">endsWith</span>(<span class=\"hljs-string\">&#x27;/&#x27;</span>) ? n.<span class=\"hljs-title function_\">slice</span>(<span class=\"hljs-number\">0</span>, -<span class=\"hljs-number\">1</span>) : n\n    }\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-variable constant_\">TYPEENDSWITH</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>()\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">let</span> i = conf.<span class=\"hljs-property\">n</span>; i--;) {\n      <span class=\"hljs-keyword\">let</span> n = (mod ? i % mod : i)\n      <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">1</span>) n = <span class=\"hljs-string\">&#x27;stringwith/&#x27;</span>\n      <span class=\"hljs-keyword\">else</span> <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">2</span>) n = <span class=\"hljs-string\">&#x27;stringwithout&#x27;</span>\n      <span class=\"hljs-keyword\">else</span> n = <span class=\"hljs-string\">&#x27;value&#x27;</span> + i\n\n      obj += n.<span class=\"hljs-title function_\">charCodeAt</span>(n.<span class=\"hljs-property\">length</span> - <span class=\"hljs-number\">1</span>) === <span class=\"hljs-number\">47</span> ? n.<span class=\"hljs-title function_\">slice</span>(<span class=\"hljs-number\">0</span>, -<span class=\"hljs-number\">1</span>) : n\n    }\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">return</span> obj\n}\n</code></pre></details><pre><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">removeEndSlashRegExp</span> = n =&gt;\n  n.<span class=\"hljs-title function_\">replace</span>(<span class=\"hljs-regexp\">/\\/$/</span>, <span class=\"hljs-string\">&#x27;&#x27;</span>)\n\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">removeEndSlashEndsWith</span> = n =&gt;\n  n.<span class=\"hljs-title function_\">endsWith</span>(<span class=\"hljs-string\">&#x27;/&#x27;</span>) ? n.<span class=\"hljs-title function_\">slice</span>(<span class=\"hljs-number\">0</span>, -<span class=\"hljs-number\">1</span>) : n\n\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">removeEndSlashCharAt</span> = n =&gt;\n  n.<span class=\"hljs-title function_\">charCodeAt</span>(n.<span class=\"hljs-property\">length</span> - <span class=\"hljs-number\">1</span>) === <span class=\"hljs-number\">47</span>\n    ? n.<span class=\"hljs-title function_\">slice</span>(<span class=\"hljs-number\">0</span>, -<span class=\"hljs-number\">1</span>) : n\n</code></pre><table>\n<thead>\n<tr>\n<th>Test</th>\n<th>Ops/sec</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>remove end slash, RegExp</td>\n<td>1,333,148.47</td>\n</tr>\n<tr>\n<td><strong>remove end slash, endsWith</strong></td>\n<td><strong>3,982,025.14</strong></td>\n</tr>\n<tr>\n<td>remove end slahs, charCodeAt</td>\n<td>3,822,301.22</td>\n</tr>\n</tbody></table>\n<hr>\n<h3>Checking if property in object</h3>\n<details>\n  <summary>property-in-vs-property-lookup</summary><pre><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import</span> common <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">&#x27;../node-v22.9.0/benchmark/common.js&#x27;</span>\n\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">TYPELOOKUP</span> = <span class=\"hljs-string\">&#x27;exists lookup&#x27;</span>\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">TYPEINOBJ</span> = <span class=\"hljs-string\">&#x27;exists in obj&#x27;</span>\n\n<span class=\"hljs-keyword\">const</span> bench = common.<span class=\"hljs-title function_\">createBenchmark</span>(main, {\n  <span class=\"hljs-attr\">n</span>: [<span class=\"hljs-number\">4000</span>],\n  <span class=\"hljs-attr\">mod</span>: <span class=\"hljs-number\">3</span>,\n  <span class=\"hljs-attr\">type</span>: [\n    <span class=\"hljs-variable constant_\">TYPELOOKUP</span>,\n    <span class=\"hljs-variable constant_\">TYPEINOBJ</span>\n  ]\n})\n\n<span class=\"hljs-keyword\">async</span> <span class=\"hljs-keyword\">function</span> <span class=\"hljs-title function_\">main</span>(<span class=\"hljs-params\">conf</span>) {\n  <span class=\"hljs-comment\">// save then return this obj to try bypassing any</span>\n  <span class=\"hljs-comment\">// runtime optimisation identifying this code as unused</span>\n  <span class=\"hljs-keyword\">let</span> obj = <span class=\"hljs-string\">&#x27;&#x27;</span>\n\n  <span class=\"hljs-keyword\">const</span> type = conf.<span class=\"hljs-property\">type</span>\n  <span class=\"hljs-keyword\">const</span> mod = conf.<span class=\"hljs-property\">mod</span>\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-variable constant_\">TYPELOOKUP</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>()\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">let</span> i = conf.<span class=\"hljs-property\">n</span>; i--;) {\n      <span class=\"hljs-keyword\">let</span> n = (mod ? i % mod : i)\n      <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">1</span>) n = { <span class=\"hljs-attr\">anobj</span>: <span class=\"hljs-literal\">true</span> }\n      <span class=\"hljs-keyword\">else</span> <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">2</span>) n = [<span class=\"hljs-string\">&#x27;array&#x27;</span>]\n      <span class=\"hljs-keyword\">else</span> n = {}\n\n      obj += n[<span class=\"hljs-string\">&#x27;anobj&#x27;</span>]\n    }\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-variable constant_\">TYPEINOBJ</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>()\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">let</span> i = conf.<span class=\"hljs-property\">n</span>; i--;) {\n      <span class=\"hljs-keyword\">let</span> n = (mod ? i % mod : i)\n      <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">1</span>) n = { <span class=\"hljs-attr\">anobj</span>: <span class=\"hljs-literal\">true</span> }\n      <span class=\"hljs-keyword\">else</span> <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">2</span>) n = [<span class=\"hljs-string\">&#x27;array&#x27;</span>]\n      <span class=\"hljs-keyword\">else</span> n = {}\n\n      obj += <span class=\"hljs-string\">&#x27;anobj&#x27;</span> <span class=\"hljs-keyword\">in</span> n\n    }\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">return</span> obj\n}\n</code></pre></details><pre><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">propertyIn</span> = obj =&gt;\n  <span class=\"hljs-string\">&#x27;property&#x27;</span> <span class=\"hljs-keyword\">in</span> obj\n\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">propertyLookup</span> = obj =&gt;\n  obj[<span class=\"hljs-string\">&#x27;property&#x27;</span>]\n</code></pre><table>\n<thead>\n<tr>\n<th>Test</th>\n<th>Ops/sec</th>\n</tr>\n</thead>\n<tbody><tr>\n<td>property in obj</td>\n<td>2,281,780.50</td>\n</tr>\n<tr>\n<td><strong>obj[property]</strong></td>\n<td><strong>3,030,011.51</strong></td>\n</tr>\n</tbody></table>\n<hr>\n<h3>Array destructuring vs array lookup</h3>\n<details>\n  <summary>array-destructure-vs-array-lookup</summary><pre><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import</span> common <span class=\"hljs-keyword\">from</span> <span class=\"hljs-string\">&#x27;../node-v22.9.0/benchmark/common.js&#x27;</span>\n\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">TYPEDESTRUCTURE</span> = <span class=\"hljs-string\">&#x27;destructure&#x27;</span>\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-variable constant_\">TYPELOOKUP</span> = <span class=\"hljs-string\">&#x27;lookup&#x27;</span>\n\n<span class=\"hljs-keyword\">const</span> bench = common.<span class=\"hljs-title function_\">createBenchmark</span>(main, {\n  <span class=\"hljs-attr\">n</span>: [<span class=\"hljs-number\">2000</span>],\n  <span class=\"hljs-attr\">mod</span>: <span class=\"hljs-number\">3</span>,\n  <span class=\"hljs-attr\">type</span>: [\n    <span class=\"hljs-variable constant_\">TYPEDESTRUCTURE</span>,\n    <span class=\"hljs-variable constant_\">TYPELOOKUP</span>\n  ]\n})\n\n<span class=\"hljs-keyword\">async</span> <span class=\"hljs-keyword\">function</span> <span class=\"hljs-title function_\">main</span>(<span class=\"hljs-params\">conf</span>) {\n  <span class=\"hljs-comment\">// save then return this obj to try bypassing any</span>\n  <span class=\"hljs-comment\">// runtime optimisation identifying this code as unused</span>\n  <span class=\"hljs-keyword\">let</span> obj = <span class=\"hljs-string\">&#x27;&#x27;</span>\n\n  <span class=\"hljs-keyword\">const</span> type = conf.<span class=\"hljs-property\">type</span>\n  <span class=\"hljs-keyword\">const</span> mod = conf.<span class=\"hljs-property\">mod</span>\n\n  <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">arrayLookup</span> = arr =&gt; {\n    <span class=\"hljs-keyword\">const</span> val0 = arr[<span class=\"hljs-number\">0</span>]\n    <span class=\"hljs-keyword\">const</span> val1 = arr[<span class=\"hljs-number\">1</span>]\n    <span class=\"hljs-keyword\">const</span> val2 = arr[<span class=\"hljs-number\">2</span>]\n\n    <span class=\"hljs-keyword\">return</span> val1 + val0 + val2\n  }\n\n  <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">arrayDestructure</span> = arr =&gt; {\n    <span class=\"hljs-keyword\">const</span> [val0, val1, val2] = arr\n\n    <span class=\"hljs-keyword\">return</span> val1 + val0 + val2\n  }\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-variable constant_\">TYPELOOKUP</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>()\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">let</span> i = conf.<span class=\"hljs-property\">n</span>; i--;) {\n      <span class=\"hljs-keyword\">let</span> n = (mod ? i % mod : i)\n      <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">1</span>) n = [<span class=\"hljs-string\">&#x27;arg&#x27;</span> + n, n, i]\n      <span class=\"hljs-keyword\">else</span> <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">2</span>) n = [<span class=\"hljs-string\">&#x27;arg&#x27;</span> + n, i, n]\n      <span class=\"hljs-keyword\">else</span> n = [<span class=\"hljs-string\">&#x27;value&#x27;</span> + i, i, i]\n\n      obj += <span class=\"hljs-title function_\">arrayLookup</span>(n)\n    }\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-variable constant_\">TYPEDESTRUCTURE</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>()\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">let</span> i = conf.<span class=\"hljs-property\">n</span>; i--;) {\n      <span class=\"hljs-keyword\">let</span> n = (mod ? i % mod : i)\n      <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">1</span>) n = [<span class=\"hljs-string\">&#x27;arg&#x27;</span> + n, n, i]\n      <span class=\"hljs-keyword\">else</span> <span class=\"hljs-keyword\">if</span> (n === <span class=\"hljs-number\">2</span>) n = [<span class=\"hljs-string\">&#x27;arg&#x27;</span> + n, i, n]\n      <span class=\"hljs-keyword\">else</span> n = [<span class=\"hljs-string\">&#x27;value&#x27;</span> + i, i, i]\n\n      obj += <span class=\"hljs-title function_\">arrayDestructure</span>(n)\n    }\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">return</span> obj\n}\n</code></pre></details><pre><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">arrayLookup</span> = arr =&gt; {\n  <span class=\"hljs-keyword\">const</span> val0 = arr[<span class=\"hljs-number\">0</span>]\n  <span class=\"hljs-keyword\">const</span> val1 = arr[<span class=\"hljs-number\">1</span>]\n  <span class=\"hljs-keyword\">const</span> val2 = arr[<span class=\"hljs-number\">2</span>]\n\n  <span class=\"hljs-keyword\">return</span> val1 + val0 + val2\n}\n\n<span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">arrayDestructure</span> = arr =&gt; {\n  <span class=\"hljs-keyword\">const</span> [val0, val1, val2] = arr\n\n  <span class=\"hljs-keyword\">return</span> val1 + val0 + val2\n}\n</code></pre><table>\n<thead>\n<tr>\n<th>Test</th>\n<th>Ops/sec</th>\n</tr>\n</thead>\n<tbody><tr>\n<td><strong>array lookup</strong></td>\n<td><strong>1,200,048.00</strong></td>\n</tr>\n<tr>\n<td>array destructure</td>\n<td>708,328.67</td>\n</tr>\n</tbody></table>\n",
    "date_published": "2024-10-11T20:12:16-08:00",
    "tags": ["software"]
  }, {
    "id": "/blog/2024-09-21-callbacks-win/",
    "url": "https://bumblehead.com/blog/2024-09-21-callbacks-win/",
    "title": "callbacks win",
    "summary": "callbacks win",
    "content_html": "<p><strong>Javascript callbacks are faster than async-await.</strong></p>\n<p>This benchmark can be used with node&#39;s official <a href=\"https://github.com/nodejs/node/blob/main/doc/contributing/writing-and-running-benchmarks.md#basics-of-a-benchmark\">benchmark.js scripts</a> <strong>The last number is the rate of operations measured in ops/sec (higher is better).</strong></p>\n<details>\n  <summary>async-vs-cb.nested-benchmark.js</summary><pre><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">const</span> common = <span class=\"hljs-built_in\">require</span>(<span class=\"hljs-string\">&#x27;./node/benchmark/common.js&#x27;</span>);\n\n<span class=\"hljs-keyword\">const</span> bench = common.<span class=\"hljs-title function_\">createBenchmark</span>(main, {\n  <span class=\"hljs-attr\">n</span>: [ <span class=\"hljs-number\">1400</span> ],\n  <span class=\"hljs-attr\">type</span>: [ <span class=\"hljs-string\">&#x27;await-deep&#x27;</span>, <span class=\"hljs-string\">&#x27;await-shallow&#x27;</span>, <span class=\"hljs-string\">&#x27;cb-deep&#x27;</span>, <span class=\"hljs-string\">&#x27;cb-deep-promisified&#x27;</span> ]\n});\n\n<span class=\"hljs-keyword\">async</span> <span class=\"hljs-keyword\">function</span> <span class=\"hljs-title function_\">main</span>(<span class=\"hljs-params\">conf</span>) {\n  <span class=\"hljs-keyword\">let</span> res = <span class=\"hljs-title class_\">Math</span>.<span class=\"hljs-title function_\">random</span>()\n\n  <span class=\"hljs-keyword\">const</span> string = conf.<span class=\"hljs-property\">string</span>\n  <span class=\"hljs-keyword\">const</span> type = conf.<span class=\"hljs-property\">type</span>\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-string\">&#x27;await-deep&#x27;</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>();\n    res = <span class=\"hljs-title function_\">await</span> (<span class=\"hljs-keyword\">async</span> <span class=\"hljs-keyword\">function</span> <span class=\"hljs-title function_\">nestedAsync</span> (<span class=\"hljs-params\">val, count</span>) {\n      <span class=\"hljs-keyword\">if</span> (!count--) <span class=\"hljs-keyword\">return</span> val\n\n      <span class=\"hljs-keyword\">return</span> <span class=\"hljs-title function_\">nestedAsync</span>(<span class=\"hljs-title class_\">Math</span>.<span class=\"hljs-title function_\">random</span>() &gt; <span class=\"hljs-title class_\">Math</span>.<span class=\"hljs-title function_\">random</span>() ? <span class=\"hljs-number\">1</span> : -<span class=\"hljs-number\">1</span>, count)\n    })(<span class=\"hljs-title class_\">Math</span>.<span class=\"hljs-title function_\">random</span>(), conf.<span class=\"hljs-property\">n</span>)\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>);\n  }\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-string\">&#x27;await-shallow&#x27;</span>) {\n    <span class=\"hljs-keyword\">const</span> arr = <span class=\"hljs-title class_\">Array</span>.<span class=\"hljs-title function_\">from</span>({<span class=\"hljs-attr\">length</span>: conf.<span class=\"hljs-property\">n</span>}, <span class=\"hljs-function\">(<span class=\"hljs-params\">v, i</span>) =&gt;</span> i)\n    <span class=\"hljs-keyword\">const</span> <span class=\"hljs-title function_\">oneAsyncRes</span> = <span class=\"hljs-keyword\">async</span> (<span class=\"hljs-params\">val, count</span>) =&gt; (\n      count + <span class=\"hljs-title class_\">Math</span>.<span class=\"hljs-title function_\">random</span>() &gt; <span class=\"hljs-title class_\">Math</span>.<span class=\"hljs-title function_\">random</span>() ? <span class=\"hljs-number\">1</span> : -<span class=\"hljs-number\">1</span>)\n    \n    bench.<span class=\"hljs-title function_\">start</span>();\n    <span class=\"hljs-keyword\">for</span> (<span class=\"hljs-keyword\">const</span> n <span class=\"hljs-keyword\">of</span> arr)\n      res = <span class=\"hljs-keyword\">await</span> <span class=\"hljs-title function_\">oneAsyncRes</span>(n, res)\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>);\n  }\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-string\">&#x27;cb-deep&#x27;</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>();\n    (<span class=\"hljs-keyword\">function</span> <span class=\"hljs-title function_\">nestedCb</span>(<span class=\"hljs-params\">val, count, cb</span>) {\n      <span class=\"hljs-keyword\">if</span> (!count--) <span class=\"hljs-keyword\">return</span> <span class=\"hljs-title function_\">cb</span>(<span class=\"hljs-literal\">null</span>, val)\n\n      <span class=\"hljs-keyword\">return</span> <span class=\"hljs-title function_\">nestedCb</span>(<span class=\"hljs-title class_\">Math</span>.<span class=\"hljs-title function_\">random</span>() &gt; <span class=\"hljs-title class_\">Math</span>.<span class=\"hljs-title function_\">random</span>() ? <span class=\"hljs-number\">1</span> : -<span class=\"hljs-number\">1</span>, count, cb)\n    })(<span class=\"hljs-title class_\">Math</span>.<span class=\"hljs-title function_\">random</span>(), conf.<span class=\"hljs-property\">n</span>, <span class=\"hljs-function\">(<span class=\"hljs-params\">err, res</span>) =&gt;</span> {\n      bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n    })\n  }\n\n  <span class=\"hljs-keyword\">if</span> (type === <span class=\"hljs-string\">&#x27;cb-deep-promisified&#x27;</span>) {\n    bench.<span class=\"hljs-title function_\">start</span>();\n    <span class=\"hljs-keyword\">const</span> res = <span class=\"hljs-keyword\">await</span> <span class=\"hljs-keyword\">new</span> <span class=\"hljs-title class_\">Promise</span>(<span class=\"hljs-function\"><span class=\"hljs-params\">resolve</span> =&gt;</span> (\n      (<span class=\"hljs-keyword\">function</span> <span class=\"hljs-title function_\">nestedCb</span>(<span class=\"hljs-params\">val, count, cb</span>) {\n        <span class=\"hljs-keyword\">if</span> (!count--) <span class=\"hljs-keyword\">return</span> <span class=\"hljs-title function_\">cb</span>(<span class=\"hljs-literal\">null</span>, val)\n\n        <span class=\"hljs-keyword\">return</span> <span class=\"hljs-title function_\">nestedCb</span>(<span class=\"hljs-title class_\">Math</span>.<span class=\"hljs-title function_\">random</span>() &gt; <span class=\"hljs-title class_\">Math</span>.<span class=\"hljs-title function_\">random</span>() ? <span class=\"hljs-number\">1</span> : -<span class=\"hljs-number\">1</span>, count, cb)\n      })(<span class=\"hljs-title class_\">Math</span>.<span class=\"hljs-title function_\">random</span>(), conf.<span class=\"hljs-property\">n</span>, <span class=\"hljs-function\">(<span class=\"hljs-params\">err, res</span>) =&gt;</span> {\n        <span class=\"hljs-title function_\">resolve</span>(res)\n      })\n    ))\n    bench.<span class=\"hljs-title function_\">end</span>(conf.<span class=\"hljs-property\">n</span>)\n  }\n\n  <span class=\"hljs-keyword\">return</span> res\n}\n</code></pre></details><pre><code class=\"hljs language-bash\">$ node async-vs-cb.nested-benchmark.js\n.js <span class=\"hljs-built_in\">type</span>=<span class=\"hljs-string\">&quot;await-deep&quot;</span>          n=1400: 1,516,848.9413477853\n.js <span class=\"hljs-built_in\">type</span>=<span class=\"hljs-string\">&quot;await-shallow&quot;</span>       n=1400: 1,137,102.9378678831\n.js <span class=\"hljs-built_in\">type</span>=<span class=\"hljs-string\">&quot;cb-deep&quot;</span>             n=1400: 2,214,625.7045278023\n.js <span class=\"hljs-built_in\">type</span>=<span class=\"hljs-string\">&quot;cb-deep-promisified&quot;</span> n=1400: 1,907,328.3642888186\n</code></pre><p><strong>Conclusion: performance-sensitive, deeply-stacked callback code should not be converted to async-await.</strong></p>\n<hr>\n<p><em><strong>also</strong> updating benchmarks to send and receive destructured values shows significant performance drop, so that async/await with array destructuring is very slow</em> only getting about ~200,000 ops/sec on this local machine.</p>\n<p>To elaborate, callback functions may receive multiple values, for example,</p>\n<pre><code class=\"hljs language-javascript\"><span class=\"hljs-title function_\">callback</span>(<span class=\"hljs-keyword\">function</span> (<span class=\"hljs-params\">a, b, c, d</span>) {\n  <span class=\"hljs-comment\">// ...</span>\n})\n</code></pre><p>async function callers must receive one value and separate values are found with lookups or slower destructuring,</p>\n<pre><code class=\"hljs language-javascript\">[a, b, c, b] = <span class=\"hljs-keyword\">await</span> <span class=\"hljs-title function_\">asyncfn</span>();\n</code></pre><p>sending and receiving destructured values drops performance significantly, so that async/await with array destructuring is very slow only getting about ~200,000-300,000 ops/sec on the local machine here.</p>\n<p><img src=\"assets/img/callbacks-win.pd.fit-160.avif\" alt=\"Callback parens\" title=\"callback parens\"></p>\n",
    "date_published": "2024-09-21T20:12:16-08:00",
    "tags": ["software"]
  }, {
    "id": "/media/2018-01-21-kanaphone/",
    "url": "https://bumblehead.com/media/2018-01-21-kanaphone/",
    "title": "kanaphone",
    "summary": "Learn hiragana and katakana faster! A web-extension that updates web-pages, replacing phonetic regions with japanese kana. Kanaphone-we is a web-extension wrapper for kanaphone.",
    "content_html": "<p><img src=\"assets/img/kanaphone.fill.promo-440x280px.png\" alt=\"kanaphone-we\" title=\"kanaphone-we\"></p>\n<p><strong>Learn hiragana and katakana faster!</strong> A web-extension that updates web-pages, replacing phonetic regions with japanese kana. Kanaphone-we is a web-extension wrapper for <a href=\"https://gitlab.com/bumblehead/kanaphone\" title=\"kanaphone\">kanaphone</a>.</p>\n<p>Options allow one to decide how frequently kana appear in the document and allow one to show hiragana, katakana or both.</p>\n<p>This script is intended as an open-source cross-browser version of <a href=\"https://chrome.google.com/webstore/detail/easy-kana/nhcjgpmcngkhhfhbnopcjkhnkclhjfme?hl=en\" title=\"easy-kana\">easy-kana</a>, an excellent plugin for Chrome.</p>\n<p><img src=\"assets/img/omg-ubuntu.png\" alt=\"kanaphone-we\"></p>\n<ul>\n<li><a href=\"https://addons.mozilla.org/en-US/firefox/addon/kanaphone-we/\" title=\"firefox, amo\">firefox</a></li>\n<li><a href=\"https://chrome.google.com/webstore/detail/kanaphone-we/oppiajkidnbjnoggkjgfligelimopinn?hl=en\" title=\"chrome\">chrome</a></li>\n</ul>\n",
    "date_published": "2018-01-21T20:59:59-08:00",
    "tags": ["javascript"]
  }, {
    "id": "/media/2017-11-20-readyaim/",
    "url": "https://bumblehead.com/media/2017-11-20-readyaim/",
    "title": "readyaim",
    "summary": "Try it out by visiting this page and aiming.",
    "content_html": "<iframe src=\"https://iambumblehead.github.io/readyaim/\" width=\"100%\" height=\"400px\" style=\"border:0;\"></iframe><p><a href=\"https://iambumblehead.github.io/readyaim/\" title=\"readyaim demo\">readyaim</a> is a library that reports rayover/rayout-style aiming events from the document.</p>\n<p>Try it out by <a href=\"https://github.com/iambumblehead/readyaim\" title=\"readyaim src\">visiting this page</a> and aiming.</p>\n",
    "date_published": "2017-11-20T20:59:59-08:00",
    "tags": ["javascript"]
  }, {
    "id": "/media/2017-09-24-touchboom/",
    "url": "https://bumblehead.com/media/2017-09-24-touchboom/",
    "title": "touchboom",
    "summary": "touchboom is a library that reports  inertial movement and key/touch/mouse events from the document. A reworking of the motion scripts found here, courtesy of Ariya Hidayat.",
    "content_html": "<iframe src=\"https://iambumblehead.github.io/touchboom/\" width=\"100%\" height=\"400px\" style=\"border:0;\"></iframe><p><a href=\"https://iambumblehead.github.io/touchboom/\" title=\"touchboom demo\">touchboom</a> is a library that reports  inertial movement and key/touch/mouse events from the document. A reworking of the <a href=\"https://github.com/ariya/kinetic/\" title=\"kinetic\">motion scripts found here</a>, courtesy of Ariya Hidayat.</p>\n<p>Try it out by <a href=\"https://github.com/iambumblehead/touchboom\" title=\"touchboom src\">visiting this page</a>. Try clicking, dragging and releasing.</p>\n",
    "date_published": "2017-09-24T19:59:59-08:00",
    "tags": ["javascript"]
  }, {
    "id": "/blog/2017-07-16-big-rewrite-idea/",
    "url": "https://bumblehead.com/blog/2017-07-16-big-rewrite-idea/",
    "title": "Big Rewrite Idea",
    "summary": "Allow people to choose a role, in favor of\n\n\"a complete rewrite\", or\nincrementally improving the current system",
    "content_html": "<p><strong>Allow people to choose a role,</strong> in favor of</p>\n<ol>\n<li>&quot;a complete rewrite&quot;, <em>or</em></li>\n<li>incrementally improving the current system</li>\n</ol>\n<p><strong>Proceed with any unanimous decision, otherwise, begin a competition.</strong> Rewrite-proponents build &quot;their&quot; new system in a competion against supporters of the old system. If the new system achieves superiority, it &quot;wins&quot; and replaces the old system. The old system &quot;wins&quot; if problem-areas are resolved before it can replaced. Individuals may change sides any time and, if one side is abandonded, the other wins.</p>\n<p><strong>Hypotheses: development activity of both groups would be intense,</strong> so that velocity for each competing-project would be higher than the velocity of a single project with all individuals assigned to it.</p>\n<p>Proponents of the rewrite would validate their claims of making a system that is &quot;small, clean, simple, modern and easy to maintain&quot; etc. Proponents of the legacy system would validate their claims the current system will be fine &quot;when it is finished in two weeks&quot; or months etc.</p>\n<hr>\n<p><a href=\"http://ecolo.org/documents/documents_in_english/Rickover.pdf\">H. G. Rickover letter</a> wrote,</p>\n<blockquote>\n<p>[...] Since they are innocently unaware of the real but hidden difficulties of their plans, They speak with great facility and confidence. Those involved with practical reactors, humbled by their experiences, speak less and worry more</p>\n</blockquote>\n<p>Related links,</p>\n<ul>\n<li><a href=\"https://softwareengineering.stackexchange.com/questions/6268/when-is-a-big-rewrite-the-answer\">stackexchange: when is a big rewrite the answer?</a></li>\n<li><a href=\"https://news.ycombinator.com/item?id=11554288\" title=\"no longer believe\">ycombinator &quot;I no longer believe in rewrites.&quot;</a></li>\n</ul>\n",
    "date_published": "2017-07-16T18:46:46-08:00",
    "tags": ["software", "art"]
  }, {
    "id": "/blog/2017-07-15-qa-mike-sheldon/",
    "url": "https://bumblehead.com/blog/2017-07-15-qa-mike-sheldon/",
    "title": "QA Mike Sheldon",
    "summary": "An interview about Ubuntu Touch with Mike Sheldon from a UBPorts Telegram group chat. Mike was part of the System Apps team at Canonical for over three years.",
    "content_html": "<p><a href=\"assets/img/Ubuntu-for-Phones-Now-Supports-USB-Tethering-454650-2.jpg\" title=\"ubuntu touch\"><img src=\"assets/img/Ubuntu-for-Phones-Now-Supports-USB-Tethering_360x200.jpg\" alt=\"ubuntu-for-phones\" title=\"ubuntu touch\"></a></p>\n<p><strong>An interview about Ubuntu Touch with Mike Sheldon</strong> from a UBPorts Telegram group chat. Mike was part of the System Apps team at Canonical for over three years. His blog is <a href=\"http://blog.mikeasoft.com/\" title=\"mike sheldon\">here</a>.</p>\n<ul>\n<li><p><em>Chris</em> <strong>Do you believe there was any conspiracy sort of situation to deprive the market of an ubuntu touch device? Do you think ubuntu touch was &#39;ready&#39;? If not, how far from ready-state do you think things were?</strong></p>\n</li>\n<li><p><em>Mike</em> Definitely no conspiracy. I don&#39;t think it was ready for a main stream audience yet, I think a lot more could have been made of the geek/developer audience though.</p>\n</li>\n<li><p><em>Mike</em> for some people it&#39;s ready, but it really depends on your usage and technical skill level</p>\n</li>\n<li><p><em>Mike</em> I used mine as my main phone for years (as did my mum for that matter), but I know a lot of people would struggle without access to a lot of the apps they&#39;ve come to expect and there were lots of issues that needed ironing out</p>\n</li>\n<li><p><em>Mike</em> e.g. compatibility across various car bluetooth systems was a big issue for some people, if you&#39;ve come to rely on that with a phone then it&#39;s a major issue</p>\n</li>\n<li><p><em>Mike</em> but lots of people don&#39;t bother with car bluetooth stuff, so for them it didn&#39;t matter</p>\n</li>\n</ul>\n<hr>\n<ul>\n<li><p><em>Chris</em> <strong>Do you think unity 8 would have been finished if another year of development had continued?</strong></p>\n</li>\n<li><p><em>Mike</em> yeah, it was getting into a pretty good state; it&#39;s very disappointing that things finished when they did</p>\n</li>\n</ul>\n<hr>\n<ul>\n<li><p><em>Chris</em> <strong>If you could have changed one thing about the development of ubuntu touch or unity, what would you change? in the large, as far as market, internal politics, development lifecycle etc. do you think either of these projects could have been a &#39;success&#39; —what should success have looked like?</strong></p>\n</li>\n<li><p><em>Mike</em> well I think sticking with things longer would have helped ;)</p>\n</li>\n<li><p><em>Mike</em> but also focusing on external developers a lot more</p>\n</li>\n<li><p><em>Mike</em> I tried to do that as much as I could myself (e.g. making tutorial videos aimed at developers for UDM and content-hub), but the general focus from upper management I think was always on consumers</p>\n</li>\n<li><p><em>Mike</em> and I think that focus should have come much later, after first focusing on creating something that other developers could create apps for easily</p>\n</li>\n<li><p><em>Mike</em> there&#39;s lots of great stuff in the platform that external developers hardly knew about most of the time, because it&#39;s just mentioned in a bit of API doc somewhere without any context as to how it fits into the system as a whole</p>\n</li>\n</ul>\n<hr>\n<ul>\n<li><p><em>Chris</em> <strong>Why do you think management would focus on marketing, when the product is not ready? How could a company that <em>does</em> software fail in this way?</strong></p>\n</li>\n<li><p><em>Mike</em>  I don&#39;t really know, I didn&#39;t have any real interaction with anyone involved in that stuff so could only speculate randomly</p>\n</li>\n</ul>\n<hr>\n<ul>\n<li><p><em>Chris</em>  <strong>Were there many people working on Unity and Ubuntu Touch, or was it a small focused group? How difficult would it be for someone to gain a job working on one of these teams? What do you appreciate most about canonical&#39;s development of Ubuntu Touch? What things did they get &#39;right&#39;?</strong></p>\n</li>\n<li><p><em>Mike</em> Well, it was a lot of people working on it from the perspective of a company of Canonical&#39;s size. Compared to Google/Apple etc. there was hardly anyone working on it ;)</p>\n</li>\n<li><p><em>Mike</em> Google probably have more people working on their keyboard stack than we had on the whole system apps team</p>\n</li>\n<li><p><em>Mike</em> so for the most part each app and many bits of infrastructure only had one main developer</p>\n</li>\n<li><p><em>Mike</em> I think I was probably part of one of the last main waves of expansion, we only had one other person join our team after me; and I know competition for the position was pretty hot, we had some great candidates for it</p>\n</li>\n<li><p><em>Mike</em> I absolutely loved working with my team, our manager was amazing. I think that was a lot of people&#39;s experience too, at the team/engineering manager level Canonical was astounding and is the main reason we achieved so much with so few resources</p>\n</li>\n</ul>\n<hr>\n<ul>\n<li><p><em>Chris</em> <strong>In a broad professional sense, how has working on ubuntu touch changed you?</strong></p>\n</li>\n<li><p><em>Mike</em> heh, it&#39;s probably ruined any possibility of me ever wanting to work on boring stuff ;). The three years I spent working on Ubuntu Touch were some of the most fulfiling I&#39;ve had professionally even if things didn&#39;t work out in the end</p>\n</li>\n</ul>\n<hr>\n<ul>\n<li><p><em>Chris</em> <strong>You have good things to say about Canonical management, politically how &#39;aligned&#39; do you think Canonical&#39;s management were? Were they aligned on the same page throughout most of the development?</strong></p>\n</li>\n<li><p><em>Chris</em> <strong>if marketing was prioritized over development it would seem that marketing executives had the upper hand over engineering layers —was this true from your perspective?</strong></p>\n</li>\n<li><p><em>Mike</em> I think it varied a lot depending on the level of management, at the engineering level the managers were fantastic. But higher up at the more strategic level of management I get the impression that things went in and out of favour a bit too much, stopping anything from reaching it&#39;s full potential before it was deprioritised for the next big thing</p>\n</li>\n<li><p><em>Mike</em> I don&#39;t think there was much in the way of internal politics between departments getting in the way, and at its heart Canonical has always been pretty engineering focused (I think we had a much better time of it than the design teams for instance)</p>\n</li>\n<li><p><em>Mike</em> it was just unfortunate things were never given a chance to mature into what they could have been</p>\n</li>\n<li><p><em>Mike</em> e.g. first scopes are the big thing, then convergence, then snappy, etc.</p>\n</li>\n<li><p><em>Mike</em> with everything being left at a first okayish version, but never getting to be as good as it could have been</p>\n</li>\n</ul>\n<hr>\n<ul>\n<li><p><em>Chris</em>  <strong>Was there an &#39;event&#39; that began Canonical&#39;s disengagement with Ubuntu touch / Unity 8? or did it just occur as a slow dynamic over time?</strong></p>\n</li>\n<li><p><em>Chris</em> <strong>I read about an OTA update that left many meizu devices in an unsable state... did that really happen? was it a big deal inside of the canonical ubuntu touch team?</strong></p>\n</li>\n<li><p><em>Mike</em> not sure I can answer that one really, since it involved pretty internal company stuff</p>\n</li>\n<li><p><em>Mike</em> I&#39;m not aware of that, but that&#39;d probably have been something the hardware enablement people would have looked at rather than coming anywhere near my team</p>\n</li>\n</ul>\n<hr>\n<ul>\n<li><p><em>Chris</em> <strong>As Ubports and Yunit begin taking ownership of ubuntu touch / unity, what do you think are the &#39;key&#39; areas of focus?</strong></p>\n</li>\n<li><p><em>Mike</em> I don&#39;t know what makes most strategic sense over all, but I think it&#39;s good in the early stages if people just work on whatever personally interests them so as to keep everyone engaged as things take off. Besides that, personally I&#39;m pretty hot on making things as easy as possible for app developers.</p>\n</li>\n</ul>\n<hr>\n<ul>\n<li><p><em>Chris</em> <strong>I&#39;ve read about hostility and negative communication from Gnome and linux users in general... on a scale of 0 to 10, with 0 being completely irrelevant, how impactful was that on the development of unity and ubuntu touch?</strong></p>\n</li>\n<li><p><em>Mike</em> Personally I never experienced any issues with GNOME folks, plus I&#39;ve got friends who hack on GNOME stuff. I think the &quot;GNOME vs Canonical&quot; type of stuff tends to be rather overblown</p>\n</li>\n<li><p><em>Mike</em> Of course you get the odd comment on reddit about how what you&#39;re doing is pointless, which can be a bit demotivating at first, but you get used to it ;)</p>\n</li>\n</ul>\n<hr>\n<ul>\n<li><p><em>Chris</em> <strong>Today what desktop environment do you use?</strong></p>\n</li>\n<li><p><em>Mike</em> Still unity7 :)</p>\n</li>\n<li><p><em>Mike</em> Hoping to switch to Yunit in the future though :)</p>\n</li>\n<li><p><em>Mike</em> I used to use gnome-shell though (and before that gnome 2)</p>\n</li>\n<li><p><em>Mike</em> (and before that ratpoison...)</p>\n</li>\n</ul>\n<hr>\n<ul>\n<li><p><em>Chris</em> <strong>for someone just getting involved w/ ubports, for something in the functionality range of a todo-list style app, would you recommend qml/c++ or local html5/js?</strong></p>\n</li>\n<li><p><em>Mike</em> I&#39;d recommend going with QML myself, the tooling around it in Ubuntu Touch is much more mature really</p>\n</li>\n<li><p><em>Chris</em> <strong>is it true that QML apps need to be tested by installing them on the device, because the emulator is non-functional?</strong></p>\n</li>\n<li><p><em>Mike</em> well, you can run QML apps natively on the desktop too</p>\n</li>\n</ul>\n<hr>\n<ul>\n<li><p><em>Chris</em> <strong>Do you know, which country had the most participation with ubuntu? money-wise or people-wise?</strong></p>\n</li>\n<li><p><em>Mike</em> I don&#39;t know anything from working at Canonical, but from the stats <em>(disabled link, stats.ubports.com no longer resolves)</em> on Podbird it went: Germany, UK, France, Spain, USA, Italy, Netherlands, Sweden, Switzerland, Austria as the top 10</p>\n</li>\n</ul>\n<!--\n\n * _Chris_  [09.07.17 17:52]\nMay I publish the QA responses on my website? I could label you as 'anonymous'\n\n * _Chris_  [09.07.17 17:52]\nhttp://www.bumblehead.com\n\n * _Chris_  [09.07.17 17:52]\ni get no traffic basically\n\n * _Mike_ [09.07.17 17:59]\nsure, might as well stick my name on it; I haven't said anything I'd consider unprofessional to share\n\n * _Chris_  [09.07.17 17:59]\nthanks :)\n\n * _Mike_ [09.07.17 17:59]\nplus I'm pretty sure anyone who worked with me could figure out it was me from some of my answers ;)\n\n * _Chris_  [09.07.17 18:00]\nthank you\n\n * _Mike_ [09.07.17 18:01]\nyou're welcome :)\n\n * _Chris_  [09.07.17 18:03]\nI would like to introduce you before placing the qa. would you tell me how long you were there and what your role was at the end?\n\n * _Chris_  [09.07.17 18:03]\ndo you mind if I link to your site? http://blog.mikeasoft.com/\n\n * _Mike_ [09.07.17 18:04]\nI was there for a little over three years and worked on the System Apps team\n\n * _Mike_ [09.07.17 18:04]\n Sure, although I haven't updated it in quite a while :)\n \n-->\n",
    "date_published": "2017-07-15T22:46:46-08:00",
    "tags": ["software"]
  }, {
    "id": "/blog/2017-07-10-ubports-webapp/",
    "url": "https://bumblehead.com/blog/2017-07-10-ubports-webapp/",
    "title": "UBPorts Webapp",
    "summary": "Ubports is a mobile operating system that does not collect personal data. It looks beautiful and is easy to use :). My favorite.",
    "content_html": "<p><a href=\"https://ubports.com/\" title=\"ubports\">Ubports</a> is a mobile operating system that does not collect personal data. It looks beautiful and is easy to use :). My favorite.</p>\n<p>Here, I&#39;ll share what&#39;s needed to package and install an html/js app as a &quot;click&quot; package for Ubports. Download this little demo app and follow along to create a .click package with it.</p>\n<p>It does not use electron or node-webkit, but uses a web container provided by the Ubports system.</p>\n<h4>Get started</h4>\n<p><img src=\"https://github.com/iambumblehead/ubports-little-webapp/raw/master/src/img/browser-123.png\" alt=\"scrounge\"></p>\n<p>First, download or clone the app and visit it with a shell. Use npm to install and run it locally and to see it in your browser.</p>\n<pre><code class=\"hljs language-bash\">$ npm install\n$ npm start <span class=\"hljs-comment\"># after express starts, use a browser to visit http://localhost:3000/</span>\n</code></pre><p>It runs! You should see a scripted alert box. Most webapps are developed around a local service such as this, where changes can be seen in the browser.</p>\n<h4>Make a .click package!</h4>\n<p><img src=\"https://github.com/iambumblehead/ubports-little-webapp/raw/master/src/img/click-123.png\" alt=\"scrounge\"></p>\n<p>Now you&#39;re ready to make a .click package. Call the included <code>makeclick.sh</code> script. This script can be customised along with the boilerplate files found in ./platform/click.</p>\n<pre><code class=\"hljs language-bash\">$ bash ./makeclick.sh\n[...] generate .click: ubports-little-webapp-1.0.0\n[...] clean sources\n[...] write sources\n[...] write manifest version\n[...] write click\nNow executing: click-review ./ubports-little-webapp_1.0.0_all.click\n./ubports-little-webapp_1.0.0_all.click: pass\nSuccessfully built package <span class=\"hljs-keyword\">in</span> <span class=\"hljs-string\">&#x27;./ubports-little-webapp_1.0.0_all.click&#x27;</span>.\n</code></pre><h4>Test a .click package!</h4>\n<p>One of the best ways to test your .click package is to install it on a device.\n<a href=\"https://www.linuxbabe.com/ubuntu/how-to-install-adb-fastboot-ubuntu-16-04-16-10-14-04\">Install adb</a> if you haven&#39;t done that already, then turn on your device and usb-connect it. Be sure &quot;Developer mode&quot; is enabled (System Settings &gt; About &gt; Developer mode).</p>\n<pre><code class=\"hljs language-bash\">$ adb push ubports-little-webapp_1.0.0_all.click /tmp <span class=\"hljs-comment\"># copy to the device</span>\n$ adb shell <span class=\"hljs-comment\"># enter the device</span>\n$ pkcon install-local --allow-untrusted /tmp/ubports-little-webapp_1.0.0_all.click <span class=\"hljs-comment\"># install</span>\nInstalling files              [=========================]\nFinished                      [=========================]\nInstalling files              [=========================]\nTesting changes               [=========================]\nStarting                      [=========================]\nFinished                      [=========================]\nInstalled   \tubports-little-webapp-1.0.0.all\n</code></pre><p>Refresh your homescreen and click the ubports icon to start the app!</p>\n<p><img src=\"https://github.com/iambumblehead/ubports-little-webapp/raw/master/src/img/flow-123.png\" alt=\"scrounge\"></p>\n<!--\nWhat about .snap packages?\n\nIncluded with the repo, is a script named makesnap.sh that generates a .snap package. I've never succesfully generated a working snap file :S\n\nI've followed various guides and installed overlays and linked various libraries. Maybe in the future I will find a way to generate an html snap...\n--><p>Credit:</p>\n<ul>\n<li>Alan Pope&#39;s click package blog entry <em>(disabled link no longer resolves)</em></li>\n</ul>\n<p><img src=\"https://github.com/iambumblehead/scroungejs/raw/main/img/hand.png\" alt=\"scrounge\"></p>\n",
    "date_published": "2017-07-10T11:06:06-08:00",
    "tags": ["software"]
  }, {
    "id": "/media/2017-06-11-megukana/",
    "url": "https://bumblehead.com/media/2017-06-11-megukana/",
    "title": "megukana",
    "summary": "Megukana is a flashcard application for learning hiragana and katakana. Use up, down, left and right keys or mouse/touch to raise and swipe the card.",
    "content_html": "<iframe src=\"https://bumblehead.gitlab.io/megukana/\" width=\"100%\" height=\"400px\" style=\"border:0;\"></iframe><p><strong><a href=\"https://bumblehead.gitlab.io/megukana/\" title=\"megukana\">Megukana</a> is a flashcard application</strong> for learning hiragana and katakana. Use up, down, left and right keys or mouse/touch to raise and swipe the card. Click the settings button at the top left to change deck settings.</p>\n<p>Simple with no user-tracking or reporting. no advertisements. usable off-line, with any form factor. Browser session remembers your settings and card-selection state.</p>\n<p>Some resources which I found helpful:</p>\n<ul>\n<li><a href=\"https://nihongoichiban.com/2011/04/30/complete-list-of-vocabulary-for-the-jlpt-n5/\" title=\"nihongoichiban\">nihongoichiban</a></li>\n<li><a href=\"http://www.japandict.com/\" title=\"japandict\">japandict</a></li>\n<li><a href=\"http://jisho.org/\" title=\"jisho\">jisho</a></li>\n<li><a href=\"https://www.tofugu.com/japanese/\" title=\"tofugu\">tofugu</a></li>\n<li><a href=\"http://www3.nhk.or.jp/news/easy/\" title=\"nhk news\">nhk, easy</a></li>\n<li><a href=\"http://www.guidetojapanese.org/learn/grammar\" title=\"tae kim\">tae kim&#39;s guide to japanese grammar</a></li>\n<li><a href=\"https://pomax.github.io/nrGrammar/\">comprehensive japanese guide</a></li>\n<li><a href=\"https://soundcloud.com/tags/japaneseclass%20%23singapore%20%23pyaess\">great listening while practicing kana</a></li>\n</ul>\n<p>If you are seeing unicode replacement characters in the place of kanji (usually a dark colored rectangle wrapping question mark or numbers), try installing a cjk font, such as notofo cjk, and restarting your browser.</p>\n<p>The sources for this application were made to mimic the flow of a <a href=\"https://cycle.js.org/\" title=\"cycle.js\">cycle.js</a> application, but without using a stream library.</p>\n<p>The background comes from <a href=\"https://unsplash.com/\">unsplash</a>.</p>\n",
    "date_published": "2017-06-11T19:59:59-08:00",
    "tags": ["javascript"]
  }, {
    "id": "/blog/2017-06-11-megukana/",
    "url": "https://bumblehead.com/blog/2017-06-11-megukana/",
    "title": "megukana",
    "summary": "Megukana is a flashcard application for learning hiragana and katakana. Use up, down, left and right keys or mouse/touch to raise and swipe the card. Click the settings button at the top left to change deck settings.",
    "content_html": "<p><strong>Megukana is a flashcard application</strong> for learning hiragana and katakana. Use up, down, left and right keys or mouse/touch to raise and swipe the card. Click the settings button at the top left to change deck settings.</p>\n<iframe src=\"https://bumblehead.gitlab.io/megukana/\" width=\"100%\" height=\"400px\" style=\"border:0;\"></iframe><p><a href=\"https://bumblehead.gitlab.io/megukana/\" title=\"megukana\">megukana</a> is added to the <a href=\"/media/\">media</a> section with a a brief description.</p>\n",
    "date_published": "2017-06-11T19:59:59-08:00",
    "tags": ["art"]
  }, {
    "id": "/blog/2017-06-08-new-bumblehead.com/",
    "url": "https://bumblehead.com/blog/2017-06-08-new-bumblehead.com/",
    "title": "new bumblehead.com",
    "summary": "This site is relaunched today! It uses a unique static system developed to quickly build and customize web interfaces. I hope it runs quickly for you and is fun to use :).",
    "content_html": "<p>This site is relaunched today! It uses a unique static system developed to quickly build and customize web interfaces. I hope it runs quickly for you and is fun to use :).</p>\n<p>I&#39;m not sure how focused this site will be on any one topic, but I plan to host my own web experiments here and possibly start a video blog related to software development culture.</p>\n<pre><code class=\"hljs language-json\"><span class=\"hljs-punctuation\">{</span>\n  <span class=\"hljs-attr\">&quot;page&quot;</span> <span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;pgls&quot;</span><span class=\"hljs-punctuation\">,</span>\n  <span class=\"hljs-attr\">&quot;name&quot;</span> <span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;blogslist&quot;</span><span class=\"hljs-punctuation\">,</span>\n  <span class=\"hljs-attr\">&quot;maplist&quot;</span> <span class=\"hljs-punctuation\">:</span> <span class=\"hljs-punctuation\">{</span>\n    <span class=\"hljs-attr\">&quot;type&quot;</span> <span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;fn&quot;</span><span class=\"hljs-punctuation\">,</span>\n    <span class=\"hljs-attr\">&quot;fnname&quot;</span> <span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;getchildkeys&quot;</span><span class=\"hljs-punctuation\">,</span>\n    <span class=\"hljs-attr\">&quot;argprops&quot;</span> <span class=\"hljs-punctuation\">:</span> <span class=\"hljs-punctuation\">[</span><span class=\"hljs-string\">&quot;/blogs/datablogs&quot;</span><span class=\"hljs-punctuation\">]</span>\n  <span class=\"hljs-punctuation\">}</span><span class=\"hljs-punctuation\">,</span>\n  <span class=\"hljs-attr\">&quot;child&quot;</span> <span class=\"hljs-punctuation\">:</span> <span class=\"hljs-punctuation\">[</span><span class=\"hljs-punctuation\">{</span>\n    <span class=\"hljs-attr\">&quot;fkey&quot;</span> <span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;blogkey&quot;</span><span class=\"hljs-punctuation\">,</span>\n    <span class=\"hljs-attr\">&quot;spec&quot;</span> <span class=\"hljs-punctuation\">:</span> <span class=\"hljs-punctuation\">{</span> \n      <span class=\"hljs-attr\">&quot;type&quot;</span> <span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;local-ref&quot;</span><span class=\"hljs-punctuation\">,</span>\n      <span class=\"hljs-attr\">&quot;path&quot;</span> <span class=\"hljs-punctuation\">:</span> <span class=\"hljs-string\">&quot;../page-blogs-list-blog/&quot;</span>\n    <span class=\"hljs-punctuation\">}</span>\n  <span class=\"hljs-punctuation\">}</span><span class=\"hljs-punctuation\">]</span>\n<span class=\"hljs-punctuation\">}</span>\n</code></pre><p>It renders documents using a JSON-formatted design language to define layout, appearance and behaviour. JSON &quot;patterns&quot;, such as above, are resolved by an <a href=\"https://github.com/iambumblehead/specmob\" title=\"specmob, interpreter\">interpreter</a> to complete a <a href=\"https://gitlab.com/bumblehead/spectraph/\" title=\"spectraph, graph\">graph</a>. Inspect the graph for bumblehead.com by opening a browser console and entering <code>_cfg._rgraph.toJS()</code>.</p>\n<p><em>Above paragraph previously linked to a research paper written by Jeffrey Nichols. Link is disabled because it no longer resolves</em></p>\n<p>gani is still a work in progress. Building a design language is difficult. The language must be generic enough to describe future designs unknown to the author. If too verbose, the language becomes unwieldy. Modifying the language may cause backward-compatibility issues for the interpreter software (also challenging to write). </p>\n<p>If pattern files are web-accessed, one needs to organize them in ways to minimize requests. The difficulty increases if you have locale and/or language specific content in your application.</p>\n",
    "date_published": "2017-06-08T11:06:06-08:00",
    "tags": ["art"]
  }, {
    "id": "/media/2012-09-03-scroungejs/",
    "url": "https://bumblehead.com/media/2012-09-03-scroungejs/",
    "title": "scroungejs",
    "summary": "A tool for web deployment of javascript/css/template files.",
    "content_html": "<p><a href=\"https://github.com/iambumblehead/scroungejs\" title=\"scroungejs\"><img src=\"assets/img/scrounge-hand3.png\" alt=\"hand\" title=\"scroungejs logo\"></a></p>\n<ul>\n<li><a href=\"https://www.npmjs.com/package/scroungejs\" title=\"scroungejs\">NPM page</a></li>\n<li><a href=\"https://github.com/iambumblehead/scroungejs\" title=\"scroungejs\">Github page</a></li>\n</ul>\n<p>A tool for web deployment of javascript/css/template files.</p>\n",
    "date_published": "2012-09-03T16:20:20-08:00",
    "tags": ["software", "javascript"]
  }, {
    "id": "/blog/2011-07-02-el-cid/",
    "url": "https://bumblehead.com/blog/2011-07-02-el-cid/",
    "title": "El Cid",
    "summary": "Cortex Accelera will be playing in a live show at El Cid in Silverlake on 7/10. Its a free event celebrating his new released record 'The Place We Went To'.",
    "content_html": "<p>Cortex Accelera will be playing in a live show at El Cid in Silverlake on 7/10. Its a free event celebrating his new released record &#39;The Place We Went To&#39;.</p>\n<p>He remade the score for our video work, &#39;Royal Crown&#39;. Hear it in the media section of this site. The media section is updated to serve html5 video (was previously flash).</p>\n",
    "date_published": "2011-07-02T15:37:37-08:00",
    "tags": ["video", "art"]
  }, {
    "id": "/blog/2011-05-21-hello-javascript/",
    "url": "https://bumblehead.com/blog/2011-05-21-hello-javascript/",
    "title": "hello javascript",
    "summary": "Did you know, Opera's garbage collection prevents this from saying 'hi'?",
    "content_html": "<p>Did you know, Opera&#39;s garbage collection prevents this from saying &#39;hi&#39;?</p>\n<pre><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">function</span>(<span class=\"hljs-params\">src</span>) {\n  <span class=\"hljs-keyword\">var</span> i = <span class=\"hljs-keyword\">new</span> <span class=\"hljs-title class_\">Image</span>();\n  i.<span class=\"hljs-property\">onload</span> = <span class=\"hljs-keyword\">function</span>(<span class=\"hljs-params\"></span>) { <span class=\"hljs-title function_\">alert</span>(<span class=\"hljs-string\">&quot;hi&quot;</span>); }\n  i.<span class=\"hljs-property\">src</span> = src;\n}\n</code></pre>",
    "date_published": "2011-05-21T18:46:46-08:00",
    "tags": ["software", "art"]
  }, {
    "id": "/media/2010-10-10-dayshots/",
    "url": "https://bumblehead.com/media/2010-10-10-dayshots/",
    "title": "dayshots",
    "summary": "dayshots",
    "content_html": "<p>Time-lapse videos taken at the foot of Mt. Baldy.</p>\n<p>The videos are unoptimised and file sizes are large.</p>\n<p><video controls preload=\"auto\" width=\"100%\"\n  poster=\"assets/img/dayshot-01-0396.png\">\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/dayshot-01-960x540_x264_25fps.mp4\" type=\"video/mp4\" />\n</video></p>\n<p><video controls preload=\"auto\" width=\"360\" height=\"240\"\n  poster=\"assets/img/dayshot-02-smaller_1220.png\">\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/dayshot-02-960x540_x264.mp4\" type=\"video/mp4\" />\n</video></p>\n<p><video controls preload=\"auto\" width=\"360\" height=\"240\"\n  poster=\"assets/img/sunset-01-smaller_0268.png\">\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/sunset-01-1024x768_x264.mp4\" type=\"video/mp4\" />\n</video></p>\n<br /><p><video controls preload=\"auto\" width=\"100%\"\n  poster=\"assets/img/sunset-02-smaller_0033.png\">\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/sunset-02-1376x768_x264.mp4\" type=\"video/mp4\" />\n</video></p>\n<br /><p><video controls preload=\"auto\" width=\"360\" height=\"240\"\n  poster=\"assets/img/beilin-smaller_0650.png\">\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/beilin-960x540_x264.mp4\" type=\"video/mp4\" />\n</video></p>\n<video controls preload=\"auto\" width=\"360\" height=\"240\">\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/hommie_480x270_x264_25fps.mp4\" type=\"video/mp4\" />\n</video>\n",
    "date_published": "2010-10-10T16:37:37-08:00",
    "tags": ["camera"]
  }, {
    "id": "/blog/2010-06-04-making-waves/",
    "url": "https://bumblehead.com/blog/2010-06-04-making-waves/",
    "title": "making waves",
    "summary": "I finished a sinewave animation and there's a demonstration page that displays various sinewave videos made during production. The results are surprisingly dynamic.",
    "content_html": "<ul>\n<li><a href=\"assets/img/waves-sine-evolution.jpg\"><img src=\"assets/img/waves-sine-evolution.pd.fit-100.avif\" alt=\"hand\"></a></li>\n<li><a href=\"assets/img/waves-zrender.jpg\"><img src=\"assets/img/waves-zrender.pd.fit-100.avif\" alt=\"hand\"></a></li>\n<li><a href=\"assets/img/waves-emacs-screenshot.jpg\"><img src=\"assets/img/waves-emacs-screenshot.pd.fit-100.avif\" alt=\"hand\"></a></li>\n<li><a href=\"assets/img/waves-testing.jpg\"><img src=\"assets/img/waves-testing.pd.fit-100.avif\" alt=\"hand\"></a></li>\n</ul>\n<p>I finished a sinewave animation and <a href=\"https://bumblehead.gitlab.io/archive-soft/sinewave_demo/\">there&#39;s a demonstration page</a> that displays various sinewave videos made during production. The results are surprisingly dynamic. The fun part of this project involved writing a Common Lisp program for generating the sinewaves and this required a few things in addition to writing a sinewave function. There are functions for drawing circles and connecting lines. There&#39;s a class for generating exponential curves...</p>\n<p>It&#39;ll be appearing in a video.\n<em>Something To Come Undone</em>, dir. Anna Chiaretta Lavatelli, 2010</p>\n<p>Here are two tiny code pieces from sinewave.lisp. &#39;Live on, Common Lisp!</p>\n<pre><code class=\"hljs language-lisp\">(<span class=\"hljs-name\">defmethod</span>  coords-to-canvas (<span class=\"hljs-name\">coords</span> rgba (<span class=\"hljs-name\">canvas</span> image-canvas))\n  (<span class=\"hljs-name\">mapcar</span> #&#x27;(lambda (xy)\n              (pixel-to-canvas xy rgba canvas))\n          coords))\n(<span class=\"hljs-name\">defmacro</span> when-inside (<span class=\"hljs-name\">frame</span> bgn end <span class=\"hljs-symbol\">&amp;body</span> body)\n  `(when (and (&gt;= ,frame ,bgn)\n              (&lt;= ,frame ,end))\n     ,@body)) \n</code></pre>",
    "date_published": "2010-06-04T19:06:06-08:00",
    "tags": ["video", "misc", "professional", "software", "2d", "art"]
  }, {
    "id": "/media/2010-04-12-sinewave/",
    "url": "https://bumblehead.com/media/2010-04-12-sinewave/",
    "title": "sinewave",
    "summary": "A sinewave animation package written in Common Lisp. You can specify parameters for the sinewave such as origin, frequency, amplitude, phase... and the software will output image sequences of a sinewave.",
    "content_html": "<p><a href=\"assets/img/sine_small.gif\" title=\"sine wave screenshot\"><img src=\"assets/img/sine_small.gif\" alt=\"sinewave\" title=\"sine wave screenshot\"></a></p>\n<p>A sinewave animation package written in Common Lisp. You can specify parameters for the sinewave such as origin, frequency, amplitude, phase... and the software will output image sequences of a sinewave. There is an option to connect points on the sinewave with lines of a given stroke and color.</p>\n<p>I&#39;m not hosting the package as a download, but if you&#39;re interested in using it send me an email and I&#39;ll probably be happy to send you the package.</p>\n",
    "date_published": "2010-04-12T13:14:14-08:00",
    "tags": ["software"]
  }, {
    "id": "/media/2010-04-12-dropdown/",
    "url": "https://bumblehead.com/media/2010-04-12-dropdown/",
    "title": "dropdown",
    "summary": "This is a navigation page that uses jquery to position drop-down boxes. There are two things that are special about this implementation.",
    "content_html": "<p><a href=\"https://bumblehead.gitlab.io/archive-soft/soft/dropdown/index.html\" title=\"dropdown\"><img src=\"assets/img/dropdown-screen.png\" alt=\"screenshot\" title=\"dropdown screenshot\"></a> </p>\n<ul>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/soft/dropdown/index.html\" title=\"dropdown\">demonstration</a></li>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/soft/dropdown/hdr_pkg.zip\">source code</a></li>\n</ul>\n<p>This is a navigation page that uses jquery to position drop-down boxes. There are two things that are special about this implementation.</p>\n<ol>\n<li>It requires two small JQuery files only.</li>\n<li>It looks fine in IE6.</li>\n</ol>\n<p>I built this about a month ago for someone. I&#39;ve sent emails asking why they haven&#39;t paid for it. They tell me they&#39;ll get back to me and then they don&#39;t get back to me. They are using a custom-themed version of this package right now.</p>\n<p>It doesn&#39;t look like they&#39;re planning to pay for it... Hahahzzzhzhahaha. Enjoy :).</p>\n",
    "date_published": "2010-04-12T13:14:14-08:00",
    "tags": ["software", "javascript"]
  }, {
    "id": "/media/2010-03-24-phantom/",
    "url": "https://bumblehead.com/media/2010-03-24-phantom/",
    "title": "phantom",
    "summary": "This was just a terrible file to host. I'm fairly certain this site was punished by google for hosting the active demo of it here. :(",
    "content_html": "<p><a href=\"assets/img/phantom-screen.png\" title=\"screenshot\"><img src=\"assets/img/phantom-screen.png\" alt=\"screenshot\" title=\"screenshot\"></a></p>\n<ul>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/soft/phantom_pkg.tar.gz\" title=\"phantom\">phantom</a></li>\n</ul>\n<p>This was just a terrible file to host. I&#39;m fairly certain this site was punished by google for hosting the active demo of it here. :(</p>\n",
    "date_published": "2010-03-24T11:27:27-08:00",
    "tags": ["software"]
  }, {
    "id": "/blog/2010-03-24-bib/",
    "url": "https://bumblehead.com/blog/2010-03-24-bib/",
    "title": "bib",
    "summary": "running",
    "content_html": "<p>running</p>\n<p><img src=\"assets/img/marathon-bib.gif\" alt=\"bib\"></p>\n",
    "date_published": "2010-03-24T11:06:06-08:00",
    "tags": ["art"]
  }, {
    "id": "/blog/2010-02-05-made-with-pure-c/",
    "url": "https://bumblehead.com/blog/2010-02-05-made-with-pure-c/",
    "title": "made with pure C",
    "summary": "made with pure C",
    "content_html": "<pre><code class=\"hljs language-bash\"><span class=\"hljs-comment\">##                       #                        ##</span>\n  <span class=\"hljs-comment\">###                     #                    ###</span>\n     <span class=\"hljs-comment\">###                 #                  ###</span>\n        <span class=\"hljs-comment\">###               #              ###</span>\n           <span class=\"hljs-comment\">###           #            ###</span>\n              <span class=\"hljs-comment\">###         #        ###</span>\n                 <span class=\"hljs-comment\">###     #      ###</span>\n                    <span class=\"hljs-comment\">###   #  ###</span>\n<span class=\"hljs-comment\">####################################################</span>\n                    <span class=\"hljs-comment\">###  #   ###</span>\n                 <span class=\"hljs-comment\">###      #     ###</span>\n              <span class=\"hljs-comment\">###        #         ###</span>\n           <span class=\"hljs-comment\">###            #           ###</span>\n        <span class=\"hljs-comment\">###              #               ###</span>\n     <span class=\"hljs-comment\">###                  #                 ###</span>\n  <span class=\"hljs-comment\">###                    #                     ###</span>\n<span class=\"hljs-comment\">##                        #                       ##</span>\n</code></pre>",
    "date_published": "2010-02-05T18:31:31-08:00",
    "tags": ["misc"]
  }, {
    "id": "/media/2010-02-05-moc-alarm/",
    "url": "https://bumblehead.com/media/2010-02-05-moc-alarm/",
    "title": "moc alarm",
    "summary": "moc_alarm.sh is an alarm clock. When the 'alarm' goes off at the given time, a command is executed.",
    "content_html": "<p><a href=\"assets/img/script_shot.png\" title=\"screenshot\"><img src=\"assets/img/script_shot.png\" alt=\"hand\" title=\"screenshot\"></a></p>\n<ul>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/soft/moc_alarm.sh\" title=\"moc_alarm.sh\">moc_alarm.sh</a></li>\n</ul>\n<p><strong><code>moc_alarm.sh</code> is an alarm clock.</strong> When the &#39;alarm&#39; goes off at the given time, a command is executed. You would probably want to change the default settings to suit yourself by editing the script.</p>\n<p>Run the script with a command like this</p>\n<pre><code class=\"hljs language-bash\">$ bash ./moc_alarm.sh 8:45\n</code></pre>",
    "date_published": "2010-02-05T16:53:53-08:00",
    "tags": ["bash"]
  }, {
    "id": "/media/2009-12-17-royal-crown/",
    "url": "https://bumblehead.com/media/2009-12-17-royal-crown/",
    "title": "Royal Crown",
    "summary": "Royal Crown is the name of a song that Mark sent me. The video expresses an attitude. It's about hope, progress, growth, etc.",
    "content_html": "<p><video controls preload=\"auto\" width=\"360\" height=\"240\"\n  poster=\"assets/img/crown-royal-720x480.png\">\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/RoyalCrown_360x240.mp4\" type='video/mp4' />\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/RoyalCrown_360x240.ogv\" type='video/ogg' />\n</video></p>\n<ul>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/video/RoyalCrown_360x240.mp4\" title=\"mp4\">RoyalCrown.mp4</a></li>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/video/RoyalCrown_360x240.ogv\" title=\"ogv\">RoyalCrown.ogv</a></li>\n</ul>\n<p>Royal Crown is the name of a song that Mark sent me. The video expresses an attitude. It&#39;s about hope, progress, growth, etc.</p>\n<p>The production quality of the video doesn&#39;t survive in the compressed format.</p>\n",
    "date_published": "2009-12-17T23:17:17-08:00",
    "tags": ["video"]
  }, {
    "id": "/blog/2009-12-11-royal-crown/",
    "url": "https://bumblehead.com/blog/2009-12-11-royal-crown/",
    "title": "Royal Crown",
    "summary": "I did finish a GREAT new video and the production quality is very high in this one.",
    "content_html": "<p>I did finish a GREAT new video and the production quality is very high in this one.</p>\n<p><img src=\"assets/img/hand.png\" alt=\"hand\"></p>\n<p>I&#39;m experimenting with embedded video players for the media section here. Flash&#39;s F4V format is great at showing most of the videos I&#39;ve made, but Royal Crown doesn&#39;t compress well in F4V so I&#39;m not sure if I&#39;ll use Flash or not. I&#39;ll figure something out before the end of next week and make the video available at that time, -eh here&#39;s a 640x480 version for you to download until then.</p>\n<p>I have pulled some of my software off of this page and I will rarely add software to it in the future. If you want to see a sample of my PHP or Actionscript send me an email with your name and phone number in it and I&#39;ll get back to you.</p>\n",
    "date_published": "2009-12-11T15:11:11-08:00",
    "tags": ["video", "camera", "painting", "sculpture", "drawing", "2d", "3d", "art"]
  }, {
    "id": "/blog/2009-10-25-stobo-update/",
    "url": "https://bumblehead.com/blog/2009-10-25-stobo-update/",
    "title": "Stobo Update",
    "summary": "I've made an update to Stobo. It's a bug-fix update, -minor bugs that I've noticed over the last week or two:",
    "content_html": "<p><img src=\"assets/img/screenshot-recent-stobo.png\" alt=\"throw\"></p>\n<p>I&#39;ve made an update to Stobo. It&#39;s a bug-fix update, -minor bugs that I&#39;ve noticed over the last week or two:</p>\n<ul>\n<li>while processing, preview is OFF for large images</li>\n<li>some tasks have been made faster</li>\n<li>status of processed images is included in GUI</li>\n</ul>\n",
    "date_published": "2009-10-25T12:26:26-08:00",
    "tags": ["software"]
  }, {
    "id": "/media/2009-10-25-stobo/",
    "url": "https://bumblehead.com/media/2009-10-25-stobo/",
    "title": "stobo",
    "summary": "Stobo is a tool for copying and renaming images. It will 'listen' to a directory for the appearance of image files, which it will chronologically copy",
    "content_html": "<p><img src=\"assets/img/stobo-screenshot.png\" alt=\"screenshot\" title=\"screenshot\"></p>\n<ul>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/soft/Stobo_Src.zip\" title=\"source\">source</a></li>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/soft/Stobo_Win64.zip\" title=\"source\">windows.exe</a></li>\n</ul>\n<p>Stobo is a tool for copying and renaming images. It will &#39;listen&#39; to a directory for the appearance of image files, which it will chronologically copy to another location (for example, a location somehwere on your network).</p>\n<p><img src=\"assets/img/stobo-desktop-screen.png\" alt=\"screenshot\" title=\"desktop screenshot, feat. stobo\"></p>\n<p>Stobo was designed for stop-motion animation production. Its basic image formatting and copying abilities allow you to use production images in real-time with any software on any operating system that python operates on. For example, Stobo will take the pictures your camera saves, and sequentially rotate them and shrink them and save them to a folder on your OSX production system where Final Cut Pro or Apple Shake are queued to preview the sequence.</p>\n<p>You will need to install <a href=\"https://www.python.org/\" title=\"python\">Python 2.6</a> and the <a href=\"https://pypi.org/project/pillow/\" title=\"pil\">PIL</a> image library to use Stobo. If you are using linux or osx you will additionally need to install wxpython. Stobo is multi-threaded for responsiveness.</p>\n",
    "date_published": "2009-10-25T11:12:12-08:00",
    "tags": ["software", "art"]
  }, {
    "id": "/blog/2009-08-13-math-collage/",
    "url": "https://bumblehead.com/blog/2009-08-13-math-collage/",
    "title": "Math Collage",
    "summary": "Math Collage",
    "content_html": "<p><img src=\"assets/img/math-collage.png\" alt=\"math collage\"></p>\n",
    "date_published": "2009-08-13T00:48:48-08:00",
    "tags": ["art"]
  }, {
    "id": "/media/2009-08-12-timecode/",
    "url": "https://bumblehead.com/media/2009-08-12-timecode/",
    "title": "timecode",
    "summary": "This ANSI-compliant C program receives a timecode postition and an fps (frames per second) value. It outputs the frame number that exists at the timecode position for the given fps.",
    "content_html": "<p><img src=\"assets/img/timecode.png\" alt=\"screenshot\" title=\"screenshot\"></p>\n<ul>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/soft/timecode.c\" title=\"timecode\">timecode.c</a></li>\n</ul>\n<p>This ANSI-compliant C program receives a timecode postition and an fps (frames per second) value. It outputs the frame number that exists at the timecode position for the given fps.</p>\n<p>I&#39;ve been using this program for analog video production that needs to be synchronized with an audio file. &#39;So, for example, let&#39;s suppose that I will want a keyframe at exactly 1 min and 30 seconds into the audio. If I know that I&#39;ll be showing the animation at 15fps, then I can use this program to find out that the keyframe will be frame #1350. Timecode.c is accurate to the millisecond.</p>\n<p>For posix based systems using gcc, use the following command for compiling timecode.c,</p>\n<pre><code class=\"hljs language-bash\">$ gcc -g -Wall -ansi -lm -pedantic -otimecode timecode.c\n</code></pre>",
    "date_published": "2009-08-12T19:59:59-08:00",
    "tags": ["software"]
  }, {
    "id": "/blog/2009-06-27-sunset-index/",
    "url": "https://bumblehead.com/blog/2009-06-27-sunset-index/",
    "title": "Sunset Index",
    "summary": "Sunset Index",
    "content_html": "<p><img src=\"assets/img/sunset-index.jpg\" alt=\"sunset index\"></p>\n",
    "date_published": "2009-06-27T10:14:14-08:00",
    "tags": ["art", "painting", "camera"]
  }, {
    "id": "/blog/2009-06-07-room-in-june/",
    "url": "https://bumblehead.com/blog/2009-06-07-room-in-june/",
    "title": "Room in June",
    "summary": "Room in June",
    "content_html": "<ul>\n<li><a href=\"assets/img/june-in-dreams.jpg\"><img src=\"assets/img/june-in-dreams.pd.fit-100.avif\" alt=\"hand\"></a></li>\n<li><a href=\"assets/img/june-ourside-01.jpg\"><img src=\"assets/img/june-ourside-01.pd.fit-100.avif\" alt=\"hand\"></a></li>\n<li><a href=\"assets/img/june-ourside-02.jpg\"><img src=\"assets/img/june-ourside-02.pd.fit-100.avif\" alt=\"hand\"></a></li>\n<li><a href=\"assets/img/june-kristen.jpg\"><img src=\"assets/img/june-kristen.pd.fit-100.avif\" alt=\"hand\"></a></li>\n</ul>\n<p>This update brings another short video to the media section. A minor update to Stobo was made. Image transformations now affect the image in the preview window.</p>\n",
    "date_published": "2009-06-07T20:12:12-08:00",
    "tags": ["video", "camera", "software", "art"]
  }, {
    "id": "/media/2009-06-07-our-side/",
    "url": "https://bumblehead.com/media/2009-06-07-our-side/",
    "title": "Our Side",
    "summary": "Our Side",
    "content_html": "<p><video controls preload=\"auto\" width=\"360\" height=\"240\"\n  poster=\"assets/img/ourside.png\">\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/OurSide_360x240.mp4\" type='video/mp4' />\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/OurSide_360x240.ogv\" type='video/ogg' />\n</video></p>\n",
    "date_published": "2009-06-07T20:01:01-08:00",
    "tags": ["video"]
  }, {
    "id": "/blog/2009-05-26-html-page-added/",
    "url": "https://bumblehead.com/blog/2009-05-26-html-page-added/",
    "title": "HTML page added",
    "summary": "I've created a new HTML page -check it out. justingalligher.com",
    "content_html": "<ul>\n<li><a href=\"assets/img/justin-screenshot.jpg\"><img src=\"assets/img/justin-screenshot.pd.fit-100.avif\" alt=\"hand\"></a></li>\n<li><a href=\"assets/img/jgalligher-workflow.jpg\"><img src=\"assets/img/jgalligher-workflow.pd.fit-100.avif\" alt=\"hand\"></a></li>\n<li><a href=\"assets/img/stobo-screenshot.jpg\"><img src=\"assets/img/stobo-screenshot.pd.fit-100.avif\" alt=\"hand\"></a></li>\n</ul>\n<p>I&#39;ve created a new HTML page -check it out. justingalligher.com<em>(disabled link no longer resolves)</em></p>\n<p>I&#39;ve also updated Stobo. I updated the *.ico file and so now it contains multiple sizes of icon (32x32, 24x24, 16x16). Icon loading was changed so that it works better in windows environments..</p>\n",
    "date_published": "2009-05-26T21:48:48-08:00",
    "tags": ["camera", "misc", "software", "art"]
  }, {
    "id": "/media/2009-05-26-justingalligher.com/",
    "url": "https://bumblehead.com/media/2009-05-26-justingalligher.com/",
    "title": "justingalligher.com",
    "summary": "Justin is a photographer and his site is composed of simple XHTML documents.",
    "content_html": "<p><img src=\"assets/img/justin-screenshot.png\" alt=\"screenshot\" title=\"screenshot\"></p>\n<ul>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/soft/galligher_web.zip\" title=\"source\">justingalligher_com.zip</a></li>\n<li>justingalligher.com <em>(disabled link, no longer resolves)</em></li>\n</ul>\n<p>Justin is a photographer and his site is composed of simple XHTML documents.</p>\n<p>Felic is responsible for most of the design and the html/css are made by me. I think it&#39;s a great design, -it&#39;s simple and original.</p>\n",
    "date_published": "2009-05-26T09:45:45-08:00",
    "tags": ["software"]
  }, {
    "id": "/media/2009-05-25-schoolhouse/",
    "url": "https://bumblehead.com/media/2009-05-25-schoolhouse/",
    "title": "schoolhouse",
    "summary": "A 3D schoolhouse made with blender.",
    "content_html": "<p><img src=\"assets/img/schoolhouse-screenshot.jpg\" alt=\"screenshot\" title=\"screenshot\"></p>\n<p><a href=\"https://bumblehead.gitlab.io/archive-soft/soft/house_11.blend\" title=\"house11.blend\">A 3D schoolhouse</a> made with blender.</p>\n",
    "date_published": "2009-05-25T13:08:08-08:00",
    "tags": ["3d"]
  }, {
    "id": "/blog/2009-05-20-timgeorge/",
    "url": "https://bumblehead.com/blog/2009-05-20-timgeorge/",
    "title": "timgeorge",
    "summary": "I finished designing and building a web site for my friend Tim. You can see it at timgeorge.net.",
    "content_html": "<ul>\n<li><a href=\"assets/img/notepad-photo.jpg\"><img src=\"assets/img/notepad-photo.pd.fit-100.avif\" alt=\"notepad\"></a></li>\n<li><a href=\"assets/img/chs-load.jpg\"><img src=\"assets/img/chs-load.pd.fit-100.avif\" alt=\"chs load\"></a></li>\n<li><a href=\"assets/img/chris-bw.jpg\"><img src=\"assets/img/chris-bw.pd.fit-100.avif\" alt=\"chris bw\"></a></li>\n</ul>\n<p>I finished designing and building a web site for my friend Tim. You can see it at timgeorge.net. (the link no longer resolves)</p>\n",
    "date_published": "2009-05-20T12:16:16-08:00",
    "tags": ["video", "camera", "sculpture", "professional", "games", "software"]
  }, {
    "id": "/blog/2009-05-08-spring-time/",
    "url": "https://bumblehead.com/blog/2009-05-08-spring-time/",
    "title": "spring time :)",
    "summary": "Do you feel a potent creative energy in the air right now? Is it the spring sunshine...?",
    "content_html": "<p>Do you feel a potent creative energy in the air right now? Is it the spring sunshine...?</p>\n<p>I&#39;ve updated Stobo. I removed or optimized algorithms that were slowing Stobo down and I fixed a broken reference in the stop button&#39;s event handler.</p>\n<p>Here&#39;s an image of me working on Stobo earlier today...</p>\n<p><img src=\"assets/img/gross-clinic.jpeg\" alt=\"stobo\"></p>\n",
    "date_published": "2009-05-08T22:46:46-08:00",
    "tags": ["software", "art"]
  }, {
    "id": "/media/2009-05-05-the-black-box/",
    "url": "https://bumblehead.com/media/2009-05-05-the-black-box/",
    "title": "The Black Box",
    "summary": "The Black Box may be the most important video I've produced so far. Producing it absorbed a lot of time. Music made by Hollywood artist Cortex Accellera was made just for this video.",
    "content_html": "<p><video controls preload=\"auto\" width=\"360\" height=\"240\"\n  poster=\"assets/img/BlackBox.jpg\">\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/BlackBox_360x240.mp4\" type=\"video/mp4\" />\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/BlackBox_360x240.ogv\" type=\"video/ogg\" />\n</video></p>\n<p>The Black Box may be the most important video I&#39;ve produced so far. Producing it absorbed a lot of time. Music made by Hollywood artist Cortex Accellera was made just for this video. I&#39;m sending it around to film and animation festivals right now, which means that I&#39;m not allowed to publicy host the entire video, or even an entire shot. This shot was edited out of the final video, so I don&#39;t think I&#39;m breaking any rules by sharing it here. Enjoy.</p>\n<p>Curriculae Vitae for The Black Box</p>\n<ol>\n<li>Mistaken Film and Video Festival\n(British Columbia CA. 2009)</li>\n<li>{Fusion}\n(Long Beach California US. 2009)</li>\n<li>5 Second Film Festival\n(Claremont CA. 2009)</li>\n<li>???</li>\n</ol>\n",
    "date_published": "2009-05-05T21:32:32-08:00",
    "tags": ["video"]
  }, {
    "id": "/media/2009-05-05-foilness/",
    "url": "https://bumblehead.com/media/2009-05-05-foilness/",
    "title": "foilness",
    "summary": "foilness",
    "content_html": "<p><video id=\"example_video_1\" class=\"video-js vjs-default-skin\"\n  controls preload=\"auto\" width=\"360\" height=\"240\"\n  poster=\"assets/img/Foilness.jpg\"\n  data-setup='{\"example_option\":true}'>\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/Foilness_360x240.mp4\" type='video/mp4' />\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/Foilness_360x240.ogv\" type='video/ogg' />\n</video> </p>\n<ul>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/video/Foilness_360x240.mp4\" title=\"mp4\">Foilness.mp4</a></li>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/video/Foilness_360x240.ogv\" title=\"ogv\">Foilness.ogv</a></li>\n</ul>\n",
    "date_published": "2009-05-05T21:25:25-08:00",
    "tags": ["video"]
  }, {
    "id": "/media/2009-05-05-the-bus-video/",
    "url": "https://bumblehead.com/media/2009-05-05-the-bus-video/",
    "title": "The BUS VIDEO!",
    "summary": "The BUS VIDEO!",
    "content_html": "<p><video controls preload=\"auto\" width=\"360\" height=\"240\"\n  poster=\"assets/img/bus-video.gif\">\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/Bus_360x240.mp4\" type=\"video/mp4\" />\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/Bus_360x240.ogv\" type=\"video/ogg\" />\n</video> </p>\n<ul>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/video/Bus_360x240.mp4\" title=\"mp4\">Bus.mp4</a></li>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/video/Bus_360x240.ogv\" title=\"ogv\">Bus.ogv</a></li>\n</ul>\n",
    "date_published": "2009-05-05T21:18:18-08:00",
    "tags": ["video"]
  }, {
    "id": "/blog/2009-05-05-big-update/",
    "url": "https://bumblehead.com/blog/2009-05-05-big-update/",
    "title": "big update",
    "summary": "Today I'm releasing Stobo-1.0",
    "content_html": "<ul>\n<li><a href=\"assets/img/stobo-vista-screen.jpg\"><img src=\"assets/img/stobo-vista-screen.pd.fit-100.avif\" alt=\"screenshot\"></a></li>\n<li><a href=\"assets/img/stobo-linux-screen.jpg\"><img src=\"assets/img/stobo-linux-screen.pd.fit-100.avif\" alt=\"screenshot\"></a></li>\n<li><a href=\"assets/img/stobo-osx.jpg\"><img src=\"assets/img/stobo-osx.pd.fit-100.avif\" alt=\"screenshot\"></a></li>\n<li><a href=\"assets/img/stobo-about-screen.jpg\"><img src=\"assets/img/stobo-about-screen.pd.fit-100.avif\" alt=\"screenshot\"></a></li>\n</ul>\n<p>Today I&#39;m releasing Stobo-1.0</p>\n<p><img src=\"assets/img/stobo_linux.png\" alt=\"stobo\"></p>\n<p>The 1.0&#39;ness of this release signifies my opinion that Stobo is fully functional software. It has not been idiot-proofed yet, but that&#39;ll&#39;ve happened in the 2.0 release.</p>\n<p>Here&#39;s what Stobo is. It&#39;s the missing stop-motion link in the free software chain. Stobo will &#39;listen&#39; to a directory and will recognize image files if any appear in the directory. All image files in the directory are automatically copied, formatted, renamed, and saved to another location (for example, a network-mounted directory).</p>\n<p>It&#39;s free. it&#39;s cross-platform. It&#39;s camera-agnostic. It&#39;s easy to use. If you don&#39;t see the utility of this, you are either a) not a stopmotion animator, b) using the wrong work-flow or c) you are person who likes spending money (don&#39;t be ashamed).</p>\n<p>If you are &#39;c)&#39;, I still recommend that you take a look at Stobo. If you use Stobo, you&#39;ll be able to access the developer, me, for suggestions or help at any time. Note: I do love you, but don&#39;t abuse that :).</p>\n",
    "date_published": "2009-05-05T19:47:47-08:00",
    "tags": ["video", "camera", "software", "art"]
  }, {
    "id": "/blog/2009-03-15-dubin/",
    "url": "https://bumblehead.com/blog/2009-03-15-dubin/",
    "title": "dubin",
    "summary": "dubin",
    "content_html": "<p><img src=\"assets/img/oma.jpg\" alt=\"oma dubin\"></p>\n",
    "date_published": "2009-03-15T22:41:41-08:00",
    "tags": ["drawing", "2d"]
  }, {
    "id": "/blog/2008-11-27-cg-image/",
    "url": "https://bumblehead.com/blog/2008-11-27-cg-image/",
    "title": "CG Image",
    "summary": "CG Image",
    "content_html": "<p><img src=\"assets/img/fractal.png\" alt=\"CG Image\"></p>\n",
    "date_published": "2008-11-27T11:20:20-08:00",
    "tags": ["art"]
  }, {
    "id": "/media/2008-11-25-sepia-stopmo/",
    "url": "https://bumblehead.com/media/2008-11-25-sepia-stopmo/",
    "title": "Sepia Stopmo",
    "summary": "Sepia Stopmo",
    "content_html": "<p><img src=\"assets/img/sepia.gif\" alt=\"screenshot\" title=\"screenshot\"></p>\n",
    "date_published": "2008-11-25T18:40:40-08:00",
    "tags": ["2d", "sculpture"]
  }, {
    "id": "/blog/2008-11-11-creation/",
    "url": "https://bumblehead.com/blog/2008-11-11-creation/",
    "title": "creation",
    "summary": "bumblehead's PHP is remade!",
    "content_html": "<ul>\n<li><a href=\"assets/img/creation-arm-scaffold-01.jpg\"><img src=\"assets/img/creation-arm-scaffold-01.pd.fit-100.avif\" alt=\"garage\"></a></li>\n<li><a href=\"assets/img/creation-arm-scaffold-02.jpg\"><img src=\"assets/img/creation-arm-scaffold-02.pd.fit-100.avif\" alt=\"garage\"></a></li>\n<li><a href=\"assets/img/creation-arm-scaffold-03.jpg\"><img src=\"assets/img/creation-arm-scaffold-03.pd.fit-100.avif\" alt=\"garage\"></a></li>\n<li><a href=\"assets/img/creation-arm-scaffold-04.jpg\"><img src=\"assets/img/creation-arm-scaffold-04.pd.fit-100.avif\" alt=\"garage\"></a></li>\n</ul>\n<p>bumblehead&#39;s PHP is remade!</p>\n",
    "date_published": "2008-11-11T19:57:57-08:00",
    "tags": ["sculpture", "misc", "professional", "software", "drawing", "art"]
  }, {
    "id": "/media/2008-10-15-actionscript-syntax/",
    "url": "https://bumblehead.com/media/2008-10-15-actionscript-syntax/",
    "title": "Actionscript Syntax",
    "summary": "This script is for you if you are trying to develop actionscript software on an Ubuntu linux system. The script sets a mime type for .as and creates a syntax highlighting scheme",
    "content_html": "<p><img src=\"assets/img/actionscript-src-screen.png\" alt=\"screenshot\" title=\"actionscript syntax highlighting\"></p>\n<p><a href=\"https://bumblehead.gitlab.io/archive-soft/soft/add_flash_mime.sh\" title=\"add_flash_mime.sh\">This script</a> is for you if you are trying to develop actionscript software on an Ubuntu linux system. The script sets a mime type for <code>.as</code> and creates a syntax highlighting scheme that any gtksourceview application will auto-associate with your actionscript files. What that means is that mono delvelop, anjuta and gedit will correctly auto-highlight your <code>.as</code> files.</p>\n<p>Julien Castelain authored XML and LANG files that are used by the script. His original files came packaged with directives that didn&#39;t create correct mime-types on an Ubuntu system. I wrapped the files in a script so that the correct setup is automated.</p>\n<p>download the file and, from a terminal, run this:</p>\n<pre><code class=\"hljs language-bash\">$ <span class=\"hljs-built_in\">sudo</span> bash /path/to/add_flash_mime.sh\n</code></pre><p>Restart your desktop and you&#39;re ready to go!</p>\n",
    "date_published": "2008-10-15T18:54:54-08:00",
    "tags": ["bash"]
  }, {
    "id": "/blog/2008-09-27-pyramid/",
    "url": "https://bumblehead.com/blog/2008-09-27-pyramid/",
    "title": "pyramid",
    "summary": "pyramid",
    "content_html": "<p><img src=\"assets/img/pyramid.jpg\" alt=\"pyramid\"></p>\n",
    "date_published": "2008-09-27T21:45:45-08:00",
    "tags": ["misc"]
  }, {
    "id": "/media/2008-09-03-red-green-organic/",
    "url": "https://bumblehead.com/media/2008-09-03-red-green-organic/",
    "title": "red green organic",
    "summary": "A video featuring animated green and red color. An experiment with lighting.",
    "content_html": "<p><video controls preload=\"auto\" width=\"360\" height=\"240\"\n  poster=\"assets/img/LightDiff.jpg\">\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/LightDiff_360x240.mp4\" type='video/mp4' />\n <source src=\"https://bumblehead.gitlab.io/archive-soft/video/LightDiff_360x240.ogv\" type='video/ogg' />\n</video></p>\n<p>A video featuring animated green and red color. An experiment with lighting.</p>\n<ul>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/video/LightDiff_360x240.mp4\" title=\"mp4\">LightDiff.mp4</a></li>\n<li><a href=\"https://bumblehead.gitlab.io/archive-soft/video/LightDiff_360x240.ogv\" title=\"ogv\">LightDiff.ogv</a></li>\n</ul>\n",
    "date_published": "2008-09-03T11:00:00-08:00",
    "tags": ["video"]
  }, {
    "id": "/media/2008-09-03-flash-sketchbook/",
    "url": "https://bumblehead.com/media/2008-09-03-flash-sketchbook/",
    "title": "flash sketchbook",
    "summary": "This is a flash page that I designed and created for a friend, to feature storyboard content.",
    "content_html": "<p><img src=\"assets/img/timgeorge-flash-app-screen-02.jpg\" alt=\"screenshot\"></p>\n<p>This is a flash page that I designed and created for a friend, to feature storyboard content.</p>\n<p>The site is <a href=\"https://bumblehead.gitlab.io/archive-soft/soft/TimGeorge_Flash.zip\" title=\"TimGeorge_Flash.zip\">not up</a> any longer. It featured &#39;pages&#39; that would open and change with stop-motion animation.</p>\n",
    "date_published": "2008-09-03T11:00:00-08:00",
    "tags": ["software", "professional"]
  }, {
    "id": "/blog/2008-08-31-tape-out/",
    "url": "https://bumblehead.com/blog/2008-08-31-tape-out/",
    "title": "Tape Out!",
    "summary": "I finished rendering my animation today! I've been working on it for a long time.",
    "content_html": "<ul>\n<li><a href=\"assets/img/tape-out-cinelerra-screen.jpg\"><img src=\"assets/img/tape-out-cinelerra-screen.pd.fit-100.avif\" alt=\"shake\"></a></li>\n<li><a href=\"assets/img/tape-out-sh-screen.jpg\"><img src=\"assets/img/tape-out-sh-screen.pd.fit-100.avif\" alt=\"bash\"></a></li>\n<li><a href=\"assets/img/tape-out-shake-screen.jpg\"><img src=\"assets/img/tape-out-shake-screen.pd.fit-100.avif\" alt=\"shake\"></a></li>\n</ul>\n<p>I finished rendering my animation today! I&#39;ve been working on it for a long time. I was determined to use linux to get all of the digital work done. The path was forsaken and often un-clear, but I finally made it to the end.</p>\n",
    "date_published": "2008-08-31T20:44:44-08:00",
    "tags": ["software", "art"]
  }]
}