<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>418 I&apos;m a teapot</title>
    <link rel="alternate" type="text/html" href="http://little418.com/" />
    <link rel="self" type="application/atom+xml" href="http://little418.com/atom.xml" />
    <id>tag:little418.com,2011-03-22:/8</id>
    <updated>2012-03-27T22:09:58Z</updated>
    <subtitle>The resulting entity body MAY be short and stout.</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 5.04</generator>

<entry>
    <title>DOSBox full screen crashes OS X Lion</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2012/03/dosbox-full-screen-crashes-os-x-lion.html" />
    <id>tag:little418.com,2012://8.441</id>

    <published>2012-03-27T21:57:44Z</published>
    <updated>2012-03-27T22:09:58Z</updated>

    <summary>Old games are a lot of fun to play. DOSBox makes it easier than ever to blow the dust off of an old game, pop the floppy disks into a USB floppy disk drive, and game like it&#8217;s 1990 again....</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
    <category term="games" label="games" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>Old games are a lot of fun to play. <a href="http://www.dosbox.com">DOSBox</a> makes it easier than ever to blow the dust off of an old game, pop the floppy disks into a <a href="http://www.amazon.com/External-3-5-Inch-Floppy-Drive-white/dp/B005XS62UQ/ref=sr_1_3?ie=UTF8&amp;qid=1332884919&amp;sr=8-3">USB floppy disk drive</a>, and game like it&#8217;s 1990 again.</p>

<p>That was until I upgraded to Mac OS X 10.7 Lion. Suddenly, when I hit alt + enter DOSBox crashed :( Well if you&#8217;re running into that issue, here&#8217;s the fix!</p>

<ol>
<li>Install DOSBox and run it once. Exit, or if you&#8217;re feeling mean hit alt + enter and let it crash out.</li>
<li>Edit <code>~/Library/DOSBox 0.74 Preferences</code> (updating the version number to whatever version you have installed, of course)</li>
</ol>

<pre class="brush: bash">$  vi ~/Library/Preferences/DOSBox\ 0.74\ Preferences</pre>
 1.  Scroll down to the <code>output</code> variable and updated it to use <code>opengl</code>. This switches the rendering engine to a less efficient but apparently more stable implementation.
<pre class="brush: bash">
...
fullresolution=original
windowresolution=original
output=opengl  #<--- change this line
autolock=true
sensitivity=100
...
</pre>

<ol>
<li>Save the file and enjoy your favorite old school game!
<img alt="theme_park_dosbox.png" src="http://little418.com/2012/03/27/theme_park_dosbox.png" width="642" height="424" class="mt-image-center"/></li>
</ol>

<div class="g-comments-for z13oyxoolm2bxjekn224exwiqruvtda0i"></div>
]]>
        

    </content>
</entry>

<entry>
    <title>Adding ops to your new freenode channel</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2012/01/adding-ops-to-your-new-freenode-channel.html" />
    <id>tag:little418.com,2012://8.438</id>

    <published>2012-01-11T23:05:09Z</published>
    <updated>2012-01-12T01:30:37Z</updated>

    <summary>So you&#8217;ve just registered a channel on irc.freenode.net for your group. No one wants a single point of failure, and you never know when you&#8217;ll win the lottery (or be hit by a bus) so you&#8217;d like to op your...</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>So you&#8217;ve just registered a channel on <a href="http://www.freenode.net">irc.freenode.net</a> for your group. No one wants a single point of failure, and you never know when you&#8217;ll win the lottery (or be hit by a bus) so you&#8217;d like to op your teammates. This way if anything happens to you (good or bad) your colleagues can kick troublemakers and keep the /topic fresh.</p>

<p>If you&#8217;re new to IRC interacting with nickserv and chanserv can be confusing at times. There are a ton of features many of which are laden with IRC jargon.</p>

<p>Here&#8217;s a step by step for adding your collaborators as operators to your channel:</p>

<ol>
<li>Each person that you&#8217;d like to op must be <a href="http://freenode.net/faq.shtml#nicksetup">registered with nickserv</a>.</li>
<li>If you haven&#8217;t already, <a href="http://blog.freenode.net/2008/04/registering-a-channel-on-freenode/">register your channel with chanserv</a><pre class="brush: java">/msg chanserv register ##bobs-awesome-channel</pre></li>
<li>Set op flags for each user. The little <code>o</code> gives them the ability to self op. The big <code>O</code> will cause them to be auto-oped upon joining the channel. This can be useful to keep troublemakers from acting up (since they know someone is watching them).
You can set only the ability to become an op: <pre class="brush: java">/msg chanserv flags ##bobs-awesome-channel bob<em>dole +o
(notice) Flags +o were set on bob</em>dole in ##bobs-awesome-channel.</pre>
Or you can set ops and auto-ops<pre class="brush: java">/msg chanserv flags ##bobs-awesome-channel bob<em>dole +oO
(notice) Flags +oO were set on bob</em>dole in ##bobs-awesome-channel.</pre></li>
<li>You can now verify that the user flags are set properly<pre class="brush: java">/msg chanserv flags ##bobs-awesome-channel
(notice) Entry Nickname/Host          Flags
(notice) ----- ---------------------- -----
(notice) 1     jenny<em>murphy           +votsriRfAF [modified 2 weeks ago]
(notice) 1     bob</em>dole               +oO [modified 7 seconds ago]
(notice) ----- ---------------------- -----
(notice) End of ##bobs-awesome-channel FLAGS listing.
</pre></li>
</ol>

<p>And you&#8217;re all done!</p>

<p>If you&#8217;ve only set the little <code>o</code> flag, your users must tell <code>chanserv</code> to temporarily turn them into operators when they need it. </p>

<pre class="brush: java">
/msg chanserv op ##bobs-awesome-channel
</pre>

<p>That&#8217;s all I have for now. Happy IRCing! :)</p>

<div class="g-comments-for z12iwtnpdlfufjcof04cclfrluuzfj54s1s"></div>
]]>
        

    </content>
</entry>

<entry>
    <title>The Google+ Platform 30 Second Experience</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2012/01/the-google-platform-30-second-experience.html" />
    <id>tag:little418.com,2012://8.436</id>

    <published>2012-01-03T19:20:29Z</published>
    <updated>2012-01-03T21:43:12Z</updated>

    <summary>It seems like life becomes busier and busier every year. Between longer hours at work and increased obligations elsewhere, who has time to try out a new API? It&#8217;s 2012. We only have 3 years to perfect the flying DeLorean!...</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
        <category term="APIs" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Google+" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="google" label="google+" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="json" label="json" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="platform" label="platform" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="rest" label="rest" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>It seems like life becomes busier and busier every year. Between longer hours at work and increased obligations elsewhere, who has time to try out a new API? It&#8217;s 2012. We only have 3 years to perfect the flying DeLorean! </p>

<p>You say you don&#8217;t even have 5 minutes to play with one of the <a href="https://developers.google.com/+/downloads">platform starter projects</a>? Well hopefully I can give you a taste of the API in the time you just spent reading this paragraph. You don&#8217;t even have to write any code, I promise. (Although I make no promises about inspiration to code that this may cause.)</p>

<p>Since we&#8217;ve already wasted 30 seconds babbling, let&#8217;s dive into the API already. The easiest way to see the Google+ platform in action is to use the <a href="https://code.google.com/apis/explorer/">API Explorer</a>. This tool provides point and click access to most of the APIs that Google offers including the REST APIs for Google+. </p>

<p>Since this may be your first time, we&#8217;ll keep it simple. Follow these steps to view your public Google+ profile.</p>

