<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>try all your chance</title>
    <description>hi im pcl. let me tell you about computers and stuff
</description>
    <link>https://blog.pclewis.com/</link>
    <atom:link href="https://blog.pclewis.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Thu, 14 Jun 2018 21:35:40 +0000</pubDate>
    <lastBuildDate>Thu, 14 Jun 2018 21:35:40 +0000</lastBuildDate>
    <generator>Jekyll v3.7.3</generator>
    
      <item>
        <title>Shenzhen I/O Tetris</title>
        <description>&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;

&lt;p&gt;One of the missions in &lt;a href=&quot;http://www.zachtronics.com/shenzhen-io/&quot;&gt;Shenzhen I/O&lt;/a&gt; is to create a game in the sandbox.&lt;/p&gt;

&lt;p&gt;Intimidated by the idea of drawing something custom for the LCD screen, I thought about making Tetris with the default block matrix.&lt;/p&gt;

&lt;p&gt;As that is obviously impossible, I went to skip the mission.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/img/2016-10-22-shenzhen-io-tetris/promise.jpg&quot; alt=&quot;Keep holding. You promise you really made a game?&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Just before the bar filled up, I stopped. The text on this button believed in me. Could I really betray it? Could I sit there stone faced, lying through my mouse finger to it? The JRPG heroes and moral-of-the-story-having cartoons and sitcoms of my childhood raised me better than that.&lt;/p&gt;

&lt;p&gt;There was only one honorable thing to do: a hard work montage.&lt;/p&gt;

&lt;video autoplay=&quot;&quot; loop=&quot;&quot; style=&quot;margin-bottom:25px&quot;&gt;&lt;source src=&quot;/img/2016-10-22-shenzhen-io-tetris/MassiveFarAztecant-mobile.mp4&quot; /&gt;
There should be a video here!&lt;/video&gt;

&lt;p&gt;Phew! Now, let me ruin the pace we’ve set by explaining everything in excruciatingly boring detail.&lt;/p&gt;

&lt;h2 id=&quot;major-challenge-storing-more-than-one-anything&quot;&gt;Major challenge: storing more than one anything&lt;/h2&gt;

&lt;p&gt;Processors have only one working register: &lt;code class=&quot;highlighter-rouge&quot;&gt;acc&lt;/code&gt;. The larger ones add &lt;code class=&quot;highlighter-rouge&quot;&gt;dat&lt;/code&gt;, which can only be set with &lt;code class=&quot;highlighter-rouge&quot;&gt;mov&lt;/code&gt;. That means to perform operations on the value of &lt;code class=&quot;highlighter-rouge&quot;&gt;dat&lt;/code&gt;, you must clobber &lt;code class=&quot;highlighter-rouge&quot;&gt;acc&lt;/code&gt;, so even the big processors can only effectively store a single value.&lt;/p&gt;

&lt;div class=&quot;language-nasm highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dat&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acc&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;mov&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acc&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dat&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;dgt-and-dst&quot;&gt;dgt and dst&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;dgt&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;dst&lt;/code&gt; make it possible to isolate individual digits. Registers can hold three digits.&lt;/p&gt;

&lt;p&gt;A falling tetris piece has three values that change while it’s falling: the column (X), the row (Y), and the rotation.&lt;/p&gt;

&lt;p&gt;There are only 4 possible rotations for a piece, so that’s easy to fit in a digit. The default LCD matrix is 10x12, so X already fits in a digit, and Y can fit in a digit if we give up the bottom two rows.&lt;/p&gt;

&lt;p&gt;Thus we can store our whole state in one register: the left digit is the rotation (0-3), the middle digit is the row (0-9), and the right digit is the column (0-9).&lt;/p&gt;

&lt;p&gt;To move a piece right or left we just &lt;code class=&quot;highlighter-rouge&quot;&gt;add 1&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;sub 1&lt;/code&gt;, to move it down we &lt;code class=&quot;highlighter-rouge&quot;&gt;add 10&lt;/code&gt;, and to rotate it we &lt;code class=&quot;highlighter-rouge&quot;&gt;add 100&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To convert this number to a cell on the matrix, we remove the rotation (&lt;code class=&quot;highlighter-rouge&quot;&gt;dst 2 0&lt;/code&gt;) and &lt;code class=&quot;highlighter-rouge&quot;&gt;add 1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/2016-10-22-shenzhen-io-tetris/digits.png&quot;&gt;&lt;img src=&quot;/img/2016-10-22-shenzhen-io-tetris/digits.png&quot; alt=&quot;Decoding digits&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;digits-as-bits-its-all-1s-and-2s&quot;&gt;Digits as bits: it’s all 1s and 2s&lt;/h3&gt;

&lt;p&gt;We can represent all but the line piece with 6 bits. Using 1 for “on” and 0 for “off” is natural, but using 2 and 1 makes it easier to decode.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/2016-10-22-shenzhen-io-tetris/pieces.png&quot;&gt;&lt;img src=&quot;/img/2016-10-22-shenzhen-io-tetris/pieces.png&quot; alt=&quot;Storing pieces&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how most pieces share a row with another piece. This lets us squish them together when we store them in a ROM chip. This did not end up being useful, but it is neat.&lt;/p&gt;

&lt;p&gt;We can step through these bits different ways to render different rotations:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/2016-10-22-shenzhen-io-tetris/rotations.png&quot;&gt;&lt;img src=&quot;/img/2016-10-22-shenzhen-io-tetris/rotations.png&quot; alt=&quot;Rotating pieces&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;bits-as-bits&quot;&gt;Bits as bits&lt;/h3&gt;

&lt;p&gt;To determine when you’ve run into a piece that’s already in place, we need one bit for every space on the board. Since we decided the board is 10x10, that means we need 100 bits of storage.&lt;/p&gt;

&lt;p&gt;The RAM module has 14 cells, which multiplied by 3 digits give us 42 bits of storage. Even if we used two we don’t have enough space to store the whole state of the board.&lt;/p&gt;

&lt;p&gt;If we had some way to use &lt;a href=&quot;https://www.mathsisfun.com/binary-number-system.html&quot;&gt;binary numbers&lt;/a&gt;, we could store three bits per digit using values 0-7, which would give us 9 bits per cell for 126 total bits of storage.&lt;/p&gt;

