<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Navigator&apos;s Quarters</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/" />
    <link rel="self" type="application/atom+xml" href="http://www.garychambers.com/nq/atom.xml" />
    <id>tag:www.garychambers.com,2009-03-17:/nq//1</id>
    <updated>2011-02-18T02:55:13Z</updated>
    <subtitle>A comfortable nook on the Internet to discuss and review technology, current events, astronomy, and sailing and navigation.  High-quality cigars and spirits are optional, but strongly encouraged.</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type Pro 4.24-en</generator>

<entry>
    <title>Welcome WordPress!</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2011/02/welcome-wordpress.html" />
    <id>tag:garychambers.com,2011:/nq//1.78</id>

    <published>2011-02-18T02:38:55Z</published>
    <updated>2011-02-18T02:55:13Z</updated>

    <summary><![CDATA[This version of my blog is now defunct and will no longer be updated.&nbsp; I have decided to bite the bullet and install and instance of MySQL in order to use WordPress.&nbsp; It will continue to exist in pure HTML...]]></summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="general" label="general" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[This version of my blog is now defunct and will no longer be updated.&nbsp; I have decided to bite the bullet and install and instance of MySQL in order to use WordPress.&nbsp; It will continue to exist in pure HTML format to preserve the links and URLs that have been indexed by the various search engines over the past couple of years.&nbsp; Please visit (and update your bookmarks to) the new Navigator's Quarters WordPress blog at:<br /><br /><div align="center"><b><font style="font-size: 1.5625em;"><a href="http://nq.garychambers.com/">http://nq.garychambers.com/</a></font></b><br /><br /> </div>]]>
        
    </content>
</entry>

<entry>
    <title>So Long, Movable Type!</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2011/02/so-long-movable-type.html" />
    <id>tag:garychambers.com,2011:/nq//1.77</id>

    <published>2011-02-17T03:40:02Z</published>
    <updated>2011-02-17T04:27:43Z</updated>

    <summary><![CDATA[This is my final blog post using Movable Type.&nbsp; Several months ago, I learned that Six Apart would no longer natively support PostgreSQL in future versions of its software.&nbsp; Since then, I have been casually searching for a suitable replacement...]]></summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="general" label="general" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="technology" label="technology" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[This is my final blog post using Movable Type.&nbsp; <a href="http://garychambers.com/nq/2010/03/blogging-with-postgresql----or-not.html">Several months ago</a>, I learned that Six Apart would no longer natively support PostgreSQL in future versions of its software.&nbsp; Since then, I have been casually searching for a suitable replacement but found nothing worthwhile.&nbsp; I installed and briefly worked with Serendipity, but I couldn't find any noteworthy improvements over Movable Type, so I didn't think I would gain anything by a mere lateral migration.&nbsp; I began an earnest search for a replacement a few days ago and it appears that WordPress enjoys widespread support and receives good reviews from both users and administrators.&nbsp; The only problem -- and it is a <b>very big</b> problem for me -- is that the software only natively supports MySQL.&nbsp; I briefly used it back in the late-1990s.&nbsp; Suffice it to say that I am not now, have never been, nor will I ever be a proponent of MySQL, and I simply do not understand the size of the user base and acceptance it receives.&nbsp; Anyway, I held my nose and downloaded the Mac OS X version of the "database."&nbsp; Then I installed it and relearned the bare minimum I needed to create a database and configure a user account for a prototype WordPress installation.<br /><br />It took less than five minutes to get WordPress up and running.&nbsp; I've been working with it for about an hour, getting comfortable with how it operates.&nbsp; I was able to install the syntaxhighlighter plugin with zero difficulty, enable it and put it to good use even more quickly.&nbsp; There is a utility called Pg4WP out there that I may try before going to production with WordPress, but I have a feeling that it may not be worthwhile.&nbsp; In the end, I'm once again reminded that we should never say never.&nbsp; I said that I'd never voluntarily run a MySQL instance in any environment, but may end up doing just that.&nbsp; How about this?&nbsp; I'll never voluntarily run a MySQL instance in an enterprise-level capacity! ]]>
        
    </content>
