<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-14059280</id><updated>2025-03-28T00:22:01.231-07:00</updated><category term="dallas"/><category term="barcamp"/><category term="engineering"/><category term="daytripr"/><category term="startup"/><category term="food"/><category term="nyc"/><category term="mobile"/><category term="bigdata"/><category term="cohabitat"/><category term="drupal"/><category term="iphone"/><category term="speech"/><title type='text'>Architectonic</title><subtitle type='html'>The Art of Constructing Systems</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default?alt=atom'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default?alt=atom&amp;start-index=26&amp;max-results=25'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>101</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-14059280.post-5282332049599938749</id><published>2011-04-07T23:51:00.001-07:00</published><updated>2011-04-08T00:39:10.654-07:00</updated><title type='text'>Three Books</title><content type='html'>Too long for Twitter: Three books the people who actually build high tech products should read:&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://www.amazon.com/gp/product/1841120634/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=codeporn-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1841120634&quot;&gt;Crossing the Chasm&lt;/a&gt; by &lt;a href=&quot;http://en.wikipedia.org/wiki/Geoffrey_Moore&quot;&gt;Geoffrey Moore&lt;/a&gt;. Just read the whole thing cover-to-cover. Sure, it talks about ways to move from early to mainstream markets, but it also explains just what a market is, the difference between a cool technology and a &quot;Whole Product&quot; that&#39;s useful enough for somebody to actually pay for, and how to care for, feed and eventualy abandon early adopters. Moore didn&#39;t invent all (or even most of) the ideas in the book, but he took a bunch of esoteric information and turned it into a coherent, easy-to-read strategy for taking technology products to market.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://www.amazon.com/gp/product/0976470705/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=codeporn-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0976470705&quot;&gt;The Four Steps to the Epiphany&lt;/a&gt; by &lt;a href=&quot;http://en.wikipedia.org/wiki/Steven_Gary_Blank&quot;&gt;Steven Gary Blank&lt;/a&gt;. Unlike Crossing, this one&#39;s a bit of a slog, but if you&#39;re selling to businesses rather than consumers resist the temptation to skim it or read one of the &quot;lite&quot; versions floating around. Blank takes a bunch of industry best practices, mixes in his own hard-won wisdom, and produces a plan for turning an idea into a workable business. Spend a day or two reading through Crossing to get some background, then spend as long as it takes to get through Four Steps. It&#39;s worth it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href=&quot;http://www.amazon.com/gp/product/0786303158/ref=as_li_qf_sp_asin_il_tl?ie=UTF8&amp;amp;tag=codeporn-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=0786303158&quot;&gt;Solution Selling&lt;/a&gt; by Michael T. Bosworth. There&#39;s &quot;New Solution Selling&quot; by Eades and &quot;Spin Selling&quot; by Rackham, but the takeaway should be the same no matter which you choose: selling is not a black art that only born salesmen can understand. Selling is a rational processing of matching customer needs to your solutions, and you (yes you, geek engineer) are fully capable of doing it. The key is that we&#39;re not talking hucksters selling vacuum cleaners door-to-door, we&#39;re talking selling expensive, complex, high-tech solutions in an ongoing relationship. And that means actually solving your customer&#39;s problem is important. And that firmly aligns the selling with the engineering. A good engineer is still going to need to put in some work to become a competent high-tech salesperson, but engineers have a huge advantage over non-engineers in this arena.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Four Steps has a great appendix with many more recommendations, but those three are the must-reads I&#39;d want anyone I was working with (CEO to engineering intern) to have read and understood.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/5282332049599938749/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/5282332049599938749' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/5282332049599938749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/5282332049599938749'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2011/04/three-books.html' title='Three Books'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-3359899999968835866</id><published>2011-03-05T11:45:00.000-08:00</published><updated>2011-03-05T12:50:12.424-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="bigdata"/><category scheme="http://www.blogger.com/atom/ns#" term="cohabitat"/><category scheme="http://www.blogger.com/atom/ns#" term="dallas"/><category scheme="http://www.blogger.com/atom/ns#" term="engineering"/><category scheme="http://www.blogger.com/atom/ns#" term="startup"/><title type='text'>Dallas Big Data Micro Hackathon</title><content type='html'>&lt;a href=&quot;http://www.flickr.com/photos/doctorow/2711081060/&quot; title=&quot;Tape library, CERN, Geneva 2 by gruntzooki, on Flickr&quot;&gt;&lt;img src=&quot;http://farm4.static.flickr.com/3220/2711081060_ba91f69796.jpg&quot; width=&quot;400&quot; alt=&quot;Tape library, CERN, Geneva 2&quot; /&gt;&lt;/a&gt;&lt;div&gt;Tuesday, March 22nd at &lt;a href=&quot;http://cohabitat.us/&quot;&gt;Cohabitat&lt;/a&gt; in Dallas, Texas a group of geeks is getting together to write code to process &lt;a href=&quot;http://en.wikipedia.org/wiki/Big_data&quot;&gt;Big Data&lt;/a&gt;. There will likely be a group getting &lt;a href=&quot;http://hadoop.apache.org/&quot;&gt;Hadoop&lt;/a&gt; up and running on laptops (&quot;Hello, World&quot; level), and possibly a group working with &lt;a href=&quot;http://cassandra.apache.org/&quot;&gt;Cassandra&lt;/a&gt; and MapReduce on EC2 (&quot;I actually have a real-life problem to solve&quot; level) but anyone who&#39;s serious about Big Data is invited. You can sign up at:&lt;/div&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;div style=&quot;text-align: center; &quot;&gt;&lt;a href=&quot;http://dbdmh.eventbrite.com/&quot;&gt;http://dbdmh.eventbrite.com&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&quot;Big Data&quot; isn&#39;t a formally defined term, but the general idea is that if your data set could fit on a single disk or be easily hosted inside a normal relational database it&#39;s &lt;b&gt;not&lt;/b&gt; big data.  Google calculating &lt;a href=&quot;http://en.wikipedia.org/wiki/PageRank&quot;&gt;PageRank&lt;/a&gt; for every site they index? LinkedIn doing a complete &lt;a href=&quot;http://blog.linkedin.com/2010/07/01/linkedin-apache-pig/&quot;&gt;social graph analysis&lt;/a&gt; for every user? Those are definitely Big Data problems.  Technologies like &lt;a href=&quot;http://labs.google.com/papers/mapreduce.html&quot;&gt;MapReduce&lt;/a&gt; (see &lt;a href=&quot;http://hadoop.apache.org/&quot;&gt;Hadoop&lt;/a&gt;) and certain kinds of highly scalable NoSQL databases (see &lt;a href=&quot;http://cassandra.apache.org/&quot;&gt;Cassandra&lt;/a&gt;) fall under the heading, but it&#39;s a big tent and there are many other possibilities.&lt;/div&gt;&lt;div&gt;The event is free, but the idea is to keep the group small and focused, so spaces are limited. Sign up at: &lt;a href=&quot;http://dbdmh.eventbrite.com/&quot;&gt;http://dbdmh.eventbrite.com&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/3359899999968835866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/3359899999968835866' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3359899999968835866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3359899999968835866'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2011/03/dallas-big-data-micro-hackathon.html' title='Dallas Big Data Micro Hackathon'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://farm4.static.flickr.com/3220/2711081060_ba91f69796_t.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-3356966755591069710</id><published>2010-05-04T21:01:00.001-07:00</published><updated>2010-05-04T21:35:12.222-07:00</updated><title type='text'>Frustrated with Dallas</title><content type='html'>&lt;div&gt;&lt;a href=&quot;http://www.unionsquareventures.com/&quot;&gt;Union Square Ventures&lt;/a&gt;, the New York-based venture capital firm famous for its Web 2.0 investments (&lt;a href=&quot;http://foursquare.com/&quot;&gt;Foursquare&lt;/a&gt;, &lt;a href=&quot;http://meetup.com/&quot;&gt;Meetup&lt;/a&gt;, &lt;a href=&quot;http://tumblr.com/&quot;&gt;tumblr&lt;/a&gt;, &lt;a href=&quot;http://twitter.com/&quot;&gt;Twitter&lt;/a&gt;, &lt;a href=&quot;http://delicious.com/&quot;&gt;delicious&lt;/a&gt;, &lt;a href=&quot;http://feedburner.com/&quot;&gt;Feedburner&lt;/a&gt;, &lt;a href=&quot;http://etsy.com/&quot;&gt;etc&lt;/a&gt;) recently &lt;a href=&quot;http://unionsquareventures.com/2010/04/usv-is-hiring.php&quot;&gt;announced&lt;/a&gt; that they&#39;re hiring an investment analyst and a general manager. They invited anybody who was interested to send them links to their web presence, and the staff at USV would use that instead of a resume. Kinda cool.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;In a &lt;a href=&quot;http://www.unionsquareventures.com/2010/04/hiring-update-3.php&quot;&gt;followup post&lt;/a&gt;, they mapped the applicants. Nobody from Dallas applied for the general manager position, and only a couple could stir themselves to apply for the analyst spot. &lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;img src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsbZ3NGVC1HHtzv0FVW2Z6xavnAS5ZThMob9L62RbHDfBKTA0zBtVdbbaOcHtGURjs2veP4g7mmtA3qYzofblj3klE9VbwIxQWszqZg2SVtIhyphenhyphenzGgOVLqj2_NvnBnk97LYtBv3UA/s400/usvd.png&quot; style=&quot;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 150px;&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5467637041023000242&quot; /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;Anybody&lt;/i&gt; who wanted to could apply. No old-boy network, no experience absolutely required (although they did have some &quot;ideal candidate&quot; desiderata). And Dallas just couldn&#39;t be bothered.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I&#39;m very frustrated with Dallas.&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/3356966755591069710/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/3356966755591069710' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3356966755591069710'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3356966755591069710'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2010/05/frustrated-with-dallas.html' title='Frustrated with Dallas'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjsbZ3NGVC1HHtzv0FVW2Z6xavnAS5ZThMob9L62RbHDfBKTA0zBtVdbbaOcHtGURjs2veP4g7mmtA3qYzofblj3klE9VbwIxQWszqZg2SVtIhyphenhyphenzGgOVLqj2_NvnBnk97LYtBv3UA/s72-c/usvd.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-1140844933191862232</id><published>2010-02-14T16:00:00.000-08:00</published><updated>2010-02-15T06:38:11.926-08:00</updated><title type='text'>Linked Data, Confidence Games and the Transitivity of Trust</title><content type='html'>Over the Christmas holidays I took my family on a five thousand mile roadtrip around the American West. It took a couple of weeks and I expected to spend a lot of time on my favorite user-generated travel review site.&lt;br /&gt;&lt;br /&gt;And I did spend a lot of time on the site, enough to eventually figure out that it had been comprehensively infiltrated by review spammers. Some of the spam reviews were obvious: &quot;I loved this place! Five stars!&quot; when all the rest of the reviews were negative. Some were more devious: &quot;There were bedbugs! They spat in my soup! Zero stars!&quot; when all the other reviews were stellar. In other cases it was much harder to tell, and in all cases the average rating was highly suspect.&lt;br /&gt;&lt;br /&gt;Turns out there are companies that specialize in vandalizing review sites[1]. The companies employ actual humans who spend actual creative effort to craft misleading reviews. They even set up realistic user profiles, and on some sites they add each other as friends. In other words, it&#39;s considered worthwhile to spend real time and effort on this stuff.&lt;br /&gt;&lt;br /&gt;It&#39;s been suggested that there&#39;s a technological solution: If the reviewers are part of a social network, it&#39;s possible to extract some useful statistics that might help determine if the user is real or fake.&lt;br /&gt;&lt;br /&gt;If the reviewer is a friend, that&#39;s obviously useful information. But there&#39;s very little chance that some random reviewer is your friend.&lt;br /&gt;&lt;br /&gt;But what if the reviewer is part of your extended social network? Surely the fact that somebody is a friend of a friend is some indication that they&#39;re trustworthy, or at least that they&#39;re a real person.&lt;br /&gt;&lt;br /&gt;Nope.&lt;br /&gt;&lt;br /&gt;First off, with a fan-out of 200 friends the 2nd-level extended social graph is around 40,000 people. Allowing for annoying people who friend everybody, an extended social graph could easily include a substantial portion of the entire population of the planet. All it takes is a couple of mistaken friend-adds to get you hooked up to a spammer-created sub-network. Even if you&#39;re careful, it&#39;s overwhelmingly likely that some friend-of-a-friend isn&#39;t.&lt;br /&gt;&lt;br /&gt;So, trust is clearly not transitive and the idea of a &quot;web of trust&quot; cannot be taken literally[2].&lt;br /&gt;&lt;br /&gt;In most cases, it&#39;s only possible to determine if the &quot;shape&quot; of the reviewer&#39;s social graph is reasonable. That is, are they friends with other plausible-looking people? Are many of their friends known fake profiles? Do they have a realistic number of friends? Etc.&lt;br /&gt;&lt;br /&gt;But that&#39;s trivial to game. Even if there are obstacles to a totally automated approach, the application of ultra-cheap human labor makes it easy to set up a fake social network on any given site.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://linkeddata.org/&quot;&gt;Linked data&lt;/a&gt; and distributed social graphs (ala &lt;a href=&quot;http://esw.w3.org/topic/foaf+ssl&quot;&gt;FOAF + SSL&lt;/a&gt;) make things worse, because while before it took some amount of human effort to solve the captchas and create new accounts on a social-graph silo like Facebook, with a distributed &quot;&lt;a href=&quot;http://blogs.sun.com/bblfish/entry/more_on_authorization_in_foaf&quot;&gt;web of trust&lt;/a&gt;&quot; approach it can all be completely automated.&lt;br /&gt;&lt;br /&gt;That isn&#39;t to say FOAF + SSL isn&#39;t a neat &lt;a href=&quot;http://artofsystems.blogspot.com/2007/03/openid-and-foafhcard-live-from-sxswi.html&quot;&gt;replacement for the monstrosity&lt;/a&gt; that &lt;a href=&quot;http://openid.net/&quot;&gt;OpenID&lt;/a&gt; has become, but the &quot;web of trust&quot; part won&#39;t fly.&lt;br /&gt;&lt;br /&gt;That said, in some sense it doesn&#39;t really matter. I&#39;m certainly not arguing that we should slow in our rush towards a semantic web. The benefits are too great. But given the experience with email spammers and review fraudsters, it might be a good idea to be open about the fact that we&#39;re also introducing new hazards.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;[1] So, honestly, I only have anecdotal evidence. But it doesn&#39;t seem like a very controversial assumption.&lt;br /&gt;&lt;br /&gt;[2] &quot;Trust&quot; is a complicated word. It&#39;s not that knowing a review is by a friend-of-a-friend-of-a-friend isn&#39;t useful information, it&#39;s that using it to make a binary yes/no trust decision is misguided. There&#39;s been some interesting academic research in this area,  Wikipedia has a rundown:  &lt;a href=&quot;http://en.wikipedia.org/wiki/Web_of_trust&quot;&gt;http://en.wikipedia.org/wiki/Web_of_trust&lt;/a&gt; In what seems like a perfectly sensible approach, this paper:&lt;a href=&quot;http://www.mindswap.org/papers/Trust.pdf&quot;&gt; http://www.mindswap.org/papers/Trust.pdf&lt;/a&gt; suggests using social graph information as just one input into a full spam handling system.&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/1140844933191862232/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/1140844933191862232' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/1140844933191862232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/1140844933191862232'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2010/02/linked-data-confidence-games-and.html' title='Linked Data, Confidence Games and the Transitivity of Trust'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-7724526770108724639</id><published>2009-07-10T20:31:00.001-07:00</published><updated>2009-07-11T08:01:20.356-07:00</updated><title type='text'>303 Madness and the Giant Global Graph</title><content type='html'>I had the opportunity to do a short talk at the latest &lt;a href=&quot;http://www.semanticuniverse.com/events-meetup-semantic-web-dallas-july-meetup.html&quot;&gt;Semantic Web Dallas meetup&lt;/a&gt;. I decided on an overview of the 303-redirect dance that differentiates a URI that points to a web page from a URI that names a concept in the Semantic Web. Yes, there&#39;s a difference. Yes, it&#39;s an important difference. Probably. In any case, it&#39;s a good topic for a 10-minute talk because having to listen to stuff like this for more than ten minutes at a time can lead to bleeding from the ears. It&#39;s a complex issue with an, uhh, unexpected? solution, best approached with a sense of humor. Well, maybe not &lt;i&gt;best&lt;/i&gt; approached that way, but it seemed like a good idea at the time. And the list of references at the end is pretty good.&lt;br /&gt;&lt;br /&gt;&lt;iframe src=&#39;http://docs.google.com/present/embed?id=ah7sbx3c6vpn_117cgrsmrtm&#39; frameborder=&#39;0&#39; width=&#39;410&#39; height=&#39;342&#39;&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;If you read the references you&#39;ll learn that you can also use URLs with fragment identifiers in your RDF. But doing it that way doesn&#39;t involve a fundamental redefinition of part of HTTP so it&#39;s a lot less entertaining.</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/7724526770108724639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/7724526770108724639' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/7724526770108724639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/7724526770108724639'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2009/07/303-madness-and-giant-global-graph.html' title='303 Madness and the Giant Global Graph'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-3067741228177506010</id><published>2009-07-02T23:05:00.000-07:00</published><updated>2009-07-03T00:15:17.334-07:00</updated><title type='text'>Popstat on Google App Engine</title><content type='html'>&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwKopc83R1pIMfWEmzk83fEzwlEoM6tiACwfKsnVMHqYP9IVNvudgwNtuxwQA8JgP21fZbFXj61fnwcP_rWPcH_mHkpN-zbJrJoE8RDCRryPn_wTtiByhcbh1vdfkjuSgcQybR3w/s1600-h/Popstat.png&quot;&gt;&lt;img style=&quot;float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 152px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwKopc83R1pIMfWEmzk83fEzwlEoM6tiACwfKsnVMHqYP9IVNvudgwNtuxwQA8JgP21fZbFXj61fnwcP_rWPcH_mHkpN-zbJrJoE8RDCRryPn_wTtiByhcbh1vdfkjuSgcQybR3w/s200/Popstat.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5354127228181679746&quot; /&gt;&lt;/a&gt;Popstat is the demo application from my &lt;a href=&quot;http://artofsystems.blogspot.com/2009/06/facebook-intrigue-betrayal-murder.html&quot;&gt;Facebook Dev Garage Dallas&lt;/a&gt; presentation. It just posts a status message to Facebook and Twitter to demonstrate using both Facebook Connect and an external service. I developed it on my laptop and didn&#39;t have time to move it to a public host before the event. I wanted it out there live someplace and figured it was a good opportunity to try out &lt;a href=&quot;http://code.google.com/appengine/&quot;&gt;Google App Engine&lt;/a&gt;&#39;s Java support (Popstat uses &lt;a href=&quot;http://www.grails.org/&quot;&gt;Grails&lt;/a&gt; with a mix of &lt;a href=&quot;http://groovy.codehaus.org/&quot;&gt;Groovy&lt;/a&gt; and Java)&lt;div&gt;&lt;br /&gt;&lt;div&gt;I got it all working, but it was a pain.&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;I used the &lt;a href=&quot;http://grails.org/plugin/app-engine&quot;&gt;Grails AppEngine plugin&lt;/a&gt;. I liked it.&lt;/li&gt;&lt;li&gt;App Engine provides storage, but not in the form of a relational database. It&#39;s close enough that JPA and JDO both work (but not Hibernate, yet). I chose JPA, but either way you&#39;ll need to annotate your domain classes (I expected the &lt;a href=&quot;http://grails.org/plugin/gorm-jpa&quot;&gt;GORM-JPA&lt;/a&gt; plugin to do that for me, but it didn&#39;t)&lt;/li&gt;&lt;li&gt;You&#39;ll need to put your domain classes into named packages. Things (silently) don&#39;t go well if you leave them in the default package.&lt;/li&gt;&lt;li&gt;If you&#39;re using JPA, domain classes will need to explicitly declare an id field. Make it a Long, and add the @Id and @GeneratedValue annotations. Use GenerationType.IDENTITY.&lt;/li&gt;&lt;li&gt;I was able to use the dynamic save() method provided by GORM-JPA, but I had to wrap up the calls in a withTransaction block, and the semantics are slightly different (use merge() instead of save() for updates)&lt;/li&gt;&lt;li&gt;Depending on your version of Spring, you may get a message along the lines of &quot;org.springframework. context.annotation. internalPersistenceAnnotationProcessor&#39;: Initialization of bean failed&quot; with something about &quot;java.lang.NoClassDefFoundError:  javax/naming/NamingException&quot;. The fix &lt;a href=&quot;http://code.google.com/p/googleappengine/issues/detail?id=1240#c5&quot;&gt;here&lt;/a&gt; worked for me.&lt;/li&gt;&lt;li&gt;Popstat uses the &lt;a href=&quot;http://code.google.com/p/facebook-java-api/&quot;&gt;facebook-java-api&lt;/a&gt; library. Since App Engine forbids the use of JAXB, I had to switch to the JSON version of the client to avoid an error about JAXBContext.&lt;/li&gt;&lt;li&gt;To talk to Twitter, Popstat uses the &lt;a href=&quot;http://code.google.com/p/oauth-signpost/&quot;&gt;oauth-signpost&lt;/a&gt; library. But Signpost depends on Apache HttpClient, and HttpClient uses low-level Socket calls forbidden by App Engine. I hacked Signpost to use URLConnection, but I wouldn&#39;t recommend that approach. If I had to do it again, I&#39;d look around for an OAuth library that worked out of the box.&lt;/li&gt;&lt;li&gt;By default, the App Engine &lt;a href=&quot;http://code.google.com/appengine/docs/java/tools/devserver.html&quot;&gt;Java Development Server&lt;/a&gt; (a version of the App Engine environment you can run on your local machine) binds to localhost only. The command line client has a &quot;--address&quot; option, but the &quot;grails app-engine run&quot; command doesn&#39;t. I hacked the scripts/AppEngine.groovy plugin and harcoded the address parameter into startDevServer().&lt;/li&gt;&lt;/ul&gt;There was some other stuff that I didn&#39;t take notes on, but (other than registration being turned off) Popstat is doing what it did before.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;div&gt;Overall, though, it wasn&#39;t a great experience. Google &lt;a href=&quot;http://code.google.com/appengine/docs/java/jrewhitelist.html&quot;&gt;turns off random bits of Java&lt;/a&gt; (for security and ease of management), which means that very few third-party libraries are going to work. You&#39;ll probably have to do some porting of your own code as well. That, combined with the admin service &lt;a href=&quot;http://groups.google.com/group/google-appengine-downtime-notify&quot;&gt;being down all morning&lt;/a&gt;, left a bad taste. The free hosting thing is great for demo apps but I think I&#39;ll stick to something like Amazon EC2 for real work. I&#39;m very curious to see how Microsoft Azure stacks up (it&#39;s much more of a direct competitor to App Engine than the roll-it-all-yourself EC2)&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/3067741228177506010/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/3067741228177506010' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3067741228177506010'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3067741228177506010'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2009/07/popstat-on-google-app-engine.html' title='Popstat on Google App Engine'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwKopc83R1pIMfWEmzk83fEzwlEoM6tiACwfKsnVMHqYP9IVNvudgwNtuxwQA8JgP21fZbFXj61fnwcP_rWPcH_mHkpN-zbJrJoE8RDCRryPn_wTtiByhcbh1vdfkjuSgcQybR3w/s72-c/Popstat.png" height="72" width="72"/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-3398836769101638395</id><published>2009-06-30T20:37:00.001-07:00</published><updated>2009-06-30T21:20:04.794-07:00</updated><title type='text'>The Semantic Web or The Generic at War with the Specific</title><content type='html'>It&#39;s easy to imagine an application that takes advantage of Linked Data by extracting just what it needs and dumping it into a local relational database. But that&#39;s clearly cheating. It&#39;s equally easy to imagine a completely generic low-level Linked Data browser, but there&#39;s something less than completely satisfying about that, too. The basic problem is that a rich user experience requires &lt;span style=&quot;font-style: italic;&quot;&gt;specifics&lt;/span&gt;, while taking full advantage of the &quot;anyone can say anything about anything&quot; nature of the semantic web means that applications must be able to handle almost totally &lt;span style=&quot;font-style: italic;&quot;&gt;generic&lt;/span&gt; data[1]. At least that was the theme of my presentation to the &lt;a href=&quot;http://ixda-dfw.ning.com/&quot;&gt;Dallas chapter&lt;/a&gt; of the &lt;a href=&quot;http://www.ixda.org/&quot;&gt;IxDA&lt;/a&gt; earlier tonight...&lt;br /&gt;&lt;br /&gt;&lt;iframe src=&quot;http://docs.google.com/EmbedSlideshow?id=ah7sbx3c6vpn_91ffnpwhdt&quot; frameborder=&quot;0&quot; height=&quot;342&quot; width=&quot;410&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;I&#39;m especially proud of the way I failed to force people to sit through a detailed explanation of graph structures, subject-predicate-object triples, the use of URIs as identifiers, or any of the other traditional cruft that obscures the capabilities of semantic web technology under a morass of unnecessary detail. (Imagine introducing relational databases by first forcing people to understand index paging mechanisms, or learning to cook via an explanation of organic chemistry). The audience seemed to appreciate it.&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;br /&gt;[1] I struggled with this earlier over in &lt;a href=&quot;http://artofsystems.blogspot.com/2009/03/linked-data-end-user-applications.html&quot;&gt;/2009/03/linked-data-end-user-applications.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;[2] The translation from Keynote to Powerpoint to Google docs was not without problems. And you will definitely need to click through and get a larger version to read some of the screens. &lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/3398836769101638395/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/3398836769101638395' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3398836769101638395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3398836769101638395'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2009/06/semantic-web-or-generic-at-war-with.html' title='The Semantic Web or The Generic at War with the Specific'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-343244204046516426</id><published>2009-06-28T22:03:00.001-07:00</published><updated>2009-06-28T22:51:48.931-07:00</updated><title type='text'>Facebook, Intrigue, Betrayal, Murder</title><content type='html'>A working understanding of authentication and authorization protocols is key to making use of modern web APIs. But protocols like the three-party delegated authc/authz[1] typical of modern web services can be difficult to follow. Role-playing protocol participants[2] is a fun way to make a very abstract process concrete, so I decided to write, produce and direct some geek theater at my recent &lt;a href=&quot;http://www.facebook.com/event.php?eid=93629945905&quot;&gt;Facebook Developer Garage Dallas&lt;/a&gt; presentation. When you get to the script pages, imagine Alice played by about the least feminine guy you&#39;ve ever seen and you&#39;ll have the right atmosphere (you might need to click through and view the presentation full-sized to read the text on some pages)&lt;br /&gt;&lt;br /&gt;&lt;iframe src=&quot;http://docs.google.com/EmbedSlideshow?id=ah7sbx3c6vpn_42dqc2v4cm&quot; frameborder=&quot;0&quot; height=&quot;342&quot; width=&quot;410&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;I finished up with a quick review of some very traditional distributed programming topics. The questions &quot;just how many test cases would you need to cover the possible states your program can be in?&quot; and &quot;what makes you think you can test these modules independently?&quot; get people thinking along the right lines.&lt;br /&gt;&lt;br /&gt;Oh. In the end Alice runs off with Bob and all of Dave&#39;s money, leaving him on the hook with the Mafia for four guns and several bribes. Such is life in the high-stakes world of distributed programming.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:78%;&quot;&gt;[1] Authc = authentication, or identifying a user, and authz = authorization, or determining what services a user is allowed to make use of once they&#39;re identified. Authentication says who you are, authorization says what you can do. In the presentation I talk specifically about delegated authc/authz, and ignore the more traditional single-process examples. People seem surprised to learn that OAuth, which is an authorization protocol, doesn&#39;t necessarily tell your application the userid of the user (although many implementations include the info along with the authorization tokens that are the primary purpose of the protocol) It doesn&#39;t help that the OAuth spec confuses the two.&lt;br /&gt;&lt;br /&gt;[2] So, admittedly, the examples aren&#39;t usually acted out in front of an audience, but the role-playing does have a long and honored history. The script actually simplifies the real protocol considerably, but it should give the correct flavor:&lt;a href=&quot;http://www.networkworld.com/news/2005/020705widernetaliceandbob.html&quot;&gt; http://www.networkworld.com/news/2005/020705widernetaliceandbob.html&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/343244204046516426/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/343244204046516426' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/343244204046516426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/343244204046516426'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2009/06/facebook-intrigue-betrayal-murder.html' title='Facebook, Intrigue, Betrayal, Murder'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-3917743130786759458</id><published>2009-03-29T14:41:00.001-07:00</published><updated>2009-03-29T14:57:47.629-07:00</updated><title type='text'>Talis Connected Commons</title><content type='html'>&lt;blockquote&gt;&lt;/blockquote&gt;I&#39;ve got a &lt;a href=&quot;http://www.talis.com/platform/&quot;&gt;Talis Platform&lt;/a&gt; developer instance that I&#39;ve been using to host a tiny subset of the information from the National Register of Historic Places database. I spent some time this weekend at &lt;a href=&quot;http://vocamp.org/wiki/VoCampAustin2009&quot;&gt;VoCampAustin&lt;/a&gt; trying to get the rest ontologized, and I was wondering what I was going to do when it came time to host the entire data set. Luckily for me Talis just &lt;a href=&quot;http://blogs.talis.com/nodalities/2009/03/announcing-the-talis-connected-commons.php&quot;&gt;announced&lt;/a&gt; the &lt;a href=&quot;http://blogs.talis.com/n2/cc&quot;&gt;Talis Connected Commons&lt;/a&gt;:&lt;blockquote&gt;...if you own, or are creating, a public domain dataset then you can store that data in the Platform as RDF, for free. We’re setting an initial cap of 50 million triples on each dataset, but thats should be plenty of space in which to collect some really interesting data.&lt;/blockquote&gt;While Amazon will &quot;host&quot; your public data set, that just means they provide some free disk space you can use from within your EC2 instance: you&#39;ve still got to pay for bandwidth. With the Connected Commons, Talis takes care of those pesky bandwidth charges. I&#39;m sure there are &quot;within reason&quot; disclaimers in there somewhere, but for anyone considering RDF-izing and publishing public data sets, the Talis offer is definitely worth checking out.</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/3917743130786759458/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/3917743130786759458' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3917743130786759458'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3917743130786759458'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2009/03/talis-connected-commons.html' title='Talis Connected Commons'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-2730657313180857611</id><published>2009-03-25T12:27:00.000-07:00</published><updated>2009-03-25T15:29:21.389-07:00</updated><title type='text'>Facebook Redirects : The URL is not my son</title><content type='html'>&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgT9xmmfAgJKAfpfjYWGmNLkU7BqkevCMcjSSwJ-3-kF2IpncN6qcYMtzPLsWabq6uDcjTvyaae0aZ4qidpw3YmrZSzHCCtAOA3b9K5OcwqKlSwXxadFgTBy3ITzKLa4dy5Llnt1w/s1600-h/bad_url_error.png&quot;&gt;&lt;img style=&quot;float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 110px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgT9xmmfAgJKAfpfjYWGmNLkU7BqkevCMcjSSwJ-3-kF2IpncN6qcYMtzPLsWabq6uDcjTvyaae0aZ4qidpw3YmrZSzHCCtAOA3b9K5OcwqKlSwXxadFgTBy3ITzKLa4dy5Llnt1w/s320/bad_url_error.png&quot; border=&quot;0&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5317245214979829106&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;color:#666666;&quot;&gt;If you didn&#39;t get here via a very specific Google search[1] you probably want to stop reading now, otherwise...&lt;/span&gt; Those who eschew the standard Facebook PHP libraries are rewarded with a fuller, richer understanding of the intricacies of the API. I.e. they have to deal with obscure crud that normal people get to ignore. This particular cruddy bit recently managed to eat more time than it had any right to consume:&lt;blockquote&gt;The URL http://www.new.facebook.com/login.php?v=1.0&amp;amp;canvas&amp;amp;next=http%3A%2F%2Fapps.facebook.com&lt;br /&gt;%2Fhistoryradar%2F&amp;amp;api_key=643f14fgg7294eff is not valid.&lt;/blockquote&gt;That error message was in response to a redirect to force authorization if there was no session information on a canvas page request. I knew that the URL was in fact valid since not only was it &lt;a href=&quot;http://wiki.developers.facebook.com/index.php/Authorizing_Applications#How_Users_Can_Authorize_an_Application&quot;&gt;straight out of the Facebook API documentation&lt;/a&gt;, I could cut and paste it into a browser and get the correct response.  At first I thought it was an encoding issue (the &quot;next&quot; value needs to be encoded since it&#39;s a URL inside a parameter) but it took digging into the standard PHP library to find the real problem:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;color:#999999;&quot;&gt;public function redirect($url) {&lt;br /&gt;if ($this-&gt;in_fb_canvas()) {&lt;/span&gt;&lt;br /&gt;&lt;b&gt;echo &#39;&amp;lt;fb:redirect url=&quot;&#39; . $url . &#39;&quot;&gt;&#39;;&lt;/b&gt;&lt;br /&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;color:#999999;&quot;&gt;  } else if (preg_match(&#39;/^https?:\/\/([^\/]*\.)?facebook\.com(:\d+)?/i&#39;, $url)) {&lt;br /&gt;// make sure facebook.com url&#39;s load in the full frame so that we don&#39;t&lt;br /&gt;// get a frame within a frame.&lt;br /&gt;echo &quot;&amp;lt;script type=&quot;\&quot;text/javascript\&quot;&quot;&gt;\ntop.location.href = \&quot;$url\&quot;;\n&quot;;&lt;br /&gt;} else {&lt;br /&gt;header(&#39;Location: &#39; . $url);&lt;br /&gt;}&lt;br /&gt;exit;&lt;br /&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;code&gt;&lt;/code&gt;Right. You don&#39;t need a &quot;real&quot; &lt;a href=&quot;http://tools.ietf.org/html/rfc2616#section-10.3.3&quot;&gt;HTTP 302&lt;/a&gt; redirect, you need to send a special snippet of FBML. It&#39;s easy to forget that Facebook is its own little &lt;a href=&quot;http://en.wikipedia.org/wiki/Bizarro_World&quot;&gt;Bizarro World&lt;/a&gt; until you step just a little outside the approved way of doing things.&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class=&quot;Apple-style-span&quot;  style=&quot;font-size:small;&quot;&gt;[1] No, not &quot;the url is not my son.&quot; I mean one with &quot;login.php&quot; and &quot;url&quot; and &quot;not valid&quot; in it somewhere.&lt;/span&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/2730657313180857611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/2730657313180857611' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/2730657313180857611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/2730657313180857611'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2009/03/facebook-redirects-url-is-not-my-son.html' title='Facebook Redirects : The URL is not my son'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgT9xmmfAgJKAfpfjYWGmNLkU7BqkevCMcjSSwJ-3-kF2IpncN6qcYMtzPLsWabq6uDcjTvyaae0aZ4qidpw3YmrZSzHCCtAOA3b9K5OcwqKlSwXxadFgTBy3ITzKLa4dy5Llnt1w/s72-c/bad_url_error.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-3402941241270346853</id><published>2009-03-11T14:13:00.000-07:00</published><updated>2009-03-11T19:30:59.111-07:00</updated><title type='text'>Linked Data: End-User Applications?</title><content type='html'>&lt;a href=&quot;http://linkeddata.org&quot;&gt;Linked Data&lt;/a&gt; is a common-sense set of rules on how to use big-S Semantic Web technology to publish data on the Web. More or less[1]:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Publish your data as RDF[2].&lt;/li&gt;&lt;li&gt;Use HTTP URIs to name resources in your RDF.&lt;/li&gt;&lt;li&gt;Make the URIs dereferencable and contain more RDF.&lt;/li&gt;&lt;li&gt;Use a standard schema language (probably OWL[3]).&lt;/li&gt;&lt;/ul&gt;It&#39;s also probably safe to assume that the RDF used in Linked Data is &quot;informal&quot; and that there&#39;s a lot of it[4].&lt;br /&gt;&lt;br /&gt;Linked Data has been gaining momentum lately as sort of a down-to-earth version of the Semantic Web. The fact that it&#39;s relatively low-effort[5] means that there is quite of bit of data being published, despite the fact that very few applications outside the laboratory make use of it.&lt;br /&gt;&lt;br /&gt;Linked Data has obvious uses inside the enterprise. The BBC has done &lt;a href=&quot;http://blogs.talis.com/nodalities/2009/01/building-coherence-at-bbccouk.php&quot;&gt;some great work&lt;/a&gt; using web development techniques based on a combination of hard-core enterprise integration and brand-spanking-new semantic web technology. Linked Data behind (and just in front of) the firewall is an exciting area, and I believe that is where it will find its first widespread commercial acceptance. But that&#39;s another blog post.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-style: italic;&quot;&gt;This&lt;/span&gt; post is about is real end-user applications that take advantage of Linked Data. By &quot;real&quot; I mean something that sits on your desktop (or in your phone, or maybe even web browser) with a rich user interface tailored for a particular task. I don&#39;t mean generic browsers or infrastructure components.&lt;br /&gt;&lt;br /&gt;Since I had no clue what such an app would look like, I decided to take a generate-and-test approach: list the defining properties of Linked Data, come up with some consequences of those properties, then take the Cartesian product. Somewhere in there there must be a pony or two.&lt;br /&gt;&lt;br /&gt;After some trial and error, I picked the following:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Is the application meant to handle more than a fixed set of data? For example, a browser like &lt;a href=&quot;http://dbpedia.org/Marbles&quot;&gt;Marbles&lt;/a&gt;[5] is meant to navigate across all possible Linked Data, while a other systems limit themselves to, say, social network graphs as expressed by FOAF, or even a fixed set of in-house data sources.&lt;/li&gt;&lt;li&gt;Is the linking visible to the user? For example, in a generic browser the user sees the links and chooses which ones to navigate across. The links are central. On the other hand, a social network browser might automatically choose how to spider a FOAF network, and present the user with a summarized view containing data from many sources.&lt;/li&gt;&lt;li&gt;Is reasoning important? That is, is the raw data presented to the user, or will new triples be generated (or filtered) using formal (or informal) reasoning?&lt;/li&gt;&lt;/ul&gt;For reasoning, it&#39;s pretty much yes or no:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;  Synthesizes new triples? { Yes, No }&lt;/li&gt;&lt;/ul&gt;The same goes for linking: either the program makes the underlying low-level links visible and primary, or it covers them up somehow:&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Navigation? { User-visible Links, Invisible Links }&lt;/li&gt;&lt;/ul&gt;The extensibility question turns out to be a little more complicated than a simple Yes/No. While there are clearly some programs that are totally generic and others that are totally fixed, there are interesting cases in the middle. I added another possibility: applications that try to do something with data they don&#39;t totally understand (maybe by understanding ontology fragments like parts of FOAF or geodata)&lt;br /&gt;&lt;ul&gt;&lt;li&gt; Extensible? { Yes, Somewhat, No }&lt;/li&gt;&lt;/ul&gt;There&#39;s an interesting tradeoff, where the more specific the knowledge an application has about the data it works with, the better crafted the user experience can be.&lt;br /&gt;&lt;br /&gt;I am not happy with the list above. It leaves out some important characteristics, conflates others and is generally unsatisfactory. I originally had closer to a dozen characteristics, but the resulting combinatorial explosion made things awkward. But the list is just for inspiration, and so I&#39;m willing to live with it.&lt;br /&gt;&lt;br /&gt;And the &lt;a href=&quot;http://spreadsheets.google.com/ccc?key=pGC--TTsQhL0c6FpHHqrhCA&quot;&gt;results&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;iframe src=&quot;http://spreadsheets.google.com/pub?key=pGC--TTsQhL0c6FpHHqrhCA&amp;amp;output=html&amp;amp;widget=true&quot; frameborder=&quot;0&quot; height=&quot;355&quot; width=&quot;400&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;Linked Data applications like browsers and analysis tools show up with their own categories. That&#39;s not surprising since that&#39;s how the categories were chosen.&lt;br /&gt;&lt;br /&gt;I especially like the look of the &quot;hybrid&quot; applications: the ones that combine hardcoded knowledge of the data with the ability to process new data discovered through following links. If there&#39;s a pony to be found, I suspect it&#39;s in one of those rows.&lt;br /&gt;&lt;br /&gt;I&#39;m currently working on an iPhone application called &quot;National Register Radar&quot; that uses geolocation and a Linked Data version of the U.S. National Register of Historic Places database to help users maintain &quot;situational awareness&quot; of the history of the places around them. Right now it would be a first-row application: it has hardcoded knowledge of specific kinds of Linked Data, it hides the low-level linking and provides a summary view, and it presents the data as it finds it, with no logical reasoning.&lt;br /&gt;&lt;br /&gt;Although it&#39;s a relatively immature use of Linked Data, hardcoding makes developing the initial version of the application much easier. It means that few external libraries are required (an important consideration on a mobile device wiht an non-x86 processor and no Java). It also means that traditional application development techniques apply: I don&#39;t need to mess around with an on-phone triple store and SPARQL queries.&lt;br /&gt;&lt;br /&gt;I think, though, that I&#39;d like to turn it into a row 6 &quot;enhanced special-purpose browser&quot; that&#39;s not restricted to just a few hardcoded data sets. It&#39;s unclear how all the technology would fit together (how can the application make use of DBpedia data without hardcoding? Can Fresnel fit on a phone? Can Fresnel be adapted for voice output?) but it&#39;s worth a try (and probably a follow-up blog post).&lt;br /&gt;&lt;br /&gt;Ultimately, I suspect Linked Data will be more at home deep inside enterprise infrastructure than at the end-user level, but I&#39;m going to give National Register Radar another couple iteration and see where it ends up.&lt;br /&gt;&lt;br /&gt;I&#39;ll be demoing an alpha version at &lt;a href=&quot;http://barcamp.org/BarCampAustin4&quot;&gt;BarCampAustin4&lt;/a&gt;, if you&#39;re interested in Linked Data (or &lt;a href=&quot;http://artofsystems.blogspot.com/2009/02/speech-synthesis-on-iphone-with-flite.html&quot;&gt;speech synthesis&lt;/a&gt;) on the iPhone and are going to be in Austin, ping me and maybe we can get a BOF together...&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;&lt;br /&gt;[1] The &quot;official&quot; list is here: &lt;a href=&quot;http://www.w3.org/DesignIssues/LinkedData.html&quot;&gt;http://www.w3.org/DesignIssues/LinkedData.html,&lt;/a&gt; or even better, here: &lt;a href=&quot;http://www4.wiwiss.fu-berlin.de/bizer/pub/LinkedDataTutorial/&quot;&gt;http://www4.wiwiss.fu-berlin.de/bizer/pub/LinkedDataTutorial/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;[2] RDF is the data model for the semantic web. Think of it as an ultra-hyper-normalized database where everything has been reduced to three columns: &amp;lt;subject&gt; &amp;lt;predicate&gt; &amp;lt;object&gt;. Database keys are in the form or URIs. Don&#39;t let incredibly over-elaborate explanations fool you: it really is that simple.&lt;br /&gt;&lt;br /&gt;[3] OWL is a popular schema language for RDF. Since reducing everything to triples removes pretty much all the type data, you need a schema language to add it back in. It&#39;s a little like a much more powerful version of XML Schema that lets you bake in the kind of semantics that would normally go into the comments. The documentation for it is uniformly awful.&lt;br /&gt;&lt;br /&gt;[4] There&#39;s this really great article on just this topic that I can&#39;t seem to find a reference to right now. I&#39;ll edit it in later. Hey, it&#39;s a blog post, not a journal article, whadaya expect?&lt;br /&gt;&lt;br /&gt;[5] It&#39;s relatively low effort because some pioneers have put in tons of effort developing some slick tools to help out.&lt;br /&gt;&lt;br /&gt;[6] If it&#39;s up and running. Few of the commonly referenced Linked Data browsers worked reliably for me.&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/3402941241270346853/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/3402941241270346853' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3402941241270346853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3402941241270346853'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2009/03/linked-data-end-user-applications.html' title='Linked Data: End-User Applications?'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-1077562050528253885</id><published>2009-02-22T08:30:00.000-08:00</published><updated>2009-02-22T13:13:02.756-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="engineering"/><category scheme="http://www.blogger.com/atom/ns#" term="iphone"/><category scheme="http://www.blogger.com/atom/ns#" term="speech"/><title type='text'>Speech Synthesis on the iPhone with Flite</title><content type='html'>&lt;object height=&quot;310&quot; width=&quot;411&quot;&gt;&lt;param name=&quot;allowfullscreen&quot; value=&quot;true&quot;&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot;&gt;&lt;param name=&quot;movie&quot; value=&quot;http://vimeo.com/moogaloop.swf?clip_id=3322716&amp;amp;server=vimeo.com&amp;amp;show_title=0&amp;amp;show_byline=0&amp;amp;show_portrait=0&amp;amp;color=ff9933&amp;amp;fullscreen=1&quot;&gt;&lt;embed src=&quot;http://vimeo.com/moogaloop.swf?clip_id=3322716&amp;amp;server=vimeo.com&amp;amp;show_title=0&amp;amp;show_byline=0&amp;amp;show_portrait=0&amp;amp;color=ff9933&amp;amp;fullscreen=1&quot; type=&quot;application/x-shockwave-flash&quot; allowfullscreen=&quot;true&quot; allowscriptaccess=&quot;always&quot; height=&quot;310&quot; width=&quot;411&quot;&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;I was planning to use the Cocoa &lt;a href=&quot;http://developer.apple.com/DOCUMENTATION/Cocoa/Reference/ApplicationKit/Classes/NSSpeechSynthesizer_Class/Reference/Reference.html&quot;&gt;NSSpeechSynthesizer&lt;/a&gt; class to do &lt;a href=&quot;http://en.wikipedia.org/wiki/Speech_synthesis&quot;&gt;text-to-speech&lt;/a&gt; (TTS) in a &lt;a href=&quot;http://linkeddata.org/&quot;&gt;Linked Data&lt;/a&gt; based iPhone application, but Apple evidently isn&#39;t interested in my pitiful wants: the very slick &lt;a href=&quot;http://developer.apple.com/documentation/userexperience/SpeechTechnologies-date.html#//apple_ref/doc/uid/TP30000440-TP30000437-TP30000576&quot;&gt;OS X speech synthesis capabilities&lt;/a&gt; don&#39;t appear to be supported in iPhone OS. Not to be deterred, I managed to get the &lt;a href=&quot;http://www.speech.cs.cmu.edu/flite/&quot;&gt;Flite&lt;/a&gt; speech synthesizer up and running on the phone.  It had already been ported (multiple times) to the ARM architecture[1], so all I had to do was import the source files into Xcode.&lt;br /&gt;&lt;br /&gt;Well, pretty much. Other than the tedium of importing all the files, there were a couple of things that needed figuring out:&lt;br /&gt;&lt;br /&gt;I added the User-Defined Setting CST_AUDIO_NONE to turn off Flite&#39;s ability to play audio directly[2]. Alternatively, you could probably add a new implementation of the sound playing functions that used the iPhone audio framework, but that&#39;s too much work for a quick hack.&lt;br /&gt;&lt;br /&gt;Since I just wanted a simple proof-of-concept I called the main routine[3] of the command-line &quot;flite&quot; utility directly from my application code:&lt;br /&gt;&lt;pre&gt;int play_message( char* msg_file, char* msg ) {&lt;br /&gt; char* argv[5];&lt;br /&gt; argv[0] = &quot;flite&quot;;&lt;br /&gt; argv[1] = &quot;-t&quot;;&lt;br /&gt; argv[2] = msg;&lt;br /&gt; argv[3] = &quot;-o&quot;;&lt;br /&gt; argv[4] = msg_file;&lt;br /&gt; return flite_main( 5, argv );&lt;br /&gt;}&lt;/pre&gt;I was torn over whether to set up an in-memory buffer for the sound data or write it to a file then play the file back immediately. Since flite_main() was already set up to write to a file I took the easy way out. The only mildly tricky thing was finding someplace where I could write the temporary file. Some cut and paste from the SpeakHere[4] sample application, and:&lt;br /&gt;&lt;pre&gt;NSArray *filePaths = NSSearchPathForDirectoriesInDomains (&lt;br /&gt; NSDocumentDirectory,&lt;br /&gt; NSUserDomainMask,&lt;br /&gt; YES);&lt;br /&gt;NSString *recordingDirectory = [filePaths objectAtIndex: 0];    &lt;br /&gt;NSString *tempFilePath = [NSString&lt;br /&gt; stringWithFormat: @&quot;%@/%s&quot;,&lt;br /&gt; recordingDirectory, &quot;recording.wav&quot;];&lt;br /&gt;char *path = [ tempFilePath UTF8String]; &lt;br /&gt;play_message( path,&lt;br /&gt; &quot;mister watson, come here, i need you.&quot; );&lt;br /&gt;&lt;/pre&gt;That got the sound file written out. To play it back I pointed AVAudioPlayer[5] at the newly generated sound file:&lt;br /&gt;&lt;pre&gt;NSError *err;&lt;br /&gt;AVAudioPlayer* audioPlayer =  [[AVAudioPlayer alloc]&lt;br /&gt; initWithContentsOfURL:[NSURL fileURLWithPath:tempFilePath]&lt;br /&gt; error:&amp;amp;err];&lt;br /&gt;[audioPlayer setDelegate:self];&lt;br /&gt;[audioPlayer prepareToPlay];&lt;br /&gt;BOOL plays = [audioPlayer play];&lt;/pre&gt;I couldn&#39;t get AVAudioPlayer working without manually copying over the AVFoundation framework from /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.1.sdk/System/Library/Frameworks/AVFoundation.framework. I&#39;m not sure that&#39;s the right thing to do, but it worked, and my iPhone now says &quot;mister watson, come here, i need you&quot; with an old-school Cylon accent.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;[1] And to at least one framework useful on jailbroken phones. &lt;a href=&quot;http://www.ipodtouchfans.com/forums/showthread.php?t=70996&quot;&gt;This&lt;/a&gt; thread seemed useful if you want to go that direction. I suspect other people must have gotten Flite working in Xcode as above, but I wasn&#39;t seeing anything on the first dozen pages of search results.&lt;br /&gt;[2] CST_AUDIO_NONE is a standard Flite build flag. In Xcode, defining CST_AUDIO_NONE as a User-Defined Setting for a Target adds -DCST_AUDIO_NONE to the command line of the compiler. I prefer a good textual Makefile to the annoying graphical interface, but you take the bad with the good.&lt;br /&gt;[3] After re-naming it to &quot;flite_main()&quot; to avoid a clash with the main routine of the iPhone application. There were actually a bunch of little fiddly bits along those lines, but I didn&#39;t document them as I went along and you&#39;ll have to figure them out on your own.&lt;br /&gt;[4] SpeakHere is at &lt;a href=&quot;http://developer.apple.com/iphone/library/samplecode/SpeakHere/index.html&quot;&gt;http://developer.apple.com/iphone/library/samplecode/SpeakHere/index.html&lt;/a&gt;, but you probably need to be logged in to the iPhone Dev Center to see it.&lt;br /&gt;[5] Again with heavy cut and paste from the SpeakHere sample code.&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/1077562050528253885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/1077562050528253885' title='34 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/1077562050528253885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/1077562050528253885'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2009/02/speech-synthesis-on-iphone-with-flite.html' title='Speech Synthesis on the iPhone with Flite'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>34</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-1111966382616887199</id><published>2009-02-03T17:29:00.000-08:00</published><updated>2009-02-04T08:19:15.917-08:00</updated><title type='text'>OpenSocial: Behind the Corporate Firewall</title><content type='html'>&lt;a href=&quot;http://code.google.com/apis/opensocial/&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_0&quot;&gt;OpenSocial&lt;/span&gt;&lt;/a&gt; is an &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_1&quot;&gt;API&lt;/span&gt; for consumer social network sites like &lt;a href=&quot;http://www.linkedin.com/static?key=developers_widgets&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_2&quot;&gt;LinkedIn&lt;/span&gt;&lt;/a&gt;, &lt;a href=&quot;http://code.google.com/apis/orkut/docs/orkutdevguide/orkutdevguide-0.8.html&quot;&gt;Orkut&lt;/a&gt; and &lt;a href=&quot;http://www.hi5networks.com/developer/&quot;&gt;Hi5&lt;/a&gt;, but its greatest value may come from use behind the corporate firewall.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_3&quot;&gt;OpenSocial&lt;/span&gt; is really two separate things: &lt;a href=&quot;http://code.google.com/apis/opensocial/docs/0.8/reference/gadgets/#core&quot;&gt;a portal framework&lt;/a&gt; that describes how embedded content can interact with a page, and a glued-on &lt;a href=&quot;http://code.google.com/apis/opensocial/docs/0.8/reference/#opensocial&quot;&gt;social network &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_4&quot;&gt;API&lt;/span&gt;&lt;/a&gt; that provides a way to access things like profile and friend data.&lt;br /&gt;&lt;br /&gt;The portal framework is just &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_5&quot;&gt;Google&#39;s&lt;/span&gt; &lt;a href=&quot;http://en.wikipedia.org/wiki/IGoogle&quot;&gt;iGoogle framework&lt;/a&gt; &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_6&quot;&gt;rebranded&lt;/span&gt;, and the social-network &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_7&quot;&gt;API&lt;/span&gt; is a least-common denominator &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_8&quot;&gt;mashup&lt;/span&gt; of the &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_9&quot;&gt;APIs&lt;/span&gt; from a selection of big commercial social networks combined a dash of influence from the &lt;a href=&quot;http://developers.facebook.com/&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_10&quot;&gt;Facebook&lt;/span&gt; &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_11&quot;&gt;API&lt;/span&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Both the portal framework and the social &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_12&quot;&gt;API&lt;/span&gt; are &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_13&quot;&gt;ok&lt;/span&gt;, but neither one is really best-of-breed. There are many widely deployed, battle tested portal &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_14&quot;&gt;APIs&lt;/span&gt; available (&lt;a href=&quot;http://en.wikipedia.org/wiki/JSR_168&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_15&quot;&gt;JSR&lt;/span&gt; 168&lt;/a&gt; and &lt;a href=&quot;http://www.microsoft.com/downloads/details.aspx?familyid=05E0DD12-8394-402B-8936-A07FE8AFAFFD&amp;amp;displaylang=en&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_16&quot;&gt;Sharepoint&lt;/span&gt;&lt;/a&gt; spring to mind), and on the social side &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_17&quot;&gt;Facebook&#39;s&lt;/span&gt; &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_18&quot;&gt;API&lt;/span&gt; is (at least for the moment) superior.&lt;br /&gt;&lt;br /&gt;But in this case, I&#39;d argue &lt;a href=&quot;http://en.wikipedia.org/wiki/Worse_is_Better&quot;&gt;worse is better&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_19&quot;&gt;OpenSocial&lt;/span&gt; gadget &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_20&quot;&gt;API&lt;/span&gt; was designed to be used by web developers rather than corporate IT drones. Authoring a simple &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_21&quot;&gt;OpenSocial&lt;/span&gt; gadget is no harder than writing a web page, and the technology is nearly identical. It is much faster to get started with &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_22&quot;&gt;OpenSocial&lt;/span&gt; than to learn to program for a traditional corporate portal[1].&lt;br /&gt;&lt;br /&gt;The social &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_23&quot;&gt;API&lt;/span&gt; is important, too. &lt;a href=&quot;http://en.wikipedia.org/wiki/Enterprise_resource_planning&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_24&quot;&gt;ERP&lt;/span&gt;&lt;/a&gt; systems (to optimize the use of your company&#39;s stuff) and &lt;a href=&quot;http://en.wikipedia.org/wiki/Customer_relationship_management&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_25&quot;&gt;CRM&lt;/span&gt;&lt;/a&gt; systems (to optimize the use of your company&#39;s customers) are important, but most companies claim their people are their most important resource[2]. Anybody who&#39;s spent time on &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_26&quot;&gt;Facebook&lt;/span&gt; or Twitter probably buys that there are advantages to including social network features in enterprise applications[3]. &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_27&quot;&gt;OpenSocial&lt;/span&gt;, as a well-documented, free-to-implement standard is an obvious choice.&lt;br /&gt;&lt;br /&gt;I&#39;ve been spouting some of this stuff whenever I got the chance, so it was encouraging to see &lt;a href=&quot;http://www.atlassian.com/&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_28&quot;&gt;Atlassian&lt;/span&gt;&lt;/a&gt; (darling of the developer tools world) &lt;a href=&quot;http://blogs.atlassian.com/news/2009/01/atlascamp_keyno.html&quot;&gt;say something similar&lt;/a&gt; at their annual conference[4].&lt;br /&gt;&lt;br /&gt;I have a selfish reason for wanting &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_29&quot;&gt;OpenSocial&lt;/span&gt; behind the corporate firewall: I&#39;d like &lt;a href=&quot;http://praxisbridge.com/&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_30&quot;&gt;Praxis&lt;/span&gt; Bridge&lt;/a&gt; to have a way to keep in touch with students after the course is over, and I&#39;d like the students to have a way to keep in touch with each other. A &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_31&quot;&gt;silo&#39;ed&lt;/span&gt; social network for a limited-time event is useful, but a way to hook into the user&#39;s everyday working social network is much more valuable. And since the &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_32&quot;&gt;OpenSocial&lt;/span&gt; architecture allows container administrators control over the information leaked to external gadgets, I think it would have a shot at getting past (justifiably) paranoid corporate gatekeepers. But that&#39;s a whole &#39;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_33&quot;&gt;nother&lt;/span&gt; blog post.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;[1] Or, well, it &lt;/span&gt;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-style: italic;font-size:85%;&quot; &gt;seems&lt;/span&gt;&lt;span style=&quot;font-size:85%;&quot;&gt; that way, which is the same. Isn&#39;t the whole &quot;worse is better&quot; thing annoying?&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;[2] On a recruiting brochure you can probably assume a line like &quot;people are our most important asset&quot; is just the standard BS, but when a company&#39;s &lt;a href=&quot;http://en.wikipedia.org/wiki/10-Q&quot;&gt;10-Q&lt;/a&gt; says it you can assume they&#39;re serious.&lt;br /&gt;&lt;br /&gt;[3] &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_34&quot;&gt;ERP&lt;/span&gt; systems have human &lt;span class=&quot;blsp-spelling-corrected&quot; id=&quot;SPELLING_ERROR_35&quot;&gt;resources&lt;/span&gt; modules, but that&#39;s not quite the same thing as being &quot;social network enabled&quot;. On the other hand, the &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_36&quot;&gt;ERP&lt;/span&gt; vendors are going to start buying up &quot;behind the firewall social network&quot; vendors just as soon as the downturn ends, and at that point &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_37&quot;&gt;OpenSocial&lt;/span&gt; becomes just another standard &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_38&quot;&gt;ERP&lt;/span&gt; module.&lt;br /&gt;&lt;br /&gt;[4] &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_39&quot;&gt;OpenSocial&lt;/span&gt; comes in in the keynote at about 9:45. There&#39;s a whole session about their new &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_40&quot;&gt;plugin&lt;/span&gt; architecture at &lt;a href=&quot;http://blogs.atlassian.com/news/2009/01/atlascamp_video_1.html&quot;&gt;http://blogs.atlassian.com/news/2009/01/atlascamp_video_1.html&lt;/a&gt;. Thanks to &lt;a href=&quot;http://dewpoint.snagdata.com/&quot;&gt;Tracy Snell&lt;/a&gt; for the pointer.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/1111966382616887199/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/1111966382616887199' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/1111966382616887199'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/1111966382616887199'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2009/02/opensocial-behind-corporate-firewall.html' title='OpenSocial: Behind the Corporate Firewall'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-8872936348215269980</id><published>2009-01-23T20:55:00.000-08:00</published><updated>2009-01-23T21:06:37.732-08:00</updated><title type='text'>CoHabitat in 90 Seconds</title><content type='html'>Quick video from today&#39;s &lt;a href=&quot;http://workatjelly.com&quot;&gt;Jelly&lt;/a&gt; at &lt;a href=&quot;http://cohabitat.us/&quot;&gt;CoHabitat&lt;/a&gt;. I&#39;m posting it as much to play around with Vimeo embedding as anything else, but it definitely gives the flavor of the place:&lt;br /&gt;&lt;br /&gt;&lt;object width=&quot;411&quot; height=&quot;232&quot;&gt;&lt;param name=&quot;allowfullscreen&quot; value=&quot;true&quot; /&gt;&lt;param name=&quot;allowscriptaccess&quot; value=&quot;always&quot; /&gt;&lt;param name=&quot;movie&quot; value=&quot;http://vimeo.com/moogaloop.swf?clip_id=2936986&amp;amp;server=vimeo.com&amp;amp;show_title=0&amp;amp;show_byline=0&amp;amp;show_portrait=0&amp;amp;color=ff9933&amp;amp;fullscreen=1&quot; /&gt;&lt;embed src=&quot;http://vimeo.com/moogaloop.swf?clip_id=2936986&amp;amp;server=vimeo.com&amp;amp;show_title=0&amp;amp;show_byline=0&amp;amp;show_portrait=0&amp;amp;color=ff9933&amp;amp;fullscreen=1&quot; type=&quot;application/x-shockwave-flash&quot; allowfullscreen=&quot;true&quot; allowscriptaccess=&quot;always&quot; width=&quot;411&quot; height=&quot;232&quot;&gt;&lt;/embed&gt;&lt;/object&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/8872936348215269980/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/8872936348215269980' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/8872936348215269980'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/8872936348215269980'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2009/01/cohabitat-in-90-seconds.html' title='CoHabitat in 90 Seconds'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-1953006403975821167</id><published>2009-01-17T15:05:00.000-08:00</published><updated>2009-01-17T15:15:36.082-08:00</updated><title type='text'>OSDGD: Introduction to OpenSocial Presentation</title><content type='html'>OpenSocial Dev Garage Dallas is over, the mess has been cleaned up, and pretty much everyone has gone home. The pizza Traxo sponsored was delicious, the coffee Praxis Bridge provided helped get people going, and the CoHabitat venue rocked. There were a couple new faces, and I&#39;m pretty sure we&#39;ve added to the group of regulars who show up at this kind of stuff in Dallas.&lt;br /&gt;&lt;br /&gt;For reference, here&#39;s a copy of the presentation slides from the morning session:&lt;br /&gt;&lt;br /&gt;&lt;iframe src=&quot;http://docs.google.com/EmbedSlideshow?docid=ah7sbx3c6vpn_62gwg585n7&quot; frameborder=&quot;0&quot; height=&quot;342&quot; width=&quot;410&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;The idea was to get people up and running with an OpenSocial application as quickly as possible, so I skipped over the normally obligatory history, motivation and background in favor of getting to the good stuff right away. I think it worked out well, although I suspect that for a couple of people in the audience the information was too basic. It&#39;s always hard to decide on a target level, and I&#39;m happy enough overall. I think getting a more detailed agenda with a presentation outline posted in advance would have helped people judge better.</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/1953006403975821167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/1953006403975821167' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/1953006403975821167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/1953006403975821167'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2009/01/osdgd-introduction-to-opensocial.html' title='OSDGD: Introduction to OpenSocial Presentation'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-5488466896026672883</id><published>2008-12-26T12:02:00.000-08:00</published><updated>2009-01-06T13:35:04.512-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="barcamp"/><category scheme="http://www.blogger.com/atom/ns#" term="dallas"/><category scheme="http://www.blogger.com/atom/ns#" term="engineering"/><category scheme="http://www.blogger.com/atom/ns#" term="startup"/><title type='text'>OpenSocial Dev Garage Dallas</title><content type='html'>&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0FJoB74XNSpajqkbHgj2D0xgojl72D18DZP3kMsqZSk-2XeXMjK6PrvFSKIfGGmuhQJ6wKsZxXzYFn-YikMuNrhdKPEWwQ_1RuSpsmPBLZtH8xI_Cw3C1hBW3H50Kn_GkBE0h7Q/s1600-h/opensocial.jpg&quot;&gt;&lt;img style=&quot;margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 225px; height: 225px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0FJoB74XNSpajqkbHgj2D0xgojl72D18DZP3kMsqZSk-2XeXMjK6PrvFSKIfGGmuhQJ6wKsZxXzYFn-YikMuNrhdKPEWwQ_1RuSpsmPBLZtH8xI_Cw3C1hBW3H50Kn_GkBE0h7Q/s320/opensocial.jpg&quot; alt=&quot;&quot; id=&quot;BLOGGER_PHOTO_ID_5284193838176241074&quot; border=&quot;0&quot; /&gt;&lt;/a&gt;&lt;span style=&quot;font-style: italic; font-weight: bold;&quot;&gt;=== UPDATE ===&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We&#39;ve got a &lt;a href=&quot;http://wiki.opensocial.org/index.php?title=OpenSocial_Dev_Garage_Dallas&quot;&gt;page&lt;/a&gt; on the opensocial.org wiki. This page is the canonical reference for all things OpenSocial Dev Garage Dallas (except the signups, which are still on &lt;a href=&quot;http://upcoming.yahoo.com/event/1460416/&quot;&gt;Upcoming&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;If you&#39;re developing Facebook apps, it&#39;s inevitable that you&#39;ll eventually also be developing for the &quot;everybody but Facebook&quot; &lt;a href=&quot;http://code.google.com/apis/opensocial/&quot;&gt;OpenSocial API&lt;/a&gt;. Over the past couple of months, the API has stabilized substantially, and it&#39;s probably about time to check it out.&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://upcoming.yahoo.com/event/1460416/&quot;&gt;OpenSocial Dev Garage Dallas&lt;/a&gt; is your chance to write your first &quot;Hello Friends&quot; application in a supportive group environment. If you&#39;re more into writing containers than the gadgets that populate them, we&#39;re also planning to have a breakout session on implementing the API so your application can be an OpenSocial gadget host.&lt;br /&gt;&lt;br /&gt;The event is planned for Sat, January 17th at the amazing new Cohabitat coworking space in Dallas&#39;s historic State-Thomas neighborhood. In the interest of keeping things focused we&#39;re capping attendance at 25 people:&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://upcoming.yahoo.com/event/1460416/&quot;&gt;http://upcoming.yahoo.com/event/1460416/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If there&#39;s enough demand, we may be able to open up some more space, but I&#39;d recommend signing up now if you want to guarantee a spot!&lt;br /&gt;&lt;br /&gt;See you there!</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/5488466896026672883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/5488466896026672883' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/5488466896026672883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/5488466896026672883'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2008/12/opensocial-dev-garage-dallas.html' title='OpenSocial Dev Garage Dallas'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj0FJoB74XNSpajqkbHgj2D0xgojl72D18DZP3kMsqZSk-2XeXMjK6PrvFSKIfGGmuhQJ6wKsZxXzYFn-YikMuNrhdKPEWwQ_1RuSpsmPBLZtH8xI_Cw3C1hBW3H50Kn_GkBE0h7Q/s72-c/opensocial.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-5343022425359348234</id><published>2008-12-20T18:53:00.001-08:00</published><updated>2008-12-20T18:59:22.567-08:00</updated><title type='text'>Google Friend Connect</title><content type='html'>I&#39;m experimenting with &lt;a href=&quot;http://www.google.com/friendconnect/&quot;&gt;Google Friend Connect&lt;/a&gt; as you might notice from the new gadget over on the right. Feel free to join up, but as it&#39;s just an experiment there&#39;s a good chance I&#39;ll be removing the feature in a bit. I&#39;m thinking that with the addition of a couple of &lt;a href=&quot;http://code.google.com/apis/opensocial/&quot;&gt;OpenSocia&lt;/a&gt;l event management gadgets a Blogger blog might be a good, non-Facebook alternative for organizing an event, but we&#39;ll see.</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/5343022425359348234/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/5343022425359348234' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/5343022425359348234'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/5343022425359348234'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2008/12/google-friend-connect.html' title='Google Friend Connect'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-3149843627596920438</id><published>2008-11-23T12:29:00.001-08:00</published><updated>2008-11-23T13:02:03.147-08:00</updated><title type='text'>OAuth: Not a Silver Bullet</title><content type='html'>&lt;a href=&quot;http://oauth.net/&quot;&gt;OAuth&lt;/a&gt;[1] provides a standard protocol for delegated authentication. That is, it lets a site like &lt;a href=&quot;http://twitterank.com/&quot;&gt;Twitterank&lt;/a&gt;[2] get controlled access to your twitter account without your having to give Twitterank your username and password. Instead, there&#39;s a multi-step authentication process involving a &quot;token&quot; that grants temporary, limited access to a third party service.&lt;br /&gt;&lt;br /&gt;This sort of authentication system has been in use for many years in commercial and academic systems. OAuth just brings a cut-down version to the web 2.0 world.&lt;br /&gt;&lt;br /&gt;You may ask yourself: If it&#39;s so great and it&#39;s been around forever, why doesn&#39;t everybody use it? The short answer is that it&#39;s a major pain in the rear-end both for developers and users, and most of the time it&#39;s just not worth the bother.&lt;br /&gt;&lt;br /&gt;As a developer I actually like OAuth. I think it&#39;s wonderful for the times when the added complexity of delegated authentication makes sense. But the complexity is not without cost. For trivial, single-purpose services it is, at best, a very small win, and possibly even a net loss.&lt;br /&gt;&lt;br /&gt;Ignoring the implementation difficulties for now, let&#39;s take a quick look at the user experience via Twitter and the (hypothetical) Twitterevil service. Twitterevil operates by promising to calculate an amusing ranking number for your tweet history. It does in fact do that, but it also keeps your username and password and uses them to posts spam tweets. We&#39;ll look at scenarios both with and without OAuth.&lt;br /&gt;&lt;br /&gt;The first scenario, sans-OAuth, goes someething like this:&lt;br /&gt;&lt;ol&gt;&lt;li&gt; I surf to twitterevil.com and enter my Twitter username and password.&lt;/li&gt;&lt;li&gt; Twitterevil logs into Twitter as me, grabs some data, and uses it to calculate some statistics, which it tweets under my name. It also (contrary to what it says on the Twitterevil home page) keeps my username and password.&lt;/li&gt;&lt;li&gt;Later, Twitterevil starts using my Twitter account to post spam links.&lt;/li&gt;&lt;li&gt;I notice the spam links and use Twitter&#39;s password recovery feature to change my password.&lt;/li&gt;&lt;li&gt;Twitterevil can no longer use my account.&lt;/li&gt;&lt;/ol&gt;The OAuth scenario goes like this:&lt;br /&gt;&lt;ol&gt;&lt;li&gt; I surf to Twitterevil. Twitterevil has a login button button that redirects me to a special Twitter OAuth login page.&lt;/li&gt;&lt;li&gt;I enter my username and password on the Twitter OAuth login page, and hit the &quot;OK, allow Twitterevil access&quot; button.&lt;/li&gt;&lt;li&gt;I get redirected back to Twitterevil, which calculates my score, tweets it, and then starts posting spam links.&lt;/li&gt;&lt;li&gt;I notice the spam links, log into my twitter account, go to my OAuth delegated permissions page, find the twitterevil.com entry, and remove Twitterevil&#39;s permissions.&lt;/li&gt;&lt;li&gt;Twitterevil can no longer use my account.&lt;/li&gt;&lt;/ol&gt;So, conservatively, the OAuth scenario has more steps and involves the new concept of &quot;delegated authentication&quot;. This concept existed implicitly before but is now (very) visible to the user in the form of a multi-step login process and a new &quot;OAuth delegated credentials&quot; page. All to get the same end result.&lt;br /&gt;&lt;br /&gt;Actually, as some of you may have noticed, I&#39;ve lied by omission.  There&#39;s an alternate OAuth scenario that I&#39;m leaving out. It&#39;s a change to step 2, and it goes like this:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;...&lt;/li&gt;&lt;li&gt; I enter my username and password on the Twitter OAuth login page, and then read through a paragraph of explanatory text about just what Twitterevil is asking permission to do: &quot;twitterevil.com is asking permission to [Read through your posting history] and [Post tweets on your behalf]. Do you want to give twitterevil.com permission to do this (a) Once (b) For the next little while, or (c) Permanently. Note that you can always go back and revoke permission later.&quot;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;No, I&#39;m not kidding.&lt;br /&gt;&lt;br /&gt;Anybody who&#39;s looked at the problem of user security knows that nobody, even security experts, ever reads that crap. They just hit the default button automatically. So 2b is &quot;cover your behind&quot; security theater, it provides no real security in the vast majority of cases.&lt;br /&gt;&lt;br /&gt;Flickr, which uses a &lt;a href=&quot;http://www.flickr.com/services/api/auth.spec.html&quot;&gt;pre-oauth delegated authentication scheme&lt;/a&gt;, does it like 2a. They don&#39;t expose out the permissions set during authentication, instead allowing the user to go in later and see just what they approved (if users ever cared to look, which they don&#39;t). I suspect this is the result of some user experience testing. It&#39;s certainly easier.&lt;br /&gt;&lt;br /&gt;A service like Twitter has a very limited number of possible actions, so the model presented in 2b is unusually simple. A more complex application could have dozens of possible permissions. Developers who care about the experience will probably layer a &quot;user level&quot; set of permissions on top of the real underlying implementation permissions, but most won&#39;t. And that&#39;s just nasty.&lt;br /&gt;&lt;br /&gt;So, depending on how exactly the service implements the OAuth user experience, the number of user actions is either slightly or significantly more complicated for the OAuth scenario. The conceptual complexity (how many different ideas the user must keep in mind) is a clear loss for OAuth, especially if the service exposes out it&#39;s internal security architecture in the OAuth security screen.&lt;br /&gt;&lt;br /&gt;But.&lt;br /&gt;&lt;br /&gt;I was just asked by a service I won&#39;t name to hand over my Google username and password so that it could access my Google Reader data[3]. And I said &quot;no&quot;, because my Google account is not trivial or simple and there are real consequences to handing it over to somebody I don&#39;t fully trust.&lt;br /&gt;&lt;br /&gt;OAuth is a sledgehammer, and it does not make sense to use a sledgehammer when you can get away with something less. Developers should use their very limited time and money to go simplify their design, not add in significant new complexity where it&#39;s not needed.[4]&lt;br /&gt;&lt;br /&gt;But if, after serious reflection, you decided you do need a sledgehammer, OAuth appears to be shaping up into a good choice.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;[1] &lt;a href=&quot;http://oauth.net/&quot;&gt;http://oauth.net&lt;/a&gt; and also &lt;a href=&quot;http://en.wikipedia.org/wiki/OAuth&quot;&gt;http://en.wikipedia.org/wiki/OAuth&lt;/a&gt; (please help with the lame Wikipedia entry) I&#39;ve always assumed it stood for Open Authentication, but I don&#39;t see that written down anywhere.&lt;br /&gt;&lt;br /&gt;[2] Twitterank is a fun example because &lt;a href=&quot;http://www.brianoberkirch.com/&quot;&gt;Brian Oberkirch&lt;/a&gt; tweeted, as a joke with a point, that he set it up as an &lt;a href=&quot;http://twitter.com/brianoberkirch/status/1002723656&quot;&gt;evil password collector&lt;/a&gt;. But it got picked up by and &lt;a href=&quot;http://blogs.zdnet.com/collaboration/?p=163&quot;&gt;republished as a non-joke&lt;/a&gt; by ZDNet. I love ZDNet&#39;s lame attempt to substitute boilerplate &quot;rumor has it&quot; for fact checking.&lt;br /&gt;&lt;br /&gt;[3] Google is actually moving towards OAuth for all its services, but Reader doesn&#39;t have an &quot;official&quot; API yet, and OAuth doesn&#39;t work. Developers must use a sort of backdoor ClientLogin hack.&lt;br /&gt;&lt;br /&gt;[4] Note to complainers: There is some accidental complexity in OAuth that can be overcome via better libraries and documentation, but the base problem is the inherent complexity of exposing a more complex authentication scheme, and that exposure is at the heart of the claimed benefit of OAuth.&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/3149843627596920438/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/3149843627596920438' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3149843627596920438'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3149843627596920438'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2008/11/oauth-not-silver-bullet.html' title='OAuth: Not a Silver Bullet'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-9143587473407349070</id><published>2008-10-15T16:04:00.001-07:00</published><updated>2008-10-15T23:27:54.075-07:00</updated><title type='text'>I built this great product, now what?</title><content type='html'>I&#39;ve found that people who write great software generally do it because they can&#39;t help it. It&#39;s more fun than a barrel of monkeys and they&#39;d do it even if they weren&#39;t getting paid. Nobody likes the final grinding detail steps of productization, but with a good team the development phase is generally a hoot.[1]&lt;br /&gt;&lt;br /&gt;But &quot;build it and they will come&quot; isn&#39;t really a business plan. At some point most companies will need to talk convincingly about their great idea, either to get funding or make a sale. Do you pitch an investor with a demo, or a slide deck? How do you talk to the press? Is something like Demo or TechCrunch 50 worthwhile?&lt;br /&gt;&lt;br /&gt;If you&#39;ve been haunted by questions like the above, then show up this Saturday October 18th for a few hours and find out all the answers:&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.texasstartupblog.com/2008/10/15/pitch-camp-dallas-this-saturday-10am-4pm/&quot;&gt;http://www.texasstartupblog.com/2008/10/15/pitch-camp-dallas-this-saturday-10am-4pm/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;[1] In the same way a dog sled expedition to the South Pole is a hoot.&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/9143587473407349070/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/9143587473407349070' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/9143587473407349070'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/9143587473407349070'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2008/10/i-build-this-great-product-now-what.html' title='I built this great product, now what?'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-4466511402309735677</id><published>2008-08-10T11:13:00.001-07:00</published><updated>2008-08-10T11:24:38.483-07:00</updated><title type='text'>{s,S}emantic Web Workshop</title><content type='html'>Big-S, little-s, whichever direction you&#39;re coming from, parts of the semantic web are here today. It&#39;s not the &quot;Grand Vision&quot;[1] of Tim Berners-Lee, but don&#39;t let that stop you from taking advantage of some very cool technology that can enhance your site or enable your application right away. The slide deck below is from my presentation at &lt;a href=&quot;http://barcamp.org/BarCampHouston3&quot;&gt;BarCampHouston3&lt;/a&gt;. The idea was a quick intro then a workshop where attendees had the chance to actually experiment with the technology hands-on right then and there. No projector and no network access in the presentation room almost scuttled that, but we eventually borrowed the necessary infrastructure (thanks &lt;a href=&quot;http://www.gallucci.net/&quot;&gt;Giovanni&lt;/a&gt;, &lt;a href=&quot;http://flickr.com/photos/michaelcummings/&quot;&gt;Michael&lt;/a&gt; and &lt;a href=&quot;http://stor.me/&quot;&gt;Stormy&lt;/a&gt;!) and got to the presentation part, at least:&lt;br /&gt;&lt;br /&gt;&lt;iframe src=&quot;http://docs.google.com/EmbedSlideshow?docid=ah7sbx3c6vpn_26fswqwhcr&quot; frameborder=&quot;0&quot; height=&quot;342&quot; width=&quot;410&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;[1] http://www.w3.org/DesignIssues/Semantic.html In post-singularity world, the Semantic Web understands you.&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/4466511402309735677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/4466511402309735677' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/4466511402309735677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/4466511402309735677'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2008/08/ssemantic-web-workshop.html' title='{s,S}emantic Web Workshop'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-3835130112442559635</id><published>2008-07-20T10:16:00.000-07:00</published><updated>2008-07-20T10:36:27.570-07:00</updated><title type='text'>MySQL, PostgreSQL and BLOB Streaming</title><content type='html'>You can store surprisingly large binary objects in your relational database[1], but even if your chosen system is perfectly &lt;span class=&quot;blsp-spelling-corrected&quot; id=&quot;SPELLING_ERROR_0&quot;&gt;OK&lt;/span&gt; with a 100 megabyte BLOB, you&#39;re going to have to handle all that data on its way to and from storage.&lt;br /&gt;&lt;br /&gt;With a 2 MB image file you can get away with reading the data fully into memory on each access. With a 100 MB file it&#39;s a little trickier. Not only is that a pretty big byte array, you may end up with multiple copies of it (your application&#39;s copy, the driver&#39;s copy, the &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_1&quot;&gt;database&#39;s&lt;/span&gt; copy, etc)&lt;br /&gt;&lt;br /&gt;The obvious answer is to stream the data. &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_2&quot;&gt;JDBC&#39;s&lt;/span&gt; BLOB interface has the convenient-looking &quot;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_3&quot;&gt;getBinaryStream&lt;/span&gt;&quot; and &quot;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_4&quot;&gt;setBinaryStream&lt;/span&gt;&quot; calls[2]. But if you actually try to use the calls you may get a nasty (and database-specific) surprise.&lt;br /&gt;&lt;br /&gt;MySQL, for instance, implements &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_5&quot;&gt;getBinaryStream&lt;/span&gt; in their &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_6&quot;&gt;JDBC&lt;/span&gt; driver as[3]:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;return new &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_7&quot;&gt;ByteArrayInputStream&lt;/span&gt;(&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_8&quot;&gt;getBinaryData&lt;/span&gt;());&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;You see the problem. There&#39;s no point in streaming the data when the driver is just going to read it all into memory anyway. There are some workarounds[4], but ultimately there are server-side limitations that you can only be avoided via a brand-new database engine[5].&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_9&quot;&gt;PostgreSQL&lt;/span&gt; has a reputation for being more mature than MySQL, and that&#39;s the case with handling large binary objects. Of course, another part of &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_10&quot;&gt;PostgresSQL&#39;s&lt;/span&gt; reputation is a Perl-like &quot;multiple ways to do everything&quot; approach, and there are a couple of different ways to handle &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_11&quot;&gt;BLOBs&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;There are two basic &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_12&quot;&gt;API&lt;/span&gt; approaches for this sort of thing: either pretend the huge bolus of binary gunk is just another column value stored along with all the other data for the row (whether it&#39;s really stored that way or not), or put a pointer (&quot;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_13&quot;&gt;locator&lt;/span&gt;&quot;) to the data in the relational row, and provide some other interface for actually working with the data.&lt;br /&gt;&lt;br /&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_14&quot;&gt;PostgreSQL&lt;/span&gt; does both, both at the database level (it has two different low-level mechanisms[6]) and the &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_15&quot;&gt;API&lt;/span&gt; level (it has several different &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_16&quot;&gt;APIs&lt;/span&gt; that expose out the underlying mechanism in various ways). Annoyingly, you can sort of mix and match the &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_17&quot;&gt;APIs&lt;/span&gt; and underlying implementations.&lt;br /&gt;&lt;br /&gt;The following discussion assumes the use of &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_18&quot;&gt;oid&#39;s&lt;/span&gt; (&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_19&quot;&gt;locators&lt;/span&gt;), not &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_20&quot;&gt;bytea&#39;s&lt;/span&gt; (in-row blobs, see the footnote above), which means at the database level we&#39;re going to expose out the &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_21&quot;&gt;locator&lt;/span&gt; (&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_22&quot;&gt;oid&lt;/span&gt;) in the column. In &lt;span class=&quot;blsp-spelling-corrected&quot; id=&quot;SPELLING_ERROR_23&quot;&gt;other&lt;/span&gt; words, if you do a &quot;SELECT&quot; on the column, it&#39;s going to give you a bunch of integer pointers, not a bunch of binary content.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;CREATE TABLE resource_record&lt;br /&gt;(&lt;br /&gt;id serial NOT NULL,&lt;br /&gt;content &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_24&quot;&gt;oid&lt;/span&gt;,&lt;br /&gt;...&lt;br /&gt;)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Luckily, &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_25&quot;&gt;PostgreSQL&#39;s&lt;/span&gt; &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_26&quot;&gt;JDBC&lt;/span&gt; driver will (mostly) allow you to treat the &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_27&quot;&gt;locator&lt;/span&gt; column like it really holds the BLOB directly:&lt;br /&gt;&lt;br /&gt;&lt;code&gt; Blob content = ....&lt;br /&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_28&quot;&gt;InputStream&lt;/span&gt; &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_29&quot;&gt;bodyStream&lt;/span&gt; = body.&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_30&quot;&gt;getBinaryStream&lt;/span&gt;();&lt;br /&gt;...&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Well, assuming you&#39;re inside a database transaction, which is generally the only time you can stream to or from a &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_31&quot;&gt;JDBC&lt;/span&gt; BLOB[8]&lt;br /&gt;&lt;br /&gt;But it&#39;s not quite perfect. The lower-level &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_32&quot;&gt;Postgres&lt;/span&gt; calls[9] allow &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_33&quot;&gt;BLOBs&lt;/span&gt; to be shared, so deleting a row doesn&#39;t necessarily delete the corresponding blob. That conflicts with normal &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_34&quot;&gt;JDBC&lt;/span&gt; semantics that assume the the BLOB is part of the row and should be deleted when the row is deleted. &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_35&quot;&gt;Postgres&#39;&lt;/span&gt; &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_36&quot;&gt;JDBC&lt;/span&gt; driver should probably implement those semantics, but it doesn&#39;t, so you have to run out and delete it yourself. One solution is to add the semantics back in via a trigger or rule:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;CREATE OR REPLACE FUNCTION on_resource_delete() RETURNS trigger&lt;br /&gt;AS $on_resource_delete$&lt;br /&gt;BEGIN&lt;br /&gt;  PERFORM lo_unlink( old.content );&lt;br /&gt;  RETURN null;&lt;br /&gt;END;&lt;br /&gt;$on_resource_delete$&lt;br /&gt;LANGUAGE &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_37&quot;&gt;plpgsql&lt;/span&gt;&lt;br /&gt;IMMUTABLE&lt;br /&gt;RETURNS NULL ON NULL INPUT&lt;br /&gt;&lt;br /&gt;CREATE TRIGGER resource_delete_trigger&lt;br /&gt;AFTER DELETE&lt;br /&gt;ON resource_record&lt;br /&gt;FOR EACH ROW EXECUTE PROCEDURE on_resource_delete()&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;If you&#39;re interested, the data is stored over in the system table &quot;pg_&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_38&quot;&gt;largeobject&lt;/span&gt;&quot;[10]&lt;br /&gt;&lt;br /&gt;Since this is &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_39&quot;&gt;PostgreSQL&lt;/span&gt;, the discussion wouldn&#39;t be complete without a mention of vacuum. Vacuum is the &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_40&quot;&gt;PostgreSQL&lt;/span&gt; &quot;garbage collector&quot;. If you don&#39;t run it, the disk space associated with deleted &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_41&quot;&gt;BLOBs&lt;/span&gt; won&#39;t be recovered. In production that may or may not matter, but during development it can a pain to lose the disk space.&lt;br /&gt;&lt;br /&gt;On my OS X machine, the file associated with the pg_&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_42&quot;&gt;largeobject&lt;/span&gt; table turned out to be:&lt;br /&gt;&lt;br /&gt;/Library/PostgresPlus/8.3/data/base/17456/2613&lt;br /&gt;&lt;br /&gt;If you load up a couple of fairly large &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_43&quot;&gt;BLOBs&lt;/span&gt;, you can probably figure out what file is being used on your system. It&#39;s comforting to watch it grow and shrink.&lt;br /&gt;&lt;br /&gt;So, although there are other options, it definitely works to:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Make the column an &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_44&quot;&gt;oid&lt;/span&gt;&lt;/li&gt;&lt;li&gt;Add the trigger if you want your BLOB deleted with its row&lt;/li&gt;&lt;li&gt;Use normal &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_45&quot;&gt;JDBC&lt;/span&gt; BLOB interface and stream away&lt;/li&gt;&lt;li&gt;Run a full vacuum occasionally if you need to recover disk space&lt;/li&gt;&lt;li&gt;Use a cache (like Squid) if you&#39;re serving the data back out over HTTP&lt;/li&gt;&lt;/ul&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;[1] If you&#39;ve chosen the right database, have some time to spend tuning, and are willing to install something like Squid if you&#39;re serving the data back out over HTTP, then single blobs of 100&#39;s of MB are not &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_46&quot;&gt;undoable&lt;/span&gt;. Whether it&#39;s good or evil is a different question.&lt;br /&gt;[2] &lt;a href=&quot;http://java.sun.com/javase/6/docs/api/java/sql/Blob.html&quot;&gt;http://java.sun.com/javase/6/docs/api/java/sql/Blob.html&lt;/a&gt;&lt;br /&gt;[3] mysql-connector-java-5.1.6/com/mysql/jdbc/Blob.java:108&lt;br /&gt;[4] MySQL also has a (seriously crippled) &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_47&quot;&gt;locator&lt;/span&gt;-based version: &lt;a href=&quot;http://dev.mysql.com/doc/refman/6.0/en/connector-j-reference-implementation-notes.html&quot;&gt;http://dev.mysql.com/doc/refman/6.0/en/connector-j-reference-implementation-notes.html&lt;/a&gt;, see [5] for why it&#39;s problematic.&lt;br /&gt;[5] &lt;a href=&quot;http://www.blobstreaming.org/&quot;&gt;http://www.blobstreaming.org/&lt;/a&gt; Even if you fix the client side to not read the entire BLOB into memory, the server side still does, and insists and transferring the entire thing every time, even if the client only wants a tiny piece. Which is why you need the whole new engine.&lt;br /&gt;[6] &lt;a href=&quot;http://jdbc.postgresql.org/documentation/80/binary-data.html&quot;&gt;http://jdbc.postgresql.org/documentation/80/binary-data.html&lt;/a&gt; gives an overview of &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_48&quot;&gt;PostgreSQL&lt;/span&gt; BLOB support, and how there are a lot of options.&lt;br /&gt;[8] Which is painful, because it means you may have to keep the transaction open a very long time if you&#39;re, say, streaming 80 MB of data in over http from a client on a slow network connection. That&#39;s the sort of thing that drives people to stream to a temporary file first, then from the temp file to the database.&lt;br /&gt;[9] The lo_* routines, see &lt;a href=&quot;http://www.postgresql.org/docs/8.3/interactive/largeobjects.html&quot;&gt;http://www.postgresql.org/docs/8.3/interactive/largeobjects.html&lt;/a&gt;&lt;br /&gt;[10] The data is stored as very many 2k chunks: &lt;a href=&quot;http://www.postgresql.org/docs/7.4/interactive/catalog-pg-largeobject.html&quot;&gt;http://www.postgresql.org/docs/7.4/interactive/catalog-pg-largeobject.html&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/3835130112442559635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/3835130112442559635' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3835130112442559635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3835130112442559635'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2008/07/mysql-postgresql-and-blob-streaming.html' title='MySQL, PostgreSQL and BLOB Streaming'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-5888508805341090656</id><published>2008-06-16T21:07:00.000-07:00</published><updated>2008-06-17T05:49:41.843-07:00</updated><title type='text'>Tessera at the Semantic Web Austin Launch Party</title><content type='html'>Ever tried to write an application that sits on top of a fine mist of questionably accurate factoids spread in varyingly dense clumps across the whole Internet? It&#39;s a pain. The {s,S}emantic Web is a &lt;span style=&quot;font-style: italic;&quot;&gt;terrible&lt;/span&gt; platform for applications. Developers need real APIs.&lt;br /&gt;&lt;br /&gt;I&#39;ll be at the &lt;a href=&quot;http://geekaustin.org/2008/05/29/semantic-web-austin-launch-party/&quot;&gt;Semantic Web Austin Launch Party&lt;/a&gt; (Tue, June 17th) talking about Tessera, an experiment in wrapping the distributed social web (XFN, FOAF, hCard, etc) with &lt;a href=&quot;http://en.wikipedia.org/wiki/OpenSocial&quot;&gt;OpenSocial&lt;/a&gt;, the API everybody-but-Facebook is using to expose out their social networking platform.&lt;br /&gt;&lt;br /&gt;Tessera is nowhere near complete, but it&#39;s far enough along to run simple OpenSocial gadgets, and I hope to have the OpenSocial version of &lt;a href=&quot;http://artofsystems.blogspot.com/2008/06/some-experiments-with-future-of-social.html&quot;&gt;Popcitation&lt;/a&gt; up and running by tonight. Or not. But there&#39;s certainly enough there to make for some interesting discussion. Hope to see you in Austin!</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/5888508805341090656/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/5888508805341090656' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/5888508805341090656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/5888508805341090656'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2008/06/tessera-at-semantic-web-austin-launch.html' title='Tessera at the Semantic Web Austin Launch Party'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-1912658783817338782</id><published>2008-06-04T17:30:00.000-07:00</published><updated>2008-06-04T19:51:18.537-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="dallas"/><category scheme="http://www.blogger.com/atom/ns#" term="engineering"/><category scheme="http://www.blogger.com/atom/ns#" term="startup"/><title type='text'>Some Experiments with the Future of Social Network Technology</title><content type='html'>I gave a presentation at the recent &lt;a href=&quot;http://www.facebook.com/home.php#/event.php?eid=16975616668&quot;&gt;Dallas Social Network Technology event&lt;/a&gt; (yes, we&#39;re still trying to come up with a good name. Pictures &lt;a href=&quot;http://www.flickr.com/photos/cks/sets/72157605437855332/&quot;&gt;here&lt;/a&gt;.). We ended up with something just over twenty people, but it was exactly the crowd we were hoping for: developers, startup-istas, entrepreneurs and business people actually &quot;doing something&quot; with social network technology. A quick canvas of the attendees indicated that a get-together maybe once a quarter or so, with a meetup for beers slightly more often, might be about right. There was some talk from the general direction of &lt;a href=&quot;http://www.alamofire.com/&quot;&gt;Alamofire &lt;/a&gt;about a game-focused event sometime in the fall, and I suspect there will be another general event between now and then.&lt;br /&gt;&lt;br /&gt;&lt;iframe src=&quot;http://docs.google.com/EmbedSlideshow?docid=ah7sbx3c6vpn_24spnf3n95&quot; frameborder=&quot;0&quot; height=&quot;342&quot; width=&quot;410&quot;&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;The presentation was combined with a live demonstration of the &lt;a href=&quot;http://apps.facebook.com/popcitation/&quot;&gt;Popcitation Facebook application&lt;/a&gt;, and both a Google and Facebook login to the &lt;a href=&quot;http://popcitation.com/&quot;&gt;Popciation destination site&lt;/a&gt;. (All of it, but especially popcitation.com, is a development spike to test out new technology, there&#39;s a good chance it won&#39;t work quite right for you.) I got about 10% of an &lt;a href=&quot;http://code.google.com/apis/opensocial/&quot;&gt;OpenSocial&lt;/a&gt; version done, I&#39;ll try to finish that up in the near future.&lt;br /&gt;&lt;br /&gt;Closing thought: it would be cool to have an OpenSocial container with &lt;a href=&quot;http://code.google.com/p/diso/&quot;&gt;DISO&lt;/a&gt; as the backend, huh? Need to do some more research along those lines, for all I know that&#39;s the standard assumption...</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/1912658783817338782/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/1912658783817338782' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/1912658783817338782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/1912658783817338782'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2008/06/some-experiments-with-future-of-social.html' title='Some Experiments with the Future of Social Network Technology'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-7195072170229242082</id><published>2008-05-22T06:31:00.000-07:00</published><updated>2008-05-22T07:30:49.546-07:00</updated><title type='text'>Coding and Comments</title><content type='html'>Some recent Twitter posts by Adam Keys got me thinking about the role of comments in code. Good and consistent coding style that reflects a solid development philosophy helps eliminate the need for many kinds of comments. Capturing requirements in a formal-ish way (through the use of techniques like Behavior and Domain Driven Design) eliminates even more. If important requirements can be captured formally in a &quot;live&quot;[1] way, they generally should be.&lt;br /&gt;&lt;br /&gt;But (a) you&#39;re not always in a situation where formal-ish requirements capture is possible and (b) there is some information that can&#39;t be captured formally.&lt;br /&gt;&lt;br /&gt;It&#39;s clear what needs to be done in the long term about (a), but in the mean time if you&#39;re going to have static text, it&#39;s good to have it as close to the code as possible. Comments let you do that.&lt;br /&gt;&lt;br /&gt;It&#39;s not so clear what can be done about (b). Even if you&#39;ve read the code and grok it 100%, there are situations (&quot;Although it&#39;s irrational, as of Oct. 18 2005, the accounting department insists we use HTTP basic auth without SSL&quot;) in which the code is not enough. Anything to do with people and their motivations, really.&lt;br /&gt;&lt;br /&gt;So, imagine yourself as a slightly-less-clever-than-you-think-you-are future reader of your own code. Imagine that you&#39;re generally familiar with the application, have read the code in some detail, and understand the development philosophy (hopefully) baked in throughout the system. If you&#39;re still thinking &quot;WTF?!&quot; then put in a comment. If it takes a full paragraph to explain the awful circumstances that led you write something impenetrable, then do it. Your future self will thank you.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:85%;&quot;&gt;[1] In post-Singularity world, code executes you. Until then, you can&#39;t really refactor, trace, test or formally analyze static natural-language text like comments or (shudder) external requirements docs. Natural language isn&#39;t &quot;live&quot;.&lt;br /&gt;&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/7195072170229242082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/7195072170229242082' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/7195072170229242082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/7195072170229242082'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2008/05/coding-and-comments.html' title='Coding and Comments'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14059280.post-3270245473218182037</id><published>2008-05-15T14:57:00.000-07:00</published><updated>2008-05-20T06:54:32.218-07:00</updated><title type='text'>Dallas Social Network Technology Event</title><content type='html'>Based in or around Dallas? Serious about developing an application based on social network technology? Was Facebook Dev Garage too Facebook specific for you? We&#39;re planning a get-together in early June you might be interested in. It&#39;s looking like the evening of &lt;span style=&quot;font-weight:bold;&quot;&gt;Tuesday, June 3rd starting at 7:00&lt;/span&gt; and going till about 9:00 &lt;span style=&quot;font-weight:bold;&quot;&gt;at the ritzy Sabre campus&lt;/span&gt; in scenic Southlake, TX:&lt;br /&gt;&lt;br /&gt; &lt;a href=&quot;http://maps.google.com/maps?f=q&amp;hl=en&amp;q=3150+Sabre+Dr.+Southlake,+TX+76092&amp;ie=UTF8&amp;om=1&amp;z=17&amp;ll=32.982478,-97.160393&amp;spn=0.004806,0.011759&amp;t=h&quot;&gt;Sabre Holdings&lt;/a&gt;&lt;br /&gt; 3150 Sabre Dr. Southlake, TX 76092&lt;br /&gt; (Campus Directions: &lt;a href=&quot;http://barcamp.pbwiki.com/f/DevCamp1.jpg&quot;&gt;Gate&lt;/a&gt; , &lt;a href=&quot;http://barcamp.pbwiki.com/f/Directions1.jpg&quot;&gt;Parking&lt;/a&gt; , &lt;a href=&quot;http://barcamp.pbwiki.com/f/Directions2.jpg&quot;&gt;Entrance&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;When you get to the security gate, tell the guard you&#39;re with the Social Network Technology event, and you&#39;re in like Flynn.&lt;br /&gt;&lt;br /&gt;Wiki at:&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://socialdevthing.pbwiki.com&quot;&gt;http://socialdevthing.pbwiki.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Facebook event page at:&lt;br /&gt;&lt;br /&gt;&lt;a href=&quot;http://www.facebook.com/event.php?eid=16975616668&quot;&gt;http://www.facebook.com/event.php?eid=16975616668&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Current agenda is a quick round of introductions at 7:00, some demos, some discussion, and a followup at a local tasty beverage establishment. Leave a message on the Facebook event wall if you&#39;re interested in demoing or have a particular topic you&#39;d like to focus on.</content><link rel='replies' type='application/atom+xml' href='http://artofsystems.blogspot.com/feeds/3270245473218182037/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment/fullpage/post/14059280/3270245473218182037' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3270245473218182037'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14059280/posts/default/3270245473218182037'/><link rel='alternate' type='text/html' href='http://artofsystems.blogspot.com/2008/05/dallas-social-network-technology-event.html' title='Dallas Social Network Technology Event'/><author><name>cks</name><uri>http://www.blogger.com/profile/11204008921771492577</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://farm1.static.flickr.com/39/88778450_c1a8190737_m_d.jpg'/></author><thr:total>0</thr:total></entry></feed>