<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>malloc47</title>
    <link>http://malloc47.com/</link>
    <atom:link href="http://malloc47.com/rss.xml" rel="self" type="application/rss+xml" />
    <description>Blog of Jarrell W. Waggoner, computer scientist and software developer</description>
    <language>en-us</language>
    <pubDate>Fri, 17 May 2013 07:26:18 -0700</pubDate>
    <lastBuildDate>Fri, 17 May 2013 07:26:18 -0700</lastBuildDate>
    
    <item>
      <title>LaTeX Snippet&#58; (Literal) One Liners</title>
      <link>http://malloc47.com/latex-snippet-literal-one-liners/</link>
      <pubDate>Wed, 03 Apr 2013 00:00:00 -0700</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/latex-snippet-literal-one-liners</guid>
      <description>&lt;p&gt;There are some truly &lt;a href='http://tex.stackexchange.com/questions/33417/adjust-font-size-on-the-fly'&gt;impressive&lt;/a&gt; LaTeX solutions for doing PowerPoint-style font-resizing to fit into a fixed width box. I recently had need of something more simple: print text on &lt;em&gt;one line only&lt;/em&gt;, scaling the size down instead of allowing it to wrap. The following LaTeX snippet does exactly this, triggered only if the font width (before wrapping) exceeds &lt;code&gt;\textwidth&lt;/code&gt;.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='latex'&gt;&lt;span class='nb'&gt;{&lt;/span&gt;
  &lt;span class='k'&gt;\def\formattedtext&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;The no-wrap text to scale&lt;span class='nb'&gt;}&lt;/span&gt;&lt;span class='c'&gt;%&lt;/span&gt;
  &lt;span class='k'&gt;\newdimen&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\namewidth&lt;/span&gt;&lt;span class='nb'&gt;}&lt;/span&gt;&lt;span class='c'&gt;%&lt;/span&gt;
  &lt;span class='k'&gt;\setlength&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\namewidth&lt;/span&gt;&lt;span class='nb'&gt;}{&lt;/span&gt;&lt;span class='k'&gt;\widthof&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\formattedtext&lt;/span&gt;&lt;span class='nb'&gt;}}&lt;/span&gt;&lt;span class='c'&gt;%&lt;/span&gt;
  &lt;span class='k'&gt;\ifthenelse&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\lengthtest&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\namewidth&lt;/span&gt; &amp;lt; &lt;span class='k'&gt;\textwidth&lt;/span&gt;&lt;span class='nb'&gt;}}&lt;/span&gt;&lt;span class='c'&gt;%&lt;/span&gt;
  &lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\formattedtext&lt;/span&gt;&lt;span class='nb'&gt;}&lt;/span&gt;&lt;span class='c'&gt;% do nothing if shorter than text width&lt;/span&gt;
  &lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\resizebox&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\textwidth&lt;/span&gt;&lt;span class='nb'&gt;}{&lt;/span&gt;!&lt;span class='nb'&gt;}{&lt;/span&gt;&lt;span class='k'&gt;\formattedtext&lt;/span&gt;&lt;span class='nb'&gt;}}&lt;/span&gt;&lt;span class='c'&gt;% scale down&lt;/span&gt;
&lt;span class='nb'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This requires&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='latex'&gt;&lt;span class='k'&gt;\usepackage&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;xifthen&lt;span class='nb'&gt;}&lt;/span&gt;
&lt;span class='k'&gt;\usepackage&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;graphicx&lt;span class='nb'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;to handle the &lt;code&gt;\ifthenelse&lt;/code&gt;, &lt;code&gt;\lengthtest&lt;/code&gt;, and &lt;code&gt;\resizebox&lt;/code&gt; statements.&lt;/p&gt;

&lt;p&gt;It works like you might expect: check the width of the text, and then use &lt;code&gt;\resizebox&lt;/code&gt; to scale it down, if needed. Such logic isn&amp;#8217;t always obvious in LaTeX: arbitrary &lt;code&gt;def&lt;/code&gt;s cannot store length information, so you have to set the type of the &lt;code&gt;\namewidth&lt;/code&gt; variable as a dimension before you can assign/test it as a length.&lt;/p&gt;

&lt;p&gt;As with most helpful things in LaTeX, we can wrap it up in a reusable macro:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='latex'&gt;&lt;span class='k'&gt;\newcommand&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\oneline&lt;/span&gt;&lt;span class='nb'&gt;}&lt;/span&gt;[1]&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='c'&gt;%&lt;/span&gt;
  &lt;span class='k'&gt;\newdimen&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\namewidth&lt;/span&gt;&lt;span class='nb'&gt;}&lt;/span&gt;&lt;span class='c'&gt;%&lt;/span&gt;
  &lt;span class='k'&gt;\setlength&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\namewidth&lt;/span&gt;&lt;span class='nb'&gt;}{&lt;/span&gt;&lt;span class='k'&gt;\widthof&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;#1&lt;span class='nb'&gt;}}&lt;/span&gt;&lt;span class='c'&gt;%&lt;/span&gt;
  &lt;span class='k'&gt;\ifthenelse&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\lengthtest&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\namewidth&lt;/span&gt; &amp;lt; &lt;span class='k'&gt;\textwidth&lt;/span&gt;&lt;span class='nb'&gt;}}&lt;/span&gt;&lt;span class='c'&gt;%&lt;/span&gt;
  &lt;span class='nb'&gt;{&lt;/span&gt;#1&lt;span class='nb'&gt;}&lt;/span&gt;&lt;span class='c'&gt;%&lt;/span&gt;
  &lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\resizebox&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\textwidth&lt;/span&gt;&lt;span class='nb'&gt;}{&lt;/span&gt;!&lt;span class='nb'&gt;}{&lt;/span&gt;#1&lt;span class='nb'&gt;}}&lt;/span&gt;&lt;span class='c'&gt;%&lt;/span&gt;
&lt;span class='nb'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which allows&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='latex'&gt;&lt;span class='k'&gt;\oneline&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\Huge&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;The no-wrap text to scale&lt;span class='nb'&gt;}}&lt;/span&gt;

&lt;span class='k'&gt;\oneline&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;&lt;span class='k'&gt;\Huge&lt;/span&gt;&lt;span class='nb'&gt;{&lt;/span&gt;The quick brown fox jumped over the lazy dog, over and over and over and over again.&lt;span class='nb'&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;On any reasonable-sized page width, these two lines will not wrap, but the longer line will be stretched horizontally to fit in the available space.&lt;/p&gt;

&lt;p&gt;You can find a fully-working (as of TeXLive 2012) gist &lt;a href='https://gist.github.com/malloc47/5298181'&gt;here&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Tech Company Locations (North America)</title>
      <link>http://malloc47.com/tech-company-locations/</link>
      <pubDate>Sun, 24 Feb 2013 00:00:00 -0800</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/tech-company-locations</guid>
      <description>&lt;p&gt;Since I'm soon to be on the technology job market, I decided to get
a handle on where the major technology companies were located.  After
spending some quality time going back and forth bettween the &quot;Career&quot;
sections of different companies and Google Maps, I assembled this:&lt;/p&gt;

&lt;iframe width=&quot;620&quot; height=&quot;500&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot; src=&quot;//maps.google.com/maps/ms?msid=208032600690328075247.0004d67c37273c82e2363&amp;amp;msa=0&amp;amp;ie=UTF8&amp;amp;t=m&amp;amp;ll=33.578015,-96.767578&amp;amp;spn=34.833124,56.25&amp;amp;z=4&amp;amp;output=embed&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;There are a number of disclaimers here:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;This is geared primarily toward locations that emphasize
    software engineering roles.  I tried to filter accordingly if there
    are few/no engineering jobs listed for a paricular location, but
    that may not be perfect either.&lt;/li&gt;
  &lt;li&gt;Few companies provided the exact address (Microsoft being one of
    the exceptions) for every one of their locations, so if Google
    Maps searches failed, then I just approximated.&lt;/li&gt;
  &lt;li&gt;This is certainly not exhaustive; many companies (namely Amazon)
    have many subsidiaries under different branding, which may or may
    not have any engineering roles.&lt;/li&gt;
  &lt;li&gt;This doesn't include data centers, retail stores, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;a href=&quot;mailto:malloc47@gmail.com?subject=Tech Company Locations&quot;&gt;Let
me know&lt;/a&gt; if you see any gross errors, or would like me to include
any other companies with more than one location.  You can get a better
view
on &lt;a href=&quot;//maps.google.com/maps/ms?msa=0&amp;amp;msid=208032600690328075247.0004d67c37273c82e2363&amp;amp;ie=UTF8&amp;amp;t=m&amp;amp;ll=33.560275,-96.753709&amp;amp;spn=28.255532,51.3448&amp;amp;source=embed&quot;
style=&quot;color:#0000FF;text-align:left&quot;&gt;Google Maps&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Laptops are the Stenotypes of Software Engineers</title>
      <link>http://malloc47.com/laptops-are-the-stenotypes-of-software-engineers/</link>
      <pubDate>Sun, 17 Feb 2013 00:00:00 -0800</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/laptops-are-the-stenotypes-of-software-engineers</guid>
      <description>&lt;p&gt;Increasingly, I&amp;#8217;ve been asked variants on the question &amp;#8220;what will happen to desktops/laptops,&amp;#8221; particularly in light of the proliferation of smartphones and tablets. This has resulted in several good conversations, and I&amp;#8217;ve begun to use the following analogy when discussing this with colleagues in non-engineering disciplines:&lt;/p&gt;

&lt;p&gt;Laptop computers will become the stenotypes of software engineers.&lt;/p&gt;

&lt;p&gt;The &lt;a href='http://en.wikipedia.org/wiki/Stenotype'&gt;stenotype&lt;/a&gt; is a niche device used by stenographers (most prominently, court reporters) to transcribe dialog in real-time at blindingly-fast words-per-minute rates. Fellow Emacs users might appreciate how the stenotype works: instead of typing single letters, multiple keys are &amp;#8220;chorded&amp;#8221; together to allow many more combinations with many fewer keys. And instead of producing single letters, many of these combinations produce syllables or whole words. These physical optimizations are coupled with conventions among stenographers to wantonly omit or abbreviate words where there is little ambiguity of meaning, which further improves efficiency&amp;#8212;the fewer characters put to a page, the less chance of typos. This leads to the output of the stenotype being difficult to read by those who are not well-versed in the conventions (called &amp;#8220;theories&amp;#8221;) used by stenographers.&lt;/p&gt;

&lt;p&gt;One could describe the typical QWERTY keyboard as the antithesis of the stenotype. Designed to reduce jams in the old typewriting systems&amp;#8212;a constraint clearly nonexistent in modern hardware&amp;#8212;mainstream keyboards are considered more accessible compared with a stenotype. However, even considering later iterations, such as the &lt;a href='http://en.wikipedia.org/wiki/Dvorak_Simplified_Keyboard'&gt;Dvorak&lt;/a&gt; layout, these keyboards cannot hope to match the ruthless efficiency of a stenotype when used in real-time transcription work.&lt;/p&gt;

&lt;p&gt;Few would reach for a stenotype to write a letter to their mother (unless she was a stenographer herself!), and no trained court reporter would care to wonder into the courtroom with a QWERTY keyboard. Despite digital recorders making inroads into court reporting and closed caption transcription, stenotypes are still available (hint: &lt;a href='http://www.ebay.com/sch/i.html?_trksid=p5197.m570.l1313&amp;amp;_nkw=stenotype&amp;amp;_sacat=0&amp;amp;_from=R40'&gt;ebay&lt;/a&gt;), persisting thanks to an ingrained base of stenographers who remain ruthlessly efficient at these highly-specialized tasks.&lt;/p&gt;

&lt;p&gt;Which brings us back to computing.&lt;/p&gt;

&lt;p&gt;Software engineers are not your average user. We don&amp;#8217;t have an average computing workload and have a completely disparate set of tools and conventions. Dell didn&amp;#8217;t even try to lampshade this fact with their &lt;a href='http://content.dell.com/us/en/gen/d/campaigns/xps-linux-laptop'&gt;Sputnik&lt;/a&gt; Ubuntu laptop aimed squarely at developers. And, while tablets have proven to be capable of everything from typical computing tasks to &lt;a href='http://pythonforios.com/'&gt;basic software development&lt;/a&gt;,&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If it doesn&amp;#8217;t have a keyboard, I feel that my thoughts are being forced out through a straw.&lt;br /&gt; &amp;#8212;Joey Hess&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;a href='http://www.fastcompany.com/3004563/2013-when-tablets-beat-laptops'&gt;immanent death&lt;/a&gt; of the laptop is greatly exaggerated; after all, the stenotype lives on to this day. However, the fate of the laptop &lt;em&gt;as we know it&lt;/em&gt;&amp;#8212;available in every imaginable color, style, shape, size, and brandishing shiny logos to reinforce its reputation as a status symbol&amp;#8212;is less certain. This fact was made more stark for me when I realized that installing &lt;a href='http://www.android-x86.org/'&gt;Android x86&lt;/a&gt; on my Eee PC gave it more in common with modern computing platforms than my primary development laptop (Thinkpad x120e with Arch Linux and the minimal xmonad window manager). And I know I&amp;#8217;m not the only developer who has, consciously or unconsciously, increased the specialization of my desktops/laptops while using smartphones/tablets for non-work related activities. Who really wants to pull out and boot up a laptop for light internet reading when you&amp;#8217;ve got an instant-on smartphone or tablet within reach? I&amp;#8217;m becoming more convinced that this is what the real &amp;#8220;death&amp;#8221; of the laptop looks like.&lt;/p&gt;

&lt;p&gt;For software engineers, the role of laptops (and desktops even moreso) is slowly morphing into one similar to that of stenotypes. It&amp;#8217;s arguable that this is inevitable: artists don&amp;#8217;t use college-rule paper, chemists don&amp;#8217;t conduct titrations in a coffee mug, and firefighters don&amp;#8217;t roll up in a corolla to put out house fires. Professions evolve better and more efficient methodology, and when professionals outgrow the prevailing tools available to consumers, they develop new tools. This has already been well underway on the software side&amp;#8212;you won&amp;#8217;t find lawyers writing briefs with &lt;code&gt;vim&lt;/code&gt;, after all.&lt;/p&gt;

&lt;p&gt;If consumer computing devices become more recalcitrant for software engineers, it makes sense that a professional-grade tool should fill in the gap. The most natural candidate is the form factors we already have: laptops and desktops. But that certainly doesn&amp;#8217;t limit innovation to current devices&amp;#8212;a positive side effect of this &amp;#8220;death&amp;#8221; of laptops is that it provides a great opportunity to rethink what sort of device would benefit developers most, without being strictly constrained by a 1980s design that was intended for general computing. And this prospect may not be as far away as it might seem, given the recent rise of &lt;a href='http://www.hackthings.com/brace-yourself-here-come-the-hardware-startups/'&gt;hardware startups&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The next time you pull out a laptop in a coffee shop, I don&amp;#8217;t anticipate you&amp;#8217;ll get the same quizzical looks you might receive if you brought a stenotype with you. But, like the stenotype, I do think that the proliferation of tablets and other more consumer-oriented devices will necessitate a professional class of devices that are less common and more specialized. And in the meantime, that might mean the stylishness of laptops will begin to wane. I&amp;#8217;m okay with that.&lt;/p&gt;

&lt;p&gt;[Incidentally, you can turn a conventional keyboard into a stenotype-like device with &lt;a href='http://stenoknight.com/wiki/Main_Page'&gt;Plover&lt;/a&gt;, an open-source stenotype software package.]&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Producing LaTeX from NumPy Arrays</title>
      <link>http://malloc47.com/producing-latex-from-numpy-arrays/</link>
      <pubDate>Tue, 29 Jan 2013 20:00:00 -0800</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/producing-latex-from-numpy-arrays</guid>
      <description>&lt;p&gt;For my comprehensive exam, I needed to quickly convert some NumPy arrays into nice-looking LaTeX &lt;code&gt;array&lt;/code&gt; elements. The TeX Stack Exchange site has a good &lt;a href='http://tex.stackexchange.com/questions/54990/convert-numpy-array-into-tabular'&gt;answer&lt;/a&gt; for &lt;code&gt;tabular&lt;/code&gt; environments, but wasn&amp;#8217;t quite suited to the &lt;code&gt;array&lt;/code&gt; environment. The usual answer here would be &lt;a href='http://mpastell.com/pweave/'&gt;Pweave&lt;/a&gt; but, being short on time, I ended up rolling my own function instead:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;to_latex&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;label&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;A&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
    &lt;span class='n'&gt;sys&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stdout&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;write&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;\[ &amp;#39;&lt;/span&gt;
                     &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;label&lt;/span&gt;
                     &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='s'&gt;&amp;#39; = &lt;/span&gt;&lt;span class='se'&gt;\\&lt;/span&gt;&lt;span class='s'&gt;left| &lt;/span&gt;&lt;span class='se'&gt;\\&lt;/span&gt;&lt;span class='s'&gt;begin{array}{&amp;#39;&lt;/span&gt; 
                     &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;c&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;*&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;shape&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; 
                     &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;}&lt;/span&gt;&lt;span class='se'&gt;\n&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;r&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
        &lt;span class='n'&gt;sys&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stdout&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;write&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;str&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;r&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;]))&lt;/span&gt;
        &lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;c&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;r&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='p'&gt;:]:&lt;/span&gt;
            &lt;span class='n'&gt;sys&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stdout&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;write&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39; &amp;amp; &amp;#39;&lt;/span&gt;&lt;span class='o'&gt;+&lt;/span&gt;&lt;span class='nb'&gt;str&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
        &lt;span class='n'&gt;sys&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stdout&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;write&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&lt;/span&gt;&lt;span class='se'&gt;\\\\\n&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;sys&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;stdout&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;write&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&lt;/span&gt;&lt;span class='se'&gt;\\&lt;/span&gt;&lt;span class='s'&gt;end{array} &lt;/span&gt;&lt;span class='se'&gt;\\&lt;/span&gt;&lt;span class='s'&gt;right| \]&lt;/span&gt;&lt;span class='se'&gt;\n&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here&amp;#8217;s an incomplete snippet of it in action, where I convolve an array &lt;code&gt;t&lt;/code&gt; with four different filters, producing a latex formula for each result:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;filters&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;((&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;A &lt;/span&gt;&lt;span class='se'&gt;\\&lt;/span&gt;&lt;span class='s'&gt;oplus H_1&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;h1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
           &lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;A &lt;/span&gt;&lt;span class='se'&gt;\\&lt;/span&gt;&lt;span class='s'&gt;oplus H_2&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;h2&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
           &lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;A &lt;/span&gt;&lt;span class='se'&gt;\\&lt;/span&gt;&lt;span class='s'&gt;oplus H_3&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;h3&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
           &lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;A &lt;/span&gt;&lt;span class='se'&gt;\\&lt;/span&gt;&lt;span class='s'&gt;oplus H_4&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;h4&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;