</entry>

<entry>
    <title>Real Health Care Reform For The Real World</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2011/01/real-health-care-reform-for-the-real-world.html" />
    <id>tag:garychambers.com,2011:/nq//1.76</id>

    <published>2011-01-20T04:25:52Z</published>
    <updated>2011-01-20T04:54:50Z</updated>

    <summary><![CDATA[The tripe that the democrats peddled as health care reform has absolutely nothing to do with health care, nor does it have anything to do with reform (of anything).&nbsp; It is a power grab by a power-hungry bunch of corrupt,...]]></summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="obamacare" label="obamacare" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="politics" label="politics" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[The tripe that the democrats peddled as health care reform has absolutely nothing to do with health care, nor does it have anything to do with reform (of anything).&nbsp; It is a power grab by a power-hungry bunch of corrupt, lying elitists and, in true liberal form, the manufacture of a crisis to make an excuse for bigger government and reduced freedom for the American citizenry.&nbsp; The monstrosity piece of horrible legislation known as "ObamaCare" does absolutely nothing to address any of the problems that may (or may not) exist in the best medical system in the entire world.&nbsp; Quite simply, real reform begins with three (3) simple steps:<br /><br /><ol><li>Tort reform (limiting the amount of money awarded in malpractice lawsuits)</li><li>Eliminating <b>all</b> medical services to illegal aliens</li><li>Eliminating HMOs and PPOs and returning to pay-as-you-go medical care, except for catastrophic illnesses and injuries.</li></ol>Until problems 1 and 2 are resolved, everything else is meaningless and most of our so-called representatives know it.&nbsp; One of the representatives that does actually get it, Congressman Paul Ryan (R-WI), explains the smoke-and-mirrors that's contained in the horrific ObamaCare law:<br /><br /><br />
<iframe title="YouTube video player" class="youtube-player" type="text/html" width="640" height="510" src="http://www.youtube.com/embed/jp8gF7inYaM?rel=0" frameborder="0" allowFullScreen></iframe>]]>
        
    </content>
</entry>

<entry>
    <title>Liberals Tear Down All That Is Good And Wholesome</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2011/01/liberals-tear-down-all-that-is-good-and-wholesome.html" />
    <id>tag:garychambers.com,2011:/nq//1.75</id>

    <published>2011-01-15T15:54:58Z</published>
    <updated>2011-01-15T16:06:11Z</updated>

    <summary><![CDATA[Here's yet another shining example of how a liberal will do anything to destroy all that is good, wholesome, and right.&nbsp; Ronaldus Maximus' supposed son, Ronnie, Jr., has written a book in which he describes his father as suffering from...]]></summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="liberalism" label="liberalism" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="moralbankruptcy" label="moral bankruptcy" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="politics" label="politics" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[Here's yet another shining example of how a liberal will do anything to destroy all that is good, wholesome, and right.&nbsp; Ronaldus Maximus' supposed son, Ronnie, Jr., <a href="http://gqq.co/100X">has written a book</a> in which he describes his father as suffering from early stages of Alzheimer's disease while he was still in office.<br /><br />From the article:<br /><br />"The younger Reagan recalls how his father became uncharacteristically 
lost for words and looked "lost and bewildered" during the 1984 
presidential debates with Democratic rival Walter Mondale. He says his 
father may have suspected the onset of Alzheimer's in 1986 when he was 
flying over familiar canyons north of Los Angeles and became alarmed 
that he could no longer remember their names."<br /><br />Here's an "example" of how "lost and bewildered" the great man was:<br /><br /><br /><object width="480" height="385"><param name="movie" value="http://www.youtube.com/v/LoPu1UIBkBc?fs=1&amp;hl=en_US&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/LoPu1UIBkBc?fs=1&amp;hl=en_US&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"></embed></object>]]>
        
    </content>
</entry>

<entry>
    <title>The Height Of Hypocrisy And Ersatz Emotion</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2011/01/the-height-of-hypocrisy-and-ersatz-emotion.html" />
    <id>tag:garychambers.com,2011:/nq//1.74</id>

    <published>2011-01-13T03:02:27Z</published>
    <updated>2011-01-12T21:27:35Z</updated>

    <summary><![CDATA[It's difficult enough for me to see so much of the farce that is currently holding [hostage] the office of the President of the United States of America. &nbsp;Furthermore, it's almost intolerable to see the Manchurian Moonbat with the termagant...]]></summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="liberalism" label="liberalism" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="moralbankruptcy" label="moral bankruptcy" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="politics" label="politics" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[It's difficult enough for me to see so much of the farce that is currently holding [hostage] the office of the President of the United States of America. &nbsp;Furthermore, it's almost intolerable to see the Manchurian Moonbat with the termagant woman he calls his wife. &nbsp;To add insult to injury is the image below that was plastered on the FoxNews web site, exclaiming the possibility of his speech tonight in Arizona being a "defining moment" for the so-called President. What<b> a couple of disingenuous cretins</b>! &nbsp;They can't even feign sadness without looking like the incompetent boobs that they really are! &nbsp;I'd even go so far as to say that Moo-chelle has a smile on her face.<div><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><br /></span></div><div><span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="phony-obamas.jpg" src="http://garychambers.com/nq/phony-obamas.jpg" width="420" height="230" class="mt-image-none" style="" /></span></div><div><br /></div>]]>
        
    </content>