&lt;p&gt;If we then give up a column on the board, each cell can store a whole row. This lets us use one digit to pick a memory cell and one digit to pick a bit, and makes clearing completed lines very easy.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/2016-10-22-shenzhen-io-tetris/memory.png&quot;&gt;&lt;img src=&quot;/img/2016-10-22-shenzhen-io-tetris/memory.png&quot; alt=&quot;Memory&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There’s no &lt;code class=&quot;highlighter-rouge&quot;&gt;div&lt;/code&gt; instruction, but we can divide a single digit by 3 with &lt;code class=&quot;highlighter-rouge&quot;&gt;mul 34&lt;/code&gt; and then &lt;code class=&quot;highlighter-rouge&quot;&gt;dgt 2&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To convert the digit 0-7 into its component binary bits, we can multiply by 125. A set bit is indicated by a digit greater than 3 in the result. Since it is not any more expensive for callers to &lt;code class=&quot;highlighter-rouge&quot;&gt;tgt reg 3&lt;/code&gt; than &lt;code class=&quot;highlighter-rouge&quot;&gt;teq reg 0&lt;/code&gt;, we don’t need to interpret it here.&lt;/p&gt;

&lt;h2 id=&quot;putting-it-all-together&quot;&gt;Putting it all together&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://gist.github.com/pclewis/4cffbc059ed8145f26e51be437c7623a&quot;&gt;Download the working game here&lt;/a&gt;. Left and right move, up rotates. The game ends when it crashes. There’s still plenty of room to optimize and add more. The board is laid out roughly like this:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/img/2016-10-22-shenzhen-io-tetris/layout.png&quot;&gt;&lt;img src=&quot;/img/2016-10-22-shenzhen-io-tetris/layout.png&quot; alt=&quot;Layout&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is a video of it in action:&lt;/p&gt;

&lt;iframe width=&quot;560&quot; height=&quot;315&quot; src=&quot;https://www.youtube.com/embed/Oeh4RzzRIvk&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

</description>
        <pubDate>Sat, 22 Oct 2016 00:00:00 +0000</pubDate>
        <link>https://blog.pclewis.com/2016/10/22/shenzhen-io-tetris.html</link>
        <guid isPermaLink="true">https://blog.pclewis.com/2016/10/22/shenzhen-io-tetris.html</guid>
        
        <category>shenzhen-io</category>
        
        
      </item>
    
      <item>
        <title>Mopidy with Extensions on NixOS</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://www.mopidy.com/&quot;&gt;Mopidy&lt;/a&gt; is a sweet &lt;a href=&quot;https://en.wikipedia.org/wiki/Music_Player_Daemon&quot;&gt;mpd&lt;/a&gt;-compatible music player that can play local files and stream from services like Spotify and YouTube.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://nixos.org/&quot;&gt;NixOS&lt;/a&gt; has &lt;a href=&quot;https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/audio/mopidy/default.nix&quot;&gt;a package for Mopidy&lt;/a&gt; and several extensions. You can install them with &lt;a href=&quot;https://nixos.org/nix/manual/#ch-basic-package-mgmt&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;nix-env -i&lt;/code&gt;&lt;/a&gt;, but Mopidy will not detect the extensions, and it can be difficult to figure out why.&lt;/p&gt;

&lt;p&gt;This is Nix working &lt;a href=&quot;https://nixos.org/nix/manual/#ch-about-nix&quot;&gt;the way it is supposed to work&lt;/a&gt;: the extensions are Python libraries, and the build environment for the mopidy package can’t be altered by installing other packages.&lt;/p&gt;

&lt;p&gt;The solution is to make a new environment that depends on the mopidy package and any extension packages you want.&lt;/p&gt;

&lt;p&gt;It’s easy with &lt;a href=&quot;https://nixos.org/nix/manual/#sec-nix-shell&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;nix-shell&lt;/code&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nix-shell &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; mopidy mopidy-mopify mopidy-spotify &lt;span class=&quot;nt&quot;&gt;--run&lt;/span&gt; mopidy
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Turned into an executable script:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#! /usr/bin/env nix-shell&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#! nix-shell -p mopidy mopidy-mopify mopidy-spotify --run mopidy&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;There is also a &lt;a href=&quot;https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/audio/mopidy.nix&quot;&gt;mopidy service&lt;/a&gt;, used with something like this in &lt;code class=&quot;highlighter-rouge&quot;&gt;/etc/nixos/configuration.nix&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-nix highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mopidy&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;extensionPackages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pkgs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mopidy-spotify&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;pkgs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;mopidy-mopify&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;nv&quot;&gt;configuration&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    [spotify]&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    username = dade.murphy&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;    password = hack.the.planet&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;  ''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</description>
        <pubDate>Sun, 20 Mar 2016 00:00:00 +0000</pubDate>
        <link>https://blog.pclewis.com/2016/03/20/mopidy-with-extensions-on-nixos.html</link>
        <guid isPermaLink="true">https://blog.pclewis.com/2016/03/20/mopidy-with-extensions-on-nixos.html</guid>
        
        <category>nixos</category>
        
        
      </item>
    
      <item>
        <title>XMonad, Spacemacs Style</title>
        <description>&lt;h2 id=&quot;background&quot;&gt;Background&lt;/h2&gt;

&lt;p&gt;I’ve been using &lt;a href=&quot;http://xmonad.org&quot;&gt;XMonad&lt;/a&gt; for almost 10 years but I barely know my own key bindings. Every time I open &lt;code class=&quot;highlighter-rouge&quot;&gt;xmonad.hs&lt;/code&gt; I find bindings I don’t remember setting, doing things I’d forgotten were even possible. I’m hesitant to add new bindings because I know I’ll forget them.&lt;/p&gt;

&lt;p&gt;As a recent convert to &lt;a href=&quot;https://github.com/syl20bnr/spacemacs&quot;&gt;Spacemacs&lt;/a&gt;, one of the things I love most is that the key bindings are mnemonic key &lt;em&gt;sequences&lt;/em&gt;, with help that pops up when you hesitate along the way.&lt;/p&gt;

&lt;p&gt;I want the same thing in XMonad.&lt;/p&gt;

&lt;h2 id=&quot;making-it-so&quot;&gt;Making It So&lt;/h2&gt;

&lt;h3 id=&quot;key-sequences&quot;&gt;Key Sequences&lt;/h3&gt;

&lt;p&gt;The first problem was figuring out how to bind key sequences instead of key presses. I searched for things like “xmonad key sequence,” “xmonad multiple key bind,” “xmonad prefix key,” and so on, until finally &lt;a href=&quot;http://kojevnikov.com/xmonad-metacity-gnome.html&quot;&gt;a blog post by Alexander Kojevnikov&lt;/a&gt; pointed me in the right direction.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Actions-Submap.html&quot;&gt;XMonad.Actions.Submap&lt;/a&gt; lets you bind a key to the &lt;code class=&quot;highlighter-rouge&quot;&gt;submap&lt;/code&gt; action, which accepts another map of key bindings. When called, &lt;code class=&quot;highlighter-rouge&quot;&gt;submap&lt;/code&gt; intercepts the next keypress and dispatches accordingly.&lt;/p&gt;