&lt;span class='k'&gt;for&lt;/span&gt; &lt;span class='n'&gt;label&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;f&lt;/span&gt; &lt;span class='ow'&gt;in&lt;/span&gt; &lt;span class='n'&gt;filters&lt;/span&gt;&lt;span class='p'&gt;:&lt;/span&gt;
    &lt;span class='n'&gt;t2&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;scipy&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;signal&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;convolve&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;t&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;f&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;same&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;to_latex&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;t2&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;astype&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;uint8&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;&lt;span class='n'&gt;label&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='n'&gt;label&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I&amp;#8217;ll likely get around to expanding this into a full package sometime in the future, since there&amp;#8217;s a lot that is hard coded (the &lt;code&gt;\[ \]&lt;/code&gt; environment, stringification of the array, the fact that all columns are centered, etc.). A gist of the function is available &lt;a href='https://gist.github.com/4665827'&gt;here&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>pythonbrew+opencv+debian</title>
      <link>http://malloc47.com/pythonbrew-opencv-debian/</link>
      <pubDate>Sat, 24 Nov 2012 15:00:00 -0800</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/pythonbrew-opencv-debian</guid>
      <description>&lt;p&gt;There are a number of ways to go about building a modern development environment for scientific computing and computer vision in python. If you&amp;#8217;re used to developing on bleeding-edge, however, the latest debian stable makes it a chore to get started with the latest and greatest. It ships with &lt;code&gt;python2.6&lt;/code&gt; instead of 2.7, and &lt;a href='http://opencv.willowgarage.com'&gt;opencv&lt;/a&gt; is notoriously out of date in a number of distributions, debian included. I typically use Arch, but the server-class machines I have access to were running debian, so I had to bootstrap my setup into this environment.&lt;/p&gt;

&lt;p&gt;Challenge accepted.&lt;/p&gt;

&lt;p&gt;Thankfully, &lt;a href='https://github.com/utahta/pythonbrew'&gt;pythonbrew&lt;/a&gt; (or &lt;a href='https://github.com/saghul/pythonz'&gt;pythonz&lt;/a&gt;) comes to the rescue by making it easy to handle multiple pythons for a single account (without having to install them system-wide) as well as providing wrappers around &lt;a href='http://www.virtualenv.org/'&gt;virtualenv&lt;/a&gt;. However, not everything is rosy. The python you choose has to be built with shared libraries if you want to install opencv later:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;pythonbrew install --configure&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;--enable-shared&amp;quot;&lt;/span&gt; 2.7.3 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After this, you can bootstrap a &lt;code&gt;virtualenv&lt;/code&gt; as usual&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;pythonbrew venv init
pythonbrew venv create debian
pythonbrew venv use debian
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and install any requisite stuff you might need (minimum numpy/scipy)&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;pip install numpy
pip install scipy
pip install pymorph
pip install matplotlib
pip install distutils
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unfortunately, there&amp;#8217;s no such &lt;code&gt;pip&lt;/code&gt; package for opencv. Thankfully, the &lt;a href='http://opencv.willowgarage.com/wiki/InstallGuide%20%3A%20Debian'&gt;debian installation guide&lt;/a&gt; isn&amp;#8217;t too far out of date, and many of the listed packages to &lt;code&gt;apt-get&lt;/code&gt; are still relevant.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;wget http://downloads.sourceforge.net/project/opencvlibrary/opencv-unix/2.4.3/OpenCV-2.4.3.tar.bz2
tar xjvf OpenCV-2.4.3.tar.bz2
&lt;span class='nb'&gt;cd &lt;/span&gt;OpenCV-2.4.3
mkdir &lt;span class='o'&gt;{&lt;/span&gt;build,release&lt;span class='o'&gt;}&lt;/span&gt;
&lt;span class='nb'&gt;cd &lt;/span&gt;release
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;At this point, we need to delve into where &lt;code&gt;pythonbrew&lt;/code&gt; puts all its related files to configure opencv correctly. First, your installed python will be available in one of two places (here python 2.7.3 is used as an example):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;~/.pythonbrew/venvs/Python-2.7.3/{venv-name}/bin/python
~/.pythonbrew/pythons/Python-2.7.3/bin/python&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All &lt;code&gt;virtualenv&lt;/code&gt;s based on a particular version of python will have a copy of that python binary for use in their own isolated environment. In addition, the &lt;code&gt;virtualenv&lt;/code&gt; has an &lt;code&gt;include&lt;/code&gt; directory that you should use, since all your additional packages installed into the &lt;code&gt;virtualenv&lt;/code&gt; will place their headers in this directory:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;~/.pythonbrew/venvs/Python-2.7.3/{venv-name}/include/python2.7&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The hitch, however, is that the &lt;code&gt;virtualenv&lt;/code&gt; does not have a copy/symlink of the shared library we specifically built when first compiling python using &lt;code&gt;pythonbrew&lt;/code&gt;, unlike a typical native python install. This means that &lt;code&gt;cmake&lt;/code&gt;&amp;#8217;s approach to locate this library will fail. Thus we must point opencv to this&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;~/.pythonbrew/pythons/Python-2.7.3/lib/libpython2.7.so&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;for it to build corectly.&lt;/p&gt;

&lt;p&gt;Speaking of &lt;code&gt;cmake&lt;/code&gt;, there is a bug in the &lt;code&gt;cmake&lt;/code&gt; included in debian that prevents it from building opencv correctly. I was lazy and simply grabbed a binary of the latest &lt;code&gt;cmake&lt;/code&gt;,&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;wget http://www.cmake.org/files/v2.8/cmake-2.8.9-Linux-i386.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which worked on my debian build, but it&amp;#8217;s better to compile it if you plan to continue using it for more than a one-off build.&lt;/p&gt;

&lt;p&gt;Finally, understanding opencv&amp;#8217;s &lt;code&gt;cmake&lt;/code&gt; flags is important for getting everything stitched together:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PYTHON_EXECUTABLE=~/.pythonbrew/venvs/Python-2.7.3/{venv-name}/bin/python
PYTHON_INCLUDE_DIR=~/.pythonbrew/venvs/Python-2.7.3/debian/include/python2.7
PYTHON_LIBRARY=~/.pythonbrew/pythons/Python-2.7.3/lib/libpython2.7.so&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Additionally, if you find that numpy isn&amp;#8217;t autodetected, you can specify&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PYTHON_NUMPY_INCLUDE_DIR=~/.pythonbrew/venvs/Python-2.7.3/debian/lib/python2.7/site-packages/numpy/core/include&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also specify your &lt;code&gt;virtualenv&lt;/code&gt; path to install the python libraries&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;PYTHON_PACKAGES_PATH=~/.pythonbrew/venvs/Python-2.7.3/{venv-name}/lib/python2.7/site-packages&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or just symlink/copy the resulting &lt;code&gt;cv2.so&lt;/code&gt; and &lt;code&gt;cv.py&lt;/code&gt; files there later.&lt;/p&gt;

&lt;p&gt;Putting it all together, I used this command to generate the makefile which compiles correctly against &lt;code&gt;pythonbrew&lt;/code&gt;&amp;#8217;s python (where &lt;code&gt;debian&lt;/code&gt; is my &lt;code&gt;virtualenv&lt;/code&gt; name):&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;~/cmake-2.8.9-Linux-i386/bin/cmake &lt;span class='se'&gt;\&lt;/span&gt;
-D &lt;span class='nv'&gt;CMAKE_INSTALL_PREFIX&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;../build &lt;span class='se'&gt;\&lt;/span&gt;
-D &lt;span class='nv'&gt;BUILD_NEW_PYTHON_SUPPORT&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;ON &lt;span class='se'&gt;\&lt;/span&gt;
-D &lt;span class='nv'&gt;BUILD_PYTHON_SUPPORT&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;ON &lt;span class='se'&gt;\&lt;/span&gt;
-D &lt;span class='nv'&gt;BUILD_EXAMPLES&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;OFF &lt;span class='se'&gt;\&lt;/span&gt;
-D &lt;span class='nv'&gt;PYTHON_EXECUTABLE&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;~/.pythonbrew/venvs/Python-2.7.3/debian/bin/python &lt;span class='se'&gt;\&lt;/span&gt;
-D &lt;span class='nv'&gt;PYTHON_INCLUDE_DIR&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;~/.pythonbrew/venvs/Python-2.7.3/debian/include/python2.7 &lt;span class='se'&gt;\&lt;/span&gt;
-D &lt;span class='nv'&gt;PYTHON_LIBRARY&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;~/.pythonbrew/pythons/Python-2.7.3/lib/libpython2.7.so &lt;span class='se'&gt;\&lt;/span&gt;
-D &lt;span class='nv'&gt;PYTHON_NUMPY_INCLUDE_DIR&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;~/.pythonbrew/venvs/Python-2.7.3/debian/lib/python2.7/site-packages/numpy/core/include &lt;span class='se'&gt;\&lt;/span&gt;
-D &lt;span class='nv'&gt;PYTHON_PACKAGES_PATH&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;~/.pythonbrew/venvs/Python-2.7.3/debian/lib/python2.7/site-packages &lt;span class='se'&gt;\&lt;/span&gt;
../
make
make install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Depending on what you&amp;#8217;re doing, there may be other tricks with &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; to make specific things work, but your &lt;code&gt;pythonbrew&lt;/code&gt;ed python should be primed to access opencv from here.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Anatomy of a Chrome Extension</title>
      <link>http://malloc47.com/anatomy-of-a-chrome-extension/</link>
      <pubDate>Sat, 15 Sep 2012 00:00:00 -0700</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/anatomy-of-a-chrome-extension</guid>
      <description>&lt;p&gt;I launched &lt;a href='http://nonpartisan.me'&gt;nonpartisan.me&lt;/a&gt; a few weeks back, which exists primarily in the form of a Google Chrome extension (there&amp;#8217;s a Firefox add-on too). Since I released it with all of the &lt;a href='https://github.com/malloc47/nonpartisan.me'&gt;source&lt;/a&gt;, this makes it a great time to dissect the (very simple) code. As you will notice from the site and the small bit of &lt;a href='http://www.charlestoncitypaper.com/charleston/sick-of-politics-on-facebook-try-this-browser-tool/Content?oid=4153447'&gt;press&lt;/a&gt; it picked up, &lt;code&gt;nonpartisan.me&lt;/code&gt; has a very simple premise: filter out political keywords from the various newsfeeds (specifically Facebook, Twitter, and Google+).&lt;/p&gt;

&lt;p&gt;This was my first attempt at a Chrome extension, and it&amp;#8217;s surprisingly straightforward. All such extensions require a &lt;code&gt;manifest.json&lt;/code&gt;, which looks like this for &lt;code&gt;nonpartisan.me&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;name&amp;quot;&lt;/span&gt;             &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;nonpartisan.me&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;version&amp;quot;&lt;/span&gt;          &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;0.2.1&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;manifest_version&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;description&amp;quot;&lt;/span&gt;      &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Removes partisanship from your news feeds&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;icons&amp;quot;&lt;/span&gt;            &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;16&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;icon16.png&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                           &lt;span class='s2'&gt;&amp;quot;48&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;icon48.png&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                          &lt;span class='s2'&gt;&amp;quot;128&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;icon128.png&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;},&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;homepage_url&amp;quot;&lt;/span&gt;     &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;http://nonpartisan.me&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;page_action&amp;quot;&lt;/span&gt;      &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;default_icon&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;icon48.png&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                          &lt;span class='s2'&gt;&amp;quot;default_title&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;nonpartisan&amp;#39;ed&amp;quot;&lt;/span&gt; &lt;span class='p'&gt;},&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;permissions&amp;quot;&lt;/span&gt;      &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;tabs&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                          &lt;span class='s2'&gt;&amp;quot;http://www.facebook.com/&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                          &lt;span class='s2'&gt;&amp;quot;http://www.twitter.com/&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
                          &lt;span class='s2'&gt;&amp;quot;http://plus.google.com/&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;options_page&amp;quot;&lt;/span&gt;     &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;options.html&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;content_scripts&amp;quot;&lt;/span&gt;  &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;matches&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;*://*.facebook.com/*&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;js&amp;quot;&lt;/span&gt;     &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;jquery.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;common.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;fb.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;nonpartisan.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;run_at&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;document_end&amp;quot;&lt;/span&gt;
    &lt;span class='p'&gt;},&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;matches&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;*://twitter.com/*&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;js&amp;quot;&lt;/span&gt;     &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;jquery.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;common.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;tw.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;nonpartisan.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;run_at&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;document_end&amp;quot;&lt;/span&gt;
    &lt;span class='p'&gt;},&lt;/span&gt;
    &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;matches&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;*://plus.google.com/*&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;js&amp;quot;&lt;/span&gt;     &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;jquery.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;common.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;gp.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;nonpartisan.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
        &lt;span class='s2'&gt;&amp;quot;run_at&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;document_end&amp;quot;&lt;/span&gt;
    &lt;span class='p'&gt;}],&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;background&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;scripts&amp;quot;&lt;/span&gt;   &lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;common.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;background.js&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;],&lt;/span&gt;
                   &lt;span class='s2'&gt;&amp;quot;persistent&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='kc'&gt;false&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The real meat here is &lt;code&gt;content_scripts&lt;/code&gt;, which lists the javascript we wish to trigger after a page is loaded, &lt;code&gt;greasemonkey&lt;/code&gt;-style. A particularly nice feature of content scripts are that they work in an isolated environment separate from any javascript that the page itself may include. Thus we can add &lt;code&gt;jquery&lt;/code&gt; to the list of javascript that is run without fear of clashing with a page&amp;#8217;s global namespace.&lt;/p&gt;

&lt;p&gt;You can think of every element in the &lt;code&gt;&amp;quot;js&amp;quot;&lt;/code&gt; array as a separate &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tag in an &lt;code&gt;HTML&lt;/code&gt; page, so the files are loaded in the given order, all into a single namespace. Rather clumsily, I chose to simply put a callback module (which is called &lt;code&gt;plugin&lt;/code&gt; here) in the individual &lt;code&gt;fb.js&lt;/code&gt;, &lt;code&gt;tw.js&lt;/code&gt;, and &lt;code&gt;gp.js&lt;/code&gt; files which is then used by the core component, &lt;code&gt;nonpartisan.js&lt;/code&gt;, as a simple means of avoiding any hard-coded per-site values in the actual filtering code.&lt;/p&gt;

&lt;p&gt;With this, and the pseudo-regex &lt;code&gt;&amp;quot;matches&amp;quot;&lt;/code&gt; field that specifies which pages trigger the content script, we can run arbitrary code on websites we specify. For &lt;code&gt;nonpartisan.me&lt;/code&gt;, the filtering code looks like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='s2'&gt;&amp;quot;use strict&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;nonpartisan&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;plugin&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;

    &lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='nx'&gt;nonpartisan&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;watch&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='nx'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='nx'&gt;keywords&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='nx'&gt;kill&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='nx'&gt;removeList&lt;/span&gt;&lt;span class='p'&gt;){&lt;/span&gt;
            &lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;each&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;el&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
                &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;el&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;css&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;display&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;!==&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;none&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                    &lt;span class='nx'&gt;el&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;find&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;*&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;each&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                        &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;toCheck&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;text&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;toLowerCase&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
                        &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;toCheck&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;length&lt;/span&gt; &lt;span class='o'&gt;&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                           &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;removeList&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;some&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;value&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                               &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;toCheck&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;search&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;\\b&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;+&lt;/span&gt;&lt;span class='nx'&gt;value&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;toLowerCase&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;&lt;span class='o'&gt;+&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;\\b&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;&amp;gt;=&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
                           &lt;span class='p'&gt;}))&lt;/span&gt;
                          &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                            &lt;span class='nx'&gt;el&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;css&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;display&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;none&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;});&lt;/span&gt;
                            &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='kc'&gt;false&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
                        &lt;span class='p'&gt;}&lt;/span&gt;
                    &lt;span class='p'&gt;});&lt;/span&gt;
                &lt;span class='p'&gt;}&lt;/span&gt;
            &lt;span class='p'&gt;});&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;

        &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;watch&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;numChildren&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;children&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;length&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
            &lt;span class='nx'&gt;setInterval&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;newNumChildren&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;children&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;length&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
                &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;numChildren&lt;/span&gt; &lt;span class='o'&gt;!==&lt;/span&gt; &lt;span class='nx'&gt;newNumChildren&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
                    &lt;span class='nx'&gt;kill&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='nx'&gt;keywords&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
                    &lt;span class='nx'&gt;numChildren&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;newNumChildren&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
                &lt;span class='p'&gt;}&lt;/span&gt;
            &lt;span class='p'&gt;},&lt;/span&gt;
                        &lt;span class='mi'&gt;500&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
            &lt;span class='nx'&gt;kill&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;parent&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='nx'&gt;keywords&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;

    &lt;span class='c1'&gt;// get parameters from plugin and trigger nonpartisan() here...&lt;/span&gt;