</entry>

<entry>
    <title>Ayn Rand&apos;s Prescience</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2011/01/ayn-rands-prescience.html" />
    <id>tag:garychambers.com,2011:/nq//1.73</id>

    <published>2011-01-13T02:49:48Z</published>
    <updated>2011-01-12T20:24:38Z</updated>

    <summary>How is it that some people are able to so eloquently and coherently put their thoughts about the world into words? Ayn Rand was a master: Envy is regarded by most people as a petty, superficial emotion and, therefore, it...</summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="liberalism" label="liberalism" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="moralbankruptcy" label="moral bankruptcy" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="politics" label="politics" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[<p>How is it that some people are able to so eloquently and coherently put their thoughts about the world into words?  Ayn Rand was a master:</p>

<blockquote>
<p>Envy is regarded by most people as a petty, superficial emotion and, therefore, it serves as a semihuman cover for so inhuman an emotion that those who feel it seldom dare admit it even to themselves ... . That emotion is: hatred of the good for being the good.</p>

<p>This hatred is not resentment against some prescribed view of the good with which one does not agree ... . Hatred of the good for being the good means hatred of that which one regards as good by one's own (conscious or subconscious) judgment. It means hatred of a person for possessing a value or virtue one regards as desirable.</p>

<p>If a child wants to get good grades in school, but is unable or unwilling to achieve them and begins to hate the children who do, that is hatred of the good. If a man regards intelligence as a value, but is troubled by self-doubt and begins to hate the men he judges to be intelligent, that is hatred of the good. </p>
</blockquote>

<p>Put into today's context, this accurately sums-up the liberal, "progressive" mindset.  Liberals today are soulless, selfish, evil fascists who will stop at nothing to advance their ill-conceived, dangerous, puerile agenda.</p>

<p>How about:</p>

<blockquote>
They do not want to own your fortune, they want you to lose it; they do not want to succeed, they want you to fail; they do not want to live, they want you to die; they desire nothing, they hate existence, and they keep running, each trying not to learn that the object of his hatred is himself . . . . They are the essence of evil, they, those anti-living objects who seek, by devouring the world, to fill the selfless zero of their soul. It is not your wealth that they're after. Theirs is a conspiracy against the mind, which means: against life and man.
</blockquote>

<p>H/T: Atlas Shrugs</p>]]>
        
    </content>
</entry>

