<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>ramblinations</title><link href="https://www.ramblinations.com/" rel="alternate"></link><link href="https://www.ramblinations.com/feeds/atom.xml" rel="self"></link><id>https://www.ramblinations.com/</id><updated>2014-02-22T10:52:00-07:00</updated><entry><title>Koding with PHPStorm</title><link href="https://www.ramblinations.com/koding-with-phpstorm.html" rel="alternate"></link><updated>2014-02-22T10:52:00-07:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2014-02-22:koding-with-phpstorm.html</id><summary type="html">&lt;p&gt;A year or so ago I stumbled over &lt;a href="https://koding.com"&gt;Koding&lt;/a&gt; (my &lt;a href="https://koding.com/R/gemma"&gt;referral&lt;/a&gt;, if you're feeling benevolent), a social development platform that gives you (and everybody on your team) a disposable Ubuntu virtual machine, a web-based SSH terminal and code editor, and a giant network of fellow devs. It's a nifty place, and I've used it to collaborate with friends, teach myself Django and R and AngularJS and CoffeeScript, work through &lt;a href="https://github.com/ellotheth/coursera-algo-i"&gt;Coursera algorithms homework&lt;/a&gt;, develop new web applications, test &lt;a href="https://github.com/ellotheth/bulletphp-site"&gt;documentation&lt;/a&gt;, play with Node modules I don't want on my regular machine, and so on, ad infinitum. The Icelandic team behind it wants to &lt;a href="https://www.youtube.com/watch?v=CMRvf_YECAo"&gt;make the world a better place&lt;/a&gt;. It's unique. Naturally, I wanted to hook it up to &lt;a href="http://www.jetbrains.com/phpstorm/"&gt;PHPStorm&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Koding's walled garden&lt;/h2&gt;
&lt;p&gt;Koding VMs sit behind a proxy, so SSH-ing in from an external system already requires &lt;a href="http://learn.koding.com/ssh-into-your-koding-vm/"&gt;some finangling&lt;/a&gt;. PHPStorm's &lt;a href="https://www.youtube.com/watch?v=AHK20LWEWXQ"&gt;remote deployment system&lt;/a&gt; is entirely finangle-free, so getting it communicating with Koding would be impossible without our secret weapon: SSH tunnels!&lt;/p&gt;
&lt;h2&gt;Tunnelling through&lt;/h2&gt;
&lt;p&gt;I already had a &lt;a href="http://www.chiark.greenend.org.uk/~sgtatham/putty/"&gt;PuTTY&lt;/a&gt; session saved for Koding, so I copied it to preserve the proxy settings. (I'm going to assume you've already got external SSH access to your VM working. If you don't, check out the &lt;a href="http://learn.koding.com/ssh-into-your-koding-vm/"&gt;official docs&lt;/a&gt;--I even helped write them!)&lt;/p&gt;
&lt;h3&gt;Create the tunnel&lt;/h3&gt;
&lt;p&gt;In my PuTTY config, I loaded up my copied Koding session and found &lt;em&gt;Connection&lt;/em&gt; → &lt;em&gt;SSH&lt;/em&gt; → &lt;em&gt;Tunnels&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img alt="PuTTY config - Tunnels" src="/static/images/putty_create_tunnel.png" /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;I checked both boxes at the top.&lt;/li&gt;
&lt;li&gt;I set &lt;em&gt;Source port&lt;/em&gt; to an unused port on my local system.&lt;/li&gt;
&lt;li&gt;I set the &lt;em&gt;Destination&lt;/em&gt; to &lt;code&gt;localhost:22&lt;/code&gt; (note that that's &lt;code&gt;localhost&lt;/code&gt; relative to my VM, not to my local system), and selected the &lt;em&gt;Local&lt;/em&gt; option.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These settings create a "tunnel" that sends any local traffic on port &lt;code&gt;12345&lt;/code&gt; through an SSH window to my VM. (And remember, the Koding proxy server is saved already, so I don't have to mess with it again.)&lt;/p&gt;
&lt;p&gt;Since I'm not going to be interacting with the PuTTY terminal for this session, I disabled the shell entirely in &lt;em&gt;Connection&lt;/em&gt; → &lt;em&gt;SSH&lt;/em&gt;...&lt;/p&gt;
&lt;p&gt;&lt;img alt="PuTTY config - Disabling the shell" src="/static/images/putty_disable_shell.png" /&gt;&lt;/p&gt;
&lt;p&gt;...and renamed the window itself in &lt;em&gt;Window&lt;/em&gt; → &lt;em&gt;Behavior&lt;/em&gt;:&lt;/p&gt;
&lt;p&gt;&lt;img alt="PuTTY config - Name the window" src="/static/images/putty_set_title.png" /&gt;&lt;/p&gt;
&lt;p&gt;When I save and open the session, I get a non-interactive terminal that does nothing but authenticate me and set up the tunnel:&lt;/p&gt;
&lt;p&gt;&lt;img alt="PuTTY tunnel terminal" src="/static/images/putty_koding_tunnel.png" /&gt;&lt;/p&gt;
&lt;p&gt;Perfect! Whenever I want to use my Koding tunnel, I'll run the new session and let it sit. You can even test it: Open the tunnel, and then fire up a brand new PuTTY session pointed at &lt;code&gt;localhost:12345&lt;/code&gt;. You'll get shunted through the tunnel and end up in your Koding VM.&lt;/p&gt;
&lt;h3&gt;Send PHPStorm to the other side&lt;/h3&gt;
&lt;p&gt;You can probably guess where this is going: To hook up PHPStorm's &lt;a href="http://www.jetbrains.com/phpstorm/webhelp/deployment.html"&gt;remote deployment&lt;/a&gt;, we'll send it through the tunnel. Create your new project with the &lt;em&gt;Remote host, files accessible via SFTP&lt;/em&gt; option:&lt;/p&gt;
&lt;p&gt;&lt;img alt="PHPStorm - Create project" src="/static/images/phpstorm_koding_scenario.png" /&gt;&lt;/p&gt;
&lt;p&gt;When PHPStorm asks you for connection settings on the next screen, direct it to &lt;code&gt;localhost&lt;/code&gt; on port &lt;code&gt;12345&lt;/code&gt;. (Make sure the tunnel is running first!) All your other connection information (username, password, etc.) will stay the same, as if you were connecting to your Koding VM normally. (Note that if you're using key authentication, you'll need to &lt;a href="https://stackoverflow.com/questions/2224066/how-to-convert-ssh-keypairs-generated-using-puttygenwindows-into-key-pairs-use"&gt;export your *.ppk file&lt;/a&gt; to OpenSSH format.)&lt;/p&gt;
&lt;p&gt;&lt;img alt="PHPStorm - Add remote server" src="/static/images/phpstorm_koding_server.png" /&gt;&lt;/p&gt;
&lt;p&gt;That's it! PHPStorm can now deploy your project directly to your VM--it'll even &lt;a href="https://www.jetbrains.com/phpstorm/webhelp/run-debug-configuration-phpunit-on-server.html"&gt;run your PHPUnit tests&lt;/a&gt; for you. You'll need to set up &lt;a href="http://www.jetbrains.com/phpstorm/webhelp/deployment-mappings-tab.html"&gt;root paths and directory mappings&lt;/a&gt;, but the hard part's over.&lt;/p&gt;</summary><category term="tool"></category><category term="howto"></category><category term="php"></category></entry><entry><title>couples counseling for PHPStorm and MySQL</title><link href="https://www.ramblinations.com/couples-counseling-phpstorm-mysql.html" rel="alternate"></link><updated>2014-02-16T12:18:00-07:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2014-02-16:couples-counseling-phpstorm-mysql.html</id><summary type="html">&lt;p&gt;I have drunk the koolaid, and it is purple and orange. Swirled. Without mixing. Because &lt;em&gt;magic&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I thought &lt;a href="http://www.jetbrains.com/"&gt;JetBrains&lt;/a&gt; just made Eclipse knockoffs until I started watching the short &lt;a href="http://angularjs.org/"&gt;AngularJS&lt;/a&gt; tutorials at &lt;a href="https://egghead.io/tags/AngularJS"&gt;egghead.io&lt;/a&gt;. Resident guru &lt;a href="https://twitter.com/johnlindquist"&gt;John Lindquist&lt;/a&gt; wields &lt;a href="http://www.jetbrains.com/webstorm/"&gt;WebStorm&lt;/a&gt; like a syntax-highlighted scalpel, flying through line after line of auto-generated code as easily as most of us breathe. I got excited just watching. The AngularJS tutorial content is great too, but &lt;em&gt;that editor&lt;/em&gt;. I'm fast in &lt;a href="http://www.vim.org/"&gt;&lt;code&gt;vim&lt;/code&gt;&lt;/a&gt;, but not that fast.&lt;/p&gt;
&lt;p&gt;On the other hand, WebStorm doesn't really touch my mostly-PHP day job. Enter &lt;a href="https://twitter.com/mathiasverraes"&gt;Mathias Verraes&lt;/a&gt; and his &lt;a href="https://www.youtube.com/watch?v=S9pKJxOPmWM"&gt;refactoring tutorial&lt;/a&gt; in &lt;a href="http://www.jetbrains.com/phpstorm/"&gt;PHPStorm&lt;/a&gt;. Same blazing speed and mobility as WebStorm, but now with PHPUnit integration and coverage reports! Insanity. I caved. Down the rabbit hole I went.&lt;/p&gt;
&lt;h2&gt;Feet get wet&lt;/h2&gt;
&lt;p&gt;My base OS is Windows, so I do a lot of work in local Linux virtual machines. Fortunately, PHPStorm has &lt;a href="https://www.jetbrains.com/phpstorm/webhelp/new-project-from-existing-files-wizard.html"&gt;lots of options&lt;/a&gt; for talking to remote servers. I mounted the VM project directory on my host with &lt;a href="http://code.google.com/p/win-sshfs/"&gt;win-sshfs&lt;/a&gt; and chose PHPStorm's &lt;em&gt;Remote server, mounted drive&lt;/em&gt; option when I created the project. Pretty progress bar, couple spinny cursors, and I was in. The very first tip-of-the-day (don't turn them off!) told me to check out the tool shortcuts in the bottom left corner:&lt;/p&gt;
&lt;p&gt;&lt;img alt="tool menu" src="/static/images/phpstorm_tools.png" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Project&lt;/em&gt;, &lt;em&gt;TODO&lt;/em&gt;, &lt;em&gt;Favorites&lt;/em&gt;, blah blah, &lt;em&gt;Database&lt;/em&gt;--wait, what?&lt;/p&gt;
&lt;p&gt;Choose that &lt;em&gt;Database&lt;/em&gt; option, and you'll get a full data source manager, supporting about a dozen engines. I plugged in the settings for my VM's MySQL database, hit &lt;em&gt;Connect&lt;/em&gt;, and...it didn't work!&lt;/p&gt;
&lt;h2&gt;Why is it ignoring my database?!&lt;/h2&gt;
&lt;p&gt;This particular VM was running Debian Wheezy. MySQL configuration defaults may be different for other distributions, but here's what I had to do to get PHPStorm and MySQL talking:&lt;/p&gt;
&lt;h3&gt;Don't use &lt;code&gt;bind_address&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;By default, MySQL binds to (i.e. only accepts connections from) &lt;code&gt;127.0.0.1&lt;/code&gt;. You want to connect from your VM host, so comment out the &lt;code&gt;bind_address&lt;/code&gt; line in your MySQL configuration (&lt;code&gt;/etc/mysql/my.cnf&lt;/code&gt;):&lt;/p&gt;
&lt;p&gt;&lt;img alt="commented bind address" src="/static/images/mysql_bind.png" /&gt;&lt;/p&gt;
&lt;p&gt;(Note that &lt;em&gt;you should not do this on any machine that's accessible from outside your local network&lt;/em&gt;. It's bad. It's &lt;em&gt;so&lt;/em&gt; bad.But we're working with a local VM right now, so we don't care!)&lt;/p&gt;
&lt;h3&gt;Create a user with privileges to connect from anywhere.&lt;/h3&gt;
&lt;p&gt;Again by default, MySQL's root user only has local connection privileges--it can't connect from outside the VM. If you don't have one already, you'll need a MySQL user that can connect from your VM host:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;create&lt;/span&gt; &lt;span class="k"&gt;user&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;gemma&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt; &lt;span class="n"&gt;identified&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;yourpassword&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;grant&lt;/span&gt; &lt;span class="k"&gt;all&lt;/span&gt; &lt;span class="k"&gt;privileges&lt;/span&gt; &lt;span class="k"&gt;on&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;to&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;gemma&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;%&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="k"&gt;grant&lt;/span&gt; &lt;span class="k"&gt;option&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Restart MySQL&lt;/h3&gt;
&lt;p&gt;Restart the MySQL server to apply the configuration changes:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;sudo service mysql restart
&lt;/pre&gt;&lt;/div&gt;


&lt;h2&gt;Bringing back the romance&lt;/h2&gt;
&lt;p&gt;Now that MySQL is behaving itself, we can work on PHPStorm. Pull up that &lt;em&gt;Database&lt;/em&gt; tool window from before and create a new MySQL data source: Green plus sign (or &lt;code&gt;Alt + Insert&lt;/code&gt;) → &lt;em&gt;Data Source&lt;/em&gt; → &lt;em&gt;MySQL&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="create a mysql data source" src="/static/images/phpstorm_datasource.png" /&gt; &lt;/p&gt;
&lt;p&gt;In the window that appears, plug in your connection settings.&lt;/p&gt;
&lt;p&gt;&lt;img alt="mysql connection config" src="/static/images/phpstorm_mysql_config.png" /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;If you haven't already, click the link to download the driver files. It's painless; PHPStorm does it all in the background.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Host&lt;/em&gt; and &lt;em&gt;Port&lt;/em&gt; should match the connection information for your VM. I have a hostname set up (&lt;code&gt;myvm.local&lt;/code&gt;), but you could just as easily use a raw IP address.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Database&lt;/em&gt; should be the name of the MySQL database you'll be using for this project.&lt;/li&gt;
&lt;li&gt;The user credentials should match the new user you created above.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Wedded bliss&lt;/h2&gt;
&lt;p&gt;That's it! That empty &lt;em&gt;Database&lt;/em&gt; manager should now be populated with all the content from the database you specified. You can view tables, run queries, create diagrams--really everything I normally do in an external client. Pretty slick.&lt;/p&gt;
&lt;p&gt;(If you want to keep going, check out the &lt;a href="https://www.jetbrains.com/phpstorm/webhelp/data-sources.html"&gt;PHPStorm Data Source documentation&lt;/a&gt;!)&lt;/p&gt;</summary><category term="tool"></category><category term="howto"></category><category term="php"></category></entry><entry><title>on algorithms and boundaries</title><link href="https://www.ramblinations.com/on-algorithms-and-boundaries.html" rel="alternate"></link><updated>2013-08-25T14:04:00-06:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2013-08-25:on-algorithms-and-boundaries.html</id><summary type="html">&lt;p&gt;I'm taking the &lt;a href="https://www.coursera.org/course/algs4partI"&gt;Algorithms I class&lt;/a&gt; from Coursera that just started up again. (I'm going to finish it this time.) (No really!) The first programming assignment has students building a &lt;a href="http://en.wikipedia.org/wiki/Monte_Carlo_method"&gt;Monte Carlo simulation&lt;/a&gt; for the &lt;a href="http://en.wikipedia.org/wiki/Percolation_threshold"&gt;percolation problem&lt;/a&gt;, using a &lt;a href="http://algs4.cs.princeton.edu/15uf/WeightedQuickUnionUF.java.html"&gt;weighted quick-union algorithm&lt;/a&gt;. We'd already covered &lt;a href="http://en.wikipedia.org/wiki/Union_find"&gt;union finds&lt;/a&gt; and the internals of a WQU during the lectures and exercises, so the assignment focused on applying it efficiently.&lt;/p&gt;
&lt;p&gt;I built a slow prototype that mostly worked, then made it a decent amount faster, then fixed an edge case that I'd broken while making it faster, then got stuck. My solution still mostly worked--the gist was there--but it was partially wrong, and I couldn't even conceptualize a fix without at least doubling the memory or runtime. Which, obviously, would be wrong. Right? I mean, I spent six years in C. Performance is everything.&lt;/p&gt;
&lt;p&gt;I even slept on it. Nothing.&lt;/p&gt;
&lt;p&gt;Feeling fairly stupid, I started procrastinating on the class forums and stumbled over a thread that directly addressed the problem I was trying to solve. Most of the comments went something like this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Yeah, I couldn't even get close to 100% [grade] until I doubled the memory used.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;em&gt;Wait, what? They doubled the memory..and it was ok? WAIT A SECOND.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I went back to the automated feedback from my best attempt (a mere 87%) and checked the details of the memory usage tests. Sure enough, I was using less than half what the assignment allowed. I re-submitted my solution with the doubling-memory, solving-the-whole-problem tweak: 100%.&lt;/p&gt;
&lt;p&gt;Lesson learned: Don't start rejecting solutions until they overflow the actual boundaries of the problem. Speed for speed's sake, or memory for memory's sake, or &lt;abbr title="Lines of Code"&gt;LOC&lt;/abbr&gt; for &lt;abbr title="Lines of Code"&gt;LOC&lt;/abbr&gt;'s sake, or whatever imaginary boundary you've constructed for yourself ends up being just a waste of time if you can't get the rest of it done.&lt;/p&gt;</summary><category term="programming"></category><category term="edu"></category></entry><entry><title>more fun with btsync</title><link href="https://www.ramblinations.com/more-fun-with-btsync.html" rel="alternate"></link><updated>2013-08-23T00:04:00-06:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2013-08-23:more-fun-with-btsync.html</id><summary type="html">&lt;p&gt;I've &lt;a href="btsync-where-have-you-been-all-my-life.html"&gt;already gushed&lt;/a&gt; over the amazingness that is &lt;a href="http://labs.bittorrent.com/experiments/sync.html"&gt;btsync&lt;/a&gt;, but it just solved another problem for me, so here I am again.&lt;/p&gt;
&lt;p&gt;My new &lt;a href="https://clientarea.ramnode.com/aff.php?aff=594"&gt;VPS provider&lt;/a&gt; (yes, that is an affiliate link; sue me) recently announced that their backup interval would be increasing from weekly to monthly. I'm coming from a daily backup environment, so weekly was already uncomfortable; it was time to set up my own backup system. But my primary machine (and therefore backup host) is Windows--am I supposed to set up some kind of rsync service? Muck about with Scheduled Tasks? Ugh. Headaches all around.&lt;/p&gt;
&lt;p&gt;But wait! btsync to the rescue!&lt;/p&gt;
&lt;p&gt;I set up a little &lt;code&gt;cron.weekly&lt;/code&gt; job to drop the content I want saved into a bz2 tarball&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;/bin/tar -cjpf /path/to/vps-backup-folder/backup.tar.bz2 &lt;span class="se"&gt;\&lt;/span&gt;
    --exclude&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;skip-this-folder&amp;#39;&lt;/span&gt; --exclude&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;vps-backup-folder&amp;#39;&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    --exclude&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;.SyncArchive&amp;#39;&lt;/span&gt; /home/me /etc /path/to/webroot /var/log