&lt;h3 id=&quot;even-better-emacs-style-bindings&quot;&gt;Even Better: Emacs-style Bindings&lt;/h3&gt;

&lt;p&gt;From Submap I stumbled onto &lt;a href=&quot;http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Util-EZConfig.html&quot;&gt;XMonad.Util.EZConfig&lt;/a&gt;, which makes the key binding syntax much nicer. Instead of specifying a tuple with the modifier bitmask and appropriate &lt;code class=&quot;highlighter-rouge&quot;&gt;xK_&lt;/code&gt; variable, you just use a string with an Emacs-like notation. It even supports specifying a sequence of keys, so you don’t need to use Submap directly.&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;-- Using only Submap&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;modm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xK_x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;submap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fromList&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xK_w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spawn&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;xmessage 'woohoo!'&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)])&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;-- With EZConfig&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;M-x w&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spawn&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;xmessage 'woohoo!'&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;visual-feedback&quot;&gt;Visual Feedback&lt;/h3&gt;

&lt;p&gt;Submap and EZConfig don’t provide any kind of feedback that you’ve entered a submap, or expose any way to add your own. We can use &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;gt;&amp;gt;&lt;/code&gt; to call &lt;code class=&quot;highlighter-rouge&quot;&gt;spawn&lt;/code&gt; before &lt;code class=&quot;highlighter-rouge&quot;&gt;submap&lt;/code&gt;, but &lt;code class=&quot;highlighter-rouge&quot;&gt;submap&lt;/code&gt; blocks waiting for input; &lt;code class=&quot;highlighter-rouge&quot;&gt;dmenu&lt;/code&gt; won’t run because it can’t grab the keyboard, and &lt;code class=&quot;highlighter-rouge&quot;&gt;xmessage&lt;/code&gt; won’t appear because XMonad won’t notice the new window until after &lt;code class=&quot;highlighter-rouge&quot;&gt;submap&lt;/code&gt; exits.&lt;/p&gt;

