<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Biodegradable Geek &#187; Linux</title>
	<atom:link href="http://biodegradablegeek.com/category/linux/feed/" rel="self" type="application/rss+xml" />
	<link>http://biodegradablegeek.com</link>
	<description></description>
	<lastBuildDate>Tue, 22 Jun 2010 21:52:41 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=</generator>
		<item>
		<title>Bash Tips for Power Users</title>
		<link>http://biodegradablegeek.com/2009/06/bash-tips-for-power-users/</link>
		<comments>http://biodegradablegeek.com/2009/06/bash-tips-for-power-users/#comments</comments>
		<pubDate>Wed, 10 Jun 2009 19:22:14 +0000</pubDate>
		<dc:creator>Isam</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[List]]></category>
		<category><![CDATA[Misc]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[getting things done]]></category>
		<category><![CDATA[scripting]]></category>

		<guid isPermaLink="false">http://biodegradablegeek.com/?p=105</guid>
		<description><![CDATA[Every Geek site needs an obligatory Bash Tips post Copy Files Securely Between Two Machines I used to always forget the syntax for this, until I realized that the syntax is exactly like the standard cp command. In fact, you can copy files like you normally would using scp, on your local machine. The following [...]]]></description>
			<content:encoded><![CDATA[<p>Every Geek site needs an obligatory Bash Tips post</p>
<h2><strong>Copy Files Securely Between Two Machines</strong></h2>
<p>I used to always forget the syntax for this, until I realized that the syntax is exactly like the standard <strong>cp</strong> command. In fact, you can copy files like you normally would using scp, on your local machine. The following are equivalent:</p>
<pre class="brush: bash; title: ; notranslate">
$ cp file file.orig
$ scp file file.orig
</pre>
<p>Where they differ is, <strong>scp</strong> lets you copy files over a network, through SSH. Here&#8217;s an example:</p>
<pre class="brush: bash; title: ; notranslate">
$ scp contents.txt silver@ssh.domain.com:/tmp
</pre>
<p>This will copy local file contents.txt to /tmp on the remote machine ssh.domain.com, as user silver. Here are some more examples:</p>
<pre class="brush: bash; title: ; notranslate">
$ scp draft.pdf ssh.domain.com:
</pre>
<p>(copy draft.pdf to my home dir on remote machine. username is implied to be the same locally and remotely.)</p>
<pre class="brush: bash; title: ; notranslate">
$ scp swine.jpg rex@ssh.domain.com
</pre>
<p>(<strong>read</strong>: This will copy swine.jpg to local machine as a file named rex@ssh.domain.com. To make it go remote, append a : to the address, like above)<strong> </strong></p>
<p><strong>scp</strong> supports, among other things, compression (-C) and recursive copying of directories (-r).<br />
<strong> </strong></p>
<pre class="brush: bash; title: ; notranslate">
$ scp -rC code/ ssh.domain.com:/archive/code_02032009
</pre>
<p><strong></strong></p>
<p>Trying to copy to a directory you don&#8217;t have permission to (/usr etc) will fail.</p>
<h2>Don&#8217;t Get Lost Jumping To and Fro Between Directories</h2>
<p>You can use <strong>cd -</strong> to jump to the previous (NOT parent) dir. For example:</p>
<pre class="brush: bash; title: ; notranslate">
kiwi@localhost: ~ $ cd /usr/local/share
kiwi@localhost: /usr/local/share $ cd -
/home/kiwi
kiwi@localhost: ~ $ cd -
/usr/local/share
kiwi@localhost: /usr/local/share $
</pre>
<p>Another way is using <strong>pushd/popd</strong> &#8211; A Last In First Out (LIFO) stack of dirs.</p>
<pre class="brush: bash; title: ; notranslate">
kiwi@localhost: ~ $ pushd /usr/local/share/
/usr/local/share ~
</pre>
<p><strong>pushd</strong> is like cd but keeps note of the current dir before cd&#8217;ing into a new one. The stack of dirs is listed every time you invoke <strong>pushd</strong> <em>(the &#8220;/usr/local/share ~&#8221; output you see above.)</em></p>
<pre class="brush: bash; title: ; notranslate">
kiwi@localhost: /usr/local/share $ pushd /
/ /usr/local/share ~
</pre>
<p>Stack is ordered left to right, latest push first. If we pop the first dir off:</p>
<pre class="brush: bash; title: ; notranslate">
kiwi@localhost: / $ popd
/usr/local/share /tmp ~
kiwi@localhost: /usr/local/share $
</pre>
<p>We&#8217;re back in the share dir. We can keep popping until there&#8217;s nothing left (throws an error):</p>
<pre class="brush: bash; title: ; notranslate">
kiwi@localhost: /usr/local/share $ popd
/tmp ~
kiwi@localhost: /tmp $ pushd /lib
/lib /tmp ~
kiwi@localhost: /lib $ popd
/tmp ~
kiwi@localhost: /tmp $ popd
~
kiwi@localhost: ~ $ popd
bash: popd: directory stack empty
</pre>
<h2>Working with Long Lines</h2>
<p>No need for more Bash shortcut <a href="http://cheat.errtheblog.com/s/bash/" target="_blank">cheat sheets</a>, but here are some useful ones to help you work with long lines.</p>
<p>You can jump to the <strong>start &amp; end</strong> of a line using <strong>CTRL+a &amp; CTRL+e</strong> respectively. Example (* is the cursor):</p>
<pre class="brush: bash; title: ; notranslate">
kiwi@localhost: ~ $ echo al the ducks are swimming in the w*
</pre>
<p>and you want to fix the first word. You can hop to the beginning of the line with <strong>CTRL+a</strong>:</p>
<pre class="brush: bash; title: ; notranslate">
kiwi@localhost: ~ $ *echo al the ducks are swimming in the w
</pre>
<p>and now you can jump to the end of the misspelled word &#8220;al&#8221; using <strong>CTRL+Right</strong> twice to correct it:</p>
<pre class="brush: bash; title: ; notranslate">
kiwi@localhost: ~ $ echo all*the ducks are swimming in the w
</pre>
<p>Now ctrl+e to jump to the end of line:</p>
<pre class="brush: bash; title: ; notranslate">
kiwi@localhost: ~ $ echo all the ducks are swimming in the w*
</pre>
<p>Instead of backspacing every character, use <strong>ALT+Backspace</strong> to backspace entire words. You can also delete <strong>all</strong> or part of a line using <strong>CTRL+u</strong> combo. It deletes everything before the cursor. Likewise, <strong>CTRL+k</strong> wipes out everything after the cursor. I&#8217;ve developed a habit of using CTRL+e CTRL+k to delete lines.</p>
<p>Bash has a lot of <strong>ALT</strong> commands that let you move and manipulate words. <strong>ALT+l</strong> and <strong>ALT+u</strong> will make a word in front of the cursor lowercase or uppercase, for example. A neat one I don&#8217;t think I ever used is ALT+\ It pulls everything after the cursor left to the first non-whitespace character. Here&#8217;s an example, * is the cursor:</p>
<p><strong>BEFORE:</strong></p>
<pre class="brush: bash; title: ; notranslate">
$ my     spacebar is    *sticky
</pre>
<p><strong>AFTER (ALT+\):</strong></p>
<pre class="brush: bash; title: ; notranslate">
$ my     spacebar issticky
</pre>
<h2>Avoid Retyping Commands &amp; Arguments</h2>
<p><strong>ESC + .</strong> is <span style="text-decoration: underline;">very</span> useful. Escape followed by a period will output the argument you sent to your last Bash command. Command calls themselves are outputted if they were invoked without any arguments <em>(popd, ls, etc).</em></p>
<p>Example, unzipping a file and moving the archive to /tmp:</p>
<pre class="brush: bash; title: ; notranslate">
$ unzip archive-with-a-long-ambiguous-name-03092009-5960-1.2.5.zip
$ mv archive-with-a-long-ambiguous-name-03092009-5960-1.2.5.zip /tmp
</pre>
<p>In the mv command, the archive name was outputted by pressing <strong>ESC+.</strong> (full command being mv (ESC+.) /tmp) There was no need to type the long archive name twice.</p>
<p>The argument is taken from your bash history. You can keep invoking ESC+. to cycle back through all your recent command arguments. (history -c to clear)</p>
<p>Try not to forget this; You&#8217;ll naturally find plenty of uses for it.</p>
<p>Another way to avoid re-typing commands is <strong>CTRL+R</strong>. It will initiate a search of your command history. Begin typing, and watch Bash try to complete your command from previous ones you entered.</p>
<h2>Command Getting Too Big? Send it to your Editor</h2>
<p>Sometimes you begin writing what you think will be a simple command, only to realize that it has grown too complex for the command line, and you wish you were in your text editor.</p>
<p>First make sure your default editor is set. This is either in $EDITOR (export EDITOR=/usr/local/bin/vim) or elsewhere depending on the distro.</p>
<p>Use &#8220;fc&#8221; to open the last executed command in your editor:</p>
<pre class="brush: bash; title: ; notranslate">
ls -paul --sort=size
... ls output ...
fc
</pre>
<p>Now the <em>ls</em> line will be open in your editor. But what if you hadn&#8217;t executed the command yet? No problem. You&#8217;re sending off an email, but quickly realize that the command line isn&#8217;t ideal for everything:</p>
<pre class="brush: bash; title: ; notranslate">
echo -e &quot;Dear Santa, \n\n\tIt has become evident that your fat ass is contributing to Global Warming, primarily due to the large quantity of coal you distribute annually. We hereby
</pre>
<p>No matter where you are on the line, hit <strong>CTRL+x, CTRL+e</strong> to invoke your editor, which now contains what you were typing on the cmd line.</p>
<p>I always find myself wanting to finish a command in vim, but unwilling to type the first few lines over, especially when I&#8217;m trying to write a for loop or any ugly multiline Bash code.</p>
<p><strong>IMPORTANT: Whatever you type in your editor is executed automatically after you quit the editor.</strong><br />
<span id="more-105"></span></p>
<h2>Multiple Commands on a Single Line</h2>
<p>There are a number of ways to piece together commands (||, pipes, etc), depending on your need, but sometimes, you just commands executed consecutively. You can use ; or &amp;&amp;.</p>
<p><strong>semicolon (;) vs AND (&amp;&amp;)</strong>: The semicolon will run through each command consecutively, whereas &amp;&amp; is a little smarter, and will not continue if a command does not end successfully (return 0 &#8211; you can check the return value of the last app ran with <strong>echo $?</strong>).</p>
<p>&amp;&amp; is generally safer. i.e., ./configure &amp;&amp; make (&amp;&amp; sudo make install)</p>
<p>AND</p>
<pre class="brush: bash; title: ; notranslate">
$ cp bogus &amp;amp;&amp;amp; echo &quot;** copied&quot;
cp: missing destination file operand after `bogus'
Try `cp --help' for more information.
</pre>
<p>SEMICOLON;</p>
<pre class="brush: bash; title: ; notranslate">
cp bogus; echo &quot;** copied... or did I? tun tun tunnn!&quot;
cp: missing destination file operand after `bogus'
Try `cp --help' for more information.
** copied... or did I? tun tun tunnn!
</pre>
<h2>Convert between DOS and UNIX ASCII files</h2>
<p>Sometimes you get a text file that has weird ^M characters in it. These are due to a difference in how Unix and Windows systems end lines. You can convert between these formats using <strong>unix2dos</strong> or <strong>todos</strong> and <strong>dos2unix</strong> or <strong>fromdos</strong>.</p>
<pre class="brush: bash; title: ; notranslate">
$ mkdir /tmp/rcfl
$ cd /tmp/rcfl
$ echo -e &quot;Justa Lonely\nASCII File&quot; &gt; out
$ file out
out: ASCII text
$ todos out
$ file out
out: ASCII text, with CRLF line terminators
$ vim out # notice [dos] flag in status bar, quit :q!
$ fromdos out
$ file out
out: ASCII text
</pre>
<h2>Background Processes</h2>
<p>Have a little more control over your apps.</p>
<p><strong>Stop Right Thurr</strong><br />
When a program is running in the foreground, you no longer have access to the command line. An example is &#8216;tail -f&#8217; or &#8216;ruby script/server&#8217;</p>
<p>You can have a running process pause for a sec with <strong>CTRL+z</strong>.<br />
Do your dirty work and then bring the app back to the foreground with <strong>fg</strong>.<br />
To list the processes you have paused, use <strong>jobs</strong></p>
<pre class="brush: bash; title: ; notranslate">
$ tail -f useful.log
00:00:50 User did something that was log-worthy
00:00:56 User did something that was log-worthy
00:00:57 User did something that was log-worthy

# (press CTRL+z)
[1]+  Stopped                 tail -f useful.log

$ echo &quot;look ma, I can type&quot;
look ma, I can type

$ fg
tail -f useful.log

# (press CTRL+z)
[1]+  Stopped                 tail -f useful.log

$ tail -f blah.tmp

# (press CTRL+z)
[2]+  Stopped                 tail -f blah.tmp

$ jobs
[1]-  Stopped                 tail -f useful.log
[2]+  Stopped                 tail -f blah.tmp
$ fg 1
(process [2] continues)
</pre>
<p><strong>In the Background</strong></p>
<p>You can have a process start in the background by appending to it a <strong>&amp;</strong>.<br />
and bring this to the foreground using <strong>fg [#]</strong>.<br />
As before, jobs will list background processes, but with status <em>Running</em> instead of <em>Stopped</em>.</p>
<p>Programs running in the background will still output to stdout, which means they&#8217;ll make the shell ugly. So if you plan on using them, think about redirecting the output.</p>
<h2>Bash Redirection</h2>
<p>Some things are mentioned on nearly every &#8216;bash tips&#8217; page &#8212; like redirecting output. Here are the basics. We&#8217;re concerned with 2 I/O streams: STDOUT and STDERR. STDOUT has a value of 1, and it is the screen. If a program writes to stdout, that text is shown in the console. Errors are sent through a different stream, stderr, which has a value of 2. Value 0 is stdin, used for user input. The technical details aren&#8217;t important. Just remember that 1 is screen and 2 is error.</p>
<p>There&#8217;s a number of ways to redirect output:</p>
<pre class="brush: bash; title: ; notranslate">
$ echo &quot;asdfasdf&quot; 1&gt; /tmp/asdf.txt # overwrite existing file
$ echo &quot;asdfasdf&quot; &gt; /tmp/asdf.txt # (same, 1 is default, optional)
$
$ echo &quot;32452345&quot; &gt;&gt; /tmp/asdf.txt # append to end of existing file*
$ echo &quot;wash the dishes&quot; &gt; /dev/null # just ignore output
$ echo &quot;wash the dishes&quot; 2&gt; /dev/null # just ignore errors
$
$ more 1&gt; /dev/null # error still shown
$ more 2&gt; /dev/null # nothing shown
$ more &amp;&gt; /dev/null # nothing shown
$
$ more 2&gt;| /dev/null # silence errors
$ more &gt;| /tmp/more.txt # save output to file
$
$ more 1&gt; /tmp/more.txt 2&gt;&amp;1 # redirect stdout to file and redirect stderr to stdout (same file)
$ more 2&gt; /tmp/more.txt 1&gt;&amp;2 # have stdout follow stderr to file
</pre>
<p>To redirect output to a file &amp; screen, use <strong>tee</strong></p>
<pre class="brush: bash; title: ; notranslate">
$ echo &quot;dont forget the milk&quot; | tee /tmp/toforget.txt
</pre>
<p>More a more extensive guide on redirection, see <a href="http://tldp.org/LDP/abs/html/io-redirection.html" target="_blank">Bash IO Redirection</a> or some of the External Links below.</p>
<h2>Art of teh Alias</h2>
<p>I use a lot of aliases. Here are a few:</p>
<pre class="brush: bash; title: ; notranslate">
# I use these a lot. Can also have aptupdate, aptremove etc...
alias aptinstall='sudo apt-get install'
alias aptsearch='apt-cache search'
alias suvim='sudo vim'

# Aliasing command names. To use original commands, you'd need to specify absolute path.
alias a2restart='sudo apache2ctl restart'
alias gem='sudo gem'
alias checkinstall='sudo checkinstall'

# I used these to workaround the infamous FF memory leak (ugly)
# alias swapoff='sudo swapoff'
# alias swapon='sudo swapon'

# Going places. This + ssh keypair
alias macbookshell='ssh 192.168.1.17'
alias workshell='ssh meh@ssh.domain.com'

# Pretty output. (--group-directories-first might not work on your system).
alias lsf='ls -hAlF --group-directories-first --color=always --time-style=+&quot; %m/%d/%y %I:%M %p &quot;'

# List only directories
alias lsd='ls -d */'

# I'm a measly human!
alias free=&quot;free -m&quot;

# 'gimme x' is equivalent to 'sudo chown me.me x'
# alias gimme=&quot;ME6=`whoami` &amp;amp;&amp;amp; sudo \&quot;chown $ME6.$ME6\&quot;&quot;

# Usage: nullminate bloated-file.log
alias nullminate=&quot;cat /dev/null &gt; &quot;

# Search contents of an entire dir. Usage: scan &quot;PESKY_VARIABLE ?=&quot; project-123/
alias scan=&quot;grep -Rin --color&quot;
</pre>
<p>These should go in a ~/.bash_aliases file and invoked from within your user conf (.bashrc?)</p>
<p><!--<br />
screen<br />
public keys<br />
sub sections (shortcuts, history, redirection)<br />
--></p>
<p><strong>External links (related): </strong></p>
<ul>
<li><a href="http://www.caliban.org/bash/" target="_blank">Working more productively with bash 2.x/3.x</a></li>
<li><a href="http://www.hypexr.org/bash_tutorial.php" target="_blank">Getting Started with BASH</a></li>
<li><a href="http://www.wains.be/index.php/2007/11/26/bash-tips-and-tricks/" target="_blank">Bash Tips &amp; Tricks</a></li>
<li><a href="http://hacktux.com/bash/script/efficient" target="_blank">10 Tips for Writing Efficient Bash Scripts</a></li>
<li><a href="http://www.linuxtutorialblog.com/post/tutorial-the-best-tips-tricks-for-bash" target="_blank">Best Tips &amp; Trips for Bash</a></li>
<li><a href="http://linuxhelp.blogspot.com/2005/08/bash-shell-shortcuts.html" target="_blank">Bash Shell Shortcuts</a></li>
<li><a href="http://bashish.sourceforge.net/" target="_blank">Bashish</a></li>
<li><a href="http://www.davidpashley.com/articles/writing-robust-shell-scripts.html" target="_blank">Writing Robust Shell Scripts</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://biodegradablegeek.com/2009/06/bash-tips-for-power-users/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>How to Block AIM&#8217;s Annoying &#8216;AOL System Msg&#8217; in Pidgin</title>
		<link>http://biodegradablegeek.com/2009/05/how-to-block-aims-annoying-aol-system-msg-in-pidgin/</link>
		<comments>http://biodegradablegeek.com/2009/05/how-to-block-aims-annoying-aol-system-msg-in-pidgin/#comments</comments>
		<pubDate>Sat, 02 May 2009 04:44:12 +0000</pubDate>
		<dc:creator>Isam</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[Workarounds]]></category>
		<category><![CDATA[annoying]]></category>
		<category><![CDATA[chat]]></category>
		<category><![CDATA[pidgin]]></category>

		<guid isPermaLink="false">http://biodegradablegeek.com/?p=426</guid>
		<description><![CDATA[The following plugin for Pidgin will block the incredibly annoying and useless notifications from AOLSystemMsg on AIM. &#8220;AOL System Msg: Your screen name (mrEman) is now signed into AOL(R) Instant Messenger (TM) in 2 locations. Click here for more information.&#8221; To use, paste code in file, save file as blockaolsystemmsg.pl in ~/.purple/plugins/ and then open [...]]]></description>
			<content:encoded><![CDATA[<p>The following plugin for <a href="http://www.pidgin.im/">Pidgin</a> will block the incredibly annoying and useless notifications from AOLSystemMsg on AIM.</p>
<blockquote><p>&#8220;AOL System Msg: Your screen name (mrEman) is now signed into AOL(R) Instant Messenger (TM) in 2 locations. Click here for more information.&#8221;</p></blockquote>
<p>To use, paste code in file, save file as <strong>blockaolsystemmsg.pl</strong> in <strong>~/.purple/plugins/</strong> and then open (or re-open) Pidgin and go to Tools -&gt; Plugins (or press CTRL+U), and enable &#8220;Block AOLSystemMsg.&#8221; That should be it!</p>
<p><em>If you&#8217;re having any trouble, try going to Help -> Debug to open up Pidgin&#8217;s debug console. </em></p>
<pre class="brush: perl; title: ; notranslate">
#!/usr/bin/perl
# BlockAOLSystemMsg plugin tested on Pidgin 2.5.5. Put in ~/.purple/plugins/ and enable
use Purple;
our $target = 'AOL System Msg'; # case-insensitive
our $plugin_name = 'Block AOLSystemMsg'; 

%PLUGIN_INFO = (
  perl_api_version =&gt; 2,
  name =&gt; $plugin_name,
  version =&gt; &quot;0.1&quot;,
  summary =&gt; &quot;Blocks the screen name 'AOL System Msg'&quot;,
  description =&gt; &quot;Ignore annoying 'your SN has signed on at 2 locations' AIM message&quot;,
  author =&gt; &quot;Isam &quot;,
  url =&gt; &quot;http://biodegradablegeek.com&quot;,
  load =&gt; &quot;plugin_load&quot;,
  unload =&gt; &quot;plugin_unload&quot;
);

sub loginfo { Purple::Debug::info($plugin_name, &quot; @_\n&quot;); }
sub minimize {
  my $r = lc($_[0]);
  $r =~ s/ //g;
  return $r;
}

sub plugin_init { return %PLUGIN_INFO; }

sub plugin_load {
  my $plugin = shift;
  $target = minimize($target);
  loginfo(&quot;Sight set on '$target'&quot;);
  Purple::Signal::connect(Purple::Conversations::get_handle(),
                          'receiving-im-msg', $plugin, \&amp;callback, '');
}

sub plugin_unload {
  my $plugin = shift;
  loginfo('Block AOLSystemMsg Unloaded.');
}

sub callback {
  my ($acc, $sender, $msg, $flags) = @_;
  if (minimize($sender) eq $target) {
    loginfo(&quot;(BLOCKED) &lt;$sender&gt; $msg&quot;);
    return 1
  };
}
</pre>
<p>update: Fixed the botched code. Thanks.</p>
]]></content:encoded>
			<wfw:commentRss>http://biodegradablegeek.com/2009/05/how-to-block-aims-annoying-aol-system-msg-in-pidgin/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>I Can&#8217;t Live Without My vim Config</title>
		<link>http://biodegradablegeek.com/2009/04/i-cant-live-without-my-vim-config/</link>
		<comments>http://biodegradablegeek.com/2009/04/i-cant-live-without-my-vim-config/#comments</comments>
		<pubDate>Sat, 11 Apr 2009 17:43:18 +0000</pubDate>
		<dc:creator>Isam</dc:creator>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[editors]]></category>
		<category><![CDATA[gvim]]></category>
		<category><![CDATA[ide]]></category>
		<category><![CDATA[vi]]></category>
		<category><![CDATA[vim]]></category>

		<guid isPermaLink="false">http://biodegradablegeek.com/?p=384</guid>
		<description><![CDATA[I have updated the vim page with my vimrc/gvimrc configs. Instead of repeating myself, I will quote some parts of the page .. More details and the vim config itself here I recommend turning backups on if you have them off. I personally hate having the ~ files all over my OS, so I keep [...]]]></description>
			<content:encoded><![CDATA[<p>I have updated the <a href="/vim">vim</a> page with my vimrc/gvimrc configs. Instead of repeating myself, I will quote some parts of the page ..</p>
<p><strong><a href="/vim">More details and the vim config itself here</a></strong></p>
<p>I recommend turning backups on if you have them off. I personally hate having the ~ files all over my OS, so I keep them along with the .swp files in 1 backup dir in ~/.vim/</p>
<p>The programming language skeleton stuff will detect what files you are editing and change options in vim by inheriting the specified files which I put in ~/.vim/skeletons and ~/.vim/inherit.</p>
<p>The skeletons are automatically inserted in new files that vim is aware of. For example, in my own config, I have ~/.vim/inherit/c which has all the usual includes and int main() code. When I make a new C file (&#8220;gvim hello.c&#8221;), the new file begins with the skeleton code already present. Neat huh?</p>
<p>The inherit files can be used to set specific options for each language. This can mean different bindings, whitespace options, themes, etc depending on what language you&#8217;re working with, automatically.</p>
<p><a href="/vim">See the vim page</a></p>
<p><strong>What options have helped you the most?</strong></p>
]]></content:encoded>
			<wfw:commentRss>http://biodegradablegeek.com/2009/04/i-cant-live-without-my-vim-config/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to Maintain Static Sites with Git &amp; Jekyll</title>
		<link>http://biodegradablegeek.com/2009/03/how-to-maintain-static-sites-with-git-jekyll/</link>
		<comments>http://biodegradablegeek.com/2009/03/how-to-maintain-static-sites-with-git-jekyll/#comments</comments>
		<pubDate>Wed, 01 Apr 2009 04:10:00 +0000</pubDate>
		<dc:creator>Isam</dc:creator>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Productivity]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[Snippets]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://biodegradablegeek.com/?p=371</guid>
		<description><![CDATA[Static sites in this context just means non-database driven sites. Your static site can be an elaborate PHP script or just a few markup and image files. For this I am using Jekyll &#8211; A neat Ruby gem that makes your static sites dynamic. It lets you create layouts and embed custom variables in your [...]]]></description>
			<content:encoded><![CDATA[<p>Static sites in this context just means non-database driven sites. Your static site can be an elaborate PHP script or just a few markup and image files. For this I am using <strong><a href="http://github.com/mojombo/jekyll/tree/master">Jekyll</a> &#8211; A neat Ruby gem that makes your static sites dynamic.</strong> It lets you create layouts and embed custom variables in your HTML (this is a &#8220;prototype&#8221; of the site). </p>
<p>Jekyll tackles all the nuisances involved in creating static pages (I used to add just enough PHP to make a layout). It works by running your prototype through some parsers and outputs plain static HTML/XML (RSS feeds) etc. It&#8217;s perfect for lightweight sites that would be impractical on WordPress, like a few static pages of information, landing pages, portfolio/resume pages, and parked domains. </p>
<p>Git takes care of keeping your development (local) and production (remote) environments synced. Git might be a little confusing if you&#8217;re learning it with the mindset that it works like Subversion. </p>
<p><strong>I&#8217;ll update this post when the guide is done. For now, the following will assume you&#8217;re familiar with Jekyll (or at least have an empty file in the prototype directory) and git. This Bash script simplifies creating the remote git repository:</strong></p>
<p>** please read through the code and make sure you know what this does, and what you&#8217;re doing. As of now, this is bias towards my own Apache/vhost setup. It&#8217;s trivial to edit for your specific needs. <strong>You&#8217;re using this at your own risk</strong>.</p>
<p>(<a href="http://code.biodegradablegeek.com/repogen.sh" target="_blank">direct link &#8211; repogen.sh</a>)</p>
<pre lang="bash">
#!/bin/sh
#
# 04/01/2009 | http://biodegradablegeek.com | GPL
#
# You should be in site (NOT public) root (be in same dir as public/ log/ etc)
# proto/ is created and will house the jekyll prototype
# public/ will be the generated static site
# the public/ folder will be REMOVED and regenerated on every push
# 

if [ -z "$1" ]; then
  echo "Usage: ./repogen.sh domain.comn"
  exit
fi

# optional. will make it easier to copy/paste cmd to clone repo
SSHURL="ssh.domain.com"
URL="$1"

echo "** creating tmp repo"
mkdir proto
cd proto
git init
touch INITIAL
git add INITIAL
git commit -a -m "Initial Commit"

echo "** creating bare repo"
cd ..
git clone --bare proto proto.git
mv proto proto.old
git clone proto.git
rm -rf proto.old

echo "** generating hook"
HOOK=proto.git/hooks/post-update

mv $HOOK /tmp
echo '#!/bin/sh' >> $HOOK
echo '# To enable this hook, make this file executable by "chmod +x post-update".' >> $HOOK
echo '#exec git-update-server-info' >> $HOOK
echo '' >> $HOOK
echo '' >> $HOOK
echo 'URL='"$URL" >> $HOOK
echo 'PROTO="/home/$USER/www/$URL/proto"' >> $HOOK
echo 'PUBLIC="/home/$USER/www/$URL/public"' >> $HOOK
echo  '' >> $HOOK
echo 'export GIT_DIR="$PROTO/.git"' >> $HOOK
echo 'pushd $PROTO > /dev/null' >> $HOOK
echo 'git pull' >> $HOOK
echo 'popd > /dev/null' >> $HOOK
echo '' >> $HOOK
echo "echo -----------------------------" >> $HOOK
echo "echo '** Pushing changes to '$URL" >> $HOOK
echo "echo '** Moving current public to /tmp'" >> $HOOK
echo 'mv "$PUBLIC" "/tmp/'$URL'public-`date '+%m%d%Y'`"' >> $HOOK
echo 'echo "** Generating new public"' >> $HOOK
echo 'jekyll "$PROTO" "$PUBLIC"' >> $HOOK

echo "** enabling hook"
chmod a+x $HOOK 

echo "** clone repo on local machina. example:"
echo "git clone ssh://$USER@$SSHURL/~$USER/www/$SSHURL/proto.git"
</pre>
<p><strong>Usage</strong></p>
<p>Your site structure might be different. <strong>repogen.sh</strong> is made by pasting the above code in a new file, and then chmod a+x to make it executable. This should be done on the remote server.</p>
<pre lang="bash">
cd www/domain.com/

ls
public/ private/ log/ cgi-bin/

./repogen.sh domain.com
</pre>
<p>Now on your local machine, clone the new repo, move your files in, and push:</p>
<pre lang="bash">
git clone ssh://[username]@ssh.domain.com/~[username]/www/domain.com/proto.git
cd proto/
cat "hello, world" > index.htm
git add index.htm
git commit -a -m 'first local commit'
git push
</pre>
<p>After you push your changes, the post-update hook will delete the public/ directory (the root of the site). This dir and its contents are automatically generated and will get wiped out on EVERY push. Keep this in mind. All your changes and content should reside in proto/. </p>
<p>The proto/ repo will pull in the new changes, and then Jekyll will be invoked to generate the updated site in public/ from the prototype.</p>
<p>Should you need to edit it, the <strong>post-update hook</strong> is in the bare git repo (proto.git/hooks/)</p>
<p>Thanks to the authors in the posts below for sharing ideas. I first read this git method on dmiessler&#8217;s site. </p>
<p><strong>Resources:</strong><br />
<a href="http://dmiessler.com/blog/using-git-to-maintain-your-website">dmiessler.com &#8211; using git to maintain static pages</a><br />
<a href="http://toroid.org/ams/git-website-howto">toroid.org &#8211; using git to manage a web site</a><br />
<a href="http://github.com/mojombo/jekyll/tree/master">Jekyll @ GitHub</a><br />
<a href="http://media.pragprog.com/titles/tsgit/chap-005-extract.html">git info</a><br />
<a href="http://www.nardol.org/2009/2/19/git-basics-reversing-the-git-sucks-effect">more git info</a></p>
]]></content:encoded>
			<wfw:commentRss>http://biodegradablegeek.com/2009/03/how-to-maintain-static-sites-with-git-jekyll/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Burning Xbox 360 Games on Linux (Stealth!)</title>
		<link>http://biodegradablegeek.com/2009/03/burning-xbox-360-games-on-linux-stealth/</link>
		<comments>http://biodegradablegeek.com/2009/03/burning-xbox-360-games-on-linux-stealth/#comments</comments>
		<pubDate>Tue, 10 Mar 2009 05:20:02 +0000</pubDate>
		<dc:creator>Isam</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Misc]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Workarounds]]></category>
		<category><![CDATA[games]]></category>
		<category><![CDATA[piracy]]></category>
		<category><![CDATA[workaround]]></category>

		<guid isPermaLink="false">http://biodegradablegeek.com/?p=361</guid>
		<description><![CDATA[You could run ImgBurn in Wine, or probably burn the games in VirtualBox running Windows, but that&#8217;s no solution&#8230; you&#8217;re reading this because you want to burn Xbox 360 games on Linux using native tools. It&#8217;s surprisingly easy! The games are usually an ISO file, along with a little DVD (.dvd) file that tells the [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://biodegradablegeek.com/wp-content/uploads/2009/03/xbox360-bg.jpg" alt="xbox360 bg Burning Xbox 360 Games on Linux (Stealth!)" title="xbox360-bg" width="300" height="290" class="alignright plainimg size-full wp-image-367" /><br />
You could run ImgBurn in Wine, or probably burn the games in VirtualBox running Windows, but that&#8217;s no solution&#8230; you&#8217;re reading this because <strong>you want to burn Xbox 360 games on Linux using native tools</strong>. It&#8217;s surprisingly easy!</p>
<p>The games are usually an ISO file, along with a little DVD (.dvd) file that tells the burner to use a layer break value of 1913760. This file is not necessary in Linux (or Windows) as we will be telling the app to use that break value explicitly.</p>
<p><strong>I will go into detail on how to setup what you need. If you&#8217;re impatient, you might wanna skip the setup and jump straight to the <a href="#quickie">quick recap</a>.</strong></p>
<p><strong>Extract the ISO</strong></p>
<pre lang="bash">
cd /games/360/GameX
rar  x kfc-gamex.part01.rar
</pre>
<p>If you don&#8217;t have rar (&#8220;winrar&#8221;) installed, lookie: </p>
<pre lang="text">
The program 'unrar' can be found in the following packages:
 * unrar-free
 * unrar
Try: sudo apt-get install
<selected package>
</pre>
<p>you can also DL it from <a href="http://rarlabs.com">rarlabs.com</a>.</p>
<p>Now we need to see if the game is stealth/valid. This is done using an app that runs natively on Linux (and OS X) called <strong>abgx360</strong>. </p>
<h2>Install abgx360</h2>
<p><img src="http://biodegradablegeek.com/wp-content/uploads/2009/03/abgx360-linux.png" alt="abgx360 linux Burning Xbox 360 Games on Linux (Stealth!)" title="abgx360-linux" width="695" height="112" class="size-full wp-image-365" /></p>
<p>Download the tar.gz files from <a href="http://abgx360.net/download.html">http://abgx360.net/download.html</a>. The TUI is nice. Don&#8217;t bother getting the GUI for abgx360. </p>
<pre lang="bash">
tar -zxvf abgx360-1.0.0.tar.gz
cd abgx360-1.0.0/
./configure &#038;&#038; make
sudo checkinstall -D
</pre>
<p>(You may use &#8216;make install&#8217; but this is not recommended on Debian/Ubuntu. checkinstall keeps your shit organized.)</p>
<p><em>If ./configure fails with an error about wx-config/wxWidgets, make sure wxWidgets is installed..</em></p>
<pre lang="bash">
apt-cache search wxgtk2
</pre>
<p><em>and make sure wx-config is in your PATH. On Ubuntu Intrepid, it wasn&#8217;t. Find it and make a symlink to something in your path.. i.e., </em></p>
<pre lang="bash">
locate wx-config # (finds it in /etc/alternatives/wx-config)
sudo ln -s /etc/alternatives/wx-config /usr/bin/wx-config
</pre>
<p><em>Rerun ./configure/make/checkinstall</em></p>
<p>If you downloaded the local database (abgx360-data) from the site above, install it now; Just extract and move the .abgx360/ dir into your ~/ </p>
<h2>Checking ISO CRC/SS &#8211; Is the game stealth?</h2>
<pre lang="bash">
abgx360 -af3 kfc-gamex.iso
</pre>
<p>the af3 flag will automagically fix/patch the ISO should it encounter any problems.<br />
What abgx360 will do is check the ISO&#8217;s CRC against an online (or offline, ~/.abgx360/) database. It might begin by updating its database. If this is a problem (no net connection), pass it -localonly</p>
<p>When that&#8217;s done&#8230;</p>
<h2>Burning the ISO Using growisofs</h2>
<p>Making sure the dual layer DVD is in your drive, run the following command:</p>
<pre lang="bash">
# growisofs -use-the-force-luke=dao -use-the-force-luke=break:1913760  -dvd-compat -speed=4 -Z /dev/burner=kfc-gamex.iso
</pre>
<p>I commented it out so you don&#8217;t execute it trying to paste it. Let&#8217;s look closer at this command&#8230;</p>
<p>The <strong>break:1913760</strong> is the layer break, which you&#8217;ll find in the .dvd file. If for whatever reason you can&#8217;t check the .dvd file, just use this value. </p>
<p>Set your speed to something low. Some say 2.5x but I have no problems burning at 4X (my max is 8X). You don&#8217;t need to know the lowest speed your burner can go. Just set it to 2-4 and you&#8217;ll be fine.</p>
<p><strong>Set /dev/burner to your own device.</strong> It&#8217;s probably /dev/scd0, /dev/scd1, or may already have a symlink like /dev/dvd6 /dev/dvd etc..</p>
<h3>Try grepping dmesg to find your device. i.e., </h3>
<pre lang="bash">
dmesg | grep "LITE"
</pre>
<h3>This might give you some information but probably nothing too helpful: </h3>
<pre lang="bash">
sudo dvdrecord -scanbus
</pre>
<h3>To see if you have the right device, try ejecting it. </h3>
<pre lang="bash">
eject /dev/dvd6
</pre>
<p>Set the kfc-gamex.iso to whatever the name/path of your ISO is (case sensitive of course). </p>
<p>Now I usually begin with a dry run. By passing <em>-dry-run</em> to growisofs, it will proceed as normal but quit before writing anything to disk. Actually, it kind of just spits out a command and dies. Awful design! i.e., </p>
<pre lang="bash">
$ growisofs -dry-run -use-the-force-luke=dao -use-the-force-luke=break:1913760  -dvd-compat -speed=4 -Z /dev/burner=kfc-gamex.iso
Executing 'builtin_dd if=kfc-bh5.iso of=/dev/dvd6 obs=32k seek=0'
$
</pre>
<p>So the above is good. Now remove the -dry-run flag to proceed with the actual burn. </p>
<pre lang="text">
growisofs -use-the-force-luke=dao -use-the-force-luke=break:1913760  -dvd-compat -speed=4 -Z /dev/burner=kfc-gamex.iso
</pre>
<p>Find something to do, or just stare at the screen. After about 20 minutes (at 4X), you&#8217;ll see the burn end successfully with output like this: </p>
<pre lang="text">
 7798128640/7835492352 (99.5%) @3.8x, remaining 0:06 RBU 100.0% UBU  99.8%
 7815495680/7835492352 (99.7%) @3.8x, remaining 0:03 RBU  59.7% UBU  99.8%
 7832862720/7835492352 (100.0%) @3.8x, remaining 0:00 RBU   7.9% UBU  99.8%
builtin_dd: 3825936*2KB out @ average 3.9x1352KBps
/dev/burner: flushing cache
/dev/burner: closing track
/dev/burner: closing disc
</pre>
<p>You&#8217;re done! </p>
<p><a name="quickie"><br />
<h2>Quick Recap</h2>
<p></a><br />
Assuming you installed all the dependencies above, here&#8217;s a quick recap of what needs to be done to burn a game.<br />
It really takes about 1 minute to begin the process. Write a shell script if you like. </p>
<pre lang="bash">
cd GameX_REGION_FREE_XBOX360_KFC/
rar x kfc-gamex.part01.rar # Extract game ISO
abgx360 -af3 kfc-gamex.iso # Checks if rip is valid/stealth/ss patched
growisofs -use-the-force-luke=dao -use-the-force-luke=break:1913760  -dvd-compat -speed=4 -Z /dev/burner=kfc-gamex.iso
eject /dev/burner # When burn is done, eject &#038; play.
</pre>
]]></content:encoded>
			<wfw:commentRss>http://biodegradablegeek.com/2009/03/burning-xbox-360-games-on-linux-stealth/feed/</wfw:commentRss>
		<slash:comments>42</slash:comments>
		</item>
		<item>
		<title>Gentoo Sucks, Ubuntu Doesn&#8217;t.</title>
		<link>http://biodegradablegeek.com/2008/12/gentoo-sucks-ubuntu-doesnt/</link>
		<comments>http://biodegradablegeek.com/2008/12/gentoo-sucks-ubuntu-doesnt/#comments</comments>
		<pubDate>Tue, 30 Dec 2008 03:31:32 +0000</pubDate>
		<dc:creator>Isam</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[gentoo]]></category>
		<category><![CDATA[linux distros]]></category>
		<category><![CDATA[rants]]></category>
		<category><![CDATA[ubuntu]]></category>

		<guid isPermaLink="false">http://biodegradablegeek.com/?p=302</guid>
		<description><![CDATA[I used Gentoo for a few years, and at first I loved it. Mainly because of portage, but the only distro I had experience with before Gentoo was Slackware, and I used to install packages and dependencies manually, so you can see why Gentoo would was so appealing to me. When I first began my [...]]]></description>
			<content:encoded><![CDATA[<p>I used Gentoo for a few years, and at first I loved it. Mainly because of portage, but the only distro I had experience with before Gentoo was Slackware, and I used to install packages and dependencies manually, so you can see why Gentoo would was so appealing to me.</p>
<p>When I first began my new job, the only distro available was Ubuntu, which deep down I hated without any real reason. I guess I saw Ubuntu as being &#8220;too user-friendly&#8221; and Mandrake-ish: Bloated and sluggish. But 10 minutes into using it, I made the decision that as soon as I get home, I&#8217;m wiping out Gentoo and installing Ubuntu.</p>
<h2>You Learn From Compiling Apps Yourself</h2>
<p>This is somewhat true, but I don&#8217;t believe it applies to Gentoo/portage. There&#8217;s nothing educational about watching shit scroll across the screen. None. If you want a real learning experience, try Slackware or Arch. You&#8217;ll learn if you&#8217;re forced to figure out what an app depends on, and what the most efficient compile flags are for your system. With Gentoo, the app is being compiled from scratch, but you aren&#8217;t doing any work, or research, for that matter. Running 1 command and then grabbing a bite while you wait for portage to do all the work for you isn&#8217;t going to teach you more than installing an RPM.</p>
<p>Gentoo&#8217;s installation isn&#8217;t going to teach you much of anything either, except maybe that patience is a virtue. The Gentoo docs are great, but each step is spoon fed to you. You&#8217;re basically copying and pasting commands so you can compile all the necessary files to get you started. After installation, Gentoo is as user-friendly as Ubuntu, even if it doesn&#8217;t seem like it at first.</p>
<h2>Compiled Apps Are More Efficient Than Packages</h2>
<p>Maybe. Prebuilt packages are usually compiled independently for each arch, and are already optimized, probably by people way more experienced in the field than you. Compiling your own apps can be slower if you don&#8217;t know what you&#8217;re doing, but even if you optimize your portage compile flags, the peformance difference between a prebuilt package for the specific arch vs an app compiled on that arch is minimal. There are too many drawbacks to compiling every app from scratch to make this tiny performance boost (which is just theoretical) worth it.<span id="more-302"></span></p>
<p>Compiling takes time. Not only does the app need to be compiled, but so does each of its dependencies. Compiling Xorg, OpenOffice, Gnome, or any big app will require that you leave the computer for a few hours, as the high load when you&#8217;re compiling something makes it unusable. System updates also take a long time, which means that&#8230;</p>
<p>You&#8217;re more likely to avoid updating. If you&#8217;re busy, the last thing you wanna do is drop what you&#8217;re doing for an hour just so you can update ABC app from version 2.3.0 to 2.3.1. Even security updates can be ignored if the app is big enough. I just installed about 15 new apps on Ubuntu, only took around 5 minutes in total, and 80% of that time was spent downloading the packages.</p>
<h2>Gentoo Uses Less RAM Than Distro X, Y, or Z</h2>
<p>By default, Gentoo is usually leaner than most distros, but that doesn&#8217;t mean you can&#8217;t easily tweak Ubuntu or any other distro to only run the apps and modules you want. Most distros use up a lot of memory because they offer a lot of functionality. Sure, you can disable nearly everything you &#8220;don&#8217;t need&#8221; and you&#8217;ll get a speedy system that runs on a stick of 256 megs of RAM, but why sacrifice functionality and aesthetics?</p>
<p>I&#8217;m also lazy and I hate closing programs, so I like to just keep my most used apps open. This means keeping Gimp, Mono+Tomboy Notes, Firefox with 50+ tabs (uses up 600 megs of RAM, at least), numerous gvim windows, terminals and SSH connections, numerous servers and services, Pidgin, Rythmbox, Compiz (which increases productivity, mind you), and misc apps like Agave, GColor2, MySQL query browser, etc&#8230;</p>
<p>I need the functionality, so I&#8217;m willing to put down money for more power instead of sacrificing my producitivity just to save a few bucks. Besides, RAM is damn cheap. I just picked up 8 GB of OZ DDR2800 (4 sticks total) for $20, brand new.</p>
<h2>Ubuntu Has Excellent Support</h2>
<p>This doesn&#8217;t apply to Ubuntu exclusively, but to any distro (or OS) that has an active community and great hardware support. Somewhere down the line you wake up and realize that you just want to get shit done and you want your computer to Just Work. Eventually you get tired of spending half of your time tweaking and hacking away and would like to devote as much time as possible to actual projects and work. I was shocked that my wifi worked out of the box with Ubuntu, as did everything else.</p>
<p><em>You can say that Ubuntu is to other distros what Rails or CakePHP are to CGI programming.</em></p>
<p>Ubuntu really demonstrates how far Linux has come. There&#8217;s a reason it&#8217;s so popular: <strong>It pwnz</strong>. If you want a &#8220;lean Ubuntu&#8221;, you can try Debian, which Ubuntu is based on. I use Debian for most of my servers and old boxes.</p>
]]></content:encoded>
			<wfw:commentRss>http://biodegradablegeek.com/2008/12/gentoo-sucks-ubuntu-doesnt/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>Quick BASH Script to Dump &amp; Compress a MySQL Database</title>
		<link>http://biodegradablegeek.com/2008/12/quick-bash-script-to-dump-compress-a-mysql-database/</link>
		<comments>http://biodegradablegeek.com/2008/12/quick-bash-script-to-dump-compress-a-mysql-database/#comments</comments>
		<pubDate>Sat, 27 Dec 2008 18:01:19 +0000</pubDate>
		<dc:creator>Isam</dc:creator>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Projects]]></category>
		<category><![CDATA[Scripts]]></category>
		<category><![CDATA[SQL]]></category>
		<category><![CDATA[backups]]></category>
		<category><![CDATA[mysql]]></category>
		<category><![CDATA[sql]]></category>

		<guid isPermaLink="false">http://biodegradablegeek.com/?p=299</guid>
		<description><![CDATA[A quick script I whipped up to dump my MySQL database. Usage: sh backthatsqlup.sh (be warned that it dumps ALL databases. This can get huge uncompressed) #!/bin/sh # Isam (Biodegradablegeek.com) public domain 12/28/2008 # Basic BASH script to dump and compress a MySQL dump out=sequel_`date +'%m%d%Y_%M%S'`.sql dest=/bx/ function e { echo -e "n** $1" } [...]]]></description>
			<content:encoded><![CDATA[<p>A quick script I whipped up to dump my MySQL database.<br />
<strong>Usage: sh backthatsqlup.sh</strong></p>
<p><em>(be warned that it dumps ALL databases. This can get huge uncompressed)</em></p>
<pre lang="bash">#!/bin/sh
# Isam (Biodegradablegeek.com) public domain 12/28/2008
# Basic BASH script to dump and compress a MySQL dump

out=sequel_`date +'%m%d%Y_%M%S'`.sql
dest=/bx/

function e {
  echo -e "n** $1"
}

e "Dumping SQL file ($out). May take awhile..."
#echo "oh snap" &gt; $out
sudo mysqldump -u root -p --all-databases &gt; $out
if [ $? -ne 0 ]; then
  e "MySQL dump failed. Check that server is up and your username/pass"
  exit 7
fi

e "Uncompressed SQL file size"
du -hs $out

e "Compressing SQL file"
gz=$out.tar.gz
tar -zvvcf $gz $out
rt=$?

if [ $rt -ne 0 ]; then
  e "tar failed (error=$rt). Will NOT remove uncompressed SQL file"
else
  e "Removing uncompressed SQL file"
  rm -f $out
  out=$gz

  e "Compressed SQL file size"
  du -hs $out
fi

e "Moving shit to '$dest'"
sudo mv $out $dest</pre>
<p><a href="http://code.biodegradablegeek.com/backthatsqlup.sh">BackThatSqlUp.sh</a></p>
]]></content:encoded>
			<wfw:commentRss>http://biodegradablegeek.com/2008/12/quick-bash-script-to-dump-compress-a-mysql-database/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>RescueTime&#8217;s 22 Gigabyte notifier.debuglog Log File</title>
		<link>http://biodegradablegeek.com/2008/11/rescuetimes-22-gigabyte-notifierdebuglog-log-file/</link>
		<comments>http://biodegradablegeek.com/2008/11/rescuetimes-22-gigabyte-notifierdebuglog-log-file/#comments</comments>
		<pubDate>Sun, 16 Nov 2008 08:25:46 +0000</pubDate>
		<dc:creator>Isam</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Misc]]></category>
		<category><![CDATA[nuisance]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[registry cleaner]]></category>
		<category><![CDATA[rescuetime]]></category>
		<category><![CDATA[spyware]]></category>

		<guid isPermaLink="false">http://biodegradablegeek.com/?p=285</guid>
		<description><![CDATA[I did find it weird that I kept running out of disk space recently. That hasn&#8217;t happened in years, and most of my big files go on another HD. On top of that, this box has been sluggish lately, even taking into account the fact that it&#8217;s ~4 years old and I always have 5-6 [...]]]></description>
			<content:encoded><![CDATA[<p>I did find it weird that I kept running out of disk space recently. That hasn&#8217;t happened in years, and most of my big files go on another HD. On top of that, this box has been sluggish lately, even taking into account the fact that it&#8217;s ~4 years old and I always have 5-6 desktops filled to the brim.</p>
<p>I finally found the culprit. <a href="http://rescuetime.com" target="_blank">RescueTime</a>&#8216;s (unofficial) Linux client keeps a log of <strong>every single window that has gotten focus, EVER.</strong> I figured this would be cleared when the notifications were sent out, but apparently it wasn&#8217;t. My <strong>failed/</strong> dir is nearly empty, so I know the notifications are getting sent out. The file is named ~/.rescuetime/tmp/notifier.debuglog</p>
<p>It might be that the client only clears the log when the app is closed? That sucks, because I don&#8217;t shutdown or reboot (or log out of X for that matter). Aside from the handful of kernel-update reboots (yeah yeah I could just init level down to preserve my uptime), I literally haven&#8217;t kept my PC off since 2006.</p>
<p>I don&#8217;t mind the disk space, but how the hell are you opening, seeking and writing to a 22gig+ file literally every single time focus is switched? I swear to the Gods I was one CC digit away from ordering a Mac.</p>
<p style="text-align: center;"><img class="size-full wp-image-286 aligncenter" title="notifier debug log rescue time picture" src="http://biodegradablegeek.com/wp-content/uploads/2008/11/notifierdebuglog.png" alt="notifierdebuglog RescueTimes 22 Gigabyte notifier.debuglog Log File " width="500" height="243" /></p>
<p>RescueTime is a great service/app, but I&#8217;ll keep the client off until this is fixed or they release an official client. No offense to the guys working on the Linux client (&lt;3), especially considering it&#8217;s probably their pet project, and I&#8217;ve had no other problems with it thus far. Hell, maybe the debug log could of easily been turned off.</p>
<p>I&#8217;m using version 90 (newest release as of 11/16). This may have already been fixed in trunk. I&#8217;ll check/submit a bug report&#8230; eventually.</p>
<p>https://launchpad.net/rescuetime-linux-uploader</p>
]]></content:encoded>
			<wfw:commentRss>http://biodegradablegeek.com/2008/11/rescuetimes-22-gigabyte-notifierdebuglog-log-file/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Mephisto for the Masses &#8211; Installation HOWTO</title>
		<link>http://biodegradablegeek.com/2008/10/mephisto-for-the-masses-installation-howto/</link>
		<comments>http://biodegradablegeek.com/2008/10/mephisto-for-the-masses-installation-howto/#comments</comments>
		<pubDate>Wed, 22 Oct 2008 02:14:00 +0000</pubDate>
		<dc:creator>Isam</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Tips]]></category>
		<category><![CDATA[Workarounds]]></category>
		<category><![CDATA[blog]]></category>
		<category><![CDATA[deploying]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[installing]]></category>
		<category><![CDATA[logs]]></category>
		<category><![CDATA[mefisto]]></category>
		<category><![CDATA[mephisot]]></category>
		<category><![CDATA[mephisto]]></category>
		<category><![CDATA[mephsto]]></category>
		<category><![CDATA[mod_rails]]></category>
		<category><![CDATA[phusion passanger]]></category>
		<category><![CDATA[redcloth-3.0.4]]></category>
		<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://biodegradablegeek.com/?p=257</guid>
		<description><![CDATA[I&#8217;ve recently taken a fancy to Mephisto, a blogging-platform written in Rails. I have nothing against WordPress, but being in Ruby and using Liquid for themes, Mephisto is far easier (and more fun) to tweak and configure, especially when I want to migrate my sites away from the &#8220;blog look&#8221; and make them more dynamic. [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve recently taken a fancy to Mephisto, a blogging-platform written in Rails. I have nothing against WordPress, but being in Ruby and using Liquid for themes, Mephisto is far easier (and more fun) to tweak and configure, especially when I want to migrate my sites away from the &#8220;blog look&#8221; and make them more dynamic. </p>
<p>It&#8217;s unfortunate development isn&#8217;t as active as say, Typo (also a Rails app, but I haven&#8217;t tried it), but I find that Mephisto at its current level makes a simple and <strong>fast</strong> starting point for most of my projects. </p>
<p>The point of this post is to address numerous problems with the installation. These are present in the tarball release of 0.8 Drax, and in trunk (as of 10/21). </p>
<h3>Git The Code</h3>
<p>Get the files, either the <a href="http://github.com/technoweenie/mephisto/tree/master">compressed archive</a> or from edge (recommended).</p>
<pre lang="text">
git clone git://github.com/technoweenie/mephisto.git
</pre>
<h3>Pre-installation</h3>
<p>You&#8217;ll need to freeze rails 2.0.2, and have the latest tzinfo gem installed:</p>
<pre lang="text">
gem install tzinfo
cd mephisto/
rake rails:freeze:edge RELEASE=2.0.2
</pre>
<p>The file it downloads should be named rails_2.0.2.zip and NOT rails_edge.zip. </p>
<p>Copy the &#8220;new&#8221; boot.rb into the config/ folder, overwriting the existing one:</p>
<pre lang="text">
cp vendor/rails/railties/environments/boot.rb config/boot.rb
</pre>
<p>Now rename the database sample file in config/ to database.yml and edit it to fit your own DB settings. You&#8217;ll probably only be using production.</p>
<h3>Bootstrapping</h3>
<p>Now bootstrap:</p>
<pre lang="text">
rake db:bootstrap RAILS_ENV=production
</pre>
<p>If it works, GREAT. But you&#8217;ll probably get an error or two. If you&#8217;re getting the following error: </p>
<pre lang="text">
Error message:
  undefined method `initialize_schema_information' for module
  `ActiveRecord::ConnectionAdapters::SchemaStatements'
Exception class:
  NameError
</pre>
<p>You forgot to copy over boot.rb from vendor/rails/ &#8211; scroll up. If you&#8217;re getting an error that redcloth is missing (<em>no such file to load—RedCloth-3.0.4/lib/redcloth</em>), even though it&#8217;s in vendor/, it&#8217;s because the path to RedCloth is relative in <strong>config/environment.rb</strong>. Change it from:</p>
<pre lang="rails">
require '../vendor/RedCloth-3.0.4/lib/redcloth' unless Object.const_defined?(:RedCloth)
</pre>
<p>to</p>
<pre lang="rails">
require File.join(File.dirname(__FILE__), '../vendor/RedCloth-3.0.4/lib/redcloth') unless Object.const_defined?(:RedCloth)
</pre>
<h3>Running</h3>
<p>After the bootstrap, you may either start the server (ruby script/server, thin, mongrel, etc), or go with <a href="http://www.modrails.com/">mod_rails (Phusion Passanger)</a>. I recommend the latter &#8211; Passenger is amazing, and the error screen is pretty. </p>
<p>Just point your Apache2 vhost to Mephisto&#8217;s PUBLIC/ dir. Here&#8217;s an example:</p>
<pre lang="text">
<VirtualHost *:80>
   ServerAdmin mrEman@domain.com
   ServerName domain.com
   ServerAlias www.domain.com

   # DocumentRoot must be rails_app/public/
   DocumentRoot /home/kiwi/www/domain.com/public/public
   Railsenv production

   DirectoryIndex index.html index.htm index.php
   ErrorLog /home/blue/www/domain.com/log/error.log
   CustomLog /home/blue/www/domain.com/log/access.log combined
</VirtualHost>
</pre>
<p>Restart Apache2, and you&#8217;re done. The site should work right away. If you get the following error:</p>
<pre lang="text">
No such file or directory - /tmp/mysql.sock
</pre>
<p>It&#8217;s because the socket file resides somewhere else on your (host&#8217;s) distro. Just find (man find, locate, etc) and add a symlink to it. Here&#8217;s an example (Debian): </p>
<pre lang="text">
ln -s /var/run/mysqld/mysqld.sock mysql.sock
</pre>
<p>If you&#8217;re getting an error that gems you know you have aren&#8217;t found, like:</p>
<pre lang="text">
no such file to load -- tzinfo (MissingSourceFile)
</pre>
<p>it is due to the fact that Gems are not located anywhere Ruby checks. You&#8217;ll have to explicity pass Ruby -rubygems or require &#8216;rubygems&#8217; &#8212; what a nuisance. Open config/environment.rb and add the latter line:</p>
<pre lang="text">
# requires vendor-loaded redcloth
require 'rubygems'
</pre>
<p>This will be global. Now either restart the server you ran (i.e., thin), or tell mod_rails to restart the app. To do so, just create a file named &#8220;restart.txt&#8221; in the tmp/ folder of the RAILS app:</p>
<pre lang="text">
cd mephisto_root/
touch tmp/restart.txt
</pre>
<p>and refresh the page. Passenger will restart the app and restart.txt will vanish. </p>
<p>The default login for the /admin page is <strong>admin/test</strong>. <em>Wasn&#8217;t that a blast? </em></p>
]]></content:encoded>
			<wfw:commentRss>http://biodegradablegeek.com/2008/10/mephisto-for-the-masses-installation-howto/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Script to Quickly Setup WebApp Environment and Domain</title>
		<link>http://biodegradablegeek.com/2008/10/script-to-quickly-setup-webapp-environment-and-domain/</link>
		<comments>http://biodegradablegeek.com/2008/10/script-to-quickly-setup-webapp-environment-and-domain/#comments</comments>
		<pubDate>Sun, 12 Oct 2008 04:10:32 +0000</pubDate>
		<dc:creator>Isam</dc:creator>
				<category><![CDATA[Automation]]></category>
		<category><![CDATA[Code]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[deployment]]></category>
		<category><![CDATA[joomla]]></category>
		<category><![CDATA[phpmotion]]></category>
		<category><![CDATA[rio]]></category>
		<category><![CDATA[scripting]]></category>
		<category><![CDATA[Scripts]]></category>
		<category><![CDATA[warez]]></category>

		<guid isPermaLink="false">http://biodegradablegeek.com/?p=240</guid>
		<description><![CDATA[Just sharing a script I wrote to quickly deploy WordPress (and eventually a few other webapps) sites, which somebody might find useful. This uses Linode&#8216;s API* to add the domain name to the DNS server along with some subdomains. If you&#8217;re using another server, (Slicehost, your own, etc), you can alter the dns class to [...]]]></description>
			<content:encoded><![CDATA[<p>Just sharing a script I wrote to quickly deploy WordPress (and eventually a few other webapps) sites, which somebody might find useful. This uses <a href="http://linode.com">Linode</a>&#8216;s API* to add the domain name to the DNS server along with some subdomains. If you&#8217;re using another server, (Slicehost, your own, etc), you can alter the dns class to use that API, or just ignore the DNS stuff completely; Its optional.</p>
<p>This will be updated periodically as I refactor and add support for more apps (notably Joomla and Clipshare &#8211; though this would violate their terms unless you have the unlimited license). This was written primarily because I couldn&#8217;t stand setting up another vhost and WordPress installation. There are plenty of existing deployers but I plan on adding very specific features and tweaking this for in-house work. I also wanted to try Rio (Ruby-IO). GPL license. Go nuts.</p>
<p><em>* As of 10/11, the apicore.rb file on the site has some syntactic errors in the domainResourceSave method. I sent an email out to the author about it. Problems aren&#8217;t major. You can get <a href="http://biodegradablegeek.com/wp-content/uploads/2008/10/apicore.rb" target="_new">my apicore.rb here</a>.</em></p>
<p>This won&#8217;t run unless you create the appropriate folder structure in /etc/mksite/. I&#8217;ll get going on this in a bit. See the code below:</p>
<p><span id="more-240"></span></p>
<pre lang="ruby">#!/usr/bin/env ruby 

########################################################
# Isam M.
# http://biodegradablegeek.com
# MKSITE.RB (0.2) Last updated Oct 19th, 2008
#
# mksite makes it quicker to setup sites and web
# apps by doing most of the tedious work.
#
#
#                     UNSTABLE
#           Run it in your imagination,
#              not on your system!
#
#
######################################################## 

require 'rubygems'
require 'rio'
require 'yaml'
require 'mysql'
require 'highline/import'
HighLine.track_eof = false

begin
  require 'apicore'
rescue LoadError
  puts "NOTICE: Unable to load apicore.rb - domains will not be added automatically"
end

Apache_sites = '/etc/apache2/sites-available/'
Subdomains = ['', 'www', 'mail', 'blog', "dev#{(rand*10).floor}"]
Testing = false
Homedir = ENV['HOME']
Username = ENV['USER']
Applications = [:Skeleton, :Clipshare, :Joomla, :PHPMotion, 'PmWiki (N/A)', :Wordpress]
$config = nil
$log = nil

def say(txt)
  super txt
#  $log &lt;&lt; txt if $log
end

# flash('message', :notice || :error) to output msg
def flash(msg, message_type = :notice)
 if message_type.eql? :notice
    say("INFORMATION: #{msg}")
  elsif message_type.eql? :emphasize
    say("***************************************************")
    say("NOTICE: #{msg}n")
    say("***************************************************")
  elsif message_type.eql? :error
    STDERR.puts("FATAL ERROR: #{msg}n")
  end
end

# DZone 2111
def genAlpha(size=64)
  s=''
  size.times {
    s &lt;&lt; (i = Kernel.rand(62); i += ((i &lt; 10) ? 48 : ((i &lt; 36) ? 55 : 61 ))).chr
  }
  s
end

if defined? ApiCore
  class DNSAPI &lt; ApiCore
    # This depends on the Linode API Ruby bindings (apicore.rb)
    def initialize(key, debug=false, batching=false)
      super
      @batching=false
    end

    # Add domain. Return ID on success, nil on failure
    def addDomain domain
      return nil if !domain
      params = {}
      params[:DomainID] = 0
      params[:Domain] = domain
      params[:Type] = 'master'
      params[:Status] = 1
      params[:SOA_Email] = getVal('email') || ask("Enter SOA email for the domain: ")
      domainSave params
    end

    def addDomainResource(domain, resource, target, record_type = 'A')
      return nil if (did = getDomainIdByName domain).nil?
      params = {}
      params[:ResourceID] = 0
      params[:DomainID] = did
      params[:Name] = resource
      params[:Type] = record_type
      params[:Target] = target
      domainResourceSave params
    end

    def getDomainIdByName domain
      domainList.find do |dom|
        return dom["DOMAINID"] if dom["DOMAIN"].downcase == domain.downcase
      end
    end
  end
else
  flash('ApiCore not loaded. Skipping DNS stuff', :notice)
end

class App
  class &lt;&lt; self; attr_reader :message, :name, :version, :description, :vhost; end
  @message = nil
  @name = nil
  @version = nil
  @description = 'Just Another Web App'
  @vhost = 'generic'

  def initialize(rootdir, domain, db)
    flash("Initializing application (dir=#{rootdir}, domain=#{domain})")
    @rootdir = (rootdir[-1].chr.eql? '/') ? rootdir.chop : rootdir
    @domain = domain
    @db = db # hash of database info 

    # System stuff
    #if Testing
      #@templates = '/home/kiwi/Code/mksite/templates'
      #@configs = '/home/kiwi/Code/mksite/configs'
      #@vhosts = '/home/kiwi/Code/mksite/vhosts'
    #else
      @templates = '/etc/mksite/templates'
      @configs = '/etc/mksite/configs'
      @vhosts = '/etc/mksite/vhosts'
    #end
  end

  # This generally does not need to be overriden.
  # It does 'generic shit' like creating the rootdir
  # and setting permissions
  def envSetup
    if !rio(@rootdir).exist?
      flash("Creating directory #{@rootdir}")
      rio(@rootdir).mkpath
    end

    rio(@rootdir).chdir do |root|
      # Copy the generic public/private/log apache
      # structure to rootdir
      flash("Changing working dir to #{@rootdir}")
      flash("Working inside '#{root.to_s}'")
      rio(@templates,'skeleton.www').each { |df|
        # Overwrite existing files? .. yes.
        #while rio(root, df).exist? do
        df &gt; root
        #flash("Copied #{df.to_s} to #{root.to_s}")
      } 

      # Set permissions (a+w on logs, etc)
      flash('Setting permissions...')
      flash('666 ./log/*.log')
      rio('./log/access.log').chmod(00666)
      rio('./log/error.log').chmod(00666)
      flash('700 ./private')
      rio('./private/').chmod(00700)
    end
  end

  def setup
    # envSetup()
    # databaseSetup()
    raise 'OVERRIDE ME'
    #flash("setup() template function invoked. 'OVERRIDE ME'", :log)
  end

  def databaseSetup
    # Create database if it doesn't already exist
    # This usually doesn't need to be overriden
    #Mysql.server_connect(@db['name'])
    #  flash('Checking database connection... ')
    begin
      dbo = Mysql.real_connect(@db['host'], @db['user'], @db['pass'])
      flash("Creating database '#{@db['name']}'");
      res = dbo.query("CREATE DATABASE IF NOT EXISTS #{@db['name']};")
      flash("Database server returned #{res}") if res
    rescue Mysql::Error =&gt; err
      flash('Unable to connect to access/create database', :error)
      flash("Error returned (#{err.errno}) = '#{err.error}'", :error)
      exit 1
    ensure
      dbo.close if dbo
    end
  end

  def dnsSetup
    return if !defined? ApiCore

    # Setup DNS - currently uses Linode API
    flash("Setting up DNS for '#{@domain}'")
    flash("This requires a Linode API keynLogin to linode.com and find it under 'My Profile'", :emphasize)
    dns = nil
    api_key = getVal('apikey')
    loop do
      api_key = ask('Paste your Linode API key (or 'skip'): ') if api_key.nil? || api_key.empty?
      break if api_key.downcase.eql? 'skip'

      # Check API key
      begin
        dns = DNSAPI.new api_key
        dns.domainList
        break
      rescue RuntimeError
        flash("API key invalid (or service down?). Learn to paste and try again.n")
        api_key = nil
      end
    end

    unless api_key.nil? or api_key.downcase.eql? 'skip'
      flash("Adding master domain '#{@domain}'")
      begin
        begin
          dns.addDomain(@domain)
        rescue RuntimeError
          flash('Unable to add domain (exists already?). Attempting to add subdomains...', :error)
        end

        server = getVal('server') ||
                   ask("Enter IP subdomains should point to (or 'skip'): ") { |q| q.default = 'skip' } 

        unless server.downcase.eql? 'skip'
          Subdomains.each do |sub|
            flash("Adding subdomain '#{sub}.#{@domain}' (points to #{server})")
            flash('Could not add subdomain', :error) if !dns.addDomainResource(@domain, sub, server)
          end
        end
     rescue
       raise
       flash("Unable to add domain/subdomain. Skipping", :error)
     end
    end
  end

  def serverSetup
    # Set Apache vhost
    vhost_file = (defined? self.class.vhost) ? self.class.vhost : 'generic'
    flash("Generating vhost file (#{@vhosts}/#{vhost_file}) for Apache 2.x")
    vhost = ''
    email = getVal('email') || ask("Enter a valid email for tech support: ")
    rio(@vhosts, vhost_file) &gt; vhost
    vhost.gsub!('_MKS_DOMAIN_', @domain)
    vhost.gsub!('_MKS_EMAIL_', email)
    vhost.gsub!('_MKS_ROOT_', "#{@rootdir}")
    vhost.gsub!('_MKS_PUBLIC_', "#{@rootdir}/public")
    #rio(Testing ? '/tmp/' : Apache_sites, @domain).puts(vhost)
    rio('/tmp/', @domain).puts(vhost) 

    # Your enemies should not read this
    rio('/tmp/', @domain).chmod(00600)
    flash("vhost file has been generated as /tmp/#{@domain}n
          It is YOUR responsibility to move this to #{Apache_sites}n
          Site will not work until you 'a2ensite &amp;&amp; apache2ctl restart'", :emphasize)
  end

  def postInstall()
    flash("Finished!", :emphasize)
  end
end

class Skeleton &lt; App
  @name = 'Skeleton'
  @description = 'Generic WWW directory structure'
  @message = ''
  @vhost = 'generic'

  def setup
    self.envSetup()
    self.dnsSetup()
    self.serverSetup()
  end
end

class WordPress &lt; App
  @name = 'Wordpress'
  @version = '2.6.2'
  @description = 'A popular blogging platform'
  @message = 'Trying to make monies on the Internets?'
  @vhost = 'generic'

  def setup
    # This sets up the initial environment / permissions
    self.envSetup() 

    # Copy the wordpress skeleton directory to the new dir
    wproot = rio(@rootdir,'public')
    flash("Wordpress root will be #{wproot}")
    flash('Copying WordPress data over... (may take awhile)')
    rio(@templates,'wordpress').each { |df| df &gt; wproot } 

    rio(wproot).chdir do
      rio('wp-config-sample.php').rm()
      # Generate and output wp config
      flash('Generating wp-config.php based on your DB settings...')
      wpcfg = rio(@configs, 'wordpress.cfg')
      if !wpcfg.exist? || !wpcfg.readable?
        flash("Wordpress config template missing or unreadable, quitting", :error)
        exit 2
      end

      # Copy the config into a string, do things with it and then write it to disk
      config = ''
      rio(@configs, 'wordpress.cfg') &gt; config
      flash("Warning: config file '#{@configs}/wordpress.cfg' is empty") if config.empty?
      config['_MKS_DB_HOST_'] = @db['host']
      config['_MKS_DB_USER_'] = @db['user']
      config['_MKS_DB_PASS_'] = @db['pass']
      config['_MKS_DB_NAME_'] = @db['name']
      config.gsub!('_MKS_SECRET_', genAlpha())
      flash("Writing #{wpcfg} data")
      rio('wp-config.php').w!.puts(config)
    end

    # Setup the database
    self.databaseSetup() 

    # Add DNS info
    self.dnsSetup() 

    # Setup the server/vhost
    self.serverSetup()
  end
end

class Clipshare &lt; App
  def setup
    raise 'Clipshare support is currently not available. sowwie'
  end
end

class Joomla &lt; App
  @name = 'Joomla'
  @version = '1.5.7'
  @description = 'A widely used Content Management System'
  @message = ''
  @vhost = 'generic'

  def setup
    # This sets up the initial environment / permissions
    self.envSetup() 

    # Copy the wordpress skeleton directory to the new dir
    flash('Copying Joomla data over... (may take awhile)')
    jooroot = rio(@rootdir,'public')
    flash("Joomla root will be #{jooroot}")
    rio(@templates,'joomla-1.5.7').each { |df| df &gt; jooroot } 

    rio(jooroot).chdir do
      flash('Removing stock Joomla config...')
      rio('configuration.php-dist').rm()

      # Generate and output joomla config
      flash('Generating configuration.php based on provided settings...')
      joocfg = rio(@configs, 'joomla.cfg')
      if !joocfg.exist? || !joocfg.readable?
        flash("Joomla config template missing or unreadable, quitting", :error)
        exit 2
      end

      # Copy the config into a string, do things with it and then write it to disk
      config = ''
      rio(@configs, 'joomla.cfg') &gt; config
      flash("Warning: config file '#{@configs}/joomla.cfg' is empty") if config.empty?
      config['_MKS_DB_HOST_'] = @db['host']
      config['_MKS_DB_USER_'] = @db['user']
      config['_MKS_DB_PASS_'] = @db['pass']
      config['_MKS_DB_NAME_'] = @db['name']
      config.gsub!('_MKS_DOMAIN_', @domain)
      config.gsub!('_MKS_SECRET_', genAlpha()) 

      flash("Writing ./configuration.php")
      rio('configuration.php').w!.puts(config) 

      flash("Making configuration.php world writable (0666)")
      rio('configuration.php').chmod(0666)
    end

    # Setup the database
    self.databaseSetup() 

    # Add DNS info
    self.dnsSetup() 

    # Setup the server/vhost
    self.serverSetup()
  end

  def postInstall()
    flash('Joomla is ready to be setup using the web interface', :emphasize)
    flash("Go to #{@domain} where the Joomla! web based installer will
           guide you through the rest of the installation")
    flash("Here's the database information:n
           USERNAME: #{@db['user']}n
           DB HOST : #{@db['host']}n
           DB NAME : #{@db['name']}") 

    flash("nAdmin panel is located @ #{@domain}/administrator ")
    flash("You can log into Admin using the username 'admin' along with the
    password that was generated or you chose during the web based install.")
    super
  end
end

class PHPMotion &lt; App
  def setup
    raise 'PHPMotion support is currently not available. sowwie'
  end
end

class Log
  def initialize(filename="/tmp/#{Username}_mksite.log")
    @log = rio(filename)
    n=0; @log = rio("#{filename}.#{n+=1}") while @log.exist?
    @log.puts("# GENERATED BY MKS - BEGAN @ #{Time.now.to_i}")
    @log.chmod(00600)
    flash("Log file generated (important): #{@log.to_s} (no worries, set to 600)", :emphasize)
    return @log
  end

  # append to log
  def &lt;&lt;(data)
    #super &lt;&lt;(data)
    @log.puts(data)
    @log.puts("n")
    #@log &lt;&lt; data &lt;&lt; "n"
  end
end

def loadConfig()
  cfgpath = "#{ENV['HOME']}/.mksite"
  return YAML.load(rio(cfgpath).read()) if rio(cfgpath).exist?
  nil
end

def getVal(key, default=nil)
  return $config[key] if $config and defined? $config[key]
  default
end

def main
  exit 1 if 'root'==ENV['USER']
  if ($config = loadConfig())
    flash('~/.mksite config loaded')
  else
    flash('~/.mksite not found. It's fine, I'll annoy you with questions.')
  end

  puts $config.inspect if Testing
  flash('Press ^C (CTRL+C) at any time quit', :emphasize)
  # Let's ask neutral questions about the new site.
  if Testing
    rootdir = '/tmp/sandbox9/'
    domain = 'domain.cxm'
  else
    domain = ask('Enter site's domain name (no http:// or www): ') #{ |d| d.validate = !! /^www.|^http:/// }
    rootdir = ask('Root site directory (leave blank for default): ') { |q|
      q.default = "/home/#{Username}/www/#{domain}/"
      q.validate = /^/home/#{Username}//
    }
  end

  flash("Domain has been set to "#{domain}"")
  #$log = Log.new("/tmp/mks_#{domain}.log") 

  flash("Site will reside in "#{rootdir}", and the index/script")
  flash(" files (index.php, .htaccess etc) will go in "#{rootdir}/public/"nn")

  # Ask the user what app she wants to install and specific questions about that app
  app = nil
  choose do |menu|
    menu.prompt = 'Choose the software for your new site: '
    Applications.each do |app|
      menu.choice app do |a|
        app = a
      end
    end
  end

  flash("You chose #{app}. #{Kernel.const_get(app).message}n") 

  # Fetch DB info if this app needs a database
  # XXX Should just have a db flag in the App's class
  db = nil
  unless app.eql? :Skeleton
    flash('This app requires a database (only MySQL supported)')
    flash('It will be created if it doesn't exist')

    db = {}
    db['host'] = 'localhost'
    loop do
      if Testing
        db['user'] = 'kiwi'
        db['pass'] = ''
        db['name'] = 'kiwi_sandbox9'
      else
        db['user'] = getVal('db_user') || ask('Enter MySQL username: ')
        db['pass'] = getVal('db_pass') || ask('Enter MySQL password: ') { |q| q.echo = '*'}
        db['name'] = ask('Enter database name (should begin w/ your 'username_')') { |dbn| dbn.validate = /^#{Username}_/}
        puts db.inspect
      end
      flash("Please double check: mysql://#{db['user']}:#{'*' * (db['pass']).size}@#{db['host']}/#{db['name']}")
      break if Testing || agree('Is this correct?')
      flash("Please re-enter database infon")
    end
  end

  # Check permissions and database login
  flash('Doing a preliminary check', :emphasize)
  flash('Checking installation environment')
  # Quit if the directory exists and the user does not want to go ahead
  unless Testing
    exit 1 if rio(rootdir).exist? &amp;&amp; !agree("Directory '#{rootdir}' exists! Continue? (Y/N)")
  end

  # Is the parent directory available and writable?
  parentdir = rio(rootdir).dirname
  unless parentdir.exist? &amp;&amp; parentdir.writable?
    flash("Directory '#{parentdir.to_s}' either doesn't exist or is not writable. Check permissions", :error)
    exit 1
  end

  unless db.nil? || false==getVal('db_confirm')
    # Check DB connection - but this does not check if user has any privileges
    flash('Checking database connection')
    begin
      dbo = Mysql.real_connect(db['host'], db['user'], db['pass'])
      flash("Successfully connected to '#{dbo.get_server_info}'")
    rescue Mysql::Error =&gt; err
      flash('Unable to connect to database server', :error)
      flash("Error returned (#{err.errno}) = '#{err.error}'", :error)
      exit 1
    ensure
      dbo.close if dbo
    end
  end

  # Begin installation
  flash("Word on the server racks is... you're good to go", :emphasize)
  klass = Kernel.const_get(app)
  webapp = klass.new(rootdir, domain, db)
  webapp.setup()
  webapp.postInstall()
end

main()</pre>
<p><a href="http://biodegradablegeek.com/wp-content/uploads/2008/10/mksite.rb" target="_new"><strong>Download</strong> the ASCII mksite.rb file here.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://biodegradablegeek.com/2008/10/script-to-quickly-setup-webapp-environment-and-domain/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

