<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Kyle Graehl</title>
 <link href="http://kyle.graehl.org/atom.xml" rel="self"/>
 <link href="http://kyle.graehl.org/"/>
 <updated>2026-02-23T11:18:30+00:00</updated>
 <id>http://kyle.graehl.org/</id>
 <author>
   <name>Kyle Graehl</name>
   <email>kyle@graehl.org</email>
 </author>

 
 <entry>
   <title>Testing does this work</title>
   <link href="http://kyle.graehl.org/testing/2019/08/03/testing-does-this-work.html"/>
   <updated>2019-08-03T00:00:00+00:00</updated>
   <id>http://kyle.graehl.org/testing/2019/08/03/testing-does-this-work</id>
   <content type="html">&lt;p&gt;Testing if this works. 1 2 3.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>My Devtools wishlist</title>
   <link href="http://kyle.graehl.org/javascript/devtools/chrome/2016/04/13/devtools-wishlist.html"/>
   <updated>2016-04-13T00:00:00+00:00</updated>
   <id>http://kyle.graehl.org/javascript/devtools/chrome/2016/04/13/devtools-wishlist</id>
   <content type="html">&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;This mostly regards Chrome apps and extensions. When a window is created that previously had the devtools open, it remembers
that the devtools were open, and reopens devtools. Unfortunately there is some delay and the devtools have not yet attached, so they will
miss catching any exceptions for the first few hundred ms or so.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Turn off editing in source window. 99% of the time I don’t want to edit in the source window, I want to type something in
the console. I would like to turn off editing and have keyboard focus be on the console window. Currently I press escape twice
about every time I focus in the devtools to force focus on the console window.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;An option to make a sound when we enter the debugger. Ding!&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;
</content>
 </entry>
 
 <entry>
   <title>MP4Cast for Google Cast</title>
   <link href="http://kyle.graehl.org/javascript/chrome-app/chromecast/cast/mp4cast/2016/04/06/mp4cast-for-google-cast.html"/>
   <updated>2016-04-06T00:00:00+00:00</updated>
   <id>http://kyle.graehl.org/javascript/chrome-app/chromecast/cast/mp4cast/2016/04/06/mp4cast-for-google-cast</id>
   <content type="html">&lt;p&gt;I’ve just released a new Chrome App, &lt;a href=&quot;https://chrome.google.com/webstore/detail/mp4cast-for-google-chrome/lbfdhgbfobdiokoifnflhlkaphobcgmo&quot;&gt;MP4Cast&lt;/a&gt;. I started working on it when I noticed there was no way for me to stream a locally stored mp4 video from my ARM Chromebook directly to my Google Chromecast™.&lt;/p&gt;

&lt;p&gt;Actually, it sort of was possible. I had to spin up &lt;a href=&quot;https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb&quot;&gt;Web Server for Chrome&lt;/a&gt;, select the directory containing the file, then make sure the options were set to allow connections from other computers, then find the exact media URL, and then find a way to tell Chromecast to play that URL. Not a very friendly experience!&lt;/p&gt;

&lt;p&gt;So to simplify that, I built MP4Cast.&lt;/p&gt;

&lt;p&gt;You can read more about it on the &lt;a href=&quot;https://www.mp4cast.com/help.html&quot;&gt;MP4Cast help page&lt;/a&gt;. You can use it today, all you need to do is visit &lt;a href=&quot;https://www.mp4cast.com&quot;&gt;www.mp4cast.com&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Web Server for Chrome</title>
   <link href="http://kyle.graehl.org/javascript/chrome-app/2015/10/01/web-server-for-chrome.html"/>
   <updated>2015-10-01T00:00:00+00:00</updated>
   <id>http://kyle.graehl.org/javascript/chrome-app/2015/10/01/web server for chrome</id>
   <content type="html">&lt;p&gt;I just put a new user interface on my &lt;a href=&quot;https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb&quot;&gt;Web Server for Chrome&lt;/a&gt;.
I used the post 1.0 Polymer release and a few paper components. The documentation for Polymer is a little obtuse for somebody
like me who just wants to code a UI without learning the detailed inner workings of Polymer. But altogether it was OK.&lt;/p&gt;

&lt;p&gt;If you’re ever in need of a basic static web server, definitely give it a try! It’s open source with a MIT license and &lt;a href=&quot;https://github.com/kzahel/web-server-chrome&quot;&gt;available on github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ever since Chrome 44 went stable about a month ago, ChromeOS has had the ability to open up the firewall. So
now the web server app can also serve files over the local network on a Chromebook. Pretty useful!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Sorry facebook, I can't keep your mobile app installed</title>
   <link href="http://kyle.graehl.org/rant/2014/09/21/sorry-facebook.html"/>
   <updated>2014-09-21T00:00:00+00:00</updated>
   <id>http://kyle.graehl.org/rant/2014/09/21/sorry facebook</id>
   <content type="html">&lt;p&gt;I have a few friends who don’t use facebook, at all. Well perhaps one day I will manage this myself, but for
a number of reasons I haven’t yet managed this. I do look forward to the day that facebook is no longer relevant
to my life.&lt;/p&gt;

&lt;p&gt;But I have done one thing that nobody else I know does. I have uninstalled the facebook app from my android phone
and haven’t missed it in the slightest. I now use the mobile facebook website instead.
There are three main reasons for this&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;I don’t like all the permissions the app requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’m generally paranoid about permission prompts and like to reduce the number of apps which have access to essentially
all data on my phone and all sensors on my phone.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Facebook messenger. I was so annoyed when I could no longer read or send facebook messages within the app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don’t want to have two facebook apps installed, both with more permissions than any other app except possibly google services. Also
I have a low end phone and this is slow.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Links opening in a webview.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the straw that broke the camel’s back. After clicking on open in the actual web browser several times,
I decided it was over.&lt;/p&gt;

&lt;p&gt;So what are the drawbacks of using the facebook mobile website instead of the native app? For me, there are none. Horay!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>ISO Extractor Chrome app</title>
   <link href="http://kyle.graehl.org/javascript/chrome-app/2014/09/11/iso-extractor.html"/>
   <updated>2014-09-11T00:00:00+00:00</updated>
   <id>http://kyle.graehl.org/javascript/chrome-app/2014/09/11/iso-extractor</id>
   <content type="html">&lt;p&gt;I have been using a Chromebook for my main computer for a long time now. Every once and a while I have a strange itch I need to scratch. Most recently, I had an ISO file that I needed to extract some files from.&lt;/p&gt;

&lt;p&gt;Now of course the ISO 9660 file format is not exactly one that many using ChromeOS need to know about, let alone want extract files from. But for some reason I wanted to write an app that would let me extract the files.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://chrome.google.com/webstore/detail/iso-extractor/fcpcpcgghhoelelnmdecoldpaheimogc&quot;&gt;ISO Extractor - Available on the Chrome Web Store&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/kzahel/iso-extractor&quot;&gt;ISO Extractor Source code on Github&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My first step was to find a nice library that had minimal dependencies and would be easily translated into javascript. I found a &lt;a href=&quot;https://github.com/barneygale/iso9660&quot;&gt;small Python library on github iso9660.py&lt;/a&gt; which looked perfect. Only it uses generators (yield) semantics for iterating over files, which would not easily translate into javascript. What to do?&lt;/p&gt;