&lt;p&gt;Luckily, &lt;a href=&quot;https://github.com/robm/dzen&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;dzen2&lt;/code&gt;&lt;/a&gt; works and is perfect for what I have in mind. We just have to go back to calling &lt;code class=&quot;highlighter-rouge&quot;&gt;submap&lt;/code&gt; manually:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;mySubmap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;submap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fromList&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xK_w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spawn&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;xmessage 'woohoo!'&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xmonad&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultConfig&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;additionalKeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;M-m&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spawn&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;echo Entered Submap | dzen2 -p 2&quot;&lt;/span&gt;
                       &lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mySubmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With no parameters, &lt;code class=&quot;highlighter-rouge&quot;&gt;dzen2&lt;/code&gt; closes when its input is closed. We can use &lt;code class=&quot;highlighter-rouge&quot;&gt;-p 2&lt;/code&gt; to keep it open for 2 seconds, but what we really want is for it to &lt;em&gt;wait&lt;/em&gt; a second before appearing, and to disappear when we exit the submap. With &lt;code class=&quot;highlighter-rouge&quot;&gt;spawnPipe&lt;/code&gt; from &lt;a href=&quot;http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Util-Run.html&quot;&gt;XMonad.Util.Run&lt;/a&gt; we can get a handle that we can write to and close with &lt;code class=&quot;highlighter-rouge&quot;&gt;System.IO&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;mySubmap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;submap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;M&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fromList&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;[((&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xK_w&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spawn&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;xmessage 'woohoo!'&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;dzen&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;handle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spawnPipe&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;sleep 1 &amp;amp;&amp;amp; dzen2&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hPutStrLn&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handle&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;message&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;action&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;hClose&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handle&lt;/span&gt;
  
&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;xmonad&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;defaultConfig&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;additionalKeys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;`&lt;/span&gt;
                &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;M-m&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dzen&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;In Submap&quot;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mySubmap&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(&lt;code class=&quot;highlighter-rouge&quot;&gt;io&lt;/code&gt; is necessary to lift the IO monad into the X monad, because Haskell)&lt;/p&gt;

&lt;h3 id=&quot;parsing-the-keymap&quot;&gt;Parsing the Keymap&lt;/h3&gt;

&lt;p&gt;Now we can pop up a message, how do we make it tell us what the keys do?&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Util-NamedActions.html&quot;&gt;XMonad.Util.NamedActions&lt;/a&gt; is an option, but it looks really cumbersome. I don’t want to have to think of documentation and keep it up to date. It might be possible to do something with &lt;a href=&quot;https://wiki.haskell.org/Template_Haskell&quot;&gt;Template Haskell&lt;/a&gt; to auto-generate names for actions, but that seems like too much work.&lt;/p&gt;

&lt;p&gt;Since I keep my bindings neatly formatted anyway, the easiest thing to do is just yank the keys and actions directly out of xmonad.hs.&lt;/p&gt;

&lt;p&gt;I know my submaps are always going to start with a line like &lt;code class=&quot;highlighter-rouge&quot;&gt;submapName =&lt;/code&gt; and end with a &lt;code class=&quot;highlighter-rouge&quot;&gt;]&lt;/code&gt; on a line by itself. &lt;a href=&quot;http://man7.org/linux/man-pages/man1/gawk.1.html&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt;&lt;/a&gt; makes it easy to grab a range of lines:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; ~/.xmonad/xmonad.hs | awk &lt;span class=&quot;s1&quot;&gt;'/^mySubmap/,/]$/'&lt;/span&gt;
mySubmap &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; submap &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; M.fromList &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;[((&lt;/span&gt;0, xK_w&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;, spawn &lt;span class=&quot;s2&quot;&gt;&quot;xmessage 'woohoo!'&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With a little &lt;a href=&quot;http://gnosis.cx/publish/programming/regular_expressions.html&quot;&gt;regular expression&lt;/a&gt; magic, &lt;a href=&quot;http://man7.org/linux/man-pages/man1/sed.1.html&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;sed&lt;/code&gt;&lt;/a&gt; can extract the import parts:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt; | sed &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1d;$d;s/.*xK_(.)\), (.*)\)$/\1 -&amp;gt; \2/'&lt;/span&gt;
w -&amp;gt; spawn &lt;span class=&quot;s2&quot;&gt;&quot;xmessage 'woohoo!'&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;(&lt;code class=&quot;highlighter-rouge&quot;&gt;-r&lt;/code&gt; swaps which kind of paren we need to quote, and &lt;code class=&quot;highlighter-rouge&quot;&gt;1d;$d&lt;/code&gt; trims the first and last line)&lt;/p&gt;

&lt;p&gt;With a bit of work you could do this with either &lt;code class=&quot;highlighter-rouge&quot;&gt;sed&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt; alone, but I think this way is simpler.&lt;/p&gt;

&lt;p&gt;Later, once we have a bunch of them, &lt;a href=&quot;http://man7.org/linux/man-pages/man1/column.1.html&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;column&lt;/code&gt;&lt;/a&gt; can wrap them into columns:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;~&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;i &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1..6&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;done&lt;/span&gt; | column
w -&amp;gt; spawn &lt;span class=&quot;s2&quot;&gt;&quot;xmessage 'woohoo!'&quot;&lt;/span&gt;	w -&amp;gt; spawn &lt;span class=&quot;s2&quot;&gt;&quot;xmessage 'woohoo!'&quot;&lt;/span&gt;
w -&amp;gt; spawn &lt;span class=&quot;s2&quot;&gt;&quot;xmessage 'woohoo!'&quot;&lt;/span&gt;	w -&amp;gt; spawn &lt;span class=&quot;s2&quot;&gt;&quot;xmessage 'woohoo!'&quot;&lt;/span&gt;
w -&amp;gt; spawn &lt;span class=&quot;s2&quot;&gt;&quot;xmessage 'woohoo!'&quot;&lt;/span&gt;	w -&amp;gt; spawn &lt;span class=&quot;s2&quot;&gt;&quot;xmessage 'woohoo!'&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now instead of calling &lt;code class=&quot;highlighter-rouge&quot;&gt;dzen2&lt;/code&gt; directly, we can call a shell script that contains this command pipeline:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;KEYMAP&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$KEYMAP&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;                                   &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; ~/.xmonad/xmonad.hs                          &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  | awk &lt;span class=&quot;s1&quot;&gt;'/^'&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$KEYMAP&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/,/]$/'&lt;/span&gt;                      &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  | sed &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'1d;$d;s/.*xK_(.)\), (.*)\)$/\1 -&amp;gt; \2/'&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
  | columns | expand
&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; | dzen2 &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; 5 &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;onstart&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;uncollapse
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A few things to note:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;columns&lt;/code&gt; outputs tab characters, which don’t work in dzen2. &lt;code class=&quot;highlighter-rouge&quot;&gt;expand&lt;/code&gt; converts them to spaces.&lt;/li&gt;
  &lt;li&gt;We need to run the pipeline in a subshell that ends with &lt;code class=&quot;highlighter-rouge&quot;&gt;; cat&lt;/code&gt; to connect &lt;code class=&quot;highlighter-rouge&quot;&gt;dzen2&lt;/code&gt;’s input channel to the output handle we have in XMonad.&lt;/li&gt;
  &lt;li&gt;To make dzen2 show multiple lines, we need the &lt;code class=&quot;highlighter-rouge&quot;&gt;-l&lt;/code&gt; parameter. This makes the first line the title, and the rest show up in an additional window that is hidden by default unless we add &lt;code class=&quot;highlighter-rouge&quot;&gt;-e onstart=uncollapse&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;positioning&quot;&gt;Positioning&lt;/h3&gt;

&lt;p&gt;The last piece of the puzzle is getting the help to popup on the bottom of whatever monitor has focus, and &lt;code class=&quot;highlighter-rouge&quot;&gt;dzen2&lt;/code&gt; doesn’t seem to have any easy way to do this. It does make it easy to manually set the location and dimensions, we just need to figure out what those are.&lt;/p&gt;

&lt;p&gt;We can get the location and dimensions of the focused screen in XMonad by stealing some code from &lt;code class=&quot;highlighter-rouge&quot;&gt;floatLocation&lt;/code&gt; in &lt;a href=&quot;http://xmonad.org/xmonad-docs/xmonad/src/XMonad-Operations.html&quot;&gt;XMonad.Operations&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;windowScreenSize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Window&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Rectangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;windowScreenSize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;withDisplay&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;ws&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gets&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;windowset&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;wa&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getWindowAttributes&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;w&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;bw&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;asks&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;borderWidth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fromMaybe&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ws&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pointScreen&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wa_x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wa&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fi&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wa_y&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;wa&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;screenRect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;screenDetail&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sc&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fi&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fromIntegral&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;focusedScreenSize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;Rectangle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;focusedScreenSize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;withWindowSet&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;windowScreenSize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fromJust&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;W&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;peek&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can then pass those to our script with something like:&lt;/p&gt;

&lt;div class=&quot;language-haskell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;keyMapDoc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;X&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;Handle&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;keyMapDoc&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kr&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;focusedScreenSize&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;handle&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;spawnPipe&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unwords&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;~/.xmonad/showHintForKeymap.sh&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;show&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rect_x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;show&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rect_y&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;show&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rect_width&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;show&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rect_height&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ss&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;handle&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The math is straightforward so I won’t cover it here. We end up with something like:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;LINE_HEIGHT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;14
&lt;span class=&quot;nv&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; ...&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;N_LINES&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;wc &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$INFO&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;OFFSET&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;LINE_HEIGHT &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; N_LINES&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;Y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$((&lt;/span&gt;BOTTOM &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; OFFSET&lt;span class=&quot;k&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$KEYMAP&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$INFO&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; | dzen2 &lt;span class=&quot;nt&quot;&gt;-h&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$LINE_HEIGHT&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$Y&lt;/span&gt; ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-result&quot;&gt;The Result&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/img/2016-03-19-xmonad.png&quot; alt=&quot;Screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s not quite nice enough to start a project called &lt;code class=&quot;highlighter-rouge&quot;&gt;spacenads&lt;/code&gt; yet, but it’s exactly what I wanted. I have made some more tweaks and gone a little further than is described here, but you can see what I’m actually using on &lt;a href=&quot;https://github.com/pclewis/dotfiles/tree/master/xmonad/.xmonad&quot;&gt;my github&lt;/a&gt;.&lt;/p&gt;

</description>
        <pubDate>Sat, 19 Mar 2016 00:00:00 +0000</pubDate>
        <link>https://blog.pclewis.com/2016/03/19/xmonad-spacemacs-style.html</link>
        <guid isPermaLink="true">https://blog.pclewis.com/2016/03/19/xmonad-spacemacs-style.html</guid>
        
        
      </item>
    
      <item>
        <title>Groovy Gotchas</title>
        <description>&lt;h2 id=&quot;mapkey&quot;&gt;Map[‘key’]&lt;/h2&gt;

&lt;p&gt;When calling putAt() on a Map with a String as a key, the Object version of putAt() is selected over the Map version. In other words, it will only call Map.put() if a property with the same name does not exist. However, calling getAt() on a Map will only call Map.get(), and will never return an object property.&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HashMap&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// any Map&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'x'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'x'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; 1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'x'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; 1&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;putAt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'x'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'x'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; 2&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'y'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'y'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; null&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'y'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; null&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;putAt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'y'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'y'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; null&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;codehaus&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;groovy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;runtime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;DefaultGroovyMethods&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;putAt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'y'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'y'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; 3 !?&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;B&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;hi&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'y'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; &quot;hi&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;B&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'y'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; &quot;hi&quot;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;C&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Map&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;y&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* implement Map methods */&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; 
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'y'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; null&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'y'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;];&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; null&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;ranges&quot;&gt;Ranges&lt;/h2&gt;

&lt;p&gt;The exclusive range operator (..&amp;lt;) generates a Range where the ending value is one step closer to the beginning value. The less-than symbol can be somewhat unintuitive for descending ranges.&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;enum&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;E&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ONE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;TWO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;FOUR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ONE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)..(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// [ONE, TWO, THREE]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ONE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)..&amp;lt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [ONE, TWO]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)..(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ONE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// [THREE, TWO, ONE]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;THREE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)..&amp;lt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ONE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;toList&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [THREE, TWO]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Indexing a List with a Range only considers &lt;code class=&quot;highlighter-rouge&quot;&gt;from&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;to&lt;/code&gt; values &lt;em&gt;after&lt;/em&gt; the above adjustment; the result of Range.toList() is irrelevant, and whether or not it was an exclusive range is not known. Three steps are performed to get the result:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;Negative values are normalized to positive values by adding them to List.size()&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;The result is generated from List.subList( min(from, to), max(from, to) )&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;If from &amp;gt; to, the result is reversed&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In Ruby, &lt;code class=&quot;highlighter-rouge&quot;&gt;a[0...-1]&lt;/code&gt; means “From the 0th element up to and excluding the last element,” whereas the ostensibly equivalent construct in Groovy, &lt;code class=&quot;highlighter-rouge&quot;&gt;a[0..&amp;lt;-1]&lt;/code&gt;, means “From the 0th element to the 0th element.”&lt;/p&gt;

&lt;div class=&quot;language-groovy highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; [0, 1, 2, 3, 4]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; [0, 1, 2, 3]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&amp;lt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; [0]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&amp;lt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; [0, 1, 2, 3, 4]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; [0, 1, 2, 3]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; [5, 4]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&amp;lt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;           &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; [5]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Compare to Ruby:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [0, 1, 2, 3, 4]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [0, 1, 2, 3]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [0, 1, 2, 3]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [0, 1, 2]&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;              &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; [0, 1, 2, 3]&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;             &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; []&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;            &lt;span class=&quot;c1&quot;&gt;# =&amp;gt; []&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Thu, 13 Oct 2011 03:16:32 +0000</pubDate>
        <link>https://blog.pclewis.com/2011/10/groovy-gotchas/</link>
        <guid isPermaLink="true">https://blog.pclewis.com/2011/10/groovy-gotchas/</guid>
        
        <category>groovy</category>
        
        <category>programming</category>
        
        <category>ruby</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>TIP: Fixing author in git history</title>
        <description>&lt;p&gt;I always forget to set up my user info on git on new machines before I check stuff in. It’s pretty easy to fix if there’s nobody else in your repo:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git filter-branch &lt;span class=&quot;nt&quot;&gt;--env-filter&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;
  export GIT_AUTHOR_NAME=Dade&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Murphy &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;
         GIT_AUTHOR_EMAIL=zer0cool@example.com &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;
         GIT_COMMITTER_NAME=Dade&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\ &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Murphy &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;
         GIT_COMMITTER_EMAIL=zer0cool@example.com &quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Source: &lt;a href=&quot;http://serverfault.com/questions/12373/how-do-i-edit-gits-history-to-correct-an-incorrect-email-address-name&quot;&gt;serverfault&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Sat, 23 Oct 2010 22:34:36 +0000</pubDate>
        <link>https://blog.pclewis.com/2010/10/tip-fixing-author-in-git-history/</link>
        <guid isPermaLink="true">https://blog.pclewis.com/2010/10/tip-fixing-author-in-git-history/</guid>
        
        
        <category>tips</category>
        
      </item>
    
      <item>
        <title>Starcraft vs Monty Hall</title>
        <description>&lt;p&gt;If you’re not familiar with the &lt;a href=&quot;http://en.wikipedia.org/wiki/Monty_Hall_problem&quot;&gt;Monty Hall problem&lt;/a&gt;, it goes something like this:&lt;/p&gt;

&lt;p&gt;There are three doors, and one of them has a prize. You choose one of the doors, and Monty opens one of the others that is not a winner. Now you have the option to stick with your original choice, or switch to the remaining door. It might seem counter-intuitive, but switching doubles your odds of winning.&lt;/p&gt;

&lt;p&gt;Some people have attempted to apply the same logic to scouting as &lt;a href=&quot;http://starcraft.wikia.com/wiki/Zerg&quot;&gt;Zerg&lt;/a&gt; using an overlord and a drone in &lt;a href=&quot;http://en.wikipedia.org/wiki/Starcraft&quot;&gt;Starcraft&lt;/a&gt;. Stated similarly, the problem goes like this:&lt;/p&gt;

&lt;p&gt;There are three starting locations, and one of them has your enemy base. You send a drone to one location, and your overlord gets to one of the other locations and discovers no enemy base. Now you have the option to stick with your original choice, or send your drone to the remaining location.&lt;/p&gt;

&lt;p&gt;Sounds the same, but in this case, switching has no effect on your odds of winning. It is the same as the “&lt;a href=&quot;http://probability.ca/jeff/writing/montyfall.pdf&quot;&gt;Monty Fall&lt;/a&gt;” or “Ignorant Monty” variant of the Monty Hall problem, where Monty opens a door completely at random rather than one which is a non-winner.&lt;/p&gt;

&lt;p&gt;The difference is because in the classic Monty Hall problem, you are initially choosing one door, which gives you 1/3 odds of your first choice being right. If you could choose to switch to &lt;em&gt;both&lt;/em&gt; other doors, you’d obviously have a 2/3 chance of winning. In fact, this is &lt;em&gt;exactly&lt;/em&gt; what you are doing when you switch, even after one of the doors has been revealed.&lt;/p&gt;

&lt;p&gt;In the Starcraft problem, you are choosing &lt;em&gt;two&lt;/em&gt; locations to begin with, which gives you a 2/3 chance of being right. If you choose to switch your drone to the remaining location at any point, the overlord still has a 1/3 chance and the drone still has a 1/3 chance. In the Monty Hall problem, you switch from only an unknown door (1/3), to the empty door and an unknown door (2/3). In the Starcraft problem, you switch from both an empty location and an unknown location (2/3), to the same empty location and a different unknown location (2/3).&lt;/p&gt;

&lt;p&gt;To demonstrate this visually, I’ve made a &lt;a href=&quot;http://blog.pclewis.com/scvsmh/&quot;&gt;simulator&lt;/a&gt; in Javascript.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update (5/3):&lt;/strong&gt;
I added a “Monty Hall mode” to the simulator, the implementation of which may help make this even clearer. Normally, I choose two random locations from the possible enemy starting points, and send the overlord to the first and the drone to the second. This leads to 3 possibilities with an equal chance of occuring: the overlord finds the base, the drone finds the base, or neither finds the base. Only in the final case, which occurs 1/3 of the time, would it be correct to switch. In “Monty Hall mode,” the overlord is not allowed to find the base - so the 1/3 of the time where the overlord would normally have found the base, is now added to the 1/3 of the time when neither finds the base, making it correct to switch 2/3s of the time.&lt;/p&gt;

&lt;p&gt;I also added a “Stupid Overlord mode” which demonstrates that the order is important. If the overlord chooses an empty base first, rather than the drone choosing first, the chances of the drone being correct are (obviously) 1/2.
&lt;!-- more --&gt;&lt;/p&gt;

</description>
        <pubDate>Sun, 02 May 2010 21:46:11 +0000</pubDate>
        <link>https://blog.pclewis.com/2010/05/starcraft-vs-monty-hall/</link>
        <guid isPermaLink="true">https://blog.pclewis.com/2010/05/starcraft-vs-monty-hall/</guid>
        
        <category>javascript</category>
        
        <category>starcraft</category>
        
        <category>statistics</category>
        
        
        <category>misc</category>
        
      </item>
    
      <item>
        <title>Mixing Up Code and Data</title>
        <description>&lt;p&gt;From buffer overflows to cross-site scripting, decades of software security flaws can be traced back to a simple design problem: executable code (or otherwise specially meaningful data), and non-executable, black-box data are intermingled in the same channel. To execute arbitrary code, traditional buffer overflow exploits rely on non-executable data trampling execution state and eventually causing data to be executed as code. Cross-site scripting exploits, and all traditional injection exploits, work when intermediary systems fail to identify the difference between code and data in exactly the same way as some other system.&lt;/p&gt;

&lt;p&gt;To prevent these exploits, developers are generally advised to canonicalize input and encode data in output. While this is correct, I think it is important to also understand that &lt;em&gt;it shouldn’t be that way&lt;/em&gt;. Developers should have to go an extra mile to cause data to be interpreted as code, not the other way around.
&lt;!-- more --&gt;
Consider this common SQL injection scenario:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mysql_query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;select id, name, pass from users where name='&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;'&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$db&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;While it’s clear that $name is simply data to the developer, it’s being crammed into a string along with code and handed off to another system for re-interpretation. A common solution to prevent injection is something like this:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$query&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;select id, name, pass from users where name='%s' &quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mysql_real_escape_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mysql_query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$query&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$db&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s true that this solution fixes the vulnerability in this instance, but it’s a heavy burden: always remember to add a whole bunch of code every time you perform this incredibly common task, or you will introduce one of the most serious vulnerabilities possible into your application. In my opinion, even though the code may be “secure,” it is still wrong. You are still mixing up code and data in the same place on the same channel. Here is a better solution:&lt;/p&gt;

&lt;div class=&quot;language-php highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$stmt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$mysqli&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;prepare&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;select id, name, pass from users where name=?&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$stmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;bind_param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;s&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$stmt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This looks similar, but it’s important to understand how it works. The first line sends all of the code to be parsed and prepared by the server. Data to be filled in later is represented by question marks, which can only be used where data is expected. After this point, nothing is re-interpreted. When we send the data on the second line, the server is only reading data, and no special encoding is required to prevent it from being treated as code.&lt;/p&gt;

&lt;p&gt;Even though it suffers the same criticism of being extra code every time you want to execute a SQL query, a developer used to coding this way is much less likely to make a mistake than a developer used to the previous example. The statements could also be prepared in an initializer somewhere completely different instead of right next to where data is being bound, to make it even harder to make a mistake.&lt;/p&gt;

&lt;p&gt;Imagine if HTML/HTTP had something similar:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;data[0,16];&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;body&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ni&quot;&gt;&amp;amp;data[17,256];&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
Data until EOF. &lt;span class=&quot;c&quot;&gt;&amp;lt;!-- &amp;amp;amp; No possibility of being interpreted as html. &amp;lt;script&amp;gt;alert(1);&amp;lt;/script&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that the data part is a complete black box and terminated out-of-band (by closing the connection). There aren’t lengths or other special markers embedded in the data. I’m not suggesting this is a realistic possibility for HTML or any other established standard. I just want to make the point that a protocol which makes it impossible to confuse code and data is invulnerable to injection attacks by default.&lt;/p&gt;

&lt;p&gt;A related idea is identifying the source of data. When an application includes user input in its own output, or in SQL statements, or anywhere else, it takes responsibility for it; to other applications, it’s data (or code) coming from the first application, not data coming from a user or third-party application somewhere else.&lt;/p&gt;

&lt;p&gt;In cases where user input needs to be specially interpreted, especially by some other application - when you want to let people include a little HTML in a post, for example - then you have a more difficult problem which can’t be solved by shoving it all into a separate black box. But imagine how nice it would be if you could specify that some bit of HTML was from a user, or some other website (perhaps with digital signatures), or whatever, and the browser could handle sandboxing and cross-domain policies and everything else it already has the ability to do.&lt;/p&gt;

&lt;p&gt;I think it is important to address this idea up front not just when designing a protocol or file format, but when designing APIs and internal interfaces to existing systems. Even if you have to output HTML or actual SQL statements, an interface to generate the output which cleanly separates code and data can relieve the burden from developers, isolate potential weaknesses in one place, and go a long way to improve the security of a system.&lt;/p&gt;
</description>
        <pubDate>Sat, 01 May 2010 08:12:56 +0000</pubDate>
        <link>https://blog.pclewis.com/2010/05/mixing-up-code-and-data/</link>
        <guid isPermaLink="true">https://blog.pclewis.com/2010/05/mixing-up-code-and-data/</guid>
        
        
        <category>essays</category>
        
      </item>
    
      <item>
        <title>TIP: Using GDB as an Interactive C Shell</title>
        <description>&lt;p&gt;Many programming languages come with some way to run an interactive shell, or &lt;a href=&quot;http://en.wikipedia.org/wiki/REPL&quot;&gt;REPL (read-eval-print loop)&lt;/a&gt;. This makes it extremely easy to test little bits of code and understand exactly what they do, and is invaluable when learning a new language or library. For example:&lt;/p&gt;

&lt;p&gt;What’s the result of &lt;code class=&quot;highlighter-rouge&quot;&gt;(unsigned int)atoi(&quot;4294967295&quot;)&lt;/code&gt; in C?&lt;/p&gt;

&lt;p&gt;Even if you know the answer, how quickly can you prove it? How concisely can you communicate the proof via IM or email? What if it’s a poorly documented third-party library function, and not a standard one?&lt;/p&gt;

&lt;p&gt;For quick tasks, you can just use &lt;a href=&quot;http://www.gnu.org/software/gdb/&quot;&gt;gdb&lt;/a&gt; which is probably already present on any system that has &lt;a href=&quot;http://gcc.gnu.org/&quot;&gt;gcc&lt;/a&gt;. Just fire up gdb on any binary, set a breakpoint on main, and run. When it stops you will be able to call functions and examine their results, and many other common REPL tasks. The binary doesn’t matter much, but you should prefer ones with debugging symbols, and if you want to call functions in a particular library, you should use a binary that is linked to that library.&lt;/p&gt;

&lt;p&gt;Example session:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;~%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Breakpoint&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x8048452&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Starting&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;program&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;home&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pcl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sandbox&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;test&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Breakpoint&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x08048452&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;malloc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1234&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sprintf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello %d&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12345&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12345&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12345&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x96c6008&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello 170287977&quot;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;atoi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;-1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4294967295&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;unsigned&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;atoi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;4294967295&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2147483647&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;gdb lets you use arbitrarily-named, untyped convenience variables, as you can see in the example. The only practical difference between &lt;code class=&quot;highlighter-rouge&quot;&gt;print $var = expr&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;call $var = expr&lt;/code&gt;, and &lt;code class=&quot;highlighter-rouge&quot;&gt;set $var = expr&lt;/code&gt; seems to be that set does not additionally assign the result to a history variable. Obviously you also have the full debugging facilities of gdb available as well.&lt;/p&gt;

&lt;p&gt;It is also possible to do this on stripped binaries with no ‘main’ function, but there are many disadvantages:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;~%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;which&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;`&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inf&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;files&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;Entry&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;point&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x8048be0&lt;/span&gt;	&lt;span class=&quot;mh&quot;&gt;0x08048154&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x08048167&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interp&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x8048be0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;Breakpoint&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x8048be0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For a fully featured REPL for C, check out &lt;a href=&quot;http://neugierig.org/software/c-repl/&quot;&gt;c-repl&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Fri, 26 Mar 2010 20:13:54 +0000</pubDate>
        <link>https://blog.pclewis.com/2010/03/tip-using-gdb-as-an-interactive-c-shell/</link>
        <guid isPermaLink="true">https://blog.pclewis.com/2010/03/tip-using-gdb-as-an-interactive-c-shell/</guid>
        
        <category>c/c++</category>
        
        <category>gdb</category>
        
        <category>tips</category>
        
        
        <category>tips</category>
        
      </item>
    
      <item>
        <title>Analysis of Gemini Cybernetics CDS </title>
        <description>&lt;p&gt;There have been some rumors going around about a new third-party system for Second Life. The system attempts to detect avatars using third-party clients capable of duplicating objects without the creator’s permission, and the rumors are that it uses some kind of QuickTime exploit or other nefarious means to actually examine the contents of your hard drive or otherwise invade your privacy without permission. I decided to take a quick look to see what it’s all about.&lt;/p&gt;

&lt;p&gt;The system in question is called &lt;a href=&quot;https://www.xstreetsl.com/modules.php?name=Marketplace&amp;amp;file=item&amp;amp;ItemID=2138424&quot;&gt;GEMINI CDS Ban Relay&lt;/a&gt; and is advertised as a simple object which detects avatars entering your sim, and uses “a team of bots with special abilities” to determine if the avatar is “harmful.” If they are, it adds them to an external database, and can optionally ban or teleport them home. Entries in the database are permanent, so if an avatar has been considered harmful once, they are always considered harmful in the future. It claims to use several frequently updated methods to detect “illegitimate” clients.&lt;/p&gt;

&lt;p&gt;The most obvious detection method, and the only one I discovered, is a script that triggers as soon as you enter a protected sim and &lt;a href=&quot;http://wiki.secondlife.com/wiki/LlParcelMediaCommandList&quot;&gt;tells your client&lt;/a&gt; to load up a special media URL. Using a tool like &lt;a href=&quot;http://www.wireshark.org/&quot;&gt;Wireshark&lt;/a&gt; or &lt;a href=&quot;http://ngrep.sourceforge.net/&quot;&gt;ngrep&lt;/a&gt;, it is trivial to watch the HTTP request.&lt;/p&gt;

&lt;!-- more --&gt;

&lt;p&gt;&lt;img src=&quot;http://blog.pclewis.com/wp-content/uploads/2010/03/pcap1-300x203.jpg&quot; alt=&quot;Packet Capture&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Broken down, the requested URL in my case was:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;http://media.syscast.net/youtube.php
  ? licensekey = KBVaQkxGH1lDVRdBWA1GVEdaTFpQF1ReWUcREU9YEFxBRgxE
  &amp;amp; title      = BEYeQR8TAxxOLE8eBk0T
  &amp;amp; licensedon = B1IAQhUG
  &amp;amp; tvowner    = eBVbGUdLQFxeVA%3D%3D
  &amp;amp; videoid    = eEJVE0xDHwxZAUQSWBJFARMJV1RTE19BWUETGBMNQg0%3D
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At a glance, the values are obviously all Base64 encoded – the trailing %3Ds on the last two fields are a dead giveaway. Decoding them doesn’t produce anything human-readable, though; one online service gives me “(ZBLFYCUAXFTGZLZPT^YGOX\AFD” for the first field.&lt;/p&gt;

&lt;p&gt;It’s easy to decode them in Ruby, where we can play with them a little more:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;irb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;002&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;CIPHERTEXT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Base64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;decode64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'KBVaQkxGH1lDVRdBWA1GVEdaTFpQF1ReWUcREU9YEFxBRgxE'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;(&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\025&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ZBLF&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\037&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;YCU&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\027&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;AX&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\r&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;FTGZLZP&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\027&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;T^YG&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\021\021&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;OX&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\020\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;AF&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\f&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;D&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;irb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;003&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;CIPHERTEXT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;36 bytes is the same length as a &lt;a href=&quot;http://en.wikipedia.org/wiki/UUID&quot;&gt;UUID&lt;/a&gt; in canonical form, so it’s a pretty reasonable guess that this is my avatar’s UUID encrypted somehow. The only real encryption facility LSL makes available is &lt;a href=&quot;http://wiki.secondlife.com/wiki/LlXorBase64StringsCorrect&quot;&gt;XORing Base64-encoded strings together&lt;/a&gt;. &lt;a href=&quot;http://en.wikipedia.org/wiki/Xor&quot;&gt;XOR&lt;/a&gt; has an interesting property: a ⊕ b = c ⇒ a ⊕ c = b; that is, if XORing some plaintext and some key produces some ciphertext, then XORing that ciphertext and the plaintext produces the key. Let’s give it a shot:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;irb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;004&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;PLAINTEXT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'a27b84f0-2757-4176-9579-43a181d4a5a0'&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a27b84f0-2757-4176-9579-43a181d4a5a0&quot;&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;irb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;007&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;CIPHERTEXT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each_with_index&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;^&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;PLAINTEXT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])};&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;key&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;I'm trying to replace msmtp with smt&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That was easy enough. Using the key to decode the rest of the fields, we can see what is really being sent:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;http://media.syscast.net/youtube.php
  ? licensekey = a27b84f0-2757-4176-9579-43a181d4a5a0
  &amp;amp; title      = Masakazu Kojima
  &amp;amp; licensedon = Numbat
  &amp;amp; tvowner    = 1269399503
  &amp;amp; videoid    = 1e8381fe7fdf727dce67632245c8dd6e
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The second field (title) turns out to be my avatar name, followed by the sim name (licensedon), a UNIX time value (tvowner), and what looks like an MD5 hash (videoid). The time value is apparently used to prevent &lt;a href=&quot;http://en.wikipedia.org/wiki/Replay_attack&quot;&gt;replay attacks&lt;/a&gt;: it is possible to immediately replay the request exactly and get a success response, but after about 30 seconds it causes an internal server error instead.&lt;/p&gt;

&lt;p&gt;Visiting the parcel again to get another URL shows that only the time and MD5 hash change. Tampering with the values causes an immediate error redirect, which suggests that the MD5 hash is a signature to prevent forged messages. So, even though we could encrypt arbitrary values and send them, we’d need to know how the signature is generated for them to work.&lt;/p&gt;

&lt;p&gt;The response from the server is innocent enough:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;&amp;lt;!--
--&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;bgcolor=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#7f7f7f&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;leftmargin=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;topmargin=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;video-background.gif&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;width=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2000px&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;height=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;2000px&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;border=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0px&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The video-background.gif file is just a transparent 1x1 GIF image:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;00000000  47 49 46 38 39 61 01 00  01 00 80 00 00 7f 7f 7f  |GIF89a..........|
00000010  00 00 00 21 f9 04 00 00  00 00 00 2c 00 00 00 00  |...!.......,....|
00000020  01 00 01 00 00 02 02 44  01 00 3b                 |.......D..;|
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;These are the only requests that are performed. Nothing nefarious appears to be taking place. There is no evidence of any kind of exploit, or the transmission of any kind of private information. So how does the service detect “illegitimate” clients?&lt;/p&gt;

&lt;p&gt;The magic turns out to be in the “User-Agent” request header, which identifies the client. In my case: &lt;code class=&quot;highlighter-rouge&quot;&gt;Mozilla/5.0 (Windows; U; Windows NT 6.0; chrome://navigator/locale/navigator.properties; rv:1.8.1.21) Gecko/20090305 SecondLife/Emerald Viewer (default skin)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;By using &lt;a href=&quot;http://curl.haxx.se/&quot;&gt;curl&lt;/a&gt; to replay an old request, and simply replacing “Emerald Viewer” with the name of a random client from &lt;a href=&quot;http://onyx.modularsystems.sl/viewer_reference.html&quot;&gt;the Onyx project&lt;/a&gt; (NeilLife), I was able to get the system to ban an alternate account I created. Note that this worked even though the time value was old, and the HTTP response status was a 500 error, so it would appear that the system to prevent replay attacks is broken. Looks like they’re up to at least 1 false positive, even if it’s a technicality. Also note that the actual response body did not change, so there doesn’t seem to be any kind of exploit that is only sent to users of “bad” clients.&lt;/p&gt;

&lt;p&gt;Using the same IP address and computer, I was able to go back to the same parcel on my main account with no trouble.&lt;/p&gt;

&lt;h2 id=&quot;conclusions&quot;&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;Despite all the subterfuge, the Gemini CDS system seems to simply rely on “illegitimate” clients to identify themselves in an HTTP request. The message encryption is trivial to break, and it would seem that is only a matter of time before someone cares enough to figure out how to forge the message signature. It is trivial to avoid detection by this method, though the system may employ additional detection methods: the common way for third-party clients to identify each other is by the unique texture UUIDs they use for skin layer protection, which is passive and undetectable.&lt;/p&gt;

&lt;p&gt;There is no evidence that the system uses any kind of exploit or other nefarious tactic. The system does not appear to record any data other than the avatar and client self-identification information.&lt;/p&gt;
</description>
        <pubDate>Thu, 25 Mar 2010 03:13:55 +0000</pubDate>
        <link>https://blog.pclewis.com/2010/03/analysis-of-gemini-cybernetics-cds/</link>
        <guid isPermaLink="true">https://blog.pclewis.com/2010/03/analysis-of-gemini-cybernetics-cds/</guid>
        
        
        <category>second life</category>
        
      </item>
    
      <item>
        <title>TIP: Make bash tab completion ignore .svn directories</title>
        <description>&lt;p&gt;Having to tab through the fifty million otherwise empty “net/mycompany/project/unit/subunit” directories that the Java ecosystem necessitates has consistently driven me crazy because completion stops at each step to let me choose the .svn directory, and I have to look and type the first letter of the directory I actually want to make it continue.&lt;/p&gt;

&lt;p&gt;It’s actually really easy to fix this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;FIGNORE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;.svn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;$FIGNORE is just a colon-separated list of suffixes to ignore when doing tab completion.&lt;/p&gt;
</description>
        <pubDate>Tue, 16 Mar 2010 15:50:45 +0000</pubDate>
        <link>https://blog.pclewis.com/2010/03/tip-make-bash-tab-completion-ignore-svn-directories/</link>
        <guid isPermaLink="true">https://blog.pclewis.com/2010/03/tip-make-bash-tab-completion-ignore-svn-directories/</guid>
        
        <category>bash</category>
        
        <category>tips</category>
        
        
        <category>tips</category>
        
      </item>
    
  </channel>
</rss>