&lt;span class='p'&gt;}(&lt;/span&gt;&lt;span class='nx'&gt;plugin&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first chunk&amp;#8211;the &lt;code&gt;kill&lt;/code&gt; function&amp;#8211;works as advertised: given a parent element and a set of keywords, the function iterates over every child element and determines if any of the nested elements within (i.e. &lt;code&gt;el.find(&amp;#39;*&amp;#39;)&lt;/code&gt;) contains any of the keywords. Instead of deleting &lt;code&gt;DOM&lt;/code&gt; nodes, which may break the page&amp;#8217;s own javascript (I discovered this the hard way), it&amp;#8217;s easier to instead call &lt;code&gt;el.css({&amp;#39;display&amp;#39;:&amp;#39;none});&lt;/code&gt; to simply hide unwanted elements. For efficiency, the &lt;code&gt;forEach&lt;/code&gt; terminates as soon any any nested child returns a match, potentially saving a small amount of needless searching.&lt;/p&gt;

&lt;p&gt;The second chunk starts a timer (if indeed the parent is even found on the current page) that checks if the number of children of the parent element has changed and, if so, re-triggers the filtering process to determine if there are any new children to be hidden. This helps handle &lt;code&gt;AJAX&lt;/code&gt;-driven sites, like the &amp;#8220;infinite scrolling&amp;#8221; facebook newsfeed, which may mutate the &lt;code&gt;DOM&lt;/code&gt; at any time. Both of these functions are wrapped up into another easy-to-call function inside of the high-level &lt;code&gt;nonpartisan&lt;/code&gt; module.&lt;/p&gt;

&lt;p&gt;And that really is all there is to a typical &lt;code&gt;greasemonkey&lt;/code&gt;-like Chrome extension, but that&amp;#8217;s certainly not the end of what a complete and helpful extension can provide. The trickier bit is persisting configuration options. The downside of sandboxing content scripts is that they exist in a transient execution context, meaning there&amp;#8217;s no &lt;code&gt;localStorage&lt;/code&gt; to persist program options. The details of the plumbing used to kick-off the process and handle options were omitted from the above snippet, so we&amp;#8217;ll dig more into this now to illustrate how to handle persistent options.&lt;/p&gt;

&lt;p&gt;Chrome provides a nice solution to the problem of not having &lt;code&gt;localStorage&lt;/code&gt; available to content scripts by providing a &lt;code&gt;background&lt;/code&gt; script which &lt;em&gt;does&lt;/em&gt; have its own &lt;code&gt;localStorage&lt;/code&gt;, which it can transmit to a content script via the &lt;code&gt;chrome.extension.onMessage&lt;/code&gt; listener. We can then fill in the omitted component of the above snippet with:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='nx'&gt;chrome&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;extension&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;sendMessage&lt;/span&gt;&lt;span class='p'&gt;({&lt;/span&gt;&lt;span class='nx'&gt;method&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;config&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;},&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;response&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='nx'&gt;response&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;sites&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;plugin&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;site&lt;/span&gt;&lt;span class='p'&gt;])&lt;/span&gt; &lt;span class='k'&gt;return&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;l&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;response&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;filter&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;l&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='nx'&gt;l&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;length&lt;/span&gt;&lt;span class='o'&gt;&amp;gt;&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='nx'&gt;plugin&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;cb&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;l&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='nx'&gt;nonpartisan&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
    &lt;span class='c1'&gt;// get default values from common.js&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
        &lt;span class='nx'&gt;l&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='p'&gt;[];&lt;/span&gt;
        &lt;span class='k'&gt;for&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;index&lt;/span&gt; &lt;span class='k'&gt;in&lt;/span&gt; &lt;span class='nx'&gt;choices&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
            &lt;span class='nx'&gt;l&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;l&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;concat&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;choices&lt;/span&gt;&lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='nx'&gt;index&lt;/span&gt;&lt;span class='p'&gt;]);&lt;/span&gt;
        &lt;span class='p'&gt;}&lt;/span&gt;
        &lt;span class='nx'&gt;plugin&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;cb&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;l&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='nx'&gt;nonpartisan&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
    &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This sends a message, requesting &lt;code&gt;&amp;quot;config&amp;quot;&lt;/code&gt; from the &lt;code&gt;background.js&lt;/code&gt; script, which returns, among other things, the list of keywords we wish to filter. This list was saved in &lt;code&gt;localStorage&lt;/code&gt; in &lt;code&gt;background.js&lt;/code&gt;&amp;#8217;s execution context. Recall that &lt;code&gt;plugin&lt;/code&gt; is the module that specifies the particular settings for the page being filtered. Thus we pass along the list of words to filter and the &lt;code&gt;nonpartisan()&lt;/code&gt; callback function to the &lt;code&gt;plugin&lt;/code&gt; module, and it subsequently executes &lt;code&gt;nonpartisan()&lt;/code&gt; on the appropriate elements on the &lt;code&gt;DOM&lt;/code&gt;. The &lt;code&gt;background.js&lt;/code&gt; file used in &lt;code&gt;nonpartisan.me&lt;/code&gt; is a bit more &lt;a href='https://github.com/malloc47/nonpartisan.me/blob/master/chrome/background.js'&gt;involved&lt;/a&gt;, but it nonetheless essentially acts as a broker, converting Chrome&amp;#8217;s internal message-passing API calls to &lt;code&gt;localStorage&lt;/code&gt; requests.&lt;/p&gt;

&lt;p&gt;Of course, there&amp;#8217;s only so much utility to be gained from &lt;code&gt;localStorage&lt;/code&gt; without supplying the user with the ability to configure the various options that may be saved in therein. This is done by a typical &lt;code&gt;html&lt;/code&gt; page, specified by &lt;code&gt;&amp;quot;options_page&amp;quot;&lt;/code&gt;. Since there&amp;#8217;s not much magic there&amp;#8211;it&amp;#8217;s just a plain html page with enough javascript to persist the settings&amp;#8211;I will omit the gory details, which you can poke around yourself in &lt;a href='https://github.com/malloc47/nonpartisan.me/blob/master/chrome/options.js'&gt;the&lt;/a&gt; &lt;a href='https://github.com/malloc47/nonpartisan.me/blob/master/chrome/background.js'&gt;repository&lt;/a&gt;, if you&amp;#8217;re so inclined.&lt;/p&gt;

&lt;p&gt;So that&amp;#8217;s an extension. Writing the above was literally a matter of minutes and some quality time with the Chrome API specifications. As is always the case (especially when I&amp;#8217;m working outside of my area of expertise, say with making the amateurish logo), the real work is doing the little bits of spit-and-polish to handle the various configuration options, throwing together the webpage, creating the icons and promotional images for the &lt;a href='https://chrome.google.com/webstore/detail/ninebcppidndhampaggnjbijpacoadgg'&gt;Chrome Web Store&lt;/a&gt;, etc. But it&amp;#8217;s still good to know that the Chrome team has made the extension-building process as simple and well &lt;a href='http://developer.chrome.com/extensions/docs.html'&gt;documented&lt;/a&gt; as they have.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Poor Man's LDAP</title>
      <link>http://malloc47.com/poor-mans-ldap/</link>
      <pubDate>Sat, 11 Aug 2012 00:00:00 -0700</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/poor-mans-ldap</guid>
      <description>&lt;p&gt;In addition to being a researcher and backend web developer, I&amp;#8217;ve also worn the system administrator hat for a number of years. While the likes of &lt;a href='http://en.wikipedia.org/wiki/Ldap'&gt;&lt;code&gt;LDAP&lt;/code&gt;&lt;/a&gt;, &lt;a href='http://en.wikipedia.org/wiki/Active_directory'&gt;&lt;code&gt;Active Directory&lt;/code&gt;&lt;/a&gt;, &lt;a href='http://en.wikipedia.org/wiki/Network_Information_Service'&gt;&lt;code&gt;NIS&lt;/code&gt;&lt;/a&gt;, and their ilk can work quite well for managing medium-to-large networks, I&amp;#8217;ve more often been tasked with managing small-scale (&amp;lt; 20 machines) heterogeneous Linux networks, where deploying &lt;code&gt;LDAP&lt;/code&gt; with full &lt;code&gt;Kerberos&lt;/code&gt; authentication would be overkill. Typical requirements I&amp;#8217;ve encountered in small lab settings are simple user account and home folder sharing, and (relatively) similar package installations.&lt;/p&gt;

&lt;p&gt;With this in mind, I did what probably every sysadmin in the same situation would do: scrape together a simple set of scripts to handle basic file synchronization for me. Specifically, I noticed two prevalent requirements among config files being synced:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;machines and/or distros have a common header or footer that must be included (e.g., a list of system users in &lt;code&gt;/etc/passwd&lt;/code&gt;), and&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;specific machines (e.g., servers) shouldn&amp;#8217;t have some files synced with the rest of the machines (e.g., file shares might be different on a server).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Thus, &lt;a href='https://github.com/malloc47/pmldap'&gt;&lt;code&gt;Poor Man&amp;#39;s LDAP&lt;/code&gt;&lt;/a&gt; was born.&lt;/p&gt;

&lt;p&gt;While nothing more than a collection of scripts&amp;#8211;no different than what many other sysadmins have implemented, in all likelihood&amp;#8211;they will hopefully be of use for those who, like me, are graduate students or otherwise non-full-time sysadmins that don&amp;#8217;t have time to do things the &amp;#8220;right&amp;#8221; way.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m dogfooding &lt;code&gt;pmldap&lt;/code&gt; on my research lab&amp;#8217;s network, where we (currently) have 5 Fedora machines (various versions between 10 and 16) and 5 Debian machines (all on stable). Since my recent &lt;a href='https://github.com/malloc47/pmldap/commit/ab8918c17f22d2a9dabd6ea9ca97b39c9cdc968a'&gt;patch&lt;/a&gt;, &lt;code&gt;pmldap&lt;/code&gt; now supports groups, which are useful for running &lt;code&gt;yum&lt;/code&gt; commands only on the Fedora machines and &lt;code&gt;apt&lt;/code&gt; commands on only the Debian boxes. Files being synchronized include: &lt;code&gt;fstab&lt;/code&gt;, &lt;code&gt;group&lt;/code&gt;, &lt;code&gt;hosts&lt;/code&gt;, &lt;code&gt;hosts.allow&lt;/code&gt;, &lt;code&gt;hosts.deny&lt;/code&gt;, &lt;code&gt;passwd&lt;/code&gt;, &lt;code&gt;shadow&lt;/code&gt;, and &lt;code&gt;sudoers&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also in the repo are a few convenience tools that I&amp;#8217;ve found useful:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;authorize-machine&lt;/code&gt; bootstraps a machine by setting up ssh keys&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;code&gt;setup&lt;/code&gt; bootstraps config files from a remote machine so they can be merged with the desired additions&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;code&gt;cmd&lt;/code&gt; runs an arbitrary command on all machines (or a particular group of machines)&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;code&gt;useradd&lt;/code&gt; is a feature-incomplete reimplementation of the native &lt;code&gt;useradd&lt;/code&gt; command that works on local &lt;code&gt;passwd&lt;/code&gt;, &lt;code&gt;shadow&lt;/code&gt;, and &lt;code&gt;group&lt;/code&gt; files to add new users that can later be synchronized across the network&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since I hadn&amp;#8217;t stumbled across something of this scope to fit the small-scale-network use case, I&amp;#8217;m hopeful that &lt;code&gt;pmldap&lt;/code&gt; will be of use to anyone in a similar situation.&lt;/p&gt;

&lt;p&gt;You&amp;#8217;ll find it on gitub &lt;a href='https://github.com/malloc47/pmldap'&gt;here&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Git Dotfile Versioning Across Systems</title>
      <link>http://malloc47.com/git-dotfile-versioning-across-systems/</link>
      <pubDate>Sun, 29 Jul 2012 00:00:00 -0700</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/git-dotfile-versioning-across-systems</guid>
      <description>&lt;p&gt;For users of unix-like operating systems, treating your dotfiles like real code and keeping them in a repository is a supremely good idea. While there are a myriad of ways to go about this, the typical (albeit destructive) way to do this is by symlinking files in the repository to the home folder:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='c'&gt;#!/bin/bash&lt;/span&gt;
&lt;span class='nv'&gt;DEST&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='nv'&gt;$HOME&lt;/span&gt;
&lt;span class='nv'&gt;FILES&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='k'&gt;$(&lt;/span&gt;git ls-files | grep -v .gitignore | grep -v ^&lt;span class='k'&gt;$(&lt;/span&gt;basename &lt;span class='nv'&gt;$0&lt;/span&gt;&lt;span class='k'&gt;)&lt;/span&gt;&lt;span class='nv'&gt;$)&lt;/span&gt;
&lt;span class='k'&gt;for &lt;/span&gt;f in &lt;span class='nv'&gt;$FILES&lt;/span&gt; ; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='o'&gt;[&lt;/span&gt; -n &lt;span class='s2'&gt;&amp;quot;$(dirname $f)&amp;quot;&lt;/span&gt; &lt;span class='se'&gt;\ &lt;/span&gt;
      -a &lt;span class='s2'&gt;&amp;quot;$(dirname $f)&amp;quot;&lt;/span&gt; !&lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;.&amp;quot;&lt;/span&gt; &lt;span class='se'&gt;\&lt;/span&gt;
      -a ! -d &lt;span class='s2'&gt;&amp;quot;$DEST/$(dirname $f)&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='se'&gt;\ &lt;/span&gt;
    &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; mkdir -p &lt;span class='nv'&gt;$DEST&lt;/span&gt;/&lt;span class='k'&gt;$(&lt;/span&gt;dirname &lt;span class='nv'&gt;$f&lt;/span&gt;&lt;span class='k'&gt;)&lt;/span&gt;
    ln -sf &lt;span class='k'&gt;$(&lt;/span&gt;&lt;span class='nb'&gt;pwd&lt;/span&gt;&lt;span class='k'&gt;)&lt;/span&gt;/&lt;span class='nv'&gt;$f&lt;/span&gt; &lt;span class='nv'&gt;$DEST&lt;/span&gt;/&lt;span class='nv'&gt;$f&lt;/span&gt;
&lt;span class='k'&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I specifically chose to have &lt;code&gt;FILES&lt;/code&gt; populated using &lt;code&gt;git ls-files&lt;/code&gt; to prevent any unversioned files from sneaking into the home folder, additionally filtering out both the &lt;code&gt;.gitignore&lt;/code&gt; file, and the current script name (so it can be safely checked in as well). After this, we loop over the files, creating appropriate directories if they do not exist, effectively symlinking the &lt;em&gt;entire repo&lt;/em&gt; to the home folder, clobbering any files that are already there (without asking!).&lt;/p&gt;

&lt;p&gt;While most dotfiles won&amp;#8217;t care what system they are on, certain scripts or settings may be machine-dependent. To accommodate this, I include a &lt;code&gt;~/.sys/`hostname`/&lt;/code&gt; folder for every machine with system-specific files. Then, when symlinking, we favor files listed in the &lt;code&gt;~/.sys/`hostname`/&lt;/code&gt; folder rather than the top-level files:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt; -e &lt;span class='s2'&gt;&amp;quot;.sys/$(hostname)/$f&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;]&lt;/span&gt; ; &lt;span class='k'&gt;then&lt;/span&gt;
&lt;span class='k'&gt;    &lt;/span&gt;ln -sf &lt;span class='k'&gt;$(&lt;/span&gt;&lt;span class='nb'&gt;pwd&lt;/span&gt;&lt;span class='k'&gt;)&lt;/span&gt;/.sys/&lt;span class='k'&gt;$(&lt;/span&gt;hostname&lt;span class='k'&gt;)&lt;/span&gt;/&lt;span class='nv'&gt;$f&lt;/span&gt; &lt;span class='nv'&gt;$DEST&lt;/span&gt;/&lt;span class='nv'&gt;$f&lt;/span&gt;
&lt;span class='k'&gt;else&lt;/span&gt;
&lt;span class='k'&gt;    &lt;/span&gt;ln -sf &lt;span class='k'&gt;$(&lt;/span&gt;&lt;span class='nb'&gt;pwd&lt;/span&gt;&lt;span class='k'&gt;)&lt;/span&gt;/&lt;span class='nv'&gt;$f&lt;/span&gt; &lt;span class='nv'&gt;$DEST&lt;/span&gt;/&lt;span class='nv'&gt;$f&lt;/span&gt;
&lt;span class='k'&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Thus, for example, given &lt;code&gt;machine1&lt;/code&gt; and &lt;code&gt;machine2&lt;/code&gt; and a repo in the &lt;code&gt;~/dotfiles&lt;/code&gt; directory with these files:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;~/dotfiles/.gitconfig
~/dotfiles/.sys/machine2/.gitconfig&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;machine1&lt;/code&gt; will get a symlink from&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;~/dotfiles/.gitconfig &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to &lt;code&gt;~/.gitconfig&lt;/code&gt;, while &lt;code&gt;machine2&lt;/code&gt; will instead get a symlink from&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;~/dotfiles/.sys/machine2/.gitconfig&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to &lt;code&gt;~/.gitconfig&lt;/code&gt;. This variant of the script doesn&amp;#8217;t explicitly ignore the &lt;code&gt;.sys&lt;/code&gt; folder itself so it will be added to the home folder as well. Which, as an aside, can be useful by including something like this&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='o'&gt;[&lt;/span&gt; -d ~/.sys/&lt;span class='sb'&gt;`&lt;/span&gt;hostname&lt;span class='sb'&gt;`&lt;/span&gt;/bin &lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='nb'&gt;export &lt;/span&gt;&lt;span class='nv'&gt;PATH&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;~/.sys/&lt;span class='sb'&gt;`&lt;/span&gt;hostname&lt;span class='sb'&gt;`&lt;/span&gt;/bin:&lt;span class='nv'&gt;$PATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;in the &lt;code&gt;.bashrc&lt;/code&gt; file such that specific scripts will be on the &lt;code&gt;PATH&lt;/code&gt; for individual machines.&lt;/p&gt;

&lt;p&gt;So the final script, with a bit of input checking, looks like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='c'&gt;#!/bin/bash&lt;/span&gt;
&lt;span class='nb'&gt;set&lt;/span&gt; -e
&lt;span class='nv'&gt;EXPECTED_ARGS&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;1
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt; &lt;span class='nv'&gt;$# &lt;/span&gt;-lt &lt;span class='nv'&gt;$EXPECTED_ARGS&lt;/span&gt; &lt;span class='o'&gt;]&lt;/span&gt;
&lt;span class='k'&gt;then&lt;/span&gt;
&lt;span class='k'&gt;    &lt;/span&gt;&lt;span class='nb'&gt;echo&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Usage: `basename $0` directory&amp;quot;&lt;/span&gt;
    &lt;span class='nb'&gt;echo&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;WILL clobber existing files without permission: Use at your own risk&amp;quot;&lt;/span&gt;
    &lt;span class='nb'&gt;exit &lt;/span&gt;65 
&lt;span class='k'&gt;fi&lt;/span&gt;

&lt;span class='nv'&gt;DEST&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='nv'&gt;$1&lt;/span&gt;
&lt;span class='nv'&gt;FILES&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='k'&gt;$(&lt;/span&gt;git ls-files | grep -v .gitignore | grep -v ^&lt;span class='k'&gt;$(&lt;/span&gt;basename &lt;span class='nv'&gt;$0&lt;/span&gt;&lt;span class='k'&gt;)&lt;/span&gt;&lt;span class='nv'&gt;$)&lt;/span&gt;

&lt;span class='k'&gt;for &lt;/span&gt;f in &lt;span class='nv'&gt;$FILES&lt;/span&gt; ; &lt;span class='k'&gt;do&lt;/span&gt;
&lt;span class='k'&gt;    &lt;/span&gt;&lt;span class='nb'&gt;echo&lt;/span&gt; &lt;span class='nv'&gt;$f&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt; -n &lt;span class='s2'&gt;&amp;quot;$(dirname $f)&amp;quot;&lt;/span&gt; -a &lt;span class='s2'&gt;&amp;quot;$(dirname $f)&amp;quot;&lt;/span&gt; !&lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;.&amp;quot;&lt;/span&gt; -a ! -d &lt;span class='s2'&gt;&amp;quot;$DEST/$(dirname $f)&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;]&lt;/span&gt; ; &lt;span class='k'&gt;then&lt;/span&gt;
&lt;span class='k'&gt;        &lt;/span&gt;mkdir -p &lt;span class='nv'&gt;$DEST&lt;/span&gt;/&lt;span class='k'&gt;$(&lt;/span&gt;dirname &lt;span class='nv'&gt;$f&lt;/span&gt;&lt;span class='k'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;fi&lt;/span&gt;
&lt;span class='k'&gt;	&lt;/span&gt;
&lt;span class='k'&gt;    if&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt; -e &lt;span class='s2'&gt;&amp;quot;.sys/$(hostname)/$f&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;]&lt;/span&gt; ; &lt;span class='k'&gt;then&lt;/span&gt;
&lt;span class='k'&gt;        &lt;/span&gt;ln -sf &lt;span class='k'&gt;$(&lt;/span&gt;&lt;span class='nb'&gt;pwd&lt;/span&gt;&lt;span class='k'&gt;)&lt;/span&gt;/.sys/&lt;span class='k'&gt;$(&lt;/span&gt;hostname&lt;span class='k'&gt;)&lt;/span&gt;/&lt;span class='nv'&gt;$f&lt;/span&gt; &lt;span class='nv'&gt;$DEST&lt;/span&gt;/&lt;span class='nv'&gt;$f&lt;/span&gt;
    &lt;span class='k'&gt;else&lt;/span&gt;