<ol>
<li>Navigate to the <a href="https://code.google.com/apis/explorer/">API Explorer</a>. To make an API call we must first select the plus service. On the left pane scroll down to and select the plus API. The middle columns will update to display the available versions and methods.
<img alt="api_explorer_1.png" src="http://little418.com/2012/01/03/api_explorer_1.png" width="296" height="401" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></li>
<li>Scanning through the available methods the profile.get method looks like a match, but it requires a userId, which we do not know. We can use the shortcut value of me, but we&#8217;ll need to authorize the API explorer to discover our userId. To do this make sure plus.me is selected from the drop down at the top of the window and click on the &#8216;Switch to Private Access&#8217; link. This will trigger an OAuth popup. Grant the API Explorer permission.
<a href="http://little418.com/2012/01/03/api_explorer_2.png"><img alt="api_explorer_2.png" src="http://little418.com/assets_c/2012/01/api_explorer_2-thumb-400x107-51.png" width="400" height="107" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></li>
<li>Now that the API Explorer can determine our userId, all we need to do is specify me for the userId and to execute the query.
<a href="http://little418.com/2012/01/03/api_explorer_3.png"><img alt="api_explorer_3.png" src="http://little418.com/assets_c/2012/01/api_explorer_3-thumb-400x246-53.png" width="400" height="246" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></li>
<li>Upon execution the bottom of the API explorer, the history pane, will display the results of our request. Assuming it was successful we&#8217;ll see the HTTP headers from request and response as well as a JSON representation of our public Google+ profile.
<a href="http://little418.com/2012/01/03/api_explorer_4.png"><img alt="api_explorer_4.png" src="http://little418.com/assets_c/2012/01/api_explorer_4-thumb-400x364-55.png" width="400" height="364" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></li>
</ol>

<p>Congratulations! If you read fast enough 1 or fewer minutes have incremented on your clock and you&#8217;re already using the Google+ APIs. During these four steps we&#8217;ve witnessed many important features of the core REST APIs that make up the Google+ platform. We&#8217;ve completed the <a href="https://developers.google.com/+/api/oauth">OAuth 2.0 dance</a> to access private information, your userId via the <a href="https://developers.google.com/+/api/oauth#oauth-scopes">plus.me scope</a>, and observed a fetch of your public profile.</p>

<p>Now that you&#8217;ve had a taste of the JSON, you know you want to go grab a <a href="https://developers.google.com/+/downloads">starter project</a>, right? :D</p>

<div class="g-comments-for z13vupyq3pzwzn4n3224exwiqruvtda0i"></div>
]]>
        

    </content>
</entry>

<entry>
    <title>Google+ Comments on your Static HTML Blog</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2011/12/google-comments-on-your-static-html-blog.html" />
    <id>tag:little418.com,2011://8.435</id>

    <published>2011-12-31T02:32:39Z</published>
    <updated>2012-01-03T21:37:25Z</updated>

    <summary>Synchronize Comments Our static HTML blog is pretty cool, but do you know what would make it cooler? Comments would. Discussions about entries can really bring a blog to life, but sadly they come at a cost. Not only do...</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
        <category term="APIs" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Google+" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="google" label="google" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="google" label="google+" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="javascript" label="javascript" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="platform" label="platform" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<h2>Synchronize Comments</h2>

<p>Our static HTML blog is pretty cool, but do you know what would make it cooler? Comments would. Discussions about entries can really bring a blog to life, but sadly they come at a cost. Not only do you need to worry about comments from spammers but you also have to expose potentially sensitive software to the outside world.</p>

<p>Fortunately for us, the Google+ public data APIs expose the comments on our activities. Since we&#8217;re already sharing our blog posts to Google+ we can use JavaScript to render the comments from the activity right in the blog entry. Not only does this offload the responsibility of spam control to Google, but it also allows us to retain our super simple static HTML blog.</p>

<h2>Experiment with the APIs</h2>

<p>Before we start writing code lets become comfortable with how the APIs behave. Google provides an API explorer, which is a great way to become familiar with APIs. You can find the API explorer here: <a href="https://code.google.com/apis/explorer/">https://code.google.com/apis/explorer/</a></p>

<p>We&#8217;ll use this tool to walk through the steps that our comments plugin will follow.</p>

<ol>
<li>On the left pane scroll down to and select the plus API. The updated view will now display the available methods in the third pane from the left. We can explore these methods and work out a flow for accessing the right comments.
<a href="http://little418.com/2011/12/30/api_explorer_1.png"><img alt="api_explorer_1.png" src="http://little418.com/2011/12/30/api_explorer_1.png" width="269" height="401" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></li>
<li>Scanning through the available methods the comments.list method looks perfect, but we need an activity ID to call it.
<a href="http://little418.com/2011/12/30/api_explorer_2.png"><img alt="api_explorer_2.png" src="http://little418.com/assets_c/2011/12/api_explorer_2-thumb-400x118-33.png" width="400" height="118" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></li>
<li>Just above the comments.list method we find an activities.list method. This will allow us to list our recent activities and determine their IDs for which we can list the comments.
<a href="http://little418.com/2011/12/30/api_explorer_3.png"><img alt="api_explorer_3.png" src="http://little418.com/assets_c/2011/12/api_explorer_3-thumb-400x77-35.png" width="400" height="77" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></li>
<li>It looks like we need one more piece of information to list our activities: our userId. The easiest way to determine your userId is to copy it out of your Google+ profile URL. 
<a href="http://little418.com/2011/12/30/profile.png"><img alt="profile.png" src="http://little418.com/assets_c/2011/12/profile-thumb-400x125-39.png" width="400" height="125" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></li>
<li>On the activities.list method paste in your userId and select the public collection. Clicking the execute button triggers the API call and renders the json response in the history pane at the bottom of the page.
<a href="http://little418.com/2011/12/30/api_explorer_4.png"><img alt="api_explorer_4.png" src="http://little418.com/assets_c/2011/12/api_explorer_4-thumb-400x552-37.png" width="400" height="552" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></li>
<li>The response object consists of some top level attributes and a collection of activities within the items array. Each entry in the items array has an activity ID. Copy the ID for your most recent entry.</li>
<li>We can now switch to the comments.list method and supply the activity ID that we just copied.
<a href="http://little418.com/2011/12/30/api_explorer_5.png"><img alt="api_explorer_5.png" src="http://little418.com/assets_c/2011/12/api_explorer_5-thumb-400x76-41.png" width="400" height="76" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></li>
<li>With a click of the execute button the history pane on the bottom will be populated with a list of comments associated with that activity. </li>
</ol>

<p>It looks like we&#8217;ve discovered our flow. We can implement a very simple comments integration by manually discovering the activity ID for our share on Google+ and then using JavaScript to fetch the comments associated with it. Once we&#8217;ve fetched the comments we can render them within the page. </p>

<h2>Registering Our Application</h2>

<p>Before we can use the APIs to access public data we must first register our application. Once we register our application we&#8217;ll receive an API key that we can use to make requests.</p>

<ol>
<li>Navigate to code.google.com&#8217;s API console: <a href="https://code.google.com/apis/console/">https://code.google.com/apis/console/</a></li>
<li>Create a new project using the project drop down menu
<img alt="console_1.png" src="http://little418.com/2011/12/30/console_1.png" width="306" height="359" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></li>
<li>Click on the &#8216;Services&#8217; link in the API Console menu and toggle the Google+ APIs to &#8216;on&#8217;
<a href="http://little418.com/2011/12/30/console_2.png"><img alt="console_2.png" src="http://little418.com/assets_c/2011/12/console_2-thumb-400x75-44.png" width="400" height="75" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></li>
<li>Click on the &#8216;API Access&#8217; link in the API Console menu to access the keys for your new application.</li>
<li>Below &#8216;Simple API Access&#8217; note your &#8216;API Key&#8217;. We will use this to access the public data APIs below.
<a href="http://little418.com/2011/12/30/console_3.png"><img alt="console_3.png" src="http://little418.com/assets_c/2011/12/console_3-thumb-400x128-46.png" width="400" height="128" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></li>
</ol>

