<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1665136999654964268</id><updated>2011-12-15T17:54:43.165-08:00</updated><category term='linux'/><category term='cooking'/><category term='grails'/><category term='git'/><category term='ChromeOS'/><category term='food'/><category term='computers'/><category term='Google'/><category term='fermentation'/><category term='Chromebook'/><title type='text'>Mental Detritus</title><subtitle type='html'>A blog about... stuff</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mentaldetritus.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mentaldetritus.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Hayden Muhl</name><uri>http://www.blogger.com/profile/02828965355001302175</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>7</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1665136999654964268.post-8781999018357740817</id><published>2011-12-12T13:11:00.001-08:00</published><updated>2011-12-15T17:54:43.178-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><category scheme='http://www.blogger.com/atom/ns#' term='Chromebook'/><category scheme='http://www.blogger.com/atom/ns#' term='Google'/><category scheme='http://www.blogger.com/atom/ns#' term='ChromeOS'/><title type='text'>Free Chromebook</title><content type='html'>I'm on a plane at the moment, flying to Chicago. It turns out, Google is promoting its Chromebooks by offering them free for the duration of your flight. You give them your name, email address and swipe a credit card, and you get free use of a Chromebook and on board wi-fi. This is great for two reasons. First, I can entertain myself with cat pictures and rage comics for the three hours it will take me to get to Chicago. Second, I get to play around with a Chromebook.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I've only been using it for about a half an hour, but already I can say I would not buy one of these. The main reason is that it is just not the right device for me. I mean, it's basically a computer that can only run Chrome. Don't get me wrong, Chrome is a great browser, but I just need my computers to be able to do more than that.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I do understand the use case for a computer like this. Let's say you run something like a large customer support call center. The software needs for your call center could easily be filled by web applications. With something like a Chromebook, if a computer craps out on you, IT can just grab another Chromebook off a shelf and your employee can get back to taking calls.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Unfortunately, even if I were in a position where a computer  like this were to be useful, I still wouldn't buy a Chromebook. The experience of trying to write this blog post has been little short of infuriating. The hardware simply does not work well, at all. The keyboard regularly registers double key presses, resuultiing in worrds like thesee. The touch pad is not much better. It will often not register your finger movements at all. I suppose it's possible that these computers have seen a lot of miles, and a lot of different people have used them, but it just makes me wonder how long it would be before my own use would result in similar behavior.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;One thing this experience has shown me is the appeal of a netbook. I brought my laptop with me on this trip, and I can see where my laptop would just be too big to comfortably use on a plane. It is also quite heavy compared to this. If I were to travel more, I think something like an Eee PC would be a worthwhile investment. But that will have to wait. I think my next purchase is going to be an Android tablet of some flavor so I can read on the train during my morning and evening commute.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Update: I'm waiting for my plane back to San Francisco, and they have the free Chrommebooks again. I'm just writing to confirmm that this CChromebook has the samme problems that the last one had. Ick. Oh, well. The frustration is worth the free wifi.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1665136999654964268-8781999018357740817?l=mentaldetritus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentaldetritus.blogspot.com/feeds/8781999018357740817/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mentaldetritus.blogspot.com/2011/12/free-chromebook.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/8781999018357740817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/8781999018357740817'/><link rel='alternate' type='text/html' href='http://mentaldetritus.blogspot.com/2011/12/free-chromebook.html' title='Free Chromebook'/><author><name>Hayden Muhl</name><uri>http://www.blogger.com/profile/02828965355001302175</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1665136999654964268.post-5662353046665491288</id><published>2011-10-28T04:20:00.000-07:00</published><updated>2011-10-28T04:21:23.290-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>Damn it, I'm actually going to do it this time</title><content type='html'>I have dipped my toe in the water of Linux From Scratch (LFS) a couple times before, but I never followed through with it. Well, I'm making another go at it, but this time I intend to follow through. I'm applying to grad schools to study operating systems, and I'm recently unemployed which gives me plenty of free time.&amp;nbsp;I also have two computers to work with, which means I can screw up my LFS system without having to worry about losing important data or access to a computer.&lt;br /&gt;&lt;br /&gt;I'm in the middle of step one at the moment. I'm formatting the disks on my tower. I will install Ubuntu 10.04 on the smaller of the two disks, and the larger disk will be where I will build my LFS system.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1665136999654964268-5662353046665491288?l=mentaldetritus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentaldetritus.blogspot.com/feeds/5662353046665491288/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mentaldetritus.blogspot.com/2011/10/damn-it-im-actually-going-to-do-it-this.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/5662353046665491288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/5662353046665491288'/><link rel='alternate' type='text/html' href='http://mentaldetritus.blogspot.com/2011/10/damn-it-im-actually-going-to-do-it-this.html' title='Damn it, I&apos;m actually going to do it this time'/><author><name>Hayden</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1665136999654964268.post-9114079143049263882</id><published>2011-10-08T23:38:00.000-07:00</published><updated>2011-10-08T23:38:55.934-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='fermentation'/><category scheme='http://www.blogger.com/atom/ns#' term='cooking'/><category scheme='http://www.blogger.com/atom/ns#' term='food'/><title type='text'>pH-kraut</title><content type='html'>Do you remember using &lt;a href="http://www.youtube.com/watch?v=JsJq8RKcXts#t=180s"&gt;purple cabbage as a pH indicator&lt;/a&gt; in grade school science class? I decided to combine that with my hobby of pickling.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As sauerkraut ferments it becomes more acidic, and since purple cabbage is a pH indicator, the sauerkraut should change color.&amp;nbsp;I shredded a head of purple cabbage, mixed it with salt and thyme (yum!) and packed it into a plastic container. I took a picture every evening when I got home from work to see how it had changed.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I had hoped to post the whole series of photos here, but the sauerkraut didn't act as I had expected. The change was dramatic, but it happened too quickly for the series of photos to be of any use. The appearance of the sauerkraut did not change at all, until day 3 when it changed drastically. After that its appearance did not change again.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-88vYbbZBkyI/TpE8xJuaG3I/AAAAAAAAAAw/apI6QJ4Ir78/s1600/purpleKraut.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="http://1.bp.blogspot.com/-88vYbbZBkyI/TpE8xJuaG3I/AAAAAAAAAAw/apI6QJ4Ir78/s400/purpleKraut.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I will try this experiment again, but will have to change how I photograph the sauerkraut. I plan to set up a camera on a tripod taking pictures several times a minute so I can stitch them together into a time lapse video. Hopefully that will catch the dramatic change in detail, as well as some of the more subtle action like formation of bubbles.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And since I'm already pulling stuff off my camera, here's some dude rocking out on an old busted spinet piano at the MacArthur BART station.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/qrJiKCKjQxM/0.jpg"&gt;&lt;param name="movie" value="http://www.youtube.com/v/qrJiKCKjQxM?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed width="320" height="266"  src="http://www.youtube.com/v/qrJiKCKjQxM?version=3&amp;f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1665136999654964268-9114079143049263882?l=mentaldetritus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentaldetritus.blogspot.com/feeds/9114079143049263882/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mentaldetritus.blogspot.com/2011/10/ph-kraut.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/9114079143049263882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/9114079143049263882'/><link rel='alternate' type='text/html' href='http://mentaldetritus.blogspot.com/2011/10/ph-kraut.html' title='pH-kraut'/><author><name>Hayden</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-88vYbbZBkyI/TpE8xJuaG3I/AAAAAAAAAAw/apI6QJ4Ir78/s72-c/purpleKraut.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1665136999654964268.post-2168674486222921929</id><published>2011-09-13T14:58:00.000-07:00</published><updated>2011-09-22T13:55:55.727-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Grails events</title><content type='html'>I couldn't find a complete list of Grails event, so I've tried to compile one. Using the various text processing tools, I chewed through all of the Grails scripts in my Grails 1.3.7 installation, and here's what I came up with.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;AppCfgEnd&lt;/li&gt;&lt;li&gt;AppCfgStart&lt;/li&gt;&lt;li&gt;AppLoadEnd&lt;/li&gt;&lt;li&gt;AppLoadStart&lt;/li&gt;&lt;li&gt;CreatedArtefact&lt;/li&gt;&lt;li&gt;CreatedFile&lt;/li&gt;&lt;li&gt;CreateWarEnd&lt;/li&gt;&lt;li&gt;CreateWarStart&lt;/li&gt;&lt;li&gt;DocEnd&lt;/li&gt;&lt;li&gt;DocSkip&lt;/li&gt;&lt;li&gt;DocStart&lt;/li&gt;&lt;li&gt;Exiting&lt;/li&gt;&lt;li&gt;GenerateControllerEnd&lt;/li&gt;&lt;li&gt;GenerateViewsEnd&lt;/li&gt;&lt;li&gt;InstallPluginStart&lt;/li&gt;&lt;li&gt;IntegrateWithInit&lt;/li&gt;&lt;li&gt;PackagePluginEnd&lt;/li&gt;&lt;li&gt;PackagePluginStart&lt;/li&gt;&lt;li&gt;PackagingEnd&lt;/li&gt;&lt;li&gt;PluginLoadEnd&lt;/li&gt;&lt;li&gt;PluginLoadStart&lt;/li&gt;&lt;li&gt;PluginUninstalled&lt;/li&gt;&lt;li&gt;SetClasspath&lt;/li&gt;&lt;li&gt;StatsStart&lt;/li&gt;&lt;li&gt;StatusError&lt;/li&gt;&lt;li&gt;StatusFinal&lt;/li&gt;&lt;li&gt;StatusUpdate&lt;/li&gt;&lt;li&gt;TestCompileEnd&lt;/li&gt;&lt;li&gt;TestCompileStart&lt;/li&gt;&lt;li&gt;TestPhaseEnd&lt;/li&gt;&lt;li&gt;TestPhasesEnd&lt;/li&gt;&lt;li&gt;TestPhasesStart&lt;/li&gt;&lt;li&gt;TestPhaseStart&lt;/li&gt;&lt;li&gt;TestProduceReports&lt;/li&gt;&lt;li&gt;TestSuiteEnd&lt;/li&gt;&lt;li&gt;TestSuiteStart&lt;/li&gt;&lt;li&gt;WebXmlEnd&lt;/li&gt;&lt;li&gt;WebXmlStart&lt;/li&gt;&lt;/ul&gt;I don't know what all of them do, but it should be easy enough to guess from the name.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1665136999654964268-2168674486222921929?l=mentaldetritus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentaldetritus.blogspot.com/feeds/2168674486222921929/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mentaldetritus.blogspot.com/2011/09/grails-events.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/2168674486222921929'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/2168674486222921929'/><link rel='alternate' type='text/html' href='http://mentaldetritus.blogspot.com/2011/09/grails-events.html' title='Grails events'/><author><name>Hayden</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1665136999654964268.post-4353423335164443720</id><published>2011-09-13T14:18:00.000-07:00</published><updated>2011-09-13T14:20:11.499-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><title type='text'>Git and empty directories</title><content type='html'>One minor annoyance I have with Git is that it cannot track empty directories. This is especially annoying if you are working with an application framework, which creates an intricate structure of empty directories.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A common work-around you will see is to create an empty &lt;span class="Apple-style-span" style="background-color: #cccccc;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;.gitignore&lt;/span&gt;&lt;/span&gt; file in each empty directory. It's not a very elegant solution, but it gets the job done. The trick is making sure you actually find every empty directory. So, I wrote a simple bash script, &lt;a href="http://haydenmuhl.com/gitify.sh"&gt;gitify.sh&lt;/a&gt;, to do it for you.&lt;br /&gt;&lt;blockquote style="background-color: #cccccc;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;#!/bin/bash&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;gitify() {&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp; &amp;nbsp; if [[ -z $(ls -1A "$1") ]]&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp; &amp;nbsp; then&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; touch "$1/.gitignore"&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp; &amp;nbsp; else&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; for file in "$1"/*&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; do&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if [ -d "$file" ]&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; then&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; gitify "$file"&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; fi&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; done&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;nbsp; &amp;nbsp; fi&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;rootdir=$(readlink -f .)&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;gitify $rootdir&lt;/span&gt;&lt;/blockquote&gt;Just navigate to the root directory of your Git project, and run the script. It will descend from the working directory into all subdirectories and drop a zero byte &lt;span class="Apple-style-span" style="background-color: #cccccc;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;.gitignore&lt;/span&gt;&lt;/span&gt; file in any empty directory it finds. Just &lt;span class="Apple-style-span" style="background-color: #cccccc;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;git-add&lt;/span&gt;&lt;/span&gt; all the newly created files and check them in to your repository.&lt;br /&gt;&lt;br /&gt;I'm posting this not so much for the benefit of others as for myself. This is probably the fifth time I've written this script, because I keep losing it or deleting it. Maybe now that it's posted on the internet I won't lose it so easily.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1665136999654964268-4353423335164443720?l=mentaldetritus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentaldetritus.blogspot.com/feeds/4353423335164443720/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mentaldetritus.blogspot.com/2011/09/git-and-empty-directories.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/4353423335164443720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/4353423335164443720'/><link rel='alternate' type='text/html' href='http://mentaldetritus.blogspot.com/2011/09/git-and-empty-directories.html' title='Git and empty directories'/><author><name>Hayden</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1665136999654964268.post-4693271935757484520</id><published>2011-09-07T21:22:00.000-07:00</published><updated>2011-09-07T21:23:57.565-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><title type='text'>Easiest way to move tabs between Chrome windows</title><content type='html'>I just discovered something in Chrome that will make life much easier for me.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I often surf the web with two or more chrome windows open, both maximized. For example, I might have Reddit and email open in one window and tutorials and documentation open in another windows. Every so often I open a tab in the wrong window and I want to move it from one window to the other. This is an easy drag and drop... unless both windows are maximized.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Chrome has a spiffy little list of recently closed tabs, and it turns out this list is shared between multiple windows. If you want to move a tab from one window to the other, just close the tab in one window, open a new tab in the other window and select the first item on the recently closed tab list.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1665136999654964268-4693271935757484520?l=mentaldetritus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentaldetritus.blogspot.com/feeds/4693271935757484520/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mentaldetritus.blogspot.com/2011/09/easiest-way-to-move-tabs-between-chrome.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/4693271935757484520'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/4693271935757484520'/><link rel='alternate' type='text/html' href='http://mentaldetritus.blogspot.com/2011/09/easiest-way-to-move-tabs-between-chrome.html' title='Easiest way to move tabs between Chrome windows'/><author><name>Hayden</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1665136999654964268.post-5668606623127218211</id><published>2011-05-10T12:09:00.000-07:00</published><updated>2011-09-04T10:55:50.426-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computers'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><title type='text'>Groovy on Grails: Serving static files from the root context</title><content type='html'>Grails is a great platform for web development, but there are certain things that are fairly trivial to do in a production environment that are rather difficult in a development environment. One of those is serving up static files from the root of your host name. These could be anything, like &lt;span class="Apple-style-span" style="background-color: #cccccc; font-family: 'Courier New', Courier, monospace;"&gt;robots.txt&lt;/span&gt; or &lt;span class="Apple-style-span" style="background-color: #cccccc; font-family: 'Courier New', Courier, monospace;"&gt;crossdomain.xml&lt;/span&gt;. It's simple enough to do this with Tomcat. Simply &lt;a href="http://wiki.apache.org/tomcat/HowTo#How_do_I_make_my_web_application_be_the_Tomcat_default_application_.3F"&gt;configure your ROOT context&lt;/a&gt;, drop in the files and you're done.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;But how do you do this in a development environment? Generally, a developer will use the &lt;span class="Apple-style-span" style="background-color: #cccccc;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;grails run-app&lt;/span&gt;&lt;/span&gt;&amp;nbsp;command. This invokes a built-in instance of &lt;a href="http://jetty.codehaus.org/jetty/"&gt;Jetty&lt;/a&gt;, which makes your Grails application available at the URL &lt;span class="Apple-style-span" style="background-color: #cccccc; font-family: 'Courier New', Courier, monospace;"&gt;http://localhost:8080/yourApp/&lt;/span&gt;. It's easy enough to serve static files from below the yourApp directory. Simply drop them in the&amp;nbsp;&lt;span class="Apple-style-span" style="background-color: #cccccc; font-family: 'Courier New', Courier, monospace;"&gt;web-app&lt;/span&gt;&amp;nbsp;folder in your Grails project, but there isn't any way to serve static files from above this.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;The problem is that Grails is not designed to work this way. Many of the solutions I found online try to work against Grails' design, such as &lt;a href="http://colinharrington.net/blog/2008/07/grails-jetty-and-crossdomainxml/"&gt;hacking at the internals&lt;/a&gt; directly, or forcing the configuration to&lt;a href="http://ca.rroll.net/2009/03/27/configuring-the-grails-root-application-context/"&gt; serve everything from the root context&lt;/a&gt;. These have potential problems when it comes to things like upgrading Grails, or deploying to production.&lt;br /&gt;&lt;br /&gt;Instead, I opted to find an external mechanism to serve these static files. This way the Grails application can remain untethered from the rest of its environment. It doesn't need to be aware of what's going on outside its context, its realm of control. This can be accomplished with Apache and &lt;span class="Apple-style-span" style="background-color: #cccccc; font-family: 'Courier New', Courier, monospace;"&gt;mod_proxy&lt;/span&gt;. We can use Apache to serve documents from the root, then we can use &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;span class="Apple-style-span" style="background-color: #cccccc;"&gt;mod_proxy&lt;/span&gt; &lt;/span&gt;to delegate any requests from a subdirectory to the Jetty instance used by Grails.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. Install Apache httpd 2.2&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;The specifics of installing httpd are beyond the scope of this blog post. If your operating system has a packaging system (apt-get, yum, etc.), use that. If not, refer to the available Apache documentation.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://httpd.apache.org/docs/2.2/install.html"&gt;Install from source&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://httpd.apache.org/docs/2.2/platform/"&gt;Install for Windows&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;For the rest of this tutorial, I will be assuming use of a Linux system.&lt;br /&gt;&lt;br /&gt;Start httpd.&lt;br /&gt;&lt;blockquote style="background-color: #cccccc;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;sudo /sbin/service httpd start&lt;/span&gt;&lt;/blockquote&gt;Test that it is installed correctly using a web browser.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. Create a root directory&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Pick a location on your disk where you will keep your static files. This will be the document root for httpd. I will be using /var/grails_root.&lt;br /&gt;&lt;blockquote style="background-color: #cccccc;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;mkdir /var/grails_root&lt;br /&gt;touch /var/grails_root/crossdomain.xml&lt;/span&gt;&lt;/blockquote&gt;&lt;b&gt;3. Create a VirtualHost in httpd.conf&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Open httpd.conf in your favorite text editor.&lt;br /&gt;&lt;blockquote style="background-color: #cccccc;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;vim /etc/httpd/conf/httpd.conf&lt;/span&gt;&lt;/blockquote&gt;Pick your favorite port, and create a virtual host on that port. I will be using 9090, but any port will do.&lt;br /&gt;&lt;br /&gt;Add these lines to httpd.conf&lt;br /&gt;&lt;blockquote style="background-color: #cccccc;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;Listen 9090&lt;br /&gt;&amp;lt;VirtualHost *:9090&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; DocumentRoot "/var/grails_root"&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;Directory "/var/grails_root"&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Allow from all&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/Directory&amp;gt;&lt;br /&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/span&gt;&lt;/blockquote&gt;Restart httpd&lt;br /&gt;&lt;blockquote style="background-color: #cccccc;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;sudo /sbin/service httpd restart&lt;/span&gt;&lt;/blockquote&gt;Test that you are now able to access the static files in your document root directory. If not, you will need to fix this before moving on to the next step.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4. Enable mod_proxy and mod_proxy_http&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;You need to load both of these modules.&amp;nbsp;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;mod_proxy&lt;/span&gt; has the base functionality for proxying, and the &lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;mod_proxy_xxx&lt;/span&gt; modules have information specific to a protocol. They ship standard with httpd 2.2, so you shouldn't need to install anything extra.&lt;br /&gt;&lt;br /&gt;Add these lines to httpd.conf&lt;br /&gt;&lt;blockquote style="background-color: #cccccc;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;LoadModule proxy_module modules/mod_proxy.so&lt;br /&gt;LoadModule proxy_http_module modules/mod_proxy_http.so&lt;/span&gt;&lt;/blockquote&gt;&lt;div&gt;Now modify the virtual host you set up in the previous step. (You can omit the comments)&lt;/div&gt;&lt;div&gt;&lt;blockquote style="background-color: #cccccc;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;&amp;lt;VirtualHost *:9090&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; DocumentRoot "/var/grails_root"&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;Directory "/var/grails_root"&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Allow from all&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/Directory&amp;gt;&lt;br /&gt;# New lines start here&lt;br /&gt;&amp;nbsp; &amp;nbsp; ProxyRequests Off&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;Proxy *&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Order deny,allow&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Allow from all&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/Proxy&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; ProxyPass /grailsApp http://your.grails.server:8080/grailsApp&lt;br /&gt;# New lines end here&lt;br /&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;Restart httpd&lt;/div&gt;&lt;blockquote style="background-color: #cccccc;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"&gt;sudo /sbin/service httpd restart&lt;/span&gt;&lt;/blockquote&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;Now, you should be able to access both your static files and your Grails app via port 9090.&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;More information on this can be found&amp;nbsp;&lt;a href="http://docs.codehaus.org/display/JETTY/Configuring+mod_proxy"&gt;here&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1665136999654964268-5668606623127218211?l=mentaldetritus.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mentaldetritus.blogspot.com/feeds/5668606623127218211/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://mentaldetritus.blogspot.com/2011/05/groovy-on-grails-serving-static-file.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/5668606623127218211'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1665136999654964268/posts/default/5668606623127218211'/><link rel='alternate' type='text/html' href='http://mentaldetritus.blogspot.com/2011/05/groovy-on-grails-serving-static-file.html' title='Groovy on Grails: Serving static files from the root context'/><author><name>Hayden</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