&lt;span class='k'&gt;        &lt;/span&gt;ln -sf &lt;span class='k'&gt;$(&lt;/span&gt;&lt;span class='nb'&gt;pwd&lt;/span&gt;&lt;span class='k'&gt;)&lt;/span&gt;/&lt;span class='nv'&gt;$f&lt;/span&gt; &lt;span class='nv'&gt;$DEST&lt;/span&gt;/&lt;span class='nv'&gt;$f&lt;/span&gt;
    &lt;span class='k'&gt;fi&lt;/span&gt;
&lt;span class='k'&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;By making &lt;code&gt;DEST&lt;/code&gt; a command-line parameter, a dry-run can be done by simply giving it an empty folder. There&amp;#8217;s no issue doing this inside the repo&amp;#8217;s working tree, as only checked-in files will be transferred to the target directory:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; mkdir tmp
&amp;gt; ./deploy tmp/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Doing this, the contents of the &lt;code&gt;tmp/&lt;/code&gt; directory can be verified with &lt;code&gt;ls -al&lt;/code&gt; to see exactly what the script will do to your home folder. Once satisfied, it can be run again with&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; ./deploy ~&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to symlink all the files to the home folder proper.&lt;/p&gt;

&lt;p&gt;Feel free to grab an up-to-date version of this script from my own dotfile repo &lt;a href='https://github.com/malloc47/config/blob/master/deploy'&gt;here&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Beating Interview Problems to Death with Parallel Haskell</title>
      <link>http://malloc47.com/beating-interview-problems-to-death-with-parallel-haskell/</link>
      <pubDate>Sun, 08 Jul 2012 00:00:00 -0700</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/beating-interview-problems-to-death-with-parallel-haskell</guid>
      <description>&lt;p&gt;Like anyone for whom graduation is becoming more immanent, I&amp;#8217;ve been taking a look at the latest trends in the typical technology interview process. While many of the &lt;a href='http://imranontech.com/2007/01/24/using-fizzbuzz-to-find-developers-who-grok-coding/'&gt;Fizz Buzz&lt;/a&gt;es being thrown around aren&amp;#8217;t exactly exciting highlights of problem solving&amp;#8230; well, you can always just beat them to death.&lt;/p&gt;

&lt;p&gt;The &lt;a href='http://en.wikipedia.org/wiki/Run-length_encoding'&gt;Run Length Encoding&lt;/a&gt; algorithm is a nice, compact, and slightly real-world interview problem that has been making the rounds for &lt;a href='http://stackoverflow.com/questions/2048854/c-interview-question-run-length-coding-of-strings'&gt;years&lt;/a&gt; now. The basic idea being that &amp;#8220;runs&amp;#8221; of data, e.g. &lt;code&gt;aaaabbbbbbb&lt;/code&gt;, are compressed into tuples, e.g. &lt;code&gt;4a7b&lt;/code&gt;, which may be a smaller representation if there is a large amount of adjacent repeated information. While real-world use cases for such a naïve compression scheme aren&amp;#8217;t abundant, the algorithm is straightforward and can be implemented in a dozen lines or so in most &lt;a href='http://rosettacode.org/wiki/Run-length_encoding'&gt;languages&lt;/a&gt;. If you&amp;#8217;ve got regexes or similar libraries at your disposal, you can manage even fewer lines. In &lt;code&gt;Haskell&lt;/code&gt;&amp;#8217;s case, one:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='haskell'&gt;&lt;span class='nf'&gt;rleMap&lt;/span&gt; &lt;span class='n'&gt;l&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;map&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nf'&gt;\&lt;/span&gt;&lt;span class='n'&gt;e&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;head&lt;/span&gt; &lt;span class='n'&gt;e&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;length&lt;/span&gt; &lt;span class='n'&gt;e&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;group&lt;/span&gt; &lt;span class='n'&gt;l&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which converts a string (or any arbitrary list of items) into a list of tuples, each of which has the character and its count. The function has type&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='haskell'&gt;&lt;span class='nf'&gt;rleMap&lt;/span&gt; &lt;span class='ow'&gt;::&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kt'&gt;Eq&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='ow'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;[(&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='kt'&gt;Int&lt;/span&gt;&lt;span class='p'&gt;)]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Simple and easy. But where&amp;#8217;s the fun in calling it quits now? Let&amp;#8217;s &lt;a href='http://en.wikipedia.org/wiki/MapReduce'&gt;MapReduce&lt;/a&gt; our &lt;code&gt;RLE&lt;/code&gt; algorithm to make it easier to parallelize and potentially &lt;a href='http://hadoop.apache.org/mapreduce/'&gt;Hadoop&lt;/a&gt;-friendly. We&amp;#8217;ve already got our &lt;code&gt;map&lt;/code&gt; function, so lets create a &lt;code&gt;reduce&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='haskell'&gt;&lt;span class='nf'&gt;rleReduce&lt;/span&gt; &lt;span class='ow'&gt;::&lt;/span&gt; &lt;span class='p'&gt;[(&lt;/span&gt;&lt;span class='kt'&gt;Char&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='kt'&gt;Int&lt;/span&gt;&lt;span class='p'&gt;)]&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;[(&lt;/span&gt;&lt;span class='kt'&gt;Char&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='kt'&gt;Int&lt;/span&gt;&lt;span class='p'&gt;)]&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;[(&lt;/span&gt;&lt;span class='kt'&gt;Char&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='kt'&gt;Int&lt;/span&gt;&lt;span class='p'&gt;)]&lt;/span&gt;
&lt;span class='nf'&gt;rleReduce&lt;/span&gt; &lt;span class='kt'&gt;[]&lt;/span&gt; &lt;span class='kt'&gt;[]&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='kt'&gt;[]&lt;/span&gt;
&lt;span class='nf'&gt;rleReduce&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt;  &lt;span class='kt'&gt;[]&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt;
&lt;span class='nf'&gt;rleReduce&lt;/span&gt; &lt;span class='kt'&gt;[]&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;  &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;
&lt;span class='nf'&gt;rleReduce&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;
          &lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fst&lt;/span&gt; &lt;span class='o'&gt;$&lt;/span&gt; &lt;span class='n'&gt;last&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt; &lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fst&lt;/span&gt; &lt;span class='o'&gt;$&lt;/span&gt; &lt;span class='n'&gt;head&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; 
                 &lt;span class='n'&gt;init&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt; &lt;span class='o'&gt;++&lt;/span&gt;  &lt;span class='p'&gt;[(&lt;/span&gt;&lt;span class='n'&gt;fst&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;last&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='p'&gt;)),&lt;/span&gt;&lt;span class='n'&gt;snd&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;last&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;snd&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;head&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;b&lt;/span&gt;&lt;span class='p'&gt;)))]&lt;/span&gt; &lt;span class='o'&gt;++&lt;/span&gt; &lt;span class='n'&gt;tail&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;
          &lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;otherwise&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt; &lt;span class='o'&gt;++&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is a less common component of RLE implementations (I haven&amp;#8217;t spotted this particular bit of code anywhere else, so there&amp;#8217;s likely room for improvement), but no less straightforward: simply join two &lt;code&gt;RLE&lt;/code&gt;&amp;#8216;d lists together if their tail and head are not the same character; if they are, merge the head and tail tuple (updating the count) and combine the rest of the list as normal.&lt;/p&gt;

&lt;p&gt;Now, it&amp;#8217;s simply a matter of splitting the RLE target into pieces, &lt;code&gt;map&lt;/code&gt;ing over pieces, and &lt;code&gt;reducing&lt;/code&gt; them back into a cohesive &lt;code&gt;RLE&lt;/code&gt;-encoded document:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='haskell'&gt;&lt;span class='nf'&gt;splitRLE&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt; &lt;span class='n'&gt;s&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;foldl&lt;/span&gt; &lt;span class='n'&gt;rleReduce&lt;/span&gt; &lt;span class='kt'&gt;[]&lt;/span&gt; &lt;span class='o'&gt;$&lt;/span&gt; &lt;span class='n'&gt;map&lt;/span&gt; &lt;span class='n'&gt;rleMap&lt;/span&gt; &lt;span class='o'&gt;$&lt;/span&gt; &lt;span class='n'&gt;chunkn&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt; &lt;span class='n'&gt;s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;(&lt;code&gt;chunkn&lt;/code&gt; is a simple hand-rolled routine that splits a string into &lt;code&gt;n&lt;/code&gt; similar-sized pieces) As expected, splitting the list apart and recombining is needless overhead without parallelization:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# No splitting (rleMap s)
&amp;gt; ghc -O2 prle --make
&amp;gt; /usr/bin/time -f &amp;#39;%E&amp;#39; ./prle large.txt 1&amp;gt;/dev/null
0:02.68

# Nonparallel splitting (foldl rleReduce [] $ map rleMap $ chunkn n s)
&amp;gt; ghc -O2 prle --make
&amp;gt; /usr/bin/time -f &amp;#39;%E&amp;#39; ./prle large.txt 1&amp;gt;/dev/null
0:06.51&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we parallelize it using a simple &lt;code&gt;parMap&lt;/code&gt;,&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='haskell'&gt;&lt;span class='nf'&gt;parallelRLE&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt; &lt;span class='n'&gt;s&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;foldl&lt;/span&gt; &lt;span class='n'&gt;rleReduce&lt;/span&gt; &lt;span class='kt'&gt;[]&lt;/span&gt; &lt;span class='o'&gt;$&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;parMap&lt;/span&gt; &lt;span class='n'&gt;rdeepseq&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='n'&gt;rleMap&lt;/span&gt; &lt;span class='o'&gt;$&lt;/span&gt; &lt;span class='n'&gt;chunkn&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt; &lt;span class='n'&gt;s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;we might expect some improvement:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# parallelRLE n s = foldl rleReduce [] $ (parMap rdeepseq) rleMap $ chunkn n s
&amp;gt; ghc -O2 prle --make -threaded -rtsopts

# Parallel map 1 core
&amp;gt; /usr/bin/time -f &amp;#39;%E&amp;#39; ./prle large.txt +RTS -N1 1&amp;gt;/dev/null
0:06.31

# Parallel map 2 cores 
&amp;gt; /usr/bin/time -f &amp;#39;%E&amp;#39; ./prle large.txt +RTS -N2 1&amp;gt;/dev/null
0:08.50

# Parallel map 4 cores
/usr/bin/time -f &amp;#39;%E&amp;#39; ./prle large.txt +RTS -N4 1&amp;gt;/dev/null
0:11.00&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Unfortunately, the bookkeeping and garbage collection overwhelm the problem very quickly, never achieving better performance.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m running the above on a randomly-generated &lt;code&gt;12MB&lt;/code&gt; text file, and no amount of coaxing could make the parallelized version do any better. While we could have written our &lt;code&gt;RLE&lt;/code&gt; algorithm in plain &lt;code&gt;C&lt;/code&gt; without much more trouble and not have encountered such performance obstacles, one does not &lt;a href='http://memegenerator.net/instance/20426610'&gt;simply parallelize C&lt;/a&gt; by swapping in a &lt;code&gt;parMap&lt;/code&gt; either (see also: &lt;a href='http://en.wikipedia.org/wiki/There_ain%27t_no_such_thing_as_a_free_lunch'&gt;this&lt;/a&gt;). Thus, we deep-dive into some &lt;code&gt;Haskell&lt;/code&gt; optimization to get a performant version.&lt;/p&gt;

&lt;p&gt;There is one particularly painful bottleneck: &lt;code&gt;Haskell&lt;/code&gt; list monads are not ideal for handling bulk data of the sort we need because &lt;code&gt;Haskell&lt;/code&gt;&amp;#8217;s &lt;code&gt;String&lt;/code&gt; type is represented as a &lt;code&gt;[Char]&lt;/code&gt;. Since there&amp;#8217;s no reason to use a boxed linked list just to scan over characters, we instead turn to &lt;code&gt;Data.ByteString&lt;/code&gt; for reading the input, and to &lt;code&gt;Data.Sequence&lt;/code&gt; to handle the RLE-encoded tuples. &lt;code&gt;Data.Sequence&lt;/code&gt; specifically removes the large penalty when concatenating the lists together in the &lt;code&gt;reduce&lt;/code&gt; step, as adding to either end of a &lt;code&gt;Seq&lt;/code&gt; is a constant time operation. This is in contrast to &lt;code&gt;[]&lt;/code&gt;, where only adding an element to a list head is constant time. Importing these&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='haskell'&gt;&lt;span class='kr'&gt;import&lt;/span&gt; &lt;span class='nn'&gt;Data.ByteString.Lazy.Char8&lt;/span&gt; &lt;span class='k'&gt;as&lt;/span&gt; &lt;span class='n'&gt;BL&lt;/span&gt; 
       &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kt'&gt;ByteString&lt;/span&gt;
       &lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='n'&gt;length&lt;/span&gt;
       &lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;take&lt;/span&gt;
       &lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;null&lt;/span&gt;
       &lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;splitAt&lt;/span&gt;
       &lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;group&lt;/span&gt;
       &lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;head&lt;/span&gt;
       &lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;pack&lt;/span&gt;
       &lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;readFile&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='kr'&gt;import&lt;/span&gt; &lt;span class='nn'&gt;Data.Sequence&lt;/span&gt; &lt;span class='k'&gt;as&lt;/span&gt; &lt;span class='n'&gt;S&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;lets us rewrite our &lt;code&gt;map&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='haskell'&gt;&lt;span class='nf'&gt;rleMap&lt;/span&gt; &lt;span class='ow'&gt;::&lt;/span&gt; &lt;span class='kt'&gt;BL&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='kt'&gt;ByteString&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='kt'&gt;Seq&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kt'&gt;Char&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='kt'&gt;Int&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='nf'&gt;rleMap&lt;/span&gt; &lt;span class='n'&gt;l&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;fromList&lt;/span&gt; &lt;span class='o'&gt;$&lt;/span&gt; &lt;span class='kt'&gt;P&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;zip&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;map&lt;/span&gt; &lt;span class='kt'&gt;BL&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;head&lt;/span&gt; &lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;map&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fromIntegral&lt;/span&gt; &lt;span class='o'&gt;.&lt;/span&gt; &lt;span class='kt'&gt;BL&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;length&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='n'&gt;c&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
       &lt;span class='kr'&gt;where&lt;/span&gt;
        &lt;span class='n'&gt;c&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='kt'&gt;BL&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;group&lt;/span&gt; &lt;span class='o'&gt;$&lt;/span&gt; &lt;span class='n'&gt;l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and &lt;code&gt;reduce&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='haskell'&gt;&lt;span class='nf'&gt;rleReduce&lt;/span&gt; &lt;span class='ow'&gt;::&lt;/span&gt; &lt;span class='kt'&gt;Seq&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kt'&gt;Char&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='kt'&gt;Int&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='kt'&gt;Seq&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kt'&gt;Char&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='kt'&gt;Int&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='kt'&gt;Seq&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kt'&gt;Char&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;&lt;span class='kt'&gt;Int&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='nf'&gt;rleReduce&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;rleReduce&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;viewr&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;viewl&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
             &lt;span class='kr'&gt;where&lt;/span&gt;
              &lt;span class='n'&gt;rleReduce&amp;#39;&lt;/span&gt; &lt;span class='kt'&gt;EmptyR&lt;/span&gt; &lt;span class='kt'&gt;EmptyL&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='kt'&gt;S&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;empty&lt;/span&gt;
              &lt;span class='n'&gt;rleReduce&amp;#39;&lt;/span&gt; &lt;span class='kt'&gt;EmptyR&lt;/span&gt; &lt;span class='kr'&gt;_&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;
              &lt;span class='n'&gt;rleReduce&amp;#39;&lt;/span&gt; &lt;span class='kr'&gt;_&lt;/span&gt; &lt;span class='kt'&gt;EmptyL&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt;
              &lt;span class='n'&gt;rleReduce&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;rs&lt;/span&gt; &lt;span class='kt'&gt;:&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;r&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;l&lt;/span&gt; &lt;span class='kt'&gt;:&amp;lt;&lt;/span&gt; &lt;span class='n'&gt;ls&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
                         &lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fst&lt;/span&gt; &lt;span class='n'&gt;r&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fst&lt;/span&gt; &lt;span class='n'&gt;l&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; 
                           &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;rs&lt;/span&gt; &lt;span class='o'&gt;|&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fst&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;r&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;&lt;span class='n'&gt;snd&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;r&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;snd&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;l&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt; &lt;span class='o'&gt;&amp;gt;&amp;lt;&lt;/span&gt; &lt;span class='n'&gt;ls&lt;/span&gt;
                         &lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;otherwise&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt; &lt;span class='o'&gt;&amp;gt;&amp;lt;&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Optionally, &lt;code&gt;Data.Sequence&lt;/code&gt; can be expressed with &lt;code&gt;ViewPatterns&lt;/code&gt;. Rewriting with these in mind allows the new &lt;code&gt;reduce&lt;/code&gt; to resemble the old one fairly closely:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='haskell'&gt;&lt;span class='cm'&gt;{-# LANGUAGE ViewPatterns #-}&lt;/span&gt;
&lt;span class='nf'&gt;rleReduce&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;viewr&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='kt'&gt;EmptyR&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;viewl&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='kt'&gt;EmptyL&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='kt'&gt;S&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;empty&lt;/span&gt;
&lt;span class='nf'&gt;rleReduce&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;viewr&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='kt'&gt;EmptyR&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;
&lt;span class='nf'&gt;rleReduce&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;viewl&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='kt'&gt;EmptyL&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt;
&lt;span class='nf'&gt;rleReduce&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt;&lt;span class='o'&gt;@&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;viewr&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;rs&lt;/span&gt; &lt;span class='kt'&gt;:&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;r&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;&lt;span class='o'&gt;@&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;viewl&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;l&lt;/span&gt; &lt;span class='kt'&gt;:&amp;lt;&lt;/span&gt; &lt;span class='n'&gt;ls&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
           &lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fst&lt;/span&gt; &lt;span class='n'&gt;r&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fst&lt;/span&gt; &lt;span class='n'&gt;l&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; 
             &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;rs&lt;/span&gt; &lt;span class='o'&gt;|&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;fst&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;r&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;&lt;span class='n'&gt;snd&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;r&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;snd&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;l&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt; &lt;span class='o'&gt;&amp;gt;&amp;lt;&lt;/span&gt; &lt;span class='n'&gt;ls&lt;/span&gt;
           &lt;span class='o'&gt;|&lt;/span&gt; &lt;span class='n'&gt;otherwise&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;a&lt;/span&gt; &lt;span class='o'&gt;&amp;gt;&amp;lt;&lt;/span&gt; &lt;span class='n'&gt;b&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we finally define a new &lt;code&gt;parallelRLE&lt;/code&gt;&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='haskell'&gt;&lt;span class='nf'&gt;parallelRLE&lt;/span&gt; &lt;span class='ow'&gt;::&lt;/span&gt; &lt;span class='kt'&gt;Int&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='kt'&gt;BL&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='kt'&gt;ByteString&lt;/span&gt; &lt;span class='ow'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='kt'&gt;Seq&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kt'&gt;Char&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='kt'&gt;Int&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='nf'&gt;parallelRLE&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt; &lt;span class='n'&gt;s&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='n'&gt;foldl&lt;/span&gt; &lt;span class='n'&gt;rleReduce&lt;/span&gt; &lt;span class='n'&gt;empty&lt;/span&gt; &lt;span class='o'&gt;$&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;parMap&lt;/span&gt; &lt;span class='n'&gt;rseq&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='n'&gt;rleMap&lt;/span&gt; &lt;span class='o'&gt;$&lt;/span&gt; &lt;span class='n'&gt;chunkn&lt;/span&gt; &lt;span class='n'&gt;n&lt;/span&gt; &lt;span class='n'&gt;s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;and wrap it all up in a &lt;code&gt;IO&lt;/code&gt; monad&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='haskell'&gt;&lt;span class='nf'&gt;main&lt;/span&gt; &lt;span class='ow'&gt;::&lt;/span&gt; &lt;span class='kt'&gt;IO&lt;/span&gt;&lt;span class='nb'&gt;()&lt;/span&gt;
&lt;span class='nf'&gt;main&lt;/span&gt; &lt;span class='ow'&gt;=&lt;/span&gt; &lt;span class='kr'&gt;do&lt;/span&gt;
     &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='n'&gt;fileName&lt;/span&gt;&lt;span class='p'&gt;]&lt;/span&gt; &lt;span class='ow'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='n'&gt;getArgs&lt;/span&gt;
     &lt;span class='n'&gt;s&lt;/span&gt; &lt;span class='ow'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kt'&gt;BL&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;readFile&lt;/span&gt; &lt;span class='n'&gt;fileName&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
     &lt;span class='n'&gt;print&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;parallelRLE&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;numCapabilities&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='n'&gt;s&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With an improved algorithm and &lt;code&gt;IO&lt;/code&gt; wrapper, it&amp;#8217;s time for a more complete benchmark:&lt;/p&gt;

&lt;p&gt;&lt;a href='/img/posts/beating-interview-problems-to-death-with-parallel-haskell/prle-plot.png'&gt;&lt;img src='/img/posts/beating-interview-problems-to-death-with-parallel-haskell/prle-plot.jpg' height='400' alt='Performance Plot' width='600' /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This was run on a &lt;code&gt;0.5GB&lt;/code&gt; file, as the smaller &lt;code&gt;12MB&lt;/code&gt; file used above runs so fast that is essentially instant. Between 2 and 5 processors, we get a nicely ramped speedup. After 5 processors, the bookkeeping overhead rears its ugly head again reversing the trend, and around 48 processors (my system maximum), the parallelization ends up running as slowly as the unparallelized version. This is certainly not the end of possible optimizations, but we have to stop sometime.&lt;/p&gt;

&lt;p&gt;While I&amp;#8217;m no &lt;code&gt;Haskell&lt;/code&gt; expert, parallelization which costs no more than swapping in a &lt;code&gt;parMap&lt;/code&gt; and paying homage to the Big O gods is a very compelling reason to hammer out any other toy interview questions with &lt;code&gt;Haskell&lt;/code&gt; in the future.&lt;/p&gt;

&lt;p&gt;Get the code &lt;a href='https://github.com/malloc47/snippets/tree/master/prle'&gt;here&lt;/a&gt;. Feedback welcome.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Google Completion in Emacs</title>
      <link>http://malloc47.com/google-completion-in-emacs/</link>
      <pubDate>Sat, 19 May 2012 00:00:00 -0700</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/google-completion-in-emacs</guid>
      <description>&lt;p&gt;While many an &lt;code&gt;emacs&lt;/code&gt; include &lt;code&gt;dabbrev-expand&lt;/code&gt; for within-buffer completion, I&amp;#8217;ve always wanted (purely for reasons of amusement) to take it further: completion via Google&amp;#8217;s search suggestions. I was going to do this as a weekend project, but an ugly version was surprisingly simple.&lt;/p&gt;

&lt;p&gt;Conveniently, &lt;code&gt;curl&lt;/code&gt; is all we need to fetch the completions for a query string as &lt;code&gt;JSON&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&amp;gt; &lt;span class='nb'&gt;echo&lt;/span&gt; -en &lt;span class='k'&gt;$(&lt;/span&gt;curl -H &lt;span class='s2'&gt;&amp;quot;Accept: application/json&amp;quot;&lt;/span&gt; &lt;span class='se'&gt;\&lt;/span&gt;
  &lt;span class='s2'&gt;&amp;quot;http://suggestqueries.google.com/complete/search?client=firefox&amp;amp;q=query&amp;quot;&lt;/span&gt;&lt;span class='k'&gt;)&lt;/span&gt;

&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;query&amp;quot;&lt;/span&gt;,&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;query&amp;quot;&lt;/span&gt;,&lt;span class='s2'&gt;&amp;quot;query xiv&amp;quot;&lt;/span&gt;,&lt;span class='s2'&gt;&amp;quot;query letter&amp;quot;&lt;/span&gt;,&lt;span class='s2'&gt;&amp;quot;query_posts&amp;quot;&lt;/span&gt;,&lt;span class='s2'&gt;&amp;quot;query shark&amp;quot;&lt;/span&gt;,&lt;span class='s2'&gt;&amp;quot;query access&amp;quot;&lt;/span&gt;,&lt;span class='s2'&gt;&amp;quot;query tracker&amp;quot;&lt;/span&gt;,&lt;span class='s2'&gt;&amp;quot;query string&amp;quot;&lt;/span&gt;,&lt;span class='s2'&gt;&amp;quot;query letter sample&amp;quot;&lt;/span&gt;,&lt;span class='s2'&gt;&amp;quot;queryperformancecounter&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;]]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;using a (very platform dependent) &lt;code&gt;echo&lt;/code&gt; trick to convert the escaped unicode sequences to their proper characters.&lt;/p&gt;

