<?xml version="1.0" encoding="UTF-8"?> <rss
version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
><channel><title>Terence Eden has a Blog &#187; api</title> <atom:link href="http://shkspr.mobi/blog/index.php/tag/api/feed/" rel="self" type="application/rss+xml" /><link>http://shkspr.mobi/blog</link> <description>Mobiles, Shakespeare, Politics, Usability.</description> <lastBuildDate>Mon, 06 Feb 2012 16:31:09 +0000</lastBuildDate> <language>en</language> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.3.1</generator> <item><title>When is a URL not a URL?</title><link>http://shkspr.mobi/blog/index.php/2011/07/when-is-a-url-not-a-url/</link> <comments>http://shkspr.mobi/blog/index.php/2011/07/when-is-a-url-not-a-url/#comments</comments> <pubDate>Wed, 27 Jul 2011 11:37:57 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[/etc/]]></category> <category><![CDATA[usability]]></category> <category><![CDATA[api]]></category> <category><![CDATA[regex]]></category> <category><![CDATA[twitter]]></category> <category><![CDATA[urls]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=4271</guid> <description><![CDATA[Summary Twitter&#8217;s way of linking URLs is broken. It&#8217;s annoying to users, and a pain in the arse to developers. This quick post talks about the problem and offers a solution. I&#8217;ve raised a bug with Twitter and I hope you&#8217;ll star it as important to you. Preamble A common trope in programming classes is <a
href='http://shkspr.mobi/blog/index.php/2011/07/when-is-a-url-not-a-url/'>[...]</a>]]></description> <content:encoded><![CDATA[<h2>Summary</h2><p>Twitter&#8217;s way of linking URLs is broken.  It&#8217;s annoying to users, and a pain in the arse to developers.  This quick post talks about the problem and offers a solution.</p><p><a
href="http://code.google.com/p/twitter-api/issues/detail?id=2240">I&#8217;ve raised a bug with Twitter</a> and I hope you&#8217;ll star it as important to you.<br
/> <span
id="more-4271"></span></p><h2>Preamble</h2><p>A common trope in programming classes is &#8220;<a
href="http://www.regular-expressions.info/email.html">how do you detect valid email address</a>?&#8221;</p><p>It should be obvious, right?  A string of text, an @, a domain &#8211; probably ending in .com.<br
/> As it turns out, it&#8217;s not that simple.  &#8220;who+o&#8217;toole@invalid.museum&#8221; is a potentially valid address, for example.<br
/> There are literally thousands of ways to detect the potentially infinite variety of email addresses.</p><p>The same is true for URLs &#8211; and slavish adherence to guidelines is killing Twitter&#8217;s usefulness.</p><h2>The URL Matching Problem</h2><p>Which of these strings should be turned into hyperlinks?</p><pre>
www.bbc.co.uk

example.com

http://test

https://test.test

ftp://news.com
</pre><p>As it happens, Twitter only matches &#8220;https://test.test&#8221; and none of the others.</p><p><a
href="https://twitter.com/edent/status/96172785436590080"><img
src="http://shkspr.mobi/blog/wp-content/uploads/2011/07/URL-test-1.jpg" alt="" title="URL test 1" width="514" height="216" class="aligncenter size-full wp-image-4274" /></a></p><p>Twitter&#8217;s matching regex is, as far as I can tell, this</p><pre>If it starts with http:// or https:// and has a dot in it - it's a URL</pre><p>I think this is a serious weakness.  Twitter users are sharing URLs which their followers can&#8217;t click on &#8211; Twitter is also linking to URLs which don&#8217;t exist.</p><p>I&#8217;ve picked these examples more or less at random.<br
/> <a
href="https://twitter.com/ianvisits/status/82712842112991232"><img
src="http://shkspr.mobi/blog/wp-content/uploads/2011/07/URL-test-2.jpg" alt="" title="URL test 2" width="514" height="216" class="aligncenter size-full wp-image-4275" /></a></p><p><a
href="https://twitter.com/PeakChief/status/82722453767462912"><img
src="http://shkspr.mobi/blog/wp-content/uploads/2011/07/URL-test-3.jpg" alt="" title="URL test 3" width="514" height="216" class="aligncenter size-full wp-image-4276" /></a></p><h2>Solution?</h2><p>Much like the email regexes, I would take a much more lax approach.  Essentially, if it looks vaguely like a URL &#8211; link to it.</p><p>I would suggest the following rules:</p><ul><li>If it starts with a protocol &#8211; http:// ftp:// tel: etc &#8211; create a hyperlink.</li><li>If it starts with www. &#8211; create a hyperlink.</li><li>If it ends . then a <a
href="http://data.iana.org/TLD/tlds-alpha-by-domain.txt">valid TLD</a> &#8211; create a hyperlink.</li><li>If it contains a <a
href="http://data.iana.org/TLD/tlds-alpha-by-domain.txt">valid TLD</a> followed by a slash then some other characters &#8211; create a hyperlink.</li></ul><p>The &#8220;correct&#8221; method would then be for Twitter to perform an <a
href="http://en.wikipedia.org/wiki/HTTP#Request_methods">HTTP HEAD request</a> to see if the URL is potentially valid.  There are three drawbacks to this.</p><ol><li>It may place excessive load on Twitter&#8217;s servers to process and cache these requests.</li><li>The URL may be that of an Intranet site &#8211; and thus inaccessible to Twitter.</li><li>The URL may be valid but temporarily inaccessible.</li></ol><p>Regardless of the method, surely it&#8217;s inexcusable that &#8220;www.example.com&#8221; isn&#8217;t detected as a URL whereas &#8220;http://bork.bork.bork&#8221; is?</p><h2>ACTION!</h2><p>If you think Twitter&#8217;s approach to hyperlinks is wrong &#8211; please <a
href="http://code.google.com/p/twitter-api/issues/detail?id=2240">make your voice heard at the bug report</a>.</p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=4271&amp;md5=14fc56a48a7b728fe933b966dd9788cb" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2011/07/when-is-a-url-not-a-url/feed/</wfw:commentRss> <slash:comments>1</slash:comments> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=4271&amp;md5=14fc56a48a7b728fe933b966dd9788cb" type="text/html" /> </item> <item><title>Displaying Twitter Photos via Entities</title><link>http://shkspr.mobi/blog/index.php/2011/06/displaying-twitter-photos-via-entities/</link> <comments>http://shkspr.mobi/blog/index.php/2011/06/displaying-twitter-photos-via-entities/#comments</comments> <pubDate>Fri, 03 Jun 2011 15:43:19 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[mobile]]></category> <category><![CDATA[api]]></category> <category><![CDATA[code]]></category> <category><![CDATA[dabr]]></category> <category><![CDATA[howto]]></category> <category><![CDATA[php]]></category> <category><![CDATA[twitter]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=4150</guid> <description><![CDATA[Twitter has announced that it will soon open up a native photo sharing service. Rather than using an external service like Embed.ly to retrieve thumbnails, all the data is embedded within Twitter Entities. So, if you request a status using &#8220;include_entities=true&#8220;, you will be able to grab the image and display the thumbnail using the <a
href='http://shkspr.mobi/blog/index.php/2011/06/displaying-twitter-photos-via-entities/'>[...]</a>]]></description> <content:encoded><![CDATA[<p>Twitter has announced that it will soon open up a <a
href="http://groups.google.com/group/twitter-development-talk/browse_thread/thread/99b451ce5d8259ce#">native photo sharing service</a>.</p><p>Rather than using an external service like Embed.ly to retrieve thumbnails, all the data is embedded within <a
href="http://dev.twitter.com/pages/tweet_entities">Twitter Entities</a>.</p><p>So, if you request a status using &#8220;<em>include_entities=true</em>&#8220;, you will be able to grab the image and display the thumbnail using the following code.</p><div
class="geshi no php"><ol><li
class="li1"><div
class="de1"><span
class="kw2">function</span> twitter_get_media<span
class="br0">&#40;</span><span
class="re1">$status</span><span
class="br0">&#41;</span> <span
class="br0">&#123;</span></div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp;<span
class="kw1">if</span><span
class="br0">&#40;</span><span
class="re1">$status</span><span
class="sy0">-&gt;</span><span
class="me1">entities</span><span
class="sy0">-&gt;</span><span
class="me1">media</span><span
class="br0">&#41;</span> <span
class="br0">&#123;</span></div></li><li
class="li1"><div
class="de1">&nbsp;</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; <span
class="re1">$url</span> <span
class="sy0">=</span> <span
class="re1">$status</span><span
class="sy0">-&gt;</span><span
class="me1">entities</span><span
class="sy0">-&gt;</span><span
class="me1">media</span><span
class="br0">&#91;</span><span
class="nu0">0</span><span
class="br0">&#93;</span><span
class="sy0">-&gt;</span><span
class="me1">media_url_https</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">&nbsp;</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; <span
class="re1">$width</span> <span
class="sy0">=</span> <span
class="re1">$status</span><span
class="sy0">-&gt;</span><span
class="me1">entities</span><span
class="sy0">-&gt;</span><span
class="me1">media</span><span
class="br0">&#91;</span><span
class="nu0">0</span><span
class="br0">&#93;</span><span
class="sy0">-&gt;</span><span
class="me1">sizes</span><span
class="sy0">-&gt;</span><span
class="me1">thumb</span><span
class="sy0">-&gt;</span><span
class="me1">w</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; <span
class="re1">$height</span> <span
class="sy0">=</span> <span
class="re1">$status</span><span
class="sy0">-&gt;</span><span
class="me1">entities</span><span
class="sy0">-&gt;</span><span
class="me1">media</span><span
class="br0">&#91;</span><span
class="nu0">0</span><span
class="br0">&#93;</span><span
class="sy0">-&gt;</span><span
class="me1">sizes</span><span
class="sy0">-&gt;</span><span
class="me1">thumb</span><span
class="sy0">-&gt;</span><span
class="me1">h</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">&nbsp;</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; <span
class="re1">$media_html</span> <span
class="sy0">=</span> <span
class="st0">&quot;&lt;a href=<span
class="es0">\&quot;</span>&quot;</span> <span
class="sy0">.</span> <span
class="re1">$url</span> <span
class="sy0">.</span> <span
class="st0">&quot;<span
class="es0">\&quot;</span> target=&#39;_blank&#39;&gt;&quot;</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; <span
class="re1">$media_html</span> <span
class="sy0">.=</span> &nbsp;<span
class="st0">&quot;&lt;img src=<span
class="es0">\&quot;</span>&quot;</span> <span
class="sy0">.</span> <span
class="re1">$url</span> <span
class="sy0">.</span> <span
class="st0">&quot;:thumb<span
class="es0">\&quot;</span> width=<span
class="es0">\&quot;</span>&quot;</span> <span
class="sy0">.</span> <span
class="re1">$width</span> <span
class="sy0">.</span></div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span
class="st0">&quot;<span
class="es0">\&quot;</span> height=<span
class="es0">\&quot;</span>&quot;</span> <span
class="sy0">.</span> <span
class="re1">$height</span> <span
class="sy0">.</span> <span
class="st0">&quot;<span
class="es0">\&quot;</span> /&gt;&quot;</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; <span
class="re1">$media_html</span> <span
class="sy0">.=</span> <span
class="st0">&quot;&lt;/a&gt;&lt;br /&gt;&quot;</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp;</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; <span
class="kw1">return</span> <span
class="re1">$media_html</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp;<span
class="br0">&#125;</span> &nbsp; &nbsp; &nbsp; &nbsp;</div></li><li
class="li1"><div
class="de1"><span
class="br0">&#125;</span></div></li></ol></div><p>So, a tweet like this:<br
/> <style type='text/css'>#bbpBox_76360760606986241 a { text-decoration:none; color:#038543; }#bbpBox_76360760606986241 a:hover { text-decoration:underline; }</style><div
id='bbpBox_76360760606986241' class='bbpBox' style='padding:20px; margin:5px 0; background-color:#ACDED6; background-image:url(http://a1.twimg.com/images/themes/theme18/bg.gif); background-repeat:no-repeat'><div
style='background:#fff; padding:10px; margin:0; min-height:48px; color:#333333; -moz-border-radius:5px; -webkit-border-radius:5px;'><span
style='width:100%; font-size:18px; line-height:22px;'><a
href="http://twitter.com/search?q=%23Photos" title="#Photos">#Photos</a> on Twitter: taking flight <a
href="http://t.co/qbJx26r" rel="nofollow">http://t.co/qbJx26r</a></span><div
class='bbp-actions' style='font-size:12px; width:100%; padding:5px 0; margin:0 0 10px 0; border-bottom:1px solid #e6e6e6;'><img
align='middle' src='http://shkspr.mobi/blog/wp-content/plugins/twitter-blackbird-pie//images/bird.png' /><a
title='tweeted on 02/06/2011 18:53' href='http://twitter.com/#!/twitter/status/76360760606986241' target='_blank'>02/06/2011 18:53</a> via web<a
href='https://twitter.com/intent/tweet?in_reply_to=76360760606986241&related=https://twitter.com/edent' class='bbp-action bbp-reply-action' title='Reply'><span><em
style='margin-left: 1em;'></em><strong>Reply</strong></span></a><a
href='https://twitter.com/intent/retweet?tweet_id=76360760606986241&related=https://twitter.com/edent' class='bbp-action bbp-retweet-action' title='Retweet'><span><em
style='margin-left: 1em;'></em><strong>Retweet</strong></span></a><a
href='https://twitter.com/intent/favorite?tweet_id=76360760606986241&related=https://twitter.com/edent' class='bbp-action bbp-favorite-action' title='Favorite'><span><em
style='margin-left: 1em;'></em><strong>Favorite</strong></span></a></div><div
style='float:left; padding:0; margin:0'><a
href='http://twitter.com/intent/user?screen_name=twitter'><img
style='width:48px; height:48px; padding-right:7px; border:none; background:none; margin:0' src='http://a0.twimg.com/profile_images/1124040897/at-twitter_normal.png' /></a></div><div
style='float:left; padding:0; margin:0'><a
style='font-weight:bold' href='http://twitter.com/intent/user?screen_name=twitter'>@twitter</a><div
style='margin:0; padding-top:2px'>Twitter</div></div><div
style='clear:both'></div></div></div><br
/> Will render like this (in Dabr):<br
/> <img
src="http://shkspr.mobi/blog/wp-content/uploads/2011/06/Twitter-Dabr-Images.jpg" alt="Twitter Dabr Images" title="Twitter Dabr Images" width="317" height="528" class="aligncenter size-full wp-image-4154" /></p><h2>Notes</h2><p>This is very rough and ready proof of concept code.  Beware of the following:</p><ul><li>This will only take the first image from the tweet.</li><li>Only images are supported &#8211; I&#8217;m not sure how their proposed video sharing will work.</li><li>There&#8217;s no error checking.</li><li>In the above code, the https URL is used &#8211; if you want a non-SSL link, you&#8217;ll need to remove the &#8220;_https&#8221;</li></ul><p>Enjoy!</p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=4150&amp;md5=3e6ea664f76da8468cb1d87dd54edddd" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2011/06/displaying-twitter-photos-via-entities/feed/</wfw:commentRss> <slash:comments>3</slash:comments> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=4150&amp;md5=3e6ea664f76da8468cb1d87dd54edddd" type="text/html" /> </item> <item><title>A (Minor) Twitter Privacy Bug?</title><link>http://shkspr.mobi/blog/index.php/2011/05/a-minor-twitter-privacy-bug/</link> <comments>http://shkspr.mobi/blog/index.php/2011/05/a-minor-twitter-privacy-bug/#comments</comments> <pubDate>Mon, 09 May 2011 12:00:03 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[/etc/]]></category> <category><![CDATA[api]]></category> <category><![CDATA[https]]></category> <category><![CDATA[privacy]]></category> <category><![CDATA[security]]></category> <category><![CDATA[ssl]]></category> <category><![CDATA[twitter]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=4045</guid> <description><![CDATA[Quick Summary Twitter&#8217;s secure API hides the contents of the tweets you are reading. But it doesn&#8217;t hide the images of those you converse with. Raised as Issue 2175. A Bit More Detail Twitter has a secure (HTTPS) and insecure (HTTP) API. When calling the secure API, all the content of the returned message (tweets) <a
href='http://shkspr.mobi/blog/index.php/2011/05/a-minor-twitter-privacy-bug/'>[...]</a>]]></description> <content:encoded><![CDATA[<h2>Quick Summary</h2><p>Twitter&#8217;s secure API hides the contents of the tweets you are reading. But it doesn&#8217;t hide the images of those you converse with.</p><p><a
href="http://code.google.com/p/twitter-api/issues/detail?id=2175">Raised as Issue 2175</a>.</p><h2>A Bit More Detail</h2><p>Twitter has a secure (HTTPS) and insecure (HTTP) API.</p><p>When calling the secure API, all the content of the returned message (tweets) are encrypted.  Eavesdroppers only see the cipher-text &#8211; essentially garbage.</p><p>However, within that cipher-text are links to <em>insecure</em> resources.</p><p>For example, a user requesting my tweets will get an object which contains a link to my avatar image.</p><p>Twitter is currently returning the <em>insecure</em> link:</p><pre>"profile_image_url" :
    "http://a2.twimg.com/profile_images/1283757621/Sketch_Avatar.jpg"</pre><p>Twitter should be returning the <em>secure</em> link:</p><pre>"profile_image_url" :
    "https://si0.twimg.com/profile_images/1283757621/Sketch_Avatar.jpg"</pre><h2>Exploiting This Weakness</h2><p>A user (Anna) will request the <em>encrypted</em> text of my tweets<br
/> She then requests the <em>unencrypted</em> image.<br
/> An eavesdropper (Eve) is listening in on the connection between Anna and Twitter.</p><pre>Anna ----&gt;Eve----&gt;Twitter  (Secure request)
Anna &lt;----Eve&lt;----Twitter  (Secure response)</pre><p>When Anna makes the initial request to Twitter, the malicious Eve can&#8217;t see what they&#8217;re talking about.</p><ul><li>The request &#8220;http<strong>s</strong>://example.com/twitter/edent&#8221; is itself encrypted.  Eve only sees an encrypted request to example.com &#8211; not &#8220;twitter/edent</li><li>The response containing all the tweets is also encrypted</li></ul><pre>Anna ----&gt;Eve----&gt;Images  (insecure request)
Anna &lt;----Eve&lt;----Twitter  (insecure response)
</pre><p>Anna then makes the subsequent request for the twitter user&#8217;s image, a malicious user can see</p><ul><li>The URI of the request.</li><li>The content of the image.</li></ul><h2>Impact</h2><p>Truth is, this has a pretty low security impact.</p><ul><li>There is no way to determine a user&#8217;s name based on the URI for their image. (Unless you already have both).</li><li>An eavesdropper has no way of knowing if the image is from the timeline, a reply, a DM, a search, a retweet, or the public timeline.</li><li>Images may be locally cached by the user&#8217;s browser &#8211; so frequency analysis isn&#8217;t reliable.</li><li>A malicious user <em>could</em> alter the image in transit.</li></ul><p>Worst case scenario is that if a malicious man-in-the-middle knows which images relate to which Twitter users, they know the intercepted user has seen at least one tweet from that user.</p><p>Let&#8217;s say Anna is communicating with Bob.  Eve is trying to eavesdrop.<br
/> If Bob has never tweeted, and Eve sees repeated requests from Anna for Bob&#8217;s avatar, she may reasonably surmise that they are exchanging DMs.</p><h2>Overall</h2><p>This is a pretty low-impact privacy risk.<br
/> It can be fixed by Twitter&#8217;s API returning HTTPS URIs where possible.<br
/> In the meantime, developers can replace &#8220;http://a2.twimg.com/&#8221; with &#8220;https://si0.twimg.com&#8221;.</p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=4045&amp;md5=58b67a9f7c54e43b59a6489ce9e20d8b" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2011/05/a-minor-twitter-privacy-bug/feed/</wfw:commentRss> <slash:comments>1</slash:comments> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=4045&amp;md5=58b67a9f7c54e43b59a6489ce9e20d8b" type="text/html" /> </item> <item><title>Getting Images from a Foursquare Checkin</title><link>http://shkspr.mobi/blog/index.php/2011/03/getting-images-from-a-foursquare-checkin/</link> <comments>http://shkspr.mobi/blog/index.php/2011/03/getting-images-from-a-foursquare-checkin/#comments</comments> <pubDate>Tue, 15 Mar 2011 12:35:22 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[/etc/]]></category> <category><![CDATA[4SQ]]></category> <category><![CDATA[api]]></category> <category><![CDATA[bit.ly]]></category> <category><![CDATA[dabr]]></category> <category><![CDATA[FOURSQUARE]]></category> <category><![CDATA[programming]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=3749</guid> <description><![CDATA[&#8220;Oi!&#8221; shouted Whatleydude, &#8220;Get Dabr to show images from foursquare checkins!&#8221; &#8220;Righty-ho sir!&#8221; I said. I started coding furiously. Of course, things are never quite as simple as I first thought&#8230;. So, how do we go from http://4sq.com/fgIWov to ? 1 Expand the URL Get your Bit.ly API Key. http://api.bitly.com/v3/expand ?shortUrl=http://4sq.com/fgIWov &#038;login=YOUR_BIT_LY_USERNAME &#038;apiKey=YOUR_BIT_LY_API_KEY &#038;format=txt You <a
href='http://shkspr.mobi/blog/index.php/2011/03/getting-images-from-a-foursquare-checkin/'>[...]</a>]]></description> <content:encoded><![CDATA[<p>&#8220;Oi!&#8221; shouted <a
href="http://whatleydude.com/">Whatleydude</a>, &#8220;Get Dabr to show images from foursquare checkins!&#8221;<br
/> &#8220;Righty-ho sir!&#8221; I said.  I started coding furiously.  Of course, things are never quite as simple as I first thought&#8230;.</p><p>So, how do we go from <a
href="http://4sq.com/fgIWov">http://4sq.com/fgIWov</a><br
/> to<br
/> <img
src="http://playfoursquare.s3.amazonaws.com/derived_pix/NYI1TUY5OOMV53BB4QGK2JUBDYTR20QA13W4VTHM1U4XSAPB_300x300.jpg" alt="James' Foursquare Checkin Image" />?</p><h2>1 Expand the URL</h2><p>Get your <a
href="http://bit.ly/a/your_api_key/">Bit.ly API Key</a>.</p><pre>

http://api.bitly.com/v3/expand

   ?shortUrl=http://4sq.com/fgIWov
   &#038;login=YOUR_BIT_LY_USERNAME
   &#038;apiKey=YOUR_BIT_LY_API_KEY
   &#038;format=txt
</pre><p>You can, if you prefer, get the info back in JSON or XML. See the <a
href="http://code.google.com/p/bitly-api/wiki/ApiDocumentation#/v3/expand">Bit.ly API Expand Documentation</a>.</p><h2>2 The Foursquare URL</h2><p>Bit.ly gives us the URL which includes a checkin ID and a signature.</p><pre>

http://foursquare.com/edent/checkin/4d7e5b4f9df3f04d7400c394

   ?s=afH3jJg3L9HpLqVIwiqp-YpNL5k
</pre><h2>3 The Foursquare API Call</h2><p>From this, we construct an API call to Foursquare.  It looks like this</p><pre>

https://api.foursquare.com/v2/checkins/4d7e5b4f9df3f04d7400c394

   ?signature=afH3jJg3L9HpLqVIwiqp-YpNL5k
   &#038;oauth_token=YOUR_FOURSQUARE_OAUTH_TOKEN
</pre><p><strong>NOTE</strong> the Foursquare URL says <em>?s=</em> whereas the API call requires <em>?signature=</em><br
/> That caused me more frustration than it should&#8230;</p><p>Getting your OAuth token is a little cumbersome &#8211; follow the steps at the <a
href="http://developer.foursquare.com/docs/oauth.html">Foursquare Developers site</a>.</p><h2>4 The JSON Response</h2><p>I&#8217;ll cut the cruft out of here, so you only see what you need to display images.<br
/> The response gives us the link to the full sized image &#8211; as well as several different sizes should you wish to display thumbnails.</p><div
class="geshi no json"><ol><li
class="li1"><div
class="de1">{</div></li><li
class="li1"><div
class="de1">&nbsp; &quot;meta&quot;:{</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp;&quot;code&quot;:200</div></li><li
class="li1"><div
class="de1">&nbsp; },</div></li><li
class="li1"><div
class="de1">&nbsp; &quot;response&quot;:{</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp;&quot;checkin&quot;:{</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; },</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp;&#8230;</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp;&quot;photos&quot;:{</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &quot;count&quot;:1,</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &quot;items&quot;:[</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;{</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;id&quot;:&quot;4d7e5b4f9df3f04d7400c394&quot;,</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;createdAt&quot;:1300184596,</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;url&quot;:&quot;http://playfoursquare.s3.amazonaws.com/pix/A.jpg&quot;,</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &quot;sizes&quot;:{</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;count&quot;:4,</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;items&quot;:[</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;url&quot;:&quot;http://playfoursquare.s3.amazonaws.com/pix/B.jpg&quot;,</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;width&quot;:720,&quot;height&quot;:540</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;url&quot;:&quot;http://playfoursquare.s3.amazonaws.com/derived_pix/C.jpg&quot;,</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;width&quot;:300,&quot;height&quot;:300</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;url&quot;:&quot;http://playfoursquare.s3.amazonaws.com/derived_pix/D.jpg&quot;,</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;width&quot;:100,&quot;height&quot;:100</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;url&quot;:&quot;http://playfoursquare.s3.amazonaws.com/derived_pix/E.jpg&quot;,</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;width&quot;:36,</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&quot;height&quot;:36</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;]</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; },</div></li></ol></div><h2>5 Gotchas</h2><p>Again, nothing in life is easy.  Not all foursquare checkins have an image associated with them.  In which case, we can do one of three things.</p><ol><li>Display no image</li><li>Display the user&#8217;s avatar &#8211; if it&#8217;s public</li><li>Display an image of the venue &#8211; or one of the icons associated with it.</li></ol><h2>6 Embed.ly</h2><p>Dabr uses the <a
href="http://embed.ly/">awesome Embedly service</a>.  Rather than having hundreds of different regular expressions and API calls to get embedded images, Embed.ly gives us a single end point to call.<br
/> So, rather than rewrite huge chunks of Dabr&#8217;s code, I&#8217;ve submitted this to the clever-clogs behind Embed.ly &#8211; that way, everyone can benefit.</p><p>Any questions, comments, or clarifications &#8211; please let me know in the comments box.</p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=3749&amp;md5=8814e78d3d7a091ede6c32915214bf4e" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2011/03/getting-images-from-a-foursquare-checkin/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=3749&amp;md5=8814e78d3d7a091ede6c32915214bf4e" type="text/html" /> </item> <item><title>Share Android Apps on Twitter (or anywhere else)</title><link>http://shkspr.mobi/blog/index.php/2010/07/share-android-apps-on-twitter-or-anywhere-else/</link> <comments>http://shkspr.mobi/blog/index.php/2010/07/share-android-apps-on-twitter-or-anywhere-else/#comments</comments> <pubDate>Tue, 20 Jul 2010 09:41:43 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[mobile]]></category> <category><![CDATA[android]]></category> <category><![CDATA[api]]></category> <category><![CDATA[sdk]]></category> <category><![CDATA[sharing]]></category> <category><![CDATA[sharing is caring]]></category> <category><![CDATA[twitter]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=2172</guid> <description><![CDATA[I attended the Mobile Monday meeting &#8220;200,000 Apps &#8211; Where&#8217;s Mine&#8221; last night. One thing that became clear is that apps don&#8217;t do a very good job of promoting themselves. One crippling problems with most app stores is that there&#8217;s no (easy) way to share an app with a friend. Here&#8217;s some basic code for <a
href='http://shkspr.mobi/blog/index.php/2010/07/share-android-apps-on-twitter-or-anywhere-else/'>[...]</a>]]></description> <content:encoded><![CDATA[<p>I attended the Mobile Monday meeting &#8220;<a
href="http://www.ibegyourparton.co.uk/2010/07/20/mobile-monday-london-write-up-%E2%80%93-%E2%80%9C200000-apps-where%E2%80%99s-mine%E2%80%9D/" class="broken_link">200,000 Apps &#8211; Where&#8217;s Mine</a>&#8221; last night.<br
/> One thing that became clear is that apps don&#8217;t do a very good job of promoting themselves.  One crippling problems with most app stores is that there&#8217;s no (easy) way to share an app with a friend.</p><p>Here&#8217;s some basic code for an Android app which will post the URL of your app to Twitter.  Stick it in a button or menu item for easy sharing.</p><div
class="geshi no java"><ol><li
class="li1"><div
class="de1"><span
class="kw3">String</span> twitterUri = <span
class="st0">&quot;http://m.twitter.com/?status=&quot;</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1"><span
class="kw3">String</span> marketUri = Uri.<span
class="me1">encode</span><span
class="br0">&#40;</span><span
class="st0">&quot;http://example.com/?q=app&amp;amp;title=test&quot;</span><span
class="br0">&#41;</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">Intent shareOnTwitterIntent = <span
class="kw2">new</span> Intent<span
class="br0">&#40;</span>Intent.<span
class="me1">ACTION_VIEW</span>, Uri.<span
class="me1">parse</span><span
class="br0">&#40;</span>twitterUri + marketUri<span
class="br0">&#41;</span><span
class="br0">&#41;</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">startActivity<span
class="br0">&#40;</span>shareOnTwitterIntent<span
class="br0">&#41;</span><span
class="sy0">;</span></div></li></ol></div><p>Some important things to note.</p><ol><li>This is set to post to the <em>mobile </em>version of Twitter.  Your user is on a phone &#8211; don&#8217;t direct them to a site that won&#8217;t work on their device.</li><li>The second string is <a
href="http://en.wikipedia.org/wiki/Percent-encoding">URI encoded</a>.</li><li>Consider if you want to post a &#8220;market://&#8221; link.  I would advise against it.  Twitter won&#8217;t render it as a link and, even if it did, 90% of users won&#8217;t be able to click on it.  Make it a link that will direct desktop users to your website, mobile users to a mobile friendly site and Android users direct to the market.</li></ol><p>Facebook also has an <a
href="http://www.facebook.com/share/">API</a> for this sort of sharing.</p><pre>

http://m.facebook.com/sharer.php?u=example.com&#038;t=test
</pre><p>Again, it points to the mobile site and needs to be URL encoded.</p><p>Happy sharing!</p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=2172&amp;md5=53bfecec5b40f562ee7c4422e0e41d66" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2010/07/share-android-apps-on-twitter-or-anywhere-else/feed/</wfw:commentRss> <slash:comments>3</slash:comments> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=2172&amp;md5=53bfecec5b40f562ee7c4422e0e41d66" type="text/html" /> </item> <item><title>Android Tutorial &#8211; Clickable Widgets</title><link>http://shkspr.mobi/blog/index.php/2010/07/android-tutorial-clickable-widgets/</link> <comments>http://shkspr.mobi/blog/index.php/2010/07/android-tutorial-clickable-widgets/#comments</comments> <pubDate>Mon, 12 Jul 2010 10:09:42 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[/etc/]]></category> <category><![CDATA[mobile]]></category> <category><![CDATA[android]]></category> <category><![CDATA[api]]></category> <category><![CDATA[browser]]></category> <category><![CDATA[sdk]]></category> <category><![CDATA[tutorial]]></category> <category><![CDATA[widget]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=2149</guid> <description><![CDATA[Another quick Android tutorial. I couldn&#8217;t find an easy or correct method of launching a browser when you click on a homescreen widget. Well, here it is&#8230; public class clickWidget extends AppWidgetProvider &#123; @Override public void onUpdate&#40; Context context, AppWidgetManager appWidgetManager, int&#91;&#93; appWidgetIds &#41; &#123; RemoteViews remoteViews = &#160; &#160;new RemoteViews&#40; context.getPackageName&#40;&#41;, R.layout.widget &#41;; remoteViews.setImageViewResource&#40;R.id.ImageView01, <a
href='http://shkspr.mobi/blog/index.php/2010/07/android-tutorial-clickable-widgets/'>[...]</a>]]></description> <content:encoded><![CDATA[<p>Another quick Android tutorial.  I couldn&#8217;t find an easy or correct method of launching a browser when you click on a homescreen widget.  Well, here it is&#8230;</p><div
class="geshi no java"><ol><li
class="li1"><div
class="de1"><span
class="kw2">public</span> <span
class="kw2">class</span> clickWidget <span
class="kw2">extends</span> AppWidgetProvider</div></li><li
class="li1"><div
class="de1"><span
class="br0">&#123;</span></div></li><li
class="li1"><div
class="de1">@Override</div></li><li
class="li1"><div
class="de1"><span
class="kw2">public</span> <span
class="kw4">void</span> onUpdate<span
class="br0">&#40;</span> <span
class="kw3">Context</span> context, AppWidgetManager appWidgetManager, <span
class="kw4">int</span><span
class="br0">&#91;</span><span
class="br0">&#93;</span> appWidgetIds <span
class="br0">&#41;</span></div></li><li
class="li1"><div
class="de1"><span
class="br0">&#123;</span></div></li><li
class="li1"><div
class="de1">RemoteViews remoteViews =</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp;<span
class="kw2">new</span> RemoteViews<span
class="br0">&#40;</span> context.<span
class="me1">getPackageName</span><span
class="br0">&#40;</span><span
class="br0">&#41;</span>, R.<span
class="me1">layout</span>.<span
class="me1">widget</span> <span
class="br0">&#41;</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">remoteViews.<span
class="me1">setImageViewResource</span><span
class="br0">&#40;</span>R.<span
class="me1">id</span>.<span
class="me1">ImageView01</span>, drawableResourse<span
class="br0">&#41;</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">&nbsp;</div></li><li
class="li1"><div
class="de1">ComponentName myWidget =</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp;<span
class="kw2">new</span> ComponentName<span
class="br0">&#40;</span> context, clickWidget.<span
class="kw2">class</span> <span
class="br0">&#41;</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">&nbsp;</div></li><li
class="li1"><div
class="de1"><span
class="co1">// Create an Intent to launch Browser</span></div></li><li
class="li1"><div
class="de1">Intent intent =</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp;<span
class="kw2">new</span> Intent<span
class="br0">&#40;</span></div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp; &nbsp; Intent.<span
class="me1">ACTION_VIEW</span>, Uri.<span
class="me1">parse</span><span
class="br0">&#40;</span><span
class="st0">&quot;http://example.com&quot;</span><span
class="br0">&#41;</span></div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp;<span
class="br0">&#41;</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">PendingIntent pendingIntent =</div></li><li
class="li1"><div
class="de1">&nbsp; &nbsp;PendingIntent.<span
class="me1">getActivity</span><span
class="br0">&#40;</span>context, <span
class="nu0">0</span>, intent, <span
class="nu0">0</span><span
class="br0">&#41;</span><span
class="sy0">;</span> &nbsp; &nbsp;</div></li><li
class="li1"><div
class="de1">&nbsp;</div></li><li
class="li1"><div
class="de1">remoteViews.<span
class="me1">setOnClickPendingIntent</span><span
class="br0">&#40;</span>R.<span
class="me1">id</span>.<span
class="me1">ImageView01</span>, pendingIntent<span
class="br0">&#41;</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1">appWidgetManager.<span
class="me1">updateAppWidget</span><span
class="br0">&#40;</span> myWidget, remoteViews<span
class="br0">&#41;</span><span
class="sy0">;</span></div></li><li
class="li1"><div
class="de1"><span
class="br0">&#125;</span></div></li></ol></div><p>I&#8217;ve used this as the basis of a demo widget &#8211; &#8220;MI5 Terror Threat Level&#8221;.  The widget displays the UK&#8217;s Threat Level on your homescreen.  Clicking on it takes you to the <a
href="https://www.mi5.gov.uk/output/threat-levels.html">MI5 page discussing the threat level</a>.</p><p>The threat level is determined by parsing the <a
href="https://www.mi5.gov.uk/output/threat-level-rss.html">RSS that the security services so helpfully provide</a>.  At the moment, the widget keeps a local copy of the graphics because the <a
href="http://www.mi5.gov.uk/UKThreatLevel/UKThreatLevel.xml">RSS feed</a> contains references to &#8220;localhost&#8221; images.</p><p>You can download the widget by scanning in this QR code.<br
/><div
id="attachment_2155" class="wp-caption aligncenter" style="width: 174px"><img
src="http://shkspr.mobi/blog/wp-content/uploads/2010/07/mi5.png" alt="MI5 Widget - QR Code" title="MI5 Widget - QR Code" width="164" height="164" class="size-full wp-image-2155" /><p
class="wp-caption-text">MI5 Widget - QR Code</p></div></p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=2149&amp;md5=f83e3b51b0d2716a933f7ad8c181a888" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2010/07/android-tutorial-clickable-widgets/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=2149&amp;md5=f83e3b51b0d2716a933f7ad8c181a888" type="text/html" /> </item> <item><title>Twitter API &#8211; pagination and IDs</title><link>http://shkspr.mobi/blog/index.php/2010/06/twitter-api-pagination-and-ids/</link> <comments>http://shkspr.mobi/blog/index.php/2010/06/twitter-api-pagination-and-ids/#comments</comments> <pubDate>Sun, 27 Jun 2010 07:54:36 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[/etc/]]></category> <category><![CDATA[api]]></category> <category><![CDATA[dabr]]></category> <category><![CDATA[twitter]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=2121</guid> <description><![CDATA[Looking for some Twitter API help.  Bit of a geeky post, this&#8230; Pagination is the act of splitting data into logical  pages. Suppose I had a list of item, numbered 0 &#8211; 99.  If I want 20 items per page, it&#8217;s trivial to see that pagination looks like: p1 = 0-19 p2 = 20-40 p3 <a
href='http://shkspr.mobi/blog/index.php/2010/06/twitter-api-pagination-and-ids/'>[...]</a>]]></description> <content:encoded><![CDATA[<p>Looking for some Twitter API help.  Bit of a geeky post, this&#8230;</p><p>Pagination is the act of splitting data into logical  pages. Suppose I had a list of item, numbered 0 &#8211; 99.  If I want 20 items per page, it&#8217;s trivial to see that pagination looks like:</p><pre>p1 = 0-19
p2 = 20-40
p3 = 41-61
p4 = 62-82
p5 = 83-99
</pre><p>If I wanted to start at, say, page 55 &#8211; pagination would look like:</p><pre>p1 = 55-75
p2 = 76-96
p3 = 97-99</pre><p>Easy, right?  So why am I telling you this?</p><h2>Twitter Timeline</h2><p>Imagine that those items are Twitter Status ID.  Each one represents a tweet in your timeline.</p><p>Twitter will allow us to &#8220;page&#8221; back and forth through our timeline. If we say status ID 80 is the most recent post in our timeline, and we want to see 20 tweets at a time, pagination would look like this.</p><pre>p1 = 80-60
p2 = 60-40
... etc.</pre><p>Normally, that would be fine.</p><p>The only issue is that friends are posting <em>all the time</em>.  Imagine we start with tweets 80-60.  We go to page 2, but in the meantime, 5 new tweets have been made.</p><pre>p1 = 80-60
p2 = 65-45</pre><p>The user sees 5 tweets she has already read.  Not desirable.</p><p>If 20 tweets had been made before clicking on the &#8220;next&#8221; button, this is what happens.</p><pre>p1 = 80-60
p2 = 80-60</pre><h2>Max_ID To The Rescue (AKA, the easy bit)</h2><p>Luckily, Twitter allows us to use a max_id parameter in our API calls.  This says &#8220;Get the tweets <strong>older</strong> than this number.&#8221;</p><pre>http://api.twitter.com/1/statuses/home_timeline.json?max_id=123465789</pre><p>So, using max_id we can ensure that the user never has to read the same tweet twice.  Instead of dumbly using pages, we call the specific tweets we want.</p><pre><span style="text-decoration: line-through;">p1</span> max_id=80 = 80-60</pre><pre><span style="text-decoration: line-through;">p2</span> max_id=60 = 60-40</pre><p>Easy!  We just use the oldest tweet on the page as the max_id parameter when we call the next page.</p><h2>Looking To The Future (AKA, where it all goes horribly wrong)</h2><p>So far, we&#8217;ve looked at stepping back in time.  Seeing older tweets.  Suppose we want to see newer tweets?</p><p>Twitter provides us with a since_id parameter for API calls.  This says &#8220;Get the tweets <strong>newer</strong> than this number.&#8221;</p><p>Unfortunately, it doesn&#8217;t work.  Well, it <em>works</em> but not the way I expected it to!</p><p>Suppose our user is deep down in her tweets, this is how I would expect since_id to work</p><pre>max_id=60  = 60-40</pre><pre> (So, let's show any more recent tweets)</pre><pre>since_id=60 = 80-60</pre><p>We see the 20 tweets that occured <em>since</em> the since_id.  Right?  Wrong!  This is what happens?</p><pre>max_id=60  = 60-40</pre><pre>(So, let's show any more recent tweets)</pre><pre>since_id=60 = 100-80</pre><p><strong>What?</strong></p><h2>An Explanation</h2><p>The since_id retrieves tweets <em>starting with the most recent</em>.  It stops when it reaches the since_id.</p><p>I don&#8217;t know the max_id that I&#8217;m looking for, so I can&#8217;t call that.</p><p>I could call the most recent 200 tweets and look for the 20 I need.  That&#8217;s wasteful in terms of bandwidth and processing &#8211; there&#8217;s also no guarantee that the since_id will be in there.</p><p>So, I have a problem.  The &#8220;Older&#8221; link in my Twitter application will work.  The &#8220;Newer&#8221; links won&#8217;t.</p><p>Any suggestions?</p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=2121&amp;md5=93574a165e925710efeff37e057cc2ac" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2010/06/twitter-api-pagination-and-ids/feed/</wfw:commentRss> <slash:comments>8</slash:comments> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=2121&amp;md5=93574a165e925710efeff37e057cc2ac" type="text/html" /> </item> <item><title>Twitpic OAuth &#8211; I&#8217;m Stuck</title><link>http://shkspr.mobi/blog/index.php/2010/05/twitpic-oauth-im-stuck/</link> <comments>http://shkspr.mobi/blog/index.php/2010/05/twitpic-oauth-im-stuck/#comments</comments> <pubDate>Sun, 23 May 2010 20:15:18 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[/etc/]]></category> <category><![CDATA[api]]></category> <category><![CDATA[oauth]]></category> <category><![CDATA[php]]></category> <category><![CDATA[programming]]></category> <category><![CDATA[twitpic]]></category> <category><![CDATA[twitter]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=2073</guid> <description><![CDATA[Twitpic has implemented an OAuth API. No more having to hand out passwords to all and sundy. Only I&#8217;m too much of a dunderhead to get it working. Perhaps it&#8217;s a combination of heatstroke or this rotten head-cold, but I just can&#8217;t see what I&#8217;m doing wrong. Any help much appreciated. The easy bit. It&#8217;s <a
href='http://shkspr.mobi/blog/index.php/2010/05/twitpic-oauth-im-stuck/'>[...]</a>]]></description> <content:encoded><![CDATA[<p>Twitpic has implemented an <a
href="http://dev.twitpic.com/docs/2/upload/">OAuth API</a>. No more having to hand out passwords to all and sundy.  Only I&#8217;m too much of a dunderhead to get it working.  Perhaps it&#8217;s a combination of heatstroke or this rotten head-cold, but I just can&#8217;t see what I&#8217;m doing wrong.  Any help much appreciated.</p><h2>The easy bit.</h2><p>It&#8217;s easy to post the data to Twitpic</p><pre>$media_data = array(
	'media' =&gt; '@'.$_FILES['media']['tmp_name'],
	'message' =&gt; html_entity_decode($_POST['message']),
	'key'=&gt;'123465789132465'
);
curl_setopt($ch,CURLOPT_POSTFIELDS,$media_data);
</pre><h2>OAuth Credentials</h2><p>Using <a
href="http://twitter.com/abraham">Abrahams</a> <a
href="http://github.com/abraham/twitteroauth">OAuth library for PHP</a>, it&#8217;s easy to get the required OAuth data.</p><pre>require_once('OAuth.php');
// instantiating OAuth customer
$consumer = new OAuthConsumer(OAUTH_CONSUMER_KEY, OAUTH_CONSUMER_SECRET);
// instantiating signer
$sha1_method = new OAuthSignatureMethod_HMAC_SHA1();
// user's token
list($oauth_token, $oauth_token_secret) = explode('|', $GLOBALS['user']['password']);
$token = new OAuthConsumer($oauth_token, $oauth_token_secret);

// signing URL
$fakeurl = 'https://twitter.com/account/verify_credentials.xml';
$request = OAuthRequest::from_consumer_and_token($consumer, $token, 'GET', $fakeurl, array());
$request-&gt;sign_request($sha1_method, $consumer, $token);
$OAuthurl = $request-&gt;to_url();
</pre><h2>The Tricky Bit</h2><p>I&#8217;m following the header example in the <a
href="http://dev.twitpic.com/docs/2/upload/">API documentation</a>. Passing these variable to Twitpic is where I seem to go wrong.<br
/> <code><br
/> $header = array(<br
/> 'X-Auth-Service-Provider: https://api.twitter.com/1/account/verify_credentials.json',<br
/> 'X-Verify-Credentials-Authorization: OAuth realm="http://api.twitter.com/"'<br
/> );<br
/> </code><br
/> I then modify the second header so it reads</p><pre>
"X-Verify-Credentials-Authorization: OAuth realm="http://api.twitter.com/",
oauth_consumer_key="aaaaaaa",
oauth_nonce="bbbbbbbbbbb",
oauth_signature="ccccccccccccc%3D",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="123456798",
oauth_token="15948715-dddddddddd",
oauth_version="1.0""
</pre><h2>The Error</h2><p>401 &#8220;Could not authenticate you (header rejected by twitter).&#8221;</p><p>GAH!</p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=2073&amp;md5=b90c99ce28b1790dd6a5701cb4208df8" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2010/05/twitpic-oauth-im-stuck/feed/</wfw:commentRss> <slash:comments>14</slash:comments> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=2073&amp;md5=b90c99ce28b1790dd6a5701cb4208df8" type="text/html" /> </item> <item><title>I Love Open Source</title><link>http://shkspr.mobi/blog/index.php/2010/02/i-love-open-source/</link> <comments>http://shkspr.mobi/blog/index.php/2010/02/i-love-open-source/#comments</comments> <pubDate>Fri, 26 Feb 2010 22:21:40 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[voteuk]]></category> <category><![CDATA[api]]></category> <category><![CDATA[open source]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=1758</guid> <description><![CDATA[As I mentioned in my last post about VoteUK, I found the TheyWorkForYou API to be a little lacking when it came to image sizing. I posted a request asking if there was a pattern to the image sizes and, if not, was it possible to have the sizes returned in the API. The &#8220;standard&#8221; <a
href='http://shkspr.mobi/blog/index.php/2010/02/i-love-open-source/'>[...]</a>]]></description> <content:encoded><![CDATA[<p>As I mentioned in <a
href="http://shkspr.mobi/blog/index.php/2010/02/voteuk-updates/">my last post about VoteUK</a>, I found the TheyWorkForYou API to be a little lacking when it came to image sizing.</p><p>I <a
href="https://secure.mysociety.org/admin/lists/pipermail/developers-public/2010-February/006115.html">posted a request</a> asking if there was a pattern to the image sizes and, if not, was it possible to have the sizes returned in the API.</p><p>The &#8220;standard&#8221; open source reply &#8211; &#8220;<em>fix it yerself</em>&#8221; &#8211; was <a
href="https://secure.mysociety.org/admin/lists/pipermail/developers-public/2010-February/006117.html">predictably swift</a>.</p><p>So I did.</p><p>The <a
href="http://github.com/mysociety/theyworkforyou">source code</a> is remarkably accessible &#8211; although a few more comments wouldn&#8217;t go amiss.  This was my first experience with GIT and Github.  It was easy to get the code and, luckily, I didn&#8217;t have to dive too far in to its syntax.</p><p>I had initially thought about using the EXIF data within the images to get the width and height.  Unfortunately, not every image can be guaranteed to have (accurate) EXIF data.  PHP to the rescue once again with the <a
href="http://php.net/manual/en/function.getimagesize.php">getimagesize() </a>function.</p><p>So, where we previously had</p><pre>if ($image) $row['image'] = $image;</pre><p>This becomes</p><pre>if ($image) {
	list($width, $height) = getimagesize($image);
	$row['image'] = $image;
	$row['image_height'] = $height;
	$row['image_width'] = $width;
}</pre><p>Many thanks to Matthew Somerville for <a
href="https://secure.mysociety.org/admin/lists/pipermail/developers-public/2010-February/006172.html">testing and releasing the patch in double quick time</a>. You can <a
href="http://github.com/mysociety/theyworkforyou/commit/b6d93223b1d29dc1cc3bbe00abc61307ed89e0af">examine the changes</a> made to the code.</p><p>So now the API returns,</p><pre>&lt;image&gt;/images/mps/10409.jpg&lt;/image&gt;
&lt;image_height&gt;59&lt;/image_height&gt;
&lt;image_width&gt;49&lt;/image_width&gt;</pre><p>Brilliant!</p><p>So, I have a problem, I can see how much effort it will be to fix, I suggest a solution, it works and goes into production.  That&#8217;s the awesome power of open source.</p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=1758&amp;md5=8fc1f08c7560dd26c127d089aaa3f433" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2010/02/i-love-open-source/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=1758&amp;md5=8fc1f08c7560dd26c127d089aaa3f433" type="text/html" /> </item> <item><title>Hashtag Standards</title><link>http://shkspr.mobi/blog/index.php/2010/02/hashtag-standards/</link> <comments>http://shkspr.mobi/blog/index.php/2010/02/hashtag-standards/#comments</comments> <pubDate>Thu, 25 Feb 2010 17:35:38 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[/etc/]]></category> <category><![CDATA[usability]]></category> <category><![CDATA[api]]></category> <category><![CDATA[geek]]></category> <category><![CDATA[hashtags]]></category> <category><![CDATA[standards]]></category> <category><![CDATA[twitter]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=1730</guid> <description><![CDATA[This is one of the longest and geekiest posts I've done. It's a work in progress. All comments and abuse welcome. #hashtag – As long has there has been a way to search Tweets* people have been adding information to make the easy to find. The #hashtag syntax has become the standard for attaching a <a
href='http://shkspr.mobi/blog/index.php/2010/02/hashtag-standards/'>[...]</a>]]></description> <content:encoded><![CDATA[<pre>This is one of the longest and geekiest posts I've done.
It's a work in progress.
All comments and abuse welcome.</pre><blockquote><p>#hashtag – As long has there has been a way to search Tweets* people have been adding information to make the easy to find. The #hashtag syntax has become the standard for attaching a succinct tag to Tweets.</p></blockquote><p><a
href="http://engineering.twitter.com/2010/02/introducing-open-source-twitter-text.html">The Twitter Engineering Blog</a></p><p>That&#8217;s all well and good, but <a
href="http://shkspr.mobi/blog/index.php/2010/02/hashtags-and-implicit-knowledge/">as I discovered yesterday</a>, without standardisation the ability to search falls apart.</p><p>I&#8217;m not talking about whether you should use the #<span
style="text-decoration: underline;">LondonFire</span><strong> </strong>tag rather than #<span
style="text-decoration: underline;">FireOfLondon</span><strong> </strong>or #<span
style="text-decoration: underline;">LDNfire</span>. Rather; how does a computer recognise what a <em>valid</em> tag is?</p><h2>Why Does This Matter?</h2><p>Search and tracking quickly break down if they are inconsistent.<br
/> For example, if you are using #<span
style="text-decoration: underline;">Romeo&amp;Juliet</span> to mark all your conversations about the play you are watching, different Twitter clients will link through to either #<span
style="text-decoration: underline;">Romeo</span>, #<span
style="text-decoration: underline;">Romeo&amp;</span>, or #<span
style="text-decoration: underline;">Romeo&amp;Juliet</span>.  Each search returning potentially different conversations.</p><h2>What&#8217;s The Convention?</h2><p>Twitter&#8217;s website <em>ought</em> to be the definitive source of how hashtags work.  This is their main site.</p><div
id="attachment_1738" class="wp-caption aligncenter" style="width: 417px"><img
class="size-full wp-image-1738" title="Twitter Website Hashtag" src="http://shkspr.mobi/blog/wp-content/uploads/2010/02/Twitter-Website-Hashtag.png" alt="Twitter Website Hashtag" width="407" height="214" /><p
class="wp-caption-text">Twitter Website Hashtag</p></div><p>Yet, when we visit their mobile site &#8211; we get a completely different experience.</p><div
id="attachment_1731" class="wp-caption aligncenter" style="width: 330px"><img
class="size-full wp-image-1731" title="Mobile.Twitter's hashtags" src="http://shkspr.mobi/blog/wp-content/uploads/2010/02/snap20100225_151129.png" alt="Mobile.Twitter's hashtags" width="320" height="480" /><p
class="wp-caption-text">Mobile.Twitter&#39;s hashtags</p></div><h2>Application Confusion</h2><p>Because there aren&#8217;t any widely publicised definitions for what hashtags are, some applications have a significantly different attitude to hashtags</p><div
id="attachment_1732" class="wp-caption aligncenter" style="width: 490px"><img
class="size-full wp-image-1732" title="SocialScope Hashtags" src="http://shkspr.mobi/blog/wp-content/uploads/2010/02/Capture8_1_53.jpg" alt="SocialScope Hashtags" width="480" height="320" /><p
class="wp-caption-text">SocialScope Hashtags</p></div><h2><p><div
id="attachment_1771" class="wp-caption aligncenter" style="width: 490px"><img
class="size-full wp-image-1771" title="UberTwitter's Hashtag Support" src="http://shkspr.mobi/blog/wp-content/uploads/2010/02/x2_c38906.jpeg" alt="UberTwitter's Hashtag Support" width="480" height="360" /><p
class="wp-caption-text">UberTwitter&#39;s Hashtag Support</p></div></h2><h2>Standardisation</h2><p>To be fair, the Twitter team do have a standard.  Even if they don&#8217;t use it themselves.</p><p>They even have some <a
href="http://github.com/mzsanford/twitter-text-conformance">limited test cases</a> and libraries in Ruby and Java.</p><p>So, given that Twitter, their implementation and apps all disagree on what a hashtag is, let&#8217;s try to work our what they <em>should</em> be.</p><h2>Anatomy of a Tag</h2><p>To begin at the beginning.  A hashtag starts with a hash. #.  Simple, no? No.</p><p>There are two different hash symbols! There&#8217;s the # we all know and love, and there&#8217;s ＃.  Looks pretty similar, but in fact it&#8217;s the unicode symbol [U+FF03]</p><p>Actually, that&#8217;s not the beginning.  What comes before the # of the hashtag?</p><p>Consider the following examples &#8211; which should be hashtags?</p><ul><li>#tag &#8211; the # starts off the Tweet</li><li>This is my tweet #test &#8211; the # comes after a space.</li><li>This is it.#tag &#8211; the # is pushed against some punctuation, perhaps for reasons of space.</li><li>Here we go-#LiftOff &#8211; the # is pushed against a -</li><li>I&#8217;ve run out of space#OhNo &#8211; the # is pushed against some text</li><li>&amp;#nbsp; &#8211; the # is part of an HTML entity</li><li>text　#hashtag &#8211; the # comes after a &#8220;wide space&#8221; (U+3000)</li><li>Should I use #tag/#hashtag? The # comes after a /</li><li>Is this valid ##tag &#8211; there are two #s</li></ul><p>So, we can see it&#8217;s a little more complicated than we first thought.</p><h2>The End</h2><p>Let&#8217;s skip over what&#8217;s <em>in</em> a hashtag and as &#8220;how do we know that a tag has finished?&#8221;</p><p>Consider the following examples -</p><ul><li>New album #OMG! &#8211; should the ! be part of the hashtag?</li><li>#BreakingNews: dog bites man &#8211; should the : be part of the hashtag?</li><li>(is this a #tag) &#8211; should the ) be part of the hashtag?</li><li>I like #tags#</li></ul><p>We probably don&#8217;t want to have any punctuation at the end of our tag.  Can you think of any counter examples?</p><h2>Yummy Filling</h2><p>Our language is more than just the letters A-Z. We&#8217;ve got punctuation, numbers, symbols and all manner of other glyphs.  Which of them count as part of a hashtag?</p><p>Take a look at these examples</p><ul><li>Vote Bush! #Don&#8217;t</li><li>My dog died #:-(</li><li>Einstein #e=mc^2</li><li>I&#8217;m on bus #123</li><li>I&#8217;m giving #110%</li></ul><p>Using Twitter&#8217;s standards, <strong>none</strong> of the above render as complete tags.</p><h2>Foreign Languages</h2><p>We&#8217;ve mentioned accents above.  As we can see in the first example, &#8220;funny&#8221; characters can cause problems.  Broadly speaking, there are three issues.</p><ol><li>Accents.  Should the é on #Café be linked?</li><li>Accents.  Is #Romeo the same as #Ŕöméø?</li><li>Japanese, and some other languages, don&#8217;t use spaces.  Is #tagの valid? What about # 会議中 ?</li></ol><h2>Exhausted</h2><p>These are a fraction of the possible problems.  It&#8217;s exhausting trying to find all the possible textual combinations and permutations which could lead into a hashtag.  No wonder there is confusion!</p><p>Search is a complex, profitable, and useful business.  It&#8217;s of vital importance that there is a legitimate, comprehensive standard which <strong>all</strong> sites and applications can follow.</p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=1730&amp;md5=6d8dfcbd0bf2477df441465329d8c17d" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2010/02/hashtag-standards/feed/</wfw:commentRss> <slash:comments>2</slash:comments> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=1730&amp;md5=6d8dfcbd0bf2477df441465329d8c17d" type="text/html" /> </item> <item><title>Hashtags and Implicit Knowledge</title><link>http://shkspr.mobi/blog/index.php/2010/02/hashtags-and-implicit-knowledge/</link> <comments>http://shkspr.mobi/blog/index.php/2010/02/hashtags-and-implicit-knowledge/#comments</comments> <pubDate>Wed, 24 Feb 2010 16:58:27 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[usability]]></category> <category><![CDATA[api]]></category> <category><![CDATA[dabr]]></category> <category><![CDATA[documentation]]></category> <category><![CDATA[hashtags]]></category> <category><![CDATA[tags]]></category> <category><![CDATA[twitter]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=1706</guid> <description><![CDATA[What is &#8220;Implicit Knowledge&#8221;? Essentially it&#8217;s stuff that everyone knows, but no one has written down. Usually it&#8217;s something that people have worked out through their own experiences. This sort of knowledge is common in life &#8211; but is fatal in computing and design. Take the following tweet I received. The complaint was that #tfm&#38;a <a
href='http://shkspr.mobi/blog/index.php/2010/02/hashtags-and-implicit-knowledge/'>[...]</a>]]></description> <content:encoded><![CDATA[<p>What is &#8220;Implicit Knowledge&#8221;?  Essentially it&#8217;s stuff that everyone knows, but no one has written down.  Usually it&#8217;s something that people have worked out through their own experiences.</p><p>This sort of knowledge is common in life &#8211; but is fatal in computing and design.  Take the following tweet I received.</p><div
class="quotedtweet" id="tw9582463562" style="background-color:#eef;padding:5px;margin-bottom:5px"><div
class="tw_user-info" style="padding:10px 10px 5px 0;float:left;text-align:center;width:100px;"><div
class="tw_thumb"> <a
href="http://twitter.com/Mawkins" title="Mark Hawkins" class="quoting_pic" rel="external"><img
src="http://img.tweetimag.es/i/Mawkins_n" alt="Mawkins" /></a></div><div
class="tw_screen-name"> <em><a
href="http://twitter.com/Mawkins" title="Twitter page : Mark Hawkins" rel="external">Mawkins</a></em></div><div
class="tw_full-name"> <strong>(Mark Hawkins)</strong></div></div><div
class="tw_content" style="float: left; width: 500px; font: 20pt Georgia, Verdana, sans-serif; font-style: normal;"><div
class="tw_entry-content"> <a
href="http://www.twitter.com/edent" rel="external">@edent</a> <a
href="http://www.twitter.com/dabr" rel="external">@dabr</a> you folks aware ampersands / &amp;s don't seem to work as part of hashtag links?</div></div><div
style="clear: both; text-align: left;font-style:italic;margin-left:110px"><p
class="tw_meta tw_entry-meta" style="margin: 0;padding-top:5px"> <small> <span>On <a
href="http://twitter.com/Mawkins/status/9582463562" rel="external">24-2-2010 16:27:19</a></span> <span>from <a
href="http://www.tweetdeck.com" rel="nofollow">TweetDeck</a></span> <span> in reply to <a
href="http://twitter.com/edent/status/9581804744" rel="external">Terence Eden</a></span> </small></p></div></div><p>The complaint was that #tfm&amp;a should be rendered as <span
style="text-decoration: underline;">#tfm&amp;a</span> not <span
style="text-decoration: underline;">#tfm</span>&amp;a.</p><h2>Everyone knows that&#8217;s how hashtags work!</h2><p>On Twitter&#8217;s website, find the page which discusses hashtag syntax.  Find where they explain how they should be styled.</p><p><strong>You can&#8217;t.</strong></p><p>And thus implicit knowledge is born.  Dabr only looks at letters and numbers in a hashtag.  It assumes that any other character is the end of the tag.</p><div
id="attachment_1708" class="wp-caption aligncenter" style="width: 490px"><img
class="size-full wp-image-1708" title="Dabr's Hashtag" src="http://shkspr.mobi/blog/wp-content/uploads/2010/02/Capture16_35_30.jpg" alt="Dabr's Hashtag" width="480" height="320" /><p
class="wp-caption-text">Dabr&#39;s Hashtag</p></div><p>Without official guidance &#8211; implicit knowledge develops.</p><h2>Has Dabr Got It Wrong?</h2><p>No.  I don&#8217;t think so.  Take a look at how Twitter on the web renders hashtags&#8230;</p><div
id="attachment_1710" class="wp-caption aligncenter" style="width: 392px"><img
class="size-full wp-image-1710" title="Twitter's Web Site" src="http://shkspr.mobi/blog/wp-content/uploads/2010/02/Twitters-Web-Site.png" alt="Twitter's Web Site" width="382" height="312" /><p
class="wp-caption-text">Twitter&#39;s Web Site</p></div><p>&#8230;and on the mobile.</p><div
id="attachment_1707" class="wp-caption aligncenter" style="width: 490px"><img
class="size-full wp-image-1707" title="Twitter Mobile" src="http://shkspr.mobi/blog/wp-content/uploads/2010/02/Capture16_34_33.jpg" alt="Twitter Mobile" width="480" height="320" /><p
class="wp-caption-text">Twitter Mobile</p></div><h2>So Where Does Render The Full Tag?</h2><p>Several applications don&#8217;t render tags in the same way as Twitter.  Take a look at SocialScope</p><div
id="attachment_1709" class="wp-caption aligncenter" style="width: 490px"><img
class="size-full wp-image-1709" title="SocialScope Hashtags" src="http://shkspr.mobi/blog/wp-content/uploads/2010/02/Capture16_34_56.jpg" alt="SocialScope Hashtags" width="480" height="320" /><p
class="wp-caption-text">SocialScope Hashtags</p></div><div
id="attachment_1727" class="wp-caption aligncenter" style="width: 330px"><img
src="http://shkspr.mobi/blog/wp-content/uploads/2010/02/jsfe.jpg" alt="Tweetie2" title="Tweetie2" width="320" height="480" class="size-full wp-image-1727" /><p
class="wp-caption-text">Tweetie2</p></div><p>I&#8217;ll upload more screenshots if I find examples of &#8220;badly behaved&#8221; hashtags.  Please let me know if you find any.</p><h2>What Does Twitter Say?</h2><p>Twitter has one page devoted to hashtags.  It is a <a
href="http://help.twitter.com/forums/10711/entries/49309-what-are-hashtags-the-symbol">support page for hashtags</a>.  This explains to people what hashtags are.  There&#8217;s no detail on valid characters, maximum length, or any of the things which might be useful for a developer or designer.</p><h3>Edit 2010-02-25</h3><p>David Dorward has <a
href="http://twitter.com/dorward/status/9584777039">pointed out that there is an official resource</a>. On the Twitter Engineering blog &#8211; which isn&#8217;t linked to from the developer site &#8211; there is a <a
href="http://engineering.twitter.com/2010/02/introducing-open-source-twitter-text.html">page discussing hashtags and how to validate them</a>.  You&#8217;ll notice that they are rather circumspect on what should constitute a hashtag.</p><h2>Conclusion</h2><p>Standards and guidelines allow developers to create compatible applications.</p><p>Without explicit recommendations, developers will diverge as widely as possible.  Twitter &#8211; and everyone with an interest in compatibility and usability &#8211; needs to ensure that the knowledge they impart is <em>explicit</em>.</p><p>Letting people make it up as they go along leads to confusion.</p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=1706&amp;md5=3da27a57f5bf04e91e228cb51e8ce6b3" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2010/02/hashtags-and-implicit-knowledge/feed/</wfw:commentRss> <slash:comments>5</slash:comments> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=1706&amp;md5=3da27a57f5bf04e91e228cb51e8ce6b3" type="text/html" /> </item> <item><title>Don&#8217;t Let Users Do Things They Can&#8217;t Do</title><link>http://shkspr.mobi/blog/index.php/2010/02/dont-let-users-do-things-they-cant-do/</link> <comments>http://shkspr.mobi/blog/index.php/2010/02/dont-let-users-do-things-they-cant-do/#comments</comments> <pubDate>Mon, 22 Feb 2010 15:05:42 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[usability]]></category> <category><![CDATA[api]]></category> <category><![CDATA[dabr]]></category> <category><![CDATA[twitter]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=1682</guid> <description><![CDATA[There are many &#8220;rules&#8221; when it comes to User Interface / User Experience design.  One that I try to stick to is &#8220;Don&#8217;t let users do things they can&#8217;t do.&#8221; It&#8217;s one of my gripes with Linux.  If you&#8217;re editing a configuration file, you are relying on yourself to sanity check your input &#8211; often <a
href='http://shkspr.mobi/blog/index.php/2010/02/dont-let-users-do-things-they-cant-do/'>[...]</a>]]></description> <content:encoded><![CDATA[<p>There are many &#8220;rules&#8221; when it comes to User Interface / User Experience design.  One that I try to stick to is &#8220;Don&#8217;t let users do things they can&#8217;t do.&#8221;</p><p>It&#8217;s one of my gripes with Linux.  If you&#8217;re editing a configuration file, you are relying on yourself to sanity check your input &#8211; often without knowing what the limits are.</p><p>Take these two different examples.</p><p>In a text file, we might have:</p><blockquote><pre>#Maximum Widgets to fidget
maxW_to-F = 0
</pre></blockquote><p>Whereas a GUI would show</p><p>How many Widgets do you want to fidget?<br
/> <select><option>1</option><option>2</option><option>3</option><option>5</option> </select><p>Even if you don&#8217;t know the rules behind Widget fidgetting (must be a prime number lower than 7), the GUI won&#8217;t let you choose a value that you can&#8217;t select.  The GUI doesn&#8217;t prevent you setting an innapropriate value &#8211; just an illegal one. Your config file, however, could be set to any crazy value that a user type &#8211; often resulting in &#8220;unpredictable&#8221; results.</p><blockquote><pre>#Maximum Widgets to fidget
maxW_to-F = seventeen
</pre></blockquote><p>It&#8217;s with this in mind that I&#8217;ve made the following <a
href="http://code.google.com/p/dabr/source/detail?r=279">change to Dabr</a> &#8211; the mobile Twitter client.</p><h2>To Auth or Not To Auth? That Is The Question</h2><p>Twitter&#8217;s API has bug / peculiarity (<a
href="http://groups.google.com/group/twitter-development-talk/browse_thread/thread/318a5e820ee73765#">reported to their discussion board</a>) which causes Dabr to log a user out.  Let me explain the steps</p><ul><li>User 1 (@private) has set her tweets to &#8220;protected&#8221;.</li><li>This means no one can see @private&#8217;s tweet unless she allows them.</li><li>@private has not allowed User 2 (@edent) to view her tweets.  She is protect from his view.</li><li>@edent clicks to view @private&#8217;s profile.</li><li>@edent can see that @private has 42 friends, 17 followers and 3 favourites.</li></ul><p>So far, this is the same behaviour on Twitter&#8217;s website as it is through their API.  Here&#8217;s the difference</p><h3>Web</h3><ul><li>@edent tries to see @private&#8217;s followers and can see their names, profile pictures etc.</li><li>@edent can also see @private&#8217;s friends</li><li>@edent <strong>cannot</strong> see @private&#8217;s favourites (or even how many favourites she has)</li></ul><h3>API</h3><ul><li>@edent tries to see @private&#8217;s followers, friends or favourites</li><li>Because @edent isn&#8217;t allowed to see @private&#8217;s info, the API returns <a
href="http://apiwiki.twitter.com/HTTP-Response-Codes-and-Errors">401 Authorisation Required</a>.</li></ul><p>This is where things get tricky. Dabr sees the 401 and concludes that the user has invalid credentials.  It then, as a security measure, clears the user&#8217;s cookie and logs them out.</p><p>This may be a little harsh, but <a
href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes#4xx_Client_Error">HTTP 401 essentially says that the authorisation has failed</a>.</p><h2>Fixing It</h2><p>There are 3 ways that this could be fixed</p><ol><li>Twitter could rationalise the API to allow access to the same content that a web user gets.</li><li>Twitter could return a different status code.</li><li>Dabr needs fixing.</li></ol><p>So, how do we get Dabr not to log out when it receives a 401 <em>only</em> under these specific circumstances?</p><p><a
href="http://code.google.com/p/dabr/source/browse/trunk/common/twitter.php?r=274#293">Looking at the code</a>, we can see that Dabr simply sees the HTTP response code.  To fix it we&#8217;ll need to pass extra parameters, check where the code was called from, investigate all the edge cases, add more logic to the system, futz around breaking things, etc&#8230; etc&#8230;</p><p>What a pain in the&#8230;</p><h2>Or</h2><p><em>Don&#8217;t let users do things they </em>can&#8217;t<em> do.</em></p><p>If a user can&#8217;t see the information &#8211; why do we even let them <em>try</em> to see the information?  Why can&#8217;t we just get rid of the link?</p><p>This is what a user currently sees:</p><div
id="attachment_1688" class="wp-caption aligncenter" style="width: 364px"><img
class="size-full wp-image-1688" title="Old Style" src="http://shkspr.mobi/blog/wp-content/uploads/2010/02/Old-Style.png" alt="Old Style" width="354" height="73" /><p
class="wp-caption-text">Old Style</p></div><p>We&#8217;ve established that they can&#8217;t view followers, friends and favourites.  So we can get rid of those links (but not the information).</p><div
id="attachment_1687" class="wp-caption aligncenter" style="width: 364px"><img
class="size-full wp-image-1687" title="New Style" src="http://shkspr.mobi/blog/wp-content/uploads/2010/02/New-Style.png" alt="New Style" width="354" height="73" /><p
class="wp-caption-text">New Style</p></div><p>(Incidentally, I&#8217;ve changed the order of the links.  I&#8217;ve tried to group together similar items.  Followers, friends, favourites and lists go together. Then DM. Finally, follow, block, report spam.)</p><p>Now a user cannot click through to an unwanted error message.</p><h2>Or</h2><p>There is another way round this.  With &#8220;Direct Messages&#8221; we could do the same thing &#8211; simply remove the link if you&#8217;re not able to send that user a DM.</p><p>Instead, we&#8217;ve taken the approach of displaying a suitable error message.</p><div
id="attachment_1689" class="wp-caption aligncenter" style="width: 455px"><img
class="size-full wp-image-1689" title="Direct Message Warning" src="http://shkspr.mobi/blog/wp-content/uploads/2010/02/Direct-Message-Warning.png" alt="Direct Message Warning" width="445" height="194" /><p
class="wp-caption-text">Direct Message Warning</p></div><p>The advantage of this is that the user gets an explanation as to <em>why</em> they are unable to complete an action.</p><h2>Your Thought?</h2><p>Which do you prefer? Being unable to click on a link (with no explanation) or clicking on a link only to be given a warning message?</p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=1682&amp;md5=b886ba243cc96e8f8af7c6865be81c44" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2010/02/dont-let-users-do-things-they-cant-do/feed/</wfw:commentRss> <slash:comments>3</slash:comments> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=1682&amp;md5=b886ba243cc96e8f8af7c6865be81c44" type="text/html" /> </item> <item><title>VoteUK &#8211; Updates</title><link>http://shkspr.mobi/blog/index.php/2010/02/voteuk-updates/</link> <comments>http://shkspr.mobi/blog/index.php/2010/02/voteuk-updates/#comments</comments> <pubDate>Sun, 14 Feb 2010 16:03:09 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[voteuk]]></category> <category><![CDATA[api]]></category> <category><![CDATA[mobile]]></category> <category><![CDATA[vote]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=1633</guid> <description><![CDATA[After the tragic death of Ernest Marples, I&#8217;m sorry to say that the site fell in to a bit of disrepair. With no postcode data and no new boundary data, it looked like VoteUK was going to be permanantly out of business. Thanks &#8211; once again &#8211; to the clever-clogs at TheyWorkForYou, at least half <a
href='http://shkspr.mobi/blog/index.php/2010/02/voteuk-updates/'>[...]</a>]]></description> <content:encoded><![CDATA[<p>After the tragic death of <a
href="http://ernestmarples.com/blog/2009/10/amazing/">Ernest Marples</a>, I&#8217;m sorry to say that the site fell in to a bit of disrepair. With no postcode data and no new boundary data, it looked like VoteUK was going to be permanantly out of business.</p><p>Thanks &#8211; once again &#8211; to the clever-clogs at TheyWorkForYou, at least half of the problem has been solved.</p><p>The API call <a
href="http://www.theyworkforyou.com/api/docs/getConstituency">getConstituency</a> now has a future parameter.  Adding future=1 to the call will return the constituency the Postcode will be in for the 2010 General Election.</p><p>I&#8217;ve also made use of TWFY&#8217;s <a
href="http://www.theyworkforyou.com/api/docs/getMP">getMP</a> API call.  It returns enough detail about the current MP to be useful &#8211; including a photo.</p><p>So, a valid postcode will get you something like this:</p><div
id="attachment_1634" class="wp-caption aligncenter" style="width: 330px"><img
class="size-full wp-image-1634" title="MP Photo" src="http://shkspr.mobi/blog/wp-content/uploads/2010/02/device.png" alt="MP Photo" width="320" height="480" /><p
class="wp-caption-text">MP Photo</p></div><p>One thing to note about the photos.  Each one is a different size.  This gives us two small problems.</p><p>Firstly there is no guarantee of how small the photo is.  Should one MP&#8217;s photo be massive, that could cause a problem for the phone trying to download it. All the ones I&#8217;ve tried so far have been thumbnail size.</p><p>Secondly, because we don&#8217;t know the height and width of the image, we can&#8217;t put the height and width attributes in the &lt;img&gt; tag.  Not only is this poor HTML, but it will mean that rendering the page will take longer and &#8211; depending on the phone &#8211; page reflow may occur.</p><p>To mitigate this issue, I&#8217;m using <a
href="http://tinysrc.mobi/">http://tinysrc.mobi/</a> &#8211; it will automatically shrink the picture to fit the phone.  This doesn&#8217;t help with the page reflow issue though.</p><p>As for geo-locating Postcodes &#8211; I suggest you <a
href="http://osconsultation.ernestmarples.com/">respond to Ordnance Survey&#8217;s consultation</a> and / or lobby your MP.</p><p>Until there&#8217;s an official source for postcode data, I&#8217;ve gone back to using Yahoo!&#8217;s geo-location API.  I then pass these co-ordinates on to the Google Maps API.</p><p>So, VoteUK lives on.  Next steps are to make sure that all the <a
href="http://www.whatdotheyknow.com/request/postcodes_within_constituency_bo">data I got from the Electoral Commission</a> is valid and build a framework for volunteers to enter their local candidate details.</p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=1633&amp;md5=9e67f7856666f00fe9a72de00883ab14" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2010/02/voteuk-updates/feed/</wfw:commentRss> <slash:comments>4</slash:comments> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=1633&amp;md5=9e67f7856666f00fe9a72de00883ab14" type="text/html" /> </item> <item><title>Integrating AudioBoo and Phreadz with Dabr</title><link>http://shkspr.mobi/blog/index.php/2009/12/integrating-audioboo-phreadz-dabr/</link> <comments>http://shkspr.mobi/blog/index.php/2009/12/integrating-audioboo-phreadz-dabr/#comments</comments> <pubDate>Wed, 30 Dec 2009 14:33:58 +0000</pubDate> <dc:creator>Terence Eden</dc:creator> <category><![CDATA[mobile]]></category> <category><![CDATA[api]]></category> <category><![CDATA[audioboo]]></category> <category><![CDATA[dabr]]></category> <category><![CDATA[phreadz]]></category><guid
isPermaLink="false">http://shkspr.mobi/blog/?p=1492</guid> <description><![CDATA[A quick explanation of how I integrated AudioBoo and Phreadz with Dabr. I&#8217;m a big fan of AudioBoo &#8211; for those who don&#8217;t know it,  AudioBoo allows you to record some audio on your phone and then publish it to the web.  It&#8217;s like instant podcasting.  Originally only for the iPhone, AudioBoo now works on <a
href='http://shkspr.mobi/blog/index.php/2009/12/integrating-audioboo-phreadz-dabr/'>[...]</a>]]></description> <content:encoded><![CDATA[<p>A quick explanation of how I integrated AudioBoo and Phreadz with Dabr.</p><p>I&#8217;m a big fan of <a
href="http://audioboo.fm/">AudioBoo</a> &#8211; for those who don&#8217;t know it,  AudioBoo allows you to record some audio on your phone and then publish it to the web.  It&#8217;s like instant podcasting.  Originally only for the iPhone, AudioBoo now works on Android and there&#8217;s an S60 version comeing out &#8220;soon&#8221;.</p><p>I&#8217;m very proud to announce that as of <a
href="http://code.google.com/p/dabr/source/detail?r=260">r260</a> &#8211; Dabr now support AudioBoo!</p><p>It all started with a tweet from David Carrington (creator of Dabr) asking how one would go about linking directly to a tweeted &#8216;boo.</p><p>So &#8211; how do I turn a tweeted &#8216;boo like <a
href="http://boo.fm/b73803">http://boo.fm/b73803</a> to the associated MP3 of <a
href="http://audioboo.fm/boos/73803-rockbandboo.mp3">http://audioboo.fm/boos/73803-rockbandboo.mp3</a> ?</p><h2>Bring Me The API!</h2><p>An API is a way for two computers to talk to each other.  The client (dabr) asks the server (AudioBoo) a question.  The server replies with some data and the client then does something with it.</p><p><a
href="http://code.google.com/p/audioboo-api/">AudioBoo&#8217;s API</a> is a &#8220;work in progress&#8221; &#8211; that&#8217;s the polite term for &#8220;not quite finished&#8221;.<br
/> There are various APIs to get information about a &#8216;boo.  However, it&#8217;s not particularly intuitive.  For example, if I use /audio_clips/</p><p>http://api.audioboo.fm/audio_clips/b73803.mp3</p><p>I get an error.<br
/> I have to drop the b to get</p><p>http://api.audioboo.fm/audio_clips/73803.mp3</p><p><a
href="http://groups.google.com/group/audioboo-api-discuss/browse_thread/thread/2c9a8d5694c0c8cd">I asked on the AudioBoo forums</a> if there was a better way but I didn&#8217;t get a quick response &#8211; so I turned to twitter.  One of the top AudioBoo bods, Mark Rock, is an active twitterer (seriously &#8211; isn&#8217;t there a better word than that?)</p><div
class="quotedtweet" id="tw6891551616" style="background-color:#eef;padding:5px;margin-bottom:5px"><div
class="tw_user-info" style="padding:10px 10px 5px 0;float:left;text-align:center;width:100px;"><div
class="tw_thumb"> <a
href="http://twitter.com/markrock" title="Mark Rock" class="quoting_pic" rel="external"><img
src="http://img.tweetimag.es/i/markrock_n" alt="markrock" /></a></div><div
class="tw_screen-name"> <em><a
href="http://twitter.com/markrock" title="Twitter page : Mark Rock" rel="external">markrock</a></em></div><div
class="tw_full-name"> <strong>(Mark Rock)</strong></div></div><div
class="tw_content" style="float: left; width: 500px; font: 20pt Georgia, Verdana, sans-serif; font-style: normal;"><div
class="tw_entry-content"> <a
href="http://www.twitter.com/davidcarrington" rel="external">@davidcarrington</a> <a
href="http://www.twitter.com/edent" rel="external">@edent</a> just updated server so this works - <a
href="http://boo.fm/b1234.mp3" rel="external">http://boo.fm/b1234.mp3</a></div></div><div
style="clear: both; text-align: left;font-style:italic;margin-left:110px"><p
class="tw_meta tw_entry-meta" style="margin: 0;padding-top:5px"> <small> <span>On <a
href="http://twitter.com/markrock/status/6891551616" rel="external">21-12-2009 12:12:59</a></span> <span>from <a
href="http://www.tweetdeck.com/" rel="nofollow">TweetDeck</a></span> <span> in reply to David Carrington</span> </small></p></div></div><p>So, now I can link http://boo.fm/b73803 to http://boo.fm/b73803.mp3 &#8211; simple.  Here&#8217;s what it looks like in the browser.</p><div
id="attachment_1497" class="wp-caption aligncenter" style="width: 309px"><img
src="http://shkspr.mobi/blog/wp-content/uploads/2009/12/Screenshot-shkspr.mobi-Search-Mozilla-Firefox-e1262183483383.png" alt="AudioBoo" title="AudioBoo" width="299" height="296" class="size-full wp-image-1497" /><p
class="wp-caption-text">AudioBoo</p></div><h2>Phreadz</h2><p><a
href="http://Phreadz.com" class="broken_link">Phreadz</a> is a service which allows you to post VITAL &#8211; Video Images Text Audio Links &#8211; it&#8217;s a fantastic service, so when Kosso (its founder) asked me to integrate it into Dabr, I was keen to take on the challenge.</p><p>The code was quite simple and can be seen in <a
href="http://code.google.com/p/dabr/source/detail?r=261">r261</a>.  But there was one small complication &#8211; image sizes.</p><p>The thumbnail images from Phreadz aren&#8217;t always suitable for mobiles.  If images are too large, it will slow download speeds and potentially cost people money.</p><p>So, I used <a
href="http://tinysrc.mobi/">tinysrc.mobi</a>. Tinysrc is a very simple API which will resize any image to a mobile friendly format.  It detects the phone&#8217;s user-agent string and creates a suitable sized image.</p><p>Here&#8217;s what it looks like.</p><div
id="attachment_1498" class="wp-caption aligncenter" style="width: 410px"><img
class="size-full wp-image-1498" title="Phreadz" src="http://shkspr.mobi/blog/wp-content/uploads/2009/12/vodaclone_1261744837_400.jpg" alt="Phreadz" width="400" height="955" /><p
class="wp-caption-text">Phreadz</p></div><h2>Conclusions</h2><p>I&#8217;ve used 4 separate APIs here &#8211; twitter, AudioBoo, Phreadz, tinysrc &#8211; the joy of Web 2.0 is that all those disparate services can combine to create something new and magical.</p><p>API designers often need to think about how their products will be used &#8220;in the wild&#8221;.  It&#8217;s very easy to create something that works very well for your requirements &#8211; but much harder to think about what others will need.</p><p><a
href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=1492&amp;md5=8e778ce9a6fe1d7f41b75d382bab7480" title="Flattr" target="_blank"><img
src="http://shkspr.mobi/blog/wp-content/plugins/flattr/img/flattr-badge-large.png" alt="flattr this!"/></a></p>]]></content:encoded> <wfw:commentRss>http://shkspr.mobi/blog/index.php/2009/12/integrating-audioboo-phreadz-dabr/feed/</wfw:commentRss> <slash:comments>1</slash:comments> <enclosure
url="http://boo.fm/b73803.mp3" length="479360" type="audio/mpeg" /> <enclosure
url="http://api.audioboo.fm/audio_clips/73803.mp3" length="479360" type="audio/mpeg" /> <enclosure
url="http://audioboo.fm/boos/73803-rockbandboo.mp3" length="479360" type="audio/mpeg" /> <atom:link rel="payment" href="http://shkspr.mobi/blog/?flattrss_redirect&amp;id=1492&amp;md5=8e778ce9a6fe1d7f41b75d382bab7480" type="text/html" /> </item> </channel> </rss>
<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Minified using disk: basic
Page Caching using disk: enhanced (Requested URI is rejected)

Served from: www.shkspr.mobi @ 2012-02-08 06:24:06 -->