<h2>Time to Code</h2>

<p>In our entries we&#8217;ll place a div with a special class. We&#8217;ll then use JavaScript to replace this placeholder div with the comments for that entry. Here&#8217;s an example of a div that our JavaScript will look for:</p>

<pre class="brush: html">
&lt;div class=&quot;g-comments-for z13zevjymuuge1zvl23lyv3a2n3owdxxd04&quot;&gt;&lt;/div&gt;
</pre>

<p>Our JavaScript will look for all divs on a page with the g-comments-for class. When it finds one it will fetch all of the comments for the activity whose ID is in the other class.</p>

<p>Create a new JavaScript file <code>comments.js</code> and source it from each blog entry.  Within the JavaScript file create a namespace for our functions, because we like to be tidy. Next specify our API key. We&#8217;ll need that to make out API calls.</p>

<pre class="brush: javascript">
var commentr = commentr || {};
var apiKey = "AIzaSyA-H-eBvhWOyyjIJ2bWeaf1XAn855s8IRN";
</pre>

<p>Find all of the <code>g-comment-for</code> divs and extract the ID</p>

<pre class="brush: javascript">
// search for g-comments-for classes
commentr.go = function() {
    var fetchElements = 
         document.getElementsByClassName('g-comments-for');
    for(var i=0; i&lt;fetchElements.length; i++) {
        var activityId = fetchElements[i].classList[1];
        commentr.fetchComments(activityId);
    }
}
</pre>

<p>Next, fetch the comments for each activity that we find. Since the Google APIs reside on a different domain name than our blog we&#8217;ll use the JSONP response format. For each response this will automatically call a method to inject the comments into our page.</p>

<pre class="brush: javascript">
// foreach fetch
commentr.fetchComments = function(activityId) {
    var fetchElement = document.createElement(&quot;script&quot;);
    fetchElement.src = &#39;https://www.googleapis.com/plus/v1/activities/&#39; +
        activityId + &#39;/comments?alt=json&amp;pp=1&amp;key=&#39; + apiKey 
        + &#39;&amp;callback=commentr.praseComments&#39;;
    document.body.appendChild(fetchElement);
}


// when fetch completes, parse the response and insert the records
commentr.praseComments = function(resposneJson) {
    var activity = resposneJson.items[0].inReplyTo[0];
    var comments = resposneJson.items;

    //find element to insert into
    var insertionElements = document.getElementsByClassName(&#39;g-comments-for &#39; +
        activity.id);
    var insertionElement = insertionElements[0];

    var newContents = &quot;&quot;;
    for(i=0; i&lt;comments.length; i++) {
        var actor = comments[i].actor;

        var commentBody = comments[i].object.content;

        //do the insertion
        newContents += &quot;&lt;dt&gt;&lt;a href=&#39;&quot; + actor.url + 
            &quot;&#39;&gt;&lt;img src=&#39;&quot; + actor.image.url + &quot;&#39; /&gt;&lt;/a&gt;&lt;/dt&gt;&quot; + 
            &quot;&lt;dd&gt;&lt;a href=&#39;&quot; + actor.url + &quot;&#39;&gt;&quot; + actor.displayName + 
            &quot;&lt;/a&gt;: &quot; + commentBody + &quot;&lt;/dd&gt;&quot;;

    }
    insertionElement.innerHTML = &quot;&lt;dl&gt;&quot; + newContents + 
        &quot;&lt;/dl&gt; &lt;p class=&#39;g-commentlink&#39;&gt;Please comment on the &lt;a href=&#39;&quot; + 
        activity.url + &quot;&#39;&gt;Google+ activity&lt;/a&gt;&lt;/p&gt;&quot;;   
}
</pre>

<p>And finally we need to add register our plugin to execute after the page loads.</p>

<pre class="brush: javascript">
// Append our program to the window.onload
document.addEventListener("DOMContentLoaded", commentr.go, false);
</pre>

<h2>Comments Integration in Action</h2>

<p>That was pretty easy, wasn&#8217;t it? Now lets see it in action.</p>

<p>Using the API explorer we can find the activity ID of our most recently public entry. In this case it&#8217;s <code>z13zevjymuuge1zvl23lyv3a2n3owdxxd04</code>. Go back to the HTML code for that entry and add the magic div that inserts the comments.</p>

<pre class="brush: html">&lt;div class=&quot;g-comments-for z13zevjymuuge1zvl23lyv3a2n3owdxxd04&quot;&gt;&lt;/div&gt;</pre>

<p>Reload the page and see the rendered comments!</p>

<p><a href="http://little418.com/2011/12/30/result.png"><img alt="result.png" src="http://little418.com/assets_c/2011/12/result-thumb-400x145-48.png" width="400" height="145" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></p>

<h2>What&#8217;s Next?</h2>

<p>Our comments plugin was very easy to write, but this simplicity comes at a cost. It&#8217;s quite brittle and requires us to use the API explorer to discover the activity ID for each entry that we share. A good companion to this plugin would be a tool which fetches our most recent activities and renders a div that we can paste into our entries. </p>

<h2>Code and Demo</h2>

<p>See it in action on <a href="http://bakingdisasters.com/blog/macaron.html">Baking Disasters</a></p>

<p>Access the code (without using copy and paste) on <a href="http://code.google.com/p/baking-disasters/source/browse/#git%2Fjavascript-comment-plugin">Google Project Hosting</a></p>

<div class="g-comments-for z125jb5yhq3dyfwe5224exwiqruvtda0i"></div>
]]>
        

    </content>
</entry>

<entry>
    <title>ERROR:  While executing gem ... (Zlib::GzipFile::Error) not in gzip format</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2011/12/error-while-executing-gem-zlibgzipfileerror-not-in-gzip-format.html" />
    <id>tag:little418.com,2011://8.432</id>

    <published>2011-12-14T02:54:40Z</published>
    <updated>2012-01-03T21:37:20Z</updated>

    <summary>One fine evening I was sitting in a Taiwanese café sipping some slightly too sweet tea. While I waited for my bite sized morsels of fried chicken to emerge from their sizzling oil bath, I decided to hack a bit...</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
        <category term="Ruby" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="gem" label="gem" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ruby" label="ruby" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="troubleshooting" label="troubleshooting" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>One fine evening I was sitting in a Taiwanese café sipping some slightly too sweet tea. While I waited for my bite sized morsels of fried chicken to emerge from their sizzling oil bath, I decided to hack a bit in Ruby.</p>

<p>I could not start immediately, though. I needed some gems to start on my intended task. I attempted to install a gem only to see it fail. I tried a different one. It failed with the same error. Something was amiss.</p>

<pre class="brush: bash">
$ gem install mysql2
ERROR:  While executing gem ... (Zlib::GzipFile::Error)
    not in gzip format
$
</pre>

<p>I immediately started to troubleshoot my ruby installation. Had I screwed it up somehow? I had just upgraded XCode.</p>

<p>After a few minutes of troubleshooting I figured out the problem. Ruby and gem were fine. My Internet connection was not. It had timed out and was again redirecting me to the terms of use page. Gem was trying to install the wifi terms of use for the cafe. This was why the gunzip failed ;) The solution involved pretty standard Internet connectivity troubleshooting:</p>

<ol>
<li>Open a web browser and navigate to http://www.google.com to trigger the terms of use page</li>
<li>Once I accepted the terms I cleared my DNS cache with this command on OS X Lion: <code>dscacheutil -flushcache</code></li>
<li>I ran gem again and it worked! </li>
</ol>