&lt;p&gt;I pull out the trusty &lt;a href=&quot;https://github.com/google/traceur-compiler&quot;&gt;google-traceur-compiler&lt;/a&gt; which lets you compile ECMAScript6 which has generators into standard javascript.&lt;/p&gt;

&lt;p&gt;First, I needed to have something that behaves like cStringIO on a file. I need to .seek() and .read() synchronously. Javascript gives us FileReaderSync which must be run in a web worker.&lt;/p&gt;

&lt;p&gt;Then, I needed an equivalent to python’s “struct” module. I found a &lt;a href=&quot;https://github.com/tjfontaine/node-struct&quot;&gt;node.js module by tjfontaine&lt;/a&gt; and proceeded to make minor modifications to translate from node’s Buffer objects into standard javascript DataView and the .getUint8(position, isLittleEndian) family. You can use my modified &lt;a href=&quot;https://github.com/kzahel/iso-extractor/blob/master/jsstruct.js&quot;&gt;jsstruct.js&lt;/a&gt; if you ever need to do something similar. I didn’t translate the .pack() stuff, only the .unpack() things.&lt;/p&gt;

&lt;p&gt;When debugging breakpoints traceur-compiled javascript code that uses generators, it looks like a horrible mess (unreadable state machine case statements). However, if you go to chrome://flags and enable experimental ES6 javascript, you can simply run the generators without the aid of traceur, and you can step through your code normally. Almost. As it turned out, hitting a breakpoint inside a generator function inside a web worker was causing chrome to crash. Maybe this will be fixed in the future.&lt;/p&gt;

&lt;p&gt;In the end, I was able to get a directory listing of the files within an ISO, which seemed good enough for a days work, so I released the app and see that it’s getting about 10 installs per day. Which means maybe I’ll add some more functionality, like the ability to extract and save files from the ISO image.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Chrome fileSystem notes</title>
   <link href="http://kyle.graehl.org/javascript/development/chrome-app/2014/02/26/chrome-filesystem-notes.html"/>
   <updated>2014-02-26T10:00:00+00:00</updated>
   <id>http://kyle.graehl.org/javascript/development/chrome-app/2014/02/26/chrome-filesystem-notes</id>
   <content type="html">&lt;p&gt;(Update – I found out what the problem was. The app was being “suspended” and I was not listening for the event. When an app is suspended, nothing is guaranteed to work anymore). So make sure and listen for the chrome.runtime.onSuspend event!&lt;/p&gt;

&lt;p&gt;I’ve been trying to fix a bug in JSTorrent for the past few days. The
problem I’m seeing is that an HTML5 DirectoryEntry reference becomes
“stuck” – doing any sort of request against it like .getFile() or
.getMetadata() simply does not fire any callbacks. I’ve rewritten the
whole Disk I/O subsystem of JSTorrent, hoping to get better insight
into which conditions trigger this “broken” state.&lt;/p&gt;

&lt;p&gt;One thing I’ve started doing is keeping a cache of FileEntry objects
and re-using those. That seems to work pretty well. I haven’t run into
any issues re-using a FileEntry reference, even when the underlying
file changes due to other processes writing to or truncating the file.&lt;/p&gt;

&lt;p&gt;However, if you do the same thing to the result of a FileEntry.file()
(the actual File object on which you can do .slice() and use a
FileReader to do reads), the reference becomes invalid once the
underlying file is modified in any way (even “touch”ing the file will
make the file reference invalid)&lt;/p&gt;