<entry>
    <title>Postfix, Dovecot, and Sieve Connection Limits</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2011/01/postfix-dovecot-and-sieve-connection-limits.html" />
    <id>tag:garychambers.com,2011:/nq//1.72</id>

    <published>2011-01-12T03:16:23Z</published>
    <updated>2011-01-12T04:50:41Z</updated>

    <summary><![CDATA[I received a complaint from one of my customers about a password problem that reappeared (after having helped fix it only last night).&nbsp; A quick review of the logs revealed no authentication failures from the account, but I did see...]]></summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="dovecot" label="dovecot" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="networking" label="networking" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="postfix" label="postfix" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="sieve" label="sieve" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[I received a complaint from one of my customers about a password problem that reappeared (after having helped fix it only last night).&nbsp; A quick review of the logs revealed no authentication failures from the account, but I did see a few messages that I hadn't seen until now:<br /><br /><code>imap-login: Info: Maximum number of connections from user+IP exceeded</code><br /><br />I had just (last night) enabled Dovecot's deliver LDA (with the sieve plugin) for virtual account delivery and post-processing.&nbsp; Additionally, I enabled the managesieve plugin in the webmail client to provide customers the ability to mange everything themselves.&nbsp; A bit more research revealed (to me, anyway) that the Dovecot sieve and/or webmail managesieve plugins were consuming and holding one of those connections.<br /><br />To solve the problem, I added to dovecot.conf:<br /><br /><code>mail_max_userip_connections = 20<br /></code><br />The default seems to be 10.<br />]]>
        
    </content>
</entry>

<entry>
    <title>Yet Another URL Shortener (YAUS)</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2010/12/yet-another-url-shortener-yaus.html" />
    <id>tag:garychambers.com,2010:/nq//1.71</id>

    <published>2010-12-29T05:30:00Z</published>
    <updated>2010-12-29T05:36:38Z</updated>

    <summary>I ran across lilURL a couple of months ago, so I thought I&apos;d apply it to a short domain name I recently registered. Try it out at http://gqq.co/ and let me know what you think.It&apos;ll be around as long as...</summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="database" label="database" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="internet" label="internet" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="php" label="php" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="programming" label="programming" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[I ran across <a href="http://lilurl.sourceforge.net/">lilURL</a> a couple of months ago, so I
thought I'd apply it to a short domain name I recently registered.  Try
it out at <a href="http://gqq.co/">http://gqq.co/</a> and let me know what you think.<br /><br />It'll be around as long
as it's not abused or, if it is, if it doesn't take too long to fix
whatever weaknesses are exploited.  It contains very little of the original
lilURL code since I've ported all the database code to PostgreSQL, added URI reputation checks, and created methods out of much of the code that was originally contained in the index source file. ]]>
        
    </content>
</entry>

<entry>
    <title>Merry Christmas From Apollo 8</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2010/12/merry-christmas-from-apollo-8.html" />
    <id>tag:garychambers.com,2010:/nq//1.70</id>

    <published>2010-12-23T22:40:35Z</published>
    <updated>2010-12-23T22:46:07Z</updated>

    <summary> H/T: Michael Graham...</summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="american" label="american" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="general" label="general" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="technology" label="technology" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[ <object width="640" height="390"><param name="movie" value="http://www.youtube.com/v/SxiTKeQVjuo&hl=en_US&feature=player_embedded&version=3"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><embed src="http://www.youtube.com/v/SxiTKeQVjuo&hl=en_US&feature=player_embedded&version=3" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" width="640" height="390"></embed></object><p><p>H/T: Michael Graham]]>
        
    </content>
</entry>

<entry>
    <title>Obama and the Democrats&apos; Tax Shenanigans Explained</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2010/12/obama-and-the-democrats-tax-shenanigans-explained.html" />
    <id>tag:garychambers.com,2010:/nq//1.69</id>

    <published>2010-12-07T02:14:55Z</published>
    <updated>2010-12-07T02:23:10Z</updated>

    <summary><![CDATA[Please take a moment to learn how taxation really works in our country.&nbsp; When Obama and his ilk try to fool people into thinking that the so-called rich aren't paying their fair share, you'll be armed with information to combat...]]></summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="liberalism" label="liberalism" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="politics" label="politics" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[Please take a moment to <a href="http://gqq.co/1009" target="_blank">learn how taxation really works</a> in our country.&nbsp; When Obama and his ilk try to fool people into thinking that the so-called rich aren't paying their fair share, you'll be armed with information to combat the FUD. ]]>
        
    </content>
</entry>