<pre class="brush: bash">
$  gem install mysql2
Building native extensions.  This could take a while...
Successfully installed mysql2-0.3.11
1 gem installed
Installing ri documentation for mysql2-0.3.11...
Installing RDoc documentation for mysql2-0.3.11...
</pre>
]]>
        

    </content>
</entry>

<entry>
    <title>2nd Generation Drobo and 3TB Hard Disks</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2011/11/2nd-generation-drobo-and-3tb-hard-disks.html" />
    <id>tag:little418.com,2011://8.430</id>

    <published>2011-11-26T02:25:30Z</published>
    <updated>2011-11-26T09:51:52Z</updated>

    <summary>I love my Drobo. I know it&#8217;s the yuppie version of a home raid array, but it&#8217;s quiet enough to keep in my living room and it looks like something out of Tron. Mine is a 2nd generation 4 bay...</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
        <category term="Hardware" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="drobo" label="drobo" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="hardware" label="hardware" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="troubleshooting" label="troubleshooting" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>I love my Drobo. I know it&#8217;s the yuppie version of a home raid array, but it&#8217;s quiet enough to keep in my living room and it looks like something out of Tron.</p>

<p>Mine is a 2nd generation 4 bay Drobo that I&#8217;ve been using for a couple years. It&#8217;s worked well enough that my partner and I managed to fill it up! No problem, I thought, I&#8217;ll just swing by Fry&#8217;s Electronics and pick up a new shiny 3TB disk, right? Wrong.</p>

<p>I pulled out a lowly 1TB disk, popped in the new 3TB one and saw a red blinky light :(  According to the docs, this indicates that my disk was dead on arrival. I refused to believe this. I thought, &#8220;This is a big drive, maybe I need to update the firmware?&#8221; It turned out to be a bit more complicated than this.</p>

<p>If your Drobo is blinking red on your brand new drive, follow these steps to fix it:</p>

<ol>
<li>Look at your Drobo Dashboard software. Does it look like something written in FoxPro or Tron? If it looks like Tron skip ahead to step 5. <a href="http://little418.com/2011/11/26/drobo-dash-1.jpg"><img alt="drobo-dash-1.jpg" src="http://little418.com/assets_c/2011/11/drobo-dash-1-thumb-600x146-28.jpg" width="600" height="146" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></li>
<li><strong>Upgrading Drobo Dashboard</strong>: Since you have the older, grayer Drobo Dashboard, there&#8217;s something you should know: it&#8217;s lying to you. It probably says your Drobo&#8217;s firmware is up to date. It&#8217;s wrong. To upgrade the firmware you must first upgrade the dashboard.</li>
<li>Navigate to Drobo&#8217;s <a href="http://www.drobo.com/support/updates.php">downloads page</a>. Download the appropriate software. In my case this was the software under &#8216;Drobo Gen 2&#8217; way down near the bottom of the page.</li>
<li>Install the new dashboard. The specific instructions will depend on your platform. It should be easy so I won&#8217;t go through the specifics here. After the installation you may need to reboot.</li>
<li><strong>Upgrading your Drobo&#8217;s Firmware</strong>: Since you&#8217;re now using the new shiny Drobo Dashboard reminiscent of Tron, you can upgrade the firmware :D  Simply fire up the Drobo Dashboard click on <em>All Devices</em> -> <em>Status</em> and follow the dialogs to upgrade to the latest firmware.</li>
</ol>

<p>After your Drobo reboots it will accept your new hard disk. In as little as a day the blinking LEDs will go solid green and you will be able to enjoy your increased storage capacity. Grats!</p>
]]>
        

    </content>
</entry>

<entry>
    <title>AsciiDoc Syntax Highlighting and MacVim</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2011/07/asciidoc-syntax-highlighting-and-macvim.html" />
    <id>tag:little418.com,2011://8.429</id>

    <published>2011-07-18T23:05:49Z</published>
    <updated>2012-01-03T21:39:40Z</updated>

    <summary>I&#8217;ve recently joined the world of AsciiDoc. I&#8217;m also the kind of developer who leverages every tool she can find. Since there is no IntelliJ plugin for AsciiDoc, it looks like I&#8217;ll have to settle for MacVim as my editor...</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
        <category term="Documentation" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="asciidoc" label="asciidoc" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="documentation" label="documentation" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="macvim" label="macvim" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="vim" label="vim" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>I&#8217;ve recently joined the world of <a href="http://www.methods.co.nz/asciidoc/">AsciiDoc</a>. I&#8217;m also the kind of developer who leverages every tool she can find. Since there is no IntelliJ plugin for AsciiDoc, it looks like I&#8217;ll have to settle for <a href="http://code.google.com/p/macvim/">MacVim</a> as my editor since it supports syntax highlighting of just about everything.</p>

<p>AsciiDoc is not a built in type for the MacVim syntax highlighter, and while AsciiDocs is nice enough to attempt to install the vim highlighting during setup, I still had to complete a few manual steps.</p>

<ol>
<li>Follow the <a href="http://www.methods.co.nz/asciidoc/INSTALL.html">installation instructions</a> through.</li>
<li>If it does not exist already, create a <code>~/.vim</code> folder for your user specific vim settings. </li>
</ol>

<pre class="brush: bash">
$ mkdir -p ~/.vim
</pre>

<ol>
<li>Copy the provided vim configuration files in their entirety from the distribution to your <code>~/.vim</code> folder </li>
</ol>

