<?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: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-7100397</id><updated>2012-05-27T21:59:20.793-07:00</updated><category term='clustering'/><category term='JPA'/><category term='data mining'/><category term='no-SQL'/><category term='JSP'/><category term='Lucene'/><category term='Google TV'/><category term='HTTPS'/><category term='RDFa'/><category term='Gambit-C'/><category term='Amazon'/><category term='Ring'/><category term='Clojure'/><category term='Wave'/><category term='open content'/><category term='open source'/><category term='textmining'/><category term='Prolog'/><category term='MongoDB'/><category term='EJB'/><category term='Seaside'/><category term='travel'/><category term='JRuby'/><category term='Freebase'/><category term='Pharo'/><category term='AI'/><category term='Smalltalk'/><category term='nginx'/><category term='social graph'/><category term='Squeak'/><category term='Mac'/><category term='Play Framework'/><category term='object mapping'/><category term='Mylin'/><category term='EC2'/><category term='Web 3.0'/><category term='Cassandra'/><category term='business'/><category term='jQuery'/><category term='knowledge management'/><category term='MySQL'/><category term='ODF'/><category term='RDF'/><category term='CSS'/><category term='Javascript'/><category term='semantic web'/><category term='economy'/><category term='NetBeans'/><category term='Latex'/><category term='support vector machines'/><category term='CouchDB'/><category term='Haskell'/><category term='Ontology'/><category term='iPhone'/><category term='AllegroGraph'/><category term='PostgreSQL'/><category term='Eclipse'/><category term='Sedona'/><category term='Emacs'/><category term='Buzz'/><category term='J2EE'/><category term='Python'/><category term='Dojo'/><category term='media'/><category term='Microsoft'/><category term='GWT'/><category term='admin'/><category term='MapReduce'/><category term='nutrition'/><category term='IT'/><category term='AppEngine'/><category term='SimpleDB'/><category term='AJAX'/><category term='web applications'/><category term='Sesame'/><category term='Compojure'/><category term='SOA'/><category term='Lisp'/><category term='C++'/><category term='Scala'/><category term='Hadoop'/><category term='Neo4j'/><category term='technical writing'/><category term='IDEs'/><category term='SSL'/><category term='productivity'/><category term='Android'/><category term='Scheme'/><category term='Facebook'/><category term='Mahout'/><category term='HTML5'/><category term='Heroku'/><category term='Platform as a Service'/><category term='NLP'/><category term='cloud computing'/><category term='Mongrel'/><category term='vacation'/><category term='Merb'/><category term='politics'/><category term='deployment'/><category term='games'/><category term='Java'/><category term='Google'/><category term='publishing'/><category term='AWS'/><category term='C#'/><category term='IntelliJ'/><category term='commercial products'/><category term='SmartGWT'/><category term='Ruby'/><category term='food'/><category term='Maven'/><category term='Linux'/><category term='Ruby Rails'/><category term='mobile devices'/><category term='source code'/><category term='search'/><category term='mathematics'/><category term='Ubuntu'/><category term='machine learning'/><category term='social media'/><category term='Glassfish'/><category term='health'/><category term='Erlang'/><title type='text'>Mark Watson's blog</title><subtitle type='html'>My opinions on Java, Ruby, Clojure, AI, data mining, and the Semantic Web. I am a consultant living in Sedona Arizona and an author of 16 published books covering Artificial Intelligence (AI), Java,  Ruby, C++, Lisp, Linux, and Windows.