&lt;p&gt;Originally I wanted to use the synchronous versions of all these APIs
because that would have been much simpler. But unfortunately there is
no way to pass a FileEntry to a web worker,
(https://code.google.com/p/chromium/issues/detail?id=242373), and you
need a FileEntry to be able to do file operations (currently you call
FileEntry.createWriter and get a FileWriter object).&lt;/p&gt;

&lt;p&gt;Experiment: what happens when you have a cached DirectoryEntry and
somebody moves the file? It fires the error callback to whatever you
try to do on it.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Privacy Guardr chrome extension</title>
   <link href="http://kyle.graehl.org/javascript/development/chrome-extension/privacy/2014/01/22/privacy-guard-extension.html"/>
   <updated>2014-01-22T16:01:00+00:00</updated>
   <id>http://kyle.graehl.org/javascript/development/chrome-extension/privacy/2014/01/22/privacy-guard-extension</id>
   <content type="html">&lt;p&gt;Update Dec 1 2014 - Changed name of app from Privacy Guard to Privacy Guardr due to trademark conflict with privacyguard.com&lt;/p&gt;

&lt;p&gt;Today I am releasing a very simple Chrome extension, &lt;a href=&quot;https://chrome.google.com/webstore/detail/privacy-guardr/edcajbacgdcdeecojhlllbgingbjfbmk&quot;&gt;Privacy Guardr&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Recently there have been a few articles about malware extensions in
the Chrome Web Store. Of course, malware and spyware has been rampant
in the Chrome Web Store for quite a while already.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://arstechnica.com/security/2014/01/malware-vendors-buy-chrome-extensions-to-send-adware-filled-updates/?&quot;&gt;Article on arstechnica&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.omgchrome.com/chrome-users-start-raise-awareness-extensions-known-peddle-adware/&quot;&gt;Article on OMGChrome&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://m.androidauthority.com/google-chrome-ad-injecting-extensions-337074/&quot;&gt;Article on Android Authority&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Lifehacker recently featured &lt;a href=&quot;http://lifehacker.com/chrome-protector-notifies-you-if-youre-running-an-adwa-1505371480?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+lifehacker%2Ffull+%28Lifehacker%29&quot;&gt;an
article&lt;/a&gt;
about an extension “ExtShield” that notifies you if you have one of a
set of known malicious extensions installed.&lt;/p&gt;

&lt;p&gt;The funny thing about ExtShield is that this extension could very well
be malware itself. For it requests the most dangerous permission an
extension can ask for (Access to all data on all websites), and it has
no reason to ask for this permission. It simply does not need it in
order to function.&lt;/p&gt;

&lt;p&gt;I have had the idea to do a simple Chrome Extension that simply identifies which installed extensions have “high risk” permissions.&lt;/p&gt;

&lt;p&gt;So I am announcing &lt;a href=&quot;https://chrome.google.com/webstore/detail/privacy-guardr/edcajbacgdcdeecojhlllbgingbjfbmk&quot;&gt;Privacy Guardr&lt;/a&gt;, a free extension in the Chrome Web Store. I am releasing it now with a minimal set of functionality because it is, I believe, more useful than something like ExtShield. For one, the &lt;a href=&quot;https://github.com/kzahel/privacy-guard-extension&quot;&gt;source code&lt;/a&gt; is freely available, and it also does not make use of hard-coded lists of known “bad” extensions. It simply helps you by giving you all the information in a glance and lets you filter extensions and apps by their “risk level”&lt;/p&gt;

&lt;p&gt;For example, the Pinterest Pin it Button Chrome extension is a high-risk app, because it requests the “Access your data on all websites” permission. This app is the perfect example of an app that is flagrantly requesting more permissions than it needs. The proliferation of apps that request these permissions where they are clearly not needed (they can use a browser action instead) contributes to numbing users to the gravity of the permission grant.&lt;/p&gt;

&lt;p&gt;The “Access your data on all websites” permission means that the extension can steal any authentication tokens, capture every keystroke on every website, and do so rather undetected.&lt;/p&gt;

&lt;p&gt;So, make your reasonable voice heard, and re-evaluate whether you need to have high risk extensions installed. At the very least, take a look at who is publishing the extension and make a judgement as to whether you can trust the publisher.&lt;/p&gt;

&lt;p&gt;I have a few ideas for more features to add to the Privacy Guardr extension. I want to store the publisher data and be able to notify the user when an extension’s publisher is changed. I also would like to be able to mark certain publishers as exempt (for example, if you want to trust all Google apps and extensions). And of course, I want to add actions inside the app to disable and remove extensions. I may also incorporate lists of extensions known to have bad behaviors (injecting ads without notice, stealing affiliate links)&lt;/p&gt;

&lt;p&gt;tldr; Give &lt;a href=&quot;https://chrome.google.com/webstore/detail/privacy-guardr/edcajbacgdcdeecojhlllbgingbjfbmk&quot;&gt;Privacy Guardr&lt;/a&gt; a try.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Using Chrome Platform app chrome.fileSystem.retainEntry</title>
   <link href="http://kyle.graehl.org/javascript/development/chrome-packaged-app/2013/12/04/chrome-app-fileSystem-retainEntry.html"/>
   <updated>2013-12-04T14:01:00+00:00</updated>
   <id>http://kyle.graehl.org/javascript/development/chrome-packaged-app/2013/12/04/chrome-app-fileSystem-retainEntry</id>
   <content type="html">&lt;p&gt;I’ve been tweaking JSTorrent to add support for writing directly to
user selected directories.&lt;/p&gt;

&lt;p&gt;In the manifest file, you need to add the “write”, “directory”, and
“retainEntries” permissions. The documentation is &lt;a href=&quot;http://developer.chrome.com/apps/fileSystem.html&quot;&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tricky part is handling external media. There’s a way to get
events when external media is attached and detached. You need to
request “system.storage” permission. Docs &lt;a href=&quot;http://developer.chrome.com/apps/system_storage.html&quot;&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Unfortunately the directory “Entry” given by
chrome.fileSystem.chooseEntry with the {type:”directory”} option does
not give any information as to whether the directory selected by the
user resides on an external storage or the internal storage of the
device.&lt;/p&gt;

&lt;p&gt;This could be a very poor user experience. A torrent job would simply
show some kind of “storage error” and not be able to tell the user
that they need to re-attach a specific external storage device.&lt;/p&gt;

&lt;p&gt;The documentation for chrome.* APIs is spartan as usual, so it leaves
developers to explore all the edge cases and make guesses as to
whether these are accidental or intended and with unit tests backing
these behaviors.&lt;/p&gt;

&lt;p&gt;When the storage is detached, a call to chrome.fileSystem.restoreEntry
will NOT fail! However, when trying to do some kind of access on the
machine that would require actually accessing the device, such as
trying to read the entry’s metadata, you will get the error callback.&lt;/p&gt;

&lt;p&gt;So it’s at least possible to infer that a given retained Entry may be
from a detachable storage, if doing a getMetadata call returns a
NotFoundError. However this error also occurs when the selected
directory is renamed or removed (incidentally, if a new directory is
created and has the same absolute path on the same disk, it can be
accessed and written to via retainEntry, even though the actual inode
is different)&lt;/p&gt;

&lt;p&gt;So the moral of the story is – to the retainEntry mechanism, there is
really no difference between external storage not being available, and
a directory simply being removed from the SSD/internal disk. I guess
that’s pretty elegant, after all. So simply messaging “directory or
external disk missing” is the simplest solution. Maybe only displaying
“or external disk” if chrome.system.storage.getInfo shows there was in
fact an external disk present when the user called chooseEntry.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Use yielding (await) in javascript today, with traceur!</title>
   <link href="http://kyle.graehl.org/es6/javascript/development/2013/08/27/use-es6-yielding-today.html"/>
   <updated>2013-08-27T12:01:00+00:00</updated>
   <id>http://kyle.graehl.org/es6/javascript/development/2013/08/27/use-es6-yielding-today</id>
   <content type="html">&lt;p&gt;Javascript is pretty annoying sometimes, especially when writing a lot of callbacks.
If you’re feeling adventurous, try out the ultra awesome &lt;a href=&quot;https://github.com/google/traceur-compiler&quot;&gt;traceur compiler&lt;/a&gt; which lets you use ECMAScript Harmony features today.&lt;/p&gt;

&lt;p&gt;Boilerplate code (traceur.js and bootstrap.js from traceur)&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://traceur-compiler.googlecode.com/git/bin/traceur.js&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://traceur-compiler.googlecode.com/git/src/bootstrap.js&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/javascript&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt; 
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;traceur&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;experimental&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;script &lt;/span&gt;&lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text/traceur&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The “traceur.options.experimental” is to enable the “await” keyword, which is what we’re going to show off.&lt;/p&gt;

&lt;p&gt;And now some boilerplate code to wrap the async XMLHttpRequest into a “Deferred” (a Promise).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;simpleGet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;deferred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Deferred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// traceur defines this&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;XMLHttpRequest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; 
  &lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onreadystatechange&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;readyState&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
      &lt;span class=&quot;nx&quot;&gt;deferred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; 
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt; 
  &lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; 
  &lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; 
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;deferred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Now here’s the cool part that we’ve been waiting for. You can now write
code that looks synchronous, but doesn’t block the event loop. This is
a definite readability win, as opposed to minor gains you get with
things like CoffeeScript.&lt;/p&gt;

&lt;h1 id=&quot;the-grand-finale&quot;&gt;The Grand Finale&lt;/h1&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;http://example.com/api&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; 
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;await&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;simpleGet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;GOT IT...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you’re already compiling your application into javascript, you
might as well do it with traceur and get some actual cool features (unlike
CoffeeScript, which only gives you ambiguous looking syntax that omits
parenthesis with function calls, ick)&lt;/p&gt;

&lt;p&gt;Have fun, and be safe!&lt;/p&gt;

&lt;p&gt;Here is what the compiled code for &lt;em&gt;run()&lt;/em&gt; ends up looking like:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$that&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$storedException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$finallyFallThrough&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Deferred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$waitTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$G&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;GState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;current&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;yieldReturn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;innerFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$yieldSent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$yieldAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;REQUESTIN...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$waitTask&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;simpleGet&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$waitTask&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$createCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$createErrback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;GOT IT...&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;errback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$storedException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;traceur compiler bug: invalid state in state machine&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;moveNext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$yieldSent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$yieldAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;innerFunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$yieldSent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$yieldAction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;catch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$caughtException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;$storedException&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$caughtException&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;switch&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;na&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$continuation&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;moveNext&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$G&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$createCallback&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;$value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;$continuation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$createErrback&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;$state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$newState&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;$err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;$continuation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;$continuation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createPromise&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Good thing we did not have to write that code!&lt;/p&gt;

&lt;p&gt;Make sure to go check out the &lt;a href=&quot;https://github.com/google/traceur-compiler&quot;&gt;traceur project on
github&lt;/a&gt; and show your
support for their badassery.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Chrome extension rants, optional permissions, and chrome.tabs</title>
   <link href="http://kyle.graehl.org/chrome,/extension,/development/2013/08/18/chrome-extension-rants.html"/>
   <updated>2013-08-18T10:53:00+00:00</updated>
   <id>http://kyle.graehl.org/chrome,/extension,/development/2013/08/18/chrome-extension-rants</id>
   <content type="html">&lt;p&gt;If you are the type that writes extensions that request access to
“access my browsing tabs and history” or “all data on all websites” or
“all data on my computer and all websites I visit” then please stop
reading now. Go ahead and request your permissions and I will happily
refuse to accept them.&lt;/p&gt;

&lt;p&gt;For people like myself, slightly more mindful of exposing myself to
unnecessary security risks, please read on. The main reason why chrome
extensions are so tricky is because &lt;a href=&quot;http://developer.chrome.com/extensions/permissions.html#manifest&quot;&gt;optional
permissions&lt;/a&gt;
are a relatively new feature, and many of the APIs are simply easier
to use when you have full access to everything.&lt;/p&gt;

&lt;p&gt;I have been hacking on a chrome extension for the past few days for a
&lt;a href=&quot;https://github.com/kzahel/spotify-web-extension&quot;&gt;hack project&lt;/a&gt;. I
have not written an extension before (having only done chrome platform
apps
, i.e. &lt;a href=&quot;https://chrome.google.com/webstore/detail/jstorrent/anhdpjpojoipgpmfanmedjghaligalgb&quot;&gt;jstorrent&lt;/a&gt;). Compared
to packaged apps, chrome extensions are &lt;em&gt;hard&lt;/em&gt;. Content scripts are a
pretty weird thing, and I am spending as much time on stack overflow
and &lt;a href=&quot;code.google.com/p/chromium/issues&quot;&gt;chromium issues&lt;/a&gt; as I am in my editor.&lt;/p&gt;

&lt;p&gt;Some things I’ve learned:&lt;/p&gt;

&lt;h2 id=&quot;chrometabs-is-a-complex-beast&quot;&gt;chrome.tabs is a complex beast&lt;/h2&gt;

&lt;p&gt;chrome.tabs is available even without any special permissions. But
  you won’t know the URLS for updated tabs. If your extension wants
  access to only a single domain (i.e. www.myapp.com) and you want to
  inject content scripts there, I found it wasn’t reliable doing it in
  the manifest with the “matches”. Perhaps I could write a test app
  and file a bug report. But this method is not flexible enough anyway.&lt;/p&gt;

&lt;p&gt;Rather than using the manifest origin matching to inject content
  scripts, doing it manually allows for added flexibility. With
  chrome.tabs.executeScript, you can have your extension request
  additional access (say &amp;lt;all_urls&amp;gt;”) and now inject on those
  pages. This is not possible with manifest based pattern matching.&lt;/p&gt;

&lt;p&gt;Each time you see a chrome.tabs.onUpdated, attempt to execute code
  from your (background) event page&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// keep a &quot;PID&quot; for the background page, so that the content script&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// can know if the background page was updated. Maybe also include the&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// version number, so a content script can know if the extension was&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// updated.&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;backgroundPID&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tabs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onUpdated&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tabId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;changeInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;tab&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;updateInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;pid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;backgroundPID&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;na&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;onUpdated&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;na&quot;&gt;changeInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;changeInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                    &lt;span class=&quot;na&quot;&gt;tabInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tab&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tabs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;executeScript&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tabId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
                            &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;var updateInfo=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
                                    &lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;updateInfo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
                                    &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;;[updateInfo,window.location.origin]&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; 
                            &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;results&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;undefined&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;// we didn&apos;t have access to this tab&apos;s origin&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
       &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;injectedContentScriptInfo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;results&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;// then we have window.location.origin information &lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;// for all content scripts which we were allowed to access&lt;/span&gt;

       &lt;span class=&quot;c1&quot;&gt;// now inject the actual content script, which will have access to relevant updateInfo &lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;// (so it will know not to run twice, etc)&lt;/span&gt;
       &lt;span class=&quot;nx&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tabs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;executeScript&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tabId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;your_content_script.js&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;content_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;// do other things if you want&lt;/span&gt;
       &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;

    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Of course this method has a distinct disadvantage. If you look in your
background page’s console logs, you’ll see a lot of errors “Cannot
access contents of url…”&lt;/p&gt;

&lt;p&gt;There is a chrome.tabs.query which will return a list of tabs matching
your host query, but it has no edge triggered option. Perhaps if you
&lt;a href=&quot;https://code.google.com/p/chromium/issues/detail?id=264704&quot;&gt;star this issue&lt;/a&gt; we
will see some improvement on this front.&lt;/p&gt;

&lt;h2 id=&quot;event-pages-are-cool&quot;&gt;&lt;a href=&quot;http://developer.chrome.com/extensions/event_pages.html&quot;&gt;Event pages&lt;/a&gt; are cool&lt;/h2&gt;

&lt;p&gt;From that page: “the performance advantages are significant,
especially on low-power devices.” I wonder if this means extensions
on ARM devices, like androids is to come in the near future.&lt;/p&gt;

</content>
 </entry>
 
 <entry>
   <title>Spotify skip track chrome extension</title>
   <link href="http://kyle.graehl.org/chrome,/development/2013/08/15/spotify-skip-track-extension.html"/>
   <updated>2013-08-15T14:07:00+00:00</updated>
   <id>http://kyle.graehl.org/chrome,/development/2013/08/15/spotify-skip-track-extension</id>
   <content type="html">&lt;p&gt;&lt;em&gt;Update&lt;/em&gt; - the more advanced extension (&lt;a href=&quot;https://chrome.google.com/webstore/detail/spotify-web-extension/gkmfagbigbkgjbbphlemmafhjabeofek&quot;&gt;Spotify Web Extension&lt;/a&gt; has remote-control abilities. It uses Google Cloud Messaging to setup a push channel. When you want to remote control another computer, my server wakes up your extension using the channel, and then sets up a relay between the two (a WebSocket connection on both ends).&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I just published a very simple extension to skip to the next track in the &lt;a href=&quot;https://play.spotify.com&quot;&gt;spotify web player&lt;/a&gt;. Here is the 
&lt;a href=&quot;https://chrome.google.com/webstore/detail/cioodogigbffcemogihoifckgacjaakc&quot;&gt;chrome web store link&lt;/a&gt;. The source code is also on &lt;a href=&quot;https://github.com/kzahel/skip-track-extension&quot;&gt;github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Make sure to set a keyboard shortcut for easiest use (go to the chrome extensions page (type chrome://extensions in the URL Bar) and on the bottom click “Keyboard shortcuts”. Enjoy!&lt;/p&gt;

&lt;p&gt;I’m working on a more &lt;a href=&quot;https://github.com/kzahel/spotify-web-extension&quot;&gt;featurefull extension&lt;/a&gt; that will allow you to do more than just skip tracks :-)&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>finally using my pixel!</title>
   <link href="http://kyle.graehl.org/pixel,/chromeos,/development/2013/08/14/finally-using-my-pixel.html"/>
   <updated>2013-08-14T10:11:00+00:00</updated>
   <id>http://kyle.graehl.org/pixel,/chromeos,/development/2013/08/14/finally-using-my-pixel</id>
   <content type="html">&lt;p&gt;The other day I stayed home nursing my tennis back and had left my work computer (a macbook pro) at work, so I had to make do with my secondary computer, a chromebook pixel I picked up at Google I/O.&lt;/p&gt;

&lt;p&gt;I really liked the hardware of the machine and when I first got it I tried crouton but was annoyed that the touchscreen didn’t work very well in X11. You have to run ChromeOS’s fancy window manager system (called Aura) and a special Chrome browser build to enjoy all the benefits of the multitouch screen.&lt;/p&gt;

&lt;p&gt;I did manage to settle on a development environment that suits me alright.&lt;/p&gt;

&lt;p&gt;Little known tip. Shift-Control-plus and Shift-Control-minus do a GLOBAL zoom in/out. If you want more screen real estate quickly then you can use your tiny display as if it were a full 2560 monitor. Super useful!&lt;/p&gt;

&lt;p&gt;First of all, enable developer mode. Then follow crouton instructions to setup your linux “VM” (a chroot actually) at &lt;a href=&quot;https://github.com/dnschneid/crouton&quot;&gt;crouton&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I recommend setting a chromeos root password as well as using encryption for your chroot for added security. (otherwise any other local user would be able to inspect the data in your chroot, which means anyone with physical access would be able to look at your shit pretty easily)&lt;/p&gt;

&lt;p&gt;Now you’ll want a terminal: &lt;a href=&quot;https://chrome.google.com/webstore/detail/crosh-window/nhbmpbdladcchdhkemlojfjdknjadhmh&quot;&gt;hterm/crosh window&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Open your terminal (ctrl-alt-T in Chrome) and open the developer tools, and go to the javascript REPL. Disable the audible bell&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;term_.prefs_.set(&apos;audible-bell-sound&apos;, &apos;&apos;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you’re an emacs user, you’ll want to set some other options ( found from &lt;a href=&quot;http://git.chromium.org/gitweb/?p=chromiumos/platform/assets.git;a=blob;f=chromeapps/hterm/doc/faq.txt;h=f0d3007f9fc54c7331f68293b7fae5f5b71214ff;hb=95f6a2c7a984b1c09b7d66c24794ce2057144e86&quot;&gt;hterm FAQ&lt;/a&gt; )&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;term_.prefs_.set(&apos;alt-backspace-is-meta-backspace&apos;,true)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That makes emacs alt-backspace actually delete a word.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;term_.prefs_.set(&apos;font-size&apos;, 13)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I found the default font size of 15 to be too large.&lt;/p&gt;

&lt;p&gt;Now you’ll probably want to use tmux because it’s such a pain to bring up more terminal windows inside your chroot.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# inside your ~/.tmux.conf&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# allow scrolling through history buffers&lt;/span&gt;
set-window-option &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; mode-mouse on
&lt;span class=&quot;c&quot;&gt;# I use C-b a lot inside emacs, so &lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# rebind tmux to use C-t, which I never use&lt;/span&gt;
unbind C-b
&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; prefix C-t&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;If you want to use an X11 program from aptitude ( say you download an
MKV using
&lt;a href=&quot;https://chrome.google.com/webstore/detail/jstorrent/anhdpjpojoipgpmfanmedjghaligalgb&quot;&gt;jstorrent&lt;/a&gt;
and want to use VLC to watch it), you can do so using the useful
“host-x11” command that prints out some environment variables that you
can set and then run the program in the current X server. Best to put
it in your ~/.bashrc&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;eval&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;host-x11&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;I’m not used to using terminal emacs (have used emacs with the gtk
interface for a long time) and I end up opening a lot of separate
emacs processes. Copy/paste between them is a pain, so I ended up
using &lt;a href=&quot;http://blog.binchen.org/?p=589&quot;&gt;some clipboard functions&lt;/a&gt; to
allow copy/paste (remember to “apt-get install xsel”)&lt;/p&gt;

&lt;p&gt;I am sometimes wondering if the fan is turning itself on too
aggressively and harming my battery life. /sys/devices/virtual/thermal
has a bunch of devices. I would like to try manually disabling the
fans on occasion. But I’ll hold off on that&lt;/p&gt;

&lt;p&gt;If you use an SSH passphrase, Another nice thing to put in your
~/.profile would be a keychain. apt-get install keychain and then you
won’t have to type in your ssh key (your SSH key does have a
passphrase, right?)&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;keychain &lt;span class=&quot;nt&quot;&gt;--attempts&lt;/span&gt; 3 &lt;span class=&quot;nt&quot;&gt;-q&lt;/span&gt; ~/.ssh/id_rsa
&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; ~/.keychain/&lt;span class=&quot;nv&quot;&gt;$HOSTNAME&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-sh&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
</content>
 </entry>
 
 <entry>
   <title>Saving a torrent to your cloud</title>
   <link href="http://kyle.graehl.org/programming/2013/02/08/saving-torrent-to-your-cloud.html"/>
   <updated>2013-02-08T00:00:00+00:00</updated>
   <id>http://kyle.graehl.org/programming/2013/02/08/saving-torrent-to-your-cloud</id>
   <content type="html">&lt;p&gt;I finally have a working prototype of saving a torrent to your cloud disk. The motivation for this was to be able to consume torrent content while on an iOS device, such as an iPad. Check out &lt;a href=&quot;http://jstorrent.com&quot;&gt;JSTorrent.com&lt;/a&gt;. (Note: the iOS App store does not approve of “torrent” apps, so we need to put the app in the browser instead) &lt;strong&gt;this is not working anymore, as BitTorrent, Inc. disabled websocket connection access to their clients&lt;/strong&gt; Please go complain on &lt;a href=&quot;http://forum.bittorrent.com&quot;&gt;their forums&lt;/a&gt; and complain :-)&lt;/p&gt;

&lt;p&gt;On your first visit, you’ll be prompted to sign into your google account. Don’t worry, it will only ask for access to write and read from files in its own sandbox. It doesn’t even ask for your identity or other information.&lt;/p&gt;

&lt;p&gt;It’s a major pet peeve of mine when applications ask for permission to do a lot more than I care to let them have access to, so rest assured I am not interested in spying around your files, and I don’t even ask that you trust me that I won’t.&lt;/p&gt;

&lt;p&gt;Anyway, the drill is as per usual. Find a torrent URL somewhere on the web, paste it into the text input box at the top, and you’ll now be saving the files not to your local disk, but be streaming them directly to your google drive. Currently any gmail user will have a google drive automatically, I think it gives you something like 2GB for free (Then $2.50/month for 100GB)&lt;/p&gt;

&lt;p&gt;You can inspect the upload progress by clicking on the files tab. There’s a column that represents the fraction of data for that file that’s been uploaded to the cloud drive.&lt;/p&gt;

&lt;p&gt;Once it’s saved, you’ll see icons for opening and saving the files from the cloud drive.&lt;/p&gt;

&lt;p&gt;I’ve started to add support to saving to your DropBox, which has a similar client side javascript library.&lt;/p&gt;

&lt;p&gt;All hail the static web app that uses javascript APIs.&lt;/p&gt;

&lt;p&gt;Next time – will be adding WebRTC DataChannel functionality so you can share files directly with other browsers.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Torrent in a google chrome packaged app.</title>
   <link href="http://kyle.graehl.org/coding/2013/01/14/torrent-chrome-packaged-app.html"/>
   <updated>2013-01-14T00:00:00+00:00</updated>
   <id>http://kyle.graehl.org/coding/2013/01/14/torrent-chrome-packaged-app</id>
   <content type="html">&lt;p&gt;I finally released something based on the jstorrent code.&lt;/p&gt;

&lt;p&gt;You can download the &lt;a href=&quot;https://chrome.google.com/webstore/detail/jstorrent/anhdpjpojoipgpmfanmedjghaligalgb&quot;&gt;packaged app&lt;/a&gt; from
google play. If you’re not aware, packaged apps are like browser
extensions, only they get their own top level window. As of the date
of this writing, they are not searchable within the google app store
that you find in your chrome browser, but should be at some point. There is an ongoing &lt;a href=&quot;https://groups.google.com/forum/?fromgroups=#!topic/chromebook-central/DXJmD1ZUK2Q&quot;&gt;discussion thread on google groups&lt;/a&gt; for commonly encountered issues.&lt;/p&gt;

&lt;p&gt;It’s pretty neat, having access to raw sockets. The goal of jstorrent is to work with any type of connection, be it websockets, webrtc, or raw sockets. I like the abstraction of an “IOStream” that I picked up while working with &lt;a href=&quot;https://github.com/facebook/tornado&quot;&gt;tornado&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;    &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;IOStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;host&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;port&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sockno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_closed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_connected&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_created&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;tcp&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{},&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;oncreate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;IOStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;oncreate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sockno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socketId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bindAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;onconnect&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;do_read&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;onsend&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;got_read&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sockno&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onconnect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;onconnect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_closed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// BUG in implementation&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onopen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;do_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;do_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_closed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_connecting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sockno&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4096&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;got_read&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;got_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_closed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// BUG in implementation&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resultCode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doclose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onmessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;// somehow onmessage can close the connection... (bad data?)&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_closed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;do_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sockno&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onsend&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;onsend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bytesWritten&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doclose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;did not write all data&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;doclose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reason&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;onclose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({});&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_connected&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nx&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;disconnect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sockno&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;chrome&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;destroy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sockno&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reason&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;_closed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;// cancel pending read?&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;doclose&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;called close&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Neat. The chrome.socket implementation seems to be pretty undocumented
at this point so I had to make a few guesses with the edge cases but
this class lets me use it in about the same way I would use a
websocket stream.&lt;/p&gt;

&lt;p&gt;Currently I’m working on adding functionality to download to a cloud
storage provider (Google drive first, Dropbox and others later) so
that browsers without filesystems can still consume torrents. It’s
kind of a pain, because pieces can span multiple files and I want to
make sure I don’t have any memory leaks. Working with streams is
rather tricky. And handling error states with resumable uploads will
add even more complexity.&lt;/p&gt;

&lt;p&gt;After that, implementing a WebRTC stream class will be a game-changer!
Well, maybe. At least it’ll be a good example use case for
WebRTC. Really though, I think the best use cases for WebRTC are real
time games. It would be neat for example to see Warcraft II ported to
the browser and maybe have the connection to your friend be initiated
like it was back in the good old days, by dialing a phone number. The
browser based version should make the modem baudrate handshaking song,
too, for added effect.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Predicting the future?</title>
   <link href="http://kyle.graehl.org/society/2013/01/14/betting-on-the-future.html"/>
   <updated>2013-01-14T00:00:00+00:00</updated>
   <id>http://kyle.graehl.org/society/2013/01/14/betting-on-the-future</id>
   <content type="html">&lt;p&gt;My &lt;a href=&quot;http://jonathan.graehl.org&quot;&gt;brother&lt;/a&gt; pointed out this
article at &lt;a href=&quot;http://squid314.livejournal.com/352406.html&quot;&gt;http://squid314.livejournal.com/352406.html&lt;/a&gt;. The author
makes the point that prediction markets could be the most efficient
and accurate way to reliably predict the future. A prediction market
is some kind of system where you can bet on future outcomes based on
hypotheses.&lt;/p&gt;

&lt;p&gt;It’s an interesting thought experiement to think that I could, instead
of investing my money in markets or specific companies or stocks, that
I could invest in very specific things that match my idealogical
interests. I have some vision for how things should or could be in the
world and I put money behind my hypothesis, that if say a certain
legistlation or law or initiative is adopted, then a favorable
measurable outcome can result. Or, alternatively, if not adopted, a
measurable and less favorable outcome will result. I view it as a kind
of altruistic gambling.&lt;/p&gt;

&lt;p&gt;You can play with such prediction markets at
&lt;a href=&quot;http://www.intrade.com/&quot;&gt;http://www.intrade.com&lt;/a&gt;. There are currently many asinine questions on
there like “Will Lincoln win best picture.” As such, it has apparently
been classified as off market trading or gambling by the US govt and I
think it’s not currently advisable or possible to trade inside the US.&lt;/p&gt;

&lt;p&gt;Personally, I hardly see how buying shares in AAPL vs betting that Les
Miserables wins best picture are much different. I suppose it has
something to do with there being no oversight into the obvious type of
corruption that could result from this type of trading.&lt;/p&gt;

&lt;p&gt;What the article seems to be arguing, though, is that with enough
liquidity, that these problems are self-correcting?&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>BitTorrent video streaming in your browser</title>
   <link href="http://kyle.graehl.org/coding/2012/12/07/torrent-in-your-browser.html"/>
   <updated>2012-12-07T00:00:00+00:00</updated>
   <id>http://kyle.graehl.org/coding/2012/12/07/torrent-in-your-browser</id>
   <content type="html">&lt;p&gt;This post contains outdated information! Proceed reading with a grain of salt. I’ve abandoned trying to get torrents working on the open web platform :-)&lt;/p&gt;

&lt;p&gt;I started working on an HTML5 torrent client a few months ago when I
had the realization that if enough BitTorrent clients would accept
WebSocket connections, it would be possible to download pieces
directly from a desktop torrent client to your web browser. There
would be several advantages to being able to participate it BitTorrent
swarms in the “naked” web. By naked, I mean without any special
plugins or software. A whole new set of users could participate in the
BitTorrent ecosystem. From those who are unable and who are unwilling
to install custom desktop software, to those who are stuck in
&lt;a href=&quot;http://www.apple.com&quot;&gt;walled gardens&lt;/a&gt;, but especially for
those who don’t know or don’t care what a torrent is.&lt;/p&gt;

&lt;p&gt;There were a number of challenges I encountered when developing the
prototype. The most difficult problem is the lack of wide browser
support for the FileSystem API. Google Chrome provides this very
convenient and stable and usable interface. The only complaint I have
is that it does not support sparse files (i.e. seeking far into a file
and writing without having to manually fill in a lot of null bytes). I
was very disappointed when I read &lt;a href=&quot;https://hacks.mozilla.org/2012/07/why-no-filesystem-api-in-firefox/&quot;&gt;Mozilla’s
arguments against the implementation&lt;/a&gt;. There are polyfills that
make use of IndexedDB, but they have severe limitations for my use
case, which needs to support files up to multiple gigabytes in size.&lt;/p&gt;

&lt;p&gt;I went ahead anyway implementing &lt;a href=&quot;http://bittorrent.org/beps/bep_0003.html&quot;&gt;the protocol&lt;/a&gt; and saving files to the
browser sandbox filesystem, intent on supporting only the Chrome
browser for the time being. The &lt;a href=&quot;https://github.com/kzahel/jstorrent&quot;&gt;code to the first
prototype&lt;/a&gt; of the browser torrent client is available. You can see
the app hosted at &lt;a href=&quot;http://jstorrent.com&quot;&gt;jstorrent.com&lt;/a&gt;. It
also can be loaded as a Chrome packaged app and will make use of the
chrome experimental socket API.&lt;/p&gt;

&lt;p&gt;I currently work at &lt;a href=&quot;http://bittorrent.com&quot;&gt;BitTorrent&lt;/a&gt;,
which maintains the popular &lt;a href=&quot;http://utorrent.com&quot;&gt;µTorrent&lt;/a&gt; client. Updates to these
clients are slow and methodical, so most clients as of this date are
still unable to accept Websocket connections (this will be rolling out in version
3.3). If you have been following the latest developments with WebRTC,
you’d know that Firefox and Chrome are rolling out the DataChannel
API, which will also allow for browsers to connect directly to each
other. You can bet µTorrent will learn to speak WebRTC, too.&lt;/p&gt;

&lt;p&gt;For purposes of demonstration, I decided to write a small embeddable
html page that attempts to stream a video from a BitTorrent swarm
directly in your browser. Since it is still not possible to connect
directly to most swarms until µTorrent 3.3 usage is widespread, these make use
of a custom proxy server that behaves much like &lt;a href=&quot;https://github.com/kanaka/websockify&quot;&gt;websockify&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;iframe&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;300&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; 
&lt;span class=&quot;nx&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;http://jstorrent.com/examples/embed_window.html#hash=f8049a655273f6a000be2bb2119716bcd4c741bc&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; 
&lt;span class=&quot;nx&quot;&gt;frameborder&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;allowfullscreen&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/iframe&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Embed window:&lt;/p&gt;
&lt;div id=&quot;click&quot; style=&quot;border:1px dashed red; padding: 1em&quot;&gt;Click to load embed window (Chrome only)&lt;/div&gt;
&lt;script src=&quot;/scripts/torrent-show.js&quot;&gt;
&lt;/script&gt;

&lt;p&gt;Basically, we are downloading data from the swarm and saving it to the HTML5 FileSystem storage, then creating a video element and sourcing it to that file.&lt;/p&gt;

&lt;p&gt;Since the file is not completely downloaded, the video element will not be immediately playable. Some javascript code running in a web worker attempts to parse the MP4 box format (borrowed code from &lt;a href=&quot;https://github.com/mbebenita/Broadway/blob/master/Player/mp4.js&quot;&gt;broadway&lt;/a&gt;, see this &lt;a href=&quot;http://haxpath.squarespace.com/imported-20100930232226/2011/10/28/broadwayjs-h264-in-javascript.html&quot;&gt;fascinating article&lt;/a&gt;). We download, somewhat unintelligently, from the beginning and end of the file in order to get the important video metadata information that the webkit video player needs to be able to start playing.&lt;/p&gt;

&lt;p&gt;When seeking to somewhere in the middle of the file, we need to manually calculate using the mp4 keyframe and time to sample tables which byte offsets the video player will actually use, and prioritize downloading that data from the swarm.&lt;/p&gt;

&lt;p&gt;The implementation is very much at an early prototype stage, but it would be interesting to see how good the performance could be if each stage in this process were optimized. For example, it would be better to make use of the new &lt;a href=&quot;http://dvcs.w3.org/hg/html-media/raw-file/tip/media-source/media-source.html&quot;&gt;MediaSource API&lt;/a&gt; being developed by Microsoft, Google, and Netflix. And it would be much better if every torrent video was encoded in multiple bitrates so that it could be compatible with MPEG-DASH.&lt;/p&gt;

&lt;p&gt;I am currently working on a prototype to add support to other browsers (such as iOS Safari) that lack the FileSystem API. Instead of saving back to a local disk (which happen to be relatively small on mobile devices anyway), it would save to Google Drive or Dropbox’s multipart upload APIs.&lt;/p&gt;

&lt;p&gt;If this sounds interesting to you, I would tell you that BitTorrent is
a great place to work. BitTorrent provides options, not rules.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Non-blocking UDP in Tornado web's IOLoop</title>
   <link href="http://kyle.graehl.org/coding/2012/12/07/tornado-udpstream.html"/>
   <updated>2012-12-07T00:00:00+00:00</updated>
   <id>http://kyle.graehl.org/coding/2012/12/07/tornado-udpstream</id>
   <content type="html">&lt;p&gt;I’ve always enjoyed working with &lt;a href=&quot;https://github.com/facebook/tornado&quot;&gt;Tornado Web&lt;/a&gt;, the python web framework that is centered around the idea of using non-blocking sockets. It is a very versatile framework for working with asynchronous streams and I’ve used it to write a number of applications, including proxy servers, media streamers, and even BitTorrent clients. But tornado is noticably lacking in UDP support. This is fine, of course. After all, it is an HTTP library.&lt;/p&gt;

&lt;p&gt;When you would like to do some non-blocking UDP stuff using tornado, all you need to do is use this custom “UDPStream” class that I wrote. It acts a lot like tornado’s IOStream class.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;UDPStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in_ioloop&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_read_callback&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ioloop&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in_ioloop&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IOLoop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_add_io_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_state&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tornado&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ioloop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;IOLoop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ERROR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ioloop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
                &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileno&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_handle_events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elif&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;state&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ioloop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;update_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileno&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;msg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;recv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ioloop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;remove_handler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fileno&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;read_chunk&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callback&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_read_callback&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callback&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_read_timeout&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ioloop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add_timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;check_read_callback&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_add_io_state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ioloop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;READ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;check_read_callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_read_callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# XXX close socket?
&lt;/span&gt;            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_read_callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;timeout&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_handle_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_read_timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ioloop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;remove_timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_read_timeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_read_callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;recv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4096&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;c1&quot;&gt;# conn refused??
&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_read_callback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_read_callback&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;None&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;_handle_events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fd&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;events&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;events&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ioloop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;READ&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_handle_read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;events&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ioloop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ERROR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;logging&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;%s event error&apos;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;The basic use of this class is illustrated in the following code snippet.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-python&quot; data-lang=&quot;python&quot;&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;socket&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;udpsock&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AF_INET&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;socket&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;SOCK_DGRAM&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;udpsock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;setblocking&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;udpsock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&apos;tracker.openbittorrent.com&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;80&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UDPStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;udpsock&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&apos;some data&apos;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read_chunk&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

</content>
 </entry>
 
 <entry>
   <title>complaining about osx window manager again</title>
   <link href="http://kyle.graehl.org/2012/08/30/complaining-about-osx-window-manager-again.html"/>
   <updated>2012-08-30T09:22:00+00:00</updated>
   <id>http://kyle.graehl.org/2012/08/30/complaining-about-osx-window-manager-again</id>
   <content type="html">&lt;p&gt;The past few days I’ve had an external monitor plugged into my macbook. It’s been nice having more real estate.&lt;/p&gt;

&lt;p&gt;But now I’m sitting in a comfortable chair away from my monitor trying to do some work. But there’s too many windows! And I can’t move them around!&lt;/p&gt;

&lt;p&gt;I want my dream setup – virtual desktops that I can page around by just moving the mouse to the edge of the screen. Why does osx only let me page desktops horizontally? And why isn’t there an option to page between the screens by moving the mouse over there?&lt;/p&gt;

&lt;p&gt;I want more options, not fewer!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>reinventing the flat tire</title>
   <link href="http://kyle.graehl.org/2012/08/27/reinventing-the-flat-tire.html"/>
   <updated>2012-08-27T14:34:00+00:00</updated>
   <id>http://kyle.graehl.org/2012/08/27/reinventing-the-flat-tire</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;http://www.drdobbs.com/architecture-and-design/interview-with-alan-kay/240003442&quot;&gt;http://www.drdobbs.com/architecture-and-design/interview-with-alan-kay/240003442&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I love reading that leads to intense cognitive dissonance. Alan Kay says the web was created by “amateurs” and is headed in the wrong direction.&lt;/p&gt;

&lt;p&gt;It’s too bad his vision of computing wasn’t better understood.&lt;/p&gt;

&lt;p&gt;I would love to read more about Kay’s views on the web!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>mozilla falling behind?</title>
   <link href="http://kyle.graehl.org/2012/08/27/mozilla-falling-behind.html"/>
   <updated>2012-08-27T14:18:00+00:00</updated>
   <id>http://kyle.graehl.org/2012/08/27/mozilla-falling-behind</id>
   <content type="html">&lt;p&gt;I thought I would see how Mozilla’s browser would work with my new app using the HTML5 FileSystem API.&lt;/p&gt;

&lt;p&gt;I install Firefox. Eww, no retina support still. Okay… let’s see how the app works.
Oops… Mozilla hasn’t implemented the FileSystem API yet. I was led to a discussion on &lt;a href=&quot;https://hacks.mozilla.org/2012/07/why-no-filesystem-api-in-firefox/&quot;&gt;https://hacks.mozilla.org/2012/07/why-no-filesystem-api-in-firefox/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It seems Mozilla is a bit behind! The arguments against the FileSystem API are weak. No file locking? Not interested! All the operations are asynchronous anyway. Oh, you have a competing effort underway, the “Web API”? First off, that is a terrible name for an API. So generic. Second, why are you guys documenting some C++ classes for some dreamed-up API instead of participating in WHATWG discussions?&lt;/p&gt;

&lt;p&gt;Still, I’m interested in seeing what they come up with. But I suspect they won’t have enough manpower to come up with anything more compelling than what’s already been implemented under Chromium&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>waiting for WebRTC DataChannel</title>
   <link href="http://kyle.graehl.org/2012/08/27/waiting-for-webrtc-datachannel.html"/>
   <updated>2012-08-27T11:17:00+00:00</updated>
   <id>http://kyle.graehl.org/2012/08/27/waiting-for-webrtc-datachannel</id>
   <content type="html">&lt;p&gt;I have been spending some time recently with Websockets, and while they’re quite powerful (the latest spec supports sending javascript byte arrays), they still have one rather limiting problem: two browsers still cannot communicate directly to each other.&lt;/p&gt;

&lt;p&gt;I work with peer-to-peer software as a part of my job. Having WebRTC’s DataChannel API available would make my life such a pleasure.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://stackoverflow.com/questions/10218250/transfering-json-between-browsers-with-webrtc&quot;&gt;http://stackoverflow.com/questions/10218250/transfering-json-between-browsers-with-webrtc&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;According to some comments on that page, I may have something to work with by the end of the year. Here’s hoping!&lt;/p&gt;

&lt;p&gt;It seems like there may be some very unexpected and important privacy implications. Browsers have never had true peer-to-peer capabilities before.&lt;/p&gt;

&lt;p&gt;I hope nobody worries too hard about this and the first implementations are simply pulled into the Chromium source.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>coping with osx</title>
   <link href="http://kyle.graehl.org/2012/08/27/coping-with-osx.html"/>
   <updated>2012-08-27T10:56:00+00:00</updated>
   <id>http://kyle.graehl.org/2012/08/27/coping-with-osx</id>
   <content type="html">&lt;p&gt;I have been very happy with me new Macbook Pro with fancy retina display. The screen is beautiful and the pleasure it affords me is not unlike having some cold sweet cream melting on my tongue. Only on my eyes.&lt;/p&gt;

&lt;p&gt;Allow me to complain about how the OS, OSX, is failing me…&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;moving windows around is too hard (have to navigate my cursor to the top of the window title)&lt;/li&gt;
  &lt;li&gt;resizing windows is too hard (have to move to the very corner of the window)&lt;/li&gt;
  &lt;li&gt;moving windows between desktops is too hard (have to wait around on the edge for about 1/3 a second)&lt;/li&gt;
  &lt;li&gt;etc etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I lose so much time just because the window manager is so rigid.&lt;/p&gt;
</content>
 </entry>
 
 
</feed>