<pre class="brush: bash">
$ cp -r ~/tools/asciidoc-8.6.5/vim/* ~/.vim
</pre>

<ol>
<li>Fire up MacVim and test out the syntax highlighting by opening the AsciiDoc user manual. How meta is that? :)
<a href="http://little418.com/2011/07/18/asciidoc_meta.png"><img alt="asciidoc_meta.png" src="http://little418.com/assets_c/2011/07/asciidoc_meta-thumb-400x349-26.png" width="400" height="349" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></li>
</ol>

<p>Ta da! Now get hacking! I mean docing!</p>

<div class="g-comments-for z125ixd5fsrttt0hv04cclfrluuzfj54s1s"></div>
]]>
        

    </content>
</entry>

<entry>
    <title>Transferring your Number from AT&amp;T GoPhone to Google Voice</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2011/07/transfering-your-number-from-att-gophone-to-google-voice.html" />
    <id>tag:little418.com,2011://8.428</id>

    <published>2011-07-18T19:14:58Z</published>
    <updated>2012-01-03T21:39:13Z</updated>

    <summary><![CDATA[Transferring your number to Google Voice is the best way to leverage all of the features available. It&#8217;s pretty easy to transfer from most providers, but I ran into a few bumps when transferring my AT&amp;T prepaid GoPhone number. To...]]></summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
        <category term="Less technical" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="googlevoice" label="google voice" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="phone" label="phone" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>Transferring your number to Google Voice is the best way to leverage all of the features available. It&#8217;s pretty easy to transfer from most providers, but I ran into a few bumps when transferring my AT&amp;T prepaid GoPhone number. To make your transfer a little easier, here is what I learned.</p>

<ol>
<li>Realize that by transferring this number you will be forfeiting your remaining balance, so you may want to run it down first. Now that this disclaimer step is done, time to get to the actual steps!</li>
<li>Get your account number. This is not on the website or on any documentation you have. You must call 611 from your cell phone, dial 0 at the menu and speak to a customer service representative. Your account number will be a 12 digit number in the form of  ####-####-####.</li>
<li>Create a <a href="http://voice.google.com">Google Voice</a> account and opt to transfer your cell phone number.</li>
<li>During the flow when prompted for your cell phone information, provide the 12 digit account number in the field provided.</li>
<li>Sit back and wait for the transfer to happen.</li>
<li>If you&#8217;d like to use your handset as a forward target for Google Voice, you&#8217;ll need a new handset number. Once the transfer is complete, head on over to an AT&amp;T store and ask for a new number for your cell phone. I&#8217;ve found the least confusing way is to show up with no SIM card and ask for a new one. They&#8217;re free with a new GoPhone plan.</li>
</ol>

<p>And just like that you&#8217;re all set!</p>

<div class="g-comments-for z131uppwusa3zbyfy224exwiqruvtda0i"></div>
]]>
        

    </content>
</entry>

<entry>
    <title>yourdomain.com/+: Google+ Profile From Your Domain</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2011/07/yourdomaincom-google-profile-from-your-domain.html" />
    <id>tag:little418.com,2011://8.427</id>

    <published>2011-07-14T23:54:43Z</published>
    <updated>2012-01-03T21:39:08Z</updated>

    <summary>Google+ is pretty cool and getting cooler by the day. Circles are a great tool to connect with the people you&#8217;ve just met, but right now it&#8217;s a bit tricky to share your profile URL since they look something like...</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
        <category term="Google+" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="google" label="Google+" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="redirect" label="redirect" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>Google+ is pretty cool and getting cooler by the day. Circles are a great tool to connect with the people you&#8217;ve just met, but right now it&#8217;s a bit tricky to share your profile URL since they look something like this: <a href="https://plus.google.com/102817283354809142195">https://plus.google.com/102817283354809142195</a> (that&#8217;s my profile if you&#8217;re wondering)</p>

<p>A lot of us already have a short, witty personal domain name, and on these domains the /+ path is almost always available. Wouldn&#8217;t it be cool if we could just tell people to find us at <code>http://example.com/+</code>?</p>

<p>Now that we have the awesome idea, how do we implement it? This will differ a bit based on how your web site is set up and how much access you have there.</p>

<h2>With Apache .htaccess and mod_rewrite</h2>

<p>If you have access to write <code>.htaccess</code> files on your web host, this is a great solution. If you do not know what a <code>.htaccess</code> file is, skip to the next option :)</p>

<ol>
<li>Create a <code>.htaccess</code> file in the root directory of your domain with the following contents:</li>
</ol>

<pre class="brush: bash">
RewriteEngine On
RewriteRule ^/?\+$ https://plus.google.com/NUMBER_PART_OF_YOUR_PROFILE [R=301,L]
</pre>

<h2>On nginx</h2>

<p>There are indeed web servers other than Apache. One popular alternative is the awesome <a href="http://nginx.org/">nginx</a>. I&#8217;ve never had the pleasure of using it, but luckily <a href="https://plus.google.com/104108470253317688307">Chris Broadfoot</a> was kind enough to share this nginx rewrite rule.</p>

<ol>
<li>Drop this configuration into your <a href="http://blog.martinfjordvald.com/2010/07/nginx-primer/">server&#8217;s configuration</a> file.</li>
</ol>

<pre class="brush: javascript">
server {
  server_name yourdomain.com;
  location ^/?\+$ {
    rewrite ^ https://plus.google.com/NUMBER_PART_OF_YOUR_PROFILE permanent;
  }
}
</pre>

<h2>With JavaScript</h2>

<p>What if you lack either SSH access or are not comfortable with <code>mod_rewrite</code>? All is not lost! If your website allows you to paste in some JavaScript code you can still set up a redirext. This method is not optimal, though, because it has a way of confusing web crawlers and primitive web browsers. In any case, here are instructions:</p>

<ol>
<li>Create directory <code>+</code> in the root of your domain.</li>
<li>Add an <code>index.html</code> in that directory with the following contents:</li>
</ol>

<pre class="brush: html">
&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
window.location=&quot;https://plus.google.com/NUMBER_PART_OF_YOUR_PROFILE_URL&quot;;
&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;&lt;/body&gt;
&lt;/html&gt;
</pre>

<p>If you&#8217;d like to see this implemented on any other platforms, give me a hollar and I&#8217;ll add it :)</p>

<p>Thanks to:</p>

<ul>
<li><a href="http://parislemon.com/+">MG Siegler</a> for the idea!</li>
<li><a href="https://plus.google.com/u/1/106738194910565811651">Phillip Bradbury</a> for a stronger regex (because weak regex can cause sad results)</li>
</ul>

<div class="g-comments-for z12xuxi5ntb4gdvwt04cclfrluuzfj54s1s"></div>
]]>
        

    </content>
</entry>

<entry>
    <title>Rails 3 Validator List</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2011/03/rails-3-validator-list.html" />
    <id>tag:little418.com,2011://8.103</id>

    <published>2011-03-13T01:28:34Z</published>
    <updated>2011-03-23T04:15:00Z</updated>

    <summary>Ruby on Rails 3.0 expanded the set of available validators that can be passed to validates. Here they are in list form: :acceptance =&gt; Boolean. :confirmation =&gt; Boolean. :exclusion =&gt; { :in =&gt; Enumerable }. :inclusion =&gt; { :in =&gt;...</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
        <category term="Ruby" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>Ruby on Rails 3.0 expanded the set of available validators that can be passed to <code>validates</code>. Here they are in list form:</p>

<pre class="brush: ruby;">
:acceptance => Boolean.
:confirmation => Boolean.
:exclusion => { :in => Enumerable }.
:inclusion => { :in => Enumerable }.
:format => { :with => Regexp, :on => :create }.
:length => { :maximum => Fixnum }.
:numericality => Boolean.
:presence => Boolean.
:uniqueness => Boolean.
</pre>

<p>Source: the <a href="http://edgeguides.rubyonrails.org/3_0_release_notes.html#validations">Rails 3.0 release notes</a></p>
]]>
        

    </content>
</entry>

<entry>
    <title>SOAP vs REST</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2011/02/soap-vs-rest.html" />
    <id>tag:little418.com,2011://8.101</id>

    <published>2011-02-27T03:58:23Z</published>
    <updated>2012-01-03T21:39:05Z</updated>

    <summary>To understand SOAP and REST you must first understand web services. A web service is a method by which two pieces of software can communicate over a computer network, such as the Internet. SOAP and REST are two different approaches...</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
        <category term="APIs" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="essay" label="essay" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="rest" label="rest" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="soap" label="soap" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="webservices" label="web services" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>To understand SOAP and REST you must first understand web services. A web service is a method by which two pieces of software can communicate over a computer network, such as the Internet. SOAP and REST are two different approaches to satisfying this need. They differ in many ways such as their design philosophies, the concepts they define, the effort involved in using them and how they interact with HTTP.</p>

<p>SOAP, Simple Object Transfer Protocol, is built upon the design philosophy of remote procedure calls. In this way SOAP allows software to connect over a network and invoke behavior in other software. This ability solves a common problem in large-scale distributed software systems often found at large enterprises. On the other hand, REST, also known as Representational State Transfer, draws from very different design philosophies. It is based upon the concept of exchanging data. REST web services aim to exchange data as simply as possible by leveraging what is already available.</p>

<p>Since these two techniques differ in philosophy, they also differ in what they define and what they leave up to the implementer. Where SOAP defines a specific format for message exchange using XML, REST does not require any specific format to be used. REST does however constrain the actions performed by a service to those provided by the transfer protocol on which is operates. SOAP allows for any number of methods to be defined thereby providing more flexibility in the behaviors that clients can use.</p>

<p>Implementations of REST and SOAP are also very different. Despite its name, SOAP is a very complicated protocol governed by a set of formal specifications. Implementations often involve large toolkits and are assisted by other protocols like <a href="http://en.wikipedia.org/wiki/Wsdl">WSDL</a>. Additionally, since behavior is being invoked from a remote system, security is a major concern. Conversely, REST is a general concept that relies mainly on other existing standards to define itself. As a result REST web services can be implemented more easily without the need for REST specific toolkits.</p>

<p>While theoretically a web service can be implemented on top of any data transfer protocol, web services almost always use the ubiquitous HTTP. This is the same protocol your web browser uses to load web pages. REST web service designs attempt to harmonize with HTTP by using its existing vocabulary including both the verbs of HTTP, such as get and post, and the response codes, such as 400 for a user error. This allows REST web services to leverage existing HTTP reliability and scaling technologies quite easily. SOAP, however, is more concerned with consistency regardless of the data transfer protocol used. As a result it draws very little from existing HTTP concepts. SOAP instead defines its own vocabulary, which must be interpreted in addition to HTTP for an integration to function.</p>

<p>In the end SOAP and REST are very different approaches to solving slightly different sets of problems. REST based web services may be easier create and integrate; but some problems, such as system wide distributed transactions, can be more straightforward to implement using behavior centric models like SOAP.</p>
]]>
        

    </content>
</entry>

<entry>
    <title>Nearby Events on Eventbrite</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2011/02/nearby-events-on-eventbrite.html" />
    <id>tag:little418.com,2011://8.100</id>

    <published>2011-02-23T05:09:53Z</published>
    <updated>2011-03-23T02:14:25Z</updated>

    <summary>Welcome back! It&#8217;s time to continue exploring the Eventbrite APIs. Today we&#8217;ll write a very simple PHP page finds events very close to a specific latitude and longitude using the event_search API. What You Need Apache, or some similar HTTP...</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
        <category term="APIs" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="api" label="api" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="eventbrite" label="eventbrite" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="event_search" label="event_search" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="php" label="php" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>Welcome back!  </p>

<p>It&#8217;s time to continue exploring the <a href="http://eventbrite.com">Eventbrite</a> APIs. Today we&#8217;ll write a very simple PHP page finds events very close to a specific latitude and longitude using the <code>event_search</code> API.</p>

<h2>What You Need</h2>

<ul>
<li>Apache, or some similar HTTP server, running PHP 5 or higher</li>
<li>An <a href="http://www.eventbrite.com/api/key/">Eventbrite app key</a></li>
</ul>

<h2>Something to Start From</h2>

<p>We are not here to learn about writing forms in PHP, so to get us started here is the skeleton of an application to which we will add Eventbrite functionality. </p>

<pre class="brush: php">
&lt;?php
$app_key = "exampleApiKey"; //Supply your Eventbrite App Key here.  Remember to keep your App Key secure!

if (!(isset($_GET['latitude']) && isset($_GET['longitude']))) {
    //No coordinates are set. Display a very simple form to request a latitude and longitude
    ?>

    <form method="get">
        Latitude <input name="latitude" /> Longitude <input name="longitude" /> <input type="submit" />
    </form>

    &lt;?php

} else { //We have coordinates!  Lets get busy.
    //Normally we'd validate the input here, but we'll skip that ugly stuff
    $latitude = $_GET['latitude'];
    $longitude = $_GET['longitude'];
    print "I will search for events near lattitude $latitude longitude $longitude.<br /><br />\n";

}
</pre>

<p>Go ahead. Paste it into your editor and see how it works. On first load it will display a form with two fields: one for latitude and one for longitude. When submitted the page will print the supplied latitude and longitude values. </p>

<h2>Constructing the Query</h2>

<p>To fetch a list of events we must query the <a href="http://developer.eventbrite.com/doc/events/event_search/">event_search API</a>. All we need to do is to put together a URL that specifies our event search filters. For this tutorial we need to specify three parameters. Two of these come from our form: <code>latitude</code> and <code>longitude</code>. The third, <code>within</code> distance, we will hard code for the sake of this example. 1 mile seems like a reasonable <code>within</code> distance.</p>

<pre class="brush: php">
$request_url = "https://www.eventbrite.com/xml/event_search/?app_key=$app_key&latitude=$latitude&longitude=$longitude&within=1";
</pre>

<h2>Executing the Request and Interpreting the Response</h2>

<p>We can now use our favorite PHP HTTP client, cURL, to execute our freshly created API request.</p>

<p>After we execute the request we can parse and interpret the response. 
If the API request failed, we expect to see an <code>&lt;error&gt;</code> element at the root of the document. This element will contain an <code>&lt;error_message&gt;</code> element. We will display an error message if it is available.</p>

<p>Under normal conditions our API request will not contain an <code>&lt;error&gt;</code> element. In this case the response contains an <code>&lt;events&gt;</code> element with a single <code>&lt;summary&gt;</code> element and many <code>&lt;event&gt;</code> elements as children. We will display the total number of discovered events and list the titles of each event returned. Note that this API uses paging, so for popular areas not all event titles will be printed.</p>

<pre class="brush: php">
    //Next, lets hit the API with cURL
    $ch = curl_init($request_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response_body = curl_exec($ch);

    //We have our result in a string. Lets parse it.
    $xml = new SimpleXMLElement($response_body);

//    var_dump($xml); //Uncomment this line to see the entire parsed response

    //Check our parsed response for problems (such as an errors element). If there's an issue, let our user know.
    if ($xml->error_message) {
        //something is up here
        $error_message = $xml->error_message;
        print "Eventbrite responded with an error: $error_message<br /><br />\n";
    } else {
        //Things are looking good.  We can start by printing some of the response summary data
        print "I found " . $xml->summary->total_items . " nearby events.  Here are the titles from the first page of results: \n";

        //The bulk of our response is a list of events.  Let's display each event title.
        print "<ol>\n";
        foreach ($xml->event as $event) {
            print "<li>" . $event->title . "</li>\n";
        }
        print "</ol>\n";
    }


    //some boilerplate clean-up stuff
    curl_close($ch);
</pre>

<h2>The Result</h2>

<p>Visit this PHP page and supply the latitude and longitude for a location that is likely to have some upcoming events.  Try a latitude of 37.78 and a longitude of -122.4. This will search a populated part of San Francisco. </p>

<p>You should see something like this:</p>

<div style="border: 1px solid; margin: 10px; padding: 10px;">
I will search for events near lattitude 37.78 longitude -122.4.<br /><br />

Hitting <code>https://www.eventbrite.com/xml/event_search/?app_key=APP_KEY&latitude=37.78&longitude=-122.4&within=1 to find nearby events.</code><br /><br />

I found 369 nearby events. Here are the titles from the first page of results:<br /><br />

<ol><li>Manor West</li>
<li>Signature Series at MANOR WEST DJ Z-TRIP</li>
<li>&#8220;Signature Series&#8221; at Manor West ~ featuring Yolanda Be Cool: &#8220;We No Speak Americano&#8221;</li>
<li>Elite Session With STIMMING</li>
<li>FIP Seminar at San Francisco WestEd</li>
<li>Bridal Stylist Training & Certification</li>
<li>Image Consultant Certification Training</li>
<li>Learn Color Analysis Get Certified Too!</li>
<li>MAKEOVER YOU and Get the Date, Job, Money!!</li>
<li>City Nights Mardi Gras 2011 featuring DJ CLASS</li>
</ol>
</div>

<h2>Knock It Up a Notch</h2>

<p>We have a list of events within a mile of our latitude and longitude. If we happen to be carrying our GPS and are simply curious about what is going on around us, this may be useful, but there is so much more that we can do with this API. Here are a few ideas for features that you may wish to add to our search tool:</p>

<ul>
<li>Plot the nearby events on a <a href="http://code.google.com/apis/maps/documentation/javascript/basics.html">Google Map</a>. </li>
<li>Use <a href="http://dev.w3.org/geo/api/spec-source.html">HTML5 geolocation</a> to remove the need for that pesky latitude and longitude form.</li>
</ul>

<h2>All of the Code</h2>

<p>Did some of my instructions confuse you? Would you like to skip all my wordy explanation and just hack at the code?  If so, here is the complete code for this tutorial.</p>

<p>Enjoy!</p>

<pre class="brush: php">
&lt;?php
$app_key = "exampleApiKey"; //Supply your Eventbrite App Key here.  Remember to keep your App Key secure!

if (!(isset($_GET['latitude']) && isset($_GET['longitude']))) {
    //No coordinates are set. Display a very simple form to request a latitude and longitude
    ?>

    <form method="get">
        Latitude <input name="latitude" /> Longitude <input name="longitude" /> <input type="submit" />
    </form>

    &lt;?php

} else { //We have coordinates!  Lets get busy.
    //Normally we'd validate the input here, but we'll skip that ugly stuff
    $latitude = $_GET['latitude'];
    $longitude = $_GET['longitude'];
    print "I will search for events near lattitude $latitude longitude $longitude.<br /><br />\n";


    //First, we need to construct our request URL
    $request_url = "https://www.eventbrite.com/xml/event_search/?app_key=$app_key&latitude=$latitude&longitude=$longitude&within=1";

    print "Hitting <code>$request_url</code> to find nearby events.<br /><br />\n&#8221;;

    //Next, lets hit the API with cURL
    $ch = curl_init($request_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response_body = curl_exec($ch);

    //We have our result in a string. Lets parse it.
    $xml = new SimpleXMLElement($response_body);

//    var_dump($xml); //Uncomment this line to see the entire parsed response

    //Check our parsed response for problems (such as an errors element). If there&#8217;s an issue, let our user know.
    if ($xml->error_message) {
        //something is up here
        $error_message = $xml->error_message;
        print &#8220;Eventbrite responded with an error: $error_message<br /><br />\n&#8221;;
    } else {
        //Things are looking good.  We can start by printing some of the response summary data
        print &#8220;I found &#8221; . $xml->summary->total_items . &#8221; nearby events.  Here are the titles from the first page of results: \n&#8221;;

        //The bulk of our response is a list of events.  Let&#8217;s display each event title.
        print &#8220;<ol>\n&#8221;;
        foreach ($xml->event as $event) {
            print &#8220;<li>&#8221; . $event->title . &#8220;</li>\n&#8221;;
        }
        print &#8220;</ol>\n&#8221;;
    }


    //some boilerplate clean-up stuff
    curl_close($ch);
}
</pre>
]]>
        

    </content>
</entry>

<entry>
    <title>Getting Started With Eventbrite APIs</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2011/02/getting-started-with-eventbrite-apis.html" />
    <id>tag:little418.com,2011://8.99</id>

    <published>2011-02-19T06:43:13Z</published>
    <updated>2011-03-23T02:14:25Z</updated>

    <summary>Hello! It&#8217;s time for a bit of a departure from my usual blog structure. Instead of writing about a specific annoying error message and SEOing the heck out of it, I&#8217;ll be writing a short series of posts describing a...</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
        <category term="APIs" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="api" label="api" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="curl" label="cURL" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="eventbrite" label="eventbrite" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="example" label="example" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>Hello!</p>

<p>It&#8217;s time for a bit of a departure from my usual blog structure. Instead of writing about a specific annoying error message and SEOing the heck out of it, I&#8217;ll be writing a short series of posts describing a new set of APIs that I&#8217;m playing with: the <a href="http://eventbrite.com">Eventbrite</a> APIs.</p>

<p>The Eventbrite APIs are roughly <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer">RESTful</a>. This is very good news.  We can begin our exploration using off-the-shelf tools like command line <a href="http://en.wikipedia.org/wiki/CURL">cURL</a>.</p>

<p>First we&#8217;ll experiment with failure and success in searching for an event, a read operation.  Once we have a handle on reads, let&#8217;s create a new event. </p>

<h2>What You Need</h2>

<ul>
<li>Command line cURL (You already have this if you are on OS X or Linux.  Try <a href="http://www.cygwin.com/">Cygwin</a> if you are on Windows.)</li>
<li>An <a href="http://www.eventbrite.com/api/key/">Eventbrite app key</a></li>
<li>Your Eventbrite <a href="http://www.eventbrite.com/userkeyapi">user key</a> for creating data</li>
</ul>

<h2>Fail First</h2>

<p>To clearly understand success, it&#8217;s often importnat to fail at least once.  Understanding this failure makes it easier to identify success.</p>

<p>From the <a href="http://developer.eventbrite.com/doc/events/event_search/">event_search</a> reference documentation we can see that an <code>app_key</code> parameter is required.  Let us access the API without specifying one to see what happens.</p>

<pre class="brush: bash">
$  curl -i 'https://www.eventbrite.com/xml/event_search'
HTTP/1.1 200 OK
Server: nginx
Date: Sat, 19 Feb 2011 09:51:43 GMT
Content-Type: application/xml
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-cache, must-revalidate, no-cache="Set-Cookie", private
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Pragma: no-cache
Vary: Accept-Encoding

<error>
        <error_message>Please provide your Application Key in the URL as &quot;?app_key=&quot;.</error_message>
        <error_type>Application Key Error</error_type>
</error>
$ 
</pre>

<p>Did you notice anything interesting?  The response body is as expected, an xml document describing our missing <code>app_key</code>, but check out the HTTP response headers.  The status is <code>200 OK</code>.  You may have expected an HTTP 400 response of some kind since the request failed.  We now know that the API may respond indicating success even when there is a problem.  We cannot rely on the HTTP status in our application and must always parse the response body and check errors.</p>

<h2>Success in Search</h2>

<p>As we saw above, failing on purpose teaches us important lessons, but success is much more satisfying.  Let&#8217;s add our <code>api_key</code> into our query URL and observe success.</p>

<pre class="brush: bash">
$ curl -i 'https://www.eventbrite.com/xml/event_search?app_key=exampleApiKey'
HTTP/1.1 200 OK
Server: nginx
Date: Sat, 19 Feb 2011 10:05:10 GMT
Content-Type: application/xml
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-cache, must-revalidate, no-cache="Set-Cookie", private
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Pragma: no-cache
Vary: Accept-Encoding

<events>
    <summary>
        <filters>
        </filters>
        <first_event>12058066</first_event>
        <last_event>46957451</last_event>
        <num_showing>10</num_showing>
        <total_items>42114</total_items>
    </summary>
    <event>
        ... a very long list of events ...
    </event>
</events>
$
</pre>

<p>As we hoped, there is a long list of event elements in the response body.  The list of events is a bit arbitrary, since we did not specify any filters, but that is no surprise.  </p>

<p>Try some queries with filters and observe the narrowing of the response list.  Here are some URLs to get you started:</p>

<ul>
<li><code>https://www.eventbrite.com/xml/event_search?app_key=exampleApiKey&amp; keywords=google%20OR%20multimedia</code></li>
<li><code>https://www.eventbrite.com/xml/event_search?app_key=exampleApiKey&amp;postal_code=94107</code></li>
<li><code>https://www.eventbrite.com/xml/event_search?app_key=exampleApiKey&amp;date=today</code></li>
<li><code>https://www.eventbrite.com/xml/event_search?app_key=exampleApiKey&amp;count_only=true</code></li>
</ul>

<h2>Creating an Event </h2>

<p>Searching events is pretty powerful, but a proper application </p>

<pre class="brush: bash">
$  curl -i 'https://www.eventbrite.com/xml/event_new?app_key=exampleApiKey&user_key=exampleUserKey&title=test&description=testDescription&start_date=2012-12-31%2010:00:00&end_date=2013-01-01%2002:00:00&timezone=GMT+01'
HTTP/1.1 200 OK
Server: nginx
Date: Sat, 19 Feb 2011 10:43:46 GMT
Content-Type: application/xml
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: no-cache, must-revalidate, no-cache="Set-Cookie", private
Expires: Fri, 01 Jan 1990 00:00:00 GMT
Pragma: no-cache
Vary: Accept-Encoding

<process>
        <id>1341790331</id>
        <message>event_new : Complete </message>
        <method>(Draft)</method>
        <status>OK</status>
</process>
$ 
</pre>

<p>It looks like we&#8217;ve created an event!  You can see this event in your <a href="http://www.eventbrite.com/myevents">My Events</a> page.</p>

<p>You have probably already figured this out, but even though we made an HTTP GET request, which is supposed to be repeatable, be careful not to repeat this query as it will create additional events.</p>

<h2>Conclusion </h2>

<p>In just a few short minutes, without writing a single line of code, we have learned a lot about the Eventbrite API.  Taking care to look before we leap can save us countless hours down the road.</p>

<p>Armed with some new facts about the Eventbrite API, it&#8217;s time to fire up our favorite text editor or IDE.  You guessed right, it&#8217;s time to code!</p>
]]>
        

    </content>
</entry>

<entry>
    <title>PowerPoint 2008 for Mac Print Slide Backgrounds</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2010/12/powerpoint-2008-for-mac-print-slide-backgrounds.html" />
    <id>tag:little418.com,2010://8.98</id>

    <published>2010-12-06T23:20:14Z</published>
    <updated>2011-03-23T02:14:24Z</updated>

    <summary>Most of my entries are about the cryptic errors that I encounter while writing code or using some poorly documented engineering tool, but consumer products by Microsoft can sometimes be complicated too. Today I had a slide deck I was...</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
        <category term="Less technical" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="microsoft" label="Microsoft" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="powerpoint" label="PowerPoint" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>Most of my entries are about the cryptic errors that I encounter while writing code or using some <a href="http://xkcd.com/293/">poorly documented engineering tool</a>, but consumer products by Microsoft can sometimes be <a href="http://www.youtube.com/watch?v=xtEsSdP6sR8">complicated</a> too.  </p>

<p>Today I had a slide deck I was attempting to print on my black and white laser printer.  No problem, right?  Apparently now.  The background image for these slides were pretty important.  I walked to the printer and saw a mostly blank deck of slides.  I had a sad.  I searched around and could find on control that corresponded to the printing of slide backgrounds.</p>

<p>As it turns out selecting 'Output: color' (even for a black and white laser printer) is the setting I was looking for.</p>

<p>Just to review:</p>

<p><font class="Apple-style-span" style="font-size: 1.5625em; ">To print with backgrounds, use this setting</font></p>

<span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="ppt_backgrounds.jpg" src="http://little418.com/images/ppt_backgrounds.jpg" width="604" height="514" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span>

<p><font class="Apple-style-span" style="font-size: 1.5625em; ">To print with <strong>no</strong> backgrounds, use this setting</font></p>

<span class="mt-enclosure mt-enclosure-image" style="display: inline;"><img alt="ppt_no_backgrounds.jpg" src="http://little418.com/images/ppt_no_backgrounds.jpg" width="601" height="510" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></span>]]>
        
    </content>
</entry>

<entry>
    <title>Multiple Google Calendars on the iPad or iPhone</title>
    <link rel="alternate" type="text/html" href="http://little418.com/2010/11/multiple-google-calendars-on-the-ipad-or-iphone.html" />
    <id>tag:little418.com,2010://8.97</id>

    <published>2010-11-09T18:47:02Z</published>
    <updated>2012-01-03T21:38:59Z</updated>

    <summary>By default if you set up your Google account with your iDevice only your account&#8217;s main calendar will be displayed. If you make heavy use of shared calendars across many accounts (e.g. a personal calendar on your own domain and...</summary>
    <author>
        <name>Jennifer</name>
        
    </author>
    
        <category term="Less technical" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="calendar" label="calendar" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="google" label="google" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="idevice" label="iDevice" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://little418.com/">
        <![CDATA[<p>By default if you set up your Google account with your <a href="http://en.wikipedia.org/wiki/IDevice">iDevice</a> only your account&#8217;s main calendar will be displayed.  If you make heavy use of shared calendars across many accounts (e.g. a personal calendar on your own domain and a work calendar on your work domain), this can be quite a problem, but don&#8217;t worry!  It&#8217;s easy to fix.  We just need to do a little URL hax0ring,</p>

<ol>
<li>First, select a primary Google account.  This is the account that will rule them all in that we&#8217;ll be syncing your iDevice with it for calendaring.  For the sake of this tutorial we&#8217;ll call this primary account awesome@gmail.com.  <ul><li>If you wish to use push mail notifications, this is the only account you will be able to do that with so chose wisely.</li></ul></li>
<li>On all of your other Google accounts, log in and share your calendars with your primary account, awesome@gmail.com.  Read only sharing is sufficient.  If you&#8217;re unable to share your calendar to an outside domain, contact your Google Apps administrator for your domain.  They may need to <a href="http://www.google.com/support/calendar/bin/answer.py?hl=en&amp;answer=143754">enable this</a>.</li>
<li>From your primary account, awesome@gmail.com, use the <a href="http://calendar.google.com">web calendar interface</a> to verify that all of the calendars are successfully shared.</li>
<li>We&#8217;re almost there!  Just a few more steps.  Now <a href="http://www.google.com/support/mobile/bin/answer.py?hl=en&amp;answer=138740">configure your iDevice</a> to synchronize calendar with this gmail account.  <ul><li>You can optionally configure email and contacts synchronization at this time as well. </li><li>After a few minutes you should see your primary calendar on your iDevice, but none of the shared calendars (yet).</li></ul></li>
<li>Time for some l337 URL hax0ring.  Still logged into your primary account, awesome@gmail.com, go to this magic iDevice calendar configuration page: <a href="http://www.google.com/calendar/iphoneselect">http://www.google.com/calendar/iphoneselect</a>  You should see all of your shared calendars listed.  Check the checkbox for each calendar you&#8217;d like to appear on your iDevice. <ul><li>If your primary account is on a domain hosted by google, for example you&#8217;re really awesome@example.com where example.com is a Google Apps domain, go to this magic URL instead: http://www.google.com/calendar/hosted/example.com/iphoneselect substituting your hosted domain name for example.com</li></ul> <span class="mt-enclosure mt-enclosure-image" style="display: inline;"><a href="http://little418.com/images/iphone%20sync.png"><img alt="iphone sync.png" src="http://little418.com/assets_c/2010/11/iphone sync-thumb-398x650-30.png" width="398" height="650" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></a></span></li>
<li>You&#8217;re all done!  Wait about 10 minutes and the shared calendars should all appear. <br />
I bet you&#8217;re tired from all of that computer hacking.  You diserve a <a href="http://uncyclopedia.wikia.com/wiki/Tab">tab</a> for all your efforts.</li>
</ol>

<p><a href="http://www.google.com/support/forum/p/Calendar/thread?tid=3c4f4acf1e539f53&amp;hl=en">source</a></p>

<p><strong>Disclaimer</strong>: I don&#8217;t actually own the email address awesome@gmail.com, it&#8217;s just an example&#8230; an awesome example, but still an example.  If you&#8217;re awesome@gmail.com, sorry for the spam, but your email was just too awesome to resist for illustrative purposes.</p>
]]>
        

    </content>
</entry>

</feed>