/bin/chown me:me /path/to/vps-backup-folder/backup.tar.bz2
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;and (wait wait, I bet you can guess) registered &lt;code&gt;/path/to/vps-backup-folder&lt;/code&gt; as a btsync source. Now my VPS backups will sync (encrypted!) to any client with the key, whenever they happen to come online. And as a bonus, btsync's own backup system (in &lt;code&gt;.SyncArchive&lt;/code&gt;) will hang on to old versions of the backup tarball for as long as I specify.&lt;/p&gt;
&lt;p&gt;Really, this stuff is magic.&lt;/p&gt;
&lt;p&gt;(I did briefly investigate &lt;a href="http://forums.vpslink.com/howtos/1920-incremental-backups-gnu-tar.html"&gt;tar-based incremental backups&lt;/a&gt;, but I don't want to store every increment ever from the beginning of backed-up time. It'd be a particularly ridiculous degree of overkill.) &lt;/p&gt;</summary><category term="linux"></category><category term="tool"></category><category term="security"></category><category term="vps"></category></entry><entry><title>who left the burner on?</title><link href="https://www.ramblinations.com/who-left-the-burner-on.html" rel="alternate"></link><updated>2013-08-12T13:37:00-06:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2013-08-12:who-left-the-burner-on.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;Researchers in Uppsala, Sweden, accidentally left a reaction running over the weekend and ended up solving a century-old chemistry problem. Their work has led to the development of new material, dubbed Upsalite, with remarkable water-binding properties. Upsalite promises to find applications in everything from humidity control at home to chemical manufacturing in industry....&lt;/p&gt;
&lt;p&gt;When one mixture was accidentally allowed to react over a long weekend, researchers came back to find a gel. It turns out the gel was formed because methanol molecules had been trapped within the material. When heated to 70°C, which is above the boiling point of methanol, the gel “solidifies and collapses into a white and coarse powder.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;(&lt;a href="http://arstechnica.com/science/2013/08/scientists-make-impossible-material-dubbed-upsalite-by-accident/"&gt;source&lt;/a&gt;)&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;Jane, entering the lab and flipping the lights, glances around the room&lt;/dt&gt;
&lt;dd&gt;Erm.&lt;/dd&gt;
&lt;dt&gt;John, following behind, yawning&lt;/dt&gt;
&lt;dd&gt;What?&lt;/dd&gt;
&lt;dt&gt;Jane, inching toward a table covered in a blue gelatinous substance&lt;/dt&gt;
&lt;dd&gt;Did you leave the burner on Thursday night?&lt;/dd&gt;
&lt;dt&gt;John, yawning&lt;/dt&gt;
&lt;dd&gt;Me? No way, I left early.&lt;/dd&gt;
&lt;dt&gt;Jane&lt;/dt&gt;
&lt;dd&gt;We all went for drinks. I don't remember who was the last out.&lt;/dd&gt;
&lt;dt&gt;John&lt;/dt&gt;
&lt;dd&gt;Why, what happened?&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;&lt;em&gt;Jane points at the blue goo.&lt;/em&gt;&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;John, eyes widening&lt;/dt&gt;
&lt;dd&gt;What the hell is that?&lt;/dd&gt;
&lt;dt&gt;Jane&lt;/dt&gt;
&lt;dd&gt;Not what it's supposed to be, I can say that much.&lt;/dd&gt;
&lt;dt&gt;John approaches the table warily&lt;/dt&gt;
&lt;dd&gt;How'd that happen? Which reaction was this?&lt;/dd&gt;
&lt;dt&gt;Jane&lt;/dt&gt;
&lt;dd&gt;I think it was Fred's magnesium oxide mix.&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;&lt;em&gt;Jane and John ponder the accident in silence.&lt;/em&gt;&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;Jane, pulling on rubber gloves and a set of safety goggles&lt;/dt&gt;
&lt;dd&gt;Say, whaddya think'll happen if we heat it up some more?&lt;/dd&gt;
&lt;/dl&gt;
&lt;p&gt;Whoops, science!&lt;/p&gt;</summary><category term="politics"></category><category term="science"></category></entry><entry><title>btsync, where have you been all my life</title><link href="https://www.ramblinations.com/btsync-where-have-you-been-all-my-life.html" rel="alternate"></link><updated>2013-08-10T01:55:00-06:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2013-08-10:btsync-where-have-you-been-all-my-life.html</id><summary type="html">&lt;p&gt;Well, that was easy.&lt;/p&gt;
&lt;p&gt;I've been using &lt;a href="http://keepass.info/"&gt;KeePass&lt;/a&gt; for password management for roughly five years, ish. I like that it's free, that it runs on all my devices and that it integrates with any password-protected application (not just my browser). Syncing the database to all said devices, on the other hand, has always been a minor headache. I don't want to rely on free cloud storage providers, so I substitute various incarnations of personal servers, and I sacrifice the nifty auto-syncing clients. I could run something like &lt;a href="http://sparkleshare.org/"&gt;SparkleShare&lt;/a&gt;, but that seems like overkill for one lousy file. I also &lt;a href="https://help.ubuntu.com/community/SSH/OpenSSH/Configuring#Disable_Password_Authentication"&gt;disable password authentication over SSH&lt;/a&gt;, so the native KeePass syncing capability is out--which isn't that big of a deal, because it doesn't work in the Android port anyway. Long story slightly less long, I've been mixing KeePass database triggers with a remote cron job and an Android port of rsync for a couple years.&lt;/p&gt;
&lt;p&gt;So today I found &lt;a href="http://labs.bittorrent.com/experiments/sync.html"&gt;BitTorrent Sync&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;mind|blown&lt;/h2&gt;
&lt;p&gt;Oh my word, people. I can't even tell you. It's amazing.&lt;/p&gt;
&lt;p&gt;You hand it a folder to sync, it hands you a 21-character key (password). The key uniquely identifies your sync folder. Any other &lt;code&gt;btsync&lt;/code&gt; peer (computer running the syncing client) with the key can sync from the folder, and no peer without the key can even see it. The actual content transmission is just like regular BitTorrent, except with 256-bit AES encryption (based, again, on the folder key).&lt;/p&gt;
&lt;p&gt;If you're running behind a LAN, that's all you need. Just &lt;code&gt;btsync&lt;/code&gt; peers and a shared key, no external servers necessary.&lt;/p&gt;
&lt;p&gt;If you're outside a LAN, you can enable &lt;a href="http://tvtropes.org/pmwiki/pmwiki.php/Main/ClarkesThirdLaw"&gt;MAGICAL THINGS&lt;/a&gt;: &lt;code&gt;btsync&lt;/code&gt; can send a one-way hash (SHA-2) of your key up to a BitTorrent tracker, and match up peers by matching up hashes. It's brilliant. The hashes can't be forged (at least until somebody breaks SHA-2), and the original keys are needed for decryption. There are millions of hashed keys hanging out on the trackers right now, looking for matching peers, completely secure. Once the tracker matches up some peers, it's done; it never sees the synced data, encrypted or otherwise, because the peers talk to each other directly.&lt;/p&gt;
&lt;p&gt;As a bonus, the &lt;code&gt;btsync&lt;/code&gt; client does local backups by default. It'll automatically keep 30 days worth of version history. I just replaced my KeePass triggers, my cron job &lt;em&gt;and&lt;/em&gt; my Android rsync with one tool, without handing any of my data to a third party.&lt;/p&gt;
&lt;h2&gt;Install&lt;/h2&gt;
&lt;p&gt;Per usual, setting up the Windows and Android clients is a fairly brainless process; setting up a Linux client is &lt;a href="http://forum.bittorrent.com/topic/18974-debian-and-ubuntu-server-packages-for-bittorrent-sync/"&gt;a little more exciting&lt;/a&gt;. Here's what I did on my Ubuntu 13.04 server:&lt;/p&gt;
&lt;h3&gt;We don't set things up manually in Ubuntu, son!&lt;/h3&gt;
&lt;p&gt;Use the &lt;a href="https://launchpad.net/~tuxpoldo/+archive/btsync"&gt;PPA&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;apt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;repository&lt;/span&gt; &lt;span class="n"&gt;ppa&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;tuxpoldo&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;btsync&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;aptitude&lt;/span&gt; &lt;span class="n"&gt;update&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;aptitude&lt;/span&gt; &lt;span class="n"&gt;install&lt;/span&gt; &lt;span class="n"&gt;btsync&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;(If you're on a version of Ubuntu that didn't come with &lt;code&gt;add-apt-repository&lt;/code&gt;, you can grab it from the &lt;code&gt;software-properties-common&lt;/code&gt; package. I mention this only because when I was on 12.04, it took way too long to find.)&lt;/p&gt;
&lt;h2&gt;Configure&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;apt&lt;/code&gt; will throw some preliminary config options at you and start the &lt;code&gt;btsync&lt;/code&gt; client in daemon mode; you can configure more things after the install is complete (check the &lt;a href="http://forum.bittorrent.com/topic/18974-debian-and-ubuntu-server-packages-for-bittorrent-sync/"&gt;main Debian/Ubuntu instructions&lt;/a&gt; and the &lt;a href="http://btsync.s3-website-us-east-1.amazonaws.com/BitTorrentSyncUserGuide.pdf"&gt;user guide&lt;/a&gt; for details):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;dpkg&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;reconfigure&lt;/span&gt; &lt;span class="n"&gt;btsync&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;dpkg-reconfigure&lt;/code&gt; saves your settings to a read-only configuration file at &lt;code&gt;/etc/btsync/debconf-default.conf&lt;/code&gt;. You can create as many syncing profiles as you want; just stick them all in &lt;code&gt;/etc/btsync&lt;/code&gt;. I ended up copying the defaults to a new profile specific to my user (&lt;code&gt;/etc/btsync/gemma.conf&lt;/code&gt;), borrowing more settings from the &lt;code&gt;/etc/btsync/user-new.conf&lt;/code&gt; sample:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;//!/usr/lib/btsync/btsync-daemon&lt;/span&gt; &lt;span class="err"&gt;--config&lt;/span&gt;
&lt;span class="err"&gt;//&lt;/span&gt;
&lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;in&lt;/span&gt; &lt;span class="err"&gt;this&lt;/span&gt; &lt;span class="err"&gt;profile,&lt;/span&gt; &lt;span class="err"&gt;btsync&lt;/span&gt; &lt;span class="err"&gt;will&lt;/span&gt; &lt;span class="err"&gt;run&lt;/span&gt; &lt;span class="err"&gt;as&lt;/span&gt; &lt;span class="err"&gt;my&lt;/span&gt; &lt;span class="err"&gt;user&lt;/span&gt; &lt;span class="err"&gt;ID&lt;/span&gt;
&lt;span class="err"&gt;//&lt;/span&gt; &lt;span class="err"&gt;DAEMON_UID=gemma&lt;/span&gt;
&lt;span class="err"&gt;//&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;device_name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;my server&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;storage_path&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/home/gemma/.btsync&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;listening_port&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;12345&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;check_for_updates&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;use_upnp&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;download_limit&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;upload_limit&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;disk_low_priority&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;lan_encrypt_data&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;lan_use_tcp&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;rate_limit_local_peers&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;folder_rescan_interval&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;quot;webui&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;quot;shared_folders&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;secret&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;my folder key&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;dir&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/path/to/my/synced/folder&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;use_relay_server&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;use_dht&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;search_lan&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;quot;use_sync_trash&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Most of that's pretty boring, except:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I disable upnp and set a specific listening port so I can easily control access with my firewall (&lt;code&gt;ufw&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;I disable the built-in web UI, because no.&lt;/li&gt;
&lt;li&gt;This client is running on my remote server, so I enable LAN encryption and the relay server, and disable LAN searching.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Once you've got your profile(s) set, you can control which one(s) &lt;code&gt;btsync&lt;/code&gt; loads with the &lt;code&gt;/etc/default/btsync&lt;/code&gt; config file. By default it loads all the profiles in &lt;code&gt;/etc/btsync&lt;/code&gt;, but I want it to only load profiles I specifically request:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;# just load gemma.conf, nothing else&lt;/span&gt;
&lt;span class="nv"&gt;AUTOSTART&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;gemma&amp;quot;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Wait wait wait&lt;/h3&gt;
&lt;p&gt;Make sure your profiles are readable by the user in &lt;code&gt;DAEMON_UID&lt;/code&gt;! The &lt;code&gt;btsync&lt;/code&gt; client is still pretty young, there's not much (read: any) logging, and if it can't read the configuration file, it'll just fail silently.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;chown&lt;/span&gt; &lt;span class="n"&gt;gemma&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;gemma&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;btsync&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gemma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;At the same time, the profile has your folder key in it, so protect it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;chmod&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;btsync&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;gemma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;h3&gt;Let 'er rip&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;btsync&lt;/code&gt; package is automatically hooked into &lt;code&gt;upstart&lt;/code&gt;, so this part's easy:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="n"&gt;btsync&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;
 &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Starting&lt;/span&gt; &lt;span class="n"&gt;P2P&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="n"&gt;synchronisation&lt;/span&gt; &lt;span class="n"&gt;daemon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)...&lt;/span&gt;
 &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Autostarting&lt;/span&gt; &lt;span class="n"&gt;btsync&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;gemma&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt;