<entry>
    <title>Software Engineering Blogging Software</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2010/10/software-engineering-blogging-software.html" />
    <id>tag:garychambers.com,2010:/nq//1.68</id>

    <published>2010-10-24T02:30:46Z</published>
    <updated>2010-10-24T03:03:44Z</updated>

    <summary><![CDATA[As I was "struggeling" Struggeling sound clip &nbsp;NFL sound clips with my previous entry on PostgreSQL MVC backups, I was constantly thinking that there had to be a better way to do this. Blogging software is not, by default, well-suited...]]></summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="programming" label="programming" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[As I was "struggeling" <embed src="http://media.entertonement.com/embed/OpenEntPlayer.swf" id="1_0a3d0724_df18_11df_ae77_00219b9a62b5" name="1_0a3d0724_df18_11df_ae77_00219b9a62b5" flashvars="auto_play=false&clip_pid=jhjhyczvxl&e=&id=1_0a3d0724_df18_11df_ae77_00219b9a62b5&skin_pid=wfxswdnlkf" width="300" height="30" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" allowscriptaccess="always" wmode="transparent"></embed><div id="1_0a3d0724_df18_11df_ae77_00219b9a62b5_anchor" style="font-size: 8px; color: black; text-decoration: none; display: block; text-align: center;"><a href="http://www.entertonement.com/clips/jhjhyczvxl--Struggeling-NFL-Joe-Namath-Football-New-York-Jets" style="font-size: 8px; color: black;" target="_blank">Struggeling sound clip</a> &nbsp;<a href="http://www.entertonement.com/collections/2615/NFL?ht_link=1_0a3d0724_df18_11df_ae77_00219b9a62b5" style="font-size: 8px; color: black;" target="_blank">NFL sound clips</a></div><img alt="Struggeling sound clip" border="0" height="0" src="http://www.entertonement.com/widgets/img/clip/jhjhyczvxl/1/1_0a3d0724_df18_11df_ae77_00219b9a62b5/blank.gif" style="visibility: hidden; width: 0px; height: 0px; margin:0; padding:0; float:right" width="0" /> with my previous entry on PostgreSQL MVC backups, I was constantly thinking that there <strong>had to be a better way</strong> to do this.<p>
<p>Blogging software is not, by default, well-suited to writing articles specific to software engineering (i.e. those requiring that source code be presented in a meaningful and accessible manner) -- at least not this one (Movable Type&trade;). I admit that my blogging experience is rather limited, and I'm mostly naive to many of the newer web technologies introduced in the past couple of years, so it's quite possible that there is something better out there.<p>
<p>Any ideas?]]>
        
    </content>
</entry>

