<rss 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/" version="2.0">
<channel>
  <title>Derek Arnold</title>
  <atom:link href="http://derekarnold.net/rss" rel="self"
    type="application/rss+xml" />
  <link>http://derekarnold.net</link>
  <description></description>
  <language>en</language>
  <sy:updatePeriod>hourly</sy:updatePeriod>
  <sy:updateFrequency>1</sy:updateFrequency>
  <generator>http://github.com/lysol/derekarnold.net</generator>
  
  
    <item>
    <title>Deploying a single page portfolio page with Wordpress and the Bootstrap Framework</title>
    <link>http://derekarnold.net/post/ruaarnold</link>
    <guid isPermaLink="true">http://derekarnold.net/post/ruaarnold</guid>
    <pubDate>Sun, 04 Dec 2011 21:12:00 +0000</pubDate>
    <dc:creator>Derek Arnold</dc:creator>
    
    
      <category>
        <![CDATA[php]]>
      </category>
    
      <category>
        <![CDATA[wordpress]]>
      </category>
    
      <category>
        <![CDATA[portfolio]]>
      </category>
    
      <category>
        <![CDATA[bootstrap]]>
      </category>
    
      <category>
        <![CDATA[rua]]>
      </category>
    
    
    <description>
      <![CDATA[
        <p>We recently moved to Des Moines, Iowa and <a href="http://ruaarnold.com">my wife</a> has
been job hunting. She's had a portfolio online using
<a href="http://www.behance.net/prosite">Behance ProSite</a>, and the predefined
templates are visually good. But if you really need to curate your content, they
don't offer any options for real markup, and you have to really fight the
admin panel to make it look good. </p>

<p>My wife was really stuck on the idea of a single page site with a static
header for navig...
      ]]>
    </description>
    <content:encoded>
      <![CDATA[
        <p>We recently moved to Des Moines, Iowa and <a href="http://ruaarnold.com">my wife</a> has
been job hunting. She's had a portfolio online using
<a href="http://www.behance.net/prosite">Behance ProSite</a>, and the predefined
templates are visually good. But if you really need to curate your content, they
don't offer any options for real markup, and you have to really fight the
admin panel to make it look good. </p>

<p>My wife was really stuck on the idea of a single page site with a static
header for navigation to each section. If you're thinking about doing this,
just use <a href="http://twitter.github.com/bootstrap/">Bootstrap</a>. Their
implementation of a Scroll Spy plugin is the easiest to implement that I've
seen and like most grid frameworks it eliminates all the repeated word of
setting up the page as fluid, non-fluid, multiple columns, etc. It's really a
bit of overkill for a simpler site like this, but still pretty effective.</p>

<p>Also a bit of overkill is Wordpress to managing the content. All it's really
being used is for adding posts with images to query in the template. No posts
are actually being used and the blog isn't even rendered.</p>

<p>The actual portfolio section of the page is a custom JS slider I wrote from
scratch. I opted for multiple sliders using a single viewport. Sections on the
right are automatically created from posts with a given category, using
attached images. Images are automatically resized to fit the slider and pop
out into a lightbox.</p>

<p>The code's pretty sloppy and the server side portions are just in the template
files and functions.php. At any rate, I have it <a href="http://github.com/lysol/Rua">hosted</a>
at Github and it might serve as a good example of something like this for
someone else.</p>

<p>See my wife's site at <a href="http://ruaarnold.com">ruaarnold.com</a> and
<a href="http://twitter.com/ruaarnold">follow her on twitter</a>.</p>
      ]]>
    </content:encoded>
    </item>
  
    <item>
    <title>Hooch</title>
    <link>http://derekarnold.net/post/hooch</link>
    <guid isPermaLink="true">http://derekarnold.net/post/hooch</guid>
    <pubDate>Mon, 28 Nov 2011 21:55:00 +0000</pubDate>
    <dc:creator>Derek Arnold</dc:creator>
    
    
      <category>
        <![CDATA[php]]>
      </category>
    
    
    <description>
      <![CDATA[
        <p>I wrote a microframework for PHP a while back because other PHP frameworks are
usually too big and clumsy, and using vanilla PHP is obviously an excercise in
pain sooner or later.</p>

<p>I've decided to throw it up on Github, and called it <a href="http://github.com/lysol/Hooch">Hooch</a>.</p>

<p>Here's the basic usage:</p>

<pre><code>require_once 'Twig/Autoloader.php';
require_once 'hooch.php';

Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem('templates');
$twig = new Twig_Environmen...
      ]]>
    </description>
    <content:encoded>
      <![CDATA[
        <p>I wrote a microframework for PHP a while back because other PHP frameworks are
usually too big and clumsy, and using vanilla PHP is obviously an excercise in
pain sooner or later.</p>

<p>I've decided to throw it up on Github, and called it <a href="http://github.com/lysol/Hooch">Hooch</a>.</p>

<p>Here's the basic usage:</p>

<pre><code>require_once 'Twig/Autoloader.php';
require_once 'hooch.php';

Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem('templates');
$twig = new Twig_Environment($loader, array('debug' =&gt; true,
    'strict_variables' =&gt; true));

// Assuming ../ is a non-publicly accessible path,
// put your DB info there.
$config = parse_ini_file("../config.ini", false);

// Instantiate the App class. Handles path routing and such.
$app = new App(true);

// Retrieve the base URL path from the config file.
// You must set this if you want anything to work at all.
// basePath should be equal to the base path of the URL.
// For example, if it's http://127.0.0.1/~test/, set basePath to
// /~test/
$app-&gt;basePath = $config['basePath'];

// These are things we will use in every template, more or less.
$twig-&gt;addGlobal('basePath', $basePath);

// Use a Preprocessor to implement authentication, etc.
// This is a bad example, but you get it. You're smart.
class AuthProcessor extends Preprocessor {
    public function test($path) {
        global $authenticated;
        return $authenticated;
    }
}
// If you're not using a preprocessor, omit this line.
$app-&gt;preprocess(new AuthProcessor());


// Handle the home page. True anonymous functions require
// PHP 5.3.0 and above.

$app-&gt;get('/', function($args) use ($twig) {
    $template = $twig-&gt;loadTemplate('home.html');
    return $template-&gt;render(array('someVal' =&gt; true));
});
// Look, even PHP can have moustaches!


// If you're on an older version of PHP:
function second_page($args) {
    global $twig;
    $template = $twig-&gt;loadTemplate('person.html');
    return $template-&gt;render(array('person' =&gt; $args['name']));
}

$app-&gt;get('/person/:name', second_page);

// Handle POST requests
// Here's an example of a redirect as well.
$app-&gt;post('/save', function ($args) use ($twig, $app) {
    if (isset($_POST['name'])) {
        $app-&gt;seeother('/person/' + $_POST['name']);
    } else {
        // Throw a 404.
        $app-&gt;notFound();
    }
});

// Need to return some JSON for an AJAX call?

$app-&gt;post('/saveAJAX', function ($args) use ($app) {
    return $app-&gt;apiSimple(function() use ($args) {
        return array(
            'test' =&gt; 1,
            'another-test' =&gt; 2
            );
    });
});


// And the thing that makes it all happen:
$app-&gt;serve();
</code></pre>

<p>You'll also need an .htaccess to redirect everything to your index.php file.
This one works:</p>

<pre><code>RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
</code></pre>
      ]]>
    </content:encoded>
    </item>
  
    <item>
    <title>typeto.me</title>
    <link>http://derekarnold.net/post/typeto-me</link>
    <guid isPermaLink="true">http://derekarnold.net/post/typeto-me</guid>
    <pubDate>Tue, 23 Aug 2011 10:52:00 +0000</pubDate>
    <dc:creator>Derek Arnold</dc:creator>
    
    
      <category>
        <![CDATA[nodejs]]>
      </category>
    
      <category>
        <![CDATA[socketio]]>
      </category>
    
      <category>
        <![CDATA[coffeescript]]>
      </category>
    
    
    <description>
      <![CDATA[
        <p><a href="http://3e.org/dmd/">Daniel Drucker</a> insisted that there should be a web
version of <a href="http://linux.die.net/man/1/talk">talk</a>, so we made something
like it. <a href="http://typeto.me">typeto.me</a> is built with <a href="http://nodejs.org">Node.js</a>,
<a href="http://jashkenas.github.com/coffee-script/">Coffeescript</a>, <a href="http://socket.io/">socket.io</a>,
and works in most modern browsers.</p>

<p>Daniel also <a href="http://news.ycombinator.com/item?id=2916453">posted</a> it ...
      ]]>
    </description>
    <content:encoded>
      <![CDATA[
        <p><a href="http://3e.org/dmd/">Daniel Drucker</a> insisted that there should be a web
version of <a href="http://linux.die.net/man/1/talk">talk</a>, so we made something
like it. <a href="http://typeto.me">typeto.me</a> is built with <a href="http://nodejs.org">Node.js</a>,
<a href="http://jashkenas.github.com/coffee-script/">Coffeescript</a>, <a href="http://socket.io/">socket.io</a>,
and works in most modern browsers.</p>

<p>Daniel also <a href="http://news.ycombinator.com/item?id=2916453">posted</a> it to Hacker News,
so go vote it up!</p>
      ]]>
    </content:encoded>
    </item>
  
    <item>
    <title>dqprintf</title>
    <link>http://derekarnold.net/post/dqprintf</link>
    <guid isPermaLink="true">http://derekarnold.net/post/dqprintf</guid>
    <pubDate>Tue, 26 Jul 2011 10:47:00 +0000</pubDate>
    <dc:creator>Derek Arnold</dc:creator>
    
    
      <category>
        <![CDATA[postgres]]>
      </category>
    
    
    <description>
      <![CDATA[
        <p>Part of my job involves performing data transformations using tables loaded via
CSVs, which themselves were created from tab-delimited reports. Nasty.</p>

<p>Making something usable out of these involves a nice handful of PL/PGSQL
functions. These functions involve arguments specifying table names and other
values that are used to build dynamic queries that either perform
<code>INSERT ... SELECT FROM</code>, or loop through result sets because the reports
require some amount of contextual processing befo...
      ]]>
    </description>
    <content:encoded>
      <![CDATA[
        <p>Part of my job involves performing data transformations using tables loaded via
CSVs, which themselves were created from tab-delimited reports. Nasty.</p>

<p>Making something usable out of these involves a nice handful of PL/PGSQL
functions. These functions involve arguments specifying table names and other
values that are used to build dynamic queries that either perform
<code>INSERT ... SELECT FROM</code>, or loop through result sets because the reports
require some amount of contextual processing before performing an <code>INSERT</code>.
Blech.</p>

<p>The two main functions that make this all possible are <code>quote_ident</code> and
<code>quote_literal</code>. They ensure you're not just blindly concatenating illegal
identifier names into your queries. Please don't just type in
<code>" || table_name || "</code>. It hurts.</p>

<p>Unfortunately, your function will inevitably end up looking a little like this:</p>

<pre><code>iQuery := $Q$
    SELECT
        $Q$ || quote_ident(some_column) || $Q$ || $Q$ ||
            quote_literal(some_value) || $Q$ || '-1'
    FROM $Q$ || quote_ident(some_table) || $Q$
    WHERE another_column = $Q$ || quote_literal(another_value) || $Q$
$Q$;

FOR mRow IN EXECUTE iQuery
LOOP
...
</code></pre>

<p>Gross, but this isn't a new problem, so here's a simple solution.</p>

<p>I adapted <a href="http://wiki.postgresql.org/wiki/Sprintf Sprintf">this function</a> a
bit to make <code>dqprintf</code>, a simple <code>sprintf</code>-like function to create dynamic
queries:</p>

<pre><code>CREATE OR REPLACE FUNCTION dqprintf(fmt text, VARIADIC args anyarray)
RETURNS text
LANGUAGE PLPGSQL AS $$
DECLARE
        argcnt int = 1;
        chrcnt int = 0;
        fmtlen int;
        CHR text;
        NEXT_CHR text;
        output text = '';
        curarg text;

BEGIN
        fmtlen = LENGTH(fmt);
        LOOP
                chrcnt = chrcnt + 1;

                -- ran out of format string? bail out
                IF chrcnt &gt; fmtlen THEN
                        EXIT;
                END IF;

                -- grab our char
                CHR = substring(fmt, chrcnt, 1);
                NEXT_CHR = substring(fmt, chrcnt + 1, 1);

                -- %% means output a single %, and skip them
                IF CHR = '%' AND substring(fmt, chrcnt + 1, 1) = '%' THEN
                        output = output || '%';
                        chrcnt = chrcnt + 1;
                        continue;
            END IF;

                -- %i means we're going to quote an identifier
                -- %l means we're going to quote a literal
                -- %s is anything else. Not exactly a printf format.
                IF CHR = '%' THEN
                        curarg := COALESCE(args[argcnt]::text, '');

                        IF NEXT_CHR = 'i' THEN
                            curarg := quote_ident(curarg);
                        ELSIF NEXT_CHR = 'l' THEN
                            curarg := quote_literal(curarg);
                        ELSIF NEXT_CHR &lt;&gt; 's' THEN
                            -- improper format identifier
                            RAISE EXCEPTION 'Incorrect format identifier: %', NEXT_CHR;
                        END IF;

                        output = output || curarg;
                        argcnt = argcnt + 1;
                        chrcnt = chrcnt + 1;
                        CONTINUE;

                END IF;

                -- no special case? output the thing
                output = output || CHR;
        END LOOP;

        RETURN output;
END;
$$;
</code></pre>

<p>This will turn the above pipe character mess into something a bit more manageable:</p>

<pre><code>iQuery := $Q$
    SELECT
        %i || %l || '-1'
    FROM %i
    WHERE another_column = %l
$Q$;
FOR mRow IN EXECUTE dqprintf(iQuery, some_column, some_value,
    some_table, another_value)
LOOP
...
</code></pre>

<p>A couple of notes. First, every argument needs to be cast to the same type,
preferably <code>text</code>. If you're using this in a PL/PGSQL function, you most likely
have this covered if these are typed arguments to the function already.</p>

<p>Secondly, error handling isn't terribly robust, so debugging it might be
clumsy. You're already used to that, though, if you're writing PL/PGSQL
functions.</p>
      ]]>
    </content:encoded>
    </item>
  
    <item>
    <title>On DML Logging</title>
    <link>http://derekarnold.net/post/on-DML-logging</link>
    <guid isPermaLink="true">http://derekarnold.net/post/on-DML-logging</guid>
    <pubDate>Sun, 24 Jul 2011 08:21:00 +0000</pubDate>
    <dc:creator>Derek Arnold</dc:creator>
    
    
      <category>
        <![CDATA[postgres]]>
      </category>
    
    
    <description>
      <![CDATA[
        <p>If your shop is like ours, your devs working with PostgreSQL want to log
UPDATE, INSERT and DELETE operations by users, as a tool to analyze bugs in
your software or to audit user activities. Trigger functions immediately jump
to mind, and they are rightfully suited to the task, but bring some baggage of
their own that may give you some pause if your users or developers are
sensitive to the speed of their database queries.</p>

<p>First things first, PL/PGSQL is great. If you absolutely can't write your
f...
      ]]>
    </description>
    <content:encoded>
      <![CDATA[
        <p>If your shop is like ours, your devs working with PostgreSQL want to log
UPDATE, INSERT and DELETE operations by users, as a tool to analyze bugs in
your software or to audit user activities. Trigger functions immediately jump
to mind, and they are rightfully suited to the task, but bring some baggage of
their own that may give you some pause if your users or developers are
sensitive to the speed of their database queries.</p>

<p>First things first, PL/PGSQL is great. If you absolutely can't write your
function in plain SQL, use PL/PGSQL if you can. PL/Python is fun, very
powerful, and if you're like me, writing Python is like a Slip 'N Slide that
never ends. But for trigger functions on what could be millions of queries, it
may give you the gift of a significant performance penalty that will irritate
you for around a year before it finally prompts you to complain about it in
writing, on the Internet.</p>

<p>Unfortunately for PL/PGSQL, the trigger function's row object doesn't provide
any sort of data you can use to find out exactly <em>what</em> fields are contained
within the row object. You also can't dynamically refer to these columns in
the row variable. You have to infer this from the table you created the
trigger on, and write your function appropriately.  So, that works...if you're
logging a single table. Fast forward to writing trigger functions for 40 or
more tables and you see the dilemma.</p>

<p>So, long story made short, PL/Python trigger functions provide rows as a Dict,
and it's fairly obvious what to do with it. But then there's a performance hit.
It's not even so much the OLTP queries that drag us down as the data loading.
Like most people dealing with real data, you have to load quite a bit from time
to time, and if you're nice, you won't grab an exclusive lock on the entire
table and disable triggers just so you can bring in a few years of history.</p>

<p>You can see where this is going. Every row inserted brings you another single
INSERT to your logging table. It doesn't matter what structure you've made
for storing this log data, it's going to be painful.</p>

<p>You could include code in the trigger function to turn around and exit if it
sees a specially named session-local temporary table. This takes off some of
the hit from the INSERTs. But, you're still firing off the Python interpreter
500,000 times if you're creating 500,000 records.</p>

<p>That leaves us with some options.</p>

<ul>
<li>Write the trigger function in another PL that isn't as slow. It'll probably
still be slow.</li>
<li>Write the trigger function in C. Without putting buckshot in your own foot.</li>
<li>Write a function that writes a PL/PGSQL function. Dynamically generate a
trigger function for each table that performs the appropriate INSERTS,
per-column by effectively unlooping your FOR loop.</li>
</ul>

<p>The last one is crazy enough that it might work, but I haven't even tried to
test it yet.</p>
      ]]>
    </content:encoded>
    </item>
  
    <item>
    <title>New site</title>
    <link>http://derekarnold.net/post/new-blog</link>
    <guid isPermaLink="true">http://derekarnold.net/post/new-blog</guid>
    <pubDate>Thu, 21 Jul 2011 19:04:00 +0000</pubDate>
    <dc:creator>Derek Arnold</dc:creator>
    
    
      <category>
        <![CDATA[meta]]>
      </category>
    
      <category>
        <![CDATA[coffeescript]]>
      </category>
    
      <category>
        <![CDATA[nodejs]]>
      </category>
    
    
    <description>
      <![CDATA[
        <p>It's alive. Here's the rundown. The site's running on node.js,
written in Coffeescript, served up via Apache and mod_proxy. Posts are
statically generated from hybrid JSON/Markdown files.</p>

<p>That's it!</p>
      ]]>
    </description>
    <content:encoded>
      <![CDATA[
        <p>It's alive. Here's the rundown. The site's running on node.js,
written in Coffeescript, served up via Apache and mod_proxy. Posts are
statically generated from hybrid JSON/Markdown files.</p>

<p>That's it!</p>
      ]]>
    </content:encoded>
    </item>
  
  
</channel>
</rss>