&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="n"&gt;btsync&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
 &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;BTSYNC&lt;/span&gt; &lt;span class="err"&gt;&amp;#39;&lt;/span&gt;&lt;span class="n"&gt;gemma&lt;/span&gt;&lt;span class="err"&gt;&amp;#39;&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;running&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;That's it. The sync folder(s) listed in the &lt;code&gt;gemma.conf&lt;/code&gt; profile will now sync with any and every matching peer (in my case, a desktop, a laptop and a smartphone).&lt;/p&gt;
&lt;p&gt;Happy syncing!&lt;/p&gt;</summary><category term="linux"></category><category term="ubuntu"></category><category term="howto"></category><category term="tool"></category><category term="security"></category></entry><entry><title>casedCamels and underscores</title><link href="https://www.ramblinations.com/casedcamels-and-underscores.html" rel="alternate"></link><updated>2013-03-09T23:35:00-07:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2013-03-09:casedcamels-and-underscores.html</id><summary type="html">&lt;p&gt;Ah, coding styles. A favorite holy war. Are your braces &lt;em&gt;one true&lt;/em&gt; or &lt;em&gt;K&amp;amp;R&lt;/em&gt;? Is your indenting tabbed or spaced? Are your variables underscored or camelCased? In my case, respectively K&amp;amp;R, spaced and camelCased &amp;mdash; but that's just my preference. It's not like any one style is objectively better than any other. Let's all just get along, people.&lt;/p&gt;
&lt;p&gt;Unless you're CompSci researchers in Maryland, in which case you should &lt;a href="http://www.cs.loyola.edu/~binkley/papers/tr-loy110720.pdf" title="The impact of identifier style on effort and comprehension, 'Empirical Software Engineering' volume 18 "&gt;do a study&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A family of studies investigating the impact of program identifier style on human comprehension is presented. Two popular identifier styles are examined, namely camel case and underscore. The underlying hypothesis is that identifier style affects the speed and accuracy of comprehending source code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Essentially, they're asking if &lt;code&gt;getValue()&lt;/code&gt; is easier to read than &lt;code&gt;get_value()&lt;/code&gt;, which somehow, despite decades of flame wars, has never been formally asked. Here's the really interesting part:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If reading source code and reading natural language are substantially the same undertakings, then a significant body of foundational research on natural language can be used as a basis for program com-prehension studies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Whether &lt;code&gt;myValue&lt;/code&gt; is better than &lt;code&gt;my_value&lt;/code&gt; is interesting enough on its own, but the real value of the study is in tying the comparison to existing principles for reading in general. If reading code is like reading prose, programmers could theoretically adapt and use the same techniques to improve code comprehension that teachers use to improve prose comprehension. Maybe you're awesome and reading others' code comes naturally to you; I'm not, and it doesn't, so I'll take all the help I can get.&lt;/p&gt;
&lt;p&gt;The researchers expected that existing natural language comprehension principles would apply to code comprehension; specifically, that text with some kind of spacing between words (like_this) is easier to read than un-spaced text (likeThis). They ran an interdependent series of experiments on about 170 college-age programmers (mostly male, roughly even mix of style preferences), gauging response time and correctness. All the experiments were modeled after natural language predecessors, which fits with the overall attempt to correlate prose and code comprehension:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Find an identifier in a cloud of similar identifiers&lt;/li&gt;
&lt;li&gt;Find all the occurrences of an identifier in a code fragment&lt;/li&gt;
&lt;li&gt;Answer SAT-style questions about a prose snippet displayed with underscores or camelCasing.&lt;/li&gt;
&lt;li&gt;Same concept as #3, but with code instead of prose.&lt;/li&gt;
&lt;li&gt;Track eye movements while reading and verbally summarizing code fragments.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In general, the results were unexpected. Naming style didn't really affect comprehension for experienced programmers, while beginners seemed to do better with camel case than underscores (the &lt;em&gt;opposite&lt;/em&gt; of prose comprehension):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In particular, the visual effort for short identifier names (e.g., rowSum) appears to be greater when using underscores. One possible explanation is that programmers chunk such short phrases into one concept because they are common concepts in the problem or solution domain (e.g., rowSum, xAxis). Thus, the use of underscore gets in the way of understanding these identifiers....the result of comprehension is a program plan with the specifics of the syntactic features filtered out rather than a rote memorization of the exact program text.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The theory is that since code already has a fairly structured form, comprehension is less about reading the words and more about recognizing the conceptual units. (Those of us who use &lt;code&gt;i&lt;/code&gt;, &lt;code&gt;j&lt;/code&gt; and &lt;code&gt;k&lt;/code&gt; for array indices probably have no trouble swallowing that idea.) The studies demonstrate handily that reading code is not a parallel for reading prose &amp;mdash; which, though it means we don't get to automatically apply all the cool natural language research to what we do, opens up massive potential for future research.&lt;/p&gt;</summary><category term="programming"></category><category term="research"></category></entry><entry><title>monobar gets a monomenu</title><link href="https://www.ramblinations.com/monobar-gets-a-monomenu.html" rel="alternate"></link><updated>2013-02-10T09:27:00-07:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2013-02-10:monobar-gets-a-monomenu.html</id><summary type="html">&lt;p&gt;Way back in the dark ages of less than a year ago, I read what was to become a classic Linus Torvalds rant on &lt;a href="https://github.com/torvalds/linux/pull/17#issuecomment-5659933"&gt;the inadequacy of Github pull requests&lt;/a&gt;. Afterwards, I started seeing it everywhere: text boxes that &lt;em&gt;tell me nothing about the text&lt;/em&gt;! I mean really, the nerve. How am I supposed to write pretty text for ancient, barely-used applications like &lt;a href="http://lynx.browser.org/"&gt;Lynx&lt;/a&gt; and &lt;a href="http://www.mutt.org/"&gt;mutt&lt;/a&gt; if I have no idea what the text is doing?! &lt;strong&gt;SOMETHING MUST BE DONE.&lt;/strong&gt;&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1" rel="footnote"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2&gt;Doing something!&lt;/h2&gt;
&lt;p&gt;So I made &lt;a href="https://github.com/ellotheth/chromext-monobar"&gt;a Chrome extension&lt;/a&gt;. When you're in a text field (specifically a &lt;code&gt;&amp;lt;textarea&amp;gt;&lt;/code&gt; field, so things like search boxes don't count), it pops up a little bar with information about whatever you're writing.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/ellotheth/chromext-monobar/tree/131005f53080e9c29f23afd89573fabe7a083038#bar"&gt;&lt;img alt="monobar" src="https://raw.github.com/ellotheth/chromext-monobar/131005f53080e9c29f23afd89573fabe7a083038/images/monobar-ss-bar.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Nobody uses it besides me, as far as I know, so &lt;em&gt;clearly&lt;/em&gt; it needed more bells and whistles.&lt;/p&gt;
&lt;h2&gt;Doing &lt;em&gt;more&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;Yesterday I added a bell (or possibly a whistle). Does it drive anyone else bonkers that Gmail has you typing supposedly plain-text emails in a proportional font? No? Nobody? Really? Well, fine, I hope you all enjoy your irritation-free lives; I'll be over here growling about the latest Facebook redesign AND enjoying my new context menu item that toggles whatever I'm typing between monospace and proportional fonts.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/ellotheth/chromext-monobar/tree/131005f53080e9c29f23afd89573fabe7a083038#menu"&gt;&lt;img alt="monomenu!" src="https://raw.github.com/ellotheth/chromext-monobar/131005f53080e9c29f23afd89573fabe7a083038/images/monobar-ss-menu.png" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It works on anything editable, not just Gmail composition windows. (Technically it doesn't toggle monospace off, exactly. It just flips between monospace and whatever the parent element's font is.)&lt;/p&gt;
&lt;h2&gt;The guts&lt;/h2&gt;
&lt;p&gt;Setting up the context menu item ended up slightly more complicated than I was expecting, mostly because Chrome context menus &lt;a href="https://code.google.com/p/chromium/issues/detail?id=39507"&gt;don't actually know anything about where they were clicked from&lt;/a&gt;. They can tell you the tab, and the page URL, and information about the menu itself, but they have no clue which piece of the website you clicked.&lt;/p&gt;
&lt;p&gt;To get around that, I had to both create the context menu item &lt;em&gt;and&lt;/em&gt; check for global &lt;code&gt;contextmenu&lt;/code&gt; events, which are fired whenever the user gets a context menu. Javascript events know where they were triggered, so combining the global event with the click on the menu item itself let me grab the element:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cm"&gt;/* When any context menu pops up */&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;editable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;contextmenu&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;editable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cm"&gt;/* When the &amp;#39;Toggle monospace font&amp;#39; item is clicked */&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;changefont&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;element&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tabs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tab&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;monobar-changefont&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;That &lt;code&gt;sendMessage&lt;/code&gt; call is really where the magic happens. Now that I've got both events, they have to talk to each other. Clicking the menu item sends a &lt;code&gt;monobar-changefont&lt;/code&gt; message, so I listen globally for &lt;code&gt;monobar-changefont&lt;/code&gt; messages:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="cm"&gt;/* Do things when the monobar-changefont message comes in! */&lt;/span&gt;
&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;extension&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onMessage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;monobar-changefont&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="cm"&gt;/* This message only comes in if a context menu is up, so&lt;/span&gt;
&lt;span class="cm"&gt;         * get &amp;#39;editable&amp;#39; from above and muck about with it&lt;/span&gt;
&lt;span class="cm"&gt;         */&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The whole &lt;code&gt;sendMessage&lt;/code&gt; rigamarole is only necessary because &lt;a href="http://developer.chrome.com/extensions/content_scripts.html"&gt;content scripts&lt;/a&gt; are distinct from &lt;a href="http://developer.chrome.com/extensions/background_pages.html"&gt;background scripts&lt;/a&gt;, and getting them talk to each other is &lt;a href="http://stackoverflow.com/search?q=chrome+background+content"&gt;slightly less straightforward&lt;/a&gt; than "Hey, gimme the element!" Regardless, it was massively fun to learn, so &lt;a href="https://github.com/ellotheth/chromext-monobar#install"&gt;go grab the final product&lt;/a&gt; and &lt;strong&gt;MONOSPACE ALL THE THINGS&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Drama added for emphasis.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" rev="footnote" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</summary><category term="project"></category><category term="programming"></category></entry><entry><title>solving problems with threads</title><link href="https://www.ramblinations.com/solving-problems-with-threads.html" rel="alternate"></link><updated>2013-02-08T00:00:00-07:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2013-02-08:solving-problems-with-threads.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;A programmer had a problem. He thought “I know, I’ll solve it with threads!”. has Now problems. two he&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="http://leonsbuddydave.tumblr.com/post/41782978674/a-programmer-had-a-problem-he-thought-i-know"&gt;leonsbuddydave&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Still giggling, fifteen minutes later.&lt;/p&gt;</summary><category term="programming"></category><category term="quote"></category></entry><entry><title>pernicious kingdoms</title><link href="https://www.ramblinations.com/pernicious-kingdoms.html" rel="alternate"></link><updated>2013-02-03T11:25:00-07:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2013-02-03:pernicious-kingdoms.html</id><summary type="html">&lt;p&gt;From &lt;em&gt;&lt;a href="http://cwe.mitre.org/documents/sources/SevenPerniciousKingdoms.pdf"&gt;Seven Pernicious Kingdoms: A Taxonomy of Software Security Errors&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One of the first studies of computer security and privacy was the RISOS (Research Into Secure Operating Systems) project [in 1976]. RISOS proposed and described seven categories of operating system security defects...: &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Incomplete Parameter Validation &lt;/li&gt;
&lt;li&gt;Inconsistent Parameter Validation &lt;/li&gt;
&lt;li&gt;Implicit Sharing of Privileges / Confidential Data &lt;/li&gt;
&lt;li&gt;Asynchronous Validation / Inadequate Serialization &lt;/li&gt;
&lt;li&gt;Inadequate Identification / Authentication / Authorization &lt;/li&gt;
&lt;li&gt;Violable Prohibition / Limit &lt;/li&gt;
&lt;li&gt;Exploitable Logic Error&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The study shows that there are a small number of fundamental defects that recur in different contexts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Heh. You could say that, yes. Here we are, 40 years later, dealing (or more often, failing to deal) with exactly the same problems. How long were people starting cars with hand cranks, ten years? Fifteen?&lt;/p&gt;</summary><category term="stevens"></category><category term="programming"></category><category term="security"></category></entry><entry><title>a todo list for pelican</title><link href="https://www.ramblinations.com/a-todo-list-for-pelican.html" rel="alternate"></link><updated>2013-02-01T20:01:00-07:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2013-02-01:a-todo-list-for-pelican.html</id><summary type="html">&lt;p&gt;I'm loving &lt;a href="http://blog.getpelican.com/"&gt;Pelican&lt;/a&gt;. Naturally I want to change it all.&lt;/p&gt;
&lt;h2&gt;Favicons&lt;/h2&gt;
&lt;p&gt;Not that modifying the theme &lt;code&gt;base.html&lt;/code&gt; is hard, but the process could be easily automated, so it's a good candidate for built-in functionality. Everybody uses favicons. Give Pelican a &lt;code&gt;FAVICON_PATH&lt;/code&gt; variable in the configuration, and the engine copies the file to some constant location for themes to pick up and &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;. Easy. (Also, seriously, how awesome is my little boat? I'll tell you: &lt;em&gt;pretty awesome&lt;/em&gt;.)&lt;/p&gt;
&lt;h2&gt;&lt;del&gt;Minification&lt;/del&gt;&lt;/h2&gt;
&lt;p&gt;Pelican is a static site generator, so automatically &lt;a href="http://www.hanselman.com/blog/TheImportanceAndEaseOfMinifyingYourCSSAndJavaScriptAndOptimizingPNGsForYourBlogOrWebsite.aspx"&gt;minifying&lt;/a&gt; CSS and JS source files seems like a no-brainer. Of course, that's because it &lt;em&gt;is&lt;/em&gt; a no-brainer, and has &lt;a href="https://pelican.readthedocs.org/en/3.1.1/plugins.html#asset-management"&gt;already been done&lt;/a&gt;. Hurrah for the internet.&lt;/p&gt;
&lt;h2&gt;Git integration&lt;/h2&gt;
&lt;p&gt;Technically this isn't a Pelican item so much as a "make my &lt;a href="http://git-scm.com/book/ch7-3.html#Server-Side-Hooks"&gt;git hook&lt;/a&gt; cooler" item: I want to pull post entry dates from the git commit author date, and tags from the commit message. Seems simple enough, but it gets complicated when you consider the entire change history of an entry. &lt;a href="https://github.com/creationix/wheat"&gt;Wheat&lt;/a&gt;, a git-based blog engine I tried briefly, handles entry changes by giving the reader literally every change ever made in a clickable list. (With a commit hash and everything, it's pretty wild.) The design makes sense for a wiki-style site, heavy with community content and editorial oversight, but gets a little cumbersome for a personal blog. (I'm ok with readers &lt;em&gt;not&lt;/em&gt; seeing every typo I'll ever make, thanks.)&lt;/p&gt;
&lt;p&gt;My version would be more boring: Find the commit that added the entry, and use that &lt;code&gt;GIT_AUTHOR_DATE&lt;/code&gt; as the initial entry date. It could even find the commit that most recently changed the entry, and add some kind of &lt;em&gt;Updated on foobity bar date&lt;/em&gt; footer.&lt;/p&gt;
&lt;p&gt;Pulling tags from commit messages could be similarly straightforward: Parse the messages in every commit that changed the entry for whatever the tag pattern is, and add all the tags found. Throw in some kind of lexical mechanism for identifying tags removed (maybe &lt;code&gt;-tag&lt;/code&gt; instead of just &lt;code&gt;tag&lt;/code&gt;?), and turn the result into a tag list.&lt;/p&gt;
&lt;h3&gt;Speaking of which&lt;/h3&gt;
&lt;p&gt;My &lt;code&gt;post-receive&lt;/code&gt; now handles multiple branches. Since the Pelican &lt;code&gt;Makefile&lt;/code&gt; is part of each branch, publishing a draft is as simple as &lt;code&gt;git checkout draft &amp;amp;&amp;amp; make html&lt;/code&gt; (or rather, just pushing &lt;code&gt;draft&lt;/code&gt;, since the hook takes care of the rest). Along the same lines, incorporating draft changes in the live site is as simple as merging &lt;code&gt;draft&lt;/code&gt; to &lt;code&gt;master&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;function &lt;/span&gt;publish &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;branch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;

    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$pelicanweb&lt;/span&gt;
    git checkout -fq &lt;span class="nv"&gt;$branch&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git fetch &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git reset --hard origin/&lt;span class="nv"&gt;$branch&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; -ne 0 &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;git broke, go check the configs or something&amp;#39;&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="k"&gt;    &lt;/span&gt;make html &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$branch changes live&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nb"&gt;unset&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt;git rev-parse --local-env-vars&lt;span class="k"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read &lt;/span&gt;oldrev newrev ref