<entry>
    <title>MVC Backups Updated</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2010/10/mvc-backups-updated.html" />
    <id>tag:garychambers.com,2010:/nq//1.67</id>

    <published>2010-10-22T01:30:59Z</published>
    <updated>2010-10-22T04:19:38Z</updated>

    <summary><![CDATA[David Fetter expanded upon a blog entry written by Joshua Drake by demonstrating how to create a PostgreSQL backup system based on the Model-View-Controller (MVC) design pattern.&nbsp; The simplicity of implementing such a reliable backup system inspired me to add...]]></summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="database" label="database" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="postgresql" label="postgresql" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[<a href="http://people.planetpostgresql.org/dfetter/index.php?/archives/61-MVC-Backups.html">David Fetter</a> expanded upon a <a href="http://www.commandprompt.com/blogs/joshua_drake/2010/07/a_better_backup_with_postgresql_using_pg_dump/">blog entry written by Joshua Drake</a> by demonstrating how to create a PostgreSQL backup system based on the Model-View-Controller (MVC) design pattern.&nbsp; The simplicity of implementing such a reliable backup system inspired me to add a bit more functionality to make it fit a bit better within my organization since our backup requirements are a bit more complex than just a daily backup of each database.&nbsp; We, for example, make an hourly backup of a fairly large database and a weekly backup of another, very large database.<br /><br />I chose to create a MVC backup system that would provide the administrator the ability to create backup profiles called by psql from a single script and store this backup configuration data within the database.&nbsp; Accordingly, I chose to implement a few rules to make it a safe system:<br /><br /><ol><li>All databases are backed-up unless they are expressly ignored.&nbsp; This means that an administrator can create databases until the cows come home and they will automatically be included in the backup.&nbsp; Unless...</li><li>Any number of databases can be excluded by adding them to the backup_ignored table for the profile.</li><li>All databases are backed-up if the backup_included table for the profile contains zero entries.</li><li>Finally, only those databases listed in the backup_included table are backed-up, regardless of the contents of the backup_ignored table.</li></ol>With the rules defined, let's put it all together.<br /><br /><b><font style="font-size: 1.25em;">The Schema<br /></font></b><blockquote>It's a simple, three-table schema (look Josh, no surrogate keys!):</blockquote>
<pre class='brush: sql'>
-- create pg-backups schema
--
drop table backup_profiles cascade;
create table backup_profiles (
    profile_name    text    constraint pk_backup_profiles primary key,
    dest_directory  text    not null default '/var/tmp/',
    bin_directory   text    default null,
    backup_globals  boolean not null default false
);
-- Create the default (full backup) profile
insert into backup_profiles(profile_name, backup_globals) values ('default', true);

drop table backup_ignored cascade;
create table backup_ignored (
    profile_name    text    constraint fk_backup_ignored_profile_name references backup_profiles
                            on delete cascade,
    db_name         text    not null,
        constraint pk_backup_ignored primary key (profile_name, db_name)
);

drop table backup_included cascade;
create table backup_included (
    profile_name    text    constraint fk_backup_included_profile_name references backup_profiles
                            on delete cascade
                            -- The default profile is used for full backups unless
                            -- the database is expressly ignored.
                            constraint ck_backup_included_profile_name
                                check (trim(profile_name) &lt;&gt; 'default'),
    db_name         text    not null,
        constraint pk_backup_included primary key (profile_name, db_name)
);
</pre>
<b><font style="font-size: 1.25em;">The Support Functions</font></b><br /><font style="font-size: 1.25em;"><font style="font-size: 0.8em;"><blockquote>These are the support functions:</blockquote></font></font>
<pre class='brush: sql'>
-- Pg backups functions
--

create or replace function get_all_dbs() returns setof text as
$$
    select quote_ident(datname) as d
    from pg_database
    where not datistemplate;
$$ language sql;

create or replace function ignore_db(v_pname text, v_db text) returns boolean as
$$
begin
    insert into backup_ignored(profile_name, db_name) values (v_pname, v_db);
    return found;
end;
$$ language plpgsql volatile;

create or replace function include_db(v_pname text, v_db text) returns boolean as
$$
begin
    insert into backup_included(profile_name, db_name) values (v_pname, v_db);
    return found;
end;
$$ language plpgsql volatile;

create or replace function add_trailing_slash(text) returns text as
$$
    select case when substr($1, length($1)) = E'/' then $1 else $1 || E'/' end;
$$ language sql immutable;

create or replace function add_profile(
    v_pname text, v_destdir text, v_bindir text,
    v_bkglobals boolean default false) returns boolean as
$$
begin
    insert into backup_profiles(profile_name, dest_directory, bin_directory, backup_globals)
        values(v_pname, v_destdir, v_bindir, v_bkglobals);
    return found;
end;
$$ language plpgsql volatile;

create or replace function fixup_profiles() returns trigger as
$$
begin
    new.profile_name := lower(new.profile_name);
    new.dest_directory := add_trailing_slash(new.dest_directory);
    new.bin_directory := add_trailing_slash(new.bin_directory);
    return new;
end;
$$ language plpgsql;

create or replace function fixup_profile_name() returns trigger as
$$
begin
    new.profile_name := lower(new.profile_name);
    return new;
end;
$$ language plpgsql;

create trigger trg_excluded_fixup_profile_name before insert or update on backup_ignored
for each row execute procedure fixup_profile_name();

create trigger trg_included_fixup_profile_name before insert or update on backup_included
for each row execute procedure fixup_profile_name();

create trigger trg_profile_fixups before insert or update on backup_profiles
for each row execute procedure fixup_profiles();
</pre>
<b><font style="font-size: 1.25em;">The Workhorse Function<br /></font></b><blockquote>This is the workhorse function.  I apologize for the pathetic word-wrapping.  It will be easier if you view the source directly.</blockquote>
<pre class='brush: sql'>
create or replace function pg_backups(v_pname text default 'default') returns setof text as
$$
declare
    p backup_profiles%rowtype;
    i backup_included%rowtype;
    included_count integer;
    query_str text;

begin
    -- Determine if the profile exists
    select * into p from backup_profiles where profile_name = v_pname;
    if not found then
        raise exception 'Invalid profile: %', v_pname;
    end if;

    -- Determine if the profile specifies individual databases
    select count(*) into included_count from backup_included where profile_name = v_pname;

    -- If the default profile is specified or if the profile doesn't specify any databases
    -- include all the databases except those explicitly ignored.
    -- This is the model part of MVC
    if (v_pname = 'default' or included_count = 0) then
        query_str :=        'with dbs as (
            select * from get_all_dbs() as d
            except
            select db_name from backup_ignored where profile_name = ' ||   
                  quote_literal(v_pname) || ') ';
    else
        -- Otherwise grab only those databases specified in the profile
        query_str :=
        'with dbs as (
            select db_name as d from backup_included where profile_name = ' || 
            quote_literal(v_pname) || ') ';
    end if;
    
    -- Do this here to avoid the headache of an additional quote_literal below
    p.bin_directory := coalesce(p.bin_directory, '');
    
    -- Append the view part of the MVC equation
    query_str := query_str ||
        'select ' || quote_literal(p.bin_directory || 'pg_dump -U postgres -Fc --file=' ||
        p.dest_directory) || ' || d  || ' || 
        'to_char(now(), ' || quote_literal('-YYYYMMDD-HH24MISS') || ') || ' || 
        quote_literal('.pgbackup ')  || ' || d ' ||      
        'from dbs
        union
        select ' || quote_literal(p.bin_directory || 'pg_dumpall -g -U postgres --file=' || p.dest_directory ||         
'globals') || ' || ' ||
            'to_char(now(), ' || quote_literal('-YYYYMMDD-HH24MISS') || ') || ' || quote_literal('.pgbackup ')  || ' '  ||
        'where ' || quote_literal(p.backup_globals) || ' = true';
    return query execute query_str;
