<?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>CUPPSTER.COM</title>
	<atom:link href="http://cuppster.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://cuppster.com</link>
	<description>Programmer at Large in Small Batches</description>
	<lastBuildDate>Wed, 12 Jun 2013 00:37:43 +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>If you see it&#8230;</title>
		<link>http://cuppster.com/2013/04/03/if-you-see-it/</link>
		<comments>http://cuppster.com/2013/04/03/if-you-see-it/#comments</comments>
		<pubDate>Wed, 03 Apr 2013 22:58:51 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://cuppster.com/?p=1909</guid>
		<description><![CDATA[If you see it, you&#8217;ll #### bricks. The things programmers make users deal with&#8230;]]></description>
				<content:encoded><![CDATA[<p>If you see it, you&#8217;ll #### bricks. The things programmers make users deal with&#8230;</p>
<p><a href="http://cuppster.com/wp-content/uploads/2013/04/badmenu.png"><img src="http://cuppster.com/wp-content/uploads/2013/04/badmenu.png" alt="badmenu" width="219" height="62" class="aligncenter size-full wp-image-1908" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://cuppster.com/2013/04/03/if-you-see-it/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Serving Images with MongoDB, GridFS and Flask</title>
		<link>http://cuppster.com/2013/03/12/serving-images-with-mongodb-gridfs-and-flask/</link>
		<comments>http://cuppster.com/2013/03/12/serving-images-with-mongodb-gridfs-and-flask/#comments</comments>
		<pubDate>Tue, 12 Mar 2013 21:30:52 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Recipe]]></category>
		<category><![CDATA[Flask]]></category>
		<category><![CDATA[GridFS]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[PIL]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[Requests]]></category>

		<guid isPermaLink="false">http://cuppster.com/?p=1891</guid>
		<description><![CDATA[Recently, I&#8217;ve had the pleasure of accumulating over 1 million thumbnail and preview images on my drive. I like having as many files on my disk as the next guy, but I thought since I&#8217;m using MongoDB anyway, why not use GridFS to store the images! The trick was to fetch an image at a [...]]]></description>
				<content:encoded><![CDATA[<p>Recently, I&#8217;ve had the pleasure of accumulating over 1 million <em>thumbnail</em> and <em>preview</em> images on my drive. I like having as many files on my disk as the next guy, but I thought since I&#8217;m using MongoDB anyway, why not use GridFS to store the images!</p>
<p>The trick was to fetch an image at a URL, save it into GridFS, then be able to serve it back out &#8211; all without temp files or creating individual files for every image. Here&#8217;s a recipe that does it all!</p>
<p><span id="more-1891"></span></p>
<p>I didn&#8217;t have much luck using the plain StringIO class and it&#8217;s tricky to get the right interfaces working together &#8211; some stream readers are more demanding than others&#8230;</p>
<script src="https://gist.github.com/5145500.js"></script><noscript><pre><code class="language-python python">#!/usr/bin/env python
# -*- coding: utf-8 -*-
&quot;&quot;&quot;
SYNOPSIS

    flask_gridfs_images.py --start
    flask_gridfs_images.py --add &lt;IMAGE_URL&gt;
    
DESCRIPTION

    Use the --add option to download and insert an image into a mongo gridfs
    collection. Use the --start option to start a Flask application that can
    serve images at the url /example_image.jpg.    
    
AUTHOR

    Jason Cupp &lt;jason at cuppster.com&gt;
    
LICENSE
    
    Public Domain

&quot;&quot;&quot;

from flask import Flask, send_file

import argparse
import cStringIO
import mimetypes
import requests
from PIL import Image

from pymongo import Connection
import gridfs


# setup mongo
MONGODB_HOST = 'localhost'
MONGODB_PORT = 27017

# connect to the database &amp; get a gridfs handle
mongo_con = Connection(MONGODB_HOST, MONGODB_PORT)
grid_fs = gridfs.GridFS(mongo_con.test_database)


def serve_pil_image(pil_img):
    &quot;&quot;&quot;
    see: 
        https://groups.google.com/forum/?fromgroups=#!topic/python-tornado/B19D6ll_uZE
        http://stackoverflow.com/questions/7877282/how-to-send-image-generated-by-pil-to-browser
    &quot;&quot;&quot;
    img_io = cStringIO.StringIO() 
    pil_img.save(img_io, 'JPEG', quality=70)
    img_io.seek(0)
    return send_file(img_io, mimetype='image/jpeg')
    
    
def add_image(image_url):
    &quot;&quot;&quot;add an image to mongo's gridfs&quot;&quot;&quot;
        
    # gridfs filename
    gridfs_filename = 'example_image.jpg'        
   
    # guess the mimetype and request the image resource
    mime_type = mimetypes.guess_type(image_url)[0]        
    r = requests.get(image_url, stream=True)
 
    # insert the resource into gridfs using the raw stream
    _id = grid_fs.put(r.raw, contentType=mime_type, filename=gridfs_filename)
    print &quot;created new gridfs file {0} with id {1}&quot;.format(gridfs_filename, _id)


def start():
    &quot;&quot;&quot;start the flask service&quot;&quot;&quot;
    
    # create app
    app = Flask(__name__)
    app.debug = True
    
    # our ONE route, to serve up image from gridfs
    @app.route('/image/&lt;path:filename&gt;')
    def get_image(filename):        
        &quot;&quot;&quot;retrieve an image from mongodb gridfs&quot;&quot;&quot;
        
        if not grid_fs.exists(filename=filename):
            raise Exception(&quot;mongo file does not exist! {0}&quot;.format(filename))
        
        im_stream = grid_fs.get_last_version(filename)
        im = Image.open(im_stream)
        return serve_pil_image(im)
    
    
    # let's go!
    app.run()
    

def main():
    
    # CLI
    parser = argparse.ArgumentParser()    
    parser.add_argument('--start', action='store_true', help='start the service')
    parser.add_argument('--add', help='add an image via URL')    
    args = parser.parse_args()
    
    if args.start:
        start()
    elif args.add:
        add_image(args.add)

    
if __name__ == &quot;__main__&quot;:
    main()
    </code></pre></noscript>
]]></content:encoded>
			<wfw:commentRss>http://cuppster.com/2013/03/12/serving-images-with-mongodb-gridfs-and-flask/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Backbone.js Template: API-Driven Data Tables</title>
		<link>http://cuppster.com/2013/02/23/backbone-js-template-api-driven-data-tables/</link>
		<comments>http://cuppster.com/2013/02/23/backbone-js-template-api-driven-data-tables/#comments</comments>
		<pubDate>Sat, 23 Feb 2013 06:46:33 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Front-end]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[backbone.js]]></category>
		<category><![CDATA[datatables]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[tables]]></category>

		<guid isPermaLink="false">http://cuppster.com/?p=1883</guid>
		<description><![CDATA[Here&#8217;s a gist combining Backbone.js views and routes with API-driven tables from datatables.net. HTML not included, but it should be fairly obvious what&#8217;s going on here&#8230; a simple app for browsing auction listings. &#8230; Enjoy!]]></description>
				<content:encoded><![CDATA[<p>Here&#8217;s a gist combining <a href="https://gist.github.com/cuppster/5018724">Backbone.js views and routes with API-driven tables</a> from <a href="http://datatables.net">datatables.net</a>. HTML not included, but it should be fairly obvious what&#8217;s going on here&#8230; a simple app for browsing auction listings.</p>
<p>&#8230; Enjoy!</p>
<p><span id="more-1883"></span><br />
<script src="https://gist.github.com/5018724.js"></script><noscript><pre><code class="language-javascript javascript">/*
 * Template backbone.js code that encapsulates a 
 * datatable.net table within a view for a hypothetical ;)
 * auction listings application.
 */
 
var HomeRouter = Backbone.Router.extend({
  
  routes: {
    'refresh'     : 'refresh',   
    'newest'      : 'newest', 
    'endingsoon'  : 'endingsoon',
    'recentsold'  : 'recentsold', 
  },
    
});


var HomeView = Backbone.View.extend({
  
  // our default table view
  'present' : 'newest',
  
  'router' : new HomeRouter(),
  
  'events': {
    
    // users can enter a keyword,
    // but the table will only refresh after
    // the user can laid off the keys for 500ms
    'keyup #searchbox': _.debounce(function() {
      this.refresh();   
    }, 500 /* ms delay until taking real action */),
    
  },
  
  'newest': function() {
    this.present = 'newest';
    this.refresh();
  },
  
  'endingsoon': function() {
    this.present = 'endingsoon';
    this.refresh();   
  },
  
  'recentsold': function() {    
    this.present = 'recentsold';
    this.refresh();       
  },
  
  'refresh': function() {
    this.table.fnReloadAjax();    
  },

  
  'initialize': function() {
    
    var view = this;
    
    // setup routes
    //
    view.router.on('route:refresh', function() {      
      view.refresh();     
    });
    view.router.on('route:newest', function() {     
      view.newest();      
    });
    view.router.on('route:endingsoon', function() {     
      view.endingsoon();      
    });
    view.router.on('route:recentsold', function() {     
      view.recentsold();      
    });

    // setup table
    //
    view.table = $('#example').dataTable({
      &quot;bProcessing&quot;: true,
      &quot;bServerSide&quot;: true,
      &quot;sAjaxSource&quot;: &quot;/api/data&quot;,
  
      // override this, we supply our own keyword inputbox
      &quot;sDom&quot;       : 'p&lt;&quot;#toolbar&quot;&gt;rtp',
  
      &quot;aoColumns&quot;: [

        /* table declarations */

      ],
      
      &quot;fnServerParams&quot;: function (aoData) {
        // before sending the request for data
        // we'll add our custom parameters for 'present' and 'keyword'
        if (view.present) {
          aoData.push( { &quot;name&quot;: &quot;present&quot;, &quot;value&quot;: view.present } );
        }
        aoData.push( { &quot;name&quot;: &quot;keyword&quot;, &quot;value&quot;: $('#searchbox').val() } );
      },      
    });   
  },  
});

/**
 * reload ajax plugin - available at http://datatables.net/plug-ins/api#fnReloadAjax
 */
$.fn.dataTableExt.oApi.fnReloadAjax = function ( oSettings, sNewSource, fnCallback, bStandingRedraw )
{

  if ( typeof sNewSource != 'undefined' &amp;&amp; sNewSource != null ) {
    oSettings.sAjaxSource = sNewSource;
  }
 
  // Server-side processing should just call fnDraw
  if ( oSettings.oFeatures.bServerSide ) {
    this.fnDraw();
    return;
  }
 
  this.oApi._fnProcessingDisplay( oSettings, true );
  var that = this;
  var iStart = oSettings._iDisplayStart;
  var aData = [];
  
  this.oApi._fnServerParams( oSettings, aData );
    
  oSettings.fnServerData.call( oSettings.oInstance, oSettings.sAjaxSource, aData, function(json) {
    /* Clear the old information from the table */
    that.oApi._fnClearTable( oSettings );
      
    /* Got the data - add it to the table */
    var aData =  (oSettings.sAjaxDataProp !== &quot;&quot;) ?
      that.oApi._fnGetObjectDataFn( oSettings.sAjaxDataProp )( json ) : json;
      
    for ( var i=0 ; i&lt;aData.length ; i++ )
    {
      that.oApi._fnAddData( oSettings, aData[i] );
    }
      
    oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
      
    if ( typeof bStandingRedraw != 'undefined' &amp;&amp; bStandingRedraw === true )
    {
      oSettings._iDisplayStart = iStart;
      that.fnDraw( false );
    }
    else
    {
      that.fnDraw();
    }
      
    that.oApi._fnProcessingDisplay( oSettings, false );
      
    /* Callback user function - for event handlers etc */
    if ( typeof fnCallback == 'function' &amp;&amp; fnCallback != null )
    {
      fnCallback( oSettings );
    }
  }, oSettings );
};

/*
 * create the app view and start the browser history
 */
$(document).ready(function() {
    
  // app view
  new HomeView({el: $('body')});
  
  // get this party started
  Backbone.history.start();

} );
</code></pre></noscript></p>
]]></content:encoded>
			<wfw:commentRss>http://cuppster.com/2013/02/23/backbone-js-template-api-driven-data-tables/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Decorators, Scrapers and Generators</title>
		<link>http://cuppster.com/2013/01/30/decorators-scrapers-and-generators/</link>
		<comments>http://cuppster.com/2013/01/30/decorators-scrapers-and-generators/#comments</comments>
		<pubDate>Wed, 30 Jan 2013 06:20:05 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Fun]]></category>
		<category><![CDATA[comics]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[scraping]]></category>

		<guid isPermaLink="false">http://cuppster.com/?p=1786</guid>
		<description><![CDATA[Whoever said scraping web pages can&#8217;t be fun never tried it using Python decorators and generators! We&#8217;ll use this mini-framework to fetch all the upcoming comic book releases from one of my favorite online comic book stores. A couple of interesting things going on here programmatically: 1) using decorators that are static methods of a [...]]]></description>
				<content:encoded><![CDATA[<p>Whoever said scraping web pages can&#8217;t be fun never tried it using Python decorators and generators! We&#8217;ll use this mini-framework to fetch all the upcoming comic book releases from one of my favorite <a href="http://mycomicshop.com">online comic book stores</a>.</p>
<p>A couple of interesting things going on here programmatically: 1) using decorators that are static methods of a class that maintains some state for the decorated operations and 2) decorating class methods that are generators &#8211; the typical decorator can&#8217;t handle a <em>yielded </em>result&#8230;</p>
<p><span id="more-1786"></span></p>
<p>Here&#8217;s a class that defines some static methods for us: <code>scrape.route</code> and <code>scrape.tag</code>. We&#8217;ll use these as decorators in another class that&#8217;s specific to our scraping task.  These decorators will declare URL patterns that our decorated methods will handle when called using <code>scrape.nav()</code>.</p>
<script src="https://gist.github.com/4671004.js?file=scrape.py"></script><noscript><pre><code class="language-python python">class scrape:
  
    _scrape_routes = {}
    _scrape_tags = {}

    def __init__(self, ctx=None):
        self._ctx = ctx

    @staticmethod
    def route(route):
    
        def inner(f):
            def wrapped(*args, **kwargs):
              return f(*args, **kwargs)
            wrapped = wraps(f)(wrapped)          
            if isinstance(route, list):
                for r in route:
                    scrape._scrape_routes[r] = wrapped
            else:
                scrape._scrape_routes[route] = wrapped              
            return wrapped
        return inner
  
    @staticmethod
    def tag(self, tag):
        def inner(f):
            def wrapped(*args, **kwargs):
                return f(*args, **kwargs)
            wrapped = wraps(f)(wrapped)
            scrape._scrape_tags[tag] = wrapped
            return wrapped
        return inner
          
    def nav(self, url, tag=None):
        if tag is not None:
            for tag_i in scrape._scrape_tags.iterkeys():
                if tag == tag_i:
                    f = scrape._scrape_tags[tag]
                    d = pq(url=url)
                    return list(f(self._ctx, url, d))
                  
            return []
      
        else:
            for pat in scrape._scrape_routes.iterkeys():
                if re.search(pat, url):
                    f = scrape._scrape_routes[pat]
                    d = pq(url=url)
                    return list(f(self._ctx, url, d))
                  
            return []</code></pre></noscript>
<p>Now we&#8217;ll create a class that&#8217;s specific to our scraping task. We&#8217;ll use the <code>scrape.route</code> decorator to capture a web page for a specific URL pattern with: <code>@scrape.route('/newreleases')</code>. When we navigate to a URL patching this pattern, the class method <code>weekly</code> will be called.</p>
<script src="https://gist.github.com/4671004.js?file=comics.py"></script><noscript><pre><code class="language-python python">class NewComics:
    
    def __init__(self):
        self.pages = None
    
    @scrape.route('/newreleases')
    def weekly(self, url, d):
        
        # save the total number of pages
        if self.pages is None:
            page_links = d('#resultstab .nav-search:first-child .paginate:first-child li a')          
            last_page = pq(page_links[-1]).text()            
            self.pages = int(last_page)
        
        for el in d('div.search-results div.title'):
            yield pq(el).text()</code></pre></noscript>
<p>Notice that when <code>weekly</code> is first called, it captures the total number of pages. We&#8217;ll use this information later on subsequent round-trips.</p>
<p>Now for the main event! We instantiate <code>NewComics</code> and pass the instance to the <code>scrape</code> constructor. This instance is our context object when we call the <code>scrape.nav(<em>url</em>)</code> method. </p>
<p>When <code>nav(<em>url</em>)</code> is called and matches a route we declared with the <code>scrape.route</code> decorator, the handler <code>weekly(<em>url, d</em>)</code> is called. &#8216;<code>d</code>&#8216; is our <code>PyQuery</code> object which can be used to traverse the document.</p>
<p>Route handlers like <code>weekly</code>, can be generators or return anything that suitable for the <code>list()</code> constructor. In this example, we yield the titles of upcoming comic book releases compliments of <a href="http://mycomicshop.com">MyComicShop.com</a>. Go grab <a href="https://gist.github.com/4671155">the full source</a> at GitHub!</p>
<script src="https://gist.github.com/4671004.js?file=main.py"></script><noscript><pre><code class="language-python python">def main():    

    # setup our routes
    # saving some state when needed
    nc = NewComics()
    url = r'http://www.mycomicshop.com/newreleases?dw=0&amp;p={0}'
    
    # get a navigator with a context object
    nav = scrape(nc).nav    
    
    for title in nav(url.format('1')):
        print title
    
    if 1 &lt; nc.pages:
        for p in range(2, nc.pages + 1):
            for title in nav(url.format(p)):
                print title
    
    
if __name__ == &quot;__main__&quot;:
    main()</code></pre></noscript>
<p>TL;DR; <a href="https://gist.github.com/4671155">Go right to the Gist on GitHub</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://cuppster.com/2013/01/30/decorators-scrapers-and-generators/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Image Search Considered Hard</title>
		<link>http://cuppster.com/2013/01/29/image-search-considered-hard/</link>
		<comments>http://cuppster.com/2013/01/29/image-search-considered-hard/#comments</comments>
		<pubDate>Tue, 29 Jan 2013 03:54:48 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Images]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[images]]></category>
		<category><![CDATA[search]]></category>

		<guid isPermaLink="false">http://cuppster.com/?p=1778</guid>
		<description><![CDATA[These were my results searching for a default avatar for a Tumblr blog. Clearly &#8216;metadata&#8217; isn&#8217;t being used here, just low-level image features&#8230; Vermont, OK. But, Minnesota? Come on! It&#8217;s even more apparent that NO &#8216;metadata&#8217; is being used when Google Maps map tiles make it in the results&#8230; It&#8217;s REALLY hard to deliver relevant [...]]]></description>
				<content:encoded><![CDATA[<p>These were my results searching for a default avatar for a Tumblr blog. Clearly &#8216;metadata&#8217; isn&#8217;t being used here, just low-level image features&#8230; Vermont, OK. But, Minnesota? Come on! <img src='http://cuppster.com/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<p><a href="http://cuppster.com/wp-content/uploads/2013/01/Selection_026.png"><img class="aligncenter size-medium wp-image-1779" alt="Selection_026" src="http://cuppster.com/wp-content/uploads/2013/01/Selection_026-300x132.png" /></a></p>
<p>It&#8217;s even more apparent that NO &#8216;metadata&#8217; is being used when Google Maps map tiles make it in the results&#8230;</p>
<p><a href="http://cuppster.com/wp-content/uploads/2013/01/Selection_027.png"><img class="aligncenter size-medium wp-image-1780" alt="Selection_027" src="http://cuppster.com/wp-content/uploads/2013/01/Selection_027-300x31.png" /></a></p>
<p>It&#8217;s REALLY hard to deliver relevant images similarity results without any context&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://cuppster.com/2013/01/29/image-search-considered-hard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Updating Views with Events, Models and Rivets</title>
		<link>http://cuppster.com/2012/08/29/updating-views-with-events-models-and-rivets/</link>
		<comments>http://cuppster.com/2012/08/29/updating-views-with-events-models-and-rivets/#comments</comments>
		<pubDate>Wed, 29 Aug 2012 21:24:52 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[backbone.js]]></category>
		<category><![CDATA[binding]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[models]]></category>
		<category><![CDATA[rivets]]></category>
		<category><![CDATA[views]]></category>

		<guid isPermaLink="false">http://cuppster.com/?p=1728</guid>
		<description><![CDATA[In this Backbone.js recipe, we&#8217;re going to allow updating a view via events triggered from any sub-view. The view won&#8217;t need a refresh(), because it will be bound to model change events using Rivets. tl;dr; live demo and gist The header view below will initialize and bind a model to our view&#8217;s element using Rivets. [...]]]></description>
				<content:encoded><![CDATA[<p>In this <a href="http://backbonejs.org/">Backbone.js</a> recipe, we&#8217;re going to allow updating a view via events triggered from any sub-view. The view won&#8217;t need a refresh(), because it will be bound to model change events using <a href="http://rivetsjs.com/">Rivets</a>.</p>
<p>tl;dr; <a href="http://jsfiddle.net/cuppster/9dmb2/">live demo</a> and <a href="https://gist.github.com/3518966">gist</a></p>
<p><span id="more-1728"></span></p>
<p>The header view below will initialize and bind a model to our view&#8217;s element using Rivets. Updating the model will cause Rivets to refresh our view based on <em>data-</em> attributes in the HTML, and the updating of the model is triggered by an &#8216;updateHeader&#8217; event bound to the BODY element. This means that any sub-view can trigger updates to our header.</p>
<p><script type="text/javascript" src="https://gist.github.com/3518966.js?file=1.js"></script></p>
<p>The application view will setup event handlers on buttons so we can toggle between status states. These button click events trigger an &#8216;updateHeader&#8217; event sending new data for our model, which will bubble-up to the handler defined in the header view.</p>
<p><script type="text/javascript" src="https://gist.github.com/3518966.js?file=2.js"></script></p>
<p>The HTML contains the Rivets <em>data-</em> directives to hide and show alternative status text.</p>
<p><script src="https://gist.github.com/3518966.js?file=3.html"></script></p>
<p>See the <a href="http://jsfiddle.net/cuppster/9dmb2/">live demo</a> or browse the <a href="https://gist.github.com/3518966">gist</a>&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://cuppster.com/2012/08/29/updating-views-with-events-models-and-rivets/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Routed Commands for Backbone.js</title>
		<link>http://cuppster.com/2012/06/29/routed-commands-for-backbone-js/</link>
		<comments>http://cuppster.com/2012/06/29/routed-commands-for-backbone-js/#comments</comments>
		<pubDate>Fri, 29 Jun 2012 23:39:53 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[backbone.js]]></category>
		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://cuppster.com/?p=1693</guid>
		<description><![CDATA[Here&#8217;s a quick fiddle that shows how to route a command between sub-views no matter how they&#8217;re nested in the DOM. Basically, when a sub-view is rendered it triggers a subscribe event that&#8217;s captured by the application view which then sets a delegate on another sub-view. This other sub-view is the source of the events, [...]]]></description>
				<content:encoded><![CDATA[<p>Here&#8217;s a quick fiddle that shows how to route a <a href="http://jsfiddle.net/cuppster/vTDbR/16/">command between sub-views</a> no matter how they&#8217;re nested in the DOM. Basically, when a sub-view is rendered it triggers a subscribe event that&#8217;s captured by the application view which then sets a delegate on another sub-view. This other sub-view is the source of the events, e.g. a menu bar.</p>
<p>When the event source sub-view triggers events (e.g. clicking a link), it does so on the delegate. Event names are specified in the HTML using a <code>data-event</code> attribute on the link. <strong><em>Enjoy!</em></strong></p>
<p><span id="more-1693"></span></p>
<p>When we initialize the application view, the control (source) and subview (target) are created.</p>
<p><script src="https://gist.github.com/3364166.js?file=1.js"></script></p>
<p>The control view listens to &#8216;subscribe&#8217; events and sets the delegate subview, then responds to clicks from links with data-event attributes sending them to the delegate subview.</p>
<p><script src="https://gist.github.com/3364166.js?file=2.js"></script></p>
<p>The target view triggers a &#8216;subscribe&#8217; event, sending itself to the control for delegation and listens for those events described in the control&#8217;s view.</p>
<p><script src="https://gist.github.com/3364166.js?file=3.js"></script></p>
]]></content:encoded>
			<wfw:commentRss>http://cuppster.com/2012/06/29/routed-commands-for-backbone-js/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simple String Generator in Python</title>
		<link>http://cuppster.com/2012/04/26/simple-string-generator-in-python/</link>
		<comments>http://cuppster.com/2012/04/26/simple-string-generator-in-python/#comments</comments>
		<pubDate>Thu, 26 Apr 2012 17:44:38 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[generators]]></category>
		<category><![CDATA[patterns]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[string]]></category>

		<guid isPermaLink="false">http://cuppster.com/?p=1681</guid>
		<description><![CDATA[Here&#8217;s some handy code for generating combinations of strings in Python. Provide a string with substitution variables and a list of iterables, and poof! Output http://example.com/page/1 http://example.com/page/2 http://example.com/page/3 http://example.com/page/4]]></description>
				<content:encoded><![CDATA[<p>Here&#8217;s some handy code for generating combinations of strings in Python. Provide a string with substitution variables and a list of iterables, and poof!</p>
<p><span id="more-1681"></span></p>
<p><script src="https://gist.github.com/3364712.js?file=1.py"></script></p>
<p>Output</p>
<p>http://example.com/page/1</p>
<p>http://example.com/page/2</p>
<p>http://example.com/page/3</p>
<p>http://example.com/page/4</p>
]]></content:encoded>
			<wfw:commentRss>http://cuppster.com/2012/04/26/simple-string-generator-in-python/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CORS Middleware for Node.js and Express</title>
		<link>http://cuppster.com/2012/04/10/cors-middleware-for-node-js-and-express/</link>
		<comments>http://cuppster.com/2012/04/10/cors-middleware-for-node-js-and-express/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 18:19:38 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Gist]]></category>
		<category><![CDATA[cors]]></category>
		<category><![CDATA[gist]]></category>
		<category><![CDATA[middleware]]></category>
		<category><![CDATA[node.js]]></category>

		<guid isPermaLink="false">http://cuppster.com/?p=1672</guid>
		<description><![CDATA[Here&#8217;s a little gist of Express middleware that will add support for CORS pre-flight handling to your website or API service. Many examples found on interwebs don&#8217;t return immediately after detecting the pre-flight request, and end up issuing duplicate database queries, etc&#8230;]]></description>
				<content:encoded><![CDATA[<p>Here&#8217;s a little gist of <a href="http://expressjs.com/">Express</a> middleware that will add support for <a href="http://www.w3.org/TR/cors/">CORS</a> pre-flight handling to your website or API service. Many examples found on interwebs don&#8217;t return immediately after detecting the pre-flight request, and end up issuing duplicate database queries, etc&#8230;</p>
<p><span id="more-1672"></span></p>
<p><script src="https://gist.github.com/2344435.js"></script></p>
]]></content:encoded>
			<wfw:commentRss>http://cuppster.com/2012/04/10/cors-middleware-for-node-js-and-express/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The Input Box That Isn&#8217;t</title>
		<link>http://cuppster.com/2012/03/22/the-input-box-that-isnt/</link>
		<comments>http://cuppster.com/2012/03/22/the-input-box-that-isnt/#comments</comments>
		<pubDate>Thu, 22 Mar 2012 15:52:14 +0000</pubDate>
		<dc:creator>Jason</dc:creator>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[rant]]></category>
		<category><![CDATA[ui]]></category>
		<category><![CDATA[ux]]></category>

		<guid isPermaLink="false">http://cuppster.com/?p=1662</guid>
		<description><![CDATA[Just an Android rant. I really don&#8217;t like the Google Search widget on my Android desktop. Looks like a button, but isn&#8217;t. Why?? Also, apps that show multiple &#8212; sometimes 3 at a time &#8212; progress spinners. Ugh&#8230;]]></description>
				<content:encoded><![CDATA[<p>Just an Android rant. I really don&#8217;t like the Google Search widget on my Android desktop. Looks like a button, but isn&#8217;t. Why?? Also, apps that show multiple &#8212; sometimes 3 at a time &#8212; progress spinners. Ugh&#8230;</p>
<p><a href="http://cuppster.com/wp-content/uploads/2012/03/screenshot-1332370229789.png"><img src="http://cuppster.com/wp-content/uploads/2012/03/screenshot-1332370229789-180x300.png" alt="" title="screenshot-1332370229789" width="180" height="300" class="aligncenter size-medium wp-image-1663" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://cuppster.com/2012/03/22/the-input-box-that-isnt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