&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;branch&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sb"&gt;`&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$ref&lt;/span&gt; |cut -d/ -f3&lt;span class="sb"&gt;`&lt;/span&gt;
    publish &lt;span class="nv"&gt;$branch&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</summary><category term="programming"></category><category term="pelican"></category></entry><entry><title>IT'S ALIVE</title><link href="https://www.ramblinations.com/its-alive.html" rel="alternate"></link><updated>2013-02-01T13:10:00-07:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2013-02-01:its-alive.html</id><summary type="html">&lt;p&gt;Finally. At long last. The domain is pointing where it's supposed to be pointing, the design looks the way it's supposed to look (more or less), and nginx is even rewriting what it's supposed to be rewriting. Maybe. I think. Not all the DNS is propogated yet, so we'll see. But the uncertainty won't keep me from &lt;em&gt;DANCING&lt;/em&gt;!&lt;/p&gt;</summary><category term="programming"></category></entry><entry><title>deploying pelican with git</title><link href="https://www.ramblinations.com/deploying-pelican-with-git.html" rel="alternate"></link><updated>2013-01-06T15:06:00-07:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2013-01-06:deploying-pelican-with-git.html</id><summary type="html">&lt;p&gt;One of the things I love about &lt;a href="http://git-scm.com"&gt;git&lt;/a&gt; is how easy it makes &lt;a href="http://blog.ekynoxe.com/2011/10/22/git-post-receive-for-multiple-remote-branches-and-work-trees/"&gt;website deployment&lt;/a&gt;. Stick all your versions (production, development, test, yadda yadda) in different branches, push to a bare repo on the server, and set up your &lt;code&gt;post-receive&lt;/code&gt; hook to put the right versions in the right places by checking out individual branches to different working directories. Bam, done.&lt;/p&gt;