end;
$$ language plpgsql volatile;
</pre>
<b><font style="font-size: 1.25em;">Ancillary Functionality</font></b><br /><blockquote>I wanted to add some error checking to each database as it was backed-up.  To accomplish that without modifying anything in the configuration, I wrote a very simple filter in Perl:<br /></blockquote>
<pre class='brush: perl'>
#!/usr/bin/perl

# Simple example of a filter to provide more feedback
# on the status of Postgres backups using the MVC method.

my $prepend = undef;
my $append_template = &lt;&lt;apt;
2&gt; /dev/null || echo &quot;Postgres database backup of %D FAILED (rc = ${?})&quot;
apt

while (&lt;&gt;) {
    chomp(my $append = $append_template);
    # This depends on having &quot;globals&quot; in the pg_dump output
    ($dbname) = /globals/ ? &quot;globals&quot; : $_ =~ /\s+(\w+)$/;
    $append =~ s/%D/$dbname/;
    s/^/$prepend / if defined($prepend);
    s/$/ $append/ if defined($append_template);
    print;
}
</pre>
<b><font style="font-size: 1.25em;">The Controller Portion</font></b><br /><blockquote>Finally, this is what actually executes the backup process.  This is an example of how to call it from cron in a recent Linux distribution (please be aware of the possible odd word-wrapping):</blockquote>
<pre class='brush: plain'>
# /etc/cron.d/postgres: crontab fragment for Postgres backups
# Backup PostgreSQL databases
MAILTO=postgres
50 23  * * *  postgres  /usr/bin/psql --variable=profile=&quot;'default'&quot; -Aqtf /home/admin/bin/pg-backups.sql 2&gt; /dev/null | /home/admin/bin/pg-backups-filter | sh
</pre>
The psql utility is one of the most capable and useful database administration utilities with which I've ever had the pleasure of working.  The key to making this system work is the ability to pass a parameter to the function that is called by psql (listed below).<br /><br />
<b><font style="font-size: 1.25em;">The Simple SQL Script</font></b><br /><blockquote>This is, for the purposes of this discussion, the contents of /home/admin/bin/pg-backups.sql:</blockquote>
<pre class='brush: sql'>
select * from pg_backups(:profile);
</pre>
That's all folks!]]>
        
    </content>
