<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title><![CDATA[Chris L Keller...]]></title>
  <link href="http://blog.chrislkeller.com/atom.xml" rel="self"/>
  <link href="http://blog.chrislkeller.com/"/>
  <updated>2014-06-26T00:00:00-07:00</updated>
  <id>http://blog.chrislkeller.com/</id>
  <author>
    <name><![CDATA[Chris Keller]]></name>
    <email><![CDATA[christopherlawrencekeller@gmail.com]]></email>
  </author>
  <generator uri="http://octopress.org/">Octopress</generator>

  
  <entry>
    <title type="html"><![CDATA[Quick script to implement 'paging' to search Twitter API for a given hashtag]]></title>
    <link href="http://blog.chrislkeller.com/quick-refactor-of-twitter-script/"/>
    <updated>2014-06-25T23:55:00-07:00</updated>
    <id>http://blog.chrislkeller.com/quick-refactor-of-twitter-script</id>
    <content type="html"><![CDATA[<p>I helped the folks at <a href="https://twitter.com/wjchat">#wjchat</a> a while back by writing a quick django app to pull tweets each week and save them to a database. The tweets were then accessible as formatted HTML that could be posted in the <a href="http://t.co/6f2jn0jP">#wjchat Wordpress blog</a>.</p>

<p>But something happened around the middle of April. The script pulled in 389 tweets on April 16, but the following week only caught 100. Same for the week after.</p>

<p>I did some hand-holding for a few weeks, but more and more of the same occurred.</p>

<blockquote class="twitter-tweet" data-partner="tweetdeck"><p><a href="https://twitter.com/hashtag/wjchat?src=hash">#wjchat</a>-transcript news: <a href="https://twitter.com/ChrisLKeller">@ChrisLKeller</a> &amp; I are aware  we’re a couple weeks behind. Pipes running the transcripts are a little clogged. Soon!</p>&mdash; P. Kim Bui (@kimbui) <a href="https://twitter.com/kimbui/statuses/480109728521924609">June 20, 2014</a></blockquote>


<script async src="http://blog.chrislkeller.com//platform.twitter.com/widgets.js" charset="utf-8"></script>


<p>The script &mdash; which was using the Tweepy library &mdash; was missing the first hour or so of tweets, and leaving the archive incomplete. Time for a refactor.</p>

<p>I&rsquo;m not blaming Tweepy but I wanted to see what else was out there. I tried making a go with requests and oauth but I don&rsquo;t think I&rsquo;m ready yet. But the <code>twitter</code> library seems to work well.</p>

<p>Tell you the truth: the library didn&rsquo;t matter. It comes down to how tweets are returned by the search API &mdash; descending order &mdash; the maximum number of results per page &mdash; 100 &mdash; and this thing called the max_id.</p>

<p>The max_id is what amounts to <a href="https://dev.twitter.com/docs/working-with-timelines">&ldquo;paging&rdquo;</a> it seems for the Twitter API.</p>

<blockquote><p>The solution to the issue described above is to use a technique for working with streams of data called cursoring. Instead of reading a timeline relative to the top of the list (which changes frequently), an application should read the timeline relative to the IDs of Tweets it has already processed. This is achieved through the use of the max_id request parameter.</p></blockquote>

<p>So the best I could get in a single search after April 16 was 100. And once I had 100 I had no means of moving on to the next page. Thankfully tonight I figured out pretty fast how the max_id parameter can work.</p>

<p>The <a href="https://gist.github.com/chrislkeller/0420fc392aebb4a2ed06#file-twitter_search-py">script</a> is based on the #wjchat script, and takes a hashtag and a search start date as arguments and outputs the results as a csv. It requires the following packages&hellip;</p>

<pre><code>    pip install python-dateutil==2.1
    pip install pytz==2013b
    pip install twitter==1.14.3
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Makin' and bakin' chicken wings]]></title>
    <link href="http://blog.chrislkeller.com/makin-and-bakin-chicken-wings/"/>
    <updated>2014-01-06T21:40:00-08:00</updated>
    <id>http://blog.chrislkeller.com/makin-and-bakin-chicken-wings</id>
    <content type="html"><![CDATA[<p><strong>Ingredients</strong></p>

<ul>
<li>&frac12; bottle of Frank&rsquo;s Red Hot Wings sauce &ndash; Buffalo</li>
<li>A glob of Barbecue sauce</li>
<li>Three shakes of A.1. Steak Sauce or similar fare</li>
<li>Four dollops of Cholula Hot Sauce.</li>
<li>Three dashes of Back of the Yards butchers rub</li>
<li>Three dashes of cayenne pepper</li>
<li>A dash of celery salt</li>
</ul>


<p><strong>Putting it all together</strong></p>

<ul>
<li>Mix the above together with a fork until it&rsquo;s a consistent sauce.</li>
<li>Butcher two pounds of chicken wings, splitting the the biceps from the forearm and discarding everything after the tendon (Tip/Nub).</li>
<li>Bake wings for 45 minutes on a cookie sheet at 450 degrees, turning over once about half way through.</li>
<li>Toss wings in the sauce.</li>
<li>Return to the oven for 15 minutes &mdash; or a broiler if you have one &mdash; or until they reach preferred sauciness.</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Cleaning out the (digital) filing cabinet]]></title>
    <link href="http://blog.chrislkeller.com/cleaning-out-the-saved-folder/"/>
    <updated>2013-09-27T12:00:00-07:00</updated>
    <id>http://blog.chrislkeller.com/cleaning-out-the-saved-folder</id>
    <content type="html"><![CDATA[<p>At home I have an entire drawer of a filing cabinet devoted to articles and essays that I printed out from websites or pulled out of magazines. As such, clipping services like Evernote and article storage software like Instapaper and Read It Later (now called Pocket) are the greatest thing ever. And for a habitual hoarder of words and ideas like myself, the worst thing ever.</p>

<p>And so I should probably get down to the job of linking to some of these things that I&rsquo;ve been holding on to in Evernote, etc. with the idea of someday offering thoughts about others&#8217; thoughts.</p>

<hr />

<p>via Charlie Kindel: <a href="http://ceklog.kindel.com/2013/01/09/dont-make-your-team-say-no-to-you/"><strong>Don’t Make Your Team Say No To You</strong></a></p>

<blockquote><p>I&rsquo;m an idea guy. Ideas come to me a mile a minute. At that point in my career I didn&rsquo;t realize how disruptive it was to my team that I was spouting these ideas to the team while they were executing on the current plan. In my head, I was just talking about potentialities for the future; by telling the team about all the cool things we could do in the future, I was showing &ldquo;vision&rdquo;.</p>

<p>What I found out later, when talking to people who had been on that team, was they viewed me as a &ldquo;randomizer&rdquo; they needed to control. In other words, the team spent time and energy MANAGING THE MANAGER. I forced them, regularly, to say &ldquo;No&rdquo; to ME.</p>

<p>If you are a leader of an early-stage venture, you need to figure out a way to &ldquo;vent&rdquo; your ideas that has NO impact on your team. Here are some tactics I&rsquo;ve used and seen others use that might help you do this.</p></blockquote>

<hr />

<p>via Erik Paulson: <a href="http://www.forwardlookout.com/2011/11/the-next-appletv-and-the-future-of-newspapers/12975"><strong>The next AppleTV, and the future of newspapers</strong></a></p>

<blockquote><p>At their core, local TV news and newspapers are fundamentally reporters. However, I believe that it would be easier for a newspaper staff to put together the content for a TV broadcast than a TV station could put together the content for an issue of a newspaper.</p></blockquote>

<hr />

<p>via Mark Surman: <a href="http://commonspace.wordpress.com/2011/09/22/mozillians-as-inventors/"><strong>Mozillians as inventors</strong></a></p>

<blockquote><p>Admittedly, we don’t know how to do this at scale yet. The recent MoJo learning lab reached only 60 people, and was too closely tied to whether one became a fellow or not. But we did catch a glimpse of what might be possible through MoJo events and discussions that happened trough the challenge cycle. The idea of inventing new web things for the newsroom galvanized people, got them sharing ideas. It had people teaching and mentoring each other even if they didn’t know it.</p></blockquote>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Link: Making decisions based on available data]]></title>
    <link href="http://blog.chrislkeller.com/link-making-decisions-based-on-available-data/"/>
    <updated>2013-09-21T12:00:00-07:00</updated>
    <id>http://blog.chrislkeller.com/link-making-decisions-based-on-available-data</id>
    <content type="html"><![CDATA[<p>via <a href="http://stdout.be/2013/08/26/cargo-cult-analytics/">Stijn Debrouwere</a></p>

<blockquote><p>Imagine your newsroom has been pumping out articles about the papal election, yet it turns out that the article readers are clicking on is one about the civil war in Syria. Thank God, you can finally stop writing about the goddamned pope because people don’t care anyway. You can commission a new piece on Syria, perhaps even tailored to people’s exact search terms so you’re not just writing about what they care about, you’re answering their questions too. I think that’s incredibly useful information to have, information you can act on, right now.</p>

<p>Except I’ve never seen a news organization that has a workflow that would allow them to routinely respond to their readers’ behavior right now. Content farms seem to be the only content producers with that capability.</p></blockquote>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Why should you be a newsroom developer? Why shouldn't you?]]></title>
    <link href="http://blog.chrislkeller.com/why-develop-in-newsroom/"/>
    <updated>2013-07-16T21:00:00-07:00</updated>
    <id>http://blog.chrislkeller.com/why-develop-in-newsroom</id>
    <content type="html"><![CDATA[<p>Back in primitive times &mdash; oh like 2007 &mdash; I kept a text file of crime and felony arrests by police departments in Chicago&rsquo;s South Suburbs.</p>

<p>In addition to serving as the assignment editor for the South Suburban edition of <a href="http://www.nwitimes.com">The Times</a>, I was the edition&rsquo;s primary crime reporter &mdash; partly out of necessity, partly out of enjoyment and partly out of the one-man-band syndrome I suffer from.</p>

<p>Each day I would add new cases, determine which cases had upcoming court hearings and update older information. Every. Day.</p>

<p>They were meticulous. And inefficient and repetitive.</p>

<p>Naive to <a href="http://www.holovaty.com/writing/fundamental-change/">guiding lights</a> out <a href="http://stdout.be/2010/04/27/the-basic-unit-of-information/">there in the world</a> that could <a href="http://palewi.re/posts/2008/06/15/terminal-recipe-how-to-download-an-entire-web-site-with-wget/">show me</a> a better method &mdash; one that would allow me to <a href="http://overview.ap.org/">glean insights</a> from this mountain of unstructured data I had collected, or at least <a href="http://pandaproject.net/">lend structure</a> to it &mdash; I did what worked.</p>

<p>To this day I think about what I could have done, and now what you &mdash; the web developer, technologist or data analyst &mdash; could do in a similar situation. Better yet, what could you do every day  in a newsroom as part of the <a href="http://mozillaopennews.org/fellowships/">Knight-Mozilla Fellowhip program</a>.</p>

<p>The short answer: solve problems and show folks new ways of dealing with repetition and inefficiencies.</p>

<p>Fact: there are <a href="http://thescoop.org/archives/2013/07/16/why-develop-in-the-newsroom/">mountains of stories, charts, graphs, news applications</a> and much more sitting with every reporter, writer and editor in every single news organization in this world. Some are mundane. But some could change the way society <a href="http://projects.propublica.org/graphics/surveillance-suits">thinks</a>, <a href="http://media.apps.chicagotribune.com/flames/index.html">lives</a> and <a href="http://guides.latimes.com/where-can-i-see-fourth-july-fireworks-la/">plays</a>.</p>

<p>Here&rsquo;s another: that information will sit there for any number of reasons, but I&rsquo;m inclined to think that lack of imagination is not one of them. There are few too people to demonstrate a better, more efficient method. Far too few people around to develop a plan. And that&rsquo;s where your <a href="http://mozillaopennews.org/fellowships/">help matters</a>.</p>

<p>I&rsquo;m kind of ashamed that my curiosity never led me to a solution that was better than adding the name of the person arrested, their date of birth, the charges against them and other information to a text file.</p>

<p>I say that because I&rsquo;ve always loved systems. Whether as a dishwasher, the newsstand manager at a Barnes &amp; Noble or in my first jobs as a journalist at newspapers in very small Wisconsin communities, to me the foundation for how the job is done was as important as doing the job itself.</p>

<p>Certainly I was oblivious to other ways. And many other journalists &mdash; who write about the inefficiencies of government or health care or the courts and then do their jobs which are part of a larger system of repetition and routine  &mdash; are as well.</p>

<p>For me, it took learning <a href="http://hackerjournalist.net/2009/10/03/a-quick-primer-on-making-software-best-practices-tools-and-further-reading/">&ldquo;what it means to be a developer&rdquo;</a>, and thanks to <a href="http://johnkeefe.net/">the helping hands</a> and <a href="https://twitter.com/onyxfish">support</a> of <a href="http://michelleminkoff.com/">others</a> &mdash; <a href="https://twitter.com/dansinker">way</a> <a href="https://twitter.com/rdmurphy">too</a> <a href="https://twitter.com/kevinschaul">many</a> <a href="https://twitter.com/stdbrouw">people</a> <a href="https://twitter.com/mattwaite">to link</a> <a href="https://twitter.com/jeremybowers">off</a> <a href="https://twitter.com/andymboyle">to</a> &mdash; I have learned lessons that are more important than any code I have written.</p>

<ul>
<li>Identify the problem you are trying to solve.</li>
<li>Do not repeat yourself.</li>
<li>Iterate, iterate, iterate according to some philosophy.</li>
<li>&ldquo;<a href="http://blog.apps.chicagotribune.com/2011/09/02/show-your-work/">Show Your Work&#8221;</a>.</li>
<li>Share your <a href="http://hackerjournalist.net/2008/08/05/dearest-journalists-stop-being-jerks-why-not-publish-the-data-too/">data</a>.</li>
</ul>


<p>These lessons have very little to do with classes, functions and syntax and everything to do with helping to reinforce the core mission of journalism: hold those in power accountable, help people make sense of the world around them and celebrate their place in it.</p>

<p>These lessons are directly applicable to the job descriptions that reporters, editors and web producers have at news organizations large and small where there are obstacles just waiting for solutions of the technical or automated variety.</p>

<p>The solutions could be as &ldquo;simple&rdquo; as <a href="http://jazzido.github.io/tabula/">extracting information from PDFs</a> in a manner that doesn&rsquo;t require four hours of copying and pasting. Maybe they are as &ldquo;complex&rdquo; as combining four or five daily processes that have been duct-taped together through <a href="http://blog.apps.chicagotribune.com/2013/02/15/using-google-docs-to-send-email/">Google spreadsheets</a>, emails, meetings and in-person conversations.</p>

<p>Or maybe there&rsquo;s simply someone out there with a bunch of text files, waiting for another way they didn&rsquo;t know they wanted.</p>

<p>Convinced? Become one of the five people who will spend 10 months combining code, data and journalism as a <a href="http://mozillaopennews.org/fellowships/">Knight-Mozilla Fellow</a>. Go and <a href="http://mozillaopennews.org/fellowships/apply.html">apply to become a 2014 fellow</a> today.</p>

<p>Not convinced? Then read what these folks &mdash; to whom I offer eternal thank yous &mdash; have to say about creating code in newsrooms in the service of journalism. Then just fill out the <a href="http://mozillaopennews.org/fellowships/apply.html">application</a>. You have nothing to lose and everything to gain.</p>

<ul>
<li><a href="http://knightlab.northwestern.edu/2013/07/15/newsroom-developer-why-journalism-matters-and-it-is-in-crisis-is-why/">Miranda Mulligan</a> of the KnightLab.</li>
<li><a href="http://thescoop.org/archives/2013/07/16/why-develop-in-the-newsroom/">Derek Willis</a> from the New York Times.</li>
<li><a href="http://michelleminkoff.com/2013/07/17/why-i-develop-in-the-newsroom/">Michelle Minkoff</a> from The Associated Press.</li>
<li><a href="http://www.journogeekery.com/post/55707365311/why-develop-in-a-newsroom">Tiff Fehr</a> from the New York Times.</li>
<li>The <a href="http://www.propublica.org/nerds/item/why-develop-in-the-newsroom">nerds from ProPublica</a></li>
<li><a href="http://zzolo.org/2013/07/17/why-i-code-in-the-newsroom/">Alan Palazzolo</a> from MinnPost.</li>
<li><a href="http://www.greglinch.com/2013/07/why-develop-in-the-newsroom-opportunities-abound.html">Greg Linch</a> from the Washington Post.</li>
<li><a href="http://hackerjournalist.net/2013/07/18/why-i-work-in-a-newsroom/">Brian Boyer</a> from NPR.</li>
<li><a href="https://medium.com/i-m-h-o/c3e6c0661397">Tasneem Raja</a> from Mother Jones.</li>
<li><a href="http://brighter.net/post/55874165573/why-develop-in-the-newsroom">Jacqui Maher</a> from the New York Times.</li>
<li><a href="http://palewi.re/posts/2013/07/18/why-develop-in-the-newsroom/">Ben Welsh</a> from the LA Times.</li>
<li><a href="http://blog.knowtheory.net/post/55888372154/developers-should-hack-on-the-news">Ted Han</a> from DocumentCloud.</li>
<li><a href="http://www.ryanpitts.com/writing/why-i-love-what-i-do/">Ryan Pitts</a>, formerly of the Spokesman-Review, and now working on data tools for CensusReporter.</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Convert string Lat/Long to number for Google Maps API]]></title>
    <link href="http://blog.chrislkeller.com/convert-string-lat-lng-to-number-for-Google-Maps-api/"/>
    <updated>2013-06-15T12:00:00-07:00</updated>
    <id>http://blog.chrislkeller.com/convert-string-lat-lng-to-number-for-Google-Maps-api</id>
    <content type="html"><![CDATA[<p>When sending <a href="https://developers.google.com/maps/documentation/javascript/reference#LatLng">Lat/Long</a> values to the <a href="https://developers.google.com/maps/documentation/javascript/">Google Maps API</a> for something like setCenter(), it wants an number value. But the value we pull from an option menu like the one below is a string.</p>

<pre><code>&lt;select id="searchString" onchange="zoomToAddress(this.value);"&gt;
&lt;option value=""&gt;--Select All--&lt;/option&gt;
&lt;option value="43.138092,-89.747988"&gt;Luckenbooth Cafe&lt;/option&gt;
&lt;option value="43.017218,-89.831479"&gt;Aunt Mary's Hooterville Inn&lt;/option&gt;
&lt;/select&gt;
</code></pre>

<p>So we want to convert the above strings to numbers that the Maps API can use. We&rsquo;ll place the following inside a function called zoomToAddress.</p>

<p>First we get the value from the option menu as a string and set it to a variable.</p>

<pre><code>var searchString = document.getElementById('searchString').value;
</code></pre>

<p>Then we set a variable to find the position of the comma in the string.</p>

<pre><code>var commaPos = searchString.indexOf(',');
</code></pre>

<p>Use <a href="http://www.javascripter.net/faq/convert2.htm">parseFloat</a> to conver the string to a number while parsing out the Latitude value.</p>

<pre><code>var coordinatesLat = parseFloat(searchString.substring(0, commaPos));
</code></pre>

<p>And we do the same for the Longitude.</p>

<pre><code>var coordinatesLong = parseFloat(searchString.substring(commaPos + 1, searchString.length));
</code></pre>

<p>Those variables are combined into a new google maps LatLng pair.</p>

<pre><code>var centerPoint = new google.maps.LatLng(coordinatesLat, coordinatesLong);
</code></pre>

<p>Then we can use the setCenter() method from the Maps API.</p>

<pre><code>map.setCenter(centerPoint);
</code></pre>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Link: Teaching yourself to code for the web]]></title>
    <link href="http://blog.chrislkeller.com/link-teaching-yourself-to-code-for-the-web/"/>
    <updated>2013-05-15T12:18:00-07:00</updated>
    <id>http://blog.chrislkeller.com/link-teaching-yourself-to-code-for-the-web</id>
    <content type="html"><![CDATA[<p>via <a href="http://veltman.tumblr.com/post/50335073356/teaching-yourself-to-code-for-the-web">Noah Veltman</a></p>

<blockquote><p>I’m not big on offering advice when it comes to learning how to code.  Everyone learns differently and has different goals; my experience isn’t necessarily instructive.  But I seem to be getting asked the same question more and more often: someone wants to be able to make cool things for the web, and they don’t know how to get started.  Here are some thoughts on how to keep your head on straight while you’re trying to learn. Take them all with a big grain of salt.</p></blockquote>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Automating crowdsourced maps with apps scripts]]></title>
    <link href="http://blog.chrislkeller.com/automating-crowdsourced-maps-with-apps-scripts/"/>
    <updated>2013-05-15T12:00:00-07:00</updated>
    <id>http://blog.chrislkeller.com/automating-crowdsourced-maps-with-apps-scripts</id>
    <content type="html"><![CDATA[<p>Back in November, on my second day at <a href="http://www.scpr.org/">KPCC</a>, I collaborated with <a href="http://twitter.com/kimbui">Kim Bui</a> on a <a href="http://www.scpr.org/blogs/politics/2012/11/06/10919/you-voted-today-what-was-it/">crowd-sourced map</a> that attempted to gather information from voters who wanted to share their experience at the polls.</p>

<p>We successfully powered the map using a bunch of Google tools &mdash; a <a href="http://www.google.com/drive/apps.html#forms">form</a>, a <a href="http://www.google.com/drive/apps.html#product=sheets">spreadsheet</a> and a <a href="http://www.google.com/drive/apps.html#fusiontables">Fusion Table</a> &mdash; along with some duct tape and some manual labor.</p>

<p>Some six months later I&rsquo;ve become more comfortable here, and more comfortable with <a href="https://developers.google.com/apps-script/">Google Apps Scripts</a> thanks to some <a href="http://blog.apps.chicagotribune.com/2013/02/15/using-google-docs-to-send-email/">great examples</a> from <a href="http://project.wnyc.org/smelendez-nicar12/">others</a>. So as I re-purposed the idea for an election back in May, I wanted to see if there wasn&rsquo;t a certain level of automation that I could add to the project.</p>

<p>I didn&rsquo;t want automation for the sake of automation, but rather to eliminate the repetitive and inefficient parts of the process, while still ensuring accuracy &mdash; cause that only makes sense in journalism.</p>

<p><strong>How It Was Done &ndash; Nov. 2012</strong></p>

<p>The duct tape was necessary because even though forms and spreadsheets and Fusion Tables all exist within Google&rsquo;s Drive application, the level of integration between a form and a spreadsheet and a spreadsheet and a Fusion Table remains basic.</p>

<p>Forms can send data to spreadsheets. Fusion Tables can be created from spreadsheets. But a straight data pipeline from a submitted form to a Fusion Table doesn&rsquo;t explicitly exist. There are methods and <a href="http://kh-samples.googlecode.com/svn/trunk/code/instructions.html">scripts</a> that can send form data to a Fusion Table, but in this method once the form and table are created you&rsquo;re locked in; you can&rsquo;t add additional fields on the form or table.</p>

<p>The need to perform simple calculations, comparisons and geocoding of submitted data meant there was a level of manual labor.</p>

<p>While Google&rsquo;s geocoder will do the best it can to find the latitude and longitude of a location, it will only what you tell it to do. So I wanted to make sure the address was geocoded properly before it appeared on the map. And because we wanted different colored markers to distinguish between voting experiences, we need to perform a comparison on the submitted data.</p>

<p>And besides, it was my second day at a new job and surely didn&rsquo;t want one of my first projects to flop.</p>

<p><strong>How It Was Done &ndash; May 2013</strong></p>

<p>I still used a Google form to populate a spreadsheet, but tied a lot of the automation to a function that runs when the form&rsquo;s submit button is pressed.</p>

<p>This one &mdash; cribbed from an <a href="http://blog.apps.chicagotribune.com/2013/02/15/using-google-docs-to-send-email/">Andy Boyle walkthrough</a> &mdash; will send an email with the information that was just submitted.</p>

<p>The script sets each column to a variable; <code>e.values[0]</code> in this case represents the first column in the spreadsheet&hellip;</p>

<pre><code>    function onFormSubmit(e) {
        var emailToAddress = 'ckeller@scpr.org';
        var submissionTimeStamp = e.values[0];
        var submissionPollingPlace = e.values[1];
        var submissionExperience = e.values[6];
        var submissionNarrative = e.values[2];
        var submissionFullName = e.values[3];
        var emailSubject = 'Voter issues map submission from' + submissionPollingPlace;
        var emailBody = submissionTimeStamp + '\n' +
            'Voting at ' + submissionPollingPlace +
            ' was ' + submissionExperience + '.\n' + submissionNarrative +
            ' -- submitted by' + submissionFullName;
        MailApp.sendEmail(emailToAddress, emailSubject, emailBody);

        // run the data processing functions
        runSpreadsheetFunctions();
    };
</code></pre>

<p>I&rsquo;ve piggybacked a <code>runSpreadsheetFunctions()</code> function inside this piece of code. I don&rsquo;t know if it&rsquo;s right and proper, but I want a whole bunch of actions to take place in succession when a form is submitted.</p>

<p>One is a function to run a user-submitted address through the geocoder and add the latitude and longitude of that address to a separate spreadsheet cell:</p>

<pre><code>    function geocodeAddressFromCell(){
        var sss = SpreadsheetApp.openById(spreadsheetID);
        var ss = sss.getSheetByName(workingSheetID);
        var lastRow = ss.getLastRow();
        var addressCellData = ss.getRange(lastRow, 2).getValue();
        var results = Maps.newGeocoder().geocode(addressCellData);
        if (results.status == 'OK') {
            var bestResult = results.results[0];
            var lat = bestResult.geometry.location.lat;
            var lng = bestResult.geometry.location.lng;
            var latLng = lat + ',' + lng;
            var addressTargetCellData = ss.getRange(lastRow, 9).setValue(latLng);
        } else {
            Logger.log(results.status);
            return '0,0';
        }
    };
</code></pre>

<p>This script will open a spreadsheet based on ID and sheet name, find the last row on the specified sheet and find a value in a specific column</p>

<pre><code>    var addressCellData = ss.getRange(lastRow, 2).getValue();
</code></pre>

<p>and run that value through Google&rsquo;s geocoder and output a latitude/longitude pair</p>

<pre><code>    var latLng = lat + ',' + lng;
</code></pre>

<p>That latitude/longitude pair is assigned to a variable and added to &ldquo;geocoded_address&rdquo; column in that last row</p>

<pre><code>    var addressTargetCellData = ss.getRange(lastRow, 9).setValue(latLng);
</code></pre>

<p>While we&rsquo;re at it, let&rsquo;s create a function that will allow us use of one map marker if the voter experience is positive, and another if the experience is negative. We&rsquo;ll do this by adding an <code>=IF()</code> spreadsheet formula to a cell.</p>

<pre><code>    function evaluateVotingExperience(){
        var sss = SpreadsheetApp.openById(spreadsheetID);
        var ss = sss.getSheetByName(workingSheetID);
        var voterExperienceColumn = "G";
        var voterMarkerIdColumn = "H";
        var lastRow = ss.getLastRow();
        var voterExperienceCell = voterExperienceColumn + lastRow;
        var voterMarkerIdCell = voterMarkerIdColumn + lastRow;
        var voterExperienceFormula = "=IF(" + voterExperienceCell + "=\"Negative\", \"large_red\", IF(" + voterExperienceCell + "=\"Positive\", \"large_green\"))";
        var ssCellToGetFormula = ss.getRange(voterMarkerIdCell);
        ssCellToGetFormula.setFormula(voterExperienceFormula);
    };
</code></pre>

<p>Again, we&rsquo;ll open a spreadsheet based on ID and sheet name, and use our columns and rows to whittle our way down to the cell that holds the value we want to evaluate, and the cell that will hold the result of that evaluation, which will be a Fusion Tables marker type.</p>

<pre><code>        var voterExperienceColumn = "G";
        var voterMarkerIdColumn = "H";
        var lastRow = ss.getLastRow();
        var voterExperienceCell = voterExperienceColumn + lastRow;
        var voterMarkerIdCell = voterMarkerIdColumn + lastRow;
</code></pre>

<p>We&rsquo;ll create an IF/ELSE formula for our evaluation</p>

<pre><code>        var voterExperienceFormula = "=IF(" + voterExperienceCell + "=\"Negative\", \"large_red\", IF(" + voterExperienceCell + "=\"Positive\", \"large_green\"))";
</code></pre>

<p>and add that formula to the cell that will hold the result.</p>

<pre><code>        var ssCellToGetFormula = ss.getRange(voterMarkerIdCell);
        ssCellToGetFormula.setFormula(voterExperienceFormula);
</code></pre>

<p>Finally, I added an update script, a <a href="https://gist.github.com/chrislkeller/3013360#file-spreadsheet-to-fusion-tables">series of functions</a> that allows you to trigger a sync between a <a href="http://blog.chrislkeller.com/google-group-user-john-m-posts-script-that-br/">Google spreadsheet and a Fusion Table</a>.</p>

<p>The update script is incorporated into <code>runSpreadsheetFunctions()</code>, and which is run when a form is submitted, so the Fusion Table is updated automatically when a voter clicks the submit button.</p>

<p>To be safe, I set a &ldquo;timeout&rdquo; to make sure the previous functions have run before the Fusion Table is updated.</p>

<pre><code>    // run functions that will process the data
    function runSpreadsheetFunctions(){

        geocodeAddressFromCell();
        Utilities.sleep(1000);

        evaluateVotingExperience();
        Utilities.sleep(1000);

        updateFusion();
        Utilities.sleep(1000);
    };
</code></pre>

<p>The full script &mdash; minus API keys and such &mdash; is below.</p>

<p><strong>Tie it all together</strong></p>

<p>I know what you&rsquo;re probably thinking at this point: that&rsquo;s a heckuva lot of work and scripting to do something you could do with PHP, MySQL and a bit of Javascript.</p>

<p>You. Are. Right.</p>

<p>If I had to do it over again I might consider other approaches to this kind of project. But I think I might be inclined to take this approach again.</p>

<ul>
<li>I found the constraints to be helpful. Outside of the learning, the setup was a breeze. And because we could only do so much with this setup, our project was focused pretty tightly.</li>
<li>Once in place, the only hand-holding needed is to make sure the data being submitted makes sense and isn&rsquo;t off topic. This is done in the spreadsheet, which means zero knowledge of code is required.</li>
<li>The first time around &mdash; being new on the job and with only a day to work with &mdash; I didn&rsquo;t want my first interactions to be about setting up databases and getting server access. I knew this would work and set off in that direction.</li>
<li>As for this latest go round, I kind of wanted to see just how far I could take Apps Scripts based on work others had done, and I&rsquo;m glad I did. It allowed us to pull off an interactive crowdsourced map rather quickly and with minimal overhead.</li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Link: Merging Datasets with Common Columns in Google Refine]]></title>
    <link href="http://blog.chrislkeller.com/link-merging-datasets-with-common-columns-in-google-refine/"/>
    <updated>2013-04-28T12:38:00-07:00</updated>
    <id>http://blog.chrislkeller.com/link-merging-datasets-with-common-columns-in-google-refine</id>
    <content type="html"><![CDATA[<p>via <a href="http://blog.ouseful.info/2011/05/06/merging-datesets-with-common-columns-in-google-refine/">OUseful.Info</a></p>

<blockquote><p>It’s an often encountered situation, but one that can be a pain to address – merging data from two sources around a common column. Here’s a way of doing it in <a href="https://github.com/OpenRefine">Google Refine</a>&hellip;</p></blockquote>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Link: Meetings Are Toxic]]></title>
    <link href="http://blog.chrislkeller.com/link-meetings-are-toxic/"/>
    <updated>2013-04-28T12:18:00-07:00</updated>
    <id>http://blog.chrislkeller.com/link-meetings-are-toxic</id>
    <content type="html"><![CDATA[<p>via <a href="http://gettingreal.37signals.com/ch07_Meetings_Are_Toxic.php">Getting Real</a></p>

<p>A NICAR thread about methods of project management and product development led me to some posts on <a href="http://crunchberry.org/tag/agile/">Agile development</a> which led me to find this gem. Like any piece of knowledge that could be deemed as inherent in some people, it&rsquo;s always good to be reminded of proper meeting rules.</p>

<blockquote><p>For those times when you absolutely must have a meeting (this should be a rare event), stick to these simple rules:</p>

<ul>
<li>Set a 30 minute timer. When it rings, meeting&rsquo;s over. Period.</li>
<li>Invite as few people as possible.</li>
<li>Never have a meeting without a clear agenda.</li>
</ul>
</blockquote>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Link: We're all living in an Everyblock world]]></title>
    <link href="http://blog.chrislkeller.com/link-were-all-living-in-an-everyblock-world/"/>
    <updated>2013-03-17T12:00:00-07:00</updated>
    <id>http://blog.chrislkeller.com/link-were-all-living-in-an-everyblock-world</id>
    <content type="html"><![CDATA[<p>via <a href="http://dansinker.com/post/42525273840/were-all-living-in-an-everyblock-world">Dan Sinker</a></p>

<blockquote><p>Back in 2008, I <a href="http://myeyesglazeover.blogspot.com/2008/01/everyblock-runs-circles-around-other.html">wrote a blog post</a> welcoming the local civic info site Everyblock to the world. Today, just over five years later, <a href="http://everyblock.com/">Everyblock has announced</a> that their parent company, NBC News, has shuttered the site. Twitter has been awash with <a href="https://twitter.com/search?q=everyblock&amp;src=typd">people digesting the news</a> and I suspect that this blog post, written while battling a nasty winter cold, isn’t the first nor will it be the last. That’s what happens when you create something with the impact that Everyblock had: People care when it’s gone.</p></blockquote>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Just a little break]]></title>
    <link href="http://blog.chrislkeller.com/just-a-little-break/"/>
    <updated>2013-03-08T12:00:00-08:00</updated>
    <id>http://blog.chrislkeller.com/just-a-little-break</id>
    <content type="html"><![CDATA[<p>Playing softball this week I broke my finger ever so slightly. It&rsquo;s small enough that I didn&rsquo;t feel the need to zip to a doctor right away. But it was enough that is hurts like hell and has limited my ability to type on a keyboard normally.</p>

<p><img src="http://archives.chrislkeller.com/blog-images/2013/my_broken_finger.jpg"></p>

<p>Kind of reminds me of the scene in <a href="http://www.imdb.com/title/tt0092513/">Adventures in Babysitting</a> after the subway fight when Keith Coogan&rsquo;s Brad needs &ldquo;just one stitch.&rdquo;</p>

<div class="embed-video-container"><iframe src="http://www.youtube.com/embed/uJG3cFrkkcc "></iframe></div>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Fresh from Posterous]]></title>
    <link href="http://blog.chrislkeller.com/fresh-from-posterous/"/>
    <updated>2013-02-16T09:42:00-08:00</updated>
    <id>http://blog.chrislkeller.com/fresh-from-posterous</id>
    <content type="html"><![CDATA[<p>This is my first post using Octopress, which comes after folks finally decided to pull the plug on Posterous. It was announced yesterday that it will be <a href="http://blog.posterous.com/thanks-from-posterous">shutting down on April 30</a>, some 13 months after Twitter acquired the platform, or rather the talent that built the platform.</p>

<p>As I wrote in my last post on Posterous, I enoyed using it because it stayed out of my way… I didn&rsquo;t feel the need to fiddle with the layout, or adjust the admin or mess around with plugins. It let me just write posts… Maybe not as many as I&rsquo;d like to, but posts nonetheless. And I stuck with it to a certain degree.</p>

<p>I spent some time considering going back to Tumblr, and I found this promising platform called Snipt. Heck I even installed WordPress for spell.</p>

<p>But all in all I like the idea of Octopress, of something that will continue to stay out of my way and just let me write, of something that will lets write in markdown which is then compiled into static HTML.</p>

<p>Time will tell.</p>

<p>I can say Posterous served me well at a certain point in my life, a time when I was learning to learn, code, program and teach/show others, and I&rsquo;ll have <a href="http://archives.chrislkeller.com/">an archive</a> of that. Now it&rsquo;s time to find something new.</p>

<p>I did take some steps to prepare for a day I figured was coming.</p>

<ul>
<li><p>I moved my <a href="http://projects.chrislkeller.com/">projects page</a> away from Posterous and organized it bit.</p></li>
<li><p>I grabbed an export of all of my content that Posterous housed and moved it to <a href="http://blog.chrislkeller.com/archives">an archive</a>. <del>Now I have some time to figure out how to deal with links that will be broken</del>.</p></li>
<li><p>I started to move some <a href="https://github.com/chrislkeller/documenting-learning">learning resources and tutorials</a> to <a href="https://github.com/chrislkeller">Github</a> and <a href="https://gist.github.com/chrislkeller">Gists</a>.</p></li>
</ul>

]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Last Posterous post... time to find a new method...]]></title>
    <link href="http://blog.chrislkeller.com/last-posterous-post-time-to-find-a-new-method/"/>
    <updated>2013-02-15T00:00:00-08:00</updated>
    <id>http://blog.chrislkeller.com/last-posterous-post-time-to-find-a-new-method</id>
    <content type="html"><![CDATA[<p>Looks like folks finally decided to pull the plug on Posterous. <a href="http://blog.posterous.com/thanks-from-posterous">It will be shutting down on April 30</a>, some 13 months after Twitter acquired the platform, or rather the talent that built the platform.</p>
<p>I enjoyed using Posterous because it stayed out of my way&hellip; I didn&#8217;t feel the need to fiddle with the layout, or adjust the admin or mess around with plugins. It let me just write posts&hellip; Maybe not as many as I&#8217;d like to, but posts nonetheless. And I stuck with it to a certain degree.</p>
<p>Sadly, along with the blogging platform being gone, seems any Google juice I accumulated for things like <a href="http://www.chrislkeller.com/tag/fusiontables">Fusion Tables walkthroughs and examples</a> will be gone as well&hellip; or at least pointing to dead links.</p>
<p>But then that might be for the better. I can say Posterous served me well at a certain point in my life, a time when I was learning to learn, code, program and teach/show others, and I&#8217;ll have <a href="http://archives.chrislkeller.com/">an archive</a> of that. Now it&#8217;s time to find something new.</p>
<p>I did take some steps to prepare for a day I figured was coming.</p>
<ul>
<li>
<p>I formatted my <a href="http://projects.chrislkeller.com/">projects page</a> a bit so it&#8217;s a little more organized.</p>
</li>
<li>
<p>I grabbed an export of all of <a href="http://archives.chrislkeller.com/">my content</a> that Posterous housed. The Posterous backup made is really easy for me, and I think they way the structured the export should be a model for all content platform companies when they shutdown &#8211; ahem, Everyblock.</p>
</li>
<li>
<p>I started to move some <a href="https://github.com/chrislkeller/documenting-learning">learning resources and tutorials</a> to <a href="https://github.com/chrislkeller">Github</a> and <a href="https://gist.github.com/chrislkeller">Gists</a>.</p>
</li>
<li>
<p>And I started to research some other potential platforms. Wordpress is always there, but it&#8217;s too easy for me to get bogged down in how the site looks. Again, more writing and less fuss. <a href="https://twitter.com/gotoplanb">Dave Stanton</a> &amp; <a href="https://twitter.com/webjournalist">Robert Hernandez</a> just turned me on to <a href="https://chrislkeller.snipt.net/">Snipt</a>, which looks promising as well.</p>
</li>
</ul>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Ever want to be a fly on the wall while interesting ideas and topics are being discussed?]]></title>
    <link href="http://blog.chrislkeller.com/ever-want-to-be-a-fly-on-the-wall-while-inter/"/>
    <updated>2013-02-09T00:00:00-08:00</updated>
    <id>http://blog.chrislkeller.com/ever-want-to-be-a-fly-on-the-wall-while-inter</id>
    <content type="html"><![CDATA[<p>On Wednesday, thankfully before breaking news shifted my focus entirely, I had the pleasure of listening to some great minds in the area of technology and journalism share their thoughts on everything from data visualization to the pitfalls of throwing everything on a map.</p>
<p>O&#8217;Reilly&#8217;s Alex Howard hosted a <a href="https://plus.google.com/u/0/+AlexanderHoward/posts/Mh4s3cq3Srq">Google Hangout</a> on the topic of data journalism. Present were O&rsquo;Reilly&#8217;s <a href="https://twitter.com/macslocum" target="_blank">Mac Slocum</a>, USA Today&#8217;s <a href="https://twitter.com/AnthonyDB" target="_blank">Anthony DeBarros</a>, NPR&#8217;s <a href="https://twitter.com/brianboyer">Brian Boyer</a>, <a href="https://twitter.com/gotoplanb">Dave Stanton</a> from SmartMedia Creative, <a href="https://twitter.com/michelleminkoff">Michelle Minkoff</a> from The Associated Press, <a href="https://twitter.com/tkb">Tariq Kokhar</a> from the World Bank, <a href="https://twitter.com/smfrogers">Simon Rogers</a> from The Guardian and myself.</p>
<p><iframe src="http://www.youtube.com/embed/haOc54NmP0k?list=UUSaNIkarwOScjXdbQ6uTx0A" frameborder="0" height="281" width="500"></iframe></p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Some thoughts after a couple months with tabletop and handlebars]]></title>
    <link href="http://blog.chrislkeller.com/some-thoughts-after-a-couple-months-with-tabl/"/>
    <updated>2013-02-02T00:00:00-08:00</updated>
    <id>http://blog.chrislkeller.com/some-thoughts-after-a-couple-months-with-tabl</id>
    <content type="html"><![CDATA[<blockquote>
<p><strong>tl;dr</strong> - Learning how I can use tabletop.js &amp; handlebars.js together has opened up some really cool custom mini-CMS possibilities and ways to manage data projects.</p>
<p>But thanks to the <a href="https://twitter.com/brianboyer/status/233201509842710528">experiments of others</a>, I have learned that flat json files can be better to use in production, especially for small one-off projects.</p>
<p>While I&#8217;d like to eventually write a script to take the tabletop object and write it to a flat file, I made some adjustments to some python code so I can take a csv, create a flat json file from it and drop that file into a <a href="https://gist.github.com/3230081">handlebars function</a> with minimal effort.</p>
<p>While it works for me, I&#8217;m curious to know if it works for others&hellip;</p>
<ul>
<li><a href="http://www.chrislkeller.com/some-thoughts-after-a-couple-months-with-tabl">Blog Post</a></li>
<li><a href="https://gist.github.com/4700210">Repo</a></li>
</ul>
</blockquote>
<hr />
<p>I&#8217;m happy to say that I still have access to some gray days since moving to Southern California, and on a recent one I set about streamlining some project structures, code snippets &amp; templates for two code libraries that I&#8217;ve been using more and more since coming to <a href="http://www.scpr.org/">Southern California Public Radio</a>: <a href="https://github.com/jsoma/tabletop">tabletop.js</a> and <a href="http://handlebarsjs.com/">handlebars.js</a>.</p>
<p>I&#8217;m only now getting back to the write up and posting code.</p>
<h2>Overview</h2>
<p>tabletop.js allows you to use a Google spreadsheet as a data backend. By simply publishing the spreadsheet and adding its key to a tabletop javascript function you can retrieve an an array of objects to be used on a webpage or in a web application. The library was released back in February &#8211; right around the time of NICAR &#8211; thanks to work by <a href="http://datanews.tumblr.com/">WNYC</a> and <a href="http://www.builtbybalance.com/">Balance Media</a>.</p>
<p>handlebars.js is a templating library &#8211; much like mustache.js &#8211; that &#8220;provides the power necessary to let you build semantic templates&#8221; based on data that is formatted as &#8211; get this &#8211; javascript objects. Using an example from the handlebar.js website, the library allows you to do things like this&#8230;</p>
<div class="CodeRay">
  <div class="code"><pre>&lt;div class=&quot;entry&quot;&gt;
    &lt;h1&gt;&lt;/h1&gt;
    &lt;div class=&quot;body&quot;&gt;
        
    &lt;/div&gt;
&lt;/div&gt;</pre></div>
</div>

<p>&hellip; where  and  represents information stored in an object like this:</p>
<div class="CodeRay">
  <div class="code"><pre>var context = {title: &quot;My New Post&quot;, body: &quot;This is my first post!&quot;}</pre></div>
</div>

<h2>Practical Applications</h2>
<p>Learning how these libraries can work with each other has been a lot of fun, especially in the context of a <a href="http://www.scpr.org/about/people/staff/chris-keller">newly-created position</a> at a <a href="http://www.scpr.org/">new-to-me news organization</a> where I have had a role to play in building a foundation for the presentation of data projects.</p>
<p>For instance, using handlebars.js ability to load precompiled handlebars templates from file we&#8217;ve been able to construct a basic project wrapper that can live outside CMS, minimizes the amount of code that needs to be changed at any given time and allows us to manage a single header and one footer file. DRY FTW.</p>
<p>I&#8217;ve also been able to use the combination of these libraries to come to having a custom mini-CMS that can run some of these projects, which can then be updated by anyone that can use a spreadsheet.</p>
<p>For instance, one of my first collaborations was with our business and economy reporter <a href="http://www.scpr.org/about/people/staff/matthew-debord">Matt DeBord</a> on this project for <a href="http://www.scpr.org/blogs/economy/2012/12/07/11444/november-job-report/">Explaining the Monthly Jobs Report</a>.</p>
<p>This project combines tabletop.js with handlebars.js &#8211; and some <a href="http://www.highcharts.com/">highcharts.js</a> for good measure &#8211; to show the differences between &#8220;Initial,&#8221; &#8220;Revised,&#8221; and Final monthly jobs numbers released by the U.S. Bureau of Labor Statistics.</p>
<p>While my &#8220;design&#8221; judgement and sensibilities continue to evolve, for my money, the magic is in the fact that Matt can update this presentation for our audience by opening a Google spreadsheet and adding the new numbers. Lightweight, custom mini-CMS!</p>
<p><a href="https://twitter.com/tasneemraja">Tasneem Raja</a>, the Interactive Editor at Mother Jones, has written a <a href="http://www.ire.org/blog/on-the-road/2012/09/21/behind-story-mother-jones-and-47-percent/">solid explainer</a> on how the magazine has leveraged tabletop.js and a <a href="https://docs.google.com/spreadsheet/ccc?key=0AiK02J6OppqxdFVxTEJBLXpqcWZKNVJsRFFZdkNESGc#gid=0">Google spreadhseet</a> for collaborative projects such as their <a href="http://www.motherjones.com/politics/2012/09/charts-47-percent-romney-tax-data">You Might Be the 47 Percent If&hellip;</a> scoop.</p>
<p>Some of the projects I&#8217;ve worked on over the past couple months that use tabletop.js and handlebars.js include a presentation on the purchasing of <a href="http://projects.scpr.org/static/interactives/capital-appreciation-bonds/">Capital Appreciation Bonds</a> by local school districts, a &#8220;By The Numbers&#8221; look at the impact of the so-called <a href="http://projects.scpr.org/static/interactives/unemployment-compensation/">fiscal cliff on Emergency Unemployment Compensation benefits</a> and a comparison of <a href="http://projects.scpr.org/static/charts/gun-laws/">California and federal gun laws</a></p>
<p>But a <a href="http://newsbeastlabs.tumblr.com/post/37641296435/google-docs-miso-powered-apps-a-note-on">post on NewsBeast Labs</a> I found while writing this pointing to a post from Jeremy Singer-Vine  &#8211; appropriately titled <a href="https://gist.github.com/3295633">&#8220;Why I love Tabletop.js but don&#8217;t use it in production&#8221;</a> &#8211; and some words from <a href="https://twitter.com/maboa">Mark Boas</a> on an <a href="http://www.mozillaopennews.org/">Open News</a> call a couple weeks ago reminded me of potential obstacles and issues with relying too much on tabletop.js for projects.</p>
<p>And a tweet <del>this week</del> <a href="https://twitter.com/aboutaaron/status/289469005008338945">a few weeks back</a> from <a href="https://twitter.com/aboutaaron">Aaron Williams</a>, and <a href="https://twitter.com/mattwaite/status/297870209807704064">one today</a> from <a href="https://twitter.com/mattwaite">Matt Waite</a>, reminded me I have to finish this post you are reading.</p>
<p>All of the issues that Jeremy listed are real, and Aaron&#8217;s experience is real. Thinking about the projects I listed above, none of them really require the kind of dynamic data display that tabletop.js can pull off. It&#8217;s a nice feature to have available on the monthly jobs report, but it isn&#8217;t crucial, and certainly isn&#8217;t required on the others.</p>
<p>A flat file <a href="https://docs.google.com/presentation/embed?id=1IybYcc0eVL-Rchm7lEQNwrM-AHRfr_M8ewfGYYNjeu8&amp;start=false&amp;loop=false&amp;delayms=3000#slide=id.p">very much</a> would work just fine.</p>
<p>And so I went about finding a way to create a flat json file from a Google spreadsheet that I could use in a handlebars.js template.</p>
<h2>My Workaround</h2>
<p>I already had <a href="https://twitter.com/andymboyle">Andy Boyle&#8217;s</a> python <a href="http://www.andymboyle.com/2011/11/02/quick-csv-to-json-parser-in-python/">script</a> from a year ago that creates json from a csv. And I noticed in the comments section on Andy&#8217;s post that <a href="https://twitter.com/onyxfish">Christopher Groskopf&#8217;s</a> <a href="http://csvkit.readthedocs.org/en/latest/">csvkit</a> has a <a href="http://csvkit.readthedocs.org/en/latest/scripts/csvjson.html">csvjson utility</a> that can also convert a csv to a json file.</p>
<p>After flirting with the idea of adding a custom argument to the csvjson utility to allow me to specify a key, I <a href="https://gist.github.com/4700210#file-handlebars-json-py">adjusted Andy&#8217;s script</a> to create a file that looks like this&hellip;</p>
<div class="CodeRay">
  <div class="code"><pre>{&quot;objects&quot;: [{&quot;Source&quot;: &quot;National Employment Law Project&quot;, &quot;DataOrder&quot;: &quot;1&quot;, &quot;SourceLink&quot;: &quot;http://www.nelp.org/&quot;, &quot;Data&quot;: &quot;12.29.2012&quot;, &quot;Title&quot;: &quot;The last day anyone will receive benefits from the Emergency Unemployment Compensation program unless Congress acts to renew it.&quot;}, {&quot;Source&quot;: &quot;Congressional Budget Office&quot;, &quot;DataOrder&quot;: &quot;2&quot;, &quot;SourceLink&quot;: &quot;&quot;, &quot;Data&quot;: &quot;$30,000,000,000&quot;, &quot;Title&quot;: &quot;Estimated cost to renew the Emergency Unemployment Compensation program through the end of 2013.&quot;}, {&quot;Source&quot;: &quot;National Employment Law Project&quot;, &quot;DataOrder&quot;: &quot;3&quot;, &quot;SourceLink&quot;: &quot;http://www.nelp.org/&quot;, &quot;Data&quot;: &quot;400,000&quot;, &quot;Title&quot;: &quot;Estimated number of Californians receiving benefits from the Emergency Unemployment Compensation program, which is set to expire Jan. 2.&quot;}, {&quot;Source&quot;: &quot;National Employment Law Project&quot;, &quot;DataOrder&quot;: &quot;4&quot;, &quot;SourceLink&quot;: &quot;http://www.nelp.org/&quot;, &quot;Data&quot;: &quot;2,100,000&quot;, &quot;Title&quot;: &quot;Estimated number of Americans receiving benefits under the Emergency Unemployment Compensation program that would lose their unemployment benefits come January if Congress doesn\u2019t act.&quot;}]</pre></div>
</div>

<p>&hellip; which is something that allows me to plug my new file name into a variable in <a href="https://gist.github.com/raw/3230081/31abdbfb3f4746f8fb761d196dcfa81cdd38184d/data-script.js">this script</a> and fly.</p>
<h2>Snags</h2>
<p>Now, admittedly it works because most of my handlebars work thus far has used simple data structures &#8211; largely an object that contains an array of objects &#8211; but my workflow might fall apart quickly should I need to access multiple data streams, etc. (UPDATE: This has already happened!)</p>
<p>One thing I have noticed through this experiment is tabletop.js strips uppercase letters and underscores from object keys, while the csv to json version doesn&#8217;t. So that&#8217;s a thing as it&#8217;s the difference between a handlebars.js template that uses&hellip;</p>
<div class="CodeRay">
  <div class="code"><pre>//what tabletop brings
</pre></div>
</div>

<p>and</p>
<div class="CodeRay">
  <div class="code"><pre>// created from a csv to json method
</pre></div>
</div>

<p>Another thing I&#8217;ve noticed is the python script that converts the csv to json renders everything as a string, which has caused some issues when using something like highcharts, which requires is data objects to be integers. So I continue to explore a way to fix this.</p>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Here's a simple script to generate a boilerplate FOIA-letter type thing that I cobbled together... ]]></title>
    <link href="http://blog.chrislkeller.com/heres-a-foia-letter-creator-script-i-cobbled/"/>
    <updated>2013-01-29T00:00:00-08:00</updated>
    <id>http://blog.chrislkeller.com/heres-a-foia-letter-creator-script-i-cobbled</id>
    <content type="html"><![CDATA[<p>This is a <a href="https://gist.github.com/4668929" target="_blank">super simple shell script</a> that takes boilerplate FOIA language and creates a <a href="http://daringfireball.net/projects/markdown/" target="_blank">markdown</a> file that can be addressed to a particular agency.</p>
<p>It&#8217;s tailored to California, but you can adjust it to your liking.</p>
<p>You will still have to add the address, city, state and zip code of the agency, and the type of data being requested, but this is a step up from having a file that I copy and paste from.</p>
<p>The script takes a filename as an argument. That filename will have the date prepended to it so you can see at a glance which were sent out when.</p>
<p>I haven&#8217;t decided yet to allow for the address and other potential variables to be passed into the script. At certain points you want to allow for mistakes, and most folks are bound to make mistakes when entering information in on the command line.</p>
<div class="CodeRay">
  <div class="code"><pre>#!/bin/bash

    # date variable
    DATE=&quot;$(date +&quot;%m-%d-%y&quot;)&quot;

    # input for newfile
    NAME_OF_FOIA_LETTER=&quot;$1&quot;

    # name for newfile
    OUTPUT_FILE=&quot;$DATE-$NAME_OF_FOIA_LETTER.md&quot;

    # create markdown FOIA
    echo &quot;Creating $NAME_OF_FOIA_LETTER FOIA letter&quot;
    cat &lt;&lt;EOF &gt;$OUTPUT_FILE
    **$DATE**

    ADDRESS  $line
    STREET  $line
    CITY, STATE, ZIP CODE  $line

    **RE**: Public records request for NAME OF RECORD

    **To Whom It May Concern**:

    Under the California Public Records Act (Government Code Section 6250 et seq.), I ask to obtain a copy of the following records or data sets which I understand to be held by your agency:

    &gt;*DATA TO BE REQUESTED HERE*

    I ask for a determination on this request within 10 days of receipt, or sooner should you make a determination without review of the record(s) in question.

    If you determine that any or all or the information if exempt, I would like to know if the exemption is discretionary, if it's necessary to exercise discretion in this case and a signed notification citing the legal authorities used to determine the records are exempt.

    Should some -- but not all of the information -- be exempt from disclosure -- and you intend to withhold it -- I ask that you redact it for the time being and make the rest available as requested.

    Please notify me of any duplication costs that will exceed \$10.00. If I can provide any clarification or answer any questions, my contact information is below.

    Thanks in advance and take care.

    Sincerely:

    Chris Keller  $line
    Data Journalist/News Applications Developer  $line
    Southern California Public Radio  $line
    **Web**: scpr.org  $line
    **Email**: ckeller@scpr.org  $line
    **Desk**: (626) 583-5214  $line

    EOF

    open $OUTPUT_FILE</pre></div>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Link: "TLDR" is unnecessary]]></title>
    <link href="http://blog.chrislkeller.com/link-tldr-is-unnecessary/"/>
    <updated>2013-01-13T00:00:00-08:00</updated>
    <id>http://blog.chrislkeller.com/link-tldr-is-unnecessary</id>
    <content type="html"><![CDATA[<div class="posterous_bookmarklet_entry">
<blockquote class="posterous_short_quote">If you summarize your idea in your first sentence, writing &#8220;TLDR&#8221; is superfluous.</blockquote>
<div class="posterous_quote_citation">via <a href="http://douglastarr.com/tldr-is-unnecessary#comment">douglastarr.com</a></div>
<p>As a guy who has taken to adding a tl;dr nugget on the top of walkthroughs reading the above makes me want to whack myself upside the head&#8230; But maybe what I have been trying to do has another name&#8230; Maybe something along the lines of, &#8220;You Will Accomplish&#8221;</p>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[Display data from a flat JSON file on a Handlebars.js template file rendered with AJAX]]></title>
    <link href="http://blog.chrislkeller.com/display-data-from-a-flat-json-file-on-a-handl/"/>
    <updated>2013-01-12T00:00:00-08:00</updated>
    <id>http://blog.chrislkeller.com/display-data-from-a-flat-json-file-on-a-handl</id>
    <content type="html"><![CDATA[<blockquote>
<p><strong>tl;dr</strong>: The README on the repo below gives a bit of a walkthrough and demonstration of the script I&#8217;ve been using to display a flat data file on Handlebars templates rendered with AJAX, which has allowed me to learn to deploy interactive data projects fairly fast.</p>
<ul>
<li><a href="http://www.chrislkeller.com/display-data-from-a-flat-json-file-on-a-handl">Blog Post</a></li>
<li><a href="http://projects.chrislkeller.com/snippets/ajax-handlebars/">Demo Page</a>
<li><a href="https://gist.github.com/3230081">Repo</a></li>
</ul>
<hr />
</blockquote>
<h2>Overview</h2>
<p><a href="http://handlebarsjs.com/">Handlebars.js</a> is a templating library &#8211; much like mustache.js &#8211; that &#8220;provides the power necessary to let you build semantic templates&#8221; based on data that is formatted as &#8211; get this &#8211; javascript objects. Using an example from the handlebar.js website, the library allows you to do things like this&#8230;</p>
<div class="CodeRay">
  <div class="code"><pre>&lt;div class=&quot;entry&quot;&gt;
    &lt;h1&gt;&lt;/h1&gt;
    &lt;div class=&quot;body&quot;&gt;
        
    &lt;/div&gt;
&lt;/div&gt;</pre></div>
</div>

<p>&hellip; where  and  represents information stored in an object like this:</p>
<div class="CodeRay">
  <div class="code"><pre>var context = {title: &quot;My New Post&quot;, body: &quot;This is my first post!&quot;}</pre></div>
</div>

<p>There are some really good resources out there for those who want to start using the Handlebars JavaScript template library. Here are some links:</p>
<ul>
<li><a href="http://handlebarsjs.com/">Handlebars site</a></li>
<li><a href="https://github.com/wycats/handlebars.js/">Handlebars GitHubRepo</a></li>
<li><a href="http://net.tutsplus.com/tutorials/javascript-ajax/introduction-to-handlebars/">NetTuts Handlebars Walkthrough</a></li>
<li>Three-part series on using Handlebars: <a href="http://blog.teamtreehouse.com/getting-started-with-handlebars-js">Part one</a>; <a href="http://blog.teamtreehouse.com/code/handlebars-js-part-2-partials-and-helpers/">Part two</a>; <a href="http://blog.teamtreehouse.com/handlebars-js-part-3-tips-and-tricks">Part three</a></li>
</ul>
<p>I&#8217;d like to demonstrate a bit of the script I&#8217;ve been using to display a flat data file on Handlebars templates render with AJAX, and give a couple practical applications for using Handlebars in a newsroom environment in order to deploy interactive projects fairly fast.</p>
<h2>Walkthrough</h2>
<p>Coming across Handlebars.js after learning the basics of django templating, I really wanted a way to mimic some of that functionality and store Handlebars templates in <a href="https://github.com/wycats/handlebars.js/issues/82">reusable, decoupled files that could be shared across projects</a>.</p>
<p>Thankfully this function based on <a href="http://berzniz.com/post/24743062344/handling-handlebars-js-like-a-pro">code from here</a> helps me to do exactly that.</p>
<div class="CodeRay">
  <div class="code"><pre>// render handlebars templates via ajax
function getTemplateAjax(path, callback) {
    var source, template;
    jqueryNoConflict.ajax({
        url: path,
        success: function (data) {
            source = data;
            template = Handlebars.compile(source);
            if (callback) callback(template);
        }
    });
}</pre></div>
</div>

<p>I then abstract out a function to display the compiled template, passing in the name of the template, the css selector I am targeting and the data I want to display.</p>
<div class="CodeRay">
  <div class="code"><pre>// function to compile handlebars template
    function renderHandlebarsTemplate(withTemplate,inElement,withData){
        getTemplateAjax(withTemplate, function(template) {
            jqueryNoConflict(inElement).html(template(withData));
        })
    };</pre></div>
</div>

<p>I can then call it like this, where dataDetailsTemplate.handlebars is the name of my template, and #data-details is the css selector I am targeting, and data is what I want to display.</p>
<div class="CodeRay">
  <div class="code"><pre>renderHandlebarsTemplate('dataDetailsTemplate.handlebars', '#data-details', data);</pre></div>
</div>

<p>Let&#8217;s go through the full <a href="https://gist.github.com/raw/3230081/31abdbfb3f4746f8fb761d196dcfa81cdd38184d/data-script.js">data-script.js file</a>, because there&#8217;s a lot in there that I&#8217;ve kind of picked up over the last several months.</p>
<p>I don&#8217;t really have an idea if it is &#8220;correct&#8221; to programmers out there, but I know that it works and doesn&#8217;t throw me errors.</p>
<p>In learning to use jQuery in the context of my previous CMS &#8211; which used several jQuery libraries &#8211; I found it just made sense to use a no conflict variable and it&#8217;s something I&#8217;ve just stuck with:</p>
<div class="CodeRay">
  <div class="code"><pre>var jqueryNoConflict = jQuery;</pre></div>
</div>

<p>When the DOM is ready I call the <em>retriveData()</em> function which kind of starts the whole ball rolling:</p>
<div class="CodeRay">
  <div class="code"><pre>//begin main function
    jqueryNoConflict(document).ready(function(){
        retriveData();
    });
    //end main function</pre></div>
</div>

<p><em>retriveData()</em> looks for my flat JSON file, which set to a variable. It then uses jQuery&#8217;s getJSON method to pull the data and run it through a function called <em>renderDataVisualsTemplate()</em>. This is the function that will render my Handlebars template to the page with data in it.</p>
<div class="CodeRay">
  <div class="code"><pre>// grab data
    function retriveData() {
        var dataSource = 'working-data-file.json';
        jqueryNoConflict.getJSON(dataSource, renderDataVisualsTemplate);
    };</pre></div>
</div>

<p><em>renderDataVisualsTemplate()</em> gets an argument that represents my the data from my flat JSON file. This function runs my base handlebars template function using the name of my template (dataDetailsTemplate.handlebars), the css selector where I will inject my template (#data-details) and the data I will fill it with (data).</p>
<div class="CodeRay">
  <div class="code"><pre>// render compiled handlebars template
    function renderDataVisualsTemplate(data){
        handlebarsDebugHelper();
        renderHandlebarsTemplate('dataDetailsTemplate.handlebars', '#data-details', data);
    };</pre></div>
</div>

<p>After that, I have my function to pull my Handlebars template from an external file and compile it. I&#8217;ve also included a Handlebars debugger, a &#8220;helper&#8221; function shows information about the data I am trying to work with.</p>
<p>The base handlebars template function looks like this, and takes three parameters: the name of the template, the css selector and the data object:</p>
<div class="CodeRay">
  <div class="code"><pre>// function to compile handlebars template
    function renderHandlebarsTemplate(withTemplate,inElement,withData){
        getTemplateAjax(withTemplate, function(template) {
            jqueryNoConflict(inElement).html(template(withData));
        })
    };</pre></div>
</div>

<p>Let&#8217;s take a look at the flat JSON file I am using to hold the data that will be rendered to the page. It&#8217;s structured as it is in the Handlebars walkthrough.</p>
<div class="CodeRay">
  <div class="code"><pre>{&quot;objects&quot;: [{&quot;Source&quot;: &quot;National Employment Law Project&quot;, &quot;DataOrder&quot;: &quot;1&quot;, &quot;SourceLink&quot;: &quot;http://www.nelp.org/&quot;, &quot;Data&quot;: &quot;12.29.2012&quot;, &quot;Title&quot;: &quot;The last day anyone will receive benefits from the Emergency Unemployment Compensation program unless Congress acts to renew it.&quot;}, {&quot;Source&quot;: &quot;Congressional Budget Office&quot;, &quot;DataOrder&quot;: &quot;2&quot;, &quot;SourceLink&quot;: &quot;&quot;, &quot;Data&quot;: &quot;$30,000,000,000&quot;, &quot;Title&quot;: &quot;Estimated cost to renew the Emergency Unemployment Compensation program through the end of 2013.&quot;}]}</pre></div>
</div>

<p>To render the data, the Handlebars template is structured just as it would be if it was inline on the index.html page, save for wrapping it in a script tag.</p>
<div class="CodeRay">
  <div class="code"><pre>&lt;div&gt;
        
        &lt;h2&gt;Flat file data displayed on a handlebars.js template loaded with ajax&lt;/h2&gt;
        
            &lt;p&gt;: &lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;
            -- <a href="" target="_blank"><em></em></a>&lt;/p&gt;
        
    &lt;/div&gt;</pre></div>
</div>

<p>In this case, I&#8217;m asking that every instance of an object</p>
<div class="CodeRay">
  <div class="code"><pre>

    </pre></div>
</div>

<p>be rendered to the page and structured in a certain way.</p>
<div class="CodeRay">
  <div class="code"><pre>&lt;p&gt;: &lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;
    -- <a href="" target="_blank"><em></em></a>&lt;/p&gt;</pre></div>
</div>

<p>My HTML page isn&#8217;t any special, other than have a div that will have all kinds of data injected into it thanks to Handlebars.</p>
<div class="CodeRay">
  <div class="code"><pre>&lt;div id=&quot;data-details&quot;&gt;&lt;/div&gt;</pre></div>
</div>

<h3>Practical Applications?</h3>
<p>Your mileage might vary, but I&#8217;ve found several practical applications of Handlebars.js just by looking at my needs.</p>
<p>For instance, I came from shops that used a CMS where I could add html, css and JavaScript to a CMS &#8220;asset&#8221; which was then wrapped by the site header, rail and footer. Here at <a href="http://www.scpr.org/">SCPR</a>, I&#8217;ve been lucky enough to have mentors who wanted to and helped to create something similar.</p>
<p><a href="http://projects.scpr.org/static/maps/pedestrian-safety/">This project</a> is on a custom structure that lies outside of the CMS. The header and footer are each Handlebars templates, external files that I add to each new project. If I need to change a link in the footer I change it in one place and it&#8217;s changed on all project pages using the template. Same goes for the header.</p>
<p>You could easily recreate something similar. Let&#8217;s say your template structure is something like:</p>
<div class="CodeRay">
  <div class="code"><pre>&lt;body&gt;
        &lt;div id=&quot;data-header&quot;&gt;&lt;/div&gt;
            &lt;div id=&quot;data-container&quot;&gt;
                &lt;div class=&quot;row-fluid&quot;&gt;
                    &lt;div class=&quot;span4&quot;&gt;
                        &lt;div id=&quot;data-details&quot;&gt;&lt;/div&gt;
                    &lt;/div&gt;
                    &lt;div class=&quot;span8&quot;&gt;
                        &lt;div id=&quot;data-visuals&quot;&gt;&lt;/div&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;div id=&quot;data-footer&quot;&gt;&lt;/div&gt;
    &lt;/body&gt;</pre></div>
</div>

<p>You can probably spot some candidates for possible Handlebars templates now; data-header, data-details, data-visuals and data footer all make sense, where data-header and data-footer could be used on all projects.</p>
<p>Or say you want to quickly create a table to display some information. Using the data file from my earlier example, I can create a Handlebars template to do just that:</p>
<div class="CodeRay">
  <div class="code"><pre>&lt;table class=&quot;table&quot;&gt;
        &lt;tbody&gt;
            &lt;tr&gt;
                
                    &lt;td&gt;&lt;/td&gt;
                    &lt;td&gt;&lt;/td&gt;
                    &lt;td&gt;&lt;/td&gt;
                
            &lt;/tr&gt;
        &lt;/tbody&gt;
    &lt;/table&gt;</pre></div>
</div>

<h2>Wrap up</h2>
<p>As an intermediate beginner to the world of web development, and entering my fifth year of being an &#8220;online guy&#8221; in a newsroom, I&#8217;ve found Handlebars to be a lot of fun. To increase that fun, there are all kinds of add ons and helper functions that you can use. <a href="http://elving.github.com/swag/">swag.js</a> might be the most fun thus far.</p>
<p>See while Handlebars tried to keep logic out of the templates &#8211; and I respect that &#8211; there some things I&#8217;d like to be able to do, and swag.js allows for some of that. For instance, if in my table example I wanted the title to be in all-caps I can do this with swag:</p>
<div class="CodeRay">
  <div class="code"><pre></pre></div>
</div>

<p>Or if I want to evaluate the data in my flat JSON file, I can run comparisons on my Handlebars templates.</p>
<div class="CodeRay">
  <div class="code"><pre>
        
            &lt;td&gt;The Source is &lt;/td&gt;
        
            &lt;td&gt;No Source&lt;/td&gt;
        
    </pre></div>
</div>
]]></content>
  </entry>
  
  <entry>
    <title type="html"><![CDATA[What I learned back at BuildMadison and in making CitySolver...]]></title>
    <link href="http://blog.chrislkeller.com/what-i-learned-back-at-buildmadison-and-in-ma/"/>
    <updated>2012-12-31T00:00:00-08:00</updated>
    <id>http://blog.chrislkeller.com/what-i-learned-back-at-buildmadison-and-in-ma</id>
    <content type="html"><![CDATA[<p>Back in September I had the chance to participate in an event called  <a href="http://buildmadison.org/">Build Madison</a>, a weekend event that brought tinkerers, hackers and idea people together to build things.</p>
<p>At the event, myself and Paul Klemstine and another took up the challenge of building on a pitch to come up with a way to submit quality of life issues &#8211; graffiti, potholes, sidewalks in need of repair &#8211; to the city of Madison from a mobile device. Pictures were a must, as was the ability to add a user&#8217;s location.</p>
<p><img src="http://archives.chrislkeller.com/blog-images/2012/12/city_solver_incident.png" /></p>
<p>The Build Madison pitch also positioned this project as something that would tie in with the city&#8217;s existing &#8221;<a href="https://www.cityofmadison.com/reportaproblem/index.cfm?">Report a Problem</a>&#8221; infrastructure.</p>
<p>Paul and I developed had a good time hacking together a project we called <a href="https://github.com/chrislkeller/CitySolver">City Solver</a>&hellip; It could aspire to be more &#8211; a foundation for an open-source <a href="http://seeclickfix.com/">See, Click, Fix</a> or a tool for smaller municipalities &#8211; or less and left to lessons learned, of which there were many that apply to many things I find myself involved in on a daily basis.</p>
<ol>
<li>
<p>From different angles and perspectives keep asking, &#8220;Is this a problem that needs to be solved?&#8221;</p>
<p>The original pitch wanted to tie an application into the city of Madison &#8220;Report a Problem&#8221; system. Needless to say that is an exponentially difficult task, and one not easily tackled by a hackathon team with 24 hours to work with.</p>
<p>And nevermind that the city of Madison has a comprehensive website that city residents can use to report specific issues and wasn&#8217;t looking to extend the system in the manner the pitch stated.</p>
<p>Finally, I knew that Open Data was on the horizon in the city, as the city council had recently passed an ordinance that would let information start following for developers to use.</p>
<p>In the end, our project ended up with a couple prizes from the event, and I had the chance to meet with city officials on two occassions to discuss CitySolver courtesy of Eve Galanter,  a former city council member who pitched the project.</p>
<p>The conversation were fruitful as we were able to gain some insight into future city plans in this &#8220;Report a Problem&#8221; arena, some of which include mobile access and user feedback that we had in mind.</p>
<p>And as soon as the Open Data starts following, real problems might be made available to develop around.</p>
</li>
<li>
<p>Know who else has &#8220;solved&#8221; or attempted to &#8220;solve&#8221; this problem.</p>
<p>Had in been better in touch with the work being done by Code For America, I would have known that developers have open-sourced similar <a href="http://brigade.codeforamerica.org/applications/1">crowd-sourcing applications</a> and made code available that we could have built upon.</p>
<p>That said, as an intermediate beginner, building something myself was very fufilling and helped increase my confidence about what I was capable of learning.</p>
</li>
<li>
<p>Spend more time on knowing the following:</p>
<ul>
<li>Who are your users?</li>
<li>What are their needs?</li>
<li>What can we do for them?</li>
</ul>
<p>Some advice from <a href="http://codeforamerica.org/author/kevin/">Code For America&#8217;s Kevin Curry</a> helped focus ideas on this project further, when he suggested the following after I posted to a Google Group:</p>
<blockquote class="posterous_medium_quote">
<p>The key element of your plan is residents working together to close their own tickets. That&#8217;s significant. I think you should base everything off of that and make it totally obvious this is not a tool for reporting problems about the city that only the city can fix.</p>
</blockquote>
<p>To Kevin&#8217;s point, after thinking more about this project as something &#8220;long-term&#8221; I was able to come up with the following:</p>
<ul>
<li>City residents have the power, know-how and &#8211; I believe &#8211; a want to work together to solve some common problems.</li>
<li>That said, that power and ability is limited when a distinction is made between a resident&#8217;s fence that is in disrepair, a street with potholes and a malfunctioning street light.</li>
<li>Success in building a coalition-based platform might best come if based around a <a href="https://neighborland.com/" target="_blank">singular idea</a>.</li>
<li>Privacy is a real concern and offers a very real hurdle to overcome when considering the idea of neighbors reporting on issues with neighbors.</li>
</ul>
</li>
<li>
<p>That last one is a biggie, hence even if everything at this point is coming up roses, would anyone use this thing?</p>
<p>There are privacy aspects to keep in mind, and very real hurdles to overcome when considering the idea of neighbors reporting on issues with neighbors. For instance, &#8220;Thank you, I&#8217;d like to repair my broken fence, but I&#8217;m without work and my wife is sick and I haven&#8217;t made the time, so thank you for posting a photo of it online with your brutish comment.&#8221;</p>
</li>
</ol>
<p>All that said, what follows are the bullet points from the BuildMadison presentation.</p>
<h3>Build Madison Presentation Bullet Points</h3>
<p><img src="http://archives.chrislkeller.com/blog-images/2012/12/city_solver_web.png" alt="CitySolver" width="100%" /></p>
<p>City Solver is a multi-device platform that allows everyday citizens to submit information about quality of life issues and problems they feel a municipality could or should address.</p>
<p>Whether using a web app, a native Android app, or their laptop, desktop computer or tablet, city residents could send images and descriptions of these issues and opportunities.</p>
<p>A rating system is Phase One of furthering the platform to allow neighborhood residents to band together to solve issues or to clean up the neighborhood.</p>
<h4>Features</h4>
<ul>
<li>Native Android app pulls geolocation and user information to auto-populate data fields, and sends photo and photo location to a database.</li>
<li>Thumbs up and thumbs down ranking of issues to gauge interest from others.</li>
<li>Interface thats works on devices and browsers.</li>
<li>Photo uploads work on Android and laptop, desktop web browsers. Photo uploads will be possible for users on iOS 6 Safari.</li>
</ul>
<p><img src="http://archives.chrislkeller.com/blog-images/2012/12/city_solver_mobile.png" alt="CitySolver" width="100%" /></p>
<h4>Wishlist</h4>
<ul>
<li>Coalition building. Sign up to band together to fix this problem.</li>
<li>Use geolocation of an issue to query against aldermanic districts to add more context, or partner with OpenBallotBox?</li>
<li>Allow user to submit information via SMS</li>
<li>Use email to submit information.</li>
<li>Full screen map with geolocation to find issues near you.</li>
<li>Filtering &amp; Search.</li>
<li>Admin view of database to assign issues, mark as resolved or not feasible and communicate back with user if needed.</li>
</ul>
]]></content>
  </entry>
  
</feed>