&lt;p&gt;I would have set up &lt;a href="http://getpelican.com"&gt;pelican&lt;/a&gt; the same way, except I want to be able to make changes directly on the server. Technically, what I should have done is create the bare master repo, point the detached checkout to wherever I want the live site, and make a separate local clone as my on-server work area. (Really pelican content isn't &lt;em&gt;live&lt;/em&gt;, per se, but it generates the static files that are, so close enough.):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Master repo: &lt;code&gt;/path/to/pelican-master.git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Work area: &lt;code&gt;/path/to/pelican-work&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Live area for detached checkout: &lt;code&gt;/path/to/pelican-live&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What I did instead was create the on-server work area (the local clone) where the detached checkout would normally be:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Master repo: &lt;code&gt;/path/to/pelican-master.git&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Work area: &lt;code&gt;/path/to/pelican-live&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Live area for detached checkout: same as the work area!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Seemed like a good idea at the time, because it cut down on random arbitrary directories of zillions of copies of the same files all over the place, but I broke the whole detached checkout idea. If &lt;code&gt;pelican-live&lt;/code&gt; is already a repo, I can't really use it as the detached working directory for the master repo. My clean and clear &lt;code&gt;post-receive&lt;/code&gt; hook is now an unholy hash of &lt;code&gt;checkout -f&lt;/code&gt;/&lt;code&gt;fetch&lt;/code&gt;/&lt;code&gt;reset&lt;/code&gt; nonsense:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;master&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$branch&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="nv"&gt;$pelicanweb&lt;/span&gt;
    git checkout -fq &lt;span class="nv"&gt;$branch&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git fetch &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git reset --hard origin/&lt;span class="nv"&gt;$branch&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; -ne 0 &lt;span class="o"&gt;]&lt;/span&gt;; &lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;git broke, go check the configs or something&amp;#39;&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="k"&gt;    &lt;/span&gt;make html &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Changes live&amp;#39;&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;On the other hand, it's working, and I want to go play with CSS.&lt;/p&gt;</summary><category term="programming"></category><category term="git"></category><category term="pelican"></category></entry><entry><title>how to walk through a door</title><link href="https://www.ramblinations.com/how-to-walk-through-a-door.html" rel="alternate"></link><updated>2013-01-06T08:30:00-07:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2013-01-06:how-to-walk-through-a-door.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;Let's say I am giving directions for how to leave this room. In Python, I