</entry>

<entry>
    <title>Obama, The Snob And Your Lizard Brain</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2010/10/obama-the-snob-and-your-lizard-brain.html" />
    <id>tag:garychambers.com,2010:/nq//1.66</id>

    <published>2010-10-21T02:11:24Z</published>
    <updated>2010-10-21T02:23:30Z</updated>

    <summary><![CDATA[For those of you foolish enough to have voted for the arrogant, narcissist-in-chief, Barack Hussein Obama, are you sorry yet?&nbsp; You should be.&nbsp; Worst.&nbsp; President.&nbsp; Ever!&nbsp; ...but I digress.There are some places that I just never consider when I am...]]></summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="liberalism" label="liberalism" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="moralbankruptcy" label="moral bankruptcy" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="politics" label="politics" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[For those of you foolish enough to have voted for the arrogant, narcissist-in-chief, Barack Hussein Obama, are you sorry yet?&nbsp; You should be.&nbsp; <b>Worst.&nbsp; President.&nbsp; Ever!</b>&nbsp; ...but I digress.<br /><br />There are some places that I just never consider when I am searching for quality, accurate, unbiased news:&nbsp; ABC, CBS, CNN, NBC, NECN, PBS, The Boston Globe, The Los Angeles Times, The New York Times, The Washington Post, to name just a few.&nbsp; Imagine my surprise, however, when I read <a href="http://www.washingtonpost.com/wp-dyn/content/article/2010/10/18/AR2010101803778_pf.html">this Michael Gerson article</a> on the Washinton Post's web site!<br /><br />Hat tip: Kevin H.<br /> ]]>
        
    </content>
</entry>

<entry>
    <title>Remember In November</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2010/10/remember-in-november.html" />
    <id>tag:garychambers.com,2010:/nq//1.65</id>

    <published>2010-10-19T02:46:44Z</published>
    <updated>2010-10-19T02:48:26Z</updated>

    <summary></summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="politics" label="politics" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[<object width="640" height="390"><param name="movie" value="http://www.youtube.com/v/3APuNTmqbDY&hl=en_US&feature=player_embedded&version=3"></param><param name="allowFullScreen" value="true"></param><param name="allowScriptAccess" value="always"></param><embed src="http://www.youtube.com/v/3APuNTmqbDY&hl=en_US&feature=player_embedded&version=3" type="application/x-shockwave-flash" allowfullscreen="true" allowScriptAccess="always" width="640" height="390"></embed></object>]]>
        
    </content>
</entry>

<entry>
    <title>Elections Matter</title>
    <link rel="alternate" type="text/html" href="http://www.garychambers.com/nq/2010/10/elections-matter.html" />
    <id>tag:garychambers.com,2010:/nq//1.64</id>

    <published>2010-10-17T19:20:58Z</published>
    <updated>2010-10-17T19:21:35Z</updated>

    <summary> You Cannot! from RightChange on Vimeo....</summary>
    <author>
        <name>Gary Chambers</name>
        <uri>http://www.garychambers.com/</uri>
    </author>
    
    <category term="politics" label="politics" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://www.garychambers.com/nq/">
        <![CDATA[ <iframe src="http://player.vimeo.com/video/15228949" width="400" height="225" frameborder="0"></iframe><p><a href="http://vimeo.com/15228949">You Cannot!</a> from <a href="http://vimeo.com/user3849600">RightChange</a> on <a href="http://vimeo.com">Vimeo</a>.</p>]]>
        
    </content>
</entry>

</feed>

