<?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>MarkMcB</title>
	<atom:link href="http://markmcb.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://markmcb.com</link>
	<description>Mark McBride of San Francisco</description>
	<lastBuildDate>Sat, 27 Apr 2013 18:14:27 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Systems: Because You Can&#8217;t Count That Fast</title>
		<link>http://markmcb.com/2013/04/27/systems-because-you-cant-count-that-fast/</link>
		<comments>http://markmcb.com/2013/04/27/systems-because-you-cant-count-that-fast/#comments</comments>
		<pubDate>Sat, 27 Apr 2013 18:08:45 +0000</pubDate>
		<dc:creator>Mark McBride</dc:creator>
				<category><![CDATA[Programming and Scripting]]></category>
		<category><![CDATA[erp]]></category>
		<category><![CDATA[kids]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[script]]></category>

		<guid isPermaLink="false">http://markmcb.com/?p=873</guid>
		<description><![CDATA[Me trying to explain a global SAP ERP network to kids. On Thursday, it was bring your daughters and sons to work day at Genentech. My little Marlowe is only 6 weeks old so I didn&#8217;t bring her, but my &#8230; <a href="http://markmcb.com/2013/04/27/systems-because-you-cant-count-that-fast/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<div style="float:right; border: 1px solid #ccc; background: #eee; padding: 5px 5px; margin: 0 0 10px 10px; font-size: 0.8em;"><img src="https://dl.dropboxusercontent.com/u/10448520/articles/201304-Systems-Kids/talking-about-systems.jpeg" style="margin: 0; padding: 0" /><br />Me trying to explain a global SAP ERP network to kids.</div>
<p>On Thursday, it was bring your daughters and sons to work day at Genentech. My little Marlowe is only 6 weeks old so I didn&#8217;t bring her, but my VP shot me a note Wednesday saying she was bringing her two boys, knew of some other kids who would be there, and wondered if I could give a 30 minute talk on systems. I responded, &#8220;sure.&#8221;</p>
<p>But why the heck do you tell kids ranging from 6-12 years old about your corporate ERP system? While fascinating, I doubt they&#8217;d care about the usual things that I work on and I wouldn&#8217;t dare show them PowerPoint slides. So what to do?<br />
<span id="more-873"></span></p>
<p>Thursday before lunch I slapped a Ruby script together (code below). It did 2 things: 1) let you decide how many plants were producing widgets, and 2) how fast they could produce. The first run looked like this:</p>
<pre class="brush:text">
How many plants are there? (max 6)
1
About how many seconds does it take a plant to make something?
5
Monitoring a network of 1 plants
STARTING P1
Plant 1: +3
Plant 1: +7
Plant 1: +3

Monitoring stopped
Plant 1 made 13
</pre>
<p>As the output slowly appeared I had them add up the widgets produced, which they did with ease. We clearly didn&#8217;t need systems &#8230; yet. Then we increased the number of plants and speed of production until we got to this scenario:</p>
<pre class="brush:text">
How many plants are there? (max 6)
6
About how many seconds does it take a plant to make something?
1
Monitoring a network of 6 plants
STARTING P1 |             |             |             |             |            
Plant 1: +8 |             |             |             |             |            
            | STARTING P2 |             |             |             |            
            | Plant 2: +9 |             |             |             |            
            |             | STARTING P3 |             |             |            
            |             | Plant 3: +3 |             |             |            
            |             |             | STARTING P4 |             |            
            |             |             | Plant 4: +5 |             |            
Plant 1: +8 |             |             |             |             |            
            |             |             |             | STARTING P5 |            
            |             |             |             | Plant 5: +4 |            
            | Plant 2: +5 |             |             |             |            
            |             |             |             |             | STARTING P6
            |             |             |             |             | Plant 6: +1
            |             | Plant 3: +7 |             |             |            
            |             |             | Plant 4: +3 |             |            
Plant 1: +9 |             |             |             |             |            
            |             |             |             | Plant 5: +1 |            
            |             |             |             |             | Plant 6: +8
            | Plant 2: +5 |             |             |             |            
            |             | Plant 3: +9 |             |             |            
            |             |             | Plant 4: +1 |             |            
            |             |             |             | Plant 5: +4 |            
Plant 1: +2 |             |             |             |             |            

Monitoring stopped
Plant 1 made 27
Plant 2 made 19
Plant 3 made 19
Plant 4 made 9
Plant 5 made 9
Plant 6 made 9
</pre>
<p>That&#8217;s a shortened example. In our exercise we let it run until each plant had made hundreds of widgets.  Though they tried hard, they simply couldn&#8217;t keep up. At this point I stopped and asked them if it was now clear why we use systems and one kid answered beautifully: yeah, because you can&#8217;t count that fast. A week ago if you asked me, &#8220;why do you use SAP ERP,&#8221; I probably would have given you some long-winded, boring answer citing dollars, value, and other things that would put you to sleep. I like the simple version much better. Thanks kids.</p>
<p>If you&#8217;re curious, here&#8217;s the code. It&#8217;s not elegant, and could certainly be refactored, but I think it worked nicely to demonstrate why we use systems at work.</p>
<pre class="brush:ruby">
# Get some input about the plants in the network
puts "How many plants are there? (max 6)"
num_plants = gets.to_i
puts "About how many seconds does it take a plant to make something?"
seconds_to_make = gets.to_i
puts "Monitoring a network of #{num_plants} plants"

# Store plant inventory in an array
@@plants = Array.new(num_plants, 0)

# Wait for the user to hit enter and exit with inventory information
Thread.new do
  loop do
    s = gets.chomp
    puts "Monitoring stopped"
    count=0
    @@plants.each{|p| puts "Plant #{count+=1} made #{p}"}
    exit
  end
end

# Starts an independent plant thread and logs inventory
def start_plant(plant, sleep_for=seconds_to_make)
  Thread.new do
    loop do
      making = rand(9)+1
      front_pad = '            | '*plant
      back_pad = ' |            '*(5-plant-(6-@@plants.length))
      puts "#{front_pad}Plant #{plant+1}: +#{making}#{back_pad}"
      @@plants[plant] += making
      sleep sleep_for+(rand(0))
    end
  end
end

# Start N plant threads
1.upto(@@plants.length) do |p|
  plant = p-1
  front_pad = '            | '*plant
  back_pad = ' |            '*(5-plant-(6-@@plants.length))
  puts "#{front_pad}STARTING P#{plant+1}#{back_pad}"
  start_plant(plant, seconds_to_make)
  sleep 1
end