would just say something like 'Get up and go through the door. In other
languages, I might have to say something like, 'Stand up, but not with so much
force that you fall over, take three steps to the north, take one step to
the east, approach the door, check that it is not open, if it is not open,
open it, then step through it with this amount of speed...'.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href="http://www.slate.com/articles/technology/technology/2012/03/ruby_ruby_on_rails_and__why_the_disappearance_of_one_of_the_world_s_most_beloved_computer_programmers_.single.html"&gt;Guido van Rossum&lt;/a&gt;&lt;/p&gt;</summary><category term="quote"></category><category term="python"></category><category term="programming"></category></entry><entry><title>hello, world</title><link href="https://www.ramblinations.com/hello-world.html" rel="alternate"></link><updated>2013-01-05T21:30:00-07:00</updated><author><name>gemma lynn</name></author><id>tag:https://www.ramblinations.com,2013-01-05:hello-world.html</id><summary type="html">&lt;p&gt;I started Early -- Took my Dog --&lt;br /&gt;
And visited the Sea --&lt;br /&gt;
The Mermaids in the basement&lt;br /&gt;
Came out to look at me --&lt;/p&gt;
&lt;p&gt;And Frigates -- in the Upper Floor&lt;br /&gt;
Extended Hempen Hands --&lt;br /&gt;
Presuming Me to be a Mouse --&lt;br /&gt;
Aground -- opon the Sands --&lt;/p&gt;
&lt;p&gt;But no Man moved Me -- till the Tide&lt;br /&gt;
Went past my simple Shoe --&lt;br /&gt;
And past my Apron -- and my Belt&lt;br /&gt;
And past my Boddice -- too --&lt;/p&gt;
&lt;p&gt;And made as He would eat me up --  &lt;br /&gt;
As wholly as a Dew&lt;br /&gt;
Opon a Dandelion's Sleeve --&lt;br /&gt;
And then -- I started -- too --&lt;/p&gt;
&lt;p&gt;And He -- He followed -- close behind --&lt;br /&gt;
I felt His Silver Heel&lt;br /&gt;
Opon my Ancle -- Then My Shoes&lt;br /&gt;
Would overflow with Pearl --&lt;/p&gt;
&lt;p&gt;Until We met the Solid Town --&lt;br /&gt;
No One He seemed to know --&lt;br /&gt;
And bowing -- with a Mighty look --&lt;br /&gt;
At me -- The Sea withdrew --&lt;/p&gt;</summary></entry></feed>