I specialize in text and data mining, Ruby, Clojure, and Java development and general Artificial Intelligence programming.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.markwatson.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default?start-index=26&amp;max-results=25'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>1015</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7100397.post-2448286079647777820</id><published>2012-05-13T13:02:00.000-07:00</published><updated>2012-05-13T13:03:57.395-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='productivity'/><title type='text'>I am adjusting to a mobile digital life: the acceleration of convenience</title><content type='html'>&lt;p&gt;The first time I used a computer was in 1962 when I was 11 years old. It was not convenient: my Dad had to take me to his office to use one of the early timesharing systems using a local teletype machine with punched tape for saving and reloading stuff. A few years later I took an extension course at a local UC campus, FORTRAN with punched cards with nice keypunch facilities: definitely a large improvement!&lt;/p&gt; &lt;p&gt;In the 1980s life really got good: my own Xerox 1108 Lisp Machine and an Internet connection.&lt;/p&gt; &lt;p&gt;In the decades starting in 1990 and 2000 there were continual improvements but progress was gradual: better Internet connections, the development of the Web, improvements in software tools like code repositories, IDEs, etc.&lt;/p&gt; &lt;p&gt;Skipping ahead to the present time, I am trying to adjust my digital life, including my work and writing flows, to a more mobile lifestyle.&lt;/p&gt; &lt;p&gt;Probably the biggest change for me is that I used to keep just about everything that I worked with and touched in a repository (first cvs, then svn, and now git). I no longer need incremental backups of all of my work because for low priority stuff I can always dig back in time using simple Time Machine backups of my MacBook Air. I do still use a lot of git repositories for high value assets like:&lt;ul&gt;&lt;li&gt;Software development projects for customers&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/mark-watson/"&gt;My open source projects at github&lt;/a&gt;&lt;/li&gt;&lt;li&gt;My own high value projects such as software and other assets for my web properties and commercial software products&lt;/li&gt;&lt;/ul&gt;This is a major change for me. I keep other assets that don't really need versioning on DropBox:&lt;ul&gt;&lt;li&gt;All assets for my writing projects: books I have written in the past, my current writing project, etc.&lt;/li&gt;&lt;li&gt;A million + 1 small code snippets and small bits or program code organized by all languages that I use (Common Lisp, Java, Ruby, Scheme, Haskell, Python, Prolog, etc. (whenever I figure out a new coding technique, how to do something generally useful, etc., I always like to save a little code snippet to refer to later)&lt;/li&gt;&lt;li&gt;Favorite pictures taken in my lifetime (old ones are now digitized)&lt;/li&gt;&lt;li&gt;Favorite videos taken in my lifetime (lots of digitally converted 8mm videos from my childhood through recent vacation videos: everything!)&lt;/li&gt;&lt;li&gt;All of my personal notes organized by travel logs, personal writing, etc.&lt;/li&gt;&lt;li&gt;A large fraction of the huge amount of music that I have purchased, organized by artist (and sometimes also by album)&lt;/li&gt;&lt;li&gt;Most of the eBooks that I have ever purchased if they are not in the Kindle format.&lt;/li&gt;&lt;/ul&gt; For Kindle books not purchased through Amazon, I email them to my Kindle/Amazon email address and let Amazon manage keeping everything in-sync on all of my devices. Kindle platform syncing the current reading location across devices is a huge convenience since I routinely read on my Kindle, iPad, and MacBook Air.&lt;/p&gt; &lt;p&gt;I am careful to not keep anything that is highly proprietary on DropBox (i.e., assets for customer projects). I used to also keep well organized directories of useful reading material found on the web (e.g., PDFs on AI, machine learning, NLP, server deployments, etc., etc.). I have very recently made the rather large step in throwing all of this material into Evernote, backing it up, and deleting it.&lt;/p&gt; &lt;p&gt;The really big win in relying on DropBox, Evernote, and the Kindle platforms is being able to switch between computers easily and also have most of my stuff available on my iPad and Droid cellphone. I use several computers and it is a slight nuisance doing a &lt;i&gt;git pull&lt;/i&gt; every time I switch computers. I like to use mobile devices for reading and general thinking time and this is a lot easier now. I have been running Apple's beta OS X Mountain Lion that has iCloud integration. There is a chance that if iCloud is very well implemented that I may slowly transition away from DropBox to iCloud, and switch to using an iPhone. However, DropBox is very well implemented so Apple would need to make iCloud's implementation across all Apple devices very, very good for me to make the switch.&lt;/p&gt; &lt;p&gt;Saving the last &lt;b&gt;big win&lt;/b&gt; for last: a mobile digital life promotes more of what Clojure creator (and general programming mentor) Rich Hickey calls "hammock time": the time you spend away from the computer thinking. I still use a pad or paper and a pen for away from a computer thinking time, but I find mobile devices augment this activity nicely.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-2448286079647777820?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/2448286079647777820/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=2448286079647777820&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/2448286079647777820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/2448286079647777820'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/05/i-am-adjusting-to-mobile-digital-life.html' title='I am adjusting to a mobile digital life: the acceleration of convenience'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-4518676713731302039</id><published>2012-05-11T19:42:00.001-07:00</published><updated>2012-05-19T13:22:19.929-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='search'/><title type='text'>Since Bing search and spelling APIs are no longer free, I did a quick survey of other services and signed up for Yahoo BOSS search.</title><content type='html'>&lt;p&gt;I signed up for Google's APIs around 2002 and used it until they stopped the service. I later switched to Microsoft's Bing APIs: the cost was great, free! Bing's new entry level cost of $40/month for 20,000 queries does not match my use case. I wish they had a $5/month for 2000 queries.&lt;/p&gt; &lt;p&gt;I do a low volume of search for personal research projects and prototypes. Yahoo BOSS's service has an attractive price but I worry about the service being terminated with the deal with Microsoft. Google offers custom site search, but I didn't see any options for a general paid-for web search API.&lt;/p&gt; &lt;p&gt;So, I signed up with &lt;a href="http://developer.yahoo.com/search/boss/"&gt;Yahoo BOSS for search&lt;/a&gt; and if the service is ever terminated, I will look elsewhere. The price is good, $0.80 per 1000 queries.&lt;/p&gt; &lt;p&gt;&lt;b&gt;2012-05-19 edit:&lt;/b&gt; &lt;a href="https://datamarket.azure.com/dataset/5BA839F1-12CE-4CCE-BF57-A49D98D29A44"&gt;Bing search&lt;/a&gt; now has a free tier for up to 5000 search requests per month. Cool! For research purposes, this is good enough.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-4518676713731302039?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/4518676713731302039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=4518676713731302039&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/4518676713731302039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/4518676713731302039'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/05/since-bing-search-and-spelling-apis-are.html' title='Since Bing search and spelling APIs are no longer free, I did a quick survey of other services and signed up for Yahoo BOSS search.'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-8702914479751764869</id><published>2012-04-23T13:24:00.002-07:00</published><updated>2012-05-13T08:49:13.170-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Clojure'/><title type='text'>Back from Vacation, catching up on work, and a Java retrospective</title><content type='html'>Carol and I got home from visiting family in Rhode Island late last night and I have been working catching up on  customer work since 4am this morning. Here is a picture of my birthday dinner. &lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-aTSvpxxe85Y/T5WuazIRxPI/AAAAAAAAFn0/49QAcgIgN-U/s1600/Mark%2527s%2Bbirthday%2Bdinner.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-aTSvpxxe85Y/T5WuazIRxPI/AAAAAAAAFn0/49QAcgIgN-U/s320/Mark%2527s%2Bbirthday%2Bdinner.jpg" width="239" /&gt;&lt;/a&gt;&lt;/div&gt;The kids got two pound lobsters for everyone - I am holding mine and a plate of grilled veggies.&lt;br/&gt;&lt;br/&gt;&lt;b&gt;Java&lt;/b&gt;: I used to do research programming in Common Lisp or Scheme. For ideas that worked I often re-coded them in Java for better deployment options, for better alignment with customer preferences, etc. I fell out of that habit six or seven years ago because I had a long term Common Lisp development job and also really got into Ruby and Clojure development. Both Ruby and Clojure are great for research programming and for some types of applications the deployment options are good.&lt;br/&gt;&lt;br/&gt;That said, even Clojure which is efficient (about 1/3 the speed of Java and uses about 3 times the amount of memory) wastes computing resources (hits the environment and the pocketbook). Ruby is much less efficient than Clojure.&lt;br/&gt;&lt;br/&gt;I started thinking about efficiency after talking on my flight home to an Intel engineer who was sitting next to me on the plane. He was reading through a book on DSP  with tons of differential equations. He said that he used C sometimes but felt better about projects that were mostly done in assembler language because it was a shame to waste processing cycles. We ended up talking about the efficiency of programming languages.&lt;br/&gt;&lt;br/&gt;I still believe that it makes sense to prototype systems in whatever language and platform make sense for getting working code in place quickly. The decision is whether to recode for more efficient deployments and if so when to do it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-8702914479751764869?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/8702914479751764869/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=8702914479751764869&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/8702914479751764869'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/8702914479751764869'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/04/back-from-vacation-catching-up-on-nlp.html' title='Back from Vacation, catching up on work, and a Java retrospective'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-aTSvpxxe85Y/T5WuazIRxPI/AAAAAAAAFn0/49QAcgIgN-U/s72-c/Mark%2527s%2Bbirthday%2Bdinner.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-6498034203814300704</id><published>2012-03-18T14:07:00.000-07:00</published><updated>2012-03-18T14:18:47.634-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AI'/><category scheme='http://www.blogger.com/atom/ns#' term='Clojure'/><title type='text'>Using Wolfram Alpha from Clojure</title><content type='html'>&lt;p&gt;I have been blown away in the last year by Wolfram Alpha but I haven't done much with the &lt;a href="http://products.wolframalpha.com/api/"&gt;developer's APIs&lt;/a&gt;. To make it easier to experiment with Wolfram Alpha, I wrote a simple Clojure wrapper for the Java APIs. You can get a copy at &lt;a href="https://github.com/mark-watson/clojure_wolfram_alpha"&gt;github&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;In case you don't want to grab the github repo, here is most of the code:&lt;pre&gt;(ns wolfram)&lt;br /&gt;&lt;br /&gt;(def appid (System/getenv "WOLFRAM_APP_ID"))&lt;br /&gt;(def engine (com.wolfram.alpha.WAEngine.))&lt;br /&gt;(.setAppID engine appid)&lt;br /&gt;(.addFormat engine "plaintext")&lt;br /&gt;&lt;br /&gt;(defn query [input]&lt;br /&gt;  (let [query (.createQuery engine)]&lt;br /&gt;    (.setInput query input)&lt;br /&gt;    (let [result (.performQuery engine query)]&lt;br /&gt;      {:pods&lt;br /&gt;       (for [pod (.getPods result)]&lt;br /&gt;         {:title (.getTitle pod)&lt;br /&gt;          :sub-pods&lt;br /&gt;          (for [sub-pod (.getSubpods pod)]&lt;br /&gt;            (for [contents (.getContents sub-pod)]&lt;br /&gt;              (.getText contents)))})})))&lt;/pre&gt;Notice that you need to set the API key for your application in an environment variable. You get 2000 free API calls a month. Here is some sample output (with some output removed for brevity):&lt;pre&gt;test=&gt; (query "distance between San Diego and San Francisco")&lt;br /&gt;{:pods ({:title "Input interpretation", :sub-pods (("distance | from | San Diego, California\nto | San Francisco, California"))} {:title "Result", :sub-pods (("453.7 miles"))} {:title "Unit conversions", :sub-pods (("730.2 km  (kilometers)") ("730194 meters") ("7.302?10^7 cm  (centimeters)") ("394.3 nmi  (nautical miles)"))} {:title "Direct travel times", :sub-pods (("aircraft  (550 mph) | 49 minutes 30 seconds\nsound | 36 minutes\nlight in fiber | 3.41 ms  (milliseconds)\nlight in vacuum | 2.44 ms  (milliseconds)\n(assuming constant-speed great-circle path)"))} {:title "Map", :sub-pods ((""))})}&lt;br /&gt;user=&gt; (query "pi")&lt;br /&gt;{:pods ({:title "Input", :sub-pods (("pi"))} {:title "Decimal approximation", :sub-pods (("3.1415926535897932384626433832795028841971693993751058..."))} {:title "Property", :sub-pods (("pi is a transcendental number"))} {:title "Number line", :sub-pods ((""))} {:title "Continued fraction", :sub-pods (("[3; 7, 15, 1, 292, 1, 1, 1, 2, 1, 3, 1, 14, 2, 1, 1, 2, 2, 2, 2, 1, 84, 2, 1, 1, 15, ...]"))} {:title "Alternative representations", :sub-pods (("pi = 180 ?") ("pi = -i log(-1)") ("pi = cos^(-1)(-1)"))} {:title "Series representations", :sub-pods (("pi = 4 sum_(k=0)^infinity(-1)^k/(2 k+1)") ("pi = -2+2 sum_(k=1)^infinity2^k/(binomial(2 k, k))") ("pi = sum_(k=0)^infinity(50 k-6)/(2^k binomial(3 k, k))"))} {:title "Integral representations", :sub-pods (("pi = 2 integral_0^infinity1/(t^2+1) dt") ("pi = 4 integral_0^1 sqrt(1-t^2) dt") ("pi = 2 integral_0^infinity(sin(t))/t dt"))})}&lt;/pre&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-6498034203814300704?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/6498034203814300704/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=6498034203814300704&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/6498034203814300704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/6498034203814300704'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/03/using-wolfram-alpha-from-clojure.html' title='Using Wolfram Alpha from Clojure'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-269364337193238966</id><published>2012-03-03T16:36:00.002-07:00</published><updated>2012-03-03T20:39:03.364-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='politics'/><category scheme='http://www.blogger.com/atom/ns#' term='knowledge management'/><category scheme='http://www.blogger.com/atom/ns#' term='economy'/><title type='text'>A bright future, with some potential problems</title><content type='html'>&lt;p&gt;Even though the news media portrays a dire world situation, I disagree. In the last few decades the world has become a safer place and fundamental shifts in technology keep driving down the cost of computing resources, networks, and storage that enable greatly increased global productivity. For much of the world globalization is a rising tide that floats most people's boats.&lt;/p&gt; &lt;p&gt;The problem is that not everyone benefits from new paradigms for constant lifelong learning, diminishing advantages of organizations who hold to old mega-scale production and business models, and a free flow of information. The book &lt;a href="http://www.amazon.com/gp/product/0465019358/ref=as_li_tf_tl?ie=UTF8&amp;tag=markwatsonassoci&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0465019358"&gt;The Power of Pull&lt;/a&gt; is a good reference for ideas how to take advantage of the transitions that the world is going through, whether you like them or not!&lt;/p&gt; &lt;p&gt;The losers in this new world are people and organizations who cannot (or don't want to) adapt and learn and who expect material rewards that are out of touch with their productivity. The biggest potential problem that concerns me is that some of these "losers" have tremendous political and economic clout and will struggle to hang on to old advantages instead of engaging in more forward thinking and productive activities. You don't have to look further than businesses that are "too big to fail" to understand the real dangers of powerful incumbents to our future prosperity and security.&lt;/p&gt; &lt;p&gt;On a personal level, I do believe that for the most part we have control of our lives and that both our happiness and sadness in life is mostly an internal process in our own minds and is fairly independent of the world at large. Certainly, some people are born into, or live, in very harsh situations, but for most people there is at least the opportunity for material success and personal happiness. A cliche, but true: people who live in the past tend to be depressed, those who live in the future are anxious, and those who live in the moment are usually happy and content. The more we can focus our attention on what we are doing in the moment the happier and more productive we can be.&lt;/p&gt; &lt;p&gt;I leave it up to you how you want to manage your life, but I will mention a few things that work for me:&lt;ul&gt;&lt;li&gt;I don't waste much time exposing myself to the negatively toned corporate-slanted news media. It is necessary to understand what is happening in the world, and why, but a few minutes a day reading news stories from multiple sources around the world suffices.&lt;/li&gt;&lt;li&gt;Everyday I enjoy the time I set aside for learning new technologies, practicing a musical instrument, trying new recipes, hiking with friends, and generally enjoying my family. Without fun time, it is difficult to be productive while working.&lt;/li&gt;&lt;li&gt;I spend time and resources helping and mentoring people, and working extra time each week to support three very worthwhile charities. I am convinced that a quality life requires the certain knowledge that we are personally helping to make the world a better place.&lt;/li&gt;&lt;li&gt;Time is probably our most precious resource. In addition to saving the time not wasted on corporate news, I try to evaluate how I spend my time, realizing that watching TV, watching too many movies, and other mindless time sinks all have tremendous opportunity costs: how much more can we accomplish and how much more can we enjoy our lives if we apply critical thinking to how we spend our time?&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-269364337193238966?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/269364337193238966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=269364337193238966&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/269364337193238966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/269364337193238966'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/03/bright-future-with-some-potential.html' title='A bright future, with some potential problems'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-3947033100758490841</id><published>2012-02-19T11:46:00.001-07:00</published><updated>2012-02-20T08:17:08.779-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Clojure'/><title type='text'>Using pjax with Clojure and Noir: minimize client side Javascript code while maintaining fast page load times</title><content type='html'>&lt;p&gt;I don't like doing a lot of client side Javascript (or Coffeescript) development. pjax is a way to minimize client side Javascript while maintaining fast page load times.&lt;/p&gt; &lt;p&gt;I became interested in pjax after reading an article on the development of Basecamp Next. DHH indicated that they looked at pjax but then rolled their own similar system.&lt;/p&gt; &lt;p&gt;Here is a &lt;a href="https://github.com/mark-watson/noir-pjax-example"&gt;github repo&lt;/a&gt; with a Clojure and Noir example web app using pjax that I wrote this morning. There were a few non-obvious aspects to using pjax with Noir so hopefully this will save you some time.&lt;/p&gt; &lt;p&gt;If you don't want to grab the github repo, here are a few interesting code snippets. First, we need to run a little Javascript to process links to set up for AJAX calls setting a "X-PJAX" header:&lt;pre&gt;$(function(){&lt;br /&gt;    // Activate PJAX test links&lt;br /&gt;    // Response will be loaded into #wrapper element&lt;br /&gt;    $('a').pjax('#wrapper')&lt;br /&gt;})&lt;/pre&gt;I put this code in resoures/public/js/application.js which is loaded in the common Clojure page wrapping code (in common.clj):&lt;pre&gt;(ns noir-pjax-example.views.common&lt;br /&gt;  (:use [noir.core :only [defpartial]]&lt;br /&gt;        hiccup.core&lt;br /&gt;        hiccup.page-helpers))&lt;br /&gt;&lt;br /&gt;(defpartial layout [&amp; content]&lt;br /&gt;  (println "\n**** layout\n")&lt;br /&gt;  (html5&lt;br /&gt;    [:head [:title "noir-pjax-example"]&lt;br /&gt;     (include-css "/css/reset.css")&lt;br /&gt;     (include-js "/js/jquery.js")&lt;br /&gt;     (include-js "/js/jquery.pjax.js")&lt;br /&gt;     (include-js "/js/application.js")]&lt;br /&gt;    [:body "&amp;lt;h1&amp;gt;&amp;lt;b&amp;gt;Demo of pjax with Clojure and Noir&amp;lt;/b&amp;gt;&amp;lt;/h1&amp;gt;&amp;lt;br/&gt;&amp;lt;br/&amp;gt;"&lt;br /&gt;     "&amp;lt;div id=\"wrapper\"&amp;gt;"&lt;br /&gt;     content&lt;br /&gt;     "&amp;lt;/div&amp;gt;"]))&lt;/pre&gt;The trick is that this wrapper code only gets executed one time and the browser only needs to set up the page one time. Only the div with id "wrapper" gets replaced by the standard pjax Javascript file jquery.pjax.js.&lt;/p&gt; &lt;p&gt;Sure, there is still Javascript using pjax, but you don't have to write much at all. In this case, I am "pjax-ifying" all HTML links with the small Javascript snippet in application.js; in a real application, you would be more selective and perhaps also set up multiple page elements that pjax updates. The following code snippet shows the file welcome.clj:&lt;pre&gt;(ns noir-pjax-example.views.welcome&lt;br /&gt;  (:require [noir-pjax-example.views.common :as common]&lt;br /&gt;            [noir.content.getting-started])&lt;br /&gt;  (:require noir.request)&lt;br /&gt;  (:use [noir.core :only [defpage]]&lt;br /&gt;        [hiccup form-helpers page-helpers]&lt;br /&gt;        hiccup.core&lt;br /&gt;        hiccup.page-helpers))&lt;br /&gt;&lt;br /&gt;(defpage "/" []&lt;br /&gt;  (if (nil? (((noir.request/ring-request) :headers)&lt;br /&gt;             "x-pjax"))&lt;br /&gt;    (common/layout&lt;br /&gt;      [:p "Welcome to noir-pjax-example /"]&lt;br /&gt;      [:a {:href "/"} "foo 1"])&lt;br /&gt;    (str&lt;br /&gt;      "&amp;lt;p&amp;gt;Welcome to noir-pjax-example /&amp;lt;/p&amp;gt;"&lt;br /&gt;      "&amp;lt;a class=foo href=\"/foo\"&amp;gt;foo 2&amp;lt;/a&amp;gt;")))&lt;br /&gt;&lt;br /&gt;(defpage "/foo" []&lt;br /&gt;  (if (nil? (((noir.request/ring-request) :headers)&lt;br /&gt;             "x-pjax"))&lt;br /&gt;    (common/layout&lt;br /&gt;      [:p "Welcome to noir-pjax-example /foo"]&lt;br /&gt;      [:a {:href "/"} "home 4"])&lt;br /&gt;    (str&lt;br /&gt;      "&amp;lt;p&amp;gt;Welcome to noir-pjax-example /foo&amp;lt;/p&amp;gt;"&lt;br /&gt;      "&amp;lt;a class=foo href=\"/\"&amp;gt;home 3&amp;lt;/a&amp;gt;")))&lt;/pre&gt;There is not much of a trick here: I check to see if there is a "x-pjax" header and if there is I don't call the common layout page wrapper function.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-3947033100758490841?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/3947033100758490841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=3947033100758490841&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/3947033100758490841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/3947033100758490841'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/02/using-pjax-with-clojure-and-noir.html' title='Using pjax with Clojure and Noir: minimize client side Javascript code while maintaining fast page load times'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-1925892826775661211</id><published>2012-02-17T15:32:00.000-07:00</published><updated>2012-02-17T15:32:36.110-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby Rails'/><category scheme='http://www.blogger.com/atom/ns#' term='Javascript'/><title type='text'>Nice discovery: PJAX and Rails</title><content type='html'>&lt;p&gt;Well this has been a discovery for me :-)&lt;p&gt; &lt;p&gt;I finished my work early today and started my afternoon working through a simple iOS 5 tutorial. As recreation, I went over to Hacker News and read a linked &lt;a href="http://37signals.com/svn/posts/3112-how-basecamp-next-got-to-be-so-damn-fast-without-using-much-client-side-ui"&gt;article&lt;/a&gt; by David Heinemeier Hansson on making the response time fast on Basecamp Next while still doing mostly server side processing. The article and the comments were great.&lt;/p&gt; &lt;p&gt;This is of some interest to me because I have recently spent a lot of time writing a lot of client side Javascript for a Dojo + Rails app: straightforward but time consuming. DHH in the article and HN comments was making the point that for his company, it was a better developer experience doing more with server side Rails and less custom rich client code in Coffeescript or Javascript. I agree. He, and other people in the comments mentioned &lt;a href="https://github.com/defunkt/jquery-pjax"&gt;pjax&lt;/a&gt; as a library for sending back requests to the server that are marked with a HTTP header 'X-PJAX' if the page layout is not to be returned. This makes it relatively easy to still write mostly server side code but make page load times small when most or all of the page layout is not changed. &lt;a href="https://github.com/edison/pjax-rails-sample"&gt;Here&lt;/a&gt; is a simple Rails demo program by Edison Machado.&lt;/p&gt; &lt;p&gt;I need a few days to digest this, but this is likely going to change how I write Rails applications.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-1925892826775661211?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/1925892826775661211/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=1925892826775661211&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/1925892826775661211'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/1925892826775661211'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/02/nice-discovery-pjax-and-rails.html' title='Nice discovery: PJAX and Rails'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-372847000821624331</id><published>2012-02-16T13:26:00.001-07:00</published><updated>2012-02-23T16:03:33.199-07:00</updated><title type='text'>I feel a bit like a traitor to the open source movement: I just re-signed up as a Mac OS X and iOS developer</title><content type='html'>&lt;p&gt;I am a Linux enthusiast (downloaded my first distro over a 2400 baud modem, a long time ago!) and I really like the Android platform.&lt;/p&gt; &lt;p&gt;That said, I have really been enjoying the integration between my iPad and my Apple iTV (that my stepson gave me for Christmas) and the Mountain Lion OS X information released today makes me feel fairly certain that the "Apple experience" is what I want when I am not earning money doing server side Java, AI and textmining consulting gigs, etc. For the work I do for making money (i.e., consulting) it doesn't matter what computer and operating system that I use. I am even planning on trading in my Droid cellphone for an iPhone this year.&lt;/p&gt; &lt;p&gt;I also have a long history with Apple. I prepaid for an Apple II and received serial number 71. I wrote the simple little chess program that Apple gave away on a cassette tape for a while. When the Mac shipped in 1984 I bought one right away and wrote a commercial app that generated a lot of revenue. So, Apple and I are old friends :-)&lt;/p&gt; &lt;p&gt;One of the reasons I paid Apple today to (re)join their developers program is that I want to play around with the early developers release of Mountain Lion. I would also like to experiment (play!) with the intersection of iOS and OS X rich clients for web services, etc.&lt;/p&gt;&lt;p&gt;&lt;i&gt;Edit: I installed Mountain Lion. So far I like it and the only disappointment is that Air Play is not working (yet) to my iTV. As expected not all Apple apps are updated to use iCloud storage, etc.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;Edit #2: AirPlay Mirroring doesn't work yet on an Intel Core 2 Duo processor.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;Edit #3: after 1 week: I have spent a few hours working through Apple's iOS 5 and OS X Xcode tutorials - fun stuff, but I am going to spend less time on this in the near future because I am very busy with work projects.&lt;/i&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-372847000821624331?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/372847000821624331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=372847000821624331&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/372847000821624331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/372847000821624331'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/02/i-feel-bit-like-traitor-to-open-source.html' title='I feel a bit like a traitor to the open source movement: I just re-signed up as a Mac OS X and iOS developer'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-1999024800253265530</id><published>2012-02-11T11:42:00.000-07:00</published><updated>2012-02-11T11:45:29.894-07:00</updated><title type='text'>github repo for 4th edition of my Java AI book</title><content type='html'>&lt;p&gt;As of right now, this new &lt;a href="https://github.com/mark-watson/Java-AI-Book-Code"&gt;github repo&lt;/a&gt; mostly contains the code from the 3rd edition of my book but as I re-write the book, I'll also be updating my code. Some of this Java code really needs a rewrite: many of the examples from the first edition were written in 1998 - a long time ago! I have reworked the code with each new edition. The code examples are licensed under the LGPL but I am considering dual licensing them under Apache 2 also.&lt;/p&gt; &lt;p&gt;Any suggestions for code improvements, pull requests, etc. will be appreciated.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-1999024800253265530?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/1999024800253265530/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=1999024800253265530&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/1999024800253265530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/1999024800253265530'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/02/github-repo-for-4th-edition-of-my-java.html' title='github repo for 4th edition of my Java AI book'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-5254524883363528981</id><published>2012-01-21T13:27:00.000-07:00</published><updated>2012-01-21T13:43:15.837-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='no-SQL'/><title type='text'>Citrusleaf: an interesting (non open source) NoSQL data store</title><content type='html'>I have been using &lt;a href="http://citrusleaf.net/devIndex.php"&gt;Citrusleaf&lt;/a&gt; for a customer (&lt;a href="http://www.sitescout.com/"&gt;SiteScout&lt;/a&gt;) task. Interesting technology. Maybe because I am excessively frugal, but I almost always favor open source tools (Ruby, Clojure, Java, PostgreSQL, MongoDB, Emacs, Rails, GWT, etc., etc. that I base my businesses on). That said, I also rely on paid for software and services (IntelliJ, Rubymine, Heroku, AWS services, etc.) and it looks like Citrusleaf is a worthy tool because of its speed and scalability (which it gets from Paxos, using lots of memory, efficient multicast when possible for communication between nodes in a cluster, etc.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-5254524883363528981?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/5254524883363528981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=5254524883363528981&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/5254524883363528981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/5254524883363528981'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/01/citrusleaf-interesting-non-open-source.html' title='Citrusleaf: an interesting (non open source) NoSQL data store'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-3917474865065529767</id><published>2012-01-18T22:12:00.000-07:00</published><updated>2012-01-21T13:35:54.992-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='no-SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Amazon'/><category scheme='http://www.blogger.com/atom/ns#' term='AWS'/><title type='text'>Yes, the DynamoDB managed data service is a very big deal</title><content type='html'>&lt;p&gt;Just announced today: &lt;a href="http://aws.amazon.com/dynamodb/"&gt;DynamoDB&lt;/a&gt; solves several problems for developers:&lt;ul&gt;&lt;li&gt;No administration except for creating database tables (including some decisions like using simple lookup keys or keys with range indices and whether reads should be consistent or not)&lt;/li&gt;&lt;li&gt;Fast and predictable performance at any scale (but see comment below on the requirement for provisioning)&lt;/li&gt;&lt;li&gt;Fault tolerance&lt;/li&gt;&lt;li&gt;Efficient atomic counters&lt;/li&gt;&lt;/ul&gt;The probable hassle for developers that I see is in knowing how to provision tables for reasonable numbers of allowed reads and writes per second. When you create tables one option is to get warning emails when you hit 80% of provisioning capacity; I interpret this to mean that you really had better not go over the capacity that you have provisioned. Amazon needs to know how much capacity you need in order to allocate enough computing nodes for your tables. The capacity that you pay for can be raised and lowered to avoid getting runtime exceptions when you go over your provisioned number of reads and/or write per second.&lt;/p&gt; &lt;p&gt;The lastest AWS Java SDK handles DynamoDB. For Ruby, the latest aws-sdk (&lt;i&gt;gem install aws-sdk&lt;/i&gt;) supports DynamoDB. I signed up for DynamoDB, looked at the Java example, and wrote a little bit of working Ruby code using &lt;a href="http://docs.amazonwebservices.com/AWSRubySDK/latest/frames.html"&gt;documentation&lt;/a&gt; - I had to slightly change the example code to get it to work for me:&lt;pre&gt;require 'aws-sdk'&lt;br /&gt;&lt;br /&gt;dynamo_db = AWS::DynamoDB.new(&lt;br /&gt;    :access_key_id =&gt; ENV['AMAZON_ACCESS_KEY_ID'],&lt;br /&gt;    :secret_access_key =&gt; ENV['AMAZON_SECRET_ACCESS_KEY'])&lt;br /&gt;table = dynamo_db.tables.create('my-table', 10, 5)&lt;br /&gt;&lt;br /&gt;begin&lt;br /&gt;  sleep 3&lt;br /&gt;  puts "Waiting on status change #{table.status}"&lt;br /&gt;end while table.status == :creating&lt;br /&gt;&lt;br /&gt;# add an item&lt;br /&gt;item = table.items.create('id' =&gt; '12345', 'foo' =&gt; 'bar')&lt;br /&gt;&lt;br /&gt;# add attributes to an item&lt;br /&gt;item.attributes.add 'category' =&gt; %w(demo), 'tags' =&gt; %w(sample item)&lt;br /&gt;p item&lt;br /&gt;&lt;br /&gt;# update an item with mixed add, delete, update&lt;br /&gt;item.attributes.update do |u|&lt;br /&gt;  u.add 'colors' =&gt; %w(red)&lt;br /&gt;  u.set 'category' =&gt; 'demo-category'&lt;br /&gt;  u.delete 'foo'&lt;br /&gt;end&lt;br /&gt;p item.attributes.to_h&lt;br /&gt;&lt;br /&gt;# delete attributes&lt;br /&gt;item.attributes.delete 'colors', 'category'&lt;br /&gt;&lt;br /&gt;# get attributes&lt;br /&gt;p item.attributes.to_h&lt;br /&gt;&lt;br /&gt;# delete an item and all of its attributes&lt;br /&gt;item.delete&lt;/pre&gt;I used the AWS web console to then delete the test table to avoid charges.&lt;/p&gt; &lt;p&gt;DynamoDB is a big deal because while it is easy enough to horizontally scale out web applications and back end business applications, it is a real pain to scale out data storage for session handling and application data. Except for paying for the service, Amazon is trying to remove these hassles for developers.&lt;/p&gt; &lt;p&gt;I think that in addition to deployments to EC2s, DynamoDB will be a very big deal for Heroku users because it gives them another data store option in addition to Heroku's excellent managed PostgreSQL service, MongoHQ, Cloudant, and other 3rd party data service providers.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-3917474865065529767?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/3917474865065529767/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=3917474865065529767&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/3917474865065529767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/3917474865065529767'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/01/yes-dynamodb-managed-data-service-is.html' title='Yes, the DynamoDB managed data service is a very big deal'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-4841992873825169315</id><published>2012-01-11T12:14:00.000-07:00</published><updated>2012-01-11T12:26:23.513-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='semantic web'/><title type='text'>Web 3.0 and the Semantic Web, a slight return</title><content type='html'>&lt;p&gt;After talking with a friend and a friend of his about the Semantic Web and healthcare yesterday, I re-watched a great &lt;a href="http://vimeo.com/11529540"&gt;video&lt;/a&gt; on Web 3.0 by Kate Ray that I bookmarked and &lt;a href="http://blog.markwatson.com/2010/05/very-good-movie-by-kate-ray-web-30.html"&gt;blogged about&lt;/a&gt; a couple of years ago. I like this video because it frames the problems that the Semantic Web is trying to solve. My last published book (for APress) had Web 3.0 in the title, a term that did not really catch on :-)&lt;/p&gt; &lt;p&gt;At least a little bit of my enthusiasm for Semantic Web technologies has diminished over the last ten years because of problems that I have had on customer projects trying to collect linked data from disparite sources and merge it into something useful. There are (apparently) no silver bullets and any data collection and exploitation activities involve a lot of difficult work.&lt;/p&gt; &lt;p&gt;I would not be surprised if this problem of merging different data sources is &lt;u&gt;not&lt;/u&gt; solved by using Ontologies and webs of linked data sites, but rather, by vendors curating data in narrow domains and selling interfaces to this curated data.&lt;/p&gt; &lt;p&gt;In a world of too much information the activity of curation can have a very high value and this value and the market price for these services will determine the amount of resources invested in combinations of automated and manual curation of information.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-4841992873825169315?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/4841992873825169315/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=4841992873825169315&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/4841992873825169315'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/4841992873825169315'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/01/web-30-and-semantic-web-slight-return.html' title='Web 3.0 and the Semantic Web, a slight return'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-8811843194108409702</id><published>2012-01-10T16:34:00.002-07:00</published><updated>2012-01-10T16:34:54.575-07:00</updated><title type='text'>sleepybird.us site is online</title><content type='html'>Yesterday I wrote about two web portals I have been working on in Clojure. One of them is online: &lt;a href="http://sleepybird.us/"&gt;our stock photo web site&lt;/a&gt;.  This is a simple web app written with Clojure and Noir. I use the excellent &lt;a href="http:stripe.com"&gt;stripe.com&lt;/a&gt; system for accepting orders for JPEGs (and soon hi-def video clips). In my tests it seems easy enough to buy JPEG files: you just check the ones you want, go to the purchase page, and in a few seconds you are downloading a ZIP file with the JPEGs you purchased. A simple little web app but I think that my wife and I will have fun with it: we are avid photographers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-8811843194108409702?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/8811843194108409702/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=8811843194108409702&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/8811843194108409702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/8811843194108409702'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/01/sleepybirdus-site-is-online.html' title='sleepybird.us site is online'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-6472826592877425370</id><published>2012-01-09T17:08:00.000-07:00</published><updated>2012-01-19T16:31:28.433-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AppEngine'/><category scheme='http://www.blogger.com/atom/ns#' term='Clojure'/><title type='text'>My two new projects: both web portals written in Clojure</title><content type='html'>I have three web portal projects that I have wanted to develop for quite some time. I am close to releasing two of them (&lt;a href="http://kbsportal.com"&gt;a text analytics web service&lt;/a&gt; and a &lt;a href="http://sleepybird.us/sedonaredrocks"&gt;stock photos and video clip store&lt;/a&gt;. My wife and I are avid photographers and we have been wanting to travel more and do more photography; I started putting together the photo site yesterday morning and hope to have it fully on line in the next day of two - simple to implement. The text analytics web service will be publicly available within a month or so (right now, just the demo page is active - I short circuited the new account login for now).  My third project is a web portal for a single consultant to manage multiple customers. Last year I prototyped this for my own use using Java + GWT + AppEngine and then ported it off of AppEngine, using MongoDB for the data store. I have had such a fun and productive time using Clojure and Noir for my two recent projects that I am considering porting this third project to Clojure. I might leave it as-is except that I have already done most of the design for a more complex web app to manage multiple consultants with multiple customers. I know that the development would go much faster using Lisp.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-6472826592877425370?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/6472826592877425370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=6472826592877425370&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/6472826592877425370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/6472826592877425370'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/01/my-two-new-businesses-both-web-portals.html' title='My two new projects: both web portals written in Clojure'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-290571565873998462</id><published>2012-01-02T13:25:00.002-07:00</published><updated>2012-01-02T13:31:50.931-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Emacs'/><title type='text'>Using Emacs and org-mode in OS X</title><content type='html'>&lt;p&gt;I recently ran across &lt;a href="http://orgmode.org/worg/org-tutorials/orgtutorial_dto.html"&gt;David O'Toole's org-mode tutorial&lt;/a&gt; and I have been experimenting with using org-mode with Emacs instead of the little utility &lt;a href="http://my-foc.us/login"&gt;web app&lt;/a&gt; I wrote for my own use a few years ago. I decided that I like org-mode better after learning the basic commands even though I can no longer access my to-do lists from ay web browser. Org-mode is useful for more than simply managing to-do lists and tasks but that is what I am mostly using it for.&lt;/p&gt; &lt;p&gt;To make org-mode always easily available I added this to my &lt;b&gt;~/.profile&lt;/b&gt;:&lt;pre&gt;alias orgmode='echo -e "\033]0;org-mode\007";Emacs -nw ~/Documents/org-mode/.'&lt;/pre&gt;This will open org-mode in a the current term window tab and change the tab title to "org-mode." I keep all of my org-files in &lt;b&gt;/Users/markw/Documents/org-mode/&lt;/b&gt; so change that bit of bash script to reflect where you want to keep your org data files. You might also want to substitute &lt;b&gt;emacs&lt;/b&gt; for &lt;b&gt;Emacs -nw&lt;/b&gt; which is what I use for command line Emacs because I prefer the latest version 2.4.x of Emacs.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-290571565873998462?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/290571565873998462/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=290571565873998462&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/290571565873998462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/290571565873998462'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2012/01/using-emacs-and-org-mode-in-os-x.html' title='Using Emacs and org-mode in OS X'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-3533971567610175374</id><published>2011-12-05T12:27:00.001-07:00</published><updated>2011-12-05T12:38:20.469-07:00</updated><title type='text'>(re) learning Clojure</title><content type='html'>&lt;p&gt;I have been using Clojure for about 25% of my consulting work in the last 2 years, read two books on Clojure, and I had some Clojure examples in a book I wrote last year.&lt;/p&gt; &lt;p&gt;That said, I don't really feel "expert" at the language the way I do with Java, Ruby, and Common Lisp.&lt;/p&gt; &lt;p&gt;I am trying to fill in some gaps by carefully reading through &lt;a href="http://ianeslick.com/pages/about-me"&gt;one of my customer's&lt;/a&gt; &lt;a href="https://github.com/eslick"&gt;Clojure code&lt;/a&gt;, and all Clojure libraries that I use like Noir, Compojure, etc. I am trying to pick up more idioms. I enjoy it when I see a new trick in someone else's code and going back to my code to improve it.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-3533971567610175374?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/3533971567610175374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=3533971567610175374&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/3533971567610175374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/3533971567610175374'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2011/12/re-learning-clojure.html' title='(re) learning Clojure'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-7388366219301419392</id><published>2011-12-04T09:29:00.001-07:00</published><updated>2011-12-04T11:03:10.197-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='semantic web'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Using the New York Times Semantic Web APIs</title><content type='html'>&lt;p&gt;I am working on a side project of my own in Clojure using the AllegroGraph 4 and Stardog RDF repositories (thanks to Franz and to Clark &amp; Parsia for licenses to use their products!) and my own NLP code. I am using the excellent NYT data access APIs to get research/test data.&lt;/p&gt; &lt;p&gt;I am going to show you some simple examples in Ruby for accessing the &lt;a href="http://developer.nytimes.com/docs/The_Semantic_API#h2-request-name"&gt;NYT Semantic Web APIs&lt;/a&gt; that are free to use up to 5000 API calls a day.&lt;/p&gt; &lt;p&gt;I also use other NYT APIs. Each API has an access key that you need to sign up for. I set my access keys as environment variables that I access in my code; for example in Ruby:&lt;pre&gt;# New York Times API Keys:&lt;br /&gt;NYT_SEMANTIC_WEB = ENV['NYT_SEMANTIC_WEB']&lt;br /&gt;NYT_SEARCH = ENV['NYT_SEARCH']&lt;br /&gt;NYT_NEWSWIRE = ENV['NYT_NEWSWIRE']&lt;br /&gt;NYT_PEOPLE = ENV['NYT_PEOPLE']&lt;br /&gt;NYT_TAGS = ENV['NYT_TAGS']&lt;/pre&gt;&lt;/p&gt; In the following code snippets, I am only using the Semantic Web APIs. I want to first search for available concept types and concept names, based on keyword search:&lt;pre&gt;require 'simple_http'&lt;br /&gt;require 'json'&lt;br /&gt;&lt;br /&gt;def semantic_concept_search query&lt;br /&gt;  uri = "http://api.nytimes.com/svc/semantic/v2/" +&lt;br /&gt;        "concept/search.json?" +&lt;br /&gt;        "query=#{CGI.escape(query)}&amp;api-key=" +&lt;br /&gt;        NYT_SEMANTIC_WEB&lt;br /&gt;  JSON.parse(SimpleHttp.get(uri))&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def  pp_semantic_concept_search query&lt;br /&gt;  json = semantic_concept_search(query)&lt;br /&gt;  puts "Results:\n"&lt;br /&gt;  json["results"].each do |result|&lt;br /&gt;    puts "\n\tconcept_name:\t#{result['concept_name']}"&lt;br /&gt;    puts "\tconcept_type:\t#{result['concept_type']}"&lt;br /&gt;    puts "\tconcept_uri:\t#{result['concept_uri']}" if result['concept_uri']&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;pp_semantic_concept_search("Obama")&lt;/pre&gt;The second method "pretty prints" the JSON data that I am interested in. Some of the sample output looks like:&lt;pre&gt;concept_name: Obama, Barack&lt;br /&gt;concept_type: nytd_per&lt;br /&gt;concept_uri: http://data.nytimes.com/47452218948077706853&lt;br /&gt;&lt;br /&gt;concept_name: Obama, Malia&lt;br /&gt;concept_type: nytd_per&lt;br /&gt;&lt;br /&gt;concept_name: Obama, Michelle&lt;br /&gt;concept_type: nytd_per&lt;br /&gt;concept_uri: http://data.nytimes.com/N13941567618952269073&lt;br /&gt;&lt;/pre&gt; Once I have a concept type and concept name I can then look up articles:&lt;pre&gt;def lookup_concept_data concept_type, concept_name&lt;br /&gt;  uri = "http://api.nytimes.com/svc/semantic/v2/" +&lt;br /&gt;        "concept/name/#{concept_type}/" +&lt;br /&gt;        "#{CGI.escape(concept_name)}.json?&amp;" +&lt;br /&gt;        "fields=all&amp;api-key=" + NYT_SEMANTIC_WEB&lt;br /&gt;  JSON.parse(SimpleHttp.get(uri))&lt;br /&gt;end&lt;br /&gt; &lt;br /&gt;def pp_lookup_concept_data concept_type, concept_name&lt;br /&gt;  puts "** type: #{concept_type} name: #{concept_name}"&lt;br /&gt;  json = lookup_concept_data(concept_type, concept_name)&lt;br /&gt;  puts "Results:\n"&lt;br /&gt;  json["results"].each do |result|    puts "\n\tLinks:"&lt;br /&gt;    result["links"].each do |link|&lt;br /&gt;      puts "\t\trelation: #{link['relation']}"&lt;br /&gt;      puts "\t\tlink: #{link['link']}"&lt;br /&gt;      puts "\t\tlink_type: #{link['link_type']}"&lt;br /&gt;    end&lt;br /&gt;    result["article_list"]["results"].each do |article|&lt;br /&gt;      puts "\tTitle: #{article['title']}"&lt;br /&gt;      puts "\tDate: #{article['date']}"&lt;br /&gt;      puts "\tBody: #{article['body']}\n\n"&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;pp_lookup_concept_data('nytd_per', 'Obama, Barack')&lt;/pre&gt;Some sample output looks like:&lt;pre&gt;Links:&lt;br /&gt; relation: sameAs&lt;br /&gt; link: http://rdf.freebase.com/ns/en.barack_obama&lt;br /&gt; link_type: freebase_uri&lt;br /&gt; relation: sameAs&lt;br /&gt; link: http://dbpedia.org/resource/Barack_Obama&lt;br /&gt; link_type: dbpedia_uri&lt;br /&gt; relation: sameAs&lt;br /&gt; link: http://en.wikipedia.org/wiki/Barack_Obama&lt;br /&gt; link_type: wikipedia_uri&lt;br /&gt;&lt;br /&gt;Title: U.S. Urges Egypt To Let Civilians Govern Quickly&lt;br /&gt;Date: 20111126&lt;br /&gt;Body: WASHINGTON -- Ever since tens of thousands of protesters converged on Tahrir Square in Cairo for the first Day of Revolution exactly 10 months ago, the Obama administration has struggled to strike the right balance between democracy and stability. In the early morning hours on Friday, President Obama came out on the side of the Arab street, issuing&lt;br /&gt;&lt;br /&gt;Title: EDITORIAL; The Solyndra Mess&lt;br /&gt;Date: 20111125&lt;br /&gt;Body: The Republicans on the House Energy and Commerce Committee appear to have hit the pause button on their investigation into the failure of Solyndra, a solar panel maker that entered bankruptcy proceedings in September, defaulting on a $528 million federal loan. What have we learned? Nobody comes out of this looking good. Not the Obama&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;Great to see useful linked data/Semantic Web data sources being made available! Hopefully these little code snippets will save you some time in getting started using the NYT APIs.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-7388366219301419392?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/7388366219301419392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=7388366219301419392&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/7388366219301419392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/7388366219301419392'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2011/12/using-new-york-times-semantic-web-apis.html' title='Using the New York Times Semantic Web APIs'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-4002671677121567246</id><published>2011-11-26T16:14:00.001-07:00</published><updated>2011-11-26T16:30:16.741-07:00</updated><title type='text'>Closer to the metal: Clojure, Noir, and plain old Javascript</title><content type='html'>&lt;p&gt;I am wrapping up a long term engagement over the next five to six weeks that uses Java EE 6 on the backend, and SmartGWT (like GWT, but with very nice commercially supported components) clients. As I have time, I am starting up some new work that uses Clojure and Noir, and it is like a breath of fresh air:&lt;/p&gt; &lt;p&gt;I keep a repl open on the lein project and also separately run the web app so any file changes (including the Javascript in the project) are immediately reflected in the app. Such a nice development environment that I don't even think about it while I am working, and maybe that is the point!&lt;/p&gt; &lt;p&gt;As I have mentioned in previous blog posts, I &lt;i&gt;really&lt;/i&gt; like the Clojure Noir web framework that builds on several other excellent projects. Developing in Noir is a lot like using the Ruby Sinatra framework: handles routes, template support options, but it is largely &lt;i&gt;roll your own environment&lt;/i&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-4002671677121567246?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/4002671677121567246/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=4002671677121567246&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/4002671677121567246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/4002671677121567246'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2011/11/closer-to-metal-clojure-noir-and-plain.html' title='Closer to the metal: Clojure, Noir, and plain old Javascript'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-6261811047073950100</id><published>2011-11-21T21:37:00.001-07:00</published><updated>2011-11-22T08:30:18.405-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JRuby'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Ruby Sinatra web apps with background work threads</title><content type='html'>In Java-land, I have often used the pattern of writing a servlet with an &lt;i&gt;init()&lt;/i&gt; method that starts up one or more background work threads. Then while my web application is handling HTTP requests the background threads can be doing work like fetching RSS feeds for display in the web app, perform periodic maintenance like flushing old data from a database, etc. This is a simple pattern that is robust and easy to implement with a few extra lines of Java code and an extra servlet definition in a web.xml file.  &lt;p&gt;In Ruby-land this pattern is even simpler to implement:&lt;/p&gt;&lt;pre&gt;require 'rubygems'&lt;br /&gt;require 'sinatra'&lt;br /&gt;&lt;br /&gt;$sum = 0&lt;br /&gt;&lt;br /&gt;Thread.new do # trivial example work thread&lt;br /&gt;  while true do&lt;br /&gt;     sleep 0.12&lt;br /&gt;     $sum += 1&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;get '/' do&lt;br /&gt;  "Testing background work thread: sum is #{$sum}"&lt;br /&gt;end&lt;/pre&gt;While the main thread is waiting for HTTP requests the background thread can do any other work. This works fine with Ruby 1.8.7 or any 1.9.*, but I would run this in JRuby for a long-running production app since JRuby uses the Java Thread class.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-6261811047073950100?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/6261811047073950100/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=6261811047073950100&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/6261811047073950100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/6261811047073950100'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2011/11/ruby-sinatra-web-apps-with-background.html' title='Ruby Sinatra web apps with background work threads'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-8421289752050087650</id><published>2011-11-21T14:14:00.001-07:00</published><updated>2011-11-22T08:32:06.779-07:00</updated><title type='text'>Using the Stardog RDF datastore from JRuby</title><content type='html'>I was playing with the latest &lt;a href="http://stardog.com/"&gt;Stardog&lt;/a&gt; release during lunch - the way to quickly get going with the included Java examples is to create a project (I use IntelliJ, but use your favorite Java IDE) and include all JAR files in &lt;i&gt;lib/&lt;/i&gt; (included all nested directories) and the source under &lt;i&gt;examples/src&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;I took the first Java example class&amp;nbsp;ConnectionAPIExample and converted the RDF loading and query part to JRuby (strange formatting to get it to fit the page width):&lt;br /&gt;&lt;pre&gt;require 'java'&lt;br /&gt;Dir.glob("lib/**.jar").each do |fname|&lt;br /&gt;  require fname&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;com.clarkparsia.stardog.security.SecurityUtil.&lt;br /&gt;      setupSingletonSecurityManager()&lt;br /&gt;com.clarkparsia.stardog.StardogDBMS.get().&lt;br /&gt;      createMemory("test")&lt;br /&gt;&lt;br /&gt;CONN = com.clarkparsia.stardog.api.&lt;br /&gt;        ConnectionConfiguration.to("test").connect()&lt;br /&gt;CONN.begin()&lt;br /&gt;CONN.add().io().format(org.openrdf.rio.RDFFormat::N3).&lt;br /&gt;  stream(java.io.FileInputStream.new(&lt;br /&gt;            "examples/data/sp2b_10k.n3"))&lt;br /&gt;&lt;br /&gt;QUERY = CONN.query("select * where {?s ?p ?o}")&lt;br /&gt;QUERY.limit(10)&lt;br /&gt;RESULTS = QUERY.executeSelect()&lt;br /&gt;&lt;br /&gt;while RESULTS.hasNext() do&lt;br /&gt;  result = RESULTS.next()&lt;br /&gt;  result.getBindingNames().toArray().each do |obj|&lt;br /&gt;    puts "#{obj}: #{result.getBinding(obj).getValue().stringValue()}"&lt;br /&gt;  end&lt;br /&gt;  puts&lt;br /&gt;end&lt;/pre&gt;This is mostly just a straight conversion from Java to Ruby. The first few lines enumerate all JAR files and require them. The last part, of&amp;nbsp;interpreting&amp;nbsp;the results, took a few minutes to figure out. I used IntelliJ to explore the result values of class&amp;nbsp;MapBindingSet, looking at available methods to call to get the binding names of the variables in my SPARQL query and the values (as strings) for these three variables for each returned result.&lt;br /&gt;&lt;br /&gt;Output will look like:&lt;pre&gt;s: http://localhost/vocabulary/bench/Journal&lt;br /&gt;p: http://www.w3.org/2000/01/rdf-schema#subClassOf&lt;br /&gt;o: http://xmlns.com/foaf/0.1/Document&lt;br /&gt;&lt;br /&gt;s: http://localhost/vocabulary/bench/Proceedings&lt;br /&gt;p: http://www.w3.org/2000/01/rdf-schema#subClassOf&lt;br /&gt;o: http://xmlns.com/foaf/0.1/Document&lt;br /&gt;...&lt;/pre&gt;If you want to run this bit of code, put it in a file test.rb in the top level Stardog distribution directroy and just run&lt;pre&gt;jruby test.rb&lt;/pre&gt;I wanted to be able to use Stardog from both JRuby and Clojure. My lunch time hacking today is just a first step.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-8421289752050087650?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/8421289752050087650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=8421289752050087650&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/8421289752050087650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/8421289752050087650'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2011/11/using-stardog-rdf-datastore-from-jruby.html' title='Using the Stardog RDF datastore from JRuby'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-8372990095760349782</id><published>2011-11-15T19:05:00.001-07:00</published><updated>2011-11-15T20:39:35.408-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='AppEngine'/><title type='text'>Experimenting with Google Cloud SQL</title><content type='html'>I received a beta invite today and had some time to read the documentation and start experimenting with it tonight.&lt;br /&gt;&lt;br /&gt;First, the best thing about Google Cloud SQL: when you create an instance you can specify more than one AppEngine application instances that can use it. This should give developers a lot of flexibility for coordinating multiple deployed applications that are in an application family. I think that this is a big deal!&lt;br /&gt;&lt;br /&gt;Another interesting thing is that you are allowed some access to the database from outside the AppEngine infrastructure. You are limited to 5 external queries per second but that does offer some coordination with other applications hosted on other platforms or host providers.&lt;br /&gt;&lt;br /&gt;Their cloud SQL service is free during beta. It will be interesting to see what the cost will be for different SQL instance types.&lt;br /&gt;&lt;br /&gt;It was very simple getting the &lt;a href="https://code.google.com/apis/sql/docs/developers_guide_java.html"&gt;example Java app&lt;/a&gt; built and deployed. I &lt;a href="https://code.google.com/apis/sql/docs/before_you_begin.html#request_a_sql_service_instance"&gt;created a separate SQL instance&lt;/a&gt; (these are separate from other deployed AppEngine application instances), made a new IntelliJ AppEngine project, pasted in the example code, and it all worked.&lt;br /&gt;&lt;br /&gt;Perception of quality is often influenced by price. Since developers now have to pay more for using AppEngine, I find myself looking more at AppEngine as a premium service, which it is. Despite my dislike for MySQL (I use PostgreSQL when given a choice), Google's hosted and managed MySQL cloud data service looks good and provides developers with more options. Their SQL service is synchronously replicated between data centers automatically for you.&lt;br /&gt;&lt;br /&gt;It has been a few years now since I had to either set up a physical server or a leased raw server for any deployments. I like that! Thank you Platform as a Service (PaaS) providers like Heroku (built on AWS) and AppEngine - they are the future. I still do a lot of work on "plain AWS" but that is still much more agile than provisioning my own servers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-8372990095760349782?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/8372990095760349782/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=8372990095760349782&amp;isPopup=true' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/8372990095760349782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/8372990095760349782'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2011/11/experimenting-with-google-cloud-sql.html' title='Experimenting with Google Cloud SQL'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-3579127882440694719</id><published>2011-11-12T08:57:00.001-07:00</published><updated>2011-11-12T09:15:36.870-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Clojure'/><title type='text'>The quality of new programming languages is apparent by looking at projects using the language</title><content type='html'>The community growing around the Clojure language is great. While the Clojure platform is still evolving (quickly!) browsing through available libraries, frameworks, and complete projects is amazing.&lt;br /&gt;&lt;br /&gt;My "latest" favorite Clojure project is &lt;a href="http://www.webnoir.org/"&gt;Noir&lt;/a&gt; that simply provides a composable mechanism for building web applications (using &lt;i&gt;defpartial&lt;/i&gt;). I get to use Noir on two customer web app projects (and some work with HBase + Clojure) over the next month or two, and I am looking forward to that. The simpler of the two web apps is an admin console exposing some APIs on a private LAN and the &lt;a href="http://tryclj.com/"&gt;Try Clojure&lt;/a&gt; web app is a great starting point, as well as an example of a nicely laid out Noir application.&lt;br /&gt;&lt;br /&gt;Since Clojure is such a concise language I find it easy to read through, understand, evaluate, and use projects. Since I am still learning Clojure (I have just used Clojure for about 6 months of paid work over the last couple of years) the time spent reading a lot of available code to find useful stuff is very well spent because reading good code with an open&amp;nbsp;&lt;i&gt;repl&lt;/i&gt; is a great way to learn new idioms.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-3579127882440694719?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/3579127882440694719/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=3579127882440694719&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/3579127882440694719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/3579127882440694719'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2011/11/quality-of-new-programming-languages-is.html' title='The quality of new programming languages is apparent by looking at projects using the language'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-1846873624321896281</id><published>2011-11-07T15:14:00.000-07:00</published><updated>2011-11-08T09:29:33.820-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='SmartGWT'/><title type='text'>Writing a simple SQL data source for the free LGPL version of SmartGWT</title><content type='html'>&lt;p&gt;While travelling back from a vacation I cleaned up some old experimental code for writing a fairly generic SmartGWT data source with the required server side support code. The commercial versions of SmartGWT have support for connecting client side grid and other components to server side databases. For the free version of SmartGWT you have to &lt;i&gt;roll your own&lt;/i&gt; and in this post I'll show you a simple way to do this that should get you started. Copy the sample web app that is included in the free LGPL version of SmartGWT and make the modifications listed below.&lt;/p&gt;&lt;p&gt;I also set up a &lt;a href="https://github.com/mark-watson/SmargGWT_LGPL_SQL_DATASOURCE"&gt;Github project&lt;/a&gt; that contains everything ready to run in IntelliJ.&lt;/p&gt;&lt;p&gt;The goal is to support defining client side grids connected to a database using a simple SQL statement to fetch the required data using a custom class &lt;b&gt;SqlDS&lt;/b&gt;. I had to strangely format the following code snippets to get them to fit the content width for my blog:&lt;/p&gt;&lt;pre&gt;    ListGrid listGrid = new ListGrid();&lt;br /&gt;    listGrid.setDataSource(&lt;br /&gt;      new &lt;b&gt;SqlDS&lt;/b&gt;(&lt;br /&gt;         "select title, content, uri from news where " +&lt;br /&gt;         "content like '%Congress%'"));&lt;br /&gt;    listGrid.setAutoFetchData(true);&lt;/pre&gt;&lt;p&gt;The following datasource looks for the column names (i.e., "title", "content", and "uri") in the SQL query and creates fields in the constructed SqlDS instance with those column names. I also assume that there is a servlet defined to process the HTTP GET fetch at the bottom of the constructor: &lt;pre&gt;package com.markwatson.client;&lt;br /&gt;&lt;br /&gt;import com.smartgwt.client.data.DataSource;&lt;br /&gt;import com.smartgwt.client.data.DataSourceField;&lt;br /&gt;import com.smartgwt.client.types.DSDataFormat;&lt;br /&gt;import com.smartgwt.client.types.FieldType;&lt;br /&gt;&lt;br /&gt;import java.util.Arrays;&lt;br /&gt;import java.util.List;&lt;br /&gt;&lt;br /&gt;public class SqlDS extends DataSource {&lt;br /&gt;  public SqlDS(String sql) {&lt;br /&gt;    setID(id);&lt;br /&gt;    setDataFormat(DSDataFormat.JSON);&lt;br /&gt;&lt;br /&gt;    List&amp;lt;String&amp;gt; tokens =&lt;br /&gt;        Arrays.asList(sql.toLowerCase()&lt;br /&gt;           .replaceAll(",", " ").split(" "));&lt;br /&gt;    int index1 = tokens.indexOf("select");&lt;br /&gt;    int index2 = tokens.indexOf("from");&lt;br /&gt;    for (int i=index1+1; i&amp;lt;index2; i++) {&lt;br /&gt;      if (tokens.get(i).length() &amp;gt; 0) {&lt;br /&gt;         addField(new DataSourceField(tokens.get(i),&lt;br /&gt;               FieldType.TEXT, tokens.get(i)));&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;    // should do a better job at UUENCODEing SQL:&lt;br /&gt;    setDataURL("/news?query="+ sql.replaceAll(" ","20%"));&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;The only thing left to do is write a servlet that processes web wervice requests like &lt;b&gt;/news?query=...&lt;/b&gt; and returns JSON data with fields from the SQL query for each returned row for display in the list grid:&lt;/p&gt;&lt;pre&gt;package com.markwatson.server;&lt;br /&gt;&lt;br /&gt;import javax.servlet.http.HttpServlet;&lt;br /&gt;import javax.servlet.http.HttpServletRequest;&lt;br /&gt;import javax.servlet.http.HttpServletResponse;&lt;br /&gt;import java.io.IOException;&lt;br /&gt;import java.io.PrintWriter;&lt;br /&gt;&lt;br /&gt;public class DbRestServlet extends HttpServlet {&lt;br /&gt;    @Override&lt;br /&gt;    public void doGet(HttpServletRequest req,&lt;br /&gt;         HttpServletResponse resp) throws IOException {&lt;br /&gt;      PrintWriter out = resp.getWriter();&lt;br /&gt;      try {&lt;br /&gt;          // remove "query="&lt;br /&gt;          String sql = req.getQueryString().substring(6); &lt;br /&gt;          int index = sql.indexOf("&amp;");&lt;br /&gt;          sql = sql.substring(0, index);&lt;br /&gt;          out.println(&lt;br /&gt;             &lt;b&gt;DbUtils&lt;/b&gt;.doQuery(sql.replaceAll("20%", " ")));&lt;br /&gt;      } catch (Exception ex) {&lt;br /&gt;        ex.printStackTrace(System.err);&lt;br /&gt;        out.println("[]");&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;The utility class &lt;b&gt;DbUtils&lt;/b&gt; returns JSON data which is what the client side SqlDS DataSource class expects from the server:&lt;/p&gt;&lt;pre&gt;package com.markwatson.server;&lt;br /&gt;&lt;br /&gt;import org.codehaus.jackson.map.ObjectMapper;&lt;br /&gt;&lt;br /&gt;import java.io.StringWriter;&lt;br /&gt;import java.sql.Connection;&lt;br /&gt;import java.sql.DriverManager;&lt;br /&gt;import java.sql.ResultSet;&lt;br /&gt;import java.sql.Statement;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.HashMap;&lt;br /&gt;import java.util.List;&lt;br /&gt;import java.util.Map;&lt;br /&gt;&lt;br /&gt;public class DbUtils {&lt;br /&gt;  static String dbURL;&lt;br /&gt;  static Connection dbCon;&lt;br /&gt;&lt;br /&gt;  static {&lt;br /&gt;    try {&lt;br /&gt;      Class.forName("org.postgresql.Driver");&lt;br /&gt;      // Define the data source for the driver&lt;br /&gt;      dbURL = "jdbc:postgresql://localhost/test_database";&lt;br /&gt;      dbCon = DriverManager.getConnection(&lt;br /&gt;                     dbURL, "postgres", "password");&lt;br /&gt;    } catch (Exception e) {&lt;br /&gt;      e.printStackTrace();&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  public static String doQuery(String sql)&lt;br /&gt;                               throws Exception {&lt;br /&gt;    ObjectMapper mapper =&lt;br /&gt;       new ObjectMapper(); // should cache and reuse this!&lt;br /&gt;    List&amp;lt;Map&amp;lt;String, String&amp;gt;&amp;gt; ret =&lt;br /&gt;        new ArrayList&amp;lt;Map&amp;lt;String, String&amp;gt;&amp;gt;();&lt;br /&gt;    Statement statement = dbCon.createStatement();&lt;br /&gt;    ResultSet rs = statement.executeQuery(&lt;br /&gt;                            sql.replaceAll("20%", " "));&lt;br /&gt;    java.sql.ResultSetMetaData meta = rs.getMetaData();&lt;br /&gt;    int size = meta.getColumnCount();&lt;br /&gt;    while (rs.next()) {&lt;br /&gt;      Map&amp;ltString, String&amp;gt; row =&lt;br /&gt;         new HashMap&amp;ltString, String&amp;gt;();&lt;br /&gt;      for (int i = 1; i &amp;lt= size; i++) {&lt;br /&gt;        String column = meta.getColumnName(i);&lt;br /&gt;        Object obj = rs.getObject(i);&lt;br /&gt;        row.put(column, "" + obj);&lt;br /&gt;      }&lt;br /&gt;      ret.add(row);&lt;br /&gt;    }&lt;br /&gt;    StringWriter sw = new StringWriter();&lt;br /&gt;    mapper.writeValue(sw, ret);&lt;br /&gt;    return sw.toString();&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;p&gt;I had to add three JAR files to the SmartGWT sample project:&lt;/p&gt;&lt;pre&gt;jackson-core-lgpl-1.8.1.jar&lt;br /&gt;jackson-mapper-lgpl-1.8.1.jar&lt;br /&gt;postgresql-9.0-801.jdbc4.jar&lt;/pre&gt;&lt;p&gt;SmartGWT's DataSource abstraction is a real improvement over how I connect to databases in GWT apps where I tend to write a lot of small RPC services to fetch and save data as required. My simple DataSource subclass SqlDS does not support writing data back to the database from the client; it can either be extended or you can use a RPC service call to save edited data.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-1846873624321896281?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/1846873624321896281/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=1846873624321896281&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/1846873624321896281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/1846873624321896281'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2011/11/writing-simple-sql-data-source-for-free.html' title='Writing a simple SQL data source for the free LGPL version of SmartGWT'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-8341401130039334518</id><published>2011-11-06T10:51:00.000-07:00</published><updated>2011-11-06T10:56:19.512-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MongoDB'/><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='Clojure'/><title type='text'>Annoyed by anti-MongoDB post on HN</title><content type='html'>I am not going to link to this article - no point in giving it more attention. The anonymous post claimed data loss and basic disaster using MongoDB. I call bullshit on this anonymous rant. Why was it posted&amp;nbsp;anonymously?&lt;br /&gt;&lt;br /&gt;I am sitting in an airport waiting to fly home right now: just finished extending a Java+MongoDB+GWT app and I am starting to do more work on a project using Clojure+Noir+MongoDB.&lt;br /&gt;&lt;br /&gt;I do have a short checklist for using MongoDB:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;For each write operation I decide if I can use the default write and forget option or slightly slow down the write operation by checking &lt;i&gt;CommandResult cr = db.getLastError();&lt;/i&gt; - every write operation can be fine tuned based on the cost of losing data. I usually give up a little performance for data robustness unless data can be lost with minimal business cost.&lt;/li&gt;&lt;li&gt;I usually use the journalling option.&lt;/li&gt;&lt;li&gt;Use replica pairs or a slave.&lt;/li&gt;&lt;li&gt;I favor using MongoDB for rapid prototyping and research.&lt;/li&gt;&lt;li&gt;I use the right tool for each job. PostgreSQL, various RDF data stores, and sometimes Neo4J are also favorite data store tools.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-8341401130039334518?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/8341401130039334518/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=8341401130039334518&amp;isPopup=true' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/8341401130039334518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/8341401130039334518'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2011/11/annoyed-by-anti-mongodb-post-on-hn.html' title='Annoyed by anti-MongoDB post on HN'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7100397.post-2088875388295597473</id><published>2011-11-04T10:16:00.000-07:00</published><updated>2011-11-04T10:16:20.366-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='GWT'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='AppEngine'/><title type='text'>Notes on converting an GWT + AppEngine web app using Objectify to a plain GWT + MongoDB web app</title><content type='html'>There has been a lot of noise in blog-space&amp;nbsp;criticizing&amp;nbsp;Google for the re-pricing of AppEngine services. I don't really agree with a lot of the complaints because it seems fair for Google to charge enough to make AppEngine a long term viable business.&lt;br /&gt;&lt;br /&gt;That said, I have never done any customer work targeting the AppEngine platform because no one has requested it. (Although I have enthusiastically used AppEngine for some of my own projects and I have written several AppEngine and Wave specific articles.) I still host &lt;a href="http://www.knowledgebooks.com/"&gt;KnowledgeBooks.com&lt;/a&gt; on AppEngine.&lt;br /&gt;&lt;br /&gt;I wrote a GWT + AppEngine app for my own use about a year ago, and since I always have at least one EC2 instance running for my own experiments and development work I decided to move my app. It turns out that converting my app is fairly easy using these steps:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Copy my IntelliJ project, renaming it and removing AppEngine facets and libraires.&lt;/li&gt;&lt;li&gt;Add the MongoDB Java required JARs&lt;/li&gt;&lt;li&gt;I had all of my Objectify datastore operations in a single utility class on the server side - I converted this to use MongoDB&lt;/li&gt;&lt;/ul&gt;Sure, a complex application would take a while, but my app only has 6 model classes (all POJOs) so the whole process took less than 90 minutes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7100397-2088875388295597473?l=blog.markwatson.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.markwatson.com/feeds/2088875388295597473/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7100397&amp;postID=2088875388295597473&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/2088875388295597473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7100397/posts/default/2088875388295597473'/><link rel='alternate' type='text/html' href='http://blog.markwatson.com/2011/11/notes-on-converting-gwt-appengine-web.html' title='Notes on converting an GWT + AppEngine web app using Objectify to a plain GWT + MongoDB web app'/><author><name>Mark Watson,  author and consultant</name><uri>http://www.blogger.com/profile/05514730816583918651</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_FOFPUsW3T3c/SWO4Tcrr14I/AAAAAAAACis/0vgJvc-yzh4/S220/Mark_hat_small.jpg'/></author><thr:total>0</thr:total></entry></feed>