# Endless loop to allow other threads to run until interrupted
loop do; sleep 1; end
</pre>
]]></content:encoded>
			<wfw:commentRss>http://markmcb.com/2013/04/27/systems-because-you-cant-count-that-fast/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hello Marlowe!</title>
		<link>http://markmcb.com/2013/03/10/hello-marlowe/</link>
		<comments>http://markmcb.com/2013/03/10/hello-marlowe/#comments</comments>
		<pubDate>Sun, 10 Mar 2013 19:23:58 +0000</pubDate>
		<dc:creator>Mark McBride</dc:creator>
				<category><![CDATA[Personal]]></category>
		<category><![CDATA[baby]]></category>

		<guid isPermaLink="false">http://markmcb.com/?p=858</guid>
		<description><![CDATA[Allow me to introduce to the world, Marlowe Maxine McBride! Marlowe was born in San Francisco, California at the University of California San Francisco (UCSF) hospital at 12:23pm on Sunday, 10 March 2013 (10 + 3 = 13 &#8230; yay! &#8230; <a href="http://markmcb.com/2013/03/10/hello-marlowe/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Allow me to introduce to the world, Marlowe Maxine McBride!</p>
<p><img src="https://dl.dropbox.com/u/10448520/articles/201303-Hello-Marlowe/217A0453.jpg" /></p>
<p>Marlowe was born in San Francisco, California at the University of California San Francisco (UCSF) hospital at 12:23pm on Sunday, 10 March 2013 (10 + 3 = 13 &#8230; yay! A math trivia birthdate!). She weighed in at 7 pounds 7 ounces, and measured 21 inches in length.</p>
<p>Both Alicia and Marlowe are doing great and getting a lot of needed rest. Marlowe&#8217;s middle name is borrowed from my paternal grandmother. Her first name was her mom&#8217;s top pick and after witnessing the process of giving birth, mom had final decision rights on the name. Luckily, when we both gave our final suggestion on what her name should be around noon on the 11th (24 hours after her birth), we both agreed Marlowe matched her personality.</p>
<p>For those of you looking for more pics, I will upload highlights by day to the link below for the first week or two, so check back each day for more:</p>
<p><span style="font-size: 3em"><a href="https://www.dropbox.com/sh/8iewpbqgrn8ftoh/8e9Nw6YbIf">Click for Marlowe Pics!</a></span></p>
]]></content:encoded>
			<wfw:commentRss>http://markmcb.com/2013/03/10/hello-marlowe/feed/</wfw:commentRss>
		<slash:comments>39</slash:comments>
		</item>
		<item>
		<title>Cleanup Unused Linux Kernels in Ubuntu</title>
		<link>http://markmcb.com/2013/02/04/cleanup-unused-linux-kernels-in-ubuntu/</link>
		<comments>http://markmcb.com/2013/02/04/cleanup-unused-linux-kernels-in-ubuntu/#comments</comments>
		<pubDate>Tue, 05 Feb 2013 03:23:27 +0000</pubDate>
		<dc:creator>Mark McBride</dc:creator>
				<category><![CDATA[Programming and Scripting]]></category>
		<category><![CDATA[apt-get]]></category>
		<category><![CDATA[boot]]></category>
		<category><![CDATA[dpkg]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[sed]]></category>
		<category><![CDATA[uname]]></category>
		<category><![CDATA[xargs]]></category>

		<guid isPermaLink="false">http://markmcb.com/?p=816</guid>
		<description><![CDATA[I update Ubuntu with a very simple script I call apt-update that looks like this: $ cat ./apt-update sudo apt-get update; sudo apt-get dist-upgrade; sudo apt-get autoremove Nothing too crazy there. It updates the apt-get cache, performs the upgrade, and &#8230; <a href="http://markmcb.com/2013/02/04/cleanup-unused-linux-kernels-in-ubuntu/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I update Ubuntu with a very simple script I call apt-update that looks like this: </p>
<pre class="brush:bash; gutter: false;">
$ cat ./apt-update 
sudo apt-get update; sudo apt-get dist-upgrade; sudo apt-get autoremove
</pre>
<p>Nothing too crazy there.  It updates the apt-get cache, performs the upgrade, and then removes all the residual junk that&#8217;s laying around.  Well, almost all.  If you do this enough, eventually you&#8217;ll see the following (assuming you&#8217;ve got the default motd Ubuntu script running and you&#8217;re logging in from a terminal):</p>
<pre class="brush:text; gutter: false;">
=> /boot is using 86.3% of 227MB
</pre>
<p>This is because that script I mentioned doesn&#8217;t consider old kernel images to be junk.  However, unless you&#8217;ve got an abnormal /boot partition, it doesn&#8217;t take too many old images to fill it up.</p>
<p>A quick Google search found <em><a href="http://ubuntugenius.wordpress.com/2011/01/08/ubuntu-cleanup-how-to-remove-all-unused-linux-kernel-headers-images-and-modules/">Ubuntu Cleanup: How to Remove All Unused Linux Kernel Headers, Images and Modules</a></em>.  The solution on the page had exactly what I&#8217;m looking for, however, I couldn&#8217;t take it at face value.  While the article offers an adequate solution, it doesn&#8217;t offer much explanation.  The remainder of this article explains the details for this one-liner noted in the article above:</p>
<div style="background: #345; padding: 5px 10px; color: #ccc; margin-bottom: 20px; box-shadow: 5px 5px 10px #888888;">
<code>$ dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d' | xargs sudo apt-get -y purge<br />
</code>
</div>
<p><strong>Note:</strong> Only run this if you&#8217;ve rebooted after installing a new kernel.</p>
<p>Ick.  Let&#8217;s dig into what&#8217;s going on here.  The pipe characters are chaining a bunch of commands together.  Each command&#8217;s output becomes the input for the next.  Given that, let&#8217;s walk through what&#8217;s going on in 3 steps.<br />
<span id="more-816"></span></p>
<h2>
Step 1 &#8211; List Linux Kernels: <code>dpkg -l 'linux-*'</code><br />
</h2>
<p>This one is fairly simple.  Just pull up the man page for dpkg:</p>
<pre class="brush:text; gutter: false;">
dpkg - package manager for Debian
...
dpkg-query actions
              -l, --list package-name-pattern...
                  List packages matching given pattern.
</pre>
<p>So, it should just list out the packages matching the pattern provided.  Let&#8217;s try:</p>
<pre class="brush:bash; gutter: false;">
$ dpkg -l 'linux-*'
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name           Version      Architecture Description
+++-==============-============-============-=================================
un  linux-doc-2.6. <none>                    (no description available)
un  linux-doc-3.0. <none>                    (no description available)
un  linux-doc-3.2. <none>                    (no description available)
un  linux-doc-3.5. <none>                    (no description available)
ii  linux-firmware 1.95         all          Firmware for Linux kernel drivers
un  linux-image    <none>                    (no description available)
un  linux-image-2. <none>                    (no description available)
ii  linux-image-2. 2.6.38-11.50 amd64        Linux kernel image for version 2.
ii  linux-image-2. 2.6.38-8.42  amd64        Linux kernel image for version 2.
un  linux-image-3. <none>                    (no description available)
rc  linux-image-3. 3.0.0-12.20  amd64        Linux kernel image for version 3.
rc  linux-image-3. 3.0.0-13.22  amd64        Linux kernel image for version 3.
rc  linux-image-3. 3.0.0-14.23  amd64        Linux kernel image for version 3.
rc  linux-image-3. 3.0.0-15.26  amd64        Linux kernel image for version 3.
rc  linux-image-3. 3.0.0-16.29  amd64        Linux kernel image for version 3.
ii  linux-image-3. 3.0.0-17.30  amd64        Linux kernel image for version 3.
rc  linux-image-3. 3.2.0-23.36  amd64        Linux kernel image for version 3.
rc  linux-image-3. 3.2.0-24.39  amd64        Linux kernel image for version 3.
rc  linux-image-3. 3.2.0-25.40  amd64        Linux kernel image for version 3.
rc  linux-image-3. 3.2.0-26.41  amd64        Linux kernel image for version 3.
rc  linux-image-3. 3.2.0-27.43  amd64        Linux kernel image for version 3.
rc  linux-image-3. 3.2.0-29.46  amd64        Linux kernel image for version 3.
rc  linux-image-3. 3.2.0-30.48  amd64        Linux kernel image for version 3.
rc  linux-image-3. 3.2.0-31.50  amd64        Linux kernel image for version 3.
ii  linux-image-3. 3.2.0-32.51  amd64        Linux kernel image for version 3.
ii  linux-image-3. 3.5.0-17.28  amd64        Linux kernel image for version 3.
ii  linux-image-3. 3.5.0-18.29  amd64        Linux kernel image for version 3.
ii  linux-image-3. 3.5.0-19.30  amd64        Linux kernel image for version 3.
ii  linux-image-3. 3.5.0-21.32  amd64        Linux kernel image for version 3.
ii  linux-image-3. 3.5.0-22.34  amd64        Linux kernel image for version 3.
ii  linux-image-3. 3.5.0-23.35  amd64        Linux kernel image for version 3.
ii  linux-image-ex 3.5.0-17.28  amd64        Linux kernel image for version 3.
ii  linux-image-ex 3.5.0-18.29  amd64        Linux kernel image for version 3.
ii  linux-image-ex 3.5.0-19.30  amd64        Linux kernel image for version 3.
ii  linux-image-ex 3.5.0-21.32  amd64        Linux kernel image for version 3.
ii  linux-image-ex 3.5.0-22.34  amd64        Linux kernel image for version 3.
ii  linux-image-ex 3.5.0-23.35  amd64        Linux kernel image for version 3.
ii  linux-image-ge 3.5.0.23.29  amd64        Generic Linux kernel image
ii  linux-image-se 3.5.0.23.29  amd64        Transitional package.
un  linux-initramf <none>                    (no description available)
un  linux-kernel-h <none>                    (no description available)
un  linux-kernel-l <none>                    (no description available)
ii  linux-libc-dev 3.5.0-23.35  amd64        Linux Kernel Headers for developm
un  linux-restrict <none>                    (no description available)
ii  linux-sound-ba 1.0.25+dfsg- all          base package for ALSA and OSS sou
un  linux-source-2 <none>                    (no description available)
un  linux-source-3 <none>                    (no description available)
un  linux-source-3 <none>                    (no description available)
un  linux-source-3 <none>                    (no description available)
un  linux-tools    <none>                    (no description available)
</pre>
<p>You can look at the man page for dpkg-query for more detail, but the items with an &#8220;i&#8221; for the 2nd character are currently installed.  We&#8217;ll essentially want to dig through these installed old kernels and purge the ones we don&#8217;t want.</p>
<h2>
Step 2 &#8211; Show Unused Linux Kernels: <code>sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d'</code><br />
</h2>
<p>This one is a little more tricky.  We need to dissect it from the inside out.  In the middle of that mess, you&#8217;ll see:</p>
<pre class="brush:bash; gutter: false;">
"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"
</pre>
<p>That&#8217;s essentially a command inside a command (kind of like the pipe concept, but injected in middle instead of the start of the input stream).  We can drop the encapsulating &#8220;$( )&#8221; to see what this does:</p>
<pre class="brush:bash; gutter: false;">
$ uname -r
3.5.0-23-generic
</pre>
<p>&#8230; and then &#8230;</p>
<pre class="brush:bash; gutter: false;">
$ uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/"
3.5.0-23
</pre>
<p>As we see, this is using the uname command with the -r option to print the kernel release that&#8217;s active on our system.  That next piece calls a powerful program called sed.  It uses a regular expression to trim down the output of uname.  If read in English, it says, &#8220;for the input given, try to first find as many characters as you can until you get to the last hyphen and remember them; if after the hyphen you find only non-numeric characters then replace the matched string with what was remembered, otherwise do nothing.&#8221;  The regular expression is much more eloquent.  :)</p>
<p>To better understand the remaining logic, we can reduce that original monster to the following by manually inserting &#8220;3.5.0-23&#8243; where that uname/sed combo was before:</p>
<pre class="brush:bash; gutter: false;">
sed '/^ii/!d;/'"3.5.0-23"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d'
</pre>
<p>This isn&#8217;t as bad as it first appears.  It&#8217;s simply a chain of matches with /d or /!d, which mean delete the match or delete everything but the match respectively.  Plus there&#8217;s one substitution. So &#8230;</p>
<pre class="brush:bash; gutter: false;">
/^ii/!d 
</pre>
<p>&#8230; means, delete all lines except those that start with ii</p>
<pre class="brush:bash; gutter: false;">
/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d
</pre>
<p>&#8230; means, delete all lines with the current kernel version in them (remember, this is equivalent to <code>/'"3.5.0-23"'/d</code>)</p>
<pre class="brush:bash; gutter: false;">
s/^[^ ]* [^ ]* \([^ ]*\).*/\1/
</pre>
<p>Consume all non-space characters, if any, followed by a space.  Repeat.  Remember the next set of non-space characters.  Consume everything that follows.  Replace everything with the remembered match.</p>
<pre class="brush:bash; gutter: false;">
/[0-9]/!d
</pre>
<p>&#8230; means, delete all lines except those with numbers.</p>
<p>My final output is the following:</p>
<pre class="brush:bash; gutter: false;">
linux-image-2.6.38-11-server
linux-image-2.6.38-8-server
linux-image-3.0.0-17-server
linux-image-3.2.0-32-generic
linux-image-3.5.0-17-generic
linux-image-3.5.0-18-generic
linux-image-3.5.0-19-generic
linux-image-3.5.0-21-generic
linux-image-3.5.0-22-generic
linux-image-extra-3.5.0-17-generic
linux-image-extra-3.5.0-18-generic
linux-image-extra-3.5.0-19-generic
linux-image-extra-3.5.0-21-generic
linux-image-extra-3.5.0-22-generic
</pre>
<h2>
Step 3 &#8211; Remove the Unused Kernels: <code>xargs sudo apt-get -y purge</code><br />
</h2>
<p>From the xargs man page, &#8220;xargs reads items from the standard input, delimited by blanks (which can be protected with double or single quotes or a backslash) or newlines, and executes the command (default is /bin/echo) one or more times with any initial-arguments followed by items read from standard input.  Blank lines on the standard input are ignored.&#8221;  In other words, xargs is going to let us issue the same command to each of those items listed in the last section.</p>
<p>The rest is fairly self explanatory.  For every package listed, we&#8217;re going to ask apt-get to purge it, which the man page states means, &#8220;packages are removed and purged (any configuration files are deleted too).&#8221;  The -y option means apt-get won&#8217;t ask for a confirmation.  If you&#8217;re uneasy about the process, you might remove this for a dry-run, but given the cyclic nature of how we&#8217;re calling the command, it will abort (which is fine for a dry run, but you&#8217;ll have to add -y for it to work).</p>
<p>For completeness, sudo runs the purge as the super user.</p>
<h2>All Together</h2>
<p>Let&#8217;s try without -y first:</p>
<pre class="brush:bash; gutter: false;">
$ dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d' | xargs sudo apt-get purge
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following packages will be REMOVED:
  linux-image-2.6.38-11-server* linux-image-2.6.38-8-server* linux-image-3.0.0-17-server* linux-image-3.2.0-32-generic* linux-image-3.5.0-17-generic*
  linux-image-3.5.0-18-generic* linux-image-3.5.0-19-generic* linux-image-3.5.0-21-generic* linux-image-3.5.0-22-generic* linux-image-extra-3.5.0-17-generic*
  linux-image-extra-3.5.0-18-generic* linux-image-extra-3.5.0-19-generic* linux-image-extra-3.5.0-21-generic* linux-image-extra-3.5.0-22-generic*
0 upgraded, 0 newly installed, 14 to remove and 0 not upgraded.
After this operation, 1,359 MB disk space will be freed.
Do you want to continue [Y/n]? Abort.
</pre>
<p>Note the abort.  This occurs automatically.  Everything looks good here.  Our current kernel isn&#8217;t in the list.  Let&#8217;s do it!  This time a lot more happens.  I&#8217;ve inserted [SIMILAR OUTPUT DELETED] where the output is iterating over versions:</p>
<pre class="brush:bash; gutter: false;">
$ dpkg -l 'linux-*' | sed '/^ii/!d;/'"$(uname -r | sed "s/\(.*\)-\([^0-9]\+\)/\1/")"'/d;s/^[^ ]* [^ ]* \([^ ]*\).*/\1/;/[0-9]/!d' | xargs sudo apt-get -y purge
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following packages will be REMOVED:
  linux-image-2.6.38-11-server* linux-image-2.6.38-8-server* linux-image-3.0.0-17-server* linux-image-3.2.0-32-generic* linux-image-3.5.0-17-generic*
  linux-image-3.5.0-18-generic* linux-image-3.5.0-19-generic* linux-image-3.5.0-21-generic* linux-image-3.5.0-22-generic* linux-image-extra-3.5.0-17-generic*
  linux-image-extra-3.5.0-18-generic* linux-image-extra-3.5.0-19-generic* linux-image-extra-3.5.0-21-generic* linux-image-extra-3.5.0-22-generic*
0 upgraded, 0 newly installed, 14 to remove and 0 not upgraded.
After this operation, 1,359 MB disk space will be freed.
(Reading database ... 196310 files and directories currently installed.)
Removing linux-image-2.6.38-11-server ...
Examining /etc/kernel/postrm.d .
run-parts: executing /etc/kernel/postrm.d/initramfs-tools 2.6.38-11-server /boot/vmlinuz-2.6.38-11-server
update-initramfs: Deleting /boot/initrd.img-2.6.38-11-server
run-parts: executing /etc/kernel/postrm.d/zz-update-grub 2.6.38-11-server /boot/vmlinuz-2.6.38-11-server
Generating grub.cfg ...
Found linux image: /boot/vmlinuz-3.5.0-23-generic
Found initrd image: /boot/initrd.img-3.5.0-23-generic
Found linux image: /boot/vmlinuz-3.5.0-22-generic
Found initrd image: /boot/initrd.img-3.5.0-22-generic
Found linux image: /boot/vmlinuz-3.5.0-21-generic
Found initrd image: /boot/initrd.img-3.5.0-21-generic
Found linux image: /boot/vmlinuz-3.5.0-19-generic
Found initrd image: /boot/initrd.img-3.5.0-19-generic
Found linux image: /boot/vmlinuz-3.5.0-18-generic
Found initrd image: /boot/initrd.img-3.5.0-18-generic
Found linux image: /boot/vmlinuz-3.5.0-17-generic
Found initrd image: /boot/initrd.img-3.5.0-17-generic
Found linux image: /boot/vmlinuz-3.2.0-32-generic
Found initrd image: /boot/initrd.img-3.2.0-32-generic
Found memtest86+ image: /memtest86+.bin
done
Purging configuration files for linux-image-2.6.38-11-server ...
Examining /etc/kernel/postrm.d .
run-parts: executing /etc/kernel/postrm.d/initramfs-tools 2.6.38-11-server /boot/vmlinuz-2.6.38-11-server
run-parts: executing /etc/kernel/postrm.d/zz-update-grub 2.6.38-11-server /boot/vmlinuz-2.6.38-11-server

[SIMILAR OUTPUT DELETED]
</pre>
<p>Note how the apt-get process even runs grub for you so your reboot menu is ready to go.  Very nice!</p>
<p>Now let&#8217;s check our /boot partition, which was using 86% of 227 MB of storage space.</p>
<pre class="brush:bash; gutter: false;">
$ du -h /boot --max-depth=0
35M	/boot
</pre>
<p>Ah, only 35 M in use, i.e., 15%.  Plenty of room for new kernel releases!</p>
]]></content:encoded>
			<wfw:commentRss>http://markmcb.com/2013/02/04/cleanup-unused-linux-kernels-in-ubuntu/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Remove Chromatic Aberration With Lightroom</title>
		<link>http://markmcb.com/2013/01/14/remove-chromatic-aberration-with-lightroom/</link>
		<comments>http://markmcb.com/2013/01/14/remove-chromatic-aberration-with-lightroom/#comments</comments>
		<pubDate>Mon, 14 Jan 2013 16:45:27 +0000</pubDate>
		<dc:creator>Mark McBride</dc:creator>
				<category><![CDATA[Apps and Data]]></category>
		<category><![CDATA[Photography]]></category>
		<category><![CDATA[chromatic aberration]]></category>
		<category><![CDATA[lightroom]]></category>
		<category><![CDATA[photography]]></category>

		<guid isPermaLink="false">http://markmcb.com/?p=761</guid>
		<description><![CDATA[I was chatting with Karen Yang last week about photography and she mentioned that she uses Photoshop to open each of her photos individually to edit them. As I&#8217;m a huge fan of all of the powerful one-or-two-click tweaks in Lightroom, &#8230; <a href="http://markmcb.com/2013/01/14/remove-chromatic-aberration-with-lightroom/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I was chatting with <a href="https://plus.google.com/u/0/115465858183986082946/about">Karen Yang</a> last week about photography and she mentioned that she uses Photoshop to open each of her photos individually to edit them. As I&#8217;m a huge fan of all of the powerful one-or-two-click tweaks in Lightroom, I thought I&#8217;d note one here that I fixed over the weekend and hopefully begin to help Karen see the Light &#8230; room. :)</p>
<p>The issue I ran into with my photo is called <a href="http://en.wikipedia.org/wiki/Chromatic_aberration">chromatic aberration</a>. It&#8217;s a term that simply means not all colors of light had the same focal alignment when captured.  Chromatic aberration usually can be seen by colors bleeding out on the edges of subjects in your photos. Check out this shot of me as an example:</p>
<div style="text-align: center">
<img src="https://dl.dropbox.com/u/10448520/articles/201301-Chromatic-Aberration/1-large-before-change.png" />
</div>
<p><span id="more-761"></span><br />
At first glance this photo seems normal. However, if you look at my face you&#8217;ll notice it has an oddly harsh contrast with the light behind it. Zooming in reveals the culprit.</p>
<div style="text-align: center">
<img src="https://dl.dropbox.com/u/10448520/articles/201301-Chromatic-Aberration/2-zoom-before-change.png" />
</div>
<p>Now the purple-pink glow on the edge of my face is obvious. That&#8217;s chromatic aberration, specifically <a href="http://en.wikipedia.org/wiki/Purple_fringing">purple fringing</a>. In this case it&#8217;s probably being caused by that very bright window behind me sending bright light past my face, which is being lit by comparatively dim light from the room (no flash).</p>
<div style="text-align: center">
<img src="https://dl.dropbox.com/u/10448520/articles/201301-Chromatic-Aberration/3-chromatic-aberration-slider.png" />
</div>
<p>In Lightroom, the fix is simple. While in Develop mode, expand the <em>Lens Corrections</em> box, and choose the <em>Color</em> sub-menu. From there, we&#8217;re just two clicks away from a clean photo. Simply check the <em>Remove Chromatic Aberration</em> box and set the amount to 5 (or whatever makes the purple color go away).</p>
<div style="text-align: center">
<img src="https://dl.dropbox.com/u/10448520/articles/201301-Chromatic-Aberration/4-zoom-after-change.png" />
</div>
<p>Tada! The photo is much better now.  You can play with the other sliders to get the exact desired correction you&#8217;re looking for, but I find that most of the time those two steps are all I need.</p>
<div style="text-align: center">
<img src="https://dl.dropbox.com/u/10448520/articles/201301-Chromatic-Aberration/5-large-after-change.png" />
</div>
<p>And when we zoom back out we&#8217;ll find that the harsh contrast between my face and the window is much less with the chromatic aberration removed.</p>
<p>So that&#8217;s it. A check box and a slider and we&#8217;re done.  It&#8217;s just one of many ways Lightroom makes quick photo touchups easy.</p>
]]></content:encoded>
			<wfw:commentRss>http://markmcb.com/2013/01/14/remove-chromatic-aberration-with-lightroom/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Managing A Large Photo Library With Lightroom, Dropbox, and Crashplan</title>
		<link>http://markmcb.com/2013/01/04/managing-a-large-photo-library-with-lightroom-dropbox-crashplan/</link>
		<comments>http://markmcb.com/2013/01/04/managing-a-large-photo-library-with-lightroom-dropbox-crashplan/#comments</comments>
		<pubDate>Fri, 04 Jan 2013 17:00:46 +0000</pubDate>
		<dc:creator>Mark McBride</dc:creator>
				<category><![CDATA[Apps and Data]]></category>
		<category><![CDATA[Photography]]></category>
		<category><![CDATA[adobe]]></category>
		<category><![CDATA[apple]]></category>
		<category><![CDATA[archive]]></category>
		<category><![CDATA[avahi]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[camera]]></category>
		<category><![CDATA[crashplan]]></category>
		<category><![CDATA[dropbox]]></category>
		<category><![CDATA[lightroom]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[macbook]]></category>
		<category><![CDATA[netatalk]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[photos]]></category>

		<guid isPermaLink="false">http://markmcb.com/?p=735</guid>
		<description><![CDATA[Late last year I made the switch to Adobe&#8217;s Lightroom 4 from Aperture and Picasa for a variety of reasons, but a big one was photo/file management. As my photo collection got larger I found that I&#8217;d need more than &#8230; <a href="http://markmcb.com/2013/01/04/managing-a-large-photo-library-with-lightroom-dropbox-crashplan/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Late last year I made the switch to Adobe&#8217;s Lightroom 4 from <a href="http://markmcb.com/2011/10/28/3-reasons-aperture-and-picasa-are-a-great-photo-combo/">Aperture and Picasa</a> for a variety of reasons, but a big one was photo/file management. As my photo collection got larger I found that I&#8217;d need more than my laptop&#8217;s hard drive to store them all. Despite all the things I liked about Aperture and Picasa, both had clunky file management and the burden was enough to make me consider alternatives. I&#8217;m now very happy with the workflow described below using Lightroom, Dropbox, Crashplan, and a Linux file server.</p>
<h2>What I Want to Accomplish</h2>
<p>I want my setup to enable the following:</p>
<ol>
<li><strong>Mobile Photo Management</strong>: To be clear, when I say &#8220;mobile,&#8221; I don&#8217;t mean smartphone. I take my Canon 5D Mark III everywhere and like to transfer photos to my Apple MacBook Pro immediately. It&#8217;s important that I be able to do whatever I need to do no matter where I am, i.e., I don&#8217;t want to be tied to my office.</li>
<li><strong>Large Photo Archive</strong>: Photos (especially RAW photos) consume a lot of disk space. I want a file server to store any photos that I&#8217;m not actively working on. It has to be huge and scalable.</li>
<li><strong>Passive Transport</strong>: I want my files to get to my file server as quickly as possible, but I don&#8217;t want it to be an active part of my workflow, e.g., I don&#8217;t want to get stuck waiting on a FTP program to finish its batch before I can disconnect from a wifi spot or put my computer to sleep. I&#8217;d rather it just happen when the opportunity arises.</li>
<li><strong>One-Time, Offsite Backup</strong>: Once my files are on the file server, I want them to back up from the server only (i.e., I don&#8217;t want my laptop doing a second backup). Also, as I&#8217;ve noted before, I like <a href="http://markmcb.com/2012/06/10/understanding-offsite-backup-vs-local-backup-vs-syncing/">offsite backup of my photos</a>. A local copy isn&#8217;t good enough.</li>
<li><strong>Accessibility</strong>. When home, I want to easily access all of my photos, whether they&#8217;re on my laptop or in the archive.</li>
</ol>
<p>Sound like a lot to accomplish? It turns out it&#8217;s pretty easy to do.<span id="more-735"></span></p>
<h2>The Right Tools For The Job</h2>
<p>I use 4 tools for the following purposes:</p>
<ol>
<li><strong>Mobile Photo Management</strong>: Lightroom 4.3</li>
<li><strong>Large Photo Archive</strong>: Linux File Server (though any OS will do as long as it meets your storage needs &#8230; more later)</li>
<li><strong>Passive Transport</strong>: Dropbox</li>
<li><strong>One-Time, Offsite Backup</strong>: Crashplan</li>
<li><strong>Accessibility</strong>: Lightroom 4.3</li>
</ol>
<p>Now let&#8217;s walk through each.</p>
<h2>Mobile Photo Management</h2>
<p>I use an Apple MacBook Pro and Adobe Lightroom for just about all of my photo work. The MacBook Pro is really just personal preference. Any laptop with decent specs running OS X or Windows (needed for Lightroom) will work just fine.</p>
<p>As for Lightroom, there are endless articles online describing the strong points of what it lets you do with your photos. I won&#8217;t reiterate those points, but will simply say it&#8217;s fantastic both for viewing and processing your photos. It&#8217;s a perfect on-the-road application that lets you quickly import, tweak, and export your photos to wherever you intend to share them.</p>
<p>What I will focus on is how it integrates with the other needs I listed, so let&#8217;s move on to those areas.</p>
<h2>Linux File Server for Large Photo Archive</h2>
<p>I essentially did 2 things:</p>
<ol>
<li><a href="http://markmcb.com/2011/06/11/5tb-lvm-volume-with-an-lsi-9265-8i-raid-controller/">Built a 5 TB RAID Array</a> &#8211; all the details you need are on that link</li>
<li>Configured an Apple File System service on the Linux server using netatalk and avahi</li>
</ol>
<p>I won&#8217;t go into details of those applications as there are plenty of other articles online documenting what they are and how to set them up, but the gist is that netatalk enables the sharing of a folder on your server to OS X, and avahi advertises it on your local network so that you see it in Finder. The key configuration after installing each is:</p>
<p>For netatalk, in /etc/netatalk/AppleVolumes.default:</p>
<pre class="brush:bash">"Media" -tcp -noddp -uamlist uams_guest.so,uams_dhx.so,uams_dhx2.so -nosavepassword</pre>
<p>And in /etc/netatalk/afpd.conf:</p>
<pre class="brush:bash"># Access The Storage Area On Your Server
/mnt/store/private/photos "Photos" allow:markmcb</pre>
<p>For avahi, in /etc/avahi/services/media_group.service:</p>
<pre class="brush:bash">&lt;?xml version="1.0" standalone='no'?&gt;
&lt;!DOCTYPE service-group SYSTEM "avahi-service.dtd"&gt;
&lt;service-group&gt;
&lt;name replace-wildcards="no"&gt;Media&lt;/name&gt;

&lt;service&gt;
&lt;type&gt;_afpovertcp._tcp&lt;/type&gt;
&lt;port&gt;548&lt;/port&gt;
&lt;/service&gt;

&lt;service&gt;
&lt;type&gt;_device-info._tcp&lt;/type&gt;
&lt;port&gt;0&lt;/port&gt;
&lt;txt-record&gt;model=RackMac&lt;/txt-record&gt;
&lt;/service&gt;

&lt;/service-group&gt;</pre>
<p>If you get that all set up, you should see something like the following in Finder (using what I listed, you&#8217;d only see the &#8220;Photos&#8221; folder).</p>
<div class="wp-caption aligncenter" style="width: 508px"><img class="        " alt="Finder" src="https://dl.dropbox.com/u/10448520/articles/201301-Lightroom/linux-apple-file-share.png" width="498" height="311" /><p class="wp-caption-text">OS X accessing a Linux file server via Finder.</p></div>
<p>If that all made sense, the rest of this steps in this article are quite easy in comparison. :)</p>
<h2>Passive Transport</h2>
<p>First, if you&#8217;re not already using <a href="http://www.dropbox.com/">Dropbox</a>, check it out. The concept is simple: for every device you install Dropbox on there is a Dropbox folder. If you put a file in the Dropbox folder on device A, it uploads to Dropbox and downloads to devices B, C, D, etc., automatically. In other words, it&#8217;s a folder that syncs across devices. The key here is that it does this automatically, i.e., you don&#8217;t tell Dropbox to start a transport, it just does it once a file is saved and an Internet connection is available.</p>
<p>All we need to do is:</p>
<ol>
<li>Install Dropbox on the laptop</li>
<li>Install Dropbox on the Linux server</li>
<li>Create a folder somewhere in Dropbox for our active photos</li>
<li>Add that folder to the folders list in Lightroom</li>
</ol>
<p>For me, #3 is ~/Dropbox/Photos/Master Workspace, and when added to Lightroom it looks like:</p>
<p><img class="aligncenter" alt="" src="https://dl.dropbox.com/u/10448520/articles/201301-Lightroom/master-workspace-folder.png" width="358" height="137" /></p>
<p>As you can see, I have 313 active photos in this workspace. As soon as I import new photos into Lightroom, Dropbox will start to upload them. Let&#8217;s say I take 100 photos and import them from my hotel room. As soon as I import them, the upload starts. Let&#8217;s say it&#8217;s a slow connection and 20 have finished when my friend calls and wants to meet up for lunch. With Dropbox, I just pack up my laptop and go. Whenever I open it next and get on the net, it will resume. In the mean time, those 20 photos that transferred are being downloaded to my Linux server that&#8217;s always online. Once the server gets the copy, it backs them up (more on that in the next section). It&#8217;s important to note that the backup process is a separate one. While Dropbox offers some backup characteristics, you really shouldn&#8217;t depend on it as a backup solution.</p>
<p>The benefit here is that, when I&#8217;m away for a few days or weeks, my photos automatically make their way to a safer place on my server. In general I like to have my laptop be a &#8220;throw-away laptop.&#8221; That&#8217;s not to say I&#8217;d be happy if I lost it, but I like knowing that data loss from such an event would be minimal or none. Dropbox helps a lot in making that true (and not just for photos).</p>
<h2>One-Time, Offsite Backup</h2>
<p>Dropbox has now sent the files to my Linux server&#8217;s Dropbox folder. This is one of two places my photos reside in this process. Once I am done actively working with them, they will move to the archive folder that we shared earlier.</p>
<p><a href="http://markmcb.com/2011/07/31/crashplan-for-large-distributed-cheap-off-site-backup/">I use Crashplan for backup</a>. I&#8217;ve been using it almost two years now and it&#8217;s really a tremendous service for the price. One of the cool things it does is smartly determine if a file needs to be backed up, or if you&#8217;ve already backed it up before and a copy is on their servers. This is critical for the workflow I&#8217;m describing. Here&#8217;s what happens:</p>
<ol>
<li>From my remote location, I import photos to Lightroom</li>
<li>Lightroom stores the photos in my laptop&#8217;s Dropbox folder, let&#8217;s call it D1</li>
<li>D1 is uploaded to Dropbox</li>
<li>The Dropbox folder on my server, D2, gets the files pushed down</li>
<li>Crashplan is watching D2 and immediately starts backing up the files to the offsite backup destinations I&#8217;ve designated.</li>
<li>Crashplan is also watching the archive folder, A1. In the next section we&#8217;ll use Lightroom to move files from D1/D2 to A1. The nice thing Crashplan does is realize that the files being moved have already been backed up and simply updates some file pointers.</li>
</ol>
<p>That last step is HUGE if you work with RAW files like I do. When you need to transfer 500 RAW files at 30+ MB each, the last thing you want to be doing is chewing up more bandwidth than you have to. Granted, you&#8217;re already moving the files twice: once through Dropbox, and once through Crashplan. However, if you started the process remotely it&#8217;s not bandwidth you&#8217;re going to miss, i.e., all or some of this happens when you&#8217;re away and is generally finished when you sit down at your home computer to work. I really, really, really love this aspect of this workflow.</p>
<p><strong>Accessibility<br />
</strong></p>
<p>The last point I&#8217;ll touch on is accessibility. Once you&#8217;re home and ready to do some serious post-processing, you want to quickly get to all of your files regardless of where they&#8217;re physically stored. Lightroom 4 is a dream in this regard. In the same way we added the Master Workspace folder above, all we need to do is add the Master Archive folder on the Linux server that we made available via Finder. Once you&#8217;ve added the folders, your catalog acts as the brain and even if you forget to mount your shared drive, Lightroom give you intelligent feedback:</p>
<p>Forgot to mount? Lightroom shows question marks indicating it can&#8217;t find the folder:</p>
<p><img class="aligncenter" alt="" src="https://dl.dropbox.com/u/10448520/articles/201301-Lightroom/archive-unmouted.png" width="353" height="370" /></p>
<p>Not a problem, simply open finder and click on the shared drive to &#8220;mount&#8221; it. Mounted:</p>
<p style="text-align: center;"><img class="aligncenter" alt="" src="https://dl.dropbox.com/u/10448520/articles/201301-Lightroom/archive-mounted.png" width="356" height="372" /></p>
<p style="text-align: left;">And that&#8217;s it. Now you can click on any of those folders and work on them as if they were all stored on your computer.  If you drag a photo or folder from the Master Workspace to the Master Archive, then files move to their new home on the server and off your laptop and out of Dropbox (this is really good since even a &#8220;pro&#8221; Dropbox account only stores 100 GB of data).</p>
<h2 style="text-align: left;">Wrap-Up</h2>
<p style="text-align: left;">As with anything this complex, there are a bazillion ways to do it. I have tinkered with quite a few setups and this one is where I ended up. I really like the flexibility, the saved bandwidth, the immediacy of backup, and the ease of access. I hope this helps someone, and if you&#8217;ve got variations of this, I&#8217;d love to hear about them.</p>
]]></content:encoded>
			<wfw:commentRss>http://markmcb.com/2013/01/04/managing-a-large-photo-library-with-lightroom-dropbox-crashplan/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
		<item>
		<title>Stop Taking Lossy JPG Screen Shots for Text in OS X.  Use PNG.</title>
		<link>http://markmcb.com/2012/11/07/stop-taking-lossy-jpg-screen-shots-for-text-in-os-x-use-png/</link>
		<comments>http://markmcb.com/2012/11/07/stop-taking-lossy-jpg-screen-shots-for-text-in-os-x-use-png/#comments</comments>
		<pubDate>Wed, 07 Nov 2012 19:08:06 +0000</pubDate>
		<dc:creator>Mark McBride</dc:creator>
				<category><![CDATA[Hardware and Operating Systems]]></category>

		<guid isPermaLink="false">http://markmcb.com/?p=719</guid>
		<description><![CDATA[If you take a lot of screen shots in OS X using the built-in screen capture functionality (e.g., cmd-shift-4) and present them to other people, you should really consider changing one of the default OS X settings. This is especially &#8230; <a href="http://markmcb.com/2012/11/07/stop-taking-lossy-jpg-screen-shots-for-text-in-os-x-use-png/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>If you take a lot of screen shots in OS X using the built-in screen capture functionality (e.g., cmd-shift-4) and present them to other people, you should really consider changing one of the default OS X settings.  This is especially true if the content contains a lot of text.  To be clear about what I mean, consider these two captures of a random gDoc form:</p>
<p>Lossy capture using JPG:<br />
<img src="https://dl.dropbox.com/u/10448520/articles/201211-Screen-Shots/lossy.jpg" title="Lossy Screen Capture Using JPG" /></p>
<p>Lossless capture using PNG:<br />
<img src="https://dl.dropbox.com/u/10448520/articles/201211-Screen-Shots/lossless.png" title="Lossless Screen Capture Using PNG" /></p>
<p>You can probably see the difference quite clearly.  The jpg looks blotchy and the color of red has been distorted.  This is because the JPG format will degrade image quality to produce a smaller file.  Given that we&#8217;re talking 9 vs. 13 KB in this case, the savings don&#8217;t really matter.  What does matter is that the image looks terrible and makes you look oh-so-non-tech-savvy.</p>
<p>The solution is quite simple if you&#8217;re using OS X.  Simply change the default format for screen captures.  Launch the Terminal app and issue the following commands:</p>
<pre class="brush:bash">
$ defaults write com.apple.screencapture type png
$ killall SystemUIServer
</pre>
<p>That&#8217;s it!  All of your screen captures will now be in the much cleaner PNG format.  If you decide you&#8217;d rather have JPG again, just replace &#8220;png&#8221; with &#8220;jpg&#8221; in that first command.</p>
]]></content:encoded>
			<wfw:commentRss>http://markmcb.com/2012/11/07/stop-taking-lossy-jpg-screen-shots-for-text-in-os-x-use-png/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Controlling Movies in QuickTime Player&#160;X&#160;(10.1) With AppleScript</title>
		<link>http://markmcb.com/2012/07/19/controlling-movies-in-quicktime-player-x-10-1-with-applescript/</link>
		<comments>http://markmcb.com/2012/07/19/controlling-movies-in-quicktime-player-x-10-1-with-applescript/#comments</comments>
		<pubDate>Fri, 20 Jul 2012 04:29:56 +0000</pubDate>
		<dc:creator>Mark McBride</dc:creator>
				<category><![CDATA[Programming and Scripting]]></category>
		<category><![CDATA[apple]]></category>
		<category><![CDATA[applescript]]></category>
		<category><![CDATA[movie]]></category>
		<category><![CDATA[quicktime]]></category>
		<category><![CDATA[script]]></category>

		<guid isPermaLink="false">http://markmcb.com/?p=680</guid>
		<description><![CDATA[The following works for Quicktime Player X (10.1) in OS X 10.7 (Lion). It takes arguments from the command line and opens a movie, resizes it, sets the volume, and starts playing the movie (there are other properties you could &#8230; <a href="http://markmcb.com/2012/07/19/controlling-movies-in-quicktime-player-x-10-1-with-applescript/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>The following works for Quicktime Player X (10.1) in OS X 10.7 (Lion).  It takes arguments from the command line and opens a movie, resizes it, sets the volume, and starts playing the movie (there are <a href="https://discussions.apple.com/thread/4100584?start=0&#038;tstart=0">other properties</a> you could add).  Hopefully this is useful for someone like me who was trying to find examples of this, but only finding mounds of info for QuickTime Player 7 (and earlier), which doesn&#8217;t help much as many of the properties have changed.</p>
<pre class="brush:applescript">
-- AppleScript to open and control movie files in QuickTime Player X

-- The script is meant to run at the command line, like so:
-- $ osascript /path/to/movie.mp4 movie.mp4 800 60
-- If you don't want to use a shell, just remove this and 
-- the last line and manually populate the first 4 variables
on run argv
	
	set movieFile to item 1 of argv -- the full path with movie filename
	set movieName to item 2 of argv -- the file name only of the movie
	set desiredWidth to item 3 of argv -- the width of the movie on the screen
	set startOffset to item 4 of argv -- how many seconds into the movie to start
	
	-- this finds the right side of the screen, then offsets to the left
	-- the desired width of the movie
	tell application "Finder"
		set desktopBounds to bounds of window of desktop
	end tell
	set rightX to item 3 of desktopBounds
	set leftX to (rightX - desiredWidth)
	
	tell application "QuickTime Player"
		
		-- open the movie and bring it to the forefront (if other movies are open)
		open movieFile
		set lastOpenedWindow to (first window whose name contains movieName)
		set visible of lastOpenedWindow to true
		
		-- resize the movie using its original aspect ratio
		set movieBounds to bounds of lastOpenedWindow
		set widthOrigin to leftX
		set heightOrigin to 1
		set originalWidth to ((item 3 of movieBounds) - (item 1 of movieBounds))
		set originalHeight to ((item 4 of movieBounds) - (item 2 of movieBounds))
		set calculatedHeight to (round ((desiredWidth / originalWidth) * originalHeight) rounding down)
		set desiredWidth to (desiredWidth + widthOrigin)
		set calculatedHeight to (calculatedHeight + heightOrigin)
		set the bounds of lastOpenedWindow to {widthOrigin, heightOrigin, desiredWidth, calculatedHeight}
		
		-- if opening multiple movies, ensure they don't overlap
		set slideDown to 1
		repeat with aWindow in (get every window)
			set boundsOfAWindow to bounds of aWindow
			set heightOfAWindow to item 4 of boundsOfAWindow
			if (heightOfAWindow > slideDown) then
				if (name of aWindow does not contain movieName) then
					set slideDown to (heightOfAWindow + 1)
				end if
			end if
		end repeat
		set the bounds of lastOpenedWindow to {widthOrigin, (heightOrigin + slideDown), desiredWidth, (calculatedHeight + slideDown)}
		
		-- note, here we select a document, not a window
		set myMovie to document 1
		tell myMovie
			set audio volume to 0
			set current time to startOffset
			play
			activate -- makes QuickTime Player the frontmost application
		end tell
		
	end tell
end run
</pre>
]]></content:encoded>
			<wfw:commentRss>http://markmcb.com/2012/07/19/controlling-movies-in-quicktime-player-x-10-1-with-applescript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Understanding Offsite Backup vs. Local Backup vs. Syncing</title>
		<link>http://markmcb.com/2012/06/10/understanding-offsite-backup-vs-local-backup-vs-syncing/</link>
		<comments>http://markmcb.com/2012/06/10/understanding-offsite-backup-vs-local-backup-vs-syncing/#comments</comments>
		<pubDate>Sun, 10 Jun 2012 16:47:42 +0000</pubDate>
		<dc:creator>Mark McBride</dc:creator>
				<category><![CDATA[Apps and Data]]></category>
		<category><![CDATA[apple]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[crashplan]]></category>
		<category><![CDATA[dropbox]]></category>
		<category><![CDATA[google drive]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[time capsule]]></category>
		<category><![CDATA[time machine]]></category>

		<guid isPermaLink="false">http://markmcb.com/?p=599</guid>
		<description><![CDATA[A few days ago a good friend of mine, Jami, sent me this question via email: &#8230; a while back &#8230; you wrote about cloud back ups and I believe you recommended Crash Plan. I tried the free trial but &#8230; <a href="http://markmcb.com/2012/06/10/understanding-offsite-backup-vs-local-backup-vs-syncing/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>A few days ago a good friend of mine, Jami, sent me this question via email:</p>
<blockquote><p>&#8230; a while back &#8230; you wrote about cloud back ups and I believe <a href="http://markmcb.com/2011/07/31/crashplan-for-large-distributed-cheap-off-site-backup/" target="_blank">you recommended Crash Plan</a>. I tried the free trial but was disappointed because it was SO slow. I like drop box, but couldn&#8217;t figure out a way to get it to automatically back up my whole computer like time machine did. I tried hooking up my old time capsule that we used to use as a router directly to my computer via ethernet, but I couldn&#8217;t get that to work. SO, I thought maybe it was just a random thing that Crash Plan was so slow the first time, so I signed up again in desperation. For 150+ gb, it says over 57 days?!? Do you think that seems right?</p>
<p>Do you have any other recommendations? I want something that worked like time machine did, preferably cloud based. I&#8217;m curious what you&#8217;re using.</p></blockquote>
<p>The following is what I responded with via email, but I&#8217;ve actually gotten this question from a few people lately, so I thought I&#8217;d post it here.<br />
<span id="more-599"></span><br />
The first fundamental question to ask is: what do you want when you say &#8220;backup&#8221;?</p>
<p>I&#8217;d say there are a few key criteria:</p>
<ol>
<li>A true backup &#8211; nothing<sup id="noteref1" style="font-size: 0.8em;"><a href="#note1">1</a></sup> you do can destroy your data</li>
<li>A fast, but at-risk backup &#8211; you&#8217;ve got a copy of everything, but you could destroy it</li>
<li>Sync &#8211; you can get to your files on any device with minor accident tolerance</li>
</ol>
<p>CrashPlan is all #1 and #2, and a partial #3.  Time Capsule is #2.  Dropbox is #3.</p>
<p>CrashPlan is as fast as your upload bandwidth to the Internet, which in general is slow.  The key with CrashPlan is that it&#8217;s:</p>
<ol>
<li>Unlimited storage for a super cheap rate.  I have almost 2 TB with them and it&#8217;s still less than $5 a month.  For Google Drive the same storage is $100/mo.  Dropbox is usually 4x Google, so while they don&#8217;t list the price for this, I assume it&#8217;d be $400/mo.  Big deal breaker.</li>
<li>It&#8217;s true backup.  First it&#8217;s off-site, so if your house burns down, someone steals your Time Capsule, or if any other catastrophe occurs, your data is still backed up.</li>
<li>If you have another computer with a large hard drive, you can have CrashPlan do super fast local backups.  For example, I back everything up to their cloud service, but I also back it up to my Linux server with a 5 TB drive.  If my laptop dies, I can quickly get my data from my local server.  If my house burns down, I can get my data from the cloud at a speed that corresponds to the speed of my Internet connection.</li>
</ol>
<p>A key thing to note with Dropbox is that it is not backup.  If I borrow your computer, delete your photos folder, and you don&#8217;t realize for a few weeks it&#8217;s just gone.  No recovery.  Dropbox does keep track of recently deleted files and allows you to restore them, but it&#8217;s unpredictable in terms of how long they&#8217;ll be available.  That feature is more for a &#8220;whoops, I didn&#8217;t mean to hit delete&#8221; situation.  Not really a true backup.  To contrast, you can tell CrashPlan to never delete backup copies of a folder like &#8220;Photos,&#8221; even if you delete it on your computer.</p>
<p>If you want true backup, I haven&#8217;t seen anything better than CrashPlan for the price.  The initial backup will take some time, but I wouldn&#8217;t worry about it too much.  If it&#8217;s a real issue, I&#8217;d check on your Internet plan and see if there&#8217;s an affordable faster plan.</p>
<p>Personally, I use all 3.  :-)</p>
<p>1. Dropbox is my sync solution.  I see it as a quick portal between computers.  I only have 8 GB on my plan though, so file size is limited.</p>
<p>2. My Linux box acts as an Apple Time Capsule.  If I want to go &#8220;back in time&#8221; in some folder, I use this.  (If disk space ever became an issue, I&#8217;d remove this.  It&#8217;s really overkill with the local half of #3 below.)</p>
<p>3. CrashPlan also runs on my Linux box and I pay for the &#8220;Pro&#8221; service.  It&#8217;s my ultimate fallback.  It is slow, but it&#8217;s the only true backup I have.</p>
<p>Ultimately it comes down to choosing what you want/need.  I&#8217;ve got tens of thousands of photos at this point that I&#8217;d hate to lose.  Moreover, I&#8217;m shooting RAW now and my photos come in around 30 MB each.  I&#8217;d hate to pay Dropbox-like fees to backup.  CrashPlan backs those (and everything else) up for a great price.</p>
<p>Notes</p>
<ol>
<li id="note1">When I say &#8220;nothing&#8221; I mean that it&#8217;s unlikely that a non-deliberate scenario would play out that would destroy data. Clearly, if you log into your backup account and say &#8220;delete my account&#8221; and then smash your computer, your data is likely gone forever. I&#8217;m not considering these unlikely and deliberate scenarios. <a href="#noteref1">↑ back.</a></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://markmcb.com/2012/06/10/understanding-offsite-backup-vs-local-backup-vs-syncing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Replacing â€“, â€™, â€œ, etc., with UTF-8 Characters in Ruby on Rails</title>
		<link>http://markmcb.com/2011/11/07/replacing-ae%e2%80%9c-ae%e2%84%a2-aeoe-etc-with-utf-8-characters-in-ruby-on-rails/</link>
		<comments>http://markmcb.com/2011/11/07/replacing-ae%e2%80%9c-ae%e2%84%a2-aeoe-etc-with-utf-8-characters-in-ruby-on-rails/#comments</comments>
		<pubDate>Mon, 07 Nov 2011 17:34:49 +0000</pubDate>
		<dc:creator>Mark McBride</dc:creator>
				<category><![CDATA[Apps and Data]]></category>
		<category><![CDATA[characters]]></category>
		<category><![CDATA[encoding]]></category>
		<category><![CDATA[rails]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[utf8]]></category>

		<guid isPermaLink="false">http://markmcb.com/?p=449</guid>
		<description><![CDATA[Recently I upgraded some older Rails applications to Rails 3.1 and Ruby 1.9.2 (from 2.3 and 1.8.7 respectively). One post-upgrade issue was that text content had a lot of garbage showing up like â€“, â€™, â€œ, etc. For example, here&#8217;s &#8230; <a href="http://markmcb.com/2011/11/07/replacing-ae%e2%80%9c-ae%e2%84%a2-aeoe-etc-with-utf-8-characters-in-ruby-on-rails/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Recently I upgraded some older Rails applications to Rails 3.1 and Ruby 1.9.2 (from 2.3 and 1.8.7 respectively).  One post-upgrade issue was that text content had a lot of garbage showing up like â€“, â€™, â€œ, etc.  For example, here&#8217;s an actual example from a comment in one of the applications:</p>
<blockquote><p>One of my â€œthings to do before Iâ€™m 50â€ is</p></blockquote>
<p>This should read:</p>
<blockquote><p>One of my “things to do before I’m 50” is </p></blockquote>
<p>It turns out these are just special characters that were improperly encoded for utf-8.  The fix is simple enough: loop through your content and replace where needed.  </p>
<p>If your database is big, this could take a long time unless you disable callbacks.  The script below highlights both how to replace the characters using Ruby and how to disable your Rails callbacks to make this script run in seconds instead of hours (depending on the complexity of your callbacks).</p>
<pre class="brush:ruby">
replacements = []
replacements << ['â€¦', '…']           # elipsis
replacements << ['â€“', '–']           # long hyphen
replacements << ['â€™', '’']           # curly apostrophe
replacements << ['â€œ', '“']           # curly open quote
replacements << [/â€[[:cntrl:]]/, '”'] # curly close quote
klasses = [Comment, Article]           # replace with relevant classes
 
klasses.each do |klass|
  klass.all.each do |obj|
    original = obj.body
    replacements.each{ |set| obj.body = obj.body.gsub(set[0], set[1]) }
    unless (original == obj.body)
      #### Remove or Customize ####
      # This should reflect your models' callbacks.  It should be safe
      # since we're just doing a simple find/replace.
      Comment.skip_callback(:save, :after,  :do_after_save_tasks ) if obj.is_a?(Comment)
      Article.skip_callback(:save, :before, :do_before_save_tasks) if obj.is_a?(Article)
      #### End Remove or Customize ####
      obj.save! 
    end
  end
end
</pre>
<p>If you noticed, I used a regular expression for the curly close quote.  This is because there is an invisible control character that is not easily copy/pasted into your code.  Using <code>[[:cntrl:]]</code> is just an easier way to catch it.</p>
]]></content:encoded>
			<wfw:commentRss>http://markmcb.com/2011/11/07/replacing-ae%e2%80%9c-ae%e2%84%a2-aeoe-etc-with-utf-8-characters-in-ruby-on-rails/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Integer Compression in Ruby (Base-10 to Base-62)</title>
		<link>http://markmcb.com/2011/11/02/integer-compression-in-ruby-base-10-to-base-62/</link>
		<comments>http://markmcb.com/2011/11/02/integer-compression-in-ruby-base-10-to-base-62/#comments</comments>
		<pubDate>Wed, 02 Nov 2011 21:17:06 +0000</pubDate>
		<dc:creator>Mark McBride</dc:creator>
				<category><![CDATA[Programming and Scripting]]></category>
		<category><![CDATA[integer]]></category>
		<category><![CDATA[math]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://markmcb.com/?p=415</guid>
		<description><![CDATA[A few days ago I was thinking about all those link shortening sites and wondered how easy it would be to compress a base-10 number like 1,234,567,890 to something much smaller like 1LY7VK. Here&#8217;s what I came up with: class &#8230; <a href="http://markmcb.com/2011/11/02/integer-compression-in-ruby-base-10-to-base-62/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>A few days ago I was thinking about all those link shortening sites and wondered how easy it would be to compress a base-10 number like 1,234,567,890 to something much smaller like 1LY7VK.  Here&#8217;s what I came up with:</p>
<pre class="brush:ruby">class IntegerCompressor
  
  CompressionCharacterSet = %w(0 1 2 3 4 5 6 7 8 9
  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
  a b c d e f g h i j k l m n o p q r s t u v w x y z)
  
  def self.to_base
    CompressionCharacterSet.length
  end

  def self.compress(number_to_convert)
    digits_needed = Math.log(number_to_convert, IntegerCompressor.to_base).floor + 1
    compressed_number_string = ''
    previous_remainder = number_to_convert
    (digits_needed-1).downto(0) do |power|
      r=previous_remainder.divmod(IntegerCompressor.to_base**power)
      compressed_number_string << CompressionCharacterSet[r[0]]
      previous_remainder = r[1]
    end
    compressed_number_string
  end
  
  def self.decompress(compressed_number)
    power = 0
    base_10_integer = 0
    compressed_number.to_s.reverse.each_char do |digit|
      base_10_integer += ((IntegerCompressor.to_base**power)*CompressionCharacterSet.index(digit))
      power+=1
    end
    base_10_integer
  end
  
end
</pre>
<p>It seems to work:</p>
<pre class="brush:ruby">$ irb
>> require '/path/to/file/integer_compressor.rb'
=> true
>> IntegerCompressor.compress 1234567890
=> "1LY7VK"
>> IntegerCompressor.decompress "1LY7VK"
=> 1234567890
</pre>
<p>If anyone has a more elegant solution, I'd be curious to see it.</p>
<p>(Thanks to <a href="https://plus.google.com/u/0/110560946703452708530/posts">Tamara</a> for the log refresher.)</p>
]]></content:encoded>
			<wfw:commentRss>http://markmcb.com/2011/11/02/integer-compression-in-ruby-base-10-to-base-62/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
<!-- This Quick Cache file was built for (  markmcb.com/feed/ ) in 0.45864 seconds, on May 22nd, 2013 at 7:11 am UTC. -->
<!-- This Quick Cache file will automatically expire ( and be re-built automatically ) on May 22nd, 2013 at 8:11 am UTC -->
<!-- +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
<!-- Quick Cache Is Fully Functional :-) ... A Quick Cache file was just served for (  markmcb.com/feed/ ) in 0.00090 seconds, on May 22nd, 2013 at 7:30 am UTC. -->