&lt;p&gt;With this, a quick hack in &lt;code&gt;elisp&lt;/code&gt; is all that&amp;#8217;s necessary to parse the results into &lt;code&gt;emacs&lt;/code&gt; and insert it into the current buffer:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='cl'&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;defun&lt;/span&gt; &lt;span class='nv'&gt;google-request&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;query&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
 &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;shell-command-to-string&lt;/span&gt; 
  &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;format&lt;/span&gt;
   &lt;span class='s'&gt;&amp;quot;echo -en $(curl -H \&amp;quot;Accept: application/json\&amp;quot; \&amp;quot;http://suggestqueries.google.com/complete/search?client=firefox&amp;amp;q=%s\&amp;quot; 2&amp;gt;/dev/null)&amp;quot;&lt;/span&gt;
   &lt;span class='nv'&gt;query&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;

&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;defun&lt;/span&gt; &lt;span class='nv'&gt;google-preprocess&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;query&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
 &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;let&lt;/span&gt; &lt;span class='p'&gt;((&lt;/span&gt;&lt;span class='nv'&gt;l&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;split-string&lt;/span&gt; 
	   &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;apply&lt;/span&gt; &lt;span class='ss'&gt;&amp;#39;string&lt;/span&gt; 
		  &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;removel&lt;/span&gt; 
		   &lt;span class='o'&gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;?\&amp;quot;&lt;/span&gt; &lt;span class='nv'&gt;?\[&lt;/span&gt; &lt;span class='nv'&gt;?\]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
		   &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;string-to-list&lt;/span&gt; &lt;span class='nv'&gt;query&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;
	   &lt;span class='s'&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;
  &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;length&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;car&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;cdr&lt;/span&gt; &lt;span class='nv'&gt;l&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;remove&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;car&lt;/span&gt; &lt;span class='nv'&gt;l&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;cdr&lt;/span&gt; &lt;span class='nv'&gt;l&lt;/span&gt;&lt;span class='p'&gt;))&lt;/span&gt;
   &lt;span class='no'&gt;nil&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;
   
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;defun&lt;/span&gt; &lt;span class='nv'&gt;google-complete&lt;/span&gt; &lt;span class='p'&gt;()&lt;/span&gt;
 &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;interactive&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
 &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;end-of-thing&lt;/span&gt; &lt;span class='ss'&gt;&amp;#39;word&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
 &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;let&lt;/span&gt; &lt;span class='p'&gt;((&lt;/span&gt;&lt;span class='nv'&gt;s&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;thing-at-point&lt;/span&gt; &lt;span class='ss'&gt;&amp;#39;word&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;
  &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;when&lt;/span&gt; &lt;span class='nv'&gt;s&lt;/span&gt;
   &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='k'&gt;let&lt;/span&gt; &lt;span class='p'&gt;((&lt;/span&gt;&lt;span class='nv'&gt;q&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;google-preprocess&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;google-request&lt;/span&gt; &lt;span class='nv'&gt;s&lt;/span&gt;&lt;span class='p'&gt;))))&lt;/span&gt;
    &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;when&lt;/span&gt; &lt;span class='nv'&gt;q&lt;/span&gt;
     &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;insert&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;substring&lt;/span&gt;
	       &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;car&lt;/span&gt; &lt;span class='nv'&gt;q&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
	       &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;length&lt;/span&gt; &lt;span class='nv'&gt;s&lt;/span&gt;&lt;span class='p'&gt;))))))))&lt;/span&gt;
		   
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;defun&lt;/span&gt; &lt;span class='nv'&gt;removel&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;el&lt;/span&gt; &lt;span class='nv'&gt;l&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
 &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;cond&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;el&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nv'&gt;removel&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;cdr&lt;/span&gt; &lt;span class='nv'&gt;el&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;remove&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;car&lt;/span&gt; &lt;span class='nv'&gt;el&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='nv'&gt;l&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;
       &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='no'&gt;t&lt;/span&gt; &lt;span class='nv'&gt;l&lt;/span&gt;&lt;span class='p'&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since it went more swiftly than anticipated, I generalized the code to parsing any delimited shell output and wrapped it in a minor mode with some key bindings and &lt;code&gt;customize&lt;/code&gt; variables. Right now, I&amp;#8217;m uncreatively calling it &lt;a href='https://github.com/malloc47/shell-parse.el/blob/master/shell-parse.el'&gt;&lt;code&gt;shell-parse.el&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After activating &lt;code&gt;shell-parse-mode&lt;/code&gt;, it has support for scrolling through the list of completions forwards (&lt;code&gt;shell-parse-complete&lt;/code&gt;) and backwards (&lt;code&gt;shell-parse-complete-backwards&lt;/code&gt;) with the &lt;code&gt;C-Tab&lt;/code&gt; and &lt;code&gt;C-Shift-Tab&lt;/code&gt; keys, respectively. Using &lt;code&gt;M-x customize-mode &amp;lt;Enter&amp;gt;
shell-parse-mode&lt;/code&gt;, you can swap out the &lt;code&gt;curl&lt;/code&gt; command with any shell snippet that will kick back completions, and change the delimiter as well.&lt;/p&gt;

&lt;p&gt;You can grab &lt;code&gt;shell-parse.el&lt;/code&gt; on &lt;a href='https://github.com/malloc47/shell-parse.el'&gt;github&lt;/a&gt;. Simply &lt;code&gt;load-file&lt;/code&gt; the &lt;code&gt;shell-parse.el&lt;/code&gt; script in &lt;code&gt;.emacs&lt;/code&gt; and it should be ready to go.&lt;/p&gt;

&lt;p&gt;It has a few todos scattered through it yet, and is not very idiomatic &lt;code&gt;emacs&lt;/code&gt; or portable, but that&amp;#8217;s what github&amp;#8217;s &lt;a href='https://github.com/malloc47/shell-parse.el/issues'&gt;issue tracker&lt;/a&gt; is for, after all.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Preprocessors and Graphviz</title>
      <link>http://malloc47.com/preprocessors-and-graphviz/</link>
      <pubDate>Sat, 07 Apr 2012 00:00:00 -0700</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/preprocessors-and-graphviz</guid>
      <description>&lt;p&gt;&lt;code&gt;Graphviz&lt;/code&gt; is a useful toolset for describing and rendering graphs. One of the features the graphviz language doesn&amp;#8217;t have, however, is a &lt;code&gt;C&lt;/code&gt;-like preprocessor to &lt;code&gt;#include&lt;/code&gt; files. Which, granted, isn&amp;#8217;t a particularly common use case when building graphs, but one I found desirable when dealing with a large number of graphs with a shared subset of nodes, differing by how they are connected.&lt;/p&gt;

&lt;p&gt;Initially, I grafted together an unwieldy &lt;a href='https://gist.github.com/2324425'&gt;script&lt;/a&gt; that used an ugly &lt;code&gt;grep&lt;/code&gt;+&lt;code&gt;sed&lt;/code&gt; combination to grab the line number and substitute the included file contents: essentially a poor man&amp;#8217;s preprocessor. Thankfully, to the rescue was a particularly useful &lt;a href='https://gist.github.com/2037497'&gt;gist&lt;/a&gt; (initially illustrated with JavaScript) I serendipitously found on &lt;a href='http://www.reddit.com/r/programming/comments/qxn73/mixing_javascript_and_the_cpreprocessor/'&gt;Reddit&lt;/a&gt;. The key call being this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cpp -P -undef -Wundef -std=c99 -nostdinc -Wtrigraphs \
    -fdollars-in-identifiers -C &amp;lt; input.dot &amp;gt; output.dot&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In your input &lt;code&gt;.dot&lt;/code&gt; file, standard &lt;code&gt;C&lt;/code&gt; include syntax&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='c'&gt;&lt;span class='cp'&gt;#include &amp;quot;common.doth&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;will work as expected, despite the fact that it is a completely different language.&lt;/p&gt;

&lt;p&gt;This solution is highly verbose if you don&amp;#8217;t drop it in a build chain and forget about it. Which is straightforward using a standard &lt;a href='https://github.com/open-it-lab/ol-curriculum/blob/master/makefile'&gt;makefile&lt;/a&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='make'&gt;&lt;span class='nv'&gt;SOURCES&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;$(&lt;/span&gt;wildcard *.dot&lt;span class='k'&gt;)&lt;/span&gt;
&lt;span class='nv'&gt;OBJECTS&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;$(&lt;/span&gt;SOURCES:.dot&lt;span class='o'&gt;=&lt;/span&gt;.doto&lt;span class='k'&gt;)&lt;/span&gt;
&lt;span class='nv'&gt;IMAGES&lt;/span&gt;  &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;$(&lt;/span&gt;SOURCES:.dot&lt;span class='o'&gt;=&lt;/span&gt;.png&lt;span class='k'&gt;)&lt;/span&gt;

&lt;span class='nf'&gt;all&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='m'&gt;$(IMAGES)&lt;/span&gt;

&lt;span class='nf'&gt;%.png&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='m'&gt;%.doto&lt;/span&gt;
	dot -Tpng &lt;span class='nv'&gt;$&amp;lt;&lt;/span&gt; &amp;gt; &lt;span class='nv'&gt;$@&lt;/span&gt;

&lt;span class='nf'&gt;%.doto&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='m'&gt;%.dot&lt;/span&gt;
	cpp -P -undef -Wundef -std&lt;span class='o'&gt;=&lt;/span&gt;c99 -nostdinc -Wtrigraphs &lt;span class='se'&gt;\&lt;/span&gt;
		-fdollars-in-identifiers -C &amp;lt; &lt;span class='nv'&gt;$&amp;lt;&lt;/span&gt; | &lt;span class='se'&gt;\&lt;/span&gt;
		gvpr -c &lt;span class='s1'&gt;&amp;#39;N[$$.degree==0]{delete(NULL,$$)}&amp;#39;&lt;/span&gt; &amp;gt; &lt;span class='nv'&gt;$@&lt;/span&gt;

&lt;span class='nf'&gt;clean&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt;
	-rm &lt;span class='k'&gt;$(&lt;/span&gt;IMAGES&lt;span class='k'&gt;)&lt;/span&gt; &lt;span class='k'&gt;$(&lt;/span&gt;OBJECTS&lt;span class='k'&gt;)&lt;/span&gt; *~
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the above example, I introduced an intermediate &lt;code&gt;doto&lt;/code&gt; file (analogous to an object file) and &lt;code&gt;doth&lt;/code&gt; (header file) to recreate a &lt;code&gt;C&lt;/code&gt;-like build process.&lt;/p&gt;

&lt;p&gt;Another ingredient above is the piped invocation of &lt;code&gt;gvpr&lt;/code&gt;, which removes nodes of degree 1 (so that included nodes that are not attached to anything in the current file will be ignored). Remember that in &lt;code&gt;makefiles&lt;/code&gt;, the &lt;code&gt;$&lt;/code&gt; must be escaped by using &lt;code&gt;$$&lt;/code&gt;. Unfortunately, the &lt;code&gt;delete&lt;/code&gt; function in &lt;code&gt;gvpr&lt;/code&gt; is &lt;a href='http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=652952'&gt;broken&lt;/a&gt; in a number of Debian-based distros (at least), but the latest version works bug-free in Arch.&lt;/p&gt;

&lt;p&gt;So, given a &lt;code&gt;nodes.doth&lt;/code&gt; file with these contents:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    node1 [label = &amp;quot;1&amp;quot;];
    node2 [label = &amp;quot;2&amp;quot;];
    node3 [label = &amp;quot;3&amp;quot;];&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and a &lt;code&gt;graph.dot&lt;/code&gt; file as such:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;graph g {
    #include &amp;quot;nodes.doth&amp;quot;

    node1 -- node2;
    node2 -- node3;
    node3 -- node1;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;the &lt;code&gt;makefile&lt;/code&gt; will use &lt;code&gt;cpp&lt;/code&gt; to generate the following intermediate file,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;graph g {
    node1 [label = &amp;quot;1&amp;quot;];
    node2 [label = &amp;quot;2&amp;quot;];
    node3 [label = &amp;quot;3&amp;quot;];
    node1 -- node2;
    node2 -- node3;
    node3 -- node1;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which will then be compiled by graphviz&amp;#8217;s &lt;code&gt;dot&lt;/code&gt; command into an image. While obviously not necessary with this toy example, scaling up to more nodes shared by multiple graphs is much more pleasant when the nodes don&amp;#8217;t have to be duplicated in each graph.&lt;/p&gt;

&lt;p&gt;Very little of this is exclusive to graphviz, and is reasonable to extrapolate to other problems fairly easily. And, since this literally uses the &lt;code&gt;C&lt;/code&gt; preprocessor to do the job, there&amp;#8217;s many more tricks to be explored.&lt;/p&gt;

&lt;p&gt;Quite helpful to have on hand when the need arises, and a testament to the quality of &lt;code&gt;cpp&lt;/code&gt; that it can be used for arbitrary metaprogramming in other languages.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>QR Codes En Masse</title>
      <link>http://malloc47.com/qr-codes-en-masse/</link>
      <pubDate>Sat, 24 Mar 2012 23:00:00 -0700</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/qr-codes-en-masse</guid>
      <description>&lt;p&gt;For the upcoming &lt;a href='http://www.posscon.org/'&gt;POSSCON&lt;/a&gt; here in Columbia, we had need of QR codes for the brochure. Lots of them. And while there are &lt;a href='http://qrcode.kaywa.com/'&gt;some&lt;/a&gt; &lt;a href='http://goqr.me/'&gt;great&lt;/a&gt; &lt;a href='http://www.patrick-wied.at/static/qrgen/'&gt;online&lt;/a&gt; &lt;a href='http://www.onlineqrlab.com/'&gt;resources&lt;/a&gt;, I wanted to create QR codes in batch.&lt;/p&gt;

&lt;p&gt;Of course, the online services could be batch processed with a dose of &lt;code&gt;curl&lt;/code&gt; magic, but there is a more UNIX way: &lt;code&gt;libqrencode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Creating a discrete QR code image is straightforward with the &lt;code&gt;qrencode&lt;/code&gt; command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;qrencode -o output.png -s 50 &amp;quot;http://www.malloc47.com&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;-s&lt;/code&gt; parameter controls the size of the QR &amp;#8220;dots&amp;#8221; and therefore the output resolution.&lt;/p&gt;

&lt;p&gt;This is great if you don&amp;#8217;t need a vectorized format, but for print-quality work where you may not know the eventual &lt;code&gt;DPI&lt;/code&gt;, having vectorized output (e.g. &lt;code&gt;eps&lt;/code&gt;, and &lt;code&gt;svg&lt;/code&gt;) is preferable.&lt;/p&gt;

&lt;p&gt;Again, the vast repositories of libre software come to the rescue here: &lt;code&gt;potrace&lt;/code&gt; is designed for exactly this. Annoyingly, it only handles bitmap (or the easy-to-generate &lt;a href='http://en.wikipedia.org/wiki/Netpbm_format'&gt;pnm&lt;/a&gt;) format, so a little &lt;code&gt;imagemagick&lt;/code&gt; will take care of this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;convert output.png output.bmp&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we can convert to a vector format easily:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;potrace -e -o output.eps output.bmp # -e is for EPS
potrace -s -o output.svg output.bmp # -s is for SVG&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can wrap it all up into a nice (&lt;code&gt;bash&lt;/code&gt;) script:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='c'&gt;#!/bin/bash&lt;/span&gt;
&lt;span class='nb'&gt;set&lt;/span&gt; -e
qrencode -o &lt;span class='nv'&gt;$1&lt;/span&gt;.png -s 50 &lt;span class='s2'&gt;&amp;quot;$2&amp;quot;&lt;/span&gt;
convert &lt;span class='nv'&gt;$1&lt;/span&gt;.png &lt;span class='nv'&gt;$1&lt;/span&gt;.bmp
potrace -e -o &lt;span class='nv'&gt;$1&lt;/span&gt;.eps &lt;span class='nv'&gt;$1&lt;/span&gt;.bmp
rm &lt;span class='nv'&gt;$1&lt;/span&gt;.png &lt;span class='nv'&gt;$1&lt;/span&gt;.bmp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which takes a file name prefix and a string to be encoded. To generate a large set of QR codes with this script, simply create a file with file prefix-&lt;code&gt;URL&lt;/code&gt;(or whatever data is to be encoded) pairs, each on a separate line,&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;google http://www.google.com
amazon http://www.amazon.com
reddit http://www.reddit.com
....&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and then loop over this file, line-by-line:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='k'&gt;while &lt;/span&gt;&lt;span class='nb'&gt;read &lt;/span&gt;line ; &lt;span class='k'&gt;do&lt;/span&gt; ./create-qr-code.sh &lt;span class='nv'&gt;$line&lt;/span&gt; ; &lt;span class='k'&gt;done&lt;/span&gt; &amp;lt; list.text
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;which conveniently gives us &lt;code&gt;google.eps&lt;/code&gt;, &lt;code&gt;amazon.eps&lt;/code&gt;, and &lt;code&gt;reddit.eps&lt;/code&gt; files for their respective &lt;code&gt;URL&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;If there is uncertainty that your &lt;code&gt;URL&lt;/code&gt;s are good (i.e. don&amp;#8217;t kick back &lt;code&gt;404&lt;/code&gt;s), then you can augment the above script with this nice &lt;code&gt;curl&lt;/code&gt; snippet (courtesy of &lt;a href='http://stackoverflow.com/questions/2924422/how-do-i-determine-if-a-web-page-exists-with-shell-scripting'&gt;this&lt;/a&gt; post on SO):&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='c'&gt;#!/bin/bash&lt;/span&gt;
&lt;span class='nb'&gt;set&lt;/span&gt; -e
curl -s --head &lt;span class='nv'&gt;$2&lt;/span&gt; | head -n 1 | grep &lt;span class='s2'&gt;&amp;quot;HTTP/1.[01] [23]..&amp;quot;&lt;/span&gt; &amp;gt; /dev/null
&lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt; &lt;span class='nv'&gt;$?&lt;/span&gt; -eq 0 &lt;span class='o'&gt;]&lt;/span&gt; ; &lt;span class='k'&gt;then&lt;/span&gt;
&lt;span class='k'&gt;    &lt;/span&gt;qrencode -o &lt;span class='nv'&gt;$1&lt;/span&gt;.png -s 50 &lt;span class='s2'&gt;&amp;quot;$2&amp;quot;&lt;/span&gt;
    convert &lt;span class='nv'&gt;$1&lt;/span&gt;.png &lt;span class='nv'&gt;$1&lt;/span&gt;.bmp
    potrace -e -o &lt;span class='nv'&gt;$1&lt;/span&gt;.eps &lt;span class='nv'&gt;$1&lt;/span&gt;.bmp
    rm &lt;span class='nv'&gt;$1&lt;/span&gt;.png &lt;span class='nv'&gt;$1&lt;/span&gt;.bmp
&lt;span class='k'&gt;else&lt;/span&gt;
&lt;span class='k'&gt;    &lt;/span&gt;&lt;span class='nb'&gt;echo&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;URL error: $2&amp;quot;&lt;/span&gt; 1&amp;gt;&amp;amp;2
&lt;span class='k'&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will let you know which &lt;code&gt;URL&lt;/code&gt;s don&amp;#8217;t come back with clean headers so you can give them further attention. It won&amp;#8217;t capture everything that might go wrong, but it does give you a programmatic way to verify that all is well.&lt;/p&gt;

&lt;p&gt;Incidentally, all the tools used here can be installed on Arch with&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;pacman -S qrencode potrace imagemagick curl&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Not exactly the prettiest shell glue, but it certainly beats slowly copy &amp;#38; pasting in and out of a browser.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Flirting with the Front End</title>
      <link>http://malloc47.com/flirting-with-the-front-end/</link>
      <pubDate>Tue, 20 Mar 2012 00:00:00 -0700</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/flirting-with-the-front-end</guid>
      <description>&lt;p&gt;Every few years, when I&amp;#8217;m not teaching introductory web programming, I revisit front end development, oftentimes in the form of retooling my site. Last time, it was a Wordpress-driven theme with cobbled-together JavaScript snippets for random bits of functionality:&lt;/p&gt;

&lt;p&gt;&lt;a href='/img/posts/flirting-with-the-front-end/old-site.png'&gt;&lt;img src='/img/posts/flirting-with-the-front-end/thumb/old-site.jpg' height='183' alt='Old Site' width='280' /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Serviceable, at least.&lt;/p&gt;

&lt;p&gt;Before this, I used a generic Wordpress theme, the specifics of which I don&amp;#8217;t recall. Rolling back all the way to the mid-90s, I had a &lt;a href='http://www.fortunecity.com'&gt;fortunecity&lt;/a&gt; site, which was&amp;#8211;as typical of sites in the 90s&amp;#8211;equal parts bland and garish:&lt;/p&gt;

&lt;p&gt;&lt;a href='/img/posts/flirting-with-the-front-end/older-site.png'&gt;&lt;img src='/img/posts/flirting-with-the-front-end/thumb/older-site.jpg' height='210' alt='Old Site' width='280' /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, it had a Christmas theme for the title page. And yes, the header, navigation bar, and footer (on individual pages) are all java applets. Not exactly, a usability panacea.&lt;/p&gt;

&lt;p&gt;And now, I&amp;#8217;ve transitioned to &lt;a href='https://github.com/mojombo/jekyll'&gt;Jekyll&lt;/a&gt;, for a few reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It&amp;#8217;s hard to get faster than static pages for serving content.&lt;/li&gt;

&lt;li&gt;&lt;a href='https://github.com/'&gt;Github&lt;/a&gt; can handle more traffic than the shared hosting I was using previously.&lt;/li&gt;

&lt;li&gt;A Jekyll deploy on github can&amp;#8217;t use external plugins. Which is, by most accounts, a downside, but it forces me to find front-end solutions for what I want rather than turning to the back end for everything.&lt;/li&gt;

&lt;li&gt;I wanted to build everything from scratch. The limited &lt;a href='http://liquidmarkup.org/'&gt;Liquid&lt;/a&gt; DSL used by Jekyll is leaner than full-blown &lt;code&gt;PHP&lt;/code&gt;, and more satisfying for building from the ground-up (all my Wordpress themes started from&amp;#8211;at minimum&amp;#8211;a skeleton theme, just to cover the essentials needed by Wordpress).&lt;/li&gt;

&lt;li&gt;Having everything in a git repo is both satisfying for my current work flow and avoids the pain of database backups.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So &lt;a href='https://github.com/malloc47/malloc47.github.com'&gt;here&lt;/a&gt; it is. I avoided &lt;code&gt;jQuery&lt;/code&gt; (convenient as it is) to keep things lean and loading quickly, and rampantly bludgeoned the site with &lt;code&gt;HTML5/CSS3&lt;/code&gt; without much regard for backwards compatibility. To further optimize queries, I used Liquid &lt;code&gt;include&lt;/code&gt;s to aggregate all the &lt;code&gt;js&lt;/code&gt; and &lt;code&gt;css&lt;/code&gt; into single files. For &lt;code&gt;JavaScript&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='o'&gt;---&lt;/span&gt;
&lt;span class='o'&gt;---&lt;/span&gt;
&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='p'&gt;()&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;use strict&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='nx'&gt;include&lt;/span&gt; &lt;span class='nx'&gt;cookies&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;js&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='nx'&gt;include&lt;/span&gt; &lt;span class='nx'&gt;mini&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='nx'&gt;clock&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;js&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='nx'&gt;include&lt;/span&gt; &lt;span class='nx'&gt;check&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='nx'&gt;time&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;js&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;{&lt;/span&gt;&lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='nx'&gt;include&lt;/span&gt; &lt;span class='nx'&gt;event&lt;/span&gt;&lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='nx'&gt;handler&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;js&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt;&lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='p'&gt;}());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;you can wrap everything with &lt;code&gt;&amp;quot;use strict&amp;quot;&lt;/code&gt; to get some extra exception goodness. Doing this may cause &lt;a href='http://www.jslint.com/'&gt;JSLint&lt;/a&gt; to complain about indentation issues, and if you don&amp;#8217;t add event handlers with JavaScript (e.g. you use the &lt;code&gt;onclick&lt;/code&gt; or &lt;code&gt;onload&lt;/code&gt; events in your &lt;code&gt;HTML&lt;/code&gt; tags), you may run into scope issues as well. All of this together provided a nearly 20-point speed bump on &lt;a href='https://developers.google.com/pagespeed/'&gt;Google page speed&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I opted for a dual-themed site, determined by the time of day. The clock drawn in the HTML5 Canvas element in the upper-left shows when the transition will occur, or you can override it with the icon next to the clock.&lt;/p&gt;

&lt;p&gt;All in all, a good transition so far.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Jedi Knight: Dark Forces II -- A coding retrospective</title>
      <link>http://malloc47.com/blog/jedi-knight-dark-forces-ii-a-coding-retrospective/</link>
      <pubDate>Tue, 28 Feb 2012 00:00:00 -0800</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/blog/jedi-knight-dark-forces-ii-a-coding-retrospective</guid>
      <description>&lt;p&gt;Years ago, before I got my hands on a real compiler, I satisfied my coding compulsion by modding &lt;em&gt;Jedi Knight: Dark Forces II&lt;/em&gt; (which, yes, has the subtitle backwards from normal). As detailed &lt;a href='http://www.gamasutra.com/view/feature/3233/adding_languages_to_game_engines.php'&gt;elsewhere&lt;/a&gt;, Jedi Knight (abbreviated JK) is one of the earlier examples of a game that used a simple scripting language to handle interaction with the game engine. COG script, as it was called was, in hindsight, designed as much to be easy to compile as it was to write. Of course, the attractive thing to any 13-year-old who desperately wants to code in a &amp;#8220;real&amp;#8221; language was COG&amp;#8217;s (superficial) similarity to C.&lt;/p&gt;

&lt;p&gt;The structure of a COG script is straightforward: it starts with a &lt;em&gt;symbols&lt;/em&gt; section, where all variables are declared, followed by a &lt;em&gt;code&lt;/em&gt; section broken into various messages (denoted by goto-like labels, which must be declared as variables in the symbol section to be valid) that represent events that could be triggered in-game. Aside from the usual expressions and flow control, there are library functions that form an elementary API for the game engine itself. Variables are typed, and have one of two scopes. The &amp;#8220;local&amp;#8221; variables are bound within the scope of the script itself. All non-local variables must be bound to external entities in the game environment&amp;#8211;think of them as free parameters that must be specified outside the script. Variable types include a few atomic types (e.g., int, flex) and some game-specific entities (e.g., things, surfaces), and event types (e.g., messages). Have a look:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;symbols

surface downsect
message activated
thing ghosttel1
thing ghosttel2
thing player local
surface upsuf1
end

code

activated:
if (GetSenderRef() == upsuf1)
{
    player = GetLocalPlayerThing();
    TeleportThing(player, ghosttel1);
    return;
}

if (GetSenderRef() == downsect)
{
    player = GetLocalPlayerThing();
    TeleportThing(player, ghosttel2);
    return;
}
return;

end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The above code works as you would expect&amp;#8211;it simulates a &amp;#8220;ladder&amp;#8221; by simply teleporting the player to the top of the ladder if they &amp;#8220;activate&amp;#8221; (by pressing the spacebar while standing near) a surface at the bottom, or teleports them back down if they activate the ladder surface at the top.&lt;/p&gt;

&lt;p&gt;With no reference whatsoever&amp;#8211;beyond the COGs included with the game itself&amp;#8211;it took me a while to get used to writing COG. But given that it had one of the more fun compilers around (though billed as a scripting language, COG was actually compiled to a stack-based language at load-time), I had little trouble finding motivation to toy with it.&lt;/p&gt;

&lt;p&gt;Aside from COG, JK had a variety of other specialized file types that could be (relatively) easily created or modified: .&lt;em&gt;3do&lt;/em&gt; for 3D models, .&lt;em&gt;mat&lt;/em&gt; and &lt;em&gt;.bm&lt;/em&gt; for images (bitmaps, essentially), &lt;em&gt;.jk&lt;/em&gt; for level meta information, &lt;em&gt;.pup&lt;/em&gt; (puppet) files that link keyframed animations to specific pose states for a character, &lt;em&gt;.key&lt;/em&gt; files which are the keyframed animations for the characters, &lt;em&gt;.snd&lt;/em&gt; files that link sound to a character, &lt;em&gt;.ai&lt;/em&gt; files that expose variables for how the characters react (simple artificial intelligence), &lt;em&gt;.gob&lt;/em&gt; files which are essentially .zip files for storing all the various resources in a level, and many many more file types I&amp;#8217;m probably forgetting.&lt;/p&gt;

&lt;p&gt;But it was always the COGs that were most interesting to me, despite the fact that I wrote some ugly and embarrassing code in it. &lt;a href='https://raw.github.com/malloc47/return-of-thrawn/master/thrawn/cog/forcefield_goal.co'&gt;Really embarrassing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And I won&amp;#8217;t even get started on my very unrefined sense of aesthetic design in the level I ended up building. Yes, I built an entire level, mainly to facilitate being able to write fun little scripts in COG. Which is not nearly as involved as it sounds thanks to &lt;a href='http://starwars.wikia.com/wiki/JED'&gt;JED&lt;/a&gt;, a community-supported level editor. I built a very basic plotline with a number of cutscenes (9, I claim in the &lt;a href='https://raw.github.com/malloc47/return-of-thrawn/master/thrawn/readme.txt'&gt;readme&lt;/a&gt;); a weapon mod that added a phaser to your arsenal (you know, the Star Trek sort&amp;#8211;I never claimed any of this made sense except to my 13-year-old self); two new types of enemies, as I never thought the original lineup was difficult enough; a few secret areas, including one with a rather famous character; a zoo (again, never said anything about making sense); a few RPG-style quests; and committed some very horrible texture misuse, a fact that the contemporary &lt;a href='http://tacc.massassi.net/levels/review.php?id=41'&gt;reviews&lt;/a&gt; will back up.&lt;/p&gt;

&lt;p&gt;I did learn some rather important software engineering lessons along the way. I recently ran across my issue-tracking system: a notepad with 50+ pages of bugs and fixes that I did on the level for the year or so it was in development. Everything from enemies falling through floors, cutscenes being mistimed, and impossible-to-win scenarios, were among the issues I recorded. I simply couldn&amp;#8217;t keep track of the number of issues I would notice on every playthrough without writing them down.&lt;/p&gt;

&lt;p&gt;On my nostalgic adventure, I decided to actually get Jedi Knight up and running again. I think my PC was perfectly adequate to run the game, according to its own system requirements analyzer:&lt;/p&gt;
&lt;div class='centered'&gt;

&lt;a href='/img/posts/jk/jk-analyzer.png'&gt;&lt;img src='/img/posts/jk/thumb/jk-analyzer.jpg' height='242' alt='Analyzer' width='280' /&gt;&lt;/a&gt;
&lt;p&gt;Though it was incorrect about the &quot;Windows 95&quot; part.&lt;/p&gt;

&lt;/div&gt;
&lt;p&gt;Thankfully, a kind soul rewrote the 16-bit installer (&lt;a href='http://code.google.com/p/starwarsjediknightaltinstall/'&gt;here&lt;/a&gt;) so, if you happen to have the Jedi Knight CDs on hand, you can actually install it on a 64-bit Windows (virtual) machine.&lt;/p&gt;
&lt;div class='centered'&gt;

&lt;a href='/img/posts/jk/jk-screenshot.png'&gt;&lt;img src='/img/posts/jk/thumb/jk-screenshot.jpg' height='132' alt='Cinematic Screenshot' width='280' /&gt;&lt;/a&gt;
&lt;p&gt;Ah, nostalgia.&lt;/p&gt;

&lt;/div&gt;
&lt;p&gt;Getting any new level up and running is typically as simple as placing the .gob file in the EPISODES folder. So, of course, I loaded up my old creation. I definitely had a lot of fun as a kid.&lt;/p&gt;
&lt;div class='columns'&gt;

&lt;a href='/img/posts/jk/002.png'&gt;&lt;img src='/img/posts/jk/thumb/002.jpg' height='175' alt='Screenshot 1' width='280' /&gt;&lt;/a&gt;
&lt;p&gt;Completely forgot about the in-game menu system (so you could bypass
the rather dry &quot;Story&quot; cutscene I included, among other things).&lt;/p&gt;

&lt;a href='/img/posts/jk/007.png'&gt;&lt;img src='/img/posts/jk/thumb/007.jpg' height='175' alt='Screenshot 2' width='280' /&gt;&lt;/a&gt;
&lt;p&gt;A planetarium. On a star destroyer, for some reason.&lt;/p&gt;

&lt;a href='/img/posts/jk/008.png'&gt;&lt;img src='/img/posts/jk/thumb/008.jpg' height='175' alt='Screenshot 3' width='280' /&gt;&lt;/a&gt;
&lt;p&gt;The aforementioned zoo.&lt;/p&gt;

&lt;a href='/img/posts/jk/011.png'&gt;&lt;img src='/img/posts/jk/thumb/011.jpg' height='175' alt='Screenshot 4' width='280' /&gt;&lt;/a&gt;
&lt;p&gt;Oddly, I also included a kitchen. Complete with an oven you have to
crawl into to complete a mission objective.&lt;/p&gt;

&lt;a href='/img/posts/jk/019.png'&gt;&lt;img src='/img/posts/jk/thumb/019.jpg' height='175' alt='Screenshot 5' width='280' /&gt;&lt;/a&gt;
&lt;p&gt;The obligatory &quot;dress up as the enemy to get through a checkpoint&quot;
plot point.&lt;/p&gt;

&lt;a href='/img/posts/jk/024.png'&gt;&lt;img src='/img/posts/jk/thumb/024.jpg' height='175' alt='Screenshot 6' width='280' /&gt;&lt;/a&gt;
&lt;p&gt;A sewer at the bottom of a detention center. Even star destroyers have
to take care of their waste somehow.&lt;/p&gt;

&lt;a href='/img/posts/jk/027.png'&gt;&lt;img src='/img/posts/jk/thumb/027.jpg' height='175' alt='Screenshot 7' width='280' /&gt;&lt;/a&gt;
&lt;p&gt;Grand Admiral Thrawn himself, wielding a phaser. And fairly deadly at
that--I died a dozen times or so before beating him.&lt;/p&gt;

&lt;a href='/img/posts/jk/035.png'&gt;&lt;img src='/img/posts/jk/thumb/035.jpg' height='175' alt='Screenshot 8' width='280' /&gt;&lt;/a&gt;
&lt;p&gt;Barney makes an appearance. And yes, you can obliterate him.&lt;/p&gt;

&lt;/div&gt;
&lt;p&gt;While my handiwork hasn&amp;#8217;t aged well (and neither has JK, for that matter), I&amp;#8217;ve placed the entire monstrosity on my github for posterity&amp;#8217;s sake: &lt;a href='https://github.com/malloc47/return-of-thrawn'&gt;https://github.com/malloc47/return-of-thrawn&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Reflecting back, COG certainly wasn&amp;#8217;t the most stretching or important language I learned (by a long-shot), nor was building my level the most disciplined software engineering project I&amp;#8217;ve undertaken, but it was one thing: it was enthralling enough to keep a kid hooked on coding and building cool things. Before the era of web apps and mobile apps, or code academies and khan academies, or Scratch and Alice, I feel rather lucky to have stumbled on something that was simultaneously fun and empowering. JK wasn&amp;#8217;t just a game. It was an ecosystem. It was an IDE. And it was fun.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Import Links into Google Plus as +1s</title>
      <link>http://malloc47.com/blog/import-links-into-google-plus-as-1s/</link>
      <pubDate>Sat, 18 Feb 2012 00:00:00 -0800</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/blog/import-links-into-google-plus-as-1s</guid>
      <description>&lt;p&gt;I&amp;#8217;ve been accumulating helpful and interesting articles for a number of years now. At first, they existed solely as starred articles in Google Reader. Eventually, I migrated to &lt;a href='http://delicious.com/'&gt;Delicious&lt;/a&gt;, and finally to &lt;a href='http://www.diigo.com'&gt;diigo&lt;/a&gt;. While diigo has served me well, I finally decided to consolidate services and begin using Google&amp;#8217;s +1 feature, as it is fairly ubiquitous and is associated with an account I am already logged into (and appears nicely on my Google+ profile).&lt;/p&gt;

&lt;p&gt;While Google&amp;#8217;s Takeout is very useful on the exporting front (a factor I consciously consider before migrating to any system), I&amp;#8217;ve never run across a good way to import a list of links as +1s on my Google+ profile. So here&amp;#8217;s what I came up with last night:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='c'&gt;#!/bin/sh&lt;/span&gt;
&lt;span class='nb'&gt;echo&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;quot;&lt;/span&gt; &amp;gt; page.html
&lt;span class='nb'&gt;echo&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&amp;lt;script type=\&amp;quot;text/javascript\&amp;quot; src=\&amp;quot;https://apis.google.com/js/plusone.js\&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;&amp;quot;&lt;/span&gt; &amp;gt;&amp;gt; page.html
&lt;span class='nb'&gt;echo&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;&amp;quot;&lt;/span&gt; &amp;gt;&amp;gt; page.html
grep -o http&lt;span class='o'&gt;[&lt;/span&gt;^&lt;span class='se'&gt;\&amp;quot;\)\&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;* &lt;span class='nv'&gt;$1&lt;/span&gt; | xargs -I&lt;span class='o'&gt;{}&lt;/span&gt; &lt;span class='nb'&gt;echo&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&amp;lt;g:plusone href=\&amp;quot;{}\&amp;quot;&amp;gt;&amp;lt;/g:plusone&amp;gt;&amp;quot;&lt;/span&gt; &amp;gt;&amp;gt; page.html
&lt;span class='nb'&gt;echo&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;&lt;/span&gt; &amp;gt;&amp;gt; page.html
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since diigo will happily let you export in a variety of formats, I chose the csv file. My goal was simply to create a webpage with the links and the +1 button next to each. The process of clicking the buttons themselves could be automated, but I decided to manually click on the buttons, since I wanted to vet the links I transferred. The very simple (read: not iron-clad) regex (&lt;code&gt;http[^\&amp;quot;\)\&amp;#39;]*&lt;/code&gt;) is used to pull out the links. It looks for an instance of a string &amp;#8220;http&amp;#8221; and then continues grabbing characters until it hits a quote. It should work in a number of contexts, aside from just CSV files. &lt;code&gt;xargs&lt;/code&gt; kindly loops over all of these addresses and outputs each in HTML form. The rest of the script just adds the usual HTML boilerplate, as well as the +1 script necessary for the buttons to work.&lt;/p&gt;

&lt;p&gt;One more wrinkle: the latest crop of browsers sandbox what javascript is allowed to do to the local filesystem (and rightfully so), so you will need to upload the generated page to a non-local path (or simply copy and paste it into a website that will let you edit html live). Once you do, just click on all the +1 buttons everywhere, and your links will be +1&amp;#8217;d accordingly.&lt;/p&gt;

&lt;p&gt;Have a &lt;a href='https://plus.google.com/u/0/113712188424853568731/plusones'&gt;look&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Man Page Readability</title>
      <link>http://malloc47.com/blog/man-page-readability/</link>
      <pubDate>Sat, 11 Feb 2012 00:00:00 -0800</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/blog/man-page-readability</guid>
      <description>&lt;p&gt;Man pages are one of the staples of a healthy *nix diet, but having grown up with them, it didn&amp;#8217;t occur to me until recently to wonder how readable they really are. The de facto standard for readability has&amp;#8211;for better or worse&amp;#8211;converged to the &lt;a href='http://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_readability_test'&gt;Flesch–Kincaid&lt;/a&gt; test, which (a particular variant) ranks readability as a &amp;#8220;grade level,&amp;#8221; roughly corresponding to an American school grade. Getting a readability score for a manpage is as simple as piping our man page to the GNU &lt;em&gt;style&lt;/em&gt; program (not installed on many distros, I discovered, and typically available in the &amp;#8220;diction&amp;#8221; package).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; man /usr/share/man/man1/git.1.gz | style
readability grades:
        Kincaid: 7.0
        ARI: 4.4
        Coleman-Liau: 4.0
        ...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice that man can read in the (tarzipped) man source file (typically located in &lt;code&gt;/usr/share/man/man?&lt;/code&gt; folders) rather than having to type the executable name.&lt;/p&gt;

&lt;p&gt;Since we&amp;#8217;re only concerned with the Kincaid score, we can apply a smattering of grep+awk to extract it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;man /usr/share/man/man1/git.1.gz | style | grep Kincaid | awk &amp;#39;{print $2&amp;#39;}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And finally, looping over all the installed man pages (+sed to trim out short sentences, headers, etc.) gives us one big file, from which we can get readability statistics.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;for i in `ls -d -1 /usr/share/man/man?/*` ; do echo -n &amp;quot;$i &amp;quot; ; man $i | tr &amp;#39;\n&amp;#39; &amp;#39; &amp;#39; | sed &amp;#39;s/\./\.\n/g&amp;#39; | sed -e &amp;#39;s/^[ \t]*//&amp;#39; | sed &amp;#39;/.\{3\}/!d&amp;#39; | grep Kincaid | awk &amp;#39;{print $2}&amp;#39; ; done &amp;gt; ~/flesch-kincaid&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;More awk magic will give us an average and standard deviation.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; awk &amp;#39;{avg+=$2} END {print avg/NR}&amp;#39; ~/flesch-kincaid
9.08134
&amp;gt; awk &amp;#39;{sum+=$2; sumsq+=$2*$2} END {print sqrt(sumsq/NR - (sum/NR)**2)}&amp;#39; ~/flesch-kincaid
10.3857&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Perhaps surprisingly, the average readability of the man pages on my machine is below the college level. More unexpectedly, the standard deviation is very high, indicating that there&amp;#8217;s a wide range of readability from one man page to another. The page with the most absurdly large readability score&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;grep `awk &amp;#39;$2&amp;gt;m{m=$2}END{print m}&amp;#39; ~/flesch-kincaid` ~/flesch-kincaid&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;consist almost entirely of code and API documentation.&lt;/p&gt;

&lt;p&gt;Of course, this does not take into account a myriad of confounding factors: some non-English language pages crept into the list, which kick out bogus scores by the Flesch–Kincaid metric, man pages have non-standard formatting (e.g. command switches) which aren&amp;#8217;t considered in the metric, etc. But knowing the general (or at least average) education level required to comprehend man pages is worth considering as more mainstream distributions bring with them an influx of younger and less experienced users.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>vim -> emacs</title>
      <link>http://malloc47.com/blog/vim-to-emacs/</link>
      <pubDate>Wed, 18 May 2011 00:00:00 -0700</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/blog/vim-to-emacs</guid>
      <description>&lt;p&gt;After having grown up in the terminal with vim at my side, I&amp;#8217;ve been transitioning to emacs. There&amp;#8217;s no shortage of guides for making the leap, but there&amp;#8217;s a number of features in vim that operate very differently in emacs, or do not map cleanly to a single feature. There&amp;#8217;s nothing like not knowing how to get that &lt;em&gt;one&lt;/em&gt; feature you rely on when making the vim-&amp;#62;emacs leap to make you want to run back to familiar territory. Here&amp;#8217;s a few of the discoveries I&amp;#8217;ve made along the way.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;dd -&amp;gt; C-Shift-Backspace&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;C-k&lt;/strong&gt; is more often cited as the analog for &lt;strong&gt;dd&lt;/strong&gt; (and it is indeed more flexible in many situations), but as far as raw functionality is concerned, sometimes you just want the current line to go away, regardless of where the cursor is. Unfortunately, the** C-Shift-Backspace** keybinding may not be triggered when you&amp;#8217;re running emacs in a screen or xterm (emacs -nw), but for the majority of standard emacs use, it&amp;#8217;s a feature-compatible substitute.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;% -&amp;gt; C-M-n, C-M-p&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Traversing pairs of grouping characters (e.g. (), [], {}, etc.) with vim&amp;#8217;s % key is invaluable, but emacs not only replicates this feature, but adds a few new bits of functionality too. In general &lt;strong&gt;C-n&lt;/strong&gt; and &lt;strong&gt;C-p&lt;/strong&gt; will traverse to the next or previous line, respectively, but &lt;strong&gt;C-M-n&lt;/strong&gt; and &lt;strong&gt;C-M-p&lt;/strong&gt; will traverse forward or backward over the current &lt;em&gt;list&lt;/em&gt;. Since emacs has a major mode related to most languages you could find yourself working in (and if not, it&amp;#8217;s not difficult to find or make one) that will do a rudimentary parse of the code into proper tokens, &lt;strong&gt;C-M-n&lt;/strong&gt; and &lt;strong&gt;C-M-p&lt;/strong&gt; can intelligently jump to the beginning or end of parenthetical structures, words, or blocks with equal effectiveness. As a bonus, you also get &lt;strong&gt;C-M-d&lt;/strong&gt; (if your window manager hasn&amp;#8217;t stolen that keybinding) and &lt;strong&gt;C-M-u&lt;/strong&gt; that go down or up (respectively) in the current structure&amp;#8212;i.e., &lt;strong&gt;C-M-d&lt;/strong&gt; will place the cursor inside the parenthetical statement, ready to iterate over the items inside the parentheses with &lt;strong&gt;C-M-n&lt;/strong&gt;, while &lt;strong&gt;C-M-u&lt;/strong&gt; will place the cursor at the beginning of the parenthesis or block structure enclosing the cursor. Check the major mode you are in for even more context-sensitive commands (e.g., &lt;strong&gt;M-a&lt;/strong&gt; and &lt;strong&gt;M-e&lt;/strong&gt; to go the beginning or ending of a statement in the C++ major mode). Another instance where it &lt;em&gt;seems&lt;/em&gt; like emacs adds overhead to the preciously minimalistic vim keybindings, but having two keys instead of one adds immeasurable navigational flexibility.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;f, F, t, T -&amp;gt; C-s, C-r&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This may not be immediately intuitive, but the best mapping for vim&amp;#8217;s nifty &amp;#8220;forward (or backward) to character&amp;#8221; feature is emacs&amp;#8217;s standard search function. While, yes, the concession is that it requires three keystrokes (you must press enter after searching in emacs to position the cursor) instead of one, you get the same functionality, with the added benefit that you can search more than one character easily, and you don&amp;#8217;t have to retype the character you want to jump to, as you would in vim.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[n]gg, :[n] -&amp;gt; M-g g&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Though emacs integrates so well into most REPLs that you don&amp;#8217;t often need to jump to specific line numbers manually, it&amp;#8217;s still trivial to hop to specific line numbers with ease. Again, you&amp;#8217;re sacrificing more keystrokes but, as with everything in emacs, you can remap anything you use often. Alternately, consider using the faster &lt;strong&gt;C-[n] M-g g&lt;/strong&gt; variant to prepend the line number instead of having to specify it (and hit enter) in the mini-buffer.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;quot;[register]p -&amp;gt; C-y M-y&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The kill ring in emacs isn&amp;#8217;t remotely complex, so it&amp;#8217;s hardly worth mentioning except that it varies greatly from vim&amp;#8217;s model of using registers to store yanked text. Instead of having to specify a register, as you do in vim, you simply paste whatever text happens to be in the ring into your document/code with &lt;strong&gt;C-y&lt;/strong&gt;, then loop through the various yanks with &lt;strong&gt;M-y&lt;/strong&gt;. Coming from a vim world, where every yank requires a register that contains only one snippet of text, the value of having yanks (or kills) you can scroll through (in the exact context you wish to paste them) is quite clear (and can actually result in fewer keystrokes for complicated yanks). As a bonus, only having to use &lt;strong&gt;C-w&lt;/strong&gt; or &lt;strong&gt;M-w&lt;/strong&gt; to yank text requires fewer keystrokes than having to use &lt;strong&gt;&amp;#8220;[reg]y&lt;/strong&gt; in vim too.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;q[register] ... q -&amp;gt; C-x ( ... C-x ) M-x name-last-kbd-macro [name]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The only surface difference between vim and emacs for keyboard macros is that vim assigns keyboard macros to a register by default, but emacs requires &lt;strong&gt;M-x name-last-kbd-macro&lt;/strong&gt; to cache more than one macro at a time. The difference becomes more stark once you explore multiple macros, as you can apply a named keyboard macro by using &lt;strong&gt;M-x [name]&lt;/strong&gt;, since emacs saves the keyboard macro as a standard emacs command. As a bonus you can use the &lt;strong&gt;M-x insert-kbd-macro&lt;/strong&gt; to save the macro to your &lt;em&gt;.emacs&lt;/em&gt; file for future use.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;u, C-r -&amp;gt; C-/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is another emacs feature that&amp;#8217;s very simple to understand, but where vim logic may trip you up. Most vim-&amp;#62;emacs guides will clue you in that vim&amp;#8217;s &lt;strong&gt;u&lt;/strong&gt; maps to emacs &lt;strong&gt;C-/&lt;/strong&gt; (&lt;strong&gt;C-_&lt;/strong&gt; or &lt;strong&gt;C-x u&lt;/strong&gt;, but those are more of a hassle), which is indeed correct. But the underlying &amp;#8220;redo&amp;#8221; logic is a bit different. Instead of vim&amp;#8217;s separate &lt;strong&gt;C-r&lt;/strong&gt; redo command, emacs lets you &amp;#8220;undo your undos&amp;#8221; (again, think yank ring). So after a series of consecutive &lt;strong&gt;C-/&lt;/strong&gt;s, all you need do is interrupt the sequence with a command that does not produce any undo history (I typically use a movement command like &lt;strong&gt;C-f&lt;/strong&gt;), and then use &lt;strong&gt;C-/&lt;/strong&gt; again, which will then, essentially, have become a &amp;#8220;redo&amp;#8221; command. This will become second nature quickly, but it&amp;#8217;s a very different model from the inferior method used by vim (and a large number of other editors).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;: -&amp;gt; M-:, M-x&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Only thing worth mentioning here is the difference between executing direct elisp code (&lt;strong&gt;M-:&lt;/strong&gt;) and emacs commands (&lt;strong&gt;M-x&lt;/strong&gt;), which is not a distinction that vim has to make.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;:tabn, gf -&amp;gt; C-x b&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Vim actually does allow for &amp;#8220;hidden&amp;#8221; buffers, so it can operate in a very emacsish way, if desired, but it a rarely-used feature; one that emacs adopts by default. Emacs doesn&amp;#8217;t have &amp;#8220;tabs&amp;#8221; to switch between, per se, but the way it handles buffers is vastly more powerful than any tab or hidden buffer in vim, minus the &amp;#8220;tab&amp;#8221; aesthetic (and ido-mode or &lt;strong&gt;C-x C-b&lt;/strong&gt; is more than capable of providing a list if that is what is needed).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Screen Line Movement -&amp;gt; Logical Line Movement&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Emacs&amp;#8217;s &lt;strong&gt;C-n&lt;/strong&gt; and &lt;strong&gt;C-p&lt;/strong&gt; move over screen lines (the line breaks you see on the screen) by default, while vim&amp;#8217;s &lt;strong&gt;j&lt;/strong&gt;,&lt;strong&gt;k&lt;/strong&gt; moves over logical lines (line breaks that are actually in the file). While vim&amp;#8217;s logical line movement can cause problems with long lines (you have to use &lt;strong&gt;gj&lt;/strong&gt; and &lt;strong&gt;gk&lt;/strong&gt; to switch over to screen lines), you can switch emacs to logical line movement, if you prefer it, with&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(setp line-move-visual nil)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which can be easily entered with &lt;strong&gt;M-:&lt;/strong&gt; in emacs to try it out, or added to your &lt;code&gt;.emacs&lt;/code&gt; file to save the setting.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>Once Upon an After</title>
      <link>http://malloc47.com/blog/once-upon-an-after/</link>
      <pubDate>Wed, 15 Dec 2010 00:00:00 -0800</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/blog/once-upon-an-after</guid>
      <description>&lt;p&gt;&amp;#8220;Well&amp;#8230;&amp;#8221; said I.&lt;/p&gt;

&lt;p&gt;&amp;#8220;Yes?&amp;#8221; said it.&lt;/p&gt;

&lt;p&gt;&amp;#8220;I don&amp;#8217;t understand what you mean by &amp;#8216;happy endings&amp;#8217; at all.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Every single of your stories is one.&amp;#8221; It seemed insistent. It couldn&amp;#8217;t have meant what it sounded like it did; its slightly strange phrasing being (I assumed) an artifact of adapting to our complex language.&lt;/p&gt;

&lt;p&gt;&amp;#8220;Surely you don&amp;#8217;t believe all of our stories have a happy ending?&amp;#8221; I added, trying to clarify things.&lt;/p&gt;

&lt;p&gt;&amp;#8220;Surely I do,&amp;#8221; was its reply.&lt;/p&gt;

&lt;p&gt;&amp;#8220;Why?&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Because they end, happily.&amp;#8221;&lt;/p&gt;

&lt;p&gt;I knew I wasn&amp;#8217;t going to get anywhere without examples. &amp;#8220;But what of stories that leave all the characters expired or cadaverous?&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;But they end.&amp;#8221; Its reply so very matter-of-fact.&lt;/p&gt;

&lt;p&gt;&amp;#8220;Well, yes. But what of stories of lost love and unhappiness?&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;They still end.&amp;#8221;&lt;/p&gt;

&lt;p&gt;The monotonous reply, coupled with its already colorless voice, was starting to grate me wrongly. &amp;#8220;But what still of stories where the miscreant escapes justice?&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;They come to an end, still.&amp;#8221;&lt;/p&gt;

&lt;p&gt;Now it was just trying to get under my skin. &amp;#8220;You can&amp;#8217;t be serious! You can&amp;#8217;t call a villain triumphant anything but a travesty; a champion dead anything but a loss!&amp;#8221;&lt;/p&gt;

&lt;p&gt;It raised one of its arms. &amp;#8220;Certainly the events are allowed less than happiness, but the story itself is still happy.&amp;#8221;&lt;/p&gt;

&lt;p&gt;I didn&amp;#8217;t know what it was getting at. &amp;#8220;What are you getting at?&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Perhaps I misspoke,&amp;#8221; it said, clearly recoiling from my words (it understood verbal frustration so much more clearly than nonverbal frustration). &amp;#8220;What I mean is that the nature of your stories is happy, by virtue of the fact that they end.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Ah, now we are getting somewhere,&amp;#8221; I uttered, relieved. &amp;#8220;I thought you meant that our stories end in a happy way, while you actually meant that our stories end, which is happy&amp;#8230; right?&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Yes, that would be it, if I understand the nuances of your language correctly.&amp;#8221; It was considerably calmer now.&lt;/p&gt;

&lt;p&gt;&amp;#8220;But&amp;#8230; why?&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Because they happily end.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;No, no, no&amp;#8230; I mean, ummm&amp;#8230;&amp;#8221; I sputtered, trying to get into words what I was asking of it. &amp;#8220;Why is the nature of an ending story happy?&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;That&amp;#8217;s a bit difficult to explain to beings subject to death&amp;#8211;&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Mortal,&amp;#8221; I chimed in, knowing it appreciated my attempts at improving its vocabulary.&lt;/p&gt;

&lt;p&gt;&amp;#8220;Yes, mortal beings. For you, endings are natural, expected, even necessary. We are not mortal, you see. Endings aren&amp;#8217;t normal for us. They&amp;#8217;re&amp;#8230; redundant.&amp;#8221;&lt;/p&gt;

&lt;p&gt;Its last word choice confused me, but I decided to focus my query on what was really bothering me. &amp;#8220;Ah, I see. I understand the unfamiliarity, I suppose. But what makes them happy?&amp;#8221;&lt;/p&gt;

&lt;p&gt;It thought for an uncomfortable minute, trying to get its thoughts into its own words. And then from its own words into my words. &amp;#8220;You see, the lot of us have lived for a very long time. And we have a surprisingly limited vocabulary&amp;#8211;only a handful of what you would call &amp;#8216;words&amp;#8217;&amp;#8211;and a very rigid set of actions we are capable of performing.&amp;#8221; It paused, wondering if I had taken in the significance of the limitations it had just explained. After a moment, my nodding acknowledgement was finally satisfactory, and it continued. &amp;#8220;After but an armful&amp;#8211;&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Handful.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Yes, handful, thank you. After a handful of your lifetimes&amp;#8211;about four hundred billion&amp;#8211;we have, each of us individually, lived out all possible combinations of any reasonably finite series of actions that can be taken, and words that can accompany them.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Well&amp;#8230;&amp;#8221; said I.&lt;/p&gt;

&lt;p&gt;&amp;#8220;We&amp;#8217;ve lived them all,&amp;#8221; it continued.&lt;/p&gt;

&lt;p&gt;This I did require a moment to soak in. It was plenty willing to oblige my contemplative moment. &amp;#8220;Wait,&amp;#8221; I exclaimed, &amp;#8220;you mean that if any of your stories were to have an ending, then you&amp;#8217;d have already lived that story?&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Yes, that is the very reason our stories have no endings. Nor can they.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Why couldn&amp;#8217;t you have a story that went on just a bit longer than all the stories you&amp;#8217;ve experienced, and then end it?&amp;#8221; I puzzled.&lt;/p&gt;

&lt;p&gt;It looked puzzled at my puzzle and then, quite rightly, replied, &amp;#8220;by the time we had heard the recount of a story of such length, we&amp;#8217;d have already experienced it ourselves. Nor could the crafting of such a tale be completed before we had fully experienced its contents.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Oh, bother,&amp;#8221; I reacted. Clearly, I had not fully grasped this notion. I probed further: &amp;#8220;So, tell me of the stories you do have.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;We may have experienced every possible permutation of events, but we still exist in time, and the order in which we experience these events is different for every one of us.&amp;#8221; It paused again. &amp;#8220;Think of it thus: no matter which book you pick up, no matter the film you view, no matter what event you might hear recounted, everything found therein you have already experienced. But the sequence of when these things were experienced varies from one to another. That&amp;#8217;s how we tell each other apart&amp;#8211;not by appearance, since we all share the same; not aurally or tactilely, but simply by distinction of the sequence of discrete stories we&amp;#8217;ve experienced.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Aha! So you need only find an ordering of stories that has never been experienced before to create a new, original tale?&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;That&amp;#8217;s hardly practical, since there is no telling if someone else has already experienced your crafted ordering (and yours isn&amp;#8217;t the only culture with lawyers). Neither is creating such a lengthy tale practical, nor partaking in the recounting of such a thing, as I&amp;#8217;ve already said.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;But the lack of novelty doesn&amp;#8217;t make a story valueless (lawyers aside),&amp;#8221; I posited, &amp;#8220;many of our stories have elements we&amp;#8217;re all familiar with: birth, growing up, death&amp;#8211;themes that don&amp;#8217;t grow tired in and of themselves.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;What if each and every one of your stories consisted of &amp;#8216;Once upon a time.&amp;#8217; That, and only that. Something so familiar and universal that its existence alone without anything accompanying it is so axiomatical as to be meaningless. That is what a finite story is to us. You, being finite, only understand the example if I take an incomplete element of a story, but to us, it&amp;#8217;s entire stories that seem this tired and common.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;I don&amp;#8217;t suppose your vocabulary allows for narrative devices that makes the story uniquely inexperiential?&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;You would be right, if I understand your meaning.&amp;#8221;&lt;/p&gt;

&lt;p&gt;It made its point clearly. &amp;#8220;But what are your stories, then? How can they be enough?&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;Simple,&amp;#8221; it replied. &amp;#8220;Our stories are the lives of those around us. That is enough for us&amp;#8221;&lt;/p&gt;

&lt;p&gt;Something was still missing, but I think I understood.&lt;/p&gt;</description>
    </item>
    
    <item>
      <title>of soundtracks and extraterrestrials</title>
      <link>http://malloc47.com/blog/of-soundtracks-and-extraterrestrials/</link>
      <pubDate>Mon, 18 Jan 2010 00:00:00 -0800</pubDate>
      <author>Jarrell Waggoner (malloc47@gmail.com)</author>
      <guid>http://malloc47.com/blog/of-soundtracks-and-extraterrestrials</guid>
      <description>&lt;p&gt;It has always been the aliens.&lt;/p&gt;

&lt;p&gt;Musically speaking, anyway. Fantasy has always had music, and music &lt;a href='http://en.wikipedia.org/wiki/Fantasia_on_a_Theme_of_Thomas_Tallis' title='You guessed it: Thomas Tallis'&gt;fantasy&lt;/a&gt;. And occasionally aliens.&lt;/p&gt;

&lt;p&gt;Whether our lovable characters are humming ditties across the foliage of Middle-earth or our intrepid explorers attempt to decipher the cacophonous intonations of extraterrestrial visitors, music has been accompanying the adventure since before adventures were being put to words.&lt;/p&gt;

&lt;p&gt;Maybe we weren’t singing along, but we were being sung to. Maybe we weren’t tapping to the beat, but the beat was there to be tapped.&lt;/p&gt;

&lt;p&gt;So where did it go?&lt;/p&gt;

&lt;p&gt;It seems that every major fantasy franchise eventually earns a signature tune once it works its way up the ranks and onto the silver screen. From the mysterious celesta stylings of John William’s ‘Hedwig’s Theme’ from &lt;em&gt;Harry Potter&lt;/em&gt; to Patrick Doyle’s bombastic ‘Eragon,’ the bigger the budget, the brassier the bravura. Apparently, without the written word, we still need someone to tell us when we should be fearful of the sprawling armies before us or marvelling at our wizard’s mysterious magics.&lt;/p&gt;

&lt;p&gt;It might as well be the aliens.&lt;/p&gt;

&lt;p&gt;Because who else is going to transport a 70-piece orchestra to the far-off lands of Narnia purely for our listening pleasure? Before, our characters were responsible for the words, our faithful authors responsible for giving them the right meter and rhyme. Our imaginations brought the orchestra. Or the fiddle. When our characters chanted their lines, we didn’t get dramatic montages to keep our attention.&lt;/p&gt;

&lt;p&gt;Ah, progress. There are many upsides to having ubiquitous fantasy soundtracks. Fantasy is bigger than life, and some of us like our music imaginative. However, it can also be detached. Trying to sing when the visuals don’t. Or make us laugh when the characters aren’t funny.&lt;/p&gt;

&lt;p&gt;But at its best, it’s the Greek chorus of the modern age, without bludgeoning us with every internal dalliance of every character, while preventing us from overlooking subtle emotions or expansive vistas. Like a Greek chorus, our soundtracks even get to poke their head in and be heard by our characters from time to time. But mostly, the aliens play well out of earshot of the action. We wouldn’t want those war drums distracting the archers, after all.&lt;/p&gt;

&lt;p&gt;Music just fits better with fantasy. Really, when you’re watching maniacal creatures attack our heroes on the battlefield, who’s going to question whether that string run was played by a wandering minstrel on the battlefield or by aliens watching from the heavens? We’ve suspended quite a bit of disbelief by that point. Which is equally valid for science fiction, where there truly is the distinct possibility that the melody was inspired by extraterrestrial entities.&lt;/p&gt;

&lt;p&gt;Say what you will about the quality of fantasy translated to film (and there is much to be said, sadly), but arguing with the bold brass and sweeping melodies of John Williams, James Newton Howard, Harry Gregson-Williams, Howard Shore, and James Horner isn’t nearly as easy a task. It’s music at its most grandiose; it &lt;em&gt;is&lt;/em&gt; fantasy. Sure, fantasy may not be its own musical genre, but one need only feel the swelling strings wash over the softly-repeating piano ostinato of &lt;em&gt;Lady in the Water&lt;/em&gt; to know that it is unique, it is immaculate, and it is &lt;em&gt;ours&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;And whether it be the latest space opera or (yet another) Final Fantasy, there’s likely much more music to come.&lt;/p&gt;

&lt;p&gt;Unless, of course, the aliens decide to take some time off.&lt;/p&gt;</description>
    </item>
    
  </channel> 
</rss>
