<?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-32093290</id><updated>2012-01-17T08:22:26.296-08:00</updated><title type='text'>when I'm not skateboarding</title><subtitle type='html'>Geoff Hendrey's blog about programming and travel.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>97</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-32093290.post-6849216373946284843</id><published>2011-08-10T18:03:00.000-07:00</published><updated>2011-08-10T18:03:31.258-07:00</updated><title type='text'>welcome...to...big...data</title><content type='html'>&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:WordDocument&gt;   &lt;w:View&gt;Normal&lt;/w:View&gt;   &lt;w:Zoom&gt;0&lt;/w:Zoom&gt;   &lt;w:TrackMoves/&gt;   &lt;w:TrackFormatting/&gt;   &lt;w:PunctuationKerning/&gt;   &lt;w:ValidateAgainstSchemas/&gt;   &lt;w:SaveIfXMLInvalid&gt;false&lt;/w:SaveIfXMLInvalid&gt;   &lt;w:IgnoreMixedContent&gt;false&lt;/w:IgnoreMixedContent&gt;   &lt;w:AlwaysShowPlaceholderText&gt;false&lt;/w:AlwaysShowPlaceholderText&gt;   &lt;w:DoNotPromoteQF/&gt;   &lt;w:LidThemeOther&gt;EN-US&lt;/w:LidThemeOther&gt;   &lt;w:LidThemeAsian&gt;X-NONE&lt;/w:LidThemeAsian&gt;   &lt;w:LidThemeComplexScript&gt;X-NONE&lt;/w:LidThemeComplexScript&gt;   &lt;w:Compatibility&gt;    &lt;w:BreakWrappedTables/&gt;    &lt;w:SnapToGridInCell/&gt;    &lt;w:WrapTextWithPunct/&gt;    &lt;w:UseAsianBreakRules/&gt;    &lt;w:DontGrowAutofit/&gt;    &lt;w:SplitPgBreakAndParaMark/&gt;    &lt;w:DontVertAlignCellWithSp/&gt;    &lt;w:DontBreakConstrainedForcedTables/&gt;    &lt;w:DontVertAlignInTxbx/&gt;    &lt;w:Word11KerningPairs/&gt;    &lt;w:CachedColBalance/&gt;   &lt;/w:Compatibility&gt;   &lt;w:DoNotOptimizeForBrowser/&gt;   &lt;m:mathPr&gt;    &lt;m:mathFont m:val="Cambria Math"/&gt;    &lt;m:brkBin m:val="before"/&gt;    &lt;m:brkBinSub m:val="&amp;#45;-"/&gt;    &lt;m:smallFrac m:val="off"/&gt;    &lt;m:dispDef/&gt;    &lt;m:lMargin m:val="0"/&gt;    &lt;m:rMargin m:val="0"/&gt;    &lt;m:defJc m:val="centerGroup"/&gt;    &lt;m:wrapIndent m:val="1440"/&gt;    &lt;m:intLim m:val="subSup"/&gt;    &lt;m:naryLim m:val="undOvr"/&gt;   &lt;/m:mathPr&gt;&lt;/w:WordDocument&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;!--[if gte mso 9]&gt;&lt;xml&gt;  &lt;w:LatentStyles DefLockedState="false" DefUnhideWhenUsed="true"  DefSemiHidden="true" DefQFormat="false" DefPriority="99"  LatentStyleCount="267"&gt;   &lt;w:LsdException Locked="false" Priority="0" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Normal"/&gt;   &lt;w:LsdException Locked="false" Priority="9" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="heading 1"/&gt;   &lt;w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 2"/&gt;   &lt;w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 3"/&gt;   &lt;w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 4"/&gt;   &lt;w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 5"/&gt;   &lt;w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 6"/&gt;   &lt;w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 7"/&gt;   &lt;w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 8"/&gt;   &lt;w:LsdException Locked="false" Priority="9" QFormat="true" Name="heading 9"/&gt;   &lt;w:LsdException Locked="false" Priority="39" Name="toc 1"/&gt;   &lt;w:LsdException Locked="false" Priority="39" Name="toc 2"/&gt;   &lt;w:LsdException Locked="false" Priority="39" Name="toc 3"/&gt;   &lt;w:LsdException Locked="false" Priority="39" Name="toc 4"/&gt;   &lt;w:LsdException Locked="false" Priority="39" Name="toc 5"/&gt;   &lt;w:LsdException Locked="false" Priority="39" Name="toc 6"/&gt;   &lt;w:LsdException Locked="false" Priority="39" Name="toc 7"/&gt;   &lt;w:LsdException Locked="false" Priority="39" Name="toc 8"/&gt;   &lt;w:LsdException Locked="false" Priority="39" Name="toc 9"/&gt;   &lt;w:LsdException Locked="false" Priority="35" QFormat="true" Name="caption"/&gt;   &lt;w:LsdException Locked="false" Priority="10" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Title"/&gt;   &lt;w:LsdException Locked="false" Priority="1" Name="Default Paragraph Font"/&gt;   &lt;w:LsdException Locked="false" Priority="11" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Subtitle"/&gt;   &lt;w:LsdException Locked="false" Priority="22" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Strong"/&gt;   &lt;w:LsdException Locked="false" Priority="20" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Emphasis"/&gt;   &lt;w:LsdException Locked="false" Priority="59" SemiHidden="false"   UnhideWhenUsed="false" Name="Table Grid"/&gt;   &lt;w:LsdException Locked="false" UnhideWhenUsed="false" Name="Placeholder Text"/&gt;   &lt;w:LsdException Locked="false" Priority="1" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="No Spacing"/&gt;   &lt;w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading"/&gt;   &lt;w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List"/&gt;   &lt;w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid"/&gt;   &lt;w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1"/&gt;   &lt;w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2"/&gt;   &lt;w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1"/&gt;   &lt;w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2"/&gt;   &lt;w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1"/&gt;   &lt;w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2"/&gt;   &lt;w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3"/&gt;   &lt;w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List"/&gt;   &lt;w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading"/&gt;   &lt;w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List"/&gt;   &lt;w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid"/&gt;   &lt;w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading Accent 1"/&gt;   &lt;w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List Accent 1"/&gt;   &lt;w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid Accent 1"/&gt;   &lt;w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 1"/&gt;   &lt;w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 1"/&gt;   &lt;w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1 Accent 1"/&gt;   &lt;w:LsdException Locked="false" UnhideWhenUsed="false" Name="Revision"/&gt;   &lt;w:LsdException Locked="false" Priority="34" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="List Paragraph"/&gt;   &lt;w:LsdException Locked="false" Priority="29" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Quote"/&gt;   &lt;w:LsdException Locked="false" Priority="30" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Intense Quote"/&gt;   &lt;w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2 Accent 1"/&gt;   &lt;w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 1"/&gt;   &lt;w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 1"/&gt;   &lt;w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 1"/&gt;   &lt;w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List Accent 1"/&gt;   &lt;w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading Accent 1"/&gt;   &lt;w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List Accent 1"/&gt;   &lt;w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid Accent 1"/&gt;   &lt;w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1 Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2 Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid Accent 2"/&gt;   &lt;w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1 Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2 Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid Accent 3"/&gt;   &lt;w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1 Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2 Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid Accent 4"/&gt;   &lt;w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1 Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2 Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid Accent 5"/&gt;   &lt;w:LsdException Locked="false" Priority="60" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Shading Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="61" SemiHidden="false"   UnhideWhenUsed="false" Name="Light List Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="62" SemiHidden="false"   UnhideWhenUsed="false" Name="Light Grid Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="63" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 1 Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="64" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Shading 2 Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="65" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 1 Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="66" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium List 2 Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="67" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 1 Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="68" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 2 Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="69" SemiHidden="false"   UnhideWhenUsed="false" Name="Medium Grid 3 Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="70" SemiHidden="false"   UnhideWhenUsed="false" Name="Dark List Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="71" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Shading Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="72" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful List Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="73" SemiHidden="false"   UnhideWhenUsed="false" Name="Colorful Grid Accent 6"/&gt;   &lt;w:LsdException Locked="false" Priority="19" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Subtle Emphasis"/&gt;   &lt;w:LsdException Locked="false" Priority="21" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Intense Emphasis"/&gt;   &lt;w:LsdException Locked="false" Priority="31" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Subtle Reference"/&gt;   &lt;w:LsdException Locked="false" Priority="32" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Intense Reference"/&gt;   &lt;w:LsdException Locked="false" Priority="33" SemiHidden="false"   UnhideWhenUsed="false" QFormat="true" Name="Book Title"/&gt;   &lt;w:LsdException Locked="false" Priority="37" Name="Bibliography"/&gt;   &lt;w:LsdException Locked="false" Priority="39" QFormat="true" Name="TOC Heading"/&gt;  &lt;/w:LatentStyles&gt; &lt;/xml&gt;&lt;![endif]--&gt;&lt;!--[if gte mso 10]&gt; &lt;style&gt; /* Style Definitions */ table.MsoNormalTable	{mso-style-name:"Table Normal";	mso-tstyle-rowband-size:0;	mso-tstyle-colband-size:0;	mso-style-noshow:yes;	mso-style-priority:99;	mso-style-qformat:yes;	mso-style-parent:"";	mso-padding-alt:0in 5.4pt 0in 5.4pt;	mso-para-margin:0in;	mso-para-margin-bottom:.0001pt;	mso-pagination:widow-orphan;	font-size:11.0pt;	font-family:"Calibri","sans-serif";	mso-ascii-font-family:Calibri;	mso-ascii-theme-font:minor-latin;	mso-fareast-font-family:"Times New Roman";	mso-fareast-theme-font:minor-fareast;	mso-hansi-font-family:Calibri;	mso-hansi-theme-font:minor-latin;	mso-bidi-font-family:"Times New Roman";	mso-bidi-theme-font:minor-bidi;}&lt;/style&gt; &lt;![endif]--&gt;  &lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;The following is excerpted from the hbase-user@apache.org mailing list...an instant classic!&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;=================================================================&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Mongodb does an excellent job at single node scalability - they use mmap and many smart things and really kick ass ... ON A SINGLE NODE.&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;That single node must have raid (raid it going out of fashion btw), and you wont be able to scale without resorting to:&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;- replication (complex setup!)&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;- sharding&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;mongo claims to help on the last item, but it is still a risk point.&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;For really large data that must span multiple machines, there is no "clustered sql" type solution that isnt (a) borked in various ways (Oracle RAC I'm looking at you) or (b) stupid expensive (Oracle RAC, STILL looking at you)&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Tools like HBase give you scalability at the cost of features (no automated secondary indexing, no query language).&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Welcome... to... big... data.&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;-ryan&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;On Thu, Aug 11, 2011 at 12:44 AM, Edward Capriolo &amp;lt;&lt;a href="mailto:edlinuxguru@gmail.com"&gt;&lt;/a&gt;&amp;gt; wrote:&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt; On Wed, Aug 10, 2011 at 4:26 PM, Li Pi &amp;lt;&lt;a href="mailto:li@cloudera.com"&gt;&lt;/a&gt;&amp;gt; wrote:&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;nbsp;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; You'll have to build your own secondary indexes for now.&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt;&amp;nbsp;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; On Wed, Aug 10, 2011 at 1:15 PM, Laurent Hatier &lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &lt;laurent.hatier@gmail.com&lt; p=""&gt;  &lt;/laurent.hatier@gmail.com&lt;&gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt;wrote:&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt;&amp;nbsp;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; Yes, i have heard this index but is it available on hbase 0.90.3 ?&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; 2011/8/10 Chris Tarnas &amp;lt;&lt;a href="mailto:cft@email.com"&gt;&lt;/a&gt;&amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; Hi Laurent,&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; Without more details on your schema and how you are finding that &lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; number&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; in&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; your table it is impossible to fully answer the question. I &lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; suspect&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; what&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; you&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; are seeing is mongo's native support for secondary indexes. If &lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; you were&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; to&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; add secondary indexes in HBase then retrieving that row should be &lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; on&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; the&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; order of 3-30ms. If that is you main query method then you could&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; reorganize&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; your table to make that long number your row key, then you would &lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; get&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; even&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; faster reads.&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; -chris&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; On Aug 10, 2011, at 10:02 AM, Laurent Hatier wrote:&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; Hi all,&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; I would like to know why MongoDB is faster than HBase to select&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; items.&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; I explain my case :&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; I've inserted 4'000'000 lines into HBase and MongoDB and i must&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; calculate&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; the geolocation with the IP. I calculate a Long number with the &lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; IP&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; and&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; i&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; go&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; to find it into the 4'000'000 lines.&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; it's take 5 ms to select the right row with Mongo instead of &lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; HBase&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; takes&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; 5&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; seconds.&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; I think that the reason is the method : cur.limit(1) with &lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; MongoDB but&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; is&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; there no function like this with HBase ?&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; --&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; Laurent HATIER&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt; &amp;gt; Étudiant en 2e année du Cycle Ingénieur à l'EISTI&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; --&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; Laurent HATIER&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt; Étudiant en 2e année du Cycle Ingénieur à l'EISTI&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt; &amp;gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;gt;&amp;nbsp;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;nbsp;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt; &lt;a href="http://www.xtranormal.com/watch/6995033/mongo-db-is-web-scale"&gt;http://www.xtranormal.com/watch/6995033/mongo-db-is-web-scale&lt;/a&gt;&lt;/div&gt;&lt;div class="MsoPlainText" style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;gt;&amp;nbsp;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-6849216373946284843?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/6849216373946284843/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2011/08/welcometobigdata.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6849216373946284843'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6849216373946284843'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2011/08/welcometobigdata.html' title='welcome...to...big...data'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-2711724319133937939</id><published>2011-01-23T13:08:00.000-08:00</published><updated>2011-01-25T21:07:10.182-08:00</updated><title type='text'>HBase 0.89 Bulk Import capability</title><content type='html'>&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;I recently posted about my experience tuning HBase for mass inserts. When I learned that HBase actually supports a way to *avoid* the insert all together, I got really excited. As the Joshua Program says, "the only way to win the game is not to play"! What better way to speed up inserts than not to do them at all! You can't get much faster than zero. So how do you get data into HBase if you don't do inserts? Aha! You can actually generate HFileOutputFormat files, that essentiallly *are* database tables. And believe me, compared to running Puts from your reducer it is fast, and you don't have the "attack my database and maybe crash it" issue. To give you an idea of how fast it is, I had a job whose reducers ran for 45 minutes doing Puts. The bulk loader took 19 seconds to load the files, and it only took a couple minutes to generate the files from the reducer. So the whole bulk load process, end to end, was maybe 2 minutes.&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;The main "gotchas" along the way: The documentation isn't entirely clear about the fact that if you use HFileOutputFormat.configureIncrementalLoad, that your reducer is silently replaced by an internal HBase class that insures total ordering. Secondly, your mapper must output either Put or KeyValue. This is not a usable way to actually write mapreduce jobs (since you lose the ability to pass domain objects between map and reduce). Therefore, I found it best to alter my existing mapreduce jobs to produce a SequenceFileOutputFormat, in which I wrote Put from my reducer as the output class (since it doesn't interfere with your job logic/classes at all to change only the *final* output class to a Put). In fact, the class I wrote to generate the HFileOutputFormat will actually accept sequence files as input if they contain either a Put, or a single column value. I included support for a single column value just 'cause I had a couple jobs lying around that produced only a single column, and would have been a hassle to convert them to producing Puts. Then my generic bulk loader mapreduce job can be run on any of my output sequence files.&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;public class BulkLoader extends Configured implements Tool{&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    public static class BulkLoaderMapper extends Mapper&amp;lt;WritableComparable, Writable, ImmutableBytesWritable, Put&amp;gt; {&lt;br /&gt;&lt;br /&gt;        protected long version;&lt;br /&gt;        protected String column;&lt;br /&gt;        protected String family;&lt;br /&gt;&lt;br /&gt;        @Override&lt;br /&gt;        protected void setup(Mapper.Context context) throws IOException, InterruptedException {&lt;br /&gt;            this.version = context.getConfiguration().getLong("version", System.currentTimeMillis());&lt;br /&gt;            this.column = context.getConfiguration().get("column");&lt;br /&gt;            this.family= context.getConfiguration().get("family");&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        private byte[] marshal(Writable o) throws IOException{&lt;br /&gt;            ByteArrayOutputStream bos = new ByteArrayOutputStream();&lt;br /&gt;            DataOutputStream dos = new DataOutputStream(bos);&lt;br /&gt;            o.write(dos);&lt;br /&gt;            return bos.toByteArray();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected byte[] getHBaseRowKeyBytes(Writable k) throws IOException{&lt;br /&gt;            return marshal(k);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected byte[] getHBaseFamilyNameBytes(){&lt;br /&gt;            return Bytes.toBytes(family);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected byte[] getHBaseColumnNameBytes(){&lt;br /&gt;            return Bytes.toBytes(column);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected byte[] getHBaseValueBytes(Writable v) throws IOException{&lt;br /&gt;            return marshal(v);&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        @Override&lt;br /&gt;        protected void map(WritableComparable key, Writable val, Context context) throws IOException, InterruptedException {&lt;br /&gt;            //KeyValue kv = new KeyValue(getHBaseRowKeyBytes(key), getHBaseFamilyNameBytes(), getHBaseColumnNameBytes(), version, getHBaseValueBytes());&lt;br /&gt;            if(context.getConfiguration().get("input-format", "column").equals("put")){ //the serialized file actually is full of puts&lt;br /&gt;                System.out.println(key.toString());&lt;br /&gt;                Put p = (Put) val;&lt;br /&gt;                //I am baffled as to why I cannot use getHBaseRowKeyBytes(key) here. It seems to not produce the correct key.&lt;br /&gt;                //Therefore I m using p.getRow() to get the rowkey bytes.&lt;br /&gt;                context.write(new ImmutableBytesWritable(p.getRow()), p);&lt;br /&gt;            }else{&lt;br /&gt;                Put put = new Put(getHBaseRowKeyBytes(key));&lt;br /&gt;                put.add(getHBaseFamilyNameBytes(), getHBaseColumnNameBytes(), version, getHBaseValueBytes(val));&lt;br /&gt;                context.write(new ImmutableBytesWritable(getHBaseRowKeyBytes(key)), put);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static void main(String[] args) throws Exception {&lt;br /&gt;        int exitCode = ToolRunner.run(new BulkLoader(), args);&lt;br /&gt;        System.exit(exitCode);&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public int run(String[] otherArgs) throws Exception {&lt;br /&gt;&lt;br /&gt;        Configuration config = (Configuration) getConf();//new Configuration();&lt;br /&gt;        Job job = new Job(config);&lt;br /&gt;&lt;br /&gt;        //job.setOutputKeyClass(ImmutableBytesWritable.class);&lt;br /&gt;        //job.setOutputValueClass(Put.class);&lt;br /&gt;        job.setMapOutputKeyClass(ImmutableBytesWritable.class);&lt;br /&gt;        job.setMapOutputValueClass(Put.class);&lt;br /&gt;        job.setMapperClass(BulkLoaderMapper.class);&lt;br /&gt;&lt;br /&gt;        job.setJarByClass(BulkLoader.class);&lt;br /&gt;        job.setInputFormatClass(SequenceFileInputFormat.class);&lt;br /&gt;        System.out.println("sequencefile-input: " + config.get("sequencefile-input"));&lt;br /&gt;        System.out.println("output-path: " + config.get("output-path"));&lt;br /&gt;        System.out.println("bulk-load-table: " + config.get("bulk-load-table"));&lt;br /&gt;        System.out.println("family: " + config.get("family"));&lt;br /&gt;        System.out.println("column: " + config.get("column"));&lt;br /&gt;        System.out.println("input-format: " + config.get("input-format", "column"));&lt;br /&gt;        SequenceFileInputFormat.addInputPath(job, new Path(config.get("sequencefile-input")));&lt;br /&gt;        job.setOutputFormatClass(HFileOutputFormat.class);&lt;br /&gt;        Configuration hConfig = HBaseConfiguration.create(config);&lt;br /&gt;        hConfig.setLong("version", System.currentTimeMillis());&lt;br /&gt;        hConfig.set("hbase.zookeeper.quorum", config.get("zk", "zk1.x.com, zk2.x.xom"));&lt;br /&gt;        job.setJobName("Bulk Loading table: " + hConfig.get("bulk-load-table","YOU HAVE NOT SET bulk-load-table PARAMETER"));&lt;br /&gt;        HFileOutputFormat.setOutputPath(job, new Path(config.get("output-path")));&lt;br /&gt;        HFileOutputFormat.configureIncrementalLoad(job, new HTable(hConfig, config.get("bulk-load-table")));&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;        job.waitForCompletion(true);&lt;br /&gt;&lt;br /&gt;        return 0; //normal exit&lt;br /&gt;&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Finally, the 0.89 jar seemed to have some packaging problems. I had to create a "lib" directory (used by hadoop in job jars) and rejar the 0.89 jar with guava.jar and a perhaps a couple other missing dependencies. With that done I was able to run the bulkloader with the completebulkload option, using ant command:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_iJr6rK5UOFc/TT-pSdtvinI/AAAAAAAAAQ0/IXUIX5n3nVE/s1600/Capture.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="276" src="http://4.bp.blogspot.com/_iJr6rK5UOFc/TT-pSdtvinI/AAAAAAAAAQ0/IXUIX5n3nVE/s640/Capture.JPG" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-2711724319133937939?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/2711724319133937939/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2011/01/hbase-089-bulk-import-capability.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2711724319133937939'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2711724319133937939'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2011/01/hbase-089-bulk-import-capability.html' title='HBase 0.89 Bulk Import capability'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_iJr6rK5UOFc/TT-pSdtvinI/AAAAAAAAAQ0/IXUIX5n3nVE/s72-c/Capture.JPG' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-2217534563785636700</id><published>2011-01-08T12:40:00.000-08:00</published><updated>2011-01-08T12:46:07.969-08:00</updated><title type='text'>Facebook announces websearch to rival Google's</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_iJr6rK5UOFc/TSjJ65F56yI/AAAAAAAAAQs/Q8P_dOsAKfg/s1600/Picture+38.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="81" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/TSjJ65F56yI/AAAAAAAAAQs/Q8P_dOsAKfg/s200/Picture+38.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Admittedly I've made up the headline "&lt;b style="color: red;"&gt;&lt;i&gt;Facebook announces websearch to rival Google's&lt;/i&gt;&lt;/b&gt;", but is it really such an outlandish proposition? It's certainly attention grabbing, and why not? Google's websearch has basically remained the same product for 10 years. Any engineer at Google would debate this, but I doubt anyone would debate that the &lt;b&gt;engineers at &lt;/b&gt;&lt;b&gt;facebook&lt;/b&gt;&lt;i&gt;&lt;b&gt; &lt;/b&gt;&lt;/i&gt;have achieved a stunning mastery over big data sets and management of the social network.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; text-align: center;"&gt;&lt;/div&gt;&lt;a href="http://2.bp.blogspot.com/_iJr6rK5UOFc/TSjJPTwDK1I/AAAAAAAAAQk/FX1m6hY0YHk/s1600/Picture+36.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="113" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/TSjJPTwDK1I/AAAAAAAAAQk/FX1m6hY0YHk/s200/Picture+36.png" width="200" /&gt;&lt;/a&gt;&lt;a href="http://2.bp.blogspot.com/_iJr6rK5UOFc/TSjJ5iaiLZI/AAAAAAAAAQo/mkTz1SfTjXk/s1600/Picture+37.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="75" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/TSjJ5iaiLZI/AAAAAAAAAQo/mkTz1SfTjXk/s200/Picture+37.png" width="200" /&gt;&lt;/a&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Based on the considerable "Big Data" and real-time data expertise at Facebook, would anyone really be surprised if such a headline surfaced? I'd find it quite a believable story: "&lt;b style="color: red;"&gt;&lt;i&gt;Facebook announces intention to best Google at web search&lt;/i&gt;&lt;/b&gt;." It's hard to overstate the earthquake that such an announcement would send rumbling through silicon valley, and the entire world. In fact, what better way for Facebook to spend their $500 million in Goldman Sachs cash then acquiring promising engineers and technologies to directly attack Google's biggest Web cash cows: search and maps. Bloodying the nose of the competition by competing with their core value has always been Google's way: If an Operating System is of value, Google builds an OS. If mobile computing is of value, google builds a mobile OS, and it's own phone hardware. The day is going to come when a Google rival will compete with Google on Google's home turf: web search. &lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-2217534563785636700?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/2217534563785636700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2011/01/facebook-announces-websearch-to-rival.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2217534563785636700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2217534563785636700'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2011/01/facebook-announces-websearch-to-rival.html' title='Facebook announces websearch to rival Google&apos;s'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iJr6rK5UOFc/TSjJ65F56yI/AAAAAAAAAQs/Q8P_dOsAKfg/s72-c/Picture+38.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-551494415323082501</id><published>2011-01-04T22:41:00.000-08:00</published><updated>2011-01-05T06:58:48.121-08:00</updated><title type='text'>Minhashing is reaaally cool</title><content type='html'>What is the Jaccard Coefficient? Answer: one of the most important concepts in information retrieval and theory of sets. The Jaccard Coeffieicnt is very simple. It is the measure of the fractional similarity of two sets. Let's take&amp;nbsp; a simple example {A,B,C,D,E,F} vs. {B,E,F}. Fractional similarity of these sets is 3/6. Easily you can see that 3 elements are shared (the intersection is {B,E,F}), whereas the total number of items in both sets (the union) is 6 elements ({A,B,C,D,E,F}).&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_iJr6rK5UOFc/TSSFt1sDwmI/AAAAAAAAAQY/VjXWs6fd0fo/s1600/Capture.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="126" src="http://4.bp.blogspot.com/_iJr6rK5UOFc/TSSFt1sDwmI/AAAAAAAAAQY/VjXWs6fd0fo/s320/Capture.JPG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;So without any mumbo-jumbo, we can see the Jaccard&amp;nbsp; Coefficient&amp;nbsp; (JC) is just the ratio of sameness (intersection) over the total amount of stuff present. Technically it's the cardinality (count) of elements in the intersection over cardinality (count) of elements in the union. So while the JC between  {A,B,C,D,E,F} and {B,E,F} is 50%, we can see that the JC between   {A,B,C,D,E,F,G,H,I} and {B,E,F} is only 33.33%. This illustrates the importance of the total amount of stuff present. The more irrelevant (non-intersection) stuff is present, the lower the Jaccard Coefficient.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_iJr6rK5UOFc/TSSGgqC5pNI/AAAAAAAAAQc/wCMf5TksIjQ/s1600/Capture.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="122" src="http://1.bp.blogspot.com/_iJr6rK5UOFc/TSSGgqC5pNI/AAAAAAAAAQc/wCMf5TksIjQ/s320/Capture.JPG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&amp;nbsp;Now pretend we have two bags. Bag 1 contains Set 1, and Bag 2 contains Set 2. I tell you the JC between these two sets is 95%. I reach into Bag 1 and I pull out the element "M". What is the probability that the element "M" is also in Bag 2? It's 95%. That's what the Jaccard Coefficient tells me. But now here is something quite amazing. What is the probability that the lowest symbol (lowest according to some ordering, like a hashcode) in Bag 1 is the *same* letter as the lowest letter in Bag 2. Again, it's 95%. Why? Some letter has to be the lowest one in a bag. Since only 5% of the letters in the other bag ought to be different, then there is a 95% chance that the lowest symbol in the second bag falls in the intersection of the sets, and is consequently the same.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_iJr6rK5UOFc/TSSHIDEP0eI/AAAAAAAAAQg/v3QT0TbUhto/s1600/Capture.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="188" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/TSSHIDEP0eI/AAAAAAAAAQg/v3QT0TbUhto/s320/Capture.JPG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Now it really gets interesting. If I group sets by a key, where the key is the lowest element of the set, then the probability that two sets get grouped by the same key is again the Jaccard Coefficient. That's cool. That's BADASS. Why? It's an almost shockingly simple way to create clusters of similar sets.&lt;br /&gt;&lt;br /&gt;I find a lot of convoluted explanations of Minhashing, but you really don't need to know mor&lt;a href="http://knol.google.com/k/simple-simhashing#"&gt;e than this guy's explanation&lt;/a&gt;. Here's a short piece of code, that given a sentence, splits the sentence into words, then builds N-grams out of the words (the N-grams are the set elements). Surrounding a word with ^ and $ is a well-known way for demarcating N-grams that are beginning and endings of words. A SHA-1 cryotographic hash function is a nice way to assign a random, but consistent ordering to any possible N-gram we might come up with. As suggested by&lt;a href="http://knol.google.com/k/simple-simhashing#"&gt; this guy&lt;/a&gt;, rather than clustering on the *single* lowest element, we can tighten the clusters up by making the cluster key the numMins smallest elements, concatenated.&amp;nbsp; I use this in a mapreduce job, where I write the minhash out as the key from the mapper, and the reducer collects all the sentences with the same minHash key, thereby clustering similar sentences. And lo and behold...it works.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;      protected String minHash(String sentence, int nGramLength, int numMins) throws Exception{&lt;br /&gt;            MessageDigest md = MessageDigest.getInstance("SHA-1");&lt;br /&gt;            PriorityQueue queue = new PriorityQueue();&lt;br /&gt;            for(String part :sentence.split("\\s")){&lt;br /&gt;                for(String gram:getNGrams("^"+part+"$",nGramLength)){&lt;br /&gt;                    md.reset();&lt;br /&gt;                    queue.add(ByteBuffer.wrap(md.digest(gram.getBytes("UTF-8"))).getLong());&lt;br /&gt;                }&lt;br /&gt;            }            &lt;br /&gt;            StringBuilder minHash = new StringBuilder();&lt;br /&gt;            while(null != queue.peek() &amp;amp;&amp;amp; numMins &amp;gt; 0){&lt;br /&gt;                minHash.append(queue.remove());&lt;br /&gt;                --numMins;&lt;br /&gt;            }&lt;br /&gt;            return minHash.toString();&lt;br /&gt;        }.&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-551494415323082501?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/551494415323082501/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2011/01/minhashing-is-reaaally-cool.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/551494415323082501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/551494415323082501'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2011/01/minhashing-is-reaaally-cool.html' title='Minhashing is reaaally cool'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_iJr6rK5UOFc/TSSFt1sDwmI/AAAAAAAAAQY/VjXWs6fd0fo/s72-c/Capture.JPG' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-9146905743360232481</id><published>2010-12-26T16:49:00.000-08:00</published><updated>2011-01-21T17:46:02.079-08:00</updated><title type='text'>Tuning HBase and Mapreduce for Mass Inserts</title><content type='html'>&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_iJr6rK5UOFc/TRfnkzAa2wI/AAAAAAAAAQU/defgp60gRpY/s1600/Capture.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="400" src="http://1.bp.blogspot.com/_iJr6rK5UOFc/TRfnkzAa2wI/AAAAAAAAAQU/defgp60gRpY/s400/Capture.JPG" width="380" /&gt;&lt;/a&gt;&lt;/div&gt;For several months my colleagues and I have been earning our battle scars as we run progressively larger bulk inserts into HBase. I'm going to try to recall as many of the lessons learned as possible. At the time of this writing HBase 20.6 is the latest production release:&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;ol style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;li&gt;Use&amp;nbsp; HBase 20.6. We had been running 20.3 and it suffered from a hideous deadlock bug, that would cause clients to simply stall and do nothing, until they were killed by the Hadoop task tracker. Even worse, because they were killed and restarted, this caused a vicious cycle of reducers stalling, restarting, stalling, etc. All the while threads and client connections were eaten up in HBase.&lt;/li&gt;&lt;li&gt;Use huge numbers of mappers, and huge numbers of reducers so that your data sets are broken into bite sized pieces. To do this, &lt;a href="http://www.blogger.com/post-create.g?blogID=32093290" name="mapred.map.tasks"&gt;set &lt;/a&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=32093290" name="mapred.tasktracker.map.tasks.maximum"&gt;mapred.tasktracker.[map|reduce].tasks.maximum (the max value that will be run by a single task tracker at once) to a value correlated to the number of cores on each box (we'll cal this "C") and the number of boxes "B". Then set set &lt;/a&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=32093290" name="mapred.map.tasks"&gt;mapred.[map|reduce].tasks (the total number of mappers or reducers that will get run) equal to a*C*B. "a" is then a free parameter which controls how big your bite sized batches of data will be. As a rule of thumb, if you are reading data out of HBase via TableMapper, I try to make a*C*B between 1000 and 10000, but it all depends on how much processing you ned to do on each chunk.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;This is an addendum to rule (2). All sorts of bad things happen when your mappers or reducers bite off too much data, and run for too long. Just a few items on the buffet of errors and warnings that you'll chase if your mappers or reducers try to handle too much data:&lt;/li&gt;&lt;ul style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;li&gt;HBase clients leases expiring&lt;/li&gt;&lt;li&gt;Chance of OoME&lt;/li&gt;&lt;li&gt;Failure to report status for more than 600 seconds causes task to get shot in the head&lt;/li&gt;&lt;li&gt;Hbase client slows down on writes(annecdotal. I can't prove this, but I know that if you want to avoid ptential slowdowns, then following rule 2, in my experience, helps a lot)&lt;/li&gt;&lt;/ul&gt;&lt;li style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Use fine grained status. Make calls to progress(), setStatus(msg), and use counters to track what your job is doing. Nothing is more annoying that not being able to tell what the hell your job is doing when it has been running for 5 hours. Rule 2 helps here too. The more mappers and reducers you have, the more continuous and fine grained will be your status reporting as each task completes with its data load into HBase. &lt;/li&gt;&lt;li style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Don't screw around too much with the default settings. &lt;a href="http://people.apache.org/%7Ejdcryans/HUG8/HUG8-rawson.pdf"&gt;Ryan Rawson has put out a good set of defaults in this PPT&lt;/a&gt;. You can turn these dials ad infinitum but I can pretty much promise you that there is no magic set of settings. This can be a massive time sync. Stick with Ryan's recommendations.&lt;/li&gt;&lt;li style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Watch out for problems with your hostnames. Let's say your hostname is "s1.x.com". If you execute "hostname" and all you get back is "s1" or "localhost" you are in for problems. Check your /etc/hosts and make sure that aliases like "s1" don't come before the fully qualified hostname.&lt;/li&gt;&lt;li style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Watch out for msiconfigured NICs. Problems with vanishing packets sent me chasing my tail for weeks. This was the classic buffet of errors, with everything seemingly leading to no resolution.&lt;/li&gt;&lt;li style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Disable the Write Ahead Log from your client code. Use an appropriately sized write buffer. There'sa point of diminishing returns here. Exceeding the size of the serverside buffers won't do you any good.&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Don't try to get too smart. Most bulk HBase data-producing M/R jobs are going to do some processing, then write the data from the reducer. Since the reducers all receive keys in the same order, this causes all the reducers to attack the same HBase region simultaneously. We had this "great idea" that if we reversed the keys that we wrote out of our mapper, then un-reversed them in the reducer, that our reducers would be randomly writing to different region servers, not hitting a single region in lock step. Now, I have some theories on why this seemingly innocuous approach repeatably destroyed our entire Hbase database. I won't wax philosophical here, but one thing is certain. Any table created via batch inserts of randomized keys got totally hosed. Scans became dirt slow and compactions ran constantly, even days after the table was created. None of these problems made a whole lot of sense, which is why it took 3-4 weeks of debugging for us to back this "key randomizing" out of our code. The hosed tables, actually had to be dropped for the problem, and ensuing chaos to totally abate.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;tail all your logs and scan them assiduously for errors and warnings. I use VNCserver with different desktops for tails of all the logs so that I never have to "re-setup" all my tailf commands when I log in and out of the server.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Disable speculative execution. You don't want two reducers trying to insert the exact same content into the database. &lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-9146905743360232481?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/9146905743360232481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/12/tuning-hbase-and-mapreduce-for-bulk.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/9146905743360232481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/9146905743360232481'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/12/tuning-hbase-and-mapreduce-for-bulk.html' title='Tuning HBase and Mapreduce for Mass Inserts'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_iJr6rK5UOFc/TRfnkzAa2wI/AAAAAAAAAQU/defgp60gRpY/s72-c/Capture.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-5549303438066683266</id><published>2010-11-29T21:46:00.000-08:00</published><updated>2010-11-29T21:46:48.827-08:00</updated><title type='text'>Black Friday Buys</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_iJr6rK5UOFc/TPSPjnlxVfI/AAAAAAAAAQE/om_fe3v-0vw/s1600/Picture+34.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/TPSPjnlxVfI/AAAAAAAAAQE/om_fe3v-0vw/s1600/Picture+34.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: small;"&gt;Picked up a wireless access point for 10 bucks on buy.com. Placed it at the highest point in the house, and set it up to pull it's own IP address from DHCP off my existing wireless access point, so it's basically a range extender. For a $10 "TRENDnet", I was really impressed at how easy it was to setup. I tried the same thing with a Linksys several months back. The linksys would work on and off and just periodically die, and it cost something like $50. Anyway, I'm posting from my living room and receiving a good signal, so definitely worth the $10.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-5549303438066683266?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/5549303438066683266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/11/black-friday-buys.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5549303438066683266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5549303438066683266'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/11/black-friday-buys.html' title='Black Friday Buys'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iJr6rK5UOFc/TPSPjnlxVfI/AAAAAAAAAQE/om_fe3v-0vw/s72-c/Picture+34.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-1851830565684786553</id><published>2010-11-27T19:13:00.000-08:00</published><updated>2010-11-27T19:13:57.980-08:00</updated><title type='text'>NoSQL: Quite Possibly The Stupidest Catch Phrase Ever?</title><content type='html'>&lt;div class="separator" style="clear: both; font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_iJr6rK5UOFc/TPHIp_2l9_I/AAAAAAAAAQA/Yt5WqW9IPV8/s1600/Picture+33.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="232" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/TPHIp_2l9_I/AAAAAAAAAQA/Yt5WqW9IPV8/s320/Picture+33.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;A recent article on Gigaom is titled "&lt;a href="http://gigaom.com/cloud/why-cloud-computing-sells-and-nosql-is-fading/"&gt;Why cloud computing sells and NoSQL is fading&lt;/a&gt;".&amp;nbsp; I'd like to parlay that discussion into one of "why NoSQL is quite possibly the stupidest catch phrase ever". Here's where I'm coming from. Clearly the "NoSQL" moniker arose from a desire to describe systems that avoided the scalability limits of relational databases. But from the get-go, the term is just...STUPID. First of all, SQL is a query language, and there are relational systems that don't use SQL. So, "NoSQL" isn't even a good way to say "non-relational". Secondly, defining systems in terms of what they *don't* do means that dozens of systems that shouldn't get grouped together, do get grouped together. Corn: NoSQL! Windbreakers: NoSQL!&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Adding the confusion was this classic: &lt;a href="http://databasecolumn.vertica.com/database-innovation/mapreduce-a-major-step-backwards/"&gt;Map Reduce: A Major Step Backwards&lt;/a&gt;.&amp;nbsp; It's amazing that this was written by Michael Stonebreaker, but this just goes to show you that even a genius can write a ridiculous article when he's writing for a PR blog. Then there was the 180 degree follow up (ooops, how stupid do we look?): &lt;a href="http://databasecolumn.vertica.com/database-innovation/reaffirming-our-commitment-and-approach-to-hadoop-mapreduce/"&gt;Reaffirming Our Commitment to Hadoop and Mapreduce&lt;/a&gt;. &lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Honestly, the entire NoSQL thing is, to me, a mark of short sited PR as well as a failure to recognize that SQL databases can and must peacefully co-exist with systems designed to tackle other aspects of scalability and data processing. When Hadoop and Mapreduce get thrown in with "NoSQL" it especially drives me nuts, because Hadoop and Mapreduce are not even data retrieval or management systems! C'mon folks, Hadoop is for data processing. And there are lots of reasons to take the output and put it in a relational database.&amp;nbsp;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;So, I was happy to see the Gigaom article. The NoSQL emperor has no clothes. It's a stupid catch phrase, and a clear indicator that the person using it is clueless.&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-1851830565684786553?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/1851830565684786553/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/11/nosql-quite-possibly-stupidest-catch.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1851830565684786553'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1851830565684786553'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/11/nosql-quite-possibly-stupidest-catch.html' title='NoSQL: Quite Possibly The Stupidest Catch Phrase Ever?'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iJr6rK5UOFc/TPHIp_2l9_I/AAAAAAAAAQA/Yt5WqW9IPV8/s72-c/Picture+33.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-1077117176261422887</id><published>2010-10-24T13:36:00.000-07:00</published><updated>2010-10-24T13:36:45.071-07:00</updated><title type='text'>SPIRE 2010 Los Cabos</title><content type='html'>&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;I recently attended the String Processing and Information Retrieval conference (SPIRE 2010). In terms of content, this conference far exceeded my expectations. Excellent presentations on the latest research. Stuff I'd *never* even heard of: Wavelet Trees for example. Very friendly presenters, who enthusiastically spent time with me between presentations to thoroughly teach some of the concepts.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_FkhWm3eJ6OM/RflKflsSejI/AAAAAAAAAPQ/UBsF6vSFm1I/s1600/memory1.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="199" src="http://4.bp.blogspot.com/_FkhWm3eJ6OM/RflKflsSejI/AAAAAAAAAPQ/UBsF6vSFm1I/s200/memory1.jpeg" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;a href="http://en.sap.info/wp-content/uploads/2008/02/6527-474x317.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;/a&gt;&lt;a href="http://www.cs.jhu.edu/%7Esnarsal/cluster_tree.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="146" src="http://www.cs.jhu.edu/%7Esnarsal/cluster_tree.png" width="200" /&gt;&lt;/a&gt;&lt;img border="0" height="133" src="http://en.sap.info/wp-content/uploads/2008/02/6527-474x317.jpg" width="200" /&gt;&lt;a href="http://images.springer.com/cda/content/image/cda_displayimage.jpg?SGWID=0-0-16-381091-0" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://images.springer.com/cda/content/image/cda_displayimage.jpg?SGWID=0-0-16-381091-0" width="131" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_iJr6rK5UOFc/TMSXF7X6j-I/AAAAAAAAAPc/LrwNprz3TPM/s1600/IMG01044-20101013-1136.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/_iJr6rK5UOFc/TMSXF7X6j-I/AAAAAAAAAPc/LrwNprz3TPM/s320/IMG01044-20101013-1136.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_iJr6rK5UOFc/TMSWzBBZS-I/AAAAAAAAAPQ/G5bwYiLHFfs/s1600/IMG01023-20101011-0927.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/_iJr6rK5UOFc/TMSWzBBZS-I/AAAAAAAAAPQ/G5bwYiLHFfs/s320/IMG01023-20101011-0927.jpg" width="320" /&gt;&lt;/a&gt;&lt;b style="color: blue;"&gt;&amp;nbsp;&lt;/b&gt;&lt;br /&gt;&lt;b style="color: blue;"&gt;&amp;nbsp;Yahoo! Research presents Time Explorer&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="color: blue;"&gt;&lt;b&gt;Microsoft Research Keynote&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;No complaints about the venue either. Met so many cool and interesting researchers in the field of IR (which is basically &lt;b style="color: orange;"&gt;&lt;u&gt;&lt;i&gt;"search&lt;/i&gt;&lt;/u&gt;&lt;/b&gt;")&lt;/span&gt;.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_iJr6rK5UOFc/TMSYvrr8gpI/AAAAAAAAAPg/z6YAuYZyJS8/s1600/IMG01045-20101013-1339.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/TMSYvrr8gpI/AAAAAAAAAPg/z6YAuYZyJS8/s320/IMG01045-20101013-1339.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_iJr6rK5UOFc/TMSYy923MyI/AAAAAAAAAPk/brJngCBAmIo/s1600/IMG01032-20101012-1836.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/TMSYy923MyI/AAAAAAAAAPk/brJngCBAmIo/s320/IMG01032-20101012-1836.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-1077117176261422887?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/1077117176261422887/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/10/spire-2010-los-cabos.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1077117176261422887'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1077117176261422887'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/10/spire-2010-los-cabos.html' title='SPIRE 2010 Los Cabos'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_FkhWm3eJ6OM/RflKflsSejI/AAAAAAAAAPQ/UBsF6vSFm1I/s72-c/memory1.jpeg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-3137277524389048223</id><published>2010-10-24T12:27:00.000-07:00</published><updated>2010-10-24T12:47:53.941-07:00</updated><title type='text'>Java SimpleDateFormat: simply a waste of Time</title><content type='html'>I've now sunk probably 8 hours&amp;nbsp; into trying to make a minimally robust date parser that can handle dates in a variety of formats. Sadly, I'm afraid this is the best I've been able to do, given the fragility of the Java SimpleDateFormat class. I've composed a little framework in two pieces. The first piece is a properties file that defines the formats that the user will be allowed to enter dates in. The second piece is the code that jumps through an absurd series of hoops in order to work around bugs and shortcomings in SimpleDateFormat. If anyone knows a better way, that's been *tested*, please, for the love of GOD, post a comment here.&lt;br /&gt;&lt;br /&gt;&lt;span style="background-color: blue; color: yellow; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;DateFormats.properties&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;format1=yyyy-MM-dd HH:mm:ss.SSS z&lt;br /&gt;format2=yyyy-MM-dd HH:mm:ss.SSS&lt;br /&gt;format3=yyyy-MM-dd HH:mm:ss&lt;br /&gt;format4=yyyy-MM-dd HH:mm&lt;br /&gt;format5=E, MMM dd, yyyy&lt;br /&gt;format6=MMM dd yyyy&lt;br /&gt;format7=MMM dd yyyy HH:mm&lt;br /&gt;format8=MMM dd, yyyy&lt;br /&gt;format9=MMM. dd, yyyy&lt;br /&gt;format10=MM/dd/yy&lt;br /&gt;format11=MM/dd/yyyy&lt;br /&gt;format12=M/d/yy&lt;br /&gt;format13=yyyy-MM-dd&lt;br /&gt;format14=yyyy-MM-dd, E&lt;br /&gt;format15=yyyy MMM. dd, HHh 1mmm ss's'&lt;br /&gt;format16=yyyy/M/dd/HH:mm:ss&lt;br /&gt;format17=yyyy-M-dd'T'HH:mm:ss&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div style="background-color: white; color: yellow; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="background-color: white; color: yellow; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;span style="color: black;"&gt;Notice in the formats above that all months and days are defined with two format chars. E.g. "MM" or "DD". Why not "M" or "D"?&amp;nbsp; SimpleDateFormat format strings are very rigid. We want the user to be able to enter 10/&lt;span style="background-color: blue; color: yellow;"&gt;1&lt;/span&gt;&lt;span style="background-color: blue;"&gt;/&lt;/span&gt;07 or 10/&lt;span style="background-color: blue; color: yellow;"&gt;01&lt;/span&gt;/07. But I don't want to clutter the properties file with single and double format chars. For this reason, the code automatically pads any single digits with zero. So "1" in isolation is converted to "01". So if the user enters "Jul 7, 2001" the string is automatically zero-padded to "Jul 07, 2001". This allows the properties file to include only the double-digit variants of date numbers without having to account for every variation in which a digit could be either single or double digit. With regard to the code below, I haven't taken time to extract it as a library, so please forgive the unexplained parameters such as "id" and "paramName".This code convers the time provided by the user into the current Greenwich Mean Time.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="background-color: white; color: yellow; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="background-color: blue; color: yellow; font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Java Source Fragments&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;private static final Pattern ISOLATED_DIGIT = Pattern.compile("(^|\\D|\\s)(\\d)(\\D|$|\\s)"); //digit can be surrounded by non-digit but also begining or end of line or whitespace&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;public static Object parseDate(String dateString, String id, String paramName) {&lt;br /&gt;        if(null == dateString){&lt;br /&gt;            return dateString;&lt;br /&gt;        }&lt;br /&gt;        if(dateString.equalsIgnoreCase("NOW")){&lt;br /&gt;            //default time stamp is Zulu time (time at prime meridian, Greenwich)&lt;br /&gt;            long currentTime = System.currentTimeMillis();&lt;br /&gt;            Timestamp ts = new java.sql.Timestamp(currentTime-TimeZone.getDefault().getOffset(currentTime));&lt;br /&gt;            return ts;&lt;br /&gt;        }else{&lt;br /&gt;            dateString = zeroPadIsolatedDigits(dateString);&lt;br /&gt;            if(log.isDebugEnabled())log.debug("input zero-padded to " + dateString);&lt;br /&gt;            for(Map.Entry entry:DATE_FORMATS.entrySet()){&lt;br /&gt;                String key = entry.getKey().toString();&lt;br /&gt;                DateFormat dateFormat = new SimpleDateFormat(entry.getValue().toString());&lt;br /&gt;                dateFormat.setLenient(false);&lt;br /&gt;                try{&lt;br /&gt;                    java.util.Date date = dateFormat.parse(dateString);&lt;br /&gt;                    &lt;br /&gt;                    //I have found bugs in the parse method, in which strings that *don't* actually match the format template&lt;br /&gt;                    //get parsed without Exception, thus truncating trailing parts of the date (like the timezone). For this reason&lt;br /&gt;                    //I am forced to regurgitate the date string, and compare it to the input, and if they don't match, skip forward in the loop&lt;br /&gt;                    String regurgitated = dateFormat.format(date);//...and no, we can't just compare the regurgitated string b/c PST and get adjusted to PDT&lt;br /&gt;                    if(regurgitated.length() != dateString.length()){ //compare their lengths to make sure nothing got truncated&lt;br /&gt;                        if(log.isDebugEnabled())log.debug(dateString + " was parsed with format " + entry.getValue() + " but was apparently parsed incorrectly as " + regurgitated + " length difference was "+(regurgitated.length()-dateString.length()));&lt;br /&gt;                        continue;&lt;br /&gt;                    }else{&lt;br /&gt;                        //the length of the regurgitated string matches the length of the input.&lt;br /&gt;                        //We still need to eat the regurgitated string, and compare the resulting  ms since epoch to the Date we originally parsed to make sure we didn't&lt;br /&gt;                        //encounter a SimpleDateFormat parsing bug.&lt;br /&gt;                         //Example: 2010-9-23 12:22:23.000 PST gets regurgintated as 2010-09-23 13:22:23.000 PDT, which is different text, but same ms since epoch&lt;br /&gt;                        //So the above illustrates why we cannot just compare the regurgitated text to the input dateString, because Java may decide on an equivalent but&lt;br /&gt;                        //textually different representation from the input (PST is the same as PDT in the half of the year when daylight savings time isn't in effect).&lt;br /&gt;                        java.util.Date reparsed = dateFormat.parse(regurgitated);&lt;br /&gt;                        if(reparsed.getTime() != date.getTime()){&lt;br /&gt;                            if(log.isDebugEnabled())log.debug(dateString+" produces different ms since epoch than  " +regurgitated );&lt;br /&gt;                            continue;&lt;br /&gt;                        }&lt;br /&gt;                    }&lt;br /&gt;                    if(log.isDebugEnabled())log.debug("handled date" + dateString +" using format template: " + entry.getValue().toString() + " which regurgitated " + dateString);&lt;br /&gt;                    TimeZone timeZone = dateFormat.getTimeZone();&lt;br /&gt;                    //if(log.isDebugEnabled())log.debug(timeZone);&lt;br /&gt;                    //convert to GMT time and account for timezone&lt;br /&gt;                    return new java.sql.Timestamp(date.getTime()-timeZone.getOffset(date.getTime()));&lt;br /&gt;                }catch(ParseException pe){&lt;br /&gt;                    if(log.isDebugEnabled()){&lt;br /&gt;                        log.debug(pe.getMessage());&lt;br /&gt;                        log.debug(dateString + "couldn't be parsed with format " + entry.getValue());&lt;br /&gt;                    }&lt;br /&gt;                }&lt;br /&gt;            }&lt;br /&gt;            throw Util.newApplicationException(id, "date "+ dateString+" could not be parsed.","DataFormatException", 130, paramName);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;     private static String zeroPadIsolatedDigits(String s) {&lt;br /&gt;        //Java date parsing will prepend leading zeros to islolated digits. For this reason, I prepend a zero to the isolated digits before parsing the string, so that the regurgitation step&lt;br /&gt;        //produces a string identical to the input&lt;br /&gt;        boolean done = false;&lt;br /&gt;        //this is an obscure case in which the matching regions overlap, therefore m.find() only finds one of the overlapping instance.&lt;br /&gt;        //For instance, 100-1-2. Find() won't find "-2 " because it overalps "-1-". Consequently we have to repeatedly call find on a new matcher after each replacement has been made&lt;br /&gt;        while (!done) {&lt;br /&gt;            Matcher m = ISOLATED_DIGIT.matcher(s);&lt;br /&gt;            StringBuffer buf = new StringBuffer();&lt;br /&gt;            if (m.find()) {&lt;br /&gt;                if(log.isDebugEnabled())log.debug("found isolated digit:" + m.group(2));&lt;br /&gt;                m.appendReplacement(buf, m.group(1) + "0" + m.group(2) + m.group(3)); //need to stuff back in the stuff before the isolated digit, then 0 (zero-pad), then the digit, then stuff after)&lt;br /&gt;            }else {&lt;br /&gt;                done = true;&lt;br /&gt;            }&lt;br /&gt;            m.appendTail(buf); //OK, al isolated digits have been replaced by leading-zero padded digits&lt;br /&gt;            s = buf.toString(); //replace input with zero-padded input&lt;br /&gt;        }&lt;br /&gt;        return s;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-3137277524389048223?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/3137277524389048223/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/10/java-simpledateformat-simply-waste-of.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3137277524389048223'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3137277524389048223'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/10/java-simpledateformat-simply-waste-of.html' title='Java SimpleDateFormat: simply a waste of Time'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-3324709512762893910</id><published>2010-10-23T13:03:00.000-07:00</published><updated>2010-10-24T12:57:05.613-07:00</updated><title type='text'>Data Storm</title><content type='html'>&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;This morning's project was installing a Davis Vantage Pro weather station. It's really an amazing piece of equipment. It logs windspeed and direction, solar radiation, and dozens of other variabls. It even has a rain collector. The data comes off the unit in real-time, and is transmitted to a nice LCD console that shows graphs, weather forecasts etc. I hope to log enough data on sun and wind in order to make a determination as to whether solar panels or wind power will be my best alterative energy source. I'm also interested in quantifying just how bizarre the microclimate of western san francisco actually is. How many days is it foggy? What time does the fog typically roll in or out in a given month? With a bit of free time, I hope to be able to load the data into nextdb to create a detailed data history.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_iJr6rK5UOFc/TMSOxToj7uI/AAAAAAAAAOg/yV7h8UKyuh0/s1600/IMG_1659.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="150" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/TMSOxToj7uI/AAAAAAAAAOg/yV7h8UKyuh0/s200/IMG_1659.JPG" width="200" /&gt;&lt;/a&gt;&lt;a href="http://2.bp.blogspot.com/_iJr6rK5UOFc/TMM9MyKEW1I/AAAAAAAAAOc/X5Q46iQ84GE/s1600/IMG_1661.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/TMM9MyKEW1I/AAAAAAAAAOc/X5Q46iQ84GE/s400/IMG_1661.JPG" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&amp;nbsp;I'm already getting some valuable siting data on windspeed. There are several interesting vertical-axis helical wind-power generators that might be appropriate. Hmmm.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-3324709512762893910?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/3324709512762893910/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/10/data-storm.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3324709512762893910'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3324709512762893910'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/10/data-storm.html' title='Data Storm'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iJr6rK5UOFc/TMSOxToj7uI/AAAAAAAAAOg/yV7h8UKyuh0/s72-c/IMG_1659.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-8712993324063075158</id><published>2010-09-25T08:02:00.000-07:00</published><updated>2010-11-27T19:17:04.843-08:00</updated><title type='text'>Government "Black Ice" Becomes a Reality</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_iJr6rK5UOFc/TJ4NfLqFP7I/AAAAAAAAAOY/Q7yirezh8tA/s1600/Picture+30.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="253" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/TJ4NfLqFP7I/AAAAAAAAAOY/Q7yirezh8tA/s320/Picture+30.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;Keeping with the William Gibson theme, the future - whoops, I meant "the present"- look increasingly like something dreamed up by said sci fi author.&amp;nbsp; This week we learned about &lt;a href="http://en.wikipedia.org/wiki/Stuxnet"&gt;STUXNET&lt;/a&gt;: Government Black Ice designed to attack industrial control facilities, and in particular the Bashir Nuclear Reactor. The sophisticated source code includes the ability to inject itself into programmable logic devices; hacking the actual hardware itself, relying on proprietary hardware secretes stolen from two Taiwanese manufacturers.&amp;nbsp; Apparently too complex to have been written by a hacker in a dorm room, the media concludes that it must be "state sponsored". Maybe. Probably. But in a present that increasingly looks like the cyberscape described in Neuromancer we shouldn't rule out multinational corporations as the source. As pointed out in the media, STUXNET *is* a *weapon*. Cyberspace is a battlefield where corporations, states, and individuals can wage war on a practically equal footing, with the ability to cloak their identity. Imagine that; anonymous war with motives known only to the participants. Target: a nuclear reactor.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-8712993324063075158?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/8712993324063075158/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/09/government-black-ice-becomes-riality.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8712993324063075158'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8712993324063075158'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/09/government-black-ice-becomes-riality.html' title='Government &quot;Black Ice&quot; Becomes a Reality'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iJr6rK5UOFc/TJ4NfLqFP7I/AAAAAAAAAOY/Q7yirezh8tA/s72-c/Picture+30.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-852183433676237362</id><published>2010-09-01T18:09:00.000-07:00</published><updated>2010-09-01T18:12:27.368-07:00</updated><title type='text'>Awesome Op-ed in New York Times by William Gibson</title><content type='html'>&lt;span style="color: orange; font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif; font-size: small;"&gt;This a fantastic Op-ed by William Gibson on Google.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_iJr6rK5UOFc/TH74ynZUejI/AAAAAAAAAN4/aT6beSW196w/s1600/Picture+26.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="275" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/TH74ynZUejI/AAAAAAAAAN4/aT6beSW196w/s400/Picture+26.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;a href="http://3.bp.blogspot.com/_iJr6rK5UOFc/TH742CNaBhI/AAAAAAAAAOA/erleKBXZIL0/s1600/Picture+27.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="313" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/TH742CNaBhI/AAAAAAAAAOA/erleKBXZIL0/s400/Picture+27.png" width="400" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_iJr6rK5UOFc/TH7432WtchI/AAAAAAAAAOI/lk-oXPVxE88/s1600/Picture+28.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="310" src="http://1.bp.blogspot.com/_iJr6rK5UOFc/TH7432WtchI/AAAAAAAAAOI/lk-oXPVxE88/s400/Picture+28.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;a href="http://3.bp.blogspot.com/_iJr6rK5UOFc/TH745K1a1lI/AAAAAAAAAOQ/OxaPMP0VL0E/s1600/Picture+29.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/TH745K1a1lI/AAAAAAAAAOQ/OxaPMP0VL0E/s400/Picture+29.png" width="400" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-852183433676237362?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/852183433676237362/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/09/awesome-op-ed-in-new-york-times-by.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/852183433676237362'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/852183433676237362'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/09/awesome-op-ed-in-new-york-times-by.html' title='Awesome Op-ed in New York Times by William Gibson'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_iJr6rK5UOFc/TH74ynZUejI/AAAAAAAAAN4/aT6beSW196w/s72-c/Picture+26.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-4005090751948114867</id><published>2010-07-15T21:44:00.000-07:00</published><updated>2010-07-15T21:44:40.240-07:00</updated><title type='text'>Neuromancer Vs. Matrix</title><content type='html'>Neuromancer was written by William Gibson and published in 1984.&amp;nbsp; I first read it high school back in 1993. Every few years I read it again, and each time I find something new to like. &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_iJr6rK5UOFc/TD_dN4qeLdI/AAAAAAAAANY/dhpoi4W0ORE/s1600/Picture+21.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/TD_dN4qeLdI/AAAAAAAAANY/dhpoi4W0ORE/s320/Picture+21.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In my most recent reading, I find myself noticing how much of the concept matter in The Matrix is based on Neuromancer. Gibson coined the term "The Matrix" and "cyberspace", and Gibson describes a Rasta "freeside" called "Zion" (albeit in orbit), and simstim memory sticks that jack in through a socket behind the ear. It's hard to imagine that Gibson wrote Neuromancer before there was a world wide web.&lt;br /&gt;&lt;div style="color: orange;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="color: orange;"&gt;"T&lt;i&gt;he Matrix is ... a concentual hallucination. ..A graphic representation of data abstracted from the banks of every computer in the human system. Unthinkable complexity. Lines of light arranged in the nonspace of the mind, clusters and constellations of data. Like city lights, receding...&lt;/i&gt;"&lt;/div&gt;&lt;br /&gt;This part reminds me of the "symbols" that fall down the screens in the movie The Matrix: &lt;br /&gt;&lt;br /&gt;&lt;div style="color: orange;"&gt;"&lt;i&gt;And in the bloodlit dark behind his eyes, silver phosphenes boiling in from the edge of space, hypnagogic images jerking past like film compiled from random frames. Symbols, figures, faces, a blurred fragmented mandala of visual information&lt;/i&gt;".&amp;nbsp;&lt;/div&gt;&lt;div style="color: orange;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="color: orange;"&gt;&lt;span style="color: black;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-4005090751948114867?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/4005090751948114867/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/07/neuromancer-vs-matrix.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4005090751948114867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4005090751948114867'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/07/neuromancer-vs-matrix.html' title='Neuromancer Vs. Matrix'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_iJr6rK5UOFc/TD_dN4qeLdI/AAAAAAAAANY/dhpoi4W0ORE/s72-c/Picture+21.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-2551372880408436235</id><published>2010-07-07T22:55:00.000-07:00</published><updated>2010-07-07T22:55:10.991-07:00</updated><title type='text'>Android Earcon</title><content type='html'>Did you notice that Google's Android phones have a startup sound that's quite familiar...that is, if you are a fan of Blade Runner. The little "bootup jingle" is from the opening scene soundtrack by Vangelis in&amp;nbsp; Blade Runner. &lt;a href="http://www.youtube.com/watch?v=YaR5wVL9x2I"&gt;Listen here&lt;/a&gt;, its at 1 minute 40 seconds.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-2551372880408436235?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/2551372880408436235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/07/android-earcon.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2551372880408436235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2551372880408436235'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/07/android-earcon.html' title='Android Earcon'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-3887793916065101188</id><published>2010-07-07T16:04:00.000-07:00</published><updated>2010-07-07T16:05:21.433-07:00</updated><title type='text'>Hadoop Summit</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div style="color: orange; font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Last week I attended the &lt;a href="http://developer.yahoo.com/events/hadoopsummit2010/"&gt;Hadoop Summi&lt;/a&gt;&lt;a href="http://developer.yahoo.com/events/hadoopsummit2010/"&gt;t&lt;/a&gt;. It was sold out ten days prior! That doesn't happen very often these days, in an environment where corporate travel is severely cut back. I even saw sizable contingents from Japan and Brazil. This is a very exciting time to be involved in the field of search and data processing. The science track was quite interesting, as was the talk by facebook about how they are crunching something like 90 TB per week, and are siting on 85 Peta Bytes. They are using hadoop mapreduce in near real-time. Processing latencies are getting close to 1 minute. That's nearly real-time availability of all the information you post on facebook, to everyone else (and every moving part) in the facebook system. Oh, and the lunch was great.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_iJr6rK5UOFc/TDUGcrnHmzI/AAAAAAAAANQ/EVF3XNpbMcM/s320/IMG_1498.JPG" /&gt;&lt;a href="http://3.bp.blogspot.com/_iJr6rK5UOFc/TDUGblsRfUI/AAAAAAAAANI/LAON0UHk8HY/s1600/IMG_1499.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/TDUGblsRfUI/AAAAAAAAANI/LAON0UHk8HY/s320/IMG_1499.JPG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-3887793916065101188?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/3887793916065101188/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/07/hadoop-summit.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3887793916065101188'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3887793916065101188'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/07/hadoop-summit.html' title='Hadoop Summit'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_iJr6rK5UOFc/TDUGcrnHmzI/AAAAAAAAANQ/EVF3XNpbMcM/s72-c/IMG_1498.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-4151468617745588418</id><published>2010-07-06T21:28:00.000-07:00</published><updated>2010-07-06T21:28:42.086-07:00</updated><title type='text'>badassery with bits: counting 1 bits</title><content type='html'>I was recently looking at some code to count the number of bits in an integer that are set to 1. Here is the method:&lt;br /&gt;&lt;br /&gt;int = getARandomInt(); &lt;br /&gt;while(n!=0){&lt;br /&gt;&amp;nbsp;&amp;nbsp; n &amp;amp;= n-1;&lt;br /&gt;&amp;nbsp;&amp;nbsp; count++;&lt;br /&gt;} &lt;br /&gt;print("There are "+count+" bits turned on.");&lt;br /&gt;&lt;br /&gt;Can you figure out why it works?&lt;br /&gt;&lt;br /&gt;hint: negative one has every bit turned on because negating a number is to take it's two's complement (which flips every bit), and add 1. Watch what happens with the carry bit when you add n to -1.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-4151468617745588418?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/4151468617745588418/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/07/badassery-with-bits-counting-1-bits.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4151468617745588418'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4151468617745588418'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/07/badassery-with-bits-counting-1-bits.html' title='badassery with bits: counting 1 bits'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-1539597226943223654</id><published>2010-06-13T21:53:00.000-07:00</published><updated>2010-07-24T13:21:39.250-07:00</updated><title type='text'>Matrix Challenge</title><content type='html'>Here is an interesting challenge posted on the website of a company called Rapleaf:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;span style="font-size: x-small;"&gt;We wish to find, for an arbitrary N, an N x N matrix with the   following property: each entry in the matrix is the smallest  non-negative number which does not appear either above the entry or to  its left.&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;         &lt;i&gt;&lt;span style="font-size: x-small;"&gt;Write a function that computes the entry in a particular row  and column. That is, complete the following:&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;i&gt;&lt;span style="font-size: x-small;"&gt;&lt;code&gt;int entry_at(int row, int column) {&lt;br /&gt;    // ...&lt;br /&gt;}&lt;/code&gt;&lt;/span&gt;&lt;/i&gt;&lt;/pre&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;&lt;span style="font-size: x-small;"&gt;Can you write the entry_at function to run in constant  space and constant time?&lt;/span&gt;&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;&lt;span style="font-size: x-small;"&gt;Can you prove that your algorithm is correct?&lt;/span&gt;&lt;/i&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&amp;nbsp;For instance, here is a 6x6&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_iJr6rK5UOFc/TBW0zi7qb6I/AAAAAAAAANA/BZa_tN9Lqg0/s1600/Picture+17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_iJr6rK5UOFc/TBW0zi7qb6I/AAAAAAAAANA/BZa_tN9Lqg0/s320/Picture+17.png" /&gt;&lt;/a&gt;&lt;/div&gt;I posted a solution before, which was wrong, because I only looked at a 6x6, and my solution failed for larger matrices. Thanks to whomever posted the comment pointing out that my solution was broken. So I rewrote it in Java, after looking at some larger matrices.&amp;nbsp; Here is a printout of the 32x32 matrix produced by the program.&lt;br /&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt; 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 &lt;br /&gt; 1  0  3  2  5  4  7  6  9  8 11 10 13 12 15 14 17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30 &lt;br /&gt; 2  3  0  1  6  7  4  5 10 11  8  9 14 15 12 13 18 19 16 17 22 23 20 21 26 27 24 25 30 31 28 29 &lt;br /&gt; 3  2  1  0  7  6  5  4 11 10  9  8 15 14 13 12 19 18 17 16 23 22 21 20 27 26 25 24 31 30 29 28 &lt;br /&gt; 4  5  6  7  0  1  2  3 12 13 14 15  8  9 10 11 20 21 22 23 16 17 18 19 28 29 30 31 24 25 26 27 &lt;br /&gt; 5  4  7  6  1  0  3  2 13 12 15 14  9  8 11 10 21 20 23 22 17 16 19 18 29 28 31 30 25 24 27 26 &lt;br /&gt; 6  7  4  5  2  3  0  1 14 15 12 13 10 11  8  9 22 23 20 21 18 19 16 17 30 31 28 29 26 27 24 25 &lt;br /&gt; 7  6  5  4  3  2  1  0 15 14 13 12 11 10  9  8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24 &lt;br /&gt; 8  9 10 11 12 13 14 15  0  1  2  3  4  5  6  7 24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23 &lt;br /&gt; 9  8 11 10 13 12 15 14  1  0  3  2  5  4  7  6 25 24 27 26 29 28 31 30 17 16 19 18 21 20 23 22 &lt;br /&gt;10 11  8  9 14 15 12 13  2  3  0  1  6  7  4  5 26 27 24 25 30 31 28 29 18 19 16 17 22 23 20 21 &lt;br /&gt;11 10  9  8 15 14 13 12  3  2  1  0  7  6  5  4 27 26 25 24 31 30 29 28 19 18 17 16 23 22 21 20 &lt;br /&gt;12 13 14 15  8  9 10 11  4  5  6  7  0  1  2  3 28 29 30 31 24 25 26 27 20 21 22 23 16 17 18 19 &lt;br /&gt;13 12 15 14  9  8 11 10  5  4  7  6  1  0  3  2 29 28 31 30 25 24 27 26 21 20 23 22 17 16 19 18 &lt;br /&gt;14 15 12 13 10 11  8  9  6  7  4  5  2  3  0  1 30 31 28 29 26 27 24 25 22 23 20 21 18 19 16 17 &lt;br /&gt;15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 &lt;br /&gt;16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31  0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 &lt;br /&gt;17 16 19 18 21 20 23 22 25 24 27 26 29 28 31 30  1  0  3  2  5  4  7  6  9  8 11 10 13 12 15 14 &lt;br /&gt;18 19 16 17 22 23 20 21 26 27 24 25 30 31 28 29  2  3  0  1  6  7  4  5 10 11  8  9 14 15 12 13 &lt;br /&gt;19 18 17 16 23 22 21 20 27 26 25 24 31 30 29 28  3  2  1  0  7  6  5  4 11 10  9  8 15 14 13 12 &lt;br /&gt;20 21 22 23 16 17 18 19 28 29 30 31 24 25 26 27  4  5  6  7  0  1  2  3 12 13 14 15  8  9 10 11 &lt;br /&gt;21 20 23 22 17 16 19 18 29 28 31 30 25 24 27 26  5  4  7  6  1  0  3  2 13 12 15 14  9  8 11 10 &lt;br /&gt;22 23 20 21 18 19 16 17 30 31 28 29 26 27 24 25  6  7  4  5  2  3  0  1 14 15 12 13 10 11  8  9 &lt;br /&gt;23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24  7  6  5  4  3  2  1  0 15 14 13 12 11 10  9  8 &lt;br /&gt;24 25 26 27 28 29 30 31 16 17 18 19 20 21 22 23  8  9 10 11 12 13 14 15  0  1  2  3  4  5  6  7 &lt;br /&gt;25 24 27 26 29 28 31 30 17 16 19 18 21 20 23 22  9  8 11 10 13 12 15 14  1  0  3  2  5  4  7  6 &lt;br /&gt;26 27 24 25 30 31 28 29 18 19 16 17 22 23 20 21 10 11  8  9 14 15 12 13  2  3  0  1  6  7  4  5 &lt;br /&gt;27 26 25 24 31 30 29 28 19 18 17 16 23 22 21 20 11 10  9  8 15 14 13 12  3  2  1  0  7  6  5  4 &lt;br /&gt;28 29 30 31 24 25 26 27 20 21 22 23 16 17 18 19 12 13 14 15  8  9 10 11  4  5  6  7  0  1  2  3 &lt;br /&gt;29 28 31 30 25 24 27 26 21 20 23 22 17 16 19 18 13 12 15 14  9  8 11 10  5  4  7  6  1  0  3  2 &lt;br /&gt;30 31 28 29 26 27 24 25 22 23 20 21 18 19 16 17 14 15 12 13 10 11  8  9  6  7  4  5  2  3  0  1 &lt;br /&gt;31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10  9  8  7  6  5  4  3  2  1  0 &lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The valAboveDiag method takes advantage of the fact the matrix is symetric about the main diagonal. For values below the diagonal, the row and column numbers are simply transposed. To compute an arbitrary value in an NxN matrix, the method executes O(log(N)). However, if I always intended to print the entire matrix, I could have rewritten this to take advantage of values already stored in the matrix. In that case, adding a new value to the matrix would occur in constant time. The central idea behind the code below, is that the matrix is built up of matrices whose sizes are powers of 2 (e.g. 2x2,4x4,8x8, etc), organized in a pattern [[A,B][B,A]]. For a given cell, above the main diagonal, the cell is either in quandrant [0,0], [0,1], or [1,1]. Because of the pattern [[A,B][B,A]], this means that quadrant [0,0] is A, quadrant [0,1] is B, and [1,1] is A. Observing that B=A+mid, where "mid" is the "middle value" midway between 0 and the maximum value of the power-of-two block, we can only need to be able to produce A to find any other value in the power-of-two block. This process simply recurses until A is found to be the identity matrix (i.e. [[0,1],[1,0]]).&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;package random;&lt;br /&gt;&lt;br /&gt;import java.util.Arrays;&lt;br /&gt;&lt;br /&gt;/**&lt;br /&gt; *&lt;br /&gt; * @author geoffreyhendrey&lt;br /&gt; */&lt;br /&gt;public class MadMatrix {&lt;br /&gt;    int[][] a;&lt;br /&gt;&lt;br /&gt;    public MadMatrix(int size){&lt;br /&gt;        a = new int[size][size];&lt;br /&gt;        for(int r=0;r&amp;lt;size;r++){&lt;br /&gt;            for(int c=0;c&amp;lt;size;c++){&lt;br /&gt;                a[r][c] = valAboveDiag(r,c);&lt;br /&gt;            }&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Override&lt;br /&gt;    public String toString(){&lt;br /&gt;        StringBuilder buf = new StringBuilder();&lt;br /&gt;        for(int[] row:a){&lt;br /&gt;            for(int column:row){&lt;br /&gt;                buf.append(String.format("%2d ", column));&lt;br /&gt;            }&lt;br /&gt;            buf.append("\n");&lt;br /&gt;        }&lt;br /&gt;        return buf.toString();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;    private int valAboveDiag(int r, int c) {&lt;br /&gt;        if(r&amp;gt;c){&lt;br /&gt;            int tmp = c;&lt;br /&gt;            c=r;&lt;br /&gt;            r=tmp;&lt;br /&gt;        }&lt;br /&gt;        int order = getOrder(c);&lt;br /&gt;        if(0 == order){&lt;br /&gt;            if(r==c) return 0;&lt;br /&gt;            return 1;&lt;br /&gt;        }&lt;br /&gt;        int mid = 1&amp;lt;&amp;lt;order;&lt;br /&gt;        if(c &amp;gt;=mid &amp;amp;&amp;amp; r&amp;lt;mid){&lt;br /&gt;            return valAboveDiag(r, c-mid) + mid;&lt;br /&gt;        }else{&lt;br /&gt;            return valAboveDiag(r-mid, c-mid);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static int getOrder(int c){&lt;br /&gt;        int order = 0;&lt;br /&gt;        while(c &amp;gt; 1){&lt;br /&gt;            c &amp;gt;&amp;gt;&amp;gt;=1;&lt;br /&gt;            order++;&lt;br /&gt;        }&lt;br /&gt;        return order;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    /**&lt;br /&gt;     * @param args the command line arguments&lt;br /&gt;     */&lt;br /&gt;    public static void main(String[] args) {&lt;br /&gt;        MadMatrix mm = new MadMatrix(32);&lt;br /&gt;        System.out.println(mm);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-1539597226943223654?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/1539597226943223654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/06/matrix-challenge.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1539597226943223654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1539597226943223654'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/06/matrix-challenge.html' title='Matrix Challenge'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_iJr6rK5UOFc/TBW0zi7qb6I/AAAAAAAAANA/BZa_tN9Lqg0/s72-c/Picture+17.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-7150230250527379141</id><published>2010-04-04T18:59:00.000-07:00</published><updated>2010-04-04T18:59:55.728-07:00</updated><title type='text'>AES Encryption in Java</title><content type='html'>&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;I wrote this block of code a couple years ago, but it has served me well. I remember it being quite a challenge to get it to work properly. There was, and maybe still is a dearth of decent examples on using AES encryption from Java. The examples I found didn't deal with Cypher Block Coding (CBC). CBC is essential to decent encryption because it feeds the output of one cyphered block forward into the next, thus creating a cascade of randomness. All you need is an initial random phrase in the data you wish to encrypt. If you don't use CBC, you'll notice that blocks of your encrypted data can easily be recognized as separators in what you are encrypting. For example, let's say I encrypt the phrase "user:bob:password:abc". The substring "user:" and "password:" will cause an identifiable pattern in the encrypted data. If someone has access to snoop the wire, they can literally lift the encrypted username and password out of someone else's transmission, and paste it into their own. While CBC with a leading random phrase will make it impossible to identify such non-randomness, you still have to guard against someone injecting cruft into the encrypted data. This should be done by appending an MD5 hash of the unencrypted data, then encrypting the whole ball of wax.&lt;/div&gt;&lt;br /&gt;&lt;pre style="background-color: #eeeeee; border: 1px dashed rgb(153, 153, 153); color: black; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; font-size: 12px; line-height: 14px; overflow: auto; padding: 5px; width: 100%;"&gt;&lt;code&gt;    private static String encrypt(String encryptMe, byte[] cryptKey, SecretKey secretKey, byte[] iv){&lt;br /&gt;        try {&lt;br /&gt;            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "SunJCE");&lt;br /&gt;            cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));&lt;br /&gt;            byte[] raw = encryptMe.toString().getBytes("ASCII");&lt;br /&gt;            if(log.isDebugEnabled())log.debug("unencrypted bytes: " + raw.length);&lt;br /&gt;            byte[] cipherText = new byte[cipher.getOutputSize(raw.length)];&lt;br /&gt;            int ctLength = cipher.update(raw, 0, raw.length, cipherText, 0);&lt;br /&gt;            ctLength += cipher.doFinal(cipherText, ctLength);&lt;br /&gt;            if(log.isDebugEnabled())log.debug("ctLength: " + ctLength);&lt;br /&gt;            if(log.isDebugEnabled())log.debug("cipherText Length: " + cipherText.length);&lt;br /&gt;            //raw = cipher.doFinal(raw, 0, raw.length);&lt;br /&gt;            byte[] copy = new byte[ctLength];&lt;br /&gt;            System.arraycopy(cipherText, 0, copy, 0, ctLength);&lt;br /&gt;            String encrypted = new String(new Base64().encode(copy), "US-ASCII");&lt;br /&gt;            return encrypted;&lt;br /&gt;        } catch (Exception ex) {&lt;br /&gt;            throw new RuntimeException(ex.getMessage(), ex);&lt;br /&gt;        }        &lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-7150230250527379141?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/7150230250527379141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/04/aes-encryption-in-java.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7150230250527379141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7150230250527379141'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/04/aes-encryption-in-java.html' title='AES Encryption in Java'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-6646827827229429647</id><published>2010-04-02T20:22:00.000-07:00</published><updated>2010-04-02T20:22:07.514-07:00</updated><title type='text'>what's in your history?</title><content type='html'>&lt;span style="font-family: Arial; font-size: x-small;"&gt;[ghendrey@geoffunix hadoop]$ cut -f1 -d" "  ~ghendrey/.bash_history | sort | uniq -c | sort -nr | head -n  20&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 206 hadoop&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  44&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 27 ls&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 23  cd&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 18 su&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 17  grep&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 15 tac&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 11  pwd&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 10 exit&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 8  env&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 5 less&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4  /mnt/hadoop/hbase-0.20.3/bin/hbase&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4  man&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4  ifconfig&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3  telnet&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3  &lt;a href="http://start-dfs.sh/" target="_blank"&gt;&lt;span class="yshortcuts" id="lw_1270263139_0"&gt;start-dfs.sh&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3  source&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3  mount&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 3 ant&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;  2 vi&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-6646827827229429647?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/6646827827229429647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/04/whats-in-your-history.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6646827827229429647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6646827827229429647'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/04/whats-in-your-history.html' title='what&apos;s in your history?'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-6506340876531333855</id><published>2010-02-23T19:11:00.000-08:00</published><updated>2010-02-23T19:11:22.623-08:00</updated><title type='text'>Webscale Computing and Hadoop</title><content type='html'>I've been using &lt;a href="http://hadoop.apache.org/"&gt;Hadoop&lt;/a&gt; extensively for a month or so now at the office. I've been a big fan of &lt;a href="http://en.wikipedia.org/wiki/Doug_Cutting"&gt;Doug Cutting&lt;/a&gt;'s Lucene technology, so when I heard that Doug Cutting was the guy behind, Hadoop, that pretty much pushed me over the edge and I started using Hadoop for building new types of database indexes from multi-gigabyte datasets.&lt;br /&gt;&lt;br /&gt;Hadoop is an incredibly rich software stack consisting of three main pieces:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The Hadoop Distributed File System (HDFS)&lt;/li&gt;&lt;li&gt; A Map/Reduce infrastructure consisting of Daemons that layer services on top of HDFS&lt;/li&gt;&lt;li&gt;A set of APIs allowing a data processing task to be split into simple Map and Reduce phases&lt;/li&gt;&lt;/ol&gt;There's a fourth piece, which is the many related tools (HBase, Hive, Pig, etc) which are layered on top of Hadoop.&lt;br /&gt;&lt;br /&gt;If one was to read the &lt;a href="http://en.wikipedia.org/wiki/MapReduce"&gt;description of map/reduce&lt;/a&gt; one might conclude that it is pretty much nonsense. In fact, it sounds to trivial to even be called an algorithm. Put things into groups, operate on the groups. Big deal. It sounds pretty much like common sense. Until you work with Hadoop, you really cannot appreciate all of the benefits that the Hadoop stack brings. It's really the collective benefits of the entire stack that make for the game changing experience that programming with Hadoop really is.&lt;br /&gt;&lt;br /&gt;With problems of processing huge datasets, the devil is in the details. Hadoop provides a framework that removes all of the annoying complexity associated with big data sets. In essence you write two simple methods and from that point on you don't care much whether you are operating on 1 byte or 1 TB. This is possible in large part because HDFS allows you to think of terrabytes worth of data as a simple URL such as hdfs://namenode/user/geoff/BigDataSet. HDFS takes care of replicating your data, and figuring out where the data blocks actually reside in the cluster. As an added bonus, Hadoop automatically deals with nuances such as the files being zipped. But wait, there's more. From the hadoop command line, you can run commands to cat and grep these URLs, again, acting as if they were simple local files.&lt;br /&gt;&lt;br /&gt;For me, one of the most interesting side effects of running a hadoop cluster has been how it changes ones ability to interact with peers on a webscale computing project. You can now shoot your co-worker a URL to a 200GB file, and they can poke and prod at the contents by doing things like "hadoop fs -text hdfs://namenode/user/geoff/BigData".&lt;br /&gt;&lt;br /&gt;I'll try to write more about this later, but for now suffice it to say that Hadoop is quite exciting to work with. I think the criticism by Michael Stonebreaker have totally missed the point of what a good implementation of a map/reduce framework can yield, probably because their criticism focused on the map/reduce algorithm, which in and of itself is trivial. And that's really the point. It's really all about the tools and the entire stack that make map/reduce simply a "part of this complete breakfast" when it comes to hadoop. So don't forget the toast, juice, and yummy Cheerios!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-6506340876531333855?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/6506340876531333855/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/02/webscale-computing-and-hadoop.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6506340876531333855'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6506340876531333855'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/02/webscale-computing-and-hadoop.html' title='Webscale Computing and Hadoop'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-132779247061012543</id><published>2010-02-21T12:24:00.000-08:00</published><updated>2010-02-22T12:28:29.990-08:00</updated><title type='text'>HATEOAS - Hypermedia As The Engine Of Application State</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Roy_Fielding"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;Roy Fielding&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;'s PhD dissertation on&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.ics.uci.edu/%7Efielding/pubs/dissertation/top.htm"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;Architectural Styles and  the Design of Network-based Software Architectures&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&amp;nbsp;is the seminal paper on the &lt;/span&gt;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;REST&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;ful style of web architecture. Before discussing &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.ics.uci.edu/%7Efielding/pubs/dissertation/top.htm"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;the pape&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;r, let's first discuss &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;what&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.ics.uci.edu/%7Efielding/pubs/dissertation/top.htm"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;it&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt; is, because &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.ics.uci.edu/%7Efielding/pubs/dissertation/top.htm"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;it&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&amp;nbsp;seems quite unusual in its approach as a PhD dissertation. Reading this paper in the 21st century, one might conclude that the paper is an&amp;nbsp;"experience paper" (as defined &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.sigplan.org/oopsla/oopsla96/how91.html"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;here&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;). However, &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.sigplan.org/oopsla/oopsla96/how91.html"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;as noted&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;, "&lt;/span&gt;&lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;An experience paper that merely confirms that which is well known as  opposed to that which is widely believed is of little value.&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;" However, in the early 1990's, the topic of the dissertation was probably not widely known. The irony now, is that as the term REST becomes more and more commonplace, and is applied to non-RESTful systems, the level of confusion over REST might be rising, not falling.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;I was certainly confused for a long time about what constitutes a RESTful system. Isn't anything that has a URL RESTful? Definitely not, as the presence of resource identifier is just one of several properties that make a system RESTful. Fielding has recently written &lt;/span&gt;&lt;/span&gt;&lt;a href="http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;this article&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt; listing the properties he sees as essential to a RESTful system. After working quite a bit on the &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.nextdb.net/wiki/en/REST"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;RESTful system for NextDB.net&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;, it seems that me that the principle of Hypermedia As The Engine Of Application State (HATEOAS), identified on the &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.ics.uci.edu/%7Efielding/pubs/dissertation/rest_arch_style.htm"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;original dissertation section 5.1.5&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;, might be the most important principle of all. Incidentally, of all the properties outlines in &lt;/span&gt;&lt;/span&gt;&lt;a href="http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;the recent article&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;, Fielding chose to title the article "REST APIs Must be Hypertext Driven". To my mind, that confirms my hunch that HATEOAS is perhaps the least understood principle of REST, and the principle in need of the most discussion and explanation.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;The essence of HATEOAS is that the client needs to understand as little as possible. In essence, this is quite similar to the experience a human requires when he browses a website. In order to move from one page to the next, we must be given links that we can navigate. This is our common experience on web pages. Consider an&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt; alternative, and less user friendly&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;, &amp;nbsp;scenario in which the home page simply consisted of a set of instructions (an API, if you will). One instruction might read "To view articles about sports, visit a URL consisting of "http://sitename/topics?name=topic-name" and replace topic-name with 'SPORTS'". You would be forced to manually construct the URL and enter it into the browser. The notion of such a website seems absurd, and yet it describes the scenario common to RPC or "fake REST" APIs in which the client is responsible for constructing the state-transition links rather than being handed a hypermedia document that provides the available state transitions.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;Quoting Fielding: &lt;/span&gt;&lt;/span&gt;&lt;i&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;"...all application state transitions must be driven by client selection of  server-provided choices that are present in the received representations  or implied by the user’s manipulation of those representations"&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;This is&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.infoq.com/articles/webber-rest-workflow"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;an interesting article that shows how non-HTML hypermedia can be used in keeping with HATEOAS&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;. However, I think there are excellent reasons why Plain Old HTML (POH) is the best hypermedia choice for use with RESTful systems:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;HTML was made for hypermedia (it has well known structures for encoding links)&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&amp;nbsp;Your mom knows what HTML is&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;By using POH for HATEOAS, your RESTful system's content can be indexed by search engines&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;You can easily view and traverse your system states using a web browser&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;POH for HATEOAS is the approach taken by &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.nextdb.net/wiki/en/REST"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;NextDB's REST&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&amp;nbsp;system. In the documentation, we do describe the explicit structure of several of the URL's, but we stick strongly to the principle outlined by Fielding that, beyond the entry point URL, or "bookmark" you shouldn't need to know the structure of any of the URLs. Using POH for HATEOAS, the proof of NextDBs' adherence to this principle is quite straightforward: I simply give you an entry point URL (a bookmark) to a table and allow you to navigate the links served in the POH. For example, here is the bookmark to an account named 'geoff' with a database named 'testchars' and a table named 'lines':&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;a class="externallink" href="http://nextdb.net/nextdb/rest/geoff/testchars/lines/" rel="nofollow" title="http://nextdb.net/nextdb/rest/geoff/testchars/lines/"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;http://nextdb.net/nextdb/rest/geoff/testchars/lines/&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;From the URL above you can click on links to visit various pages of the content and sort the content. No knowledge of an API is required. Taken to its logical conclusion, I see no reason why the RESTful service should not be allowed to directly present styled content, when the consumer of the content is human. So that is exactly what we do in NextDB, by allowing the POH to include CSS. Here is an example:&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://nextdb.net/nextdb/rest/geoff/testchars/lines/style/newspaper-a"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;http://nextdb.net/nextdb/rest/geoff/testchars/lines/style/newspaper-a&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;We're techically violating HATEOAS because we don't provide links to the styled content, rather the developer has to know about the available styles by reading our documentation. However, we'll soon correct this, as well as allowing the developer to pass in links to his own CSS for inclusion in the returned POH.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;Finally, not only do we allow you to style the POH, but we also allow you to apply XSLT transformations to the POH in order to alter the structure (as opposed to style) of the POH. Fielding discusses "Processing Elements" or "Transformers of Data" in his thesis. I believe XSLT to be the POH analog for processing elements, in that they are well understood, easily encapsulated in a markup, and supported by a wide array of processors (including browser-side processing, although this tends to be less portable, which is why NextDB opted to perform the transformation on the server).&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;In summary, NextDB is a truly RESTful database. This is important not because it conforms to a buzzword, but because it has made NextDB so easy to use that even non-programmers are able to embed the POH hypermedia in their sites. &lt;/span&gt;&lt;/span&gt;&lt;a href="http://projecthavehope.org/"&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;Project Have Hope&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt; is a great example of one such site. The "catalogs" of sponsorable children and women in Africa is POH served out of NextDB.net. &amp;nbsp;The HATEOAS architecture is the key to opening the database content to CMS engine-driven sites, as well as accessibility to web search engines.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;/span&gt;&lt;/div&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt; &lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS',sans-serif;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-132779247061012543?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/132779247061012543/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/02/hateoas-hypermedia-as-engine-of.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/132779247061012543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/132779247061012543'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/02/hateoas-hypermedia-as-engine-of.html' title='HATEOAS - Hypermedia As The Engine Of Application State'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-4277656130597239185</id><published>2010-02-15T10:37:00.000-08:00</published><updated>2010-11-27T19:27:59.530-08:00</updated><title type='text'>Spam Bucket</title><content type='html'>I'm curious to see how much spam accumulates in this database if I put a publicly &lt;a href="http://notskateboarding.blogspot.com/2010/02/spam-bucket.html"&gt;writable database table on my blog&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;UPDATE: I have the answer: "A LOT"&lt;br /&gt;"Salad Man", I commend you! "get three inches on your dick!" is a noble spam to leave on my blog, but I am dissapointed you did not include a video!!!&lt;br /&gt;&lt;br /&gt;&lt;iframe frameborder="0" height="500px" scrolling="auto" src="http://www.nextdb.net/nextdb/rest/geoff/vids/spam;%7Ecols=PK,file_CONTENT_TYPE/style/newspaper-a/pgsz/3/edit/true" width="800px"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-4277656130597239185?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/4277656130597239185/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/02/spam-bucket.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4277656130597239185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4277656130597239185'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/02/spam-bucket.html' title='Spam Bucket'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-2606313041506628244</id><published>2010-02-13T21:34:00.000-08:00</published><updated>2010-02-15T10:33:27.619-08:00</updated><title type='text'>NextDB REST tables</title><content type='html'>NextDB REST tables can be easily embedded anywhere on the web. For example:&lt;br /&gt;&amp;lt;iframe src='http://www.nextdb.net/nextdb/rest/geoff/vids/sk8;~cols=PK,video_CONTENT_TYPE,video_FID/style/newspaper-a/pgsz/3' /&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://www.nextdb.net/nextdb/rest/geoff/vids/sk8;~cols=PK,video_CONTENT_TYPE,video_FID/style/newspaper-a/pgsz/3" frameborder="0" scrolling="auto" width="700px" height="500px"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-2606313041506628244?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/2606313041506628244/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/02/nextdb-rest-tables.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2606313041506628244'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2606313041506628244'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/02/nextdb-rest-tables.html' title='NextDB REST tables'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-8132830228811815134</id><published>2010-02-12T21:52:00.000-08:00</published><updated>2010-02-12T21:52:13.998-08:00</updated><title type='text'>An update on JTIdy and XSLT</title><content type='html'>&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;A couple months back &lt;a href="http://notskateboarding.blogspot.com/2009/12/jtidy-and-handling-html-embedded-in.html"&gt;I blogged about JTidy&lt;/a&gt; I have an update to that story. If you plan to run your XHTML through an XSLT transformation, don't use tidy.setXHTML(true). The reason for this, I found after a lot of debugging. There are a "named entities", specifically ones such as &amp;amp;acirc; (and many others) that are declared in the XHTML DTD. And guess what? They are NOT valid in XML.&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt; Quick refresher: XML has only &lt;a href="http://en.wikipedia.org/wiki/List_of_XML_and_HTML_character_entity_references#Predefined_entities_in_XML"&gt;five named entities that it supports&lt;/a&gt;.&amp;nbsp;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;So you're thinking, no biggie, I don't think my documents will ever have a &amp;amp;acirc; named entity in them so what do I care? Well, they can creep in my accident, if you are allowing users to save inputs into a database. For example, there are ISO-8859-1 (Latin-1) characters with no UTF-8 equivalent. One that I have repeatedly seeen over the years from European users is the "left quote". It doesn't even exist on an american keyboard, and when it gets posted to a system expecting UTF-8 it wreaks havoc, causing a run of several incorrectly decoded characters. &lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;And so, you can get "inadvertant" named entities in your XHTML output due to this sort of character mangling where the UTF-8 byte stream interpretation gets &lt;a href="http://en.wikipedia.org/wiki/Robert_Bork"&gt;borked&lt;/a&gt;. So now, instead of just getting some gibberish in your XSLT, the entire transformation crashes, and you get no output at all except a complaint that the input document had an unsupported character reference. Hence the solution: tell jtidy NOT to produce XHTML, but instead to produce plain old XML, like this: tidy.setXmlOut(true); When you do this JTidy doesn't put these named entities in anymore.&amp;nbsp;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;One other surprise I ran into is that &lt;a href="http://www.w3.org/TR/REC-xml/#dt-charref"&gt;XML actually *DOES* support numeric character entities&lt;/a&gt;. So you will still get numeric character entities in the XML output such as &amp;amp;#128, which although &lt;a href="http://en.wikipedia.org/wiki/HTML_decimal_character_rendering"&gt;specifically forbidden by HTML&lt;/a&gt; still render properly in most browsers. So JTidy happily outputs these numeric character entities in its XML output. You are now safe to apply XSLT transformations on a valid XML input, however, just be aware that the XHTML output of your XSLT transformation is in violation of the aforementioned forbidden, but practically allowed, numeric entities.&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Confused yet? Me too. Let's all speak Esperanto and adopt 7-bit ASCII as the only allowed character set.&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-8132830228811815134?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/8132830228811815134/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/02/update-on-jtidy-and-xslt.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8132830228811815134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8132830228811815134'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/02/update-on-jtidy-and-xslt.html' title='An update on JTIdy and XSLT'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-6234170817635347443</id><published>2010-01-21T22:16:00.000-08:00</published><updated>2010-01-21T22:16:36.039-08:00</updated><title type='text'>Character Encoding Hell</title><content type='html'>&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Over the years, one of the perennial hassles that web services programmers grapple with, is undoubtedly character encoding. One of the biggest contributing factors to the problem goes all the way back to the fact that the original definition of URL-encoding failed to specify how to deal with UTF-8 or other non-ascii encodings outside the reserved character set. The &lt;a href="http://en.wikipedia.org/wiki/Percent-encoding#Current_standard"&gt;current spec&lt;/a&gt; states that if you want to send UTF-8 strings, for example "てすと&amp;nbsp;&amp;nbsp; (te-su-to) ", then you should percent encode each byte of the UTF-8 character sequence (%E3%81%A6).&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Two excellent pages for test data, should you need to test some multi-byte UTF-8 characters are:&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;a href="http://winrus.com/utf8-jap.htm"&gt;http://winrus.com/utf8-jap.htm&lt;/a&gt; and &lt;a href="http://winrus.com/codes.htm"&gt;http://winrus.com/codes.htm&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Sadly for AJAX applications, actually generating these percent encoded byte sequences is non-trivial, and doesn't seem to be readily available "off the shelf". I've had to resort to JS source such as &lt;a href="http://www.webtoolkit.info/javascript-url-decode-encode.html"&gt;this&lt;/a&gt;.Without such scripts, various attempts to use "off the shelf" JS methods produce wacky results, such as unicode representations of the strings (like \uXX\uXX) which is completely useless for transmission in a URL.&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;On the server, there are also problems in receiving and properly decoding the bytes. One of the biggest problems is that Java web servers don't do it in a standard way. For example, when I was working on Tomcat 5.x,&amp;nbsp; the Servlet getParameter method would assume ISO-8859-1 (Latin 1) encoding, which would garble any properly UTF-8 percent encoded bytes. There is a well hidden setting to switch the default to UTF-8.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;On the other hand, Jetty *does* assume the URL is UTF-8 percent encoded (love jetty!!). So without some config tweaks, don't expect servlet containers to *uniformly* deliver properly decoded UTF-8 strings.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;My latest installment of UTF-8 Hell comes as I implement some more REST capabilities for &lt;a href="http://nextdb.net/"&gt;Nextdb.net&lt;/a&gt;. Here is the content of a message I just posted to Paul Sandoz of Jersey fame (man, that guy must never sleep. he is *on the ball* on the Jersey mailing list). Mad props to Jersey. It is just killer. But I digress:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;i&gt;&lt;span style="font-size: x-small;"&gt;Hi Paul, &lt;br /&gt;&lt;br /&gt;I got to the bottom of this by trying to unmarshal the string in three different ways. As I already mentioned the first way was just to call FormDataBodyPart.getValue().&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="ii gt" id=":15f" style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;wbr&gt;&lt;/wbr&gt;&lt;i&gt;&lt;span style="font-size: x-small;"&gt;toString(). This produced the improperly decoded String. &lt;br /&gt;&lt;br /&gt;Then I tried two other ways, both of which correctly unmarshalled the bytes from the POST. As supporting information, here is the CURL line I was testing with, and an excerpt from the CURL trace, showing the proper bytes being posted. &lt;br /&gt;&lt;br /&gt;curl --trace traced -F line=てすと &lt;a href="http://localhost:8080/nextdb/rest/geoff/testchars/lines/rowid/PK/1" target="_blank"&gt;http://localhost:8080/nextdb/&lt;wbr&gt;&lt;/wbr&gt;rest/geoff/testchars/lines/&lt;wbr&gt;&lt;/wbr&gt;rowid/PK/1&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The 9 bytes highlighted below are the three japanese characters.&lt;br /&gt;&lt;br /&gt;=&amp;gt; Send data, 148 bytes (0x94)&lt;br /&gt;0000: 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d ----------------&lt;br /&gt;0010: 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 63 61 --------------ca&lt;br /&gt;0020: 33 32 31 65 31 30 39 66 36 37 0d 0a 43 6f 6e 74 321e109f67..Cont&lt;br /&gt;0030: 65 6e 74 2d 44 69 73 70 6f 73 69 74 69 6f 6e 3a ent-Disposition:&lt;br /&gt;0040: 20 66 6f 72 6d 2d 64 61 74 61 3b 20 6e 61 6d 65&amp;nbsp; form-data; name&lt;br /&gt;0050: 3d 22 6c 69 6e 65 22 0d 0a 0d 0a &lt;span style="background-color: yellow;"&gt;e3 81&lt;/span&gt; &lt;span style="background-color: yellow;"&gt;a6 e3 81&lt;/span&gt; ="line".........&lt;br /&gt;0060: &lt;span style="background-color: yellow;"&gt;99 e3 81 a8&lt;/span&gt; 0d 0a 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d ......----------&lt;br /&gt;0070: 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d 2d ----------------&lt;br /&gt;0080: 2d 2d 2d 2d 63 61 33 32 31 65 31 30 39 66 36 37 ----ca321e109f67&lt;br /&gt;0090: 2d 2d 0d 0a&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;Both of the following two methods will properly unmarshal the correct String:&lt;br /&gt;&lt;br /&gt;method 1: use InputStream to get raw bytes&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; InputStream is = theFormDataBodyPart. &lt;/span&gt;&lt;/i&gt;  &lt;wbr&gt;&lt;/wbr&gt;&lt;i&gt;&lt;span style="font-size: x-small;"&gt;getValueAs(InputStream.class);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; try {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; byte[] bytes = Util.readInputStream(is, 1024 * 1024, 1024 * 1024 * 1024);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; log.debug("this many bytes: " + bytes.length);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; for(byte b:bytes){&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; log.debug(Integer.toHexString(&lt;/span&gt;&lt;/i&gt;&lt;wbr&gt;&lt;/wbr&gt;&lt;i&gt;&lt;span style="font-size: x-small;"&gt;0x00FF&amp;amp;b));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; String s = new String(bytes, "UTF-8");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; log.debug(s);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return s;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; } catch (IOException ex) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new RuntimeException(ex.&lt;/span&gt;&lt;/i&gt;&lt;wbr&gt;&lt;/wbr&gt;&lt;i&gt;&lt;span style="font-size: x-small;"&gt;getMessage(), ex);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&amp;nbsp; &lt;br /&gt;&lt;br /&gt;Method 2) use theFormDataBodyPart.&lt;/span&gt;&lt;/i&gt;&lt;wbr&gt;&lt;/wbr&gt;&lt;i&gt;&lt;span style="font-size: x-small;"&gt;getValueAs(String.class)&lt;br /&gt;&lt;br /&gt;Cheers,&lt;br /&gt;geoff&lt;/span&gt;&lt;/i&gt; &lt;/div&gt;&lt;div style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-6234170817635347443?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/6234170817635347443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/01/character-encoding-hell.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6234170817635347443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6234170817635347443'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/01/character-encoding-hell.html' title='Character Encoding Hell'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-1811248599279579420</id><published>2010-01-04T21:07:00.001-08:00</published><updated>2010-01-04T21:07:41.433-08:00</updated><title type='text'>Well said....</title><content type='html'>&lt;span style="color: black; font-family: 'Comic Sans MS'; font-size: 13.5pt;"&gt;The        exchange between Churchill &amp;amp; Lady Astor: She said, "If you were my        husband I'd give you poison." He said, "If you were my wife, I'd drink        it."&lt;br /&gt;&lt;br /&gt;A member of Parliament to Disraeli: "Sir, you will        either die on the gallows or of some unspeakable disease." "That depends,        Sir," said Disraeli, "whether I embrace your policies or your        mistress."&lt;br /&gt;&lt;br /&gt;"He had delusions of adequacy." - &lt;span class="yshortcuts" id="lw_1262667951_14"&gt;Walter        Kerr&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"He has all the virtues I dislike and none of the vices        I admire." - &lt;span class="yshortcuts" id="lw_1262667951_15" style="border-bottom: 1px dashed rgb(0, 102, 204); cursor: pointer;"&gt;Winston Churchill&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: navy; font-family: 'Comic Sans MS'; font-size: 13.5pt;"&gt;        &lt;br /&gt;&lt;/span&gt;&lt;span style="color: black; font-family: 'Comic Sans MS'; font-size: 13.5pt;"&gt;&lt;br /&gt;"I        have never killed a man, but I have read many obituaries with great        pleasure." &lt;span class="yshortcuts" id="lw_1262667951_16"&gt;Clarence Darrow&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"He has never been known to use a        word that might send a reader to the dictionary." - &lt;span class="yshortcuts" id="lw_1262667951_17"&gt;William Faulkner&lt;/span&gt;        (about &lt;span class="yshortcuts" id="lw_1262667951_18" style="-moz-background-clip: border; -moz-background-inline-policy: continuous; -moz-background-origin: padding; background: transparent none repeat scroll 0% 0%; cursor: pointer;"&gt;Ernest Hemingway&lt;/span&gt;).&amp;nbsp;&lt;/span&gt;&lt;span style="color: navy; font-family: 'Comic Sans MS'; font-size: 13.5pt;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: black; font-family: 'Comic Sans MS'; font-size: 13.5pt;"&gt;&lt;br /&gt;"Thank        you for sending me a copy of your book; I'll waste no time reading it." -        &lt;span class="yshortcuts" id="lw_1262667951_19" style="border-bottom: 1px dashed rgb(0, 102, 204); cursor: pointer;"&gt;Moses Hadas&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"I didn't attend the funeral, but I sent a nice        letter saying I approved of it." - &lt;span class="yshortcuts" id="lw_1262667951_20"&gt;Mark Twain&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"He has no        enemies, but is intensely disliked by his friends." - &lt;span class="yshortcuts" id="lw_1262667951_21"&gt;Oscar        Wilde&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"I am enclosing two tickets to the first night of my        new play; bring a friend.... if you have one." - &lt;span class="yshortcuts" id="lw_1262667951_22"&gt;George Bernard Shaw&lt;/span&gt; to        Winston Churchill&lt;br /&gt;&lt;br /&gt;"Cannot possibly attend first night, will attend        second... if there is one." - Winston Churchill, in        response.&lt;br /&gt;&lt;br /&gt;"I feel so miserable without you; it's almost like        having you here." - Stephen Bishop&lt;br /&gt;&lt;br /&gt;"He is a &lt;span class="yshortcuts" id="lw_1262667951_23" style="-moz-background-clip: border; -moz-background-inline-policy: continuous; -moz-background-origin: padding; background: transparent none repeat scroll 0% 0%; cursor: pointer;"&gt;self-made man&lt;/span&gt; and        worships his creator." - &lt;span class="yshortcuts" id="lw_1262667951_24"&gt;John Bright&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"I've just learned about        his illness. Let's hope it's nothing trivial." - &lt;span class="yshortcuts" id="lw_1262667951_25"&gt;Irvin S.        Cobb&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"He is not only dull himself; he is the cause of        dullness in others." - &lt;span class="yshortcuts" id="lw_1262667951_26" style="border-bottom: 1px dashed rgb(0, 102, 204); cursor: pointer;"&gt;Samuel Johnson&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"He is simply a shiver        looking for a spine to run up." - &lt;span class="yshortcuts" id="lw_1262667951_27"&gt;Paul Keating&lt;/span&gt;&amp;nbsp;&lt;/span&gt;&lt;span style="color: navy; font-family: 'Comic Sans MS'; font-size: 13.5pt;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: black; font-family: 'Comic Sans MS'; font-size: 13.5pt;"&gt;&lt;br /&gt;"In        order to avoid being called a flirt, she always yielded easily." -        &lt;span class="yshortcuts" id="lw_1262667951_28"&gt;Charles&lt;/span&gt;, Count Talleyrand&lt;br /&gt;&lt;br /&gt;"He loves nature in spite of what it did        to him." - &lt;span class="yshortcuts" id="lw_1262667951_29"&gt;Forrest Tucker&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"Why do you sit there looking like        an envelope without any address on it?" - Mark Twain&lt;br /&gt;&lt;br /&gt;"His        mother should have thrown him away and kept the stork." - &lt;span class="yshortcuts" id="lw_1262667951_30" style="border-bottom: 1px dashed rgb(0, 102, 204); cursor: pointer;"&gt;Mae        West&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"Some cause happiness wherever they go; others, whenever they        go." - &lt;span class="yshortcuts" id="lw_1262667951_31" style="border-bottom: 1px dashed rgb(0, 102, 204); cursor: pointer;"&gt;Oscar Wilde&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"He uses statistics as a drunken man uses        lamp-posts... for support rather than illumination." - &lt;span class="yshortcuts" id="lw_1262667951_32" style="border-bottom: 1px dashed rgb(0, 102, 204); cursor: pointer;"&gt;Andrew Lang&lt;/span&gt;        (1844-1912)&lt;br /&gt;&lt;br /&gt;"He has Van Gogh's ear for music." - &lt;span class="yshortcuts" id="lw_1262667951_33"&gt;Billy        Wilder&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"I've had a perfectly wonderful evening. But this        wasn't it." - &lt;span class="yshortcuts" id="lw_1262667951_34"&gt;Groucho Marx&lt;/span&gt;&lt;/span&gt;&lt;span style="color: black;"&gt;        &lt;/span&gt;  &lt;br /&gt;&lt;div class="MsoNormal"&gt;&lt;span style="color: black; font-family: 'Impact','sans-serif'; font-size: 10pt;"&gt; &amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: Times-New-Roman; font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-1811248599279579420?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/1811248599279579420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2010/01/well-said.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1811248599279579420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1811248599279579420'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2010/01/well-said.html' title='Well said....'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-4012990100193132152</id><published>2009-12-16T23:18:00.000-08:00</published><updated>2010-02-15T10:55:28.231-08:00</updated><title type='text'>JavaOneRadio interview 2009</title><content type='html'>&lt;span style="font-family: &amp;quot;Trebuchet MS&amp;quot;,sans-serif;"&gt;Was just going through some photos from earlier this year. Here's a shot of the interview I did on JavaOneRadio about location based services and my work at deCarta.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_iJr6rK5UOFc/SynaMTHrwYI/AAAAAAAAAMM/k_cs9nv0R4M/s1600-h/javaoneradio.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_iJr6rK5UOFc/SynaMTHrwYI/AAAAAAAAAMM/k_cs9nv0R4M/s320/javaoneradio.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;img border="0" height="0" src="http://counters.gigya.com/wildfire/IMP/CXNID=2000002.0NXC/bT*xJmx*PTEyNjEwMzM1NzI*MTQmcHQ9MTI2MTAzMzU4MDAxNCZwPTQ1MDk3MiZkPSZnPTImbz1lMWNiY2QzNmExNzk*ZGRmOTlmMDUwNTE4MzlmYjdiMCZvZj*w.gif" style="height: 0px; visibility: hidden; width: 0px;" width="0" /&gt;&lt;embed allowscriptaccess="always" height="108" menu="false" pluginspage="http://www.adobe.com/go/getflashplayer" quality="high" src="http://www.blogtalkradio.com/BTRPlayer.swf?file=http%3A%2F%2Fwww%2Eblogtalkradio%2Ecom%2Fplaylist%2Easpx%3Fshow%5Fid%3D555834&amp;amp;autostart=false&amp;amp;bufferlength=5&amp;amp;volume=88.8888888888889&amp;amp;borderweight=1&amp;amp;bordercolor=#999999&amp;amp;backgroundcolor=#FFFFFF&amp;amp;dashboardcolor=#0098CB&amp;amp;textcolor=#FFFFFF&amp;amp;detailscolor=#FFFFFF&amp;amp;playlistcolor=#999999&amp;amp;playlisthovercolor=#333333&amp;amp;cornerradius=10&amp;amp;callback=http://www.blogtalkradio.com/FlashPlayerCallback.aspx?referrer_url=/show.aspx&amp;amp;C1=7&amp;amp;C2=6042973&amp;amp;C3=31&amp;amp;C4=&amp;amp;C5=&amp;amp;C6=" type="application/x-shockwave-flash" width="210" wmode="transparent"&gt;&lt;/embed&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-4012990100193132152?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/4012990100193132152/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/12/javaoneradio-interview-2009.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4012990100193132152'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4012990100193132152'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/12/javaoneradio-interview-2009.html' title='JavaOneRadio interview 2009'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_iJr6rK5UOFc/SynaMTHrwYI/AAAAAAAAAMM/k_cs9nv0R4M/s72-c/javaoneradio.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-7706845196883374389</id><published>2009-12-13T18:52:00.001-08:00</published><updated>2009-12-13T18:52:55.586-08:00</updated><title type='text'>Nerds!</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://nerdarama.com/wp-content/uploads/2009/02/ogre.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://nerdarama.com/wp-content/uploads/2009/02/ogre.jpg" width="320" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-7706845196883374389?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/7706845196883374389/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/12/nerds.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7706845196883374389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7706845196883374389'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/12/nerds.html' title='Nerds!'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-2776915274864967602</id><published>2009-12-12T22:31:00.000-08:00</published><updated>2009-12-12T22:51:24.532-08:00</updated><title type='text'>a==1 or 1==a</title><content type='html'>&lt;span style="font-family: trebuchet ms;"&gt;I was in one of &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://www.pdl.cmu.edu/People/bassoon.shtml"&gt;Dave Nagle's&lt;/a&gt;&lt;span style="font-family: trebuchet ms;"&gt; lectures at Carnegie Mellon in which he explained that he'd once spent an inordinate amount of time on a bug hunt. The cause: 'a=1' ... a typo. He meant to type 'a==1'. To insure he'd never suffer that pain again, he coded all his boolean comparisons with the literal on the left hand side, like this: '1==a'. This prevents the typo '1=a' because the compiler won't allow an assignment to a literal.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;After going on the exact same bug hunt myself, many years ago,  I kicked myself for not following his advice. I've coded all my Boolean expressions in the "literal on the left" style ever since, and the compiler has saved me many a bug hunt.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;To that paradigm I now have a small addition to make. I've started coding my string equals comparisons in literal-left style as follows: "something".equals(a)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;This has the nice effect warding off null pointer exceptions when a is null. I think this literal left style is better than (a+"").equals("something") which is another trick for warding off null values of a.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-2776915274864967602?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/2776915274864967602/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/12/a1-or-1a.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2776915274864967602'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2776915274864967602'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/12/a1-or-1a.html' title='a==1 or 1==a'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-3453457148097647497</id><published>2009-12-11T17:37:00.000-08:00</published><updated>2009-12-11T17:38:38.743-08:00</updated><title type='text'>Keep the hot air flowing</title><content type='html'>&lt;a style="font-family: trebuchet ms;" href="http://www.npr.org/templates/story/story.php?storyId=121353033"&gt;This is a funny satire &lt;/a&gt;&lt;span style="font-family: trebuchet ms;"&gt;of the climate change talks..."now powered exclusively by wind".&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-3453457148097647497?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/3453457148097647497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/12/keep-hot-air-flowing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3453457148097647497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3453457148097647497'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/12/keep-hot-air-flowing.html' title='Keep the hot air flowing'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-3766092412975571076</id><published>2009-12-05T22:21:00.000-08:00</published><updated>2009-12-05T22:25:06.003-08:00</updated><title type='text'>Keep it on the DL</title><content type='html'>&lt;span style="font-family: trebuchet ms;"&gt;I came across what has got to be the most rarely used HTML element. Ever heard of &amp;lt;dl&amp;gt;? me neither. Stands for "Definition List". Inside a DL you put Definition Terms (DT) and inside a DT you put a Definition Description (DD). It actually is a very handy way to markup key/value pairs, such as "firstname: bob" or "Age:34". So if you've got some kind of Object and you want to markup its fields, give the DL a try.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-3766092412975571076?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/3766092412975571076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/12/keep-it-on-dl.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3766092412975571076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3766092412975571076'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/12/keep-it-on-dl.html' title='Keep it on the DL'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-4783726252742395186</id><published>2009-12-03T23:35:00.000-08:00</published><updated>2009-12-04T00:05:54.771-08:00</updated><title type='text'>JTidy and handling HTML embedded in database strings</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;I've been dealing with an interesting issue. A customer's app needs to store documents created by end users. The document's are really just paragraphs created by the end user, using the &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://developer.yahoo.com/yui/editor/"&gt;YUI Rich Text/HTML editor&lt;/a&gt;&lt;span style="font-family:trebuchet ms;"&gt;. The user might also use the "plain text" editing mode, in which case they would actually enter tags like &amp;lt; h1&amp;gt; manually. With this freedom comes the inevitable possibility that they will enter invalid HTML. Since these documents will be stored in &lt;a style="font-family: trebuchet ms;" href="http://www.blogger.com/nextdb.net"&gt;NextDB&lt;/a&gt; the user might also apply an XSLT transformation over the &lt;a style="font-family: trebuchet ms;" href="http://nextdb.net/nextdb/rest/home/geoff/db/testchars/tbl/lines/"&gt;default HTML presentation&lt;/a&gt;&lt;span style="font-family:trebuchet ms;"&gt; of the result set.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;The problem is that if the user enters invalid XHTML, like they just throw &amp;lt;blort&amp;rt; into their document, then the XSLT will crash. The problem is made gnarlier by the fact that the documents themselves are likely to be fragments (and in fact they &lt;/span&gt;&lt;span style="font-weight: bold;font-family:trebuchet ms;" &gt;have&lt;span style="font-weight: bold;"&gt; to be &lt;/span&gt;&lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;fragments so that when they appear in the context of the &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://nextdb.net/nextdb/rest/home/geoff/db/testchars/tbl/lines/"&gt;default HTML presentation&lt;/a&gt;&lt;span style="font-family:trebuchet ms;"&gt; that they get treated as a valid portion of the overall document). In other words, if the user puts  tags around their document, you have to strip those body tags off, so that the &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://nextdb.net/nextdb/rest/home/geoff/db/testchars/tbl/lines/"&gt;default HTML presentation&lt;/a&gt;&lt;span style="font-family:trebuchet ms;"&gt; doesn't have a nested body.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;Enter&lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://jtidy.sourceforge.net/"&gt; JTidy&lt;/a&gt;&lt;span style="font-family:trebuchet ms;"&gt;. The JTidy library is all about handling crapped-up HTML, and fixing it on the fly. The journey to getting JTidy working was longer than I expected due to an unpleasant interaction with Maven. So, despite the fact that I had the most recent version of JTidy on my Netbeans's project's classpath, when I used Maven to startup Jetty using the mvn Jetty plugin, I would get runtime errors complaining that the method I was trying to call (tidy.setPrintBodyOnly(true);) didn't exist.  So, like any good bughunt, the fub began. I knew that Tidy.class was somehow sneaking into my runtime classpath. The first place I looked was my local .m2 repository -- no joy. Finally occured to me that this must be an internal inclusion of an old Tidy jar by maven.  When I ran 'grep -r Tidy.class' on my maven directory, I found that maven's 'uber jar' (maven-core-2.0.7-uber.jar) did in fact contain the older version of JTidy. Turns out if you look at the &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://maven.apache.org/ant-tasks/dependencies.html"&gt;internal dependencies for Maven&lt;/a&gt;&lt;span style="font-family:trebuchet ms;"&gt;, you find that it depends on an old version of JTidy. So I unzipped the uber-jar, replaced all the JTidy classes with the latest and greatest, rezipped the jar, and ...badabing badaboom...problem solved. Bing bang boom, very good have a drink.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:trebuchet ms;"&gt;The actual coding took less than 2 minutes. Argghh talk about an 80/20 rule. Anyhow, JTidy does exactly what I want. Fix any crufted HTML that the user might enter, and then extract only the content of the body element (and even better, if the user doesn't include a body, JTidy fixes that first). So it all boils down to this (just to print the tidied content):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            Tidy tidy = new Tidy();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            tidy.setXHTML(true);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            tidy.setPrintBodyOnly(true);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            tidy.parse(new ByteArrayInputStream((val+"").toString().getBytes()), System.out);&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;font-size:100%;" &gt; Epilogue: maybe blogger.com should start using Jquery. Ironically, this rich text editor threw up on some tags I typed into this post, and I had to spend a few minutes cleaning up the mess!!!&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-4783726252742395186?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/4783726252742395186/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/12/jtidy-and-handling-html-embedded-in.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4783726252742395186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4783726252742395186'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/12/jtidy-and-handling-html-embedded-in.html' title='JTidy and handling HTML embedded in database strings'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-1279829084217158697</id><published>2009-11-26T10:06:00.000-08:00</published><updated>2009-11-26T10:08:56.498-08:00</updated><title type='text'>Good news on C02 Emissions</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://t0.gstatic.com/images?q=tbn:7KLwcTfUqreAsM:http://mybookofrai.typepad.com/my_weblog/images/turkey.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 124px; height: 114px;" src="http://t0.gstatic.com/images?q=tbn:7KLwcTfUqreAsM:http://mybookofrai.typepad.com/my_weblog/images/turkey.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Obama's announcement, combined with &lt;a href="http://en.cop15.dk/news/view+news?newsid=2717"&gt;China's recent pledge&lt;/a&gt;, is the first good news I've heard on climate change -- ever! Happy Thanksgiving!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-1279829084217158697?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/1279829084217158697/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/good-news-on-c02-emissions.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1279829084217158697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1279829084217158697'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/good-news-on-c02-emissions.html' title='Good news on C02 Emissions'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-2589443075873550382</id><published>2009-11-25T08:15:00.000-08:00</published><updated>2009-11-25T08:44:53.192-08:00</updated><title type='text'>Viterbi Maximum Liklihood Decoding</title><content type='html'>&lt;span style="font-family: trebuchet ms;"&gt;Last night I was following up on a hunch that the Viterbi Maximum Liklihood Decoding algorithm could have application for spell checking. I remembered this algorithm from &lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://www.ece.cmu.edu/courses/18450"&gt;a class I took at Carnegie Mellon called Digital Communications&lt;/a&gt;&lt;span style="font-family: trebuchet ms;"&gt;. I went back to the &lt;a href="http://www.amazon.com/Digital-Communications-Fundamentals-Applications-2nd/dp/0130847887"&gt;course book&lt;/a&gt;, and started reviewing the matter. I hadn't remembered this course book as standing out from others, but now I can really appreciate how well written it is. It has very clear treatment of the subject matter with well broken-out examples, that build throughout the topic. Sklar is a great writer, and he clearly loves the subject matter. I like his pithy conclusions at the end of each chapter. He has a flair for understatement:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-family: trebuchet ms;"&gt;"In the last decade, coding emphasis has been in the area of convolutional codes since in almost every application, convolutional codes outperform block codes for the same implementation complexity of the encoded-decoder. For satellite communications channels, forward error correction techniques can easily reduce the required SNR for specified error performance by 5 to 6dB. This coding gain can translated directly into an equivalent reduction in required satellite effective radiated power (EIRP), which consequently reduced satellite weight and cost."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;After reviewing the Viterbi algorithm, I was curious about who this V&lt;/span&gt;&lt;a style="font-family: trebuchet ms;" href="http://www.frommittoqualcomm.com/Viterbi/index.html"&gt;iterbi guy&lt;/a&gt;&lt;span style="font-family: trebuchet ms;"&gt; was, anway. I'd also seen a chart in the Sklar book, attributed to the "Linkabit" corporation. Turns out Viterbi founded Linkabit, then later Qualcomm, an eventually donated $50 million to USC where the Viterbi school of engineering bears his name. Interesting story. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;Oh, and it turns out the Viterbi algorithm does have applications to spell checking.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-2589443075873550382?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/2589443075873550382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/viterbi-maximum-liklihood-decoding.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2589443075873550382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2589443075873550382'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/viterbi-maximum-liklihood-decoding.html' title='Viterbi Maximum Liklihood Decoding'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-8729113477538481681</id><published>2009-11-22T13:20:00.000-08:00</published><updated>2009-11-22T13:33:42.582-08:00</updated><title type='text'>Order-invariant Path Parameters with JSR-311 JAX-RS and Jersey</title><content type='html'>&lt;span style="font-family: trebuchet ms;"&gt;When defining web service resource URLs, you may find yourself in the situation in which you want path parameters to be viable in any order. For example, shouldn't these two URL's both be accaptable, and point to the same resource?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;.../person/&lt;span style="color: rgb(255, 153, 0);"&gt;firstname&lt;/span&gt;/geoff/&lt;span style="color: rgb(102, 0, 204);"&gt;lastname/&lt;/span&gt;hendrey&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;.../person/&lt;span style="color: rgb(102, 0, 204);"&gt;lastname&lt;/span&gt;/hendrey/&lt;span style="color: rgb(255, 153, 0);"&gt;firstname&lt;/span&gt;/geoff&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;I've found that the best way to do this is to creat a single resource class, in this case Person, and to define subresource locator methods for  "firstname/{firstname}" and "lastname/{lastname}". The trick is to return "this" in your subresource locator method, which affectively turns the subresource locators into a means to setting instance fields on the Person instance.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;So when we look in the "PersonResource" class, our subresource locator method for 'firstname' is:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;@Path("/person")&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;public class PersonResource{&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    private String firstname;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    private String lastname;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;&lt;span style="font-family: courier new;"&gt;    @Path("firstname/{firstn&lt;/span&gt;ame}") //subresource&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    public Person getSubResource(@PathParam("firstname") String fname){&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        this.firstname=fname; //set instance field on this resource&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;        return this;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;    @Path("lastname/{lastname}") //subresource&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: courier new;"&gt;    public Person getSubResource(@PathParam("lastname") String lname){&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: courier new;"&gt;        this.lastname=lname; //set instance field on this resource&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: courier new;"&gt;        return this;&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: courier new;"&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: trebuchet ms;"&gt;The locator method for lastname follows the same patter. And that's all there is to it! I have not found this pattern covered or described in any of the docs for Jersey, but I have found it indespensible.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-8729113477538481681?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/8729113477538481681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/order-invariant-path-parameters-with.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8729113477538481681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8729113477538481681'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/order-invariant-path-parameters-with.html' title='Order-invariant Path Parameters with JSR-311 JAX-RS and Jersey'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-5217041241512472141</id><published>2009-11-22T13:06:00.000-08:00</published><updated>2009-11-22T13:18:59.806-08:00</updated><title type='text'>Creating "alias" URLs for Jersey JAX-RS JSR-311 resources</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;In &lt;a href="http://nextdb.net/wiki/en/REST"&gt;NextDB.net REST&lt;/a&gt; we are supporting two syntaxes for accessing resources. Let's call it a "fully qualified" resource, and a "shortcut" to the resource. For example, to view a table with its fully qualified URL, you can enter a URL in the format:&lt;br /&gt;&lt;br /&gt;http://nextdb.net/nextdb/rest/home/{account}/db/{db}/tbl/{tbl}&lt;br /&gt;&lt;br /&gt;for example: &lt;a href="http://nextdb.net/nextdb/rest/home/geoff/db/testchars/tbl/lines"&gt;http://nextdb.net/nextdb/rest/home/geoff/db/testchars/tbl/lines&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The "shortcut" URL would be: &lt;/span&gt;&lt;span style="font-family:trebuchet ms;"&gt;http://nextdb.net/nextdb/rest/{account}/{db}/{tbl}&lt;br /&gt;&lt;br /&gt;for example &lt;a href="http://nextdb.net/nextdb/rest/geoff/testchars/lines"&gt;http://nextdb.net/nextdb/rest/geoff/testchars/lines&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There's a simple "trick" you can apply using JSR-311 to make your resource appear at two different URLs. First, start with your "fully qualified resource". For example, here is  snippet:&lt;br /&gt;&lt;br /&gt;@Path("/home/{account}/db/{db}/tbl/{tbl}")&lt;br /&gt;public class TableResource extends AbstractSelectableResource{&lt;br /&gt;    @PathParam("account") protected String account;&lt;br /&gt;    @PathParam("db") protected String db;&lt;br /&gt;    @PathParam("tbl") protected String table;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;Now, to make an "alias" or "shortcut" URL, just define a dummy class that extends the resource you want to make a shortcut to. The purpose of this class is simply to "mount" the resource on an additional URL. Be sure to include all the path parameters and their names must be identical.&lt;br /&gt;&lt;br /&gt;@Path("/{account}/{db}/{tbl}")&lt;br /&gt;public class ShortcutToTableResource extends TableResource{&lt;br /&gt; //this class is intentionally empty&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Now your resource will be available on both URLs!&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-5217041241512472141?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/5217041241512472141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/creating-alias-urls-for-jersey-jax-rs.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5217041241512472141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5217041241512472141'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/creating-alias-urls-for-jersey-jax-rs.html' title='Creating &quot;alias&quot; URLs for Jersey JAX-RS JSR-311 resources'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-5521885612896073208</id><published>2009-11-11T22:43:00.001-08:00</published><updated>2009-11-11T22:45:32.413-08:00</updated><title type='text'>Jamwiki</title><content type='html'>&lt;span style="font-family: trebuchet ms;"&gt;A few weeks ago I installed JamWiki to document the new NextDB REST features:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a style="font-family: trebuchet ms;" href="http://www.nextdb.net/wiki/en/REST"&gt;http://www.nextdb.net/wiki/en/REST&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;I wasted a lot of time on XWiki, which basically was bloated, didn't work well, and basically produces a constant stream of stack traces. JamWiki works really well, it's nice and clean.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-5521885612896073208?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/5521885612896073208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/jamwiki.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5521885612896073208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5521885612896073208'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/jamwiki.html' title='Jamwiki'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-2306777695214736054</id><published>2009-11-08T09:46:00.000-08:00</published><updated>2009-11-08T09:50:56.570-08:00</updated><title type='text'>New ideas for REST in NextDB.net</title><content type='html'>&lt;span style="font-family: trebuchet ms;"&gt;I've got some more stuff to work on with regard to REST. Here's a&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;peek:&lt;/span&gt;&lt;br /&gt;&lt;p style="font-family: trebuchet ms;"&gt;support for relationships in REST URLs (calling them 'links')&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: courier new; font-weight: bold;"&gt;...account/db/link/FRIENDSHIP/from/uname/john/to/uname/tom&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: trebuchet ms;"&gt;The path parameters "from" and "to" describe the tail and the head of&lt;br /&gt;the relationship, respectively. In other words, we can draw a&lt;br /&gt;relationship as an arrow from one table to another table. This makes&lt;br /&gt;'from' and 'to' the natural path parameters.&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: trebuchet ms;"&gt;The REST URL above is equivalent to:&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: courier new; font-weight: bold; color: rgb(51, 102, 255);"&gt;NAME=FIND_FRIEND;&lt;br /&gt;ROW f1 FROM FRIEND;&lt;br /&gt;ROW f2 FROM FRIEND;&lt;br /&gt;f1 RELATED f2 VIA FRIENDSHIP;&lt;br /&gt;WHERE(){&lt;br /&gt;  f1.uname='john' AND f2.uname='tom'&lt;br /&gt;&lt;/p&gt;&lt;div id="qhide_114013" style="display: block; font-family: trebuchet ms;" class="qt"&gt;&lt;span style="font-family: courier new; font-weight: bold; color: rgb(51, 102, 255);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: trebuchet ms;"&gt;In the REST URL, you don't have to specify any constraint on the 'to'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;side of the relationship. The following URL would retrieve *all* of&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;john's friends.&lt;/span&gt;&lt;br /&gt;&lt;p style="font-family: trebuchet ms;"&gt;&lt;span style="font-weight: bold; font-family: courier new;"&gt;..account/db/link/FRIENDSHIP/from/uname/john&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: trebuchet ms;"&gt;is equivalent to:&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: courier new; font-weight: bold; color: rgb(51, 51, 255);"&gt;NAME=FIND_FRIEND;&lt;br /&gt;ROW f1 FROM FRIEND;&lt;br /&gt;ROW f2 FROM FRIEND;&lt;br /&gt;f1 RELATED f2 VIA FRIENDSHIP;&lt;br /&gt;WHERE(TEXT name1){&lt;br /&gt;  f1.uname=${name1}&lt;br /&gt;&lt;/p&gt;&lt;div id="qhide_114014" style="display: block; font-family: trebuchet ms;" class="qt"&gt;&lt;span style="font-family: courier new; font-weight: bold; color: rgb(51, 51, 255);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: trebuchet ms;"&gt;You'll also be able to execute your named queries directly via rest:&lt;/span&gt;&lt;br /&gt;&lt;p style="font-family: trebuchet ms;"&gt;&lt;span style="font-family: courier new; font-weight: bold;"&gt;.../account/db/query/FIND_FRIEND/name1/john&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: trebuchet ms;"&gt;So it all will play nicely with existing queries you have already&lt;br /&gt;defined, and new ones you may define in the future.&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: trebuchet ms;"&gt;I also intend to support cookies. So let's say you wanted to log a&lt;br /&gt;user in via https, and then securely transmit his password with each&lt;br /&gt;subsequent REST URL using regular HTTP (not https). First the user&lt;br /&gt;logs in via a secure (httpS) rest access to a query you named LOGIN.&lt;br /&gt;So the password below would not be in the clear, since the form on the&lt;br /&gt;HTML page would GET to an HTTPS url. The URL is constructed&lt;br /&gt;dynamically by the form on submission:&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: trebuchet ms;"&gt;&lt;a style="font-family: courier new; font-weight: bold;" target="_blank" rel="nofollow" href="https://nextdb.net/...db/query/LOGIN/uname/geoff/pwd/xxxxxxx;set-cookie"&gt;https://nextdb.net/...db/query/LOGIN/uname/geoff/pwd/xxxxxxx;set-cookie&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: trebuchet ms;"&gt;the 'set-cookie' matrix parameter tells nextdb to return a set-cookie&lt;br /&gt;HTTP header with a value equal to cypher('xxxxxxxx'). I.e., nextdb&lt;br /&gt;will encrypt the value that was sent in your request's REST URL,&lt;br /&gt;wherever it finds ;set-cookie, and tell the browser to pass a cookie&lt;br /&gt;named 'pwd' (in this example) with a value that is the encrypted&lt;br /&gt;version of whatever is in the REST URL for the password in the pwd/&lt;br /&gt;{password} path parameter. The set-cookie matrix parameter can occur&lt;br /&gt;at any path segment in the URL, and would be applied to whatever path&lt;br /&gt;parameter is described by the path segment.&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: trebuchet ms;"&gt;from that point on you can use regular rest URLs and nextdb will&lt;br /&gt;substitute into your URL the encrypted cookie value. So you can use&lt;br /&gt;URL's like this in your application, for later actions that require a&lt;br /&gt;user's password:&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: trebuchet ms;"&gt;&lt;span style="font-family: courier new; font-weight: bold;"&gt;.../db/link/ACCOUNT_DETAILS/from/pwd/;get-cookie&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: trebuchet ms;"&gt;The get-cookie matrix parameter int the URL allows an HTML page to be&lt;br /&gt;designed with static URLs, into which nextdb will dynamically&lt;br /&gt;substitute the URL path parameters with values sent by the browser as&lt;br /&gt;cookies. It's a bit of a mind bender but this allows a site be&lt;br /&gt;designed with static URLs. The only dynamic URL ever generated by the&lt;br /&gt;app is the single login query that sets the pwd/{password} path&lt;br /&gt;parameter.&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: trebuchet ms;"&gt;so when nextdb receives the static URL above, it will first see that&lt;br /&gt;the URL incudes a get-cookie matric paramter. NextDB will then look&lt;br /&gt;for a cookie named 'pwd' sent by the browser (or other http client),&lt;br /&gt;decrypt the cookie value, and place the value into the URL where it&lt;br /&gt;finds the get-cookie matrix parameter:&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: trebuchet ms;"&gt;&lt;span style="font-family: courier new; font-weight: bold;"&gt;.../db/link/ACCOUNT_DETAILS/from/pwd/xxxxxxxx/&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: trebuchet ms;"&gt;The URL above is then equivalent to this NextQuery expression:&lt;br /&gt;&lt;/p&gt;&lt;p style="font-family: courier new; font-weight: bold; color: rgb(51, 51, 255);"&gt;NAME=ACCOUNT_DETAILS;&lt;br /&gt;ROW r1 FROM USER;&lt;br /&gt;ROW r2 FROM ACCOUNT;&lt;br /&gt;r1 RELATED r2 VIA MY_ACCOUNT;&lt;br /&gt;WHERE(){&lt;br /&gt;  r1.pwd='xxxxxxxx'&lt;br /&gt;&lt;/p&gt;&lt;span style="font-family: courier new; font-weight: bold; color: rgb(51, 51, 255);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: trebuchet ms;"&gt;The net effect of this new style of REST url for queries and relationship traversal is to vastly reduce the amount of code an applicaiton has to write, and hopefully to make nextdb accessible to HTML/front-end developers.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-2306777695214736054?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/2306777695214736054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/new-ideas-for-rest-in-nextdbnet.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2306777695214736054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2306777695214736054'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/new-ideas-for-rest-in-nextdbnet.html' title='New ideas for REST in NextDB.net'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-6525080291574701940</id><published>2009-11-08T09:32:00.000-08:00</published><updated>2009-11-08T09:45:12.170-08:00</updated><title type='text'>Native REST support in NextDB.net</title><content type='html'>I'm really stoked on using REST to access NextDB.net. I've setup a Wiki for NextDB.net and here is our REST wiki page: &lt;a href="http://www.nextdb.net/wiki/en/REST"&gt;http://www.nextdb.net/wiki/en/REST&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Beeing down with a bad cold the last few days, ironically this has given me&lt;br /&gt;some time to work with Jen from Dartmouth Design on using the REST features&lt;br /&gt;to build some features for Project Have Hope. She has graciously offered to&lt;br /&gt;share the preliminary results. So far we've used nextdb for creating&lt;br /&gt;profiles of children to sponsor. The entire page, including the paging&lt;br /&gt;links, profile data, and paypal buttons, is created by applying an XSLT&lt;br /&gt;transformation to the table served up by nextdb. The result is sourced in an&lt;br /&gt;iframe and loaded into a Joomla module. This appears to be a very nice way&lt;br /&gt;to integrate nextdb content with Joomla. I'm also very stoked to see NextDB&lt;br /&gt;used on such a worthy project.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_iJr6rK5UOFc/SvcDOkA5d4I/AAAAAAAAAME/Av3y2D3qq7c/s1600-h/Picture+2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 241px;" src="http://1.bp.blogspot.com/_iJr6rK5UOFc/SvcDOkA5d4I/AAAAAAAAAME/Av3y2D3qq7c/s400/Picture+2.png" alt="" id="BLOGGER_PHOTO_ID_5401789826774693762" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Here is the live integration site (if this is down it's just because the site has moved from integration staging to the live environment):&lt;br /&gt;&lt;br /&gt;&lt;a href="http://projecthavehope.org/sandbox/index.php?option=com_content&amp;amp;view=article&amp;amp;id=105&amp;amp;Itemid=99"&gt;Check it out&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;You can read about the XSLT approach here:&lt;br /&gt;&lt;a href="http://www.nextdb.net/wiki/en/REST#XSLT_%28reformatting_your_data%27s_presentation"&gt;&lt;br /&gt;http://www.nextdb.net/wiki/en/REST#XSLT_(reformatting_your_data%27s_presentation&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This is the XSLT that is being used by Project Have Hope.&lt;br /&gt;&lt;a href="http://nextdb.net/nextdb/rest/dd/phh/config_files/row/1/xslt.xslt"&gt;http://nextdb.net/nextdb/rest/dd/phh/config_files/row/1/xslt.xslt&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I've just learned XSLT so I think there are many things that can be done&lt;br /&gt;smarter, and there is also a bit of cruft template in the XSLT that is never&lt;br /&gt;used (for example the 'append-pad' template is never used) and needs to be&lt;br /&gt;cleaned up. But that aside, it's an amazingly small amount of XSLT&lt;br /&gt;considering this XSLT is the *only* code required to bring together this&lt;br /&gt;dynamic page.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-6525080291574701940?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/6525080291574701940/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/native-rest-support-in-nextdbnet.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6525080291574701940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6525080291574701940'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/11/native-rest-support-in-nextdbnet.html' title='Native REST support in NextDB.net'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_iJr6rK5UOFc/SvcDOkA5d4I/AAAAAAAAAME/Av3y2D3qq7c/s72-c/Picture+2.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-8908542081923796700</id><published>2009-08-03T23:28:00.000-07:00</published><updated>2009-08-03T23:47:23.006-07:00</updated><title type='text'>Three Views of REST resources</title><content type='html'>&lt;span style="font-family:trebuchet ms;"&gt;whew. Just hacked most of the day away learning how to make a custom JAX-RS provider to generate an HTML view of a resource using an XSLT transformation on the XML.&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@Provider&lt;br /&gt;@Produces(MediaType.TEXT_HTML)&lt;br /&gt;public class UsersProvider  implements MessageBodyWriter&lt;users&gt; {&lt;br /&gt;  @Override&lt;br /&gt;  public void writeTo(Users users, Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap&lt;string, object=""&gt; params, OutputStream os) throws IOException, WebApplicationException {&lt;br /&gt;      try {          &lt;br /&gt;          JAXBContext jc = new JSONJAXBContext(JSONConfiguration.natural().build(), new Class[]{users.getClass()});//JAXBContext.newInstance(users.getClass());&lt;br /&gt;          DOMResult xml = new DOMResult();&lt;br /&gt;          jc.createMarshaller().marshal(users, xml);&lt;br /&gt;          StreamSource styleSheet = new StreamSource(getClass().getResourceAsStream("/stylesheet/Users.xsl"));&lt;br /&gt;          Transformer transformer = TransformerFactory.newInstance().newTransformer(styleSheet);&lt;br /&gt;          transformer.transform(new DOMSource(xml.getNode()), new StreamResult(os));&lt;br /&gt;      }catch (Exception ex) {&lt;br /&gt;          throw new RuntimeException(ex.getMessage(), ex);&lt;br /&gt;      }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType) {&lt;br /&gt;     return (Users.class.isAssignableFrom(type) &amp;amp;&amp;amp; mediaType.isCompatible(MediaType.TEXT_HTML_TYPE));&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  @Override&lt;br /&gt;  public long getSize(Users arg0, Class arg1, Type arg2, Annotation[] arg3, MediaType arg4) {&lt;br /&gt;      return -1;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;/string,&gt;&lt;/users&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;In the end it's actually quite easy, but what threw me off was that JAX-RS has built-in support for the serialization of List&amp;lt;t&amp;gt; where T is a JAXB annotated class. The problem is that my custom provider, which applies a stylesheet to the XSL necessarily bypasses the built-in support for collections of JAXB annotated classes. Therefore, the method in my resource can't return a List&lt;user&gt;. Instead, I created the Users (note the plural "s") wrapper class, and JAXB annoted it. Note incredibly annoyingly named accessor method, "getUser". Unfortunately, this had to be named in the singular, due to a quirk of JAXB. Naming it "getUser" produces&lt;br /&gt;&amp;lt;users&amp;gt;&lt;br /&gt;&amp;lt;user&amp;gt;...&amp;lt;/user&amp;gt;&lt;br /&gt;&amp;lt;user&amp;gt;...&amp;lt;/user&amp;gt;&lt;br /&gt;&amp;lt;!-- etc --&amp;gt;&lt;br /&gt;&amp;lt;/users&amp;gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;versus naming the accessor method in the plural produces (note redundant plural users):&lt;br /&gt;&amp;lt;users&amp;gt;&lt;br /&gt;&amp;lt;user&amp;sgt;...&amp;lt;/users&amp;gt;&lt;br /&gt;&amp;lt;users&amp;gt;...&amp;lt;/users&amp;gt;&lt;br /&gt;&amp;lt;!-- etc --&amp;gt;&lt;br /&gt;&amp;lt;/users&amp;gt;&lt;br /&gt;&lt;br /&gt;so here is the JAXB annotated "wrapper" class for use instead of returning a raw List&lt;user&gt; from the Resource method:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;@XmlRootElement(name = "users")&lt;br /&gt;public class Users {&lt;br /&gt;&lt;br /&gt;  private List&lt;user&gt; users;&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * @return the users&lt;br /&gt;   */&lt;br /&gt;  @XmlElement&lt;br /&gt;  public List&lt;user&gt; getUser() {&lt;br /&gt;      return users;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /**&lt;br /&gt;   * @param users the users to set&lt;br /&gt;   */&lt;br /&gt;  public void setUsers(List&lt;user&gt; users) {&lt;br /&gt;      this.users = users;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;then the Resource method just looks like this (note that it returns the Users wrapper class):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;  @GET&lt;br /&gt;  @Produces({MediaType.TEXT_HTML})&lt;br /&gt;  @Path("/users/{user}")&lt;br /&gt;  public Users  getUsersHTML(@PathParam("user") String username) throws Exception {&lt;br /&gt;      Users users = new Users();&lt;br /&gt;      if(username.equalsIgnoreCase("*")){&lt;br /&gt;          users.setUsers(net.nextdb.SysAdminSearchAccounts.getUsers("%"));&lt;br /&gt;      }else{&lt;br /&gt;           users.setUsers(net.nextdb.SysAdminSearchAccounts.getUsers(username));&lt;br /&gt;      }&lt;br /&gt;      return users;&lt;br /&gt;  }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/user&gt;&lt;/user&gt;&lt;/user&gt;&lt;/user&gt;&lt;/user&gt;&lt;/t&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-8908542081923796700?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/8908542081923796700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/08/three-views-of-rest-resources.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8908542081923796700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8908542081923796700'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/08/three-views-of-rest-resources.html' title='Three Views of REST resources'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-1742245786530867159</id><published>2009-08-03T08:13:00.000-07:00</published><updated>2009-08-03T08:14:17.471-07:00</updated><title type='text'>JAX-RS and Jersey</title><content type='html'>I spent the better part of the day messing with Jersey, an implementation of JAX-RS. I really like the built-in support for XML and JSON, as well as the JSONP support. The one thing that feels missing is some build-in support for creating lists of URIs. For example, if you have a User resource at Path .../user/JDoe, then plain old ".../user" ought naturally to return a list of URIs, one for each User. It would be nice if there was some support for that in the framework. Other than that, I really like JAX-RS and Jersey.&lt;br /&gt;&lt;br /&gt;I'll probably wind up implementing my own providers for generating simple HTML pages and JSONP-HTML.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-1742245786530867159?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/1742245786530867159/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/08/jax-rs-and-jersey.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1742245786530867159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1742245786530867159'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/08/jax-rs-and-jersey.html' title='JAX-RS and Jersey'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-81310784411886365</id><published>2009-07-21T23:22:00.000-07:00</published><updated>2009-07-21T23:28:24.820-07:00</updated><title type='text'>JSON, in retrospect</title><content type='html'>In May of 2006, I sent this message to a friend. It's funny that the "see for yourself" page is no longer titled "see for yourself", probably because people actually did "see for themselves" and perhaps reached a conclusion similar to the one I reached below. In hindsight, JSON is wonderful and I still consider it to have different use cases than XML. I continue to heavily use both JSON and XML in my day-to-day tasks.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;From: Geoff Hendrey&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Sent: Wednesday, May 24, 2006 10:31 AM&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;To: Brent Hamby&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Subject: Json questions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Hey dude,&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;"&gt;I went to the json "see for yourself" page: http://www.json.org/example.html to compare the Json equivalent of XML.&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;"&gt;I copied each of the examples into notepad and wrote down the size-on disk:&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;"&gt;json size (bytes)           XML size (bytes)          (json size)/(XML size)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;===================================================&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;604                             630                               95%&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;252                             221                              114%&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;630                             656                              96%&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;3554                        10708                              33%&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;898                            1150                             78%&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;"&gt;AVG (json size)/(XML size)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;=====================&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;83.2%&lt;/span&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;"&gt;Based on an average size compaction to 83.2% of the XML size. Also, if you look at the 4th example they give (line 4 of the table above), they did a Json version of web.xml. Now web.xml is a notoriously bad XML design. It basically doesn't use ANY attributes, so you get pretty nasty tag bloat. So if we drop the 4th comparison, as being kinda silly, we get an average compaction to 95.4% of the original size. Is saving 4.5% really a big advantage?&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;span style="font-family: courier new;"&gt;I also saw several statements on the json web page that I would put in the "wacky" bin. This may just be personal preference, but I found the XML documents much easier to read than their json equivalents. The Json looks, to me, like "code", kinda like a snippet of PERL or something.&lt;/span&gt;&lt;br /&gt; &lt;br /&gt;&lt;geeky style="font-family: courier new;"&gt;&lt;br /&gt;Anyway, it seems clear that being able to easily marshal an object representation of your data makes it much easier to develop software in any programming language. But it seems to me that json is munging this idea up with the wire format, which to me are orthogonal concerns.&lt;br /&gt;&lt;/geeky&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-81310784411886365?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/81310784411886365/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/07/json-in-retrospect.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/81310784411886365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/81310784411886365'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/07/json-in-retrospect.html' title='JSON, in retrospect'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-1740502985528557007</id><published>2009-06-20T19:07:00.000-07:00</published><updated>2009-06-20T19:40:15.976-07:00</updated><title type='text'>JavaScript downloaded function executor</title><content type='html'>Ran into a really annoying problem trying to use the YUI text editor in a jqueryUI modal dialog. I am using jquery to load a file "richEditor.html" that has my YUI editor on it. Problems:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;required YUI script and link tags, that are needed by YUI, are defined on my page richEditor.html. I  need to be move said tags from head to body, because jQuery.load function only loads the body of the HTML page.&lt;/li&gt;&lt;li&gt;said script and link tags *begin* downloading from yahoo when jQuery calls your load callback function. That's becuase richEditor.html itself has been downloaded by jQuery, but the said script and link tags referenced ON richEditor.html have only just begun asynchronously downloading. So if you need to access a function in one of the script tags that is downloading, you have no way to be sure the function has completed downloading.&lt;/li&gt;&lt;/ol&gt;As a solution, I wrote this JS Object that will simply try to invoke your function, and try again, after a configurable delay, up to maxTries. If the function fails to execute maxTries times, a fail handling function, provided by you, is executed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Here is the Object:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;function DownloadedFunctionCaller(funcToInvoke, wait&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;MS, maxTries, _failHandler){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    var funcToInvoke = funcToInvoke;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    var waitMS = waitMS;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    var maxTries = maxTries;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    var failHandler = function(){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;        alert("Unable to access the network. Please reload the page or try again.");&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    if(null != _failHandler){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;        failHandler = _failHandler;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    var that = this;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    var tries = 0;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    this.invoke = function(){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;        try{&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;            funcToInvoke();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;        }catch(err){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;            if(++tries &gt;= maxTries){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;                failHandler();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;                return;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;            }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;            setTimeout(that.invoke, waitMS);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;        }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;    }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;and here is an example of using it to invoke a function named setEditor that is defined&lt;br /&gt;in an external file, &lt;span style="color: rgb(255, 0, 0);"&gt;richEditor.html&lt;/span&gt;. The setEditor function will only work if all the YUI scripts are downloaded, hence the need to use the DonwloadedFunctionCaller&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;        var div = $("&amp;lt;div&amp;gt;&amp;lt;/div&amp;gt;");&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;        div.addClass("yui-skin-sam");&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;        div.load("&lt;span style="color: rgb(255, 0, 0);"&gt;richEditor.html&lt;/span&gt;", null, function(content){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;                    var invokeMe = function(){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;                        setEditor(&lt;span style="color: rgb(51, 255, 51);"&gt;"Script loaded and executed."&lt;/span&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;                    }&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;                    new &lt;span style="color: rgb(255, 0, 0);"&gt;DownloadedFunctionCaller&lt;/span&gt;(invokeMe, 500,10,function(){&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;                        alert("failed to down&lt;/span&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;load rich text editor")&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;                    }).invoke();&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;          });&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If you click on this screengrab, to get a bette look at it, you will see that the text "script loaded and executed" has been set into the YUI editor's text area by the successful invocation of the setEditor method.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_iJr6rK5UOFc/Sj2cJgD2p9I/AAAAAAAAALM/xcbFiIsbB3s/s1600-h/Picture+1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 179px;" src="http://4.bp.blogspot.com/_iJr6rK5UOFc/Sj2cJgD2p9I/AAAAAAAAALM/xcbFiIsbB3s/s400/Picture+1.png" alt="" id="BLOGGER_PHOTO_ID_5349603619424872402" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-1740502985528557007?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/1740502985528557007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/06/javascript-downloaded-function-executor.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1740502985528557007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1740502985528557007'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/06/javascript-downloaded-function-executor.html' title='JavaScript downloaded function executor'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_iJr6rK5UOFc/Sj2cJgD2p9I/AAAAAAAAALM/xcbFiIsbB3s/s72-c/Picture+1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-7532938724997934459</id><published>2009-05-23T09:51:00.000-07:00</published><updated>2009-05-23T10:07:24.346-07:00</updated><title type='text'>random lines of poetry</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Akhilleus_Patroklos_Antikensammlung_Berlin_F2278.jpg/607px-Akhilleus_Patroklos_Antikensammlung_Berlin_F2278.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 348px; height: 343px;" src="http://upload.wikimedia.org/wikipedia/commons/thumb/b/ba/Akhilleus_Patroklos_Antikensammlung_Berlin_F2278.jpg/607px-Akhilleus_Patroklos_Antikensammlung_Berlin_F2278.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I woke up early this morning around 6:30 thanks to Claritin-induced sleep deprivation. I started hacking on server code for automatically building "tables of contents" for very large database tables. I'm using a bunch of Yeats poems, and The Iliad as sample rows in the database. It makes debugging a lot more fun when the data is interesting. It's also a great way to read random lines of poetry. Here is a great stanza from the Iliad:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; color: rgb(255, 204, 0);"&gt;&lt;span style="color: rgb(204, 102, 0);"&gt;Generations of men are like the leaves.  &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 102, 0);"&gt;In winter, winds blow them down to earth, &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 102, 0);"&gt;but then, when spring season comes again, &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 102, 0);"&gt;budding wood grows more.  And so with men--&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(204, 102, 0);"&gt;one generation grows, another dies away.  (Iliad 6.181-5)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 204, 0);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;Did you know the phrase "another one bites the dust" is lifted from the Iliad?&lt;br /&gt;&lt;br /&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span style="font-style: italic; color: rgb(204, 102, 0);"&gt;Grant that my sword may pierce the shirt of Hector about his heart, and  &lt;/span&gt;&lt;a style="font-style: italic; color: rgb(204, 102, 0);" name="305"&gt;&lt;/a&gt;&lt;span style="font-style: italic; color: rgb(204, 102, 0);"&gt;that full many of his comrades may &lt;span style="color: rgb(255, 0, 0);font-size:130%;" &gt;bite the dust&lt;/span&gt; as they fall dying round  &lt;/span&gt;&lt;a style="font-style: italic; color: rgb(204, 102, 0);" name="306"&gt;&lt;/a&gt;&lt;span style="font-style: italic; color: rgb(204, 102, 0);"&gt;him.&lt;/span&gt;"&lt;span style="font-style: italic; color: rgb(255, 204, 0);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-7532938724997934459?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/7532938724997934459/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/05/random-lines-of-poetry.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7532938724997934459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7532938724997934459'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/05/random-lines-of-poetry.html' title='random lines of poetry'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-7303167210821369210</id><published>2009-05-07T12:20:00.000-07:00</published><updated>2009-05-07T12:31:02.352-07:00</updated><title type='text'>PBWiki vulnerability ...this could be huge</title><content type='html'>My sister seems to have uncovered a very interesting security vulnerability in PBWiki&lt;br /&gt;&lt;br /&gt;She wrote it up here on &lt;a href="http://www.dartmouthdesign.com/about/blog" rel="dofollow"&gt;http://www.dartmouthdesign.com/about/blog&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Just by knowing the name of my wiki, she seems to have been able to take administrative control of my account. I even receive emails, like the one below, when she takes an action on my account  (which I edited to remove the actual link in the email):&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;br /&gt;Hi,&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;An administrator, An administrator (geoff_hendrey@yahoo.com), has just updated hendreytravel to PBworks 2.0.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;To access the wiki, you'll need to create a PBworks account by clicking here:&lt;br /&gt;https://my.pbworks.com/verify.php? ... &lt;br /&gt; &lt;br /&gt;&lt;br /&gt;PBworks 2.0 has a brand new interface and improved features like folders, an easier editor and faster search.&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Learn more about PBworks 2.0: http://pbworks.com/content/pbwiki-2-user-guide&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;Thanks,&lt;br /&gt;&lt;br /&gt;The PBworks Team&lt;br /&gt;&lt;br /&gt; &lt;br /&gt;&lt;br /&gt;PS: Having trouble? Contact the support team at http://pbworks.com/help.wiki?wiki=hendreytravel&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-7303167210821369210?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/7303167210821369210/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/05/pbwiki-vulnerability-this-could-be-huge.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7303167210821369210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7303167210821369210'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/05/pbwiki-vulnerability-this-could-be-huge.html' title='PBWiki vulnerability ...this could be huge'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-2399502545870456702</id><published>2009-04-11T18:37:00.000-07:00</published><updated>2009-04-11T18:40:59.144-07:00</updated><title type='text'>Tesla rocks...</title><content type='html'>Aside from the fawning interviewer, this is a great interview with the CEO of &lt;a href="http://www.teslamotors.com/"&gt;Tesla Motors&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.techcrunch.com/2009/04/10/teslas-elon-musk-grows-a-pair-good-for-him/"&gt;http://www.techcrunch.com/2009/04/10/teslas-elon-musk-grows-a-pair-good-for-him/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It would be criminal if Tesla didn't receive the funding they need. To see a loser like GM sloshing in bailout funds is a sickening contrast.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-2399502545870456702?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/2399502545870456702/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/04/tesla-rocks.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2399502545870456702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2399502545870456702'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/04/tesla-rocks.html' title='Tesla rocks...'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-3856776049847385341</id><published>2009-03-31T20:27:00.000-07:00</published><updated>2009-03-31T20:28:12.334-07:00</updated><title type='text'>Nextdb in 120 seconds</title><content type='html'>&lt;object width="1258" height="649"&gt; &lt;param name="movie" value="http://content.screencast.com/users/nextdb/folders/Jing/media/b8b8e87d-4945-49be-89fb-60c0a2cfdf03/jingswfplayer.swf"&gt;&lt;/param&gt; &lt;param name="quality" value="high"&gt;&lt;/param&gt; &lt;param name="bgcolor" value="#FFFFFF"&gt;&lt;/param&gt; &lt;param name="flashVars" value="thumb=http://content.screencast.com/users/nextdb/folders/Jing/media/b8b8e87d-4945-49be-89fb-60c0a2cfdf03/FirstFrame.jpg&amp;containerwidth=1258&amp;containerheight=649&amp;loaderstyle=jing&amp;content=http://content.screencast.com/users/nextdb/folders/Jing/media/b8b8e87d-4945-49be-89fb-60c0a2cfdf03/00000003.swf"&gt;&lt;/param&gt; &lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt; &lt;param name="scale" value="showall"&gt;&lt;/param&gt; &lt;param name="allowScriptAccess" value="always"&gt;&lt;/param&gt; &lt;param name="base" value="http://content.screencast.com/users/nextdb/folders/Jing/media/b8b8e87d-4945-49be-89fb-60c0a2cfdf03/"&gt;&lt;/param&gt;  &lt;embed src="http://content.screencast.com/users/nextdb/folders/Jing/media/b8b8e87d-4945-49be-89fb-60c0a2cfdf03/jingswfplayer.swf" quality="high" bgcolor="#FFFFFF" width="1258" height="649" type="application/x-shockwave-flash" allowScriptAccess="always" flashVars="thumb=http://content.screencast.com/users/nextdb/folders/Jing/media/b8b8e87d-4945-49be-89fb-60c0a2cfdf03/FirstFrame.jpg&amp;containerwidth=1258&amp;containerheight=649&amp;loaderstyle=jing&amp;content=http://content.screencast.com/users/nextdb/folders/Jing/media/b8b8e87d-4945-49be-89fb-60c0a2cfdf03/00000003.swf" allowFullScreen="true" base="http://content.screencast.com/users/nextdb/folders/Jing/media/b8b8e87d-4945-49be-89fb-60c0a2cfdf03/" scale="showall"&gt;&lt;/embed&gt; &lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-3856776049847385341?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/3856776049847385341/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/nextdb-in-120-seconds.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3856776049847385341'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3856776049847385341'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/nextdb-in-120-seconds.html' title='Nextdb in 120 seconds'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-8923339592386504720</id><published>2009-03-22T21:42:00.000-07:00</published><updated>2009-03-22T21:53:26.863-07:00</updated><title type='text'>Back in one piece...</title><content type='html'>Spent the weekend near Tahoe in Truckie. We got 1.5 ft of snow between saturday night and sunday afternoon. Nevertheless Emily and I decided to drive back as soon as I-80 opened so we could get back Sunday night and not miss Monday at work. Tire chains are a real pain in the butt. Both my chains snapped. Fortunately I was able to pull to the side of the road in a relatively safe location (meaning semis were roaring by like 4 feet from me as I crawled under the car to disentagle the chains from the half axle - getting fairly mired in much at the same time).  Tire chains are required at times on I-80, but they honsestly seem like very unsafe garbage. The road is littered with broken chains. My theory is they are designed to be a deterent to drivers, more than an actual functioning safety mechanism. Anyway, chain chaos aside, we had a very relaxing weekend watching snow fall on evergreens (I was tempted to say Snow Falling On Cedars, but I refrained).&lt;br /&gt;&lt;br /&gt;Actually, I just checked the DOT report for I-80:&lt;br /&gt;&lt;br /&gt;"Enter Highway Number(s)               &lt;input name="roadnumber" size="15" type="text"&gt;                       &lt;input value="Search" name="submit" type="submit"&gt;          &lt;br /&gt;          &lt;i&gt;You can also call &lt;span class="red"&gt;1-800.427.7623&lt;/span&gt; for current highway conditions. &lt;/i&gt; &lt;a href="http://www.dot.ca.gov/cgi-bin/roadscell.cgi"&gt;Mobile&lt;/a&gt;  &lt;p&gt; &lt;/p&gt;   &lt;p align="center"&gt;&lt;img src="http://www.dot.ca.gov/hq/maint/banners/Click-It-Banner.jpg" alt="Click It or Ticket" height="60" width="468" /&gt;&lt;/p&gt; &lt;p&gt;This highway information is the latest reported as of Sunday, March 22, 2009 at 21:50 .&lt;/p&gt;&lt;!-- i80 --&gt;&lt;br /&gt;I 80 &lt;br /&gt;&lt;br /&gt;    [IN NORTHERN CALIFORNIA &amp;amp; THE SIERRA NEVADA]&lt;br /&gt;    WESTBOUND TRAFFIC IS BEING HELD AT CISCO GROVE (PLACER CO) - DUE TO AN &lt;br /&gt;ACCIDENT - MOTORISTS ARE ADVISED TO USE AN ALTERNATE ROUTE &lt;br /&gt; &lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;     CHAINS ARE REQUIRED ON ALL VEHICLES EXCEPT 4-WHEEL-DRIVE VEHICLES WITH SNOW &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt; TIRES ON ALL 4 WHEELS FROM 1 MI EAST OF BAXTER (PLACERCO) TO THE  &lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt; DONNER LAKE INTERCHANGE (NEVADA CO) &lt;/span&gt; "&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-8923339592386504720?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/8923339592386504720/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/back-in-one-piece.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8923339592386504720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8923339592386504720'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/back-in-one-piece.html' title='Back in one piece...'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-3511202374050937976</id><published>2009-03-18T21:34:00.001-07:00</published><updated>2009-03-18T21:34:50.113-07:00</updated><title type='text'>you know it's time to defrag when ...</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iJr6rK5UOFc/ScHLYtr07EI/AAAAAAAAAKo/wkBUa7bYuGY/s1600-h/SnagIt1.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 113px;" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/ScHLYtr07EI/AAAAAAAAAKo/wkBUa7bYuGY/s400/SnagIt1.gif" alt="" id="BLOGGER_PHOTO_ID_5314752660714613826" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-3511202374050937976?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/3511202374050937976/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/you-know-its-time-to-defrag-when.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3511202374050937976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3511202374050937976'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/you-know-its-time-to-defrag-when.html' title='you know it&apos;s time to defrag when ...'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iJr6rK5UOFc/ScHLYtr07EI/AAAAAAAAAKo/wkBUa7bYuGY/s72-c/SnagIt1.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-5093761327818244845</id><published>2009-03-17T22:38:00.000-07:00</published><updated>2009-03-17T22:40:50.520-07:00</updated><title type='text'>Need to improve the reviews widget</title><content type='html'>Wow, people are actually using the reviews widget to leave reviews. I love that with nextdb I can just enter the web based admin to manually delete my test reviews (ok, ok, or to boost the number of stars in a posting! haha).&lt;br /&gt;&lt;br /&gt;But seriously, I need to gut the thing and redo it with something like JQuery UI.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-5093761327818244845?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/5093761327818244845/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/need-to-improve-reviews-widget.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5093761327818244845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5093761327818244845'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/need-to-improve-reviews-widget.html' title='Need to improve the reviews widget'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-6389731702354196642</id><published>2009-03-17T21:19:00.000-07:00</published><updated>2009-03-17T21:20:48.995-07:00</updated><title type='text'>From Willow Tea Room, Glasgow</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iJr6rK5UOFc/ScB2lqzqchI/AAAAAAAAAKg/OPPbNjelFsE/s1600-h/Picture+1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 220px; height: 400px;" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/ScB2lqzqchI/AAAAAAAAAKg/OPPbNjelFsE/s400/Picture+1.png" alt="" id="BLOGGER_PHOTO_ID_5314377949815403026" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-6389731702354196642?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/6389731702354196642/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/from-willow-tea-room-glasgow.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6389731702354196642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6389731702354196642'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/from-willow-tea-room-glasgow.html' title='From Willow Tea Room, Glasgow'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_iJr6rK5UOFc/ScB2lqzqchI/AAAAAAAAAKg/OPPbNjelFsE/s72-c/Picture+1.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-8744890078535910719</id><published>2009-03-16T20:01:00.000-07:00</published><updated>2009-03-17T21:10:54.077-07:00</updated><title type='text'>Photos From Scotland</title><content type='html'>In 2006 I took a trip to Scotland for an OGC meeting, and had the weekend to roam around. I visited the National Library and did a little geniological research. After a fair bit of cross-referenced parish records, pre-census, I believe I located the birth records for my great, great, great, grandfather and grandmother. Unfortunately the library closed right when I pieced it all together, but that's my next trip I guess. The microfilm will still be there!&lt;br /&gt;&lt;br /&gt;One of the most fascinating aspects of Edinburgh and Glascow was there role in the Arts and Crafts and Art Nuveau movements. Phoebe Anna Traquair (P.A.T) was one of the female artists who figured prominently in this movement. If you ever have a chance to visit the Mansfield Traquair church, do not miss it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iJr6rK5UOFc/Sb8TuNdFg6I/AAAAAAAAAJw/OsB0rDqzgFk/s1600-h/DSCF0016.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/Sb8TuNdFg6I/AAAAAAAAAJw/OsB0rDqzgFk/s400/DSCF0016.JPG" alt="" id="BLOGGER_PHOTO_ID_5313987769927041954" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;You can get a better look, here: &lt;a href="http://www.mansfieldtraquair.org.uk/nav/cag02.html"&gt;http://www.mansfieldtraquair.org.uk/nav/cag02.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If that doesn't blow your hair back, get a look at this amazing painting by P.A.T.. Oh, wait, take a second look, it isn't a painting! It's SILK EMPROIDERY!!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_iJr6rK5UOFc/Sb8XSJUfp-I/AAAAAAAAAKA/CSnfh8IyBMI/s1600-h/Picture+1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 148px; height: 400px;" src="http://1.bp.blogspot.com/_iJr6rK5UOFc/Sb8XSJUfp-I/AAAAAAAAAKA/CSnfh8IyBMI/s400/Picture+1.png" alt="" id="BLOGGER_PHOTO_ID_5313991685827438562" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;It's almost incomprehensible that a few years ago, the Mansfield Traquair church was being used as a brick storage facility. Thankfully, it was recently rescued an restored. For the life of me I cannot understand why P.A.T. and John Duncan are not better known. Please&lt;a href="http://artinconnu.blogspot.com/2008/06/phoebe-anna-traquair-1852-1936.html"&gt; read this blog&lt;/a&gt; to see some more breathtaking work by P.A.T.&lt;br /&gt;&lt;br /&gt;I am so awestruck by John Duncan's St. Bride that I recently aquired a canvas reproduction of it from an obscure source on the web. Here is a shot of it gracing my living room.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iJr6rK5UOFc/Sb8bw6LlOqI/AAAAAAAAAKI/_ycztb2B7HA/s1600-h/IMG_3791.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 300px; height: 400px;" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/Sb8bw6LlOqI/AAAAAAAAAKI/_ycztb2B7HA/s400/IMG_3791.JPG" alt="" id="BLOGGER_PHOTO_ID_5313996612385979042" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Scotland has lots of badass wildcats, which came to America as stowaways, and became the big Main Coon cats.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_iJr6rK5UOFc/Sb8Tt2_ATXI/AAAAAAAAAJo/ePlnsgb-Nxc/s1600-h/DSCF0026.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_iJr6rK5UOFc/Sb8Tt2_ATXI/AAAAAAAAAJo/ePlnsgb-Nxc/s400/DSCF0026.JPG" alt="" id="BLOGGER_PHOTO_ID_5313987763895291250" border="0" /&gt;&lt;/a&gt;Loch Ness... of course. On the way there we passed the spot where the &lt;a href="http://en.wikipedia.org/wiki/Battle_of_the_Shirts"&gt;Battle Of The Shirts&lt;/a&gt; (or lack thereof) took place. It turns out that fighting a clan battle in sweltering heat with armor is a good way to die of heat stroke. So it probably seemed like a reasonable idea is to call for a "time out" because of the heat, and take a dip in the loch. Unfortunately, it turned out to be a very bad idea to agree to fight the second half of the battle without armor because of the heat. The horrific mutual slaughter that ensued, fought with claymore broad swords and battle axes left just 12 survivors in total, and the Loch was litterally red with blood for days.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_iJr6rK5UOFc/Sb8TtgfpbAI/AAAAAAAAAJg/LvQcc2Q6pQ8/s1600-h/DSCF0091.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_iJr6rK5UOFc/Sb8TtgfpbAI/AAAAAAAAAJg/LvQcc2Q6pQ8/s400/DSCF0091.JPG" alt="" id="BLOGGER_PHOTO_ID_5313987757858188290" border="0" /&gt;&lt;/a&gt;Edinburough....&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_iJr6rK5UOFc/Sb8Ttte1MdI/AAAAAAAAAJY/Oo1fKXR3j0M/s1600-h/DSCF0096_3.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_iJr6rK5UOFc/Sb8Ttte1MdI/AAAAAAAAAJY/Oo1fKXR3j0M/s400/DSCF0096_3.JPG" alt="" id="BLOGGER_PHOTO_ID_5313987761344426450" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-8744890078535910719?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/8744890078535910719/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/photos-from-scotland.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8744890078535910719'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8744890078535910719'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/photos-from-scotland.html' title='Photos From Scotland'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_iJr6rK5UOFc/Sb8TuNdFg6I/AAAAAAAAAJw/OsB0rDqzgFk/s72-c/DSCF0016.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-3646545029631309736</id><published>2009-03-15T20:41:00.000-07:00</published><updated>2009-03-15T20:43:00.692-07:00</updated><title type='text'>Another Gem from William Morris</title><content type='html'>&lt;span style="font-weight: bold; font-family: lucida grande; color: rgb(102, 0, 0);"&gt;For the Bed at Kelmscott&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;The wind's on the wold&lt;br /&gt;And the night is a-cold,&lt;br /&gt;And Thames runs chill&lt;br /&gt;'Twixt mead and hill.&lt;br /&gt;But kind and dear&lt;br /&gt;Is the old house here&lt;br /&gt;And my heart is warm&lt;br /&gt;'Midst winter's harm.&lt;br /&gt;Rest then and rest,&lt;br /&gt;And think of the best&lt;br /&gt;'Twixt summer and spring,&lt;br /&gt;When all birds sing&lt;br /&gt;In the town of the tree,&lt;br /&gt;And ye in me&lt;br /&gt;And scarce dare move,&lt;br /&gt;Lest earth and its love&lt;br /&gt;Should fade away&lt;br /&gt;Ere the full of the day.&lt;br /&gt;I am old and have seen&lt;br /&gt;Many things that have been;&lt;br /&gt;Both grief and peace&lt;br /&gt;And wane and increase&lt;br /&gt;No tale I tell&lt;br /&gt;Of ill or well,&lt;br /&gt;But this I say:&lt;br /&gt;Night treadeth on day,&lt;br /&gt;And for worst or best&lt;br /&gt;Right good is rest.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-3646545029631309736?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/3646545029631309736/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/another-gem-from-william-morris.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3646545029631309736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/3646545029631309736'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/another-gem-from-william-morris.html' title='Another Gem from William Morris'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-5625771622151347601</id><published>2009-03-15T10:05:00.000-07:00</published><updated>2009-03-15T20:33:32.236-07:00</updated><title type='text'>ProPublica: Jouranlism in the public interest</title><content type='html'>I'm replacing my daily reading of the New York Times Online Edition with that of &lt;a href="http://www.propublica.org/"&gt;Propublica.org&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Basically, none of the major news outlets can be trusted. This is just a fact. Remember before we went into Iraq how the New York Times ran breathless stories on Sadam's vast underground bunker complex. It was all just a load of shit.&lt;br /&gt;&lt;br /&gt;So now I'm going try getting my news from ProPublica, because their mission is to reinvigorate investigative journalism.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-5625771622151347601?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/5625771622151347601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/propublica-jouranlism-in-public.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5625771622151347601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5625771622151347601'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/propublica-jouranlism-in-public.html' title='ProPublica: Jouranlism in the public interest'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-270353733874211428</id><published>2009-03-13T07:37:00.000-07:00</published><updated>2009-03-13T07:44:06.620-07:00</updated><title type='text'>Developers are starting to catch on!</title><content type='html'>Here is a link to a blog post written by a developer at SolutionSoft, about &lt;a href="http://nextdb.net"&gt;NextDB&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href=" http://blog.solutionset.com/wpmu/2009/03/11/nextdb-a-front-end-database-solution/"&gt;&lt;br /&gt;http://blog.solutionset.com/wpmu/2009/03/11/nextdb-a-front-end-database-solution/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It's a great post, and I think it illustrates how easy nextdb is to learn, and use. Nextb is getting preety close to exiting alpha and entering Beta. During the Beta we will have our "subscribe" buttons up on the site. We are targeting price points that are basically below the noise for even a personal account, so affording nextdb should not be a problem for anyone.&lt;br /&gt;&lt;br /&gt;Brent is busy developing and refining a new set of utilities for adding forms to your AJAX apps. The forms will automatically configure themselves based on the content of your table or query, and will be CSS friendly.&lt;br /&gt;&lt;br /&gt;I'm working on a notification system that will allow you to receive email when data is inserted into a table. You'll be able to request digests, as well as create email templates that receive data from the inserted row in order to create a personalized, pretty email.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-270353733874211428?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/270353733874211428/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/developers-are-starting-to-catch-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/270353733874211428'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/270353733874211428'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/03/developers-are-starting-to-catch-on.html' title='Developers are starting to catch on!'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-7672112512375633256</id><published>2009-01-25T23:29:00.000-08:00</published><updated>2009-01-25T23:38:43.577-08:00</updated><title type='text'>ulimit -n .... the saga continues</title><content type='html'>Man, I thought I had put the "ulimit -n issue" to bed once and for all with &lt;a href="http://notskateboarding.blogspot.com/2009/01/annoying-centos-problems-raising-ulimit.html"&gt;these configurations &lt;/a&gt;in CentOS. So, it was with great chagrin that I recently executed a "ulimit -n" and saw 1024.&lt;br /&gt;&lt;br /&gt;Argghhh. Will this issue never end?&lt;br /&gt;&lt;br /&gt;I've added "ulimit -n 100000" to my .bash_profile, and now I have confirmed that after logging into a new session, that the new ulimit of 100000 files is in effect.&lt;br /&gt;&lt;br /&gt;I'm not happy with putting this in my .bash_profile, but &lt;a href="http://groups.google.com/group/linux.debian.bugs.dist/browse_thread/thread/b4dfb75c3ff0e253"&gt;the alternatives looked too dangerous and or flakey.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-7672112512375633256?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/7672112512375633256/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/ulimit-n-saga-continues.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7672112512375633256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7672112512375633256'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/ulimit-n-saga-continues.html' title='ulimit -n .... the saga continues'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-5001651438109222242</id><published>2009-01-21T18:15:00.000-08:00</published><updated>2009-01-21T18:32:40.900-08:00</updated><title type='text'>some recent tech photos</title><content type='html'>At deCarta I am building a new map tile  system for our servers. Krish installed it on a floppy drive! That was pretty funny.&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iJr6rK5UOFc/SXfY_luyMYI/AAAAAAAAAI8/CB7Uisi_fPc/s1600-h/IMG_0226.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 240px; height: 320px;" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/SXfY_luyMYI/AAAAAAAAAI8/CB7Uisi_fPc/s320/IMG_0226.JPG" alt="" id="BLOGGER_PHOTO_ID_5293938473969004930" border="0" /&gt;&lt;/a&gt;Brent and I went to the Cloud Connect conference. We tried to pay attention but we were too busy hacking :-)&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iJr6rK5UOFc/SXfY_ddXuWI/AAAAAAAAAI0/AkHpc9AfaGQ/s1600-h/IMG_0227.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 240px; height: 320px;" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/SXfY_ddXuWI/AAAAAAAAAI0/AkHpc9AfaGQ/s320/IMG_0227.JPG" alt="" id="BLOGGER_PHOTO_ID_5293938471748483426" border="0" /&gt;&lt;/a&gt;Panel discussion at Cloud Connect was lively to say the least. I thought the dude from Salesforce.com was going to smash a chair on someone. But seriously, he is a very sharp dude. Would not want to debate him.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_iJr6rK5UOFc/SXfY_Z5xTeI/AAAAAAAAAIs/wiKt_LRfnlw/s1600-h/IMG_0228.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_iJr6rK5UOFc/SXfY_Z5xTeI/AAAAAAAAAIs/wiKt_LRfnlw/s320/IMG_0228.JPG" alt="" id="BLOGGER_PHOTO_ID_5293938470793858530" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-5001651438109222242?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/5001651438109222242/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/some-recent-tech-photos.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5001651438109222242'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5001651438109222242'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/some-recent-tech-photos.html' title='some recent tech photos'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iJr6rK5UOFc/SXfY_luyMYI/AAAAAAAAAI8/CB7Uisi_fPc/s72-c/IMG_0226.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-4388103641927517683</id><published>2009-01-14T20:27:00.000-08:00</published><updated>2009-02-03T19:10:52.329-08:00</updated><title type='text'>Test reviews Widget</title><content type='html'>&lt;div name="com_dartmouthdesign_reviews_Widget" reviewed="gadget1" groupId="notskateboarding" location="http://dartmouthdesign.com/reviews"&gt;&lt;/div&gt;&lt;br /&gt;&lt;script src="http://dartmouthdesign.com/reviews/reviewsWidget.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-4388103641927517683?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/4388103641927517683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/test-reviews-widget_14.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4388103641927517683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4388103641927517683'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/test-reviews-widget_14.html' title='Test reviews Widget'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-7751894501758324515</id><published>2009-01-14T07:01:00.000-08:00</published><updated>2009-01-14T07:04:14.246-08:00</updated><title type='text'>Please don't say "meme" with a straight face</title><content type='html'>It's early, I'm grouchy, and I've seen the word "meme" one too many times. People: please, please don't use the word "meme" to describe internet trends, or anything else for that matter. It's just silly. It's like putting plastic spinny rims on an '83 celica. It's basically gheto-bling.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-7751894501758324515?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/7751894501758324515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/please-dont-say-meme-with-straight-face.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7751894501758324515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7751894501758324515'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/please-dont-say-meme-with-straight-face.html' title='Please don&apos;t say &quot;meme&quot; with a straight face'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-1518451603492431734</id><published>2009-01-08T23:59:00.000-08:00</published><updated>2009-01-16T13:28:33.634-08:00</updated><title type='text'>The Wanderings of Oisin</title><content type='html'>I was trying to find an extant copy The Evergreen Periodical, when I came across &lt;a href="http://www.google.com/url?sa=U&amp;amp;start=3&amp;amp;q=http://books.google.com/books%3Fid%3DXaT_HrzWDWIC%26pg%3DPA214%26lpg%3DPA214%26dq%3D1895%2BThe%2BEvergreen%2Bperiodical%26source%3Dweb%26ots%3D6MhYTOo5h3%26sig%3DiHg6VMt9FlDeosWsD81G2QW31D0&amp;amp;ei=4-9mSYavHpr0sAOX3ZStAw&amp;amp;usg=AFQjCNFV-GFgaT-yS2BdpNYvNIGHnP761Q&amp;amp;ei=4-9mSYavHpr0sAOX3ZStAw&amp;amp;oi=book_result&amp;amp;resnum=3&amp;amp;ct=result"&gt; this intersting read&lt;/a&gt; on the Celtic revival's influence on art nouveau, which in turn led me to The Wanderings of Oisin by Yeates.&lt;br /&gt;&lt;br /&gt;"&lt;span style="color: rgb(204, 153, 51); font-family: times new roman;font-size:130%;" &gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;An old man stirs the fire to a blaze,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;In the house of a child, of a friend, of a brother.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;He has over-lingered his welcome; the days,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;Grown desolate, whisper and sigh to each other;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;He hears the storm in the chimney above,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;And bends to the fire and shakes with the cold,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;While his heart still dreams of battle and love,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;And the cry of the hounds on the hills of old.&lt;/span&gt;&lt;/span&gt;"&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-1518451603492431734?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/1518451603492431734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/wanderings-of-oisin.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1518451603492431734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1518451603492431734'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/wanderings-of-oisin.html' title='The Wanderings of Oisin'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-8385884351404239283</id><published>2009-01-08T17:21:00.000-08:00</published><updated>2009-01-08T17:36:09.667-08:00</updated><title type='text'>Hacking JS-Kit reviews widget</title><content type='html'>I just installed the JS-Kit reviews system on my blog below. I was amazed to find the following security holes:&lt;br /&gt;&lt;br /&gt;1) no CAPTCHA protection on posts. This means you can flood the reviews with bogus reviews and spam. Want to bring down the reviews system? Just write a 4-line script to execute this URL in a loop:&lt;br /&gt;&lt;a href="http://js-kit.com/comment.put?ref=http://notskateboarding.blogspot.com%2F&amp;permalink=http%3A%2F%2Fmysite.com%2Fpermanent%2Flink%2Fto%2Fpage.html&amp;rvy=1&amp;js-CmtName=reviewer04&amp;js-CmtCity=san%20franciso%2C%20USA&amp;js-CmtEmail=geoff.hendrey%40gmail.com&amp;js-Cmtsubmit=Submit%20review&amp;js-CmtsubmitOrig=Submit%20review&amp;js-CmtsubmitReply=Submit%20comment&amp;js-Cmtcancel=Cancel&amp;js-CmtText=BBBBBBBBBBBBBBBBBBBBBBBBBBB&amp;js-CmtRating=8&amp;tid=jst-1"&gt;http://js-kit.com/comment.put?ref=http://notskateboarding.blogspot.com%2F&amp;permalink=http%3A%2F%2Fmysite.com%2Fpermanent%2Flink%2Fto%2Fpage.html&amp;rvy=1&amp;js-CmtName=reviewer04&amp;js-CmtCity=san%20franciso%2C%20USA&amp;js-CmtEmail=geoff.hendrey%40gmail.com&amp;js-Cmtsubmit=Submit%20review&amp;js-CmtsubmitOrig=Submit%20review&amp;js-CmtsubmitReply=Submit%20comment&amp;js-Cmtcancel=Cancel&amp;js-CmtText=BBBBBBBBBBBBBBBBBBBBBBBBBBB&amp;js-CmtRating=8&amp;tid=jst-1&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;2) Email span the person who posted a comment you don't like! This one is really amazing! Want to send someone 1000 emails anonymously? Same technique as above, just make it a comment instead of a posting, and the person who made the original posting gets 1000 emails!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-8385884351404239283?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/8385884351404239283/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/hacking-js-kit-reviews-widget.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8385884351404239283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8385884351404239283'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/hacking-js-kit-reviews-widget.html' title='Hacking JS-Kit reviews widget'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-7769566861472332641</id><published>2009-01-08T16:03:00.000-08:00</published><updated>2009-01-15T09:09:36.144-08:00</updated><title type='text'>test a reviews widget</title><content type='html'>&lt;!--&lt;br /&gt;&lt;div class="js-kit-ratings" title="Cool Stuff" permalink="http://mysite.com/permanent/link/to/page.html"&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="js-kit-comments" permalink="http://mysite.com/permanent/link/to/page.html"&gt;&lt;/div&gt;&lt;br /&gt;&lt;script src="http://js-kit.com/reviews.js"&gt;&lt;/script&gt;&lt;br /&gt;--&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-7769566861472332641?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/7769566861472332641/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/test-reviews-widget.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7769566861472332641'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7769566861472332641'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/test-reviews-widget.html' title='test a reviews widget'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-6654948891933689996</id><published>2009-01-06T21:35:00.000-08:00</published><updated>2009-01-15T09:13:32.277-08:00</updated><title type='text'>annoying CENTOS problems raising ulimit</title><content type='html'>My last attempt to raise the open file count on a CentOS server apparently failed. After much dicking around, here is a set of steps that I believe will successfully raise the limit (don't be fooled by whatever you try. If you do a 'ulimit -n' and the returned value is 1024, you have not succeeded in raising the limit).&lt;br /&gt;&lt;br /&gt;I did a bunch of reading, and found two postings, that combined seem to have succeeded in upping the max files to 65535.&lt;br /&gt;&lt;br /&gt;Mainly I am writing this down so we can remember what the hell I did. These are the two useful posts: &lt;br /&gt;http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/ http://www.centos.org/modules/newbb/viewtopic.php?forum=1&amp;topic_id=559&amp;viewmode=flat&lt;br /&gt;&lt;br /&gt;in summary:&lt;br /&gt;1) edit /etc/sysctl.conf to add this line:&lt;br /&gt;fs.file-max = 200000&lt;br /&gt;2) sysctl -p&lt;br /&gt;3)switch to /etc/security/limits.conf and add ther following lines&lt;br /&gt;&lt;br /&gt;* soft nofiles 65535&lt;br /&gt;* hard nofiles 65535&lt;br /&gt;4)ulimit -n 65535&lt;br /&gt;&lt;br /&gt;I think this worked this time because when I do 'ulimit -n' it returns 65535, whereas prior it always returned 1024. In our previous attempt we only did step 3.&lt;br /&gt;&lt;br /&gt;The 200000 value is excessive, but who cares.&lt;br /&gt;I am working on a widget for adding reviews to blogs and websites.&lt;br /&gt;&lt;!--iframe src="http://nextdb.hostrator.com/reviews-widget/ratings.html?reviewed=centos_ulimit&amp;returnTo=http%3A//notskateboarding.blogspot.com&amp;1=1" frameborder='0' width='100%' height="100%"&gt;&lt;/iframe--&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-6654948891933689996?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/6654948891933689996/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/annoying-centos-problems-raising-ulimit.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6654948891933689996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6654948891933689996'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/annoying-centos-problems-raising-ulimit.html' title='annoying CENTOS problems raising ulimit'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-7009675241570105936</id><published>2009-01-03T15:11:00.000-08:00</published><updated>2009-01-15T10:11:03.011-08:00</updated><title type='text'>test review widget</title><content type='html'>I am working on a widget for adding reviews to blogs and websites.&lt;br /&gt;&lt;!--iframe src="http://nextdb.hostrator.com/reviews-widget/ratings.html?reviewed=gadget1&amp;returnTo=http://notskateboarding.blogspot.com" frameborder='0' width='100%' height="100%"&gt;&lt;/iframe--&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-7009675241570105936?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/7009675241570105936/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/test-review-widget.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7009675241570105936'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7009675241570105936'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/test-review-widget.html' title='test review widget'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-5374677354581584972</id><published>2009-01-02T09:45:00.001-08:00</published><updated>2009-01-02T12:52:04.974-08:00</updated><title type='text'>Tahoe Trip</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iJr6rK5UOFc/SV5-HGxehxI/AAAAAAAAAIM/Rmmkh8wRfnI/s1600-h/IMG_3448.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 150px;" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/SV5-HGxehxI/AAAAAAAAAIM/Rmmkh8wRfnI/s200/IMG_3448.JPG" alt="" id="BLOGGER_PHOTO_ID_5286801673121859346" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iJr6rK5UOFc/SV5-GwEuePI/AAAAAAAAAIE/ThzDAS5DdqY/s1600-h/IMG_3353.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 150px;" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/SV5-GwEuePI/AAAAAAAAAIE/ThzDAS5DdqY/s200/IMG_3353.JPG" alt="" id="BLOGGER_PHOTO_ID_5286801667028580594" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_iJr6rK5UOFc/SV5VSXSC1mI/AAAAAAAAAH8/5lpLnqOPOMI/s1600-h/IMG_3378.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 200px; height: 150px;" src="http://4.bp.blogspot.com/_iJr6rK5UOFc/SV5VSXSC1mI/AAAAAAAAAH8/5lpLnqOPOMI/s200/IMG_3378.JPG" alt="" id="BLOGGER_PHOTO_ID_5286756786555246178" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-5374677354581584972?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/5374677354581584972/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/tahoe-trip.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5374677354581584972'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5374677354581584972'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2009/01/tahoe-trip.html' title='Tahoe Trip'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_iJr6rK5UOFc/SV5-HGxehxI/AAAAAAAAAIM/Rmmkh8wRfnI/s72-c/IMG_3448.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-387323389480069755</id><published>2008-12-24T09:29:00.000-08:00</published><updated>2008-12-24T09:33:54.407-08:00</updated><title type='text'>Happy Newton's Birthday</title><content type='html'>&lt;a href="http://qcpages.qc.cuny.edu/EES/pep/hendrey.html"&gt;George&lt;/a&gt; just pointed me to a great article in the NYTimes titled &lt;a href="http://judson.blogs.nytimes.com/2008/12/23/the-ten-days-of-newton/"&gt;"The Ten Days of Newton"&lt;/a&gt;.&lt;br /&gt;&lt;blockquote style="font-style: italic; font-family: georgia;"&gt; &lt;p&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;On the tenth day of Newton,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;My true love gave to me,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;Ten drops of genius,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Nine silver co-oins,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;Eight circling planets,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Seven shades of li-ight,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;Six counterfeiters,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Cal-Cu-Lus!&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;Four telescopes,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;Three Laws of Motion,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;Two awful feuds,&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(51, 204, 0);"&gt;And the discovery of gravity!&lt;/span&gt;&lt;/span&gt;&lt;/p&gt; &lt;/blockquote&gt; Happy Newton, everybody!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-387323389480069755?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/387323389480069755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/happy-newtons-birthday.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/387323389480069755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/387323389480069755'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/happy-newtons-birthday.html' title='Happy Newton&apos;s Birthday'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-6570287711967966816</id><published>2008-12-23T18:18:00.000-08:00</published><updated>2008-12-23T18:20:26.503-08:00</updated><title type='text'>Histrator update</title><content type='html'>I received this email from Hostrator:&lt;br /&gt;&lt;br /&gt;"&lt;span style="font-style: italic;"&gt;Dear Geoff,&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;We have some redirection issues, Note all your files are there intact, the issue occurred while we were upgrading the bandwidth for each user (was our surprise). Again your sites (files) are there and no need to worry about it, your site will be back online in a couple of hours hopefully.&lt;/span&gt;"&lt;br /&gt;&lt;br /&gt;I guess they resolved their issue, because my widget's HTML files are back online.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-6570287711967966816?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/6570287711967966816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/histrator-update.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6570287711967966816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6570287711967966816'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/histrator-update.html' title='Histrator update'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-5119864007301266578</id><published>2008-12-22T23:46:00.000-08:00</published><updated>2008-12-22T23:49:28.025-08:00</updated><title type='text'>asscrack hosting, inc!</title><content type='html'>Wow, notice that my signup widget on the right side of the page has been replaced by the hostrator home page? Either these guys are complete scumbags, and they trick you into using free hosting, then replace your own HTML files with their homepage, or they are so broken that they have genuinely lost the files that I hosted there. Either way, their homepage is appearing where my widget should be. Well, time to find another free host for my widget HTML files. Anyone know a *reliable* and *ethical* provider of HTML file hosting?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-5119864007301266578?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/5119864007301266578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/asscrack-hosting-inc.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5119864007301266578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5119864007301266578'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/asscrack-hosting-inc.html' title='asscrack hosting, inc!'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-2826050705555280042</id><published>2008-12-21T22:50:00.000-08:00</published><updated>2008-12-25T22:27:41.412-08:00</updated><title type='text'>Encryption, digital signatures</title><content type='html'>For a few weeks &lt;a href="http://nextdb.net/"&gt;NextDB&lt;/a&gt; has had support for encryption via the CYPHER function, and sending email through the SENDEMAIL function. However, we didn't have support for providing application specific &lt;span style="color: rgb(255, 153, 0);"&gt;encryption keys, nor for digital signatures&lt;/span&gt;. Well, I spent today prototyping support for both of these two things. The CYPHER function now accepts a second argument, which is a 16-character string (128 bit privtate key). Digital signatures are accomplished through a new function called MD (Message Digest).  A DECYPHER function allows you to decrypt whatever you encrypt. This creates a "round trip" model for your data, a lot like we do for our SURIDs. But you can put whatever applicaiton specific payloads you like inside the encrypted messages.&lt;br /&gt;&lt;br /&gt;the impotus for this was being able to send out "confirmation" emails from NextQuery expressions, and not allow the content of the URL in the email to be tampered. The following is a NextQuery expression that I am using with a "5-star reviews" widget that I am developing. When the user posts a review, this query sends an email to the poster of the review, including a link to click to confirm (for sake of example, we are assuming the Reviews Widget has been places on 'mysite.com')&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;NAME=sendReviewConfirmationEmail;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;ROW review FROM REVIEW;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;WHERE(SURID pk){&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;  review.PK = ${pk}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;RETRIEVE SENDEMAIL(&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt; 'please confirm your review',    &lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;  'click this link to confirm your review\n' ||&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;  'http://mysite.com/reviewConfirm?'||CYPHER(review.title||':'||review.author||':'||MD(review.title||':'||review.author),'0123456789abcdef'),&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;  review.authoremail,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt; 'reviewAdmin@mysite.com'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt; )&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:courier new;" &gt;into email.status;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The SENDEMAIL function accepts the subject, body, to, and from parameters. The interesting thing here is the third parameter, the body of the email, which includes a URL. Part of the URL (the part after the question mark) consists of a cyphered and digitally signed concatenation of the review's title, and the author's screenname.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 153, 0);"&gt;Where things get really mindbending&lt;/span&gt;, is that the content of mysite.com/reviewConfirm is actually an HTML page with JavaScript embeded. The embedded JS can actually get access to parameters passed to the page, and thereby fulfil functions typcially handled on the serverside, even though they will run right there in the user's browser.&lt;br /&gt;&lt;br /&gt;When the "reviewConfirm" JavaScript executes, it uses &lt;a href="http://nextdb.net/docs"&gt;NextDB's JavaScript API&lt;/a&gt; to execute a query. Said query will use the DECYPHER function to decypher the URL's query parameter, and use the MD function to check the digital signature to be sure the confirmation email content has not been tampered. Said query returns a SURID with FOR UPDATE permission which allows the JS to change the value of the  'status' column of the row to 'approved'.&lt;br /&gt;&lt;br /&gt;But what about replay attacks? That's the beauty of this technique. Because the CYPHER function's secret key can be different for each query, and because the content of the encrypted message can be used to confirm the presence of a row in the database, you can't "replay" a cyphered structure from your database against someone else's database.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-2826050705555280042?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/2826050705555280042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/encryption-digital-signatures.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2826050705555280042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2826050705555280042'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/encryption-digital-signatures.html' title='Encryption, digital signatures'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-7197269793381852372</id><published>2008-12-16T06:51:00.000-08:00</published><updated>2008-12-16T06:52:10.791-08:00</updated><title type='text'>Steal This Widget</title><content type='html'>&lt;form method="POST" action="http://www.blogger.com/add-widget"&gt;  &lt;input type="hidden" name="widget.title" value="This is a test widget I am developing. It used NextDB.net.  Doesn't do much yet."&gt;  &lt;input type="hidden" name="widget.content" value="&amp;lt;iframe scrolling='false' frameborder='0' width='325px' height='575px' src='http://nextdb.hostrator.com/registration-widget/registration-widget-350x500.html'/&amp;gt;"&gt;  &lt;input type="hidden" name="widget.template" value="&amp;lt;data:content/&amp;gt;"&gt;  &lt;input type="hidden" name="infoUrl" value="http://nextdb.net"&gt;  &lt;input type="hidden" name="logoUrl" value="http://www.blogger.com/img/icon_logo32.gif"&gt;  &lt;input type="submit" name="go" value="Add User Registration Widget"&gt;&lt;/form&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-7197269793381852372?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/7197269793381852372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/steal-this-widget.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7197269793381852372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7197269793381852372'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/steal-this-widget.html' title='Steal This Widget'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-473589017040167595</id><published>2008-12-15T22:12:00.001-08:00</published><updated>2008-12-15T22:23:24.377-08:00</updated><title type='text'>Widget (Take I)</title><content type='html'>As you can see, I've added a rather oversized "signup" widget to my blog. I am experimenting with creating widgets using &lt;a href="http://nextdb.net/"&gt;NextDB.net&lt;/a&gt;.  This one will add your "user" information into the NextDB database when you signup.&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;Why?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 102, 0);"&gt;User registration is really "square one"&lt;/span&gt; of building any website. If we can encapsulate user signup into a widget, then we can encapsulate all other site functions as well. Then, with site functions "widgetized" you can essentially turn your blog, or really any web page into a full-featured AJAX site.&lt;br /&gt;&lt;br /&gt;I've learned a bit about how best to do this. The first thing I learned is that sites like blogger.com have a pretty friendly way for you to distribute your widget. It boils down to a simple button a viewer of your blog can press, and presto, they get the widget.&lt;br /&gt;&lt;br /&gt;Second thing that took more messing around than it should was to find a webhost to host the HTML and image files for the widget. I intentionally didn't want to host any of the HTML or resources on nextdb.net, because I really wanted to behave as a nextdb user, who might be a graphic designer or someone in a dorm room, for whom a free webhost was their only option. I wound up creating an account at &lt;a href="http://hostrator.com/"&gt;hostrator.com&lt;/a&gt;. But it is lame that they don't support SFTP or a better batch upload. But it's good enough. And I think that's sort of the point. With an AJAX widget it really doesn't matter who hosts the HTML file is hosted.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-473589017040167595?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/473589017040167595/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/widget-take-i.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/473589017040167595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/473589017040167595'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/widget-take-i.html' title='Widget (Take I)'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-4656538095419543182</id><published>2008-12-14T09:56:00.000-08:00</published><updated>2008-12-14T10:04:57.304-08:00</updated><title type='text'>The Lapse of The Year</title><content type='html'>&lt;span style="font-style: italic;font-family:times new roman;" &gt;&lt;span style="color: rgb(255, 153, 0);"&gt;SPRING&lt;/span&gt; I am too soft of heart&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;Much to speak ere I depart&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;Ask the summer tide to prove&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;The abundance of my love&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;&lt;span style="color: rgb(255, 102, 0);"&gt;SUMMER&lt;/span&gt; looked for long am I&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;Much shall change or ere I die&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;Prithee take it not amiss&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;Though I weary thee with bliss&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;Laden &lt;span style="color: rgb(255, 102, 0);"&gt;AUTUMN &lt;/span&gt;here I stand&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;Weak of heart and warn of hand&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;Speak the word that sets me free&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;Naught but rest seems good for me&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;Ah shall &lt;span style="color: rgb(255, 102, 0);"&gt;WINTER&lt;/span&gt; mend your case&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;Set your teeth the wind to face&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;Bear the snow down, tread the frost&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:times new roman;" &gt;All is gained when all is lost&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;-&lt;a href="http://en.wikipedia.org/wiki/William_Morris"&gt;William Morris&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-4656538095419543182?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/4656538095419543182/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/lapse-of-year.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4656538095419543182'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4656538095419543182'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/lapse-of-year.html' title='The Lapse of The Year'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-6304966546747036742</id><published>2008-12-13T17:27:00.000-08:00</published><updated>2008-12-13T17:28:50.026-08:00</updated><title type='text'>NextDB.net Google Group</title><content type='html'>&lt;a href="http://nextdb.net"&gt;NextDB.net&lt;/a&gt; now has a google group&lt;br /&gt;&lt;a href="http://groups.google.com/group/nextdb-user"&gt;&lt;br /&gt;http://groups.google.com/group/nextdb-user&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;We are hoping to get some good feedback from our user community. Small but growing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-6304966546747036742?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/6304966546747036742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/nextdbnet-google-group.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6304966546747036742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6304966546747036742'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/nextdbnet-google-group.html' title='NextDB.net Google Group'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-6079822850019150146</id><published>2008-12-09T18:13:00.000-08:00</published><updated>2008-12-09T19:10:34.465-08:00</updated><title type='text'>St. Bride</title><content type='html'>This is a painting titled "St. Bride" by the Scottish painter John Duncan, from 1913.  At the moment, this is my favorite work of art. I was fortunate enough to spend some time reflecting on this painting at the National Gallery in Scotland. It's is surprising that this painting is not more notable, considering how interesting it is (not to mention beautiful).&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iJr6rK5UOFc/ST8mENNJgHI/AAAAAAAAAHA/Pc_aQ-6VeXk/s1600-h/Picture+10.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 433px; height: 365px;" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/ST8mENNJgHI/AAAAAAAAAHA/Pc_aQ-6VeXk/s400/Picture+10.png" alt="" id="BLOGGER_PHOTO_ID_5277979142007652466" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The painting depicts two angels carrying Bridget to Bethlehem to swaddle baby Jesus. It's truly an amazing amalgamation of Christian and Celtic mythology; Briget becomes St. Bride and Christianity synthesizes the ancient beliefs.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:85%;"  &gt;"[The legend] ...goes            further back than the days of the monkish chroniclers who first attempted            to put the disguise of verbal Christian raiment on the most widely-loved            and revered beings of the ancient Gaelic pantheon. Long before the maiden            Brigida… made her fame as a 'daughter of God'… the Gaels worshipped            a Brighde or Bride, goddess of women, of fire, of poetry… one whom            the Druids held in honour as a torch bearer of the eternal light, a            Daughter of the Morning."&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a href="http://patrickgeddes.co.uk/feature_twentyone_ossian.html"&gt;This &lt;/a&gt;is a wonderfully rich posting on the "Celtic Twilight" movement. Apparently &lt;a href="http://en.wikipedia.org/wiki/William_Blake"&gt;William Blake&lt;/a&gt;, JRR Tolkien, and John Duncan shared similar influences. The more I read about this painting, the more I understand why it resonates with me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-6079822850019150146?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/6079822850019150146/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/st-bride.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6079822850019150146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6079822850019150146'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/st-bride.html' title='St. Bride'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_iJr6rK5UOFc/ST8mENNJgHI/AAAAAAAAAHA/Pc_aQ-6VeXk/s72-c/Picture+10.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-2169961328127364913</id><published>2008-12-09T18:04:00.000-08:00</published><updated>2008-12-09T18:12:03.107-08:00</updated><title type='text'>Thoughts and Pimps</title><content type='html'>Wonderful tiled mosaic: "THOUGHT: written words; Spoken words". I took this photo near Rockefeller Center.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_iJr6rK5UOFc/ST8kRJUqxjI/AAAAAAAAAG4/d2ET6yePi-4/s1600-h/IMG_0073.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_iJr6rK5UOFc/ST8kRJUqxjI/AAAAAAAAAG4/d2ET6yePi-4/s400/IMG_0073.JPG" alt="" id="BLOGGER_PHOTO_ID_5277977165280495154" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Early anthropological evidence of pimps (American Museum of Natural History)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_iJr6rK5UOFc/ST8kQoRZkZI/AAAAAAAAAGw/-nLf8nYD6jg/s1600-h/IMG_0068.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 300px; height: 400px;" src="http://1.bp.blogspot.com/_iJr6rK5UOFc/ST8kQoRZkZI/AAAAAAAAAGw/-nLf8nYD6jg/s400/IMG_0068.JPG" alt="" id="BLOGGER_PHOTO_ID_5277977156408414610" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-2169961328127364913?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/2169961328127364913/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/thoughts-and-pimps.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2169961328127364913'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2169961328127364913'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/thoughts-and-pimps.html' title='Thoughts and Pimps'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_iJr6rK5UOFc/ST8kRJUqxjI/AAAAAAAAAG4/d2ET6yePi-4/s72-c/IMG_0073.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-8974834704260811751</id><published>2008-12-09T00:06:00.000-08:00</published><updated>2008-12-09T00:21:02.389-08:00</updated><title type='text'>This is just too easy!</title><content type='html'>Wow, I am amazed how easy it is to wire up my new widget to &lt;a href="http://nextdb.net/"&gt;NextDB.net&lt;/a&gt;. I mean, I really shouldn't be surprised, given we've been developing &lt;a href="http://nextdb.net/"&gt;NextDB&lt;/a&gt; exactly to be this easy, but I'm still stoked. Here is a screenshot of the admin site for my hosted database in NextDB (just created one table for storing the widget data). Next to the admin site, on the right, is my shiny black widget.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_iJr6rK5UOFc/ST4nNbeewcI/AAAAAAAAAGg/DmGYA3WXETM/s1600-h/Picture+7.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 242px;" src="http://4.bp.blogspot.com/_iJr6rK5UOFc/ST4nNbeewcI/AAAAAAAAAGg/DmGYA3WXETM/s400/Picture+7.png" alt="" id="BLOGGER_PHOTO_ID_5277698924992184770" border="0" /&gt;&lt;/a&gt;Here is the whole 10 lines of code I literally cut-and-pasted out of the &lt;a href="http://nextdb.net/docs"&gt;NextDB JS Docs&lt;/a&gt; into my widget's HTML.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iJr6rK5UOFc/ST4nMwQzyQI/AAAAAAAAAGY/LV0Vn_wJCIU/s1600-h/Picture+8.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 160px;" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/ST4nMwQzyQI/AAAAAAAAAGY/LV0Vn_wJCIU/s400/Picture+8.png" alt="" id="BLOGGER_PHOTO_ID_5277698913392118018" border="0" /&gt;&lt;/a&gt;BOOM, press the button on the widget, the data is inserted into the database, and I can even see the row using the &lt;a href="http://nextdb.net/admin"&gt;admin tool&lt;/a&gt;. And there it is! There's my row that I inserted:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iJr6rK5UOFc/ST4pR4_TbBI/AAAAAAAAAGo/GrzbGH-sY8g/s1600-h/Picture+9.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 133px;" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/ST4pR4_TbBI/AAAAAAAAAGo/GrzbGH-sY8g/s400/Picture+9.png" alt="" id="BLOGGER_PHOTO_ID_5277701200657214482" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-8974834704260811751?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/8974834704260811751/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/this-is-just-too-easy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8974834704260811751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/8974834704260811751'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/this-is-just-too-easy.html' title='This is just too easy!'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_iJr6rK5UOFc/ST4nNbeewcI/AAAAAAAAAGg/DmGYA3WXETM/s72-c/Picture+7.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-4563214563559253669</id><published>2008-12-08T23:11:00.000-08:00</published><updated>2008-12-08T23:16:04.324-08:00</updated><title type='text'>Database feeds</title><content type='html'>I had an idea today that boils down to "RSS for Databases". I was inspired by the very geeky act of "server log watching". Basically, whenever you bring up a cool new database app, you wind up watching the logs just to get a blow-by-blow on what your users are doing. Now, obviously log watching is boring, and requires you to be logged in or ssh'd into the server. Why not apply the same "feeds" to the actual data in the database that we use to follow our favorite blogs or news sites? Obviously some filters would be required to avoid a torrent of data in the feed, but that's all do-able. I'm pretty excited about adding RSS Feeds as a native feature for &lt;a href="http://NextDB.net"&gt;NextDB&lt;/a&gt; database tables. I will probably work on it this weekend. At the moment I'm addicted to screwing with a new widget design in Adobe Fireworks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-4563214563559253669?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/4563214563559253669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/database-feeds.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4563214563559253669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4563214563559253669'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/database-feeds.html' title='Database feeds'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-4873675010124922092</id><published>2008-12-07T09:25:00.001-08:00</published><updated>2008-12-07T10:12:16.177-08:00</updated><title type='text'>Widgets!</title><content type='html'>I am in the process of creating a series of widgets that can easily be re-skinned. These widgets will fulfill many basic site functions such as: user sign-up, login, user profile management, photo gallery, blog, forum, etc. Each widget can be easily re-skinned to suit the look and feel of your site, and they are pre-wired to communicate with &lt;a href="http://nextdb.net/"&gt;NextDB.net&lt;/a&gt;. Here is an example of a sign-in widget.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iJr6rK5UOFc/STwHJzQAb8I/AAAAAAAAAGQ/lhEMCIPiOKY/s1600-h/Picture+6.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 315px; height: 400px;" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/STwHJzQAb8I/AAAAAAAAAGQ/lhEMCIPiOKY/s400/Picture+6.png" alt="" id="BLOGGER_PHOTO_ID_5277100728328941506" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-4873675010124922092?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/4873675010124922092/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/widgets.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4873675010124922092'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/4873675010124922092'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/widgets.html' title='Widgets!'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iJr6rK5UOFc/STwHJzQAb8I/AAAAAAAAAGQ/lhEMCIPiOKY/s72-c/Picture+6.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-6885722865942773545</id><published>2008-12-06T16:35:00.000-08:00</published><updated>2008-12-06T16:37:02.717-08:00</updated><title type='text'>Nice blog enrty in Wired</title><content type='html'>Looks like Wired did a &lt;a href="http://blog.wired.com/business/2008/12/database-in-the.html"&gt;blog entry on NextDB&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It's funny, if you look in the comments, there are already haters. They don't even have a clue what NextDB does, or how our security model works. That's a good sign. Haters are scared of change.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-6885722865942773545?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/6885722865942773545/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/nice-blog-enrty-in-wired.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6885722865942773545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/6885722865942773545'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/nice-blog-enrty-in-wired.html' title='Nice blog enrty in Wired'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-1456007473749517055</id><published>2008-12-06T08:54:00.000-08:00</published><updated>2008-12-06T09:04:24.938-08:00</updated><title type='text'>Big week for NextDB.net</title><content type='html'>On Thursday, &lt;a href="http://www.programmableweb.com/profile/andres"&gt;Andres Ferrate&lt;/a&gt;, posted &lt;a href="http://blog.programmableweb.com/2008/12/05/mashups-get-a-hosted-database-with-nextdbnet/"&gt;this&lt;/a&gt; article on Programmable Web titled "Mashups Get a Hosted Database With NextDB.net". We also got &lt;a href="http://www.programmableweb.com/api/nextdb"&gt;an entry on Programmable Web&lt;/a&gt; about our &lt;a href="http://www.nextdb.net/docs/"&gt;JavaScript API&lt;/a&gt;.  Very quickly the wave of account signups poured in and it hasn't crested yet. I guess this a moment that every small startup has to cope with. Fortunately both Brent and I have been there before but it never gets old. You can't keep your eyes off the server logs, and it's almost a point of pride when you hit "Too many open files" and need to kick a "ulimit -n", which in fact happened yesterday as dozens of new databases were created on NextDB.net. Well, it's not exactly what I'd call being slashdotted, but it was a fun ride. Our challenge now, is how to effectively collect feedback from these Alpha users in order to improve the service based on their experience.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-1456007473749517055?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/1456007473749517055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/big-week-for-nextdbnet.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1456007473749517055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/1456007473749517055'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/12/big-week-for-nextdbnet.html' title='Big week for NextDB.net'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-608833706623416423</id><published>2008-11-26T17:01:00.001-08:00</published><updated>2008-11-26T21:51:58.348-08:00</updated><title type='text'>SF Park</title><content type='html'>The new SF skatepark is pretty rad. It is growing on me. Here is some footy of parker I took on my point-and-shoot. This park is crowded. Note near collision with fat kid on bike (listen for the yell).&lt;br /&gt;&lt;object width="320" height="266" class="BLOG_video_class" id="BLOG_video-70b62568f9e03b7" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"&gt;&lt;param name="movie" value="http://www.youtube.com/get_player"&gt;&lt;param name="bgcolor" value="#FFFFFF"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="flashvars" value="flvurl=http://v23.nonxt7.googlevideo.com/videoplayback?id%3D070b62568f9e03b7%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1331461744%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D68F939ADB0ADA036BB1B45EC22FBFCF3D1E1BC63.372EE4BD574F2D92F1F0D1668418291D2DF9696A%26key%3Dck1&amp;amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D70b62568f9e03b7%26offsetms%3D5000%26itag%3Dw160%26sigh%3D26g9pjS0HD5ZNU77MRX-hJJwQAc&amp;amp;autoplay=0&amp;amp;ps=blogger"&gt;&lt;embed src="http://www.youtube.com/get_player" type="application/x-shockwave-flash"width="320" height="266" bgcolor="#FFFFFF"flashvars="flvurl=http://v23.nonxt7.googlevideo.com/videoplayback?id%3D070b62568f9e03b7%26itag%3D5%26app%3Dblogger%26ip%3D0.0.0.0%26ipbits%3D0%26expire%3D1331461744%26sparams%3Did,itag,ip,ipbits,expire%26signature%3D68F939ADB0ADA036BB1B45EC22FBFCF3D1E1BC63.372EE4BD574F2D92F1F0D1668418291D2DF9696A%26key%3Dck1&amp;iurl=http://video.google.com/ThumbnailServer2?app%3Dblogger%26contentid%3D70b62568f9e03b7%26offsetms%3D5000%26itag%3Dw160%26sigh%3D26g9pjS0HD5ZNU77MRX-hJJwQAc&amp;autoplay=0&amp;ps=blogger"allowFullScreen="true" /&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-608833706623416423?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='enclosure' type='video/mp4' href='http://www.blogger.com/video-play.mp4?contentId=70b62568f9e03b7&amp;type=video%2Fmp4' length='0'/><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/608833706623416423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/sf-park.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/608833706623416423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/608833706623416423'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/sf-park.html' title='SF Park'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-5285253095250179451</id><published>2008-11-26T16:53:00.000-08:00</published><updated>2008-11-26T21:54:23.149-08:00</updated><title type='text'>Read-End....</title><content type='html'>It doesn't seem to bother anyone else in the office that when you place a page on the copy machine, and hit the big green "copy" button, that this message appears:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_iJr6rK5UOFc/SS3wG3ih7eI/AAAAAAAAAGI/uYy1KFJF47k/s1600-h/IMG_0129.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 360px; height: 270px;" src="http://4.bp.blogspot.com/_iJr6rK5UOFc/SS3wG3ih7eI/AAAAAAAAAGI/uYy1KFJF47k/s400/IMG_0129.jpg" alt="" id="BLOGGER_PHOTO_ID_5273134739499380194" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;READ-END? WTF is READ-END? This copy machine can send emails, but they can't just make it copy a page when you hit the green button?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-5285253095250179451?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/5285253095250179451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/read-end.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5285253095250179451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5285253095250179451'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/read-end.html' title='Read-End....'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_iJr6rK5UOFc/SS3wG3ih7eI/AAAAAAAAAGI/uYy1KFJF47k/s72-c/IMG_0129.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-7569340007680185430</id><published>2008-11-18T15:56:00.000-08:00</published><updated>2008-11-18T17:21:19.442-08:00</updated><title type='text'>Steve's Feedback on our UI</title><content type='html'>lots of issues with the "new user" concept. First time someone signs in have obvious links to getting started guide, creating a sample database, etc.&lt;br /&gt;&lt;br /&gt;"import" has too much meaning to db guys. Make it say "create a sample database from template" WITH data.&lt;br /&gt;&lt;br /&gt;"must match regex in" in tablename is not a good error message for invalid table names.&lt;br /&gt;&lt;br /&gt;Suggested "nextdb for SQL database programmers".&lt;br /&gt;&lt;br /&gt;Wants to know how to create the primary key.&lt;br /&gt;&lt;br /&gt;Some kind of wizard to drive first time users.&lt;br /&gt;&lt;br /&gt;tooltips on tabs with check box for "never show this again"&lt;br /&gt;&lt;br /&gt;consider changing the query language parameter names and datatype names to 'human friendly' equivalents.&lt;br /&gt;&lt;br /&gt;Steve would like to be able to set the default value.&lt;br /&gt;&lt;br /&gt;wants to be able to use camel case in column names&lt;br /&gt;&lt;br /&gt;relation name should be "relationship name". It also upper cases it.&lt;br /&gt;&lt;br /&gt;show lines connecting related tables as an option.&lt;br /&gt;&lt;br /&gt;thought he could not enter a query without having data.&lt;br /&gt;&lt;br /&gt;did not like the interface for adding data.&lt;br /&gt;&lt;br /&gt;wants a "data editor" tab along the top (loads table names along left hand side)&lt;br /&gt;&lt;br /&gt;wants column types to be in parentheses.&lt;br /&gt;&lt;br /&gt;Steve wants to be able to store HTML and edit it with a foldout editor. I want permalinks to the HTML and JS.&lt;br /&gt;&lt;br /&gt;Great idea&lt;br /&gt;&lt;br /&gt;trouble executing query with join&lt;br /&gt;&lt;br /&gt;no way to relate rows&lt;br /&gt;&lt;br /&gt;wants excel spreadsheet&lt;br /&gt;&lt;br /&gt;wants a way to get his data out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-7569340007680185430?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/7569340007680185430/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/steves-feedback-on-our-ui.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7569340007680185430'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/7569340007680185430'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/steves-feedback-on-our-ui.html' title='Steve&apos;s Feedback on our UI'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-2230422953358092017</id><published>2008-11-18T10:41:00.001-08:00</published><updated>2008-11-18T11:01:27.759-08:00</updated><title type='text'>"You wouldn't want a mashup for your bank account."</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iJr6rK5UOFc/SSMPqqBG7HI/AAAAAAAAAGA/OTRB2jXyIEY/s1600-h/IMG_0131.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/SSMPqqBG7HI/AAAAAAAAAGA/OTRB2jXyIEY/s400/IMG_0131.JPG" alt="" id="BLOGGER_PHOTO_ID_5270073214461471858" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I am watching the opening panel discussion at Mashup Camp. Hart Rossman, CTO at SAIC just said &lt;span style="font-weight: bold; font-style: italic;"&gt;"You wouldn't want a mashup for your bank account."&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;That really struck a chord because it captures the inadequacy with today's mashup security model. In fact, building a banking system on &lt;a href="http://nextdb.net/"&gt;NextDB &lt;/a&gt;is sort of the logical extent of where the NextDB SURID technology can go.&lt;br /&gt;&lt;br /&gt;Another interesting statement from one of the panelists:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-weight: bold;"&gt;"SLAs can't be that strong because you can't have really strong remedies."&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;I agree&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-weight: bold;"&gt;.&lt;br /&gt;&lt;br /&gt;"you're not going to get a new CRM system out of a mashup."&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;I disa&lt;/span&gt;&lt;span&gt;gree. Once the database is secure and mashable, the entire application software development lifecycle can be handled by mashups.&lt;br /&gt;&lt;br /&gt;The proverbial Map Mashup came up again as a proof point for time savings.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;"when the users become the developers, they are doing what they want to do, not what IT wants to do"&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;br /&gt;The discussion briefly touched on whether or not Amazon Web Services (S3) constitutes a mashup. That's really a point that requires discussion. Once you realize that Amazon Web Services is not Mashable, due to its "web 1.0 security model", you find yourself somewhat dissapointed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;"where we run into a real challenge is in converting the mashup mentality into the largescale systems engineering skillset. You don't see a lot of folks puting a large ampount of skill and discipline into building the backend."&lt;/span&gt; paraphrasing what he said later: We're going to see things going in that direction though, and it will drive Mashups into the enterprise.&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold; font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-style: italic;"&gt;&lt;span style="font-weight: bold;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-2230422953358092017?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/2230422953358092017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/you-wouldnt-want-mashup-for-your-bank.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2230422953358092017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/2230422953358092017'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/you-wouldnt-want-mashup-for-your-bank.html' title='&quot;You wouldn&apos;t want a mashup for your bank account.&quot;'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_iJr6rK5UOFc/SSMPqqBG7HI/AAAAAAAAAGA/OTRB2jXyIEY/s72-c/IMG_0131.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-5776238586258504027</id><published>2008-11-16T08:55:00.000-08:00</published><updated>2009-01-15T10:09:02.771-08:00</updated><title type='text'>Mashup Camp 2008</title><content type='html'>Tomorrow is &lt;a href="http://www.mashupcamp.com/"&gt;Mashup Camp&lt;/a&gt;! I'm excited about this year's Mashup Camp because I think there is going to be a lot of activity around trying to figure out how to fuse mashups with Cloud Computing. And that, of course, is exactly where NextDB.net has a sweet spot. NextDB is fundamentally a mashable relational database in the cloud. What does that mean for the programmer? It means &lt;a href="http://nextdb.net/"&gt;NextDB &lt;/a&gt;is the ONLY relational database that you can securely mashup, without have to write ANY serverside code.&lt;br /&gt;&lt;br /&gt;So check this out. I added this "guest book" to my blog to keep track of folks I meet at Mashup Camp. This guestbook is a Mashup with &lt;a href="http://nextdb.net/"&gt;NextDB.net,&lt;/a&gt; which makes it a nice little example of a database mashup between &lt;a href="http://nextdb.net/"&gt;NextDB&lt;/a&gt; and blogger.com. Originally, Brent wrote this guestbook as an example for&lt;a href="http://ajaxworld.com/event/session/33"&gt; our talk at ajaxworld&lt;/a&gt;.  I just went to&lt;a href="http://www.brenthamby.com/ajaxworld.html"&gt; his page&lt;/a&gt;, grabbed the html, js, and css and threw them into my blog. The only tricky part was that blogger.com's editor didn't like newline characters in the HTML and CSS. So I just saved them in a file without newlines, and pasted them back to my blog. &lt;span style="font-weight: bold;"&gt;Go ahead and sign in below, and watch the AJAX goodness! &lt;/span&gt;Here is &lt;a href="http://nextdb.projectpath.com/projects/1874408/file/22019069/guestlist.js"&gt;a link to the JavaScript that the guestbook sources&lt;/a&gt;. Rather than use the nasty editor at blogger.com (and its associated issues with spaces), I just uploaded the js file to Project Path, which is a nifty collaboration site that allows file hosting.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Mashup Camp Guestbook&lt;/span&gt;&lt;br /&gt;&lt;style&gt;  &lt;!--body {font-size:10pt;font-family:arial;color:#333333;}div.panel{padding:10px;}div.success{color:green;font-size:10pt;}div.failure{color:red;font-size:10pt;}.odd{background-color:#eeeeee;}.even{background-color:#cccccc;}hr{background-color:#99cc66;border:1px solid #99cc66;}input.button{background-color:#99cc66;color:#ffffff;}input.text{padding:2px;color:#008F00;width:170px;border:1px solid #99cc66;background-color:#eeeeee;}table.attendees{border:1px solid #cccccc;}th{padding:4px;}td{padding-left:4px;}td.separate{padding-left:40px;}  --&gt;&lt;/style&gt;&lt;div class="panel"&gt;  &lt;div id="output" class="output"&gt;&lt;/div&gt;  &lt;table&gt;    &lt;tbody&gt;&lt;tr&gt;      &lt;td valign="top"&gt;        &lt;table&gt;          &lt;tbody&gt;&lt;tr&gt;            &lt;td&gt;              first name *            &lt;/td&gt;            &lt;td&gt;              &lt;input class="text" id="first_name" type="text"&gt;            &lt;/td&gt;          &lt;/tr&gt;          &lt;tr&gt;            &lt;td&gt;              last name *            &lt;/td&gt;            &lt;td&gt;              &lt;input class="text" id="last_name" type="text"&gt;            &lt;/td&gt;          &lt;/tr&gt;          &lt;tr&gt;            &lt;td&gt;              email            &lt;/td&gt;            &lt;td&gt;              &lt;input class="text" id="email" type="text"&gt;            &lt;/td&gt;          &lt;/tr&gt;          &lt;tr&gt;            &lt;td&gt;              comments            &lt;/td&gt;            &lt;td&gt;              &lt;input class="text" id="comments" type="text"&gt;            &lt;/td&gt;          &lt;/tr&gt;          &lt;tr&gt;            &lt;td&gt;         &lt;br /&gt;&lt;/td&gt;            &lt;td&gt;              &lt;img src="http://www.blogger.com/post-edit.g?blogID=32093290&amp;amp;postID=5776238586258504027" id="captchaimg" onclick="setCaptcha();" style="width: 170px; height: 50px;" /&gt;&lt;br /&gt;&lt;span style="font-family:lucida grande;"&gt;Enter the text above into the box below. Click image to get a new one if you can't read it.&lt;/span&gt;&lt;br /&gt;  &lt;/td&gt;          &lt;/tr&gt;          &lt;tr&gt;            &lt;td&gt;         &lt;br /&gt;&lt;/td&gt;            &lt;td&gt;              &lt;input class="text" id="captcha" type="text"&gt;            &lt;/td&gt;          &lt;/tr&gt;          &lt;tr&gt;            &lt;td&gt;  &lt;br /&gt;&lt;/td&gt;            &lt;td&gt;              &lt;input class="button" onclick="insert(); return false;" value="signin" type="button"&gt;            &lt;/td&gt;          &lt;/tr&gt;        &lt;/tbody&gt;&lt;/table&gt;      &lt;/td&gt;      &lt;td class="separate" valign="top"&gt;        json view: &lt;input id="show-json" onclick="getAttendees();" type="checkbox"&gt;&lt;br /&gt;&lt;br /&gt;&lt;div id="attendees" style="width: 400px;"&gt;&lt;/div&gt;      &lt;/td&gt;    &lt;/tr&gt;  &lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;!--script src="http://www.nextdb.net/api.js"&gt;&lt;/script&gt;&lt;script src="http://nextdb.projectpath.com/projects/1874408/file/22079005/guestlist.js"&gt;&lt;/script--&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-5776238586258504027?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/5776238586258504027/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/mashup-camp-2008.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5776238586258504027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5776238586258504027'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/mashup-camp-2008.html' title='Mashup Camp 2008'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-103895535889576947</id><published>2008-11-12T09:27:00.001-08:00</published><updated>2010-02-21T10:33:00.129-08:00</updated><title type='text'>NextDB At AjaxWorld 2008 West</title><content type='html'>Brent and I recently presented about &lt;a href="http://nextdb.net"&gt;NextDB.net&lt;/a&gt; at AjaxWorld 2008 West, in San Jose CA.&lt;br /&gt;&lt;br /&gt;I am going to pickup blogging a bit more regularly here. Anyway, the presentation went well. The message we hammered on was that NextDB has a fundamentally new security model that allows a hosted relational database to be exposed as a service. NextDB is the only relational database that is built from the ground up as a AJAX-programmable hosted service. As such, the round-trip security model is native; fundamentally "built in". This clearly differentiates NextDB from other pseudo-database or database services, because you can safely access it directly from JavaScript.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-103895535889576947?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/103895535889576947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/nextdb-at-ajaxworld-2008-west.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/103895535889576947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/103895535889576947'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/nextdb-at-ajaxworld-2008-west.html' title='NextDB At AjaxWorld 2008 West'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-5101225199235306691</id><published>2008-11-10T18:39:00.000-08:00</published><updated>2008-11-14T10:21:08.730-08:00</updated><title type='text'>New York Family Vacation 2008</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_iJr6rK5UOFc/SRkRYpjrWUI/AAAAAAAAAFU/S6bUfeGVSlk/s1600-h/IMG_0015.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 300px; height: 400px;" src="http://1.bp.blogspot.com/_iJr6rK5UOFc/SRkRYpjrWUI/AAAAAAAAAFU/S6bUfeGVSlk/s400/IMG_0015.JPG" alt="" id="BLOGGER_PHOTO_ID_5267260354356533570" border="0" /&gt;&lt;/a&gt;Times Square&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iJr6rK5UOFc/SRkRYU4a8-I/AAAAAAAAAFM/8_xEE_Ju3KU/s1600-h/IMG_0012.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 300px; height: 400px;" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/SRkRYU4a8-I/AAAAAAAAAFM/8_xEE_Ju3KU/s400/IMG_0012.JPG" alt="" id="BLOGGER_PHOTO_ID_5267260348806394850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iJr6rK5UOFc/SRkP7QeCV8I/AAAAAAAAAFE/MXxwiKJTDQI/s1600-h/IMG_0119.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 300px; height: 400px;" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/SRkP7QeCV8I/AAAAAAAAAFE/MXxwiKJTDQI/s400/IMG_0119.JPG" alt="" id="BLOGGER_PHOTO_ID_5267258749894154178" border="0" /&gt;&lt;/a&gt;Radio City Music Hall Christmas Spectacular stage&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iJr6rK5UOFc/SRkP7Wp1XLI/AAAAAAAAAE8/k3tTyhSddbk/s1600-h/IMG_0087.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 300px; height: 400px;" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/SRkP7Wp1XLI/AAAAAAAAAE8/k3tTyhSddbk/s400/IMG_0087.JPG" alt="" id="BLOGGER_PHOTO_ID_5267258751554247858" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iJr6rK5UOFc/SRkP69BkkYI/AAAAAAAAAE0/P7NCxXV4LWs/s1600-h/IMG_0081.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/SRkP69BkkYI/AAAAAAAAAE0/P7NCxXV4LWs/s400/IMG_0081.JPG" alt="" id="BLOGGER_PHOTO_ID_5267258744674488706" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_iJr6rK5UOFc/SRkPOqSdayI/AAAAAAAAAEs/UaAlncVbDRc/s1600-h/IMG_0102.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 300px; height: 400px;" src="http://3.bp.blogspot.com/_iJr6rK5UOFc/SRkPOqSdayI/AAAAAAAAAEs/UaAlncVbDRc/s400/IMG_0102.JPG" alt="" id="BLOGGER_PHOTO_ID_5267257983730805538" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_iJr6rK5UOFc/SRkOZZxJ9UI/AAAAAAAAAEU/mgQTNakMdkA/s1600-h/IMG_0034.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 300px;" src="http://2.bp.blogspot.com/_iJr6rK5UOFc/SRkOZZxJ9UI/AAAAAAAAAEU/mgQTNakMdkA/s400/IMG_0034.JPG" alt="" id="BLOGGER_PHOTO_ID_5267257068763084098" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_iJr6rK5UOFc/SRkOMyhJfKI/AAAAAAAAAEM/5yxVFU8Vz2s/s1600-h/IMG_0019.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 300px; height: 400px;" src="http://4.bp.blogspot.com/_iJr6rK5UOFc/SRkOMyhJfKI/AAAAAAAAAEM/5yxVFU8Vz2s/s400/IMG_0019.JPG" alt="" id="BLOGGER_PHOTO_ID_5267256852068531362" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-5101225199235306691?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/5101225199235306691/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/new-york-family-vacation-2008.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5101225199235306691'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/5101225199235306691'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2008/11/new-york-family-vacation-2008.html' title='New York Family Vacation 2008'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_iJr6rK5UOFc/SRkRYpjrWUI/AAAAAAAAAFU/S6bUfeGVSlk/s72-c/IMG_0015.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-116235485179021567</id><published>2006-10-31T20:04:00.000-08:00</published><updated>2006-10-31T20:34:58.950-08:00</updated><title type='text'>Why detachment sucks</title><content type='html'>Ahhh, yes, detachment. The idea that you must explicitely "detach" a persistent POJO from its persistence manager, and later explicitly attach it.&lt;br /&gt;&lt;br /&gt;Detachment is another opaque feature of so-called Transparent Object Persistence.&lt;br /&gt;&lt;br /&gt;Basically detachment is a work around for the fact that the JDO PersistenceManager is not itself serializable. So, when your Page, with your so-called POJO gets serialized, "oh ma god", you can't serialize your pojo. (that would be TOO SIMPLE, TOO POJO). NOOOO, you've got to implement a callback in which you detach your POJO before you serialize it.&lt;br /&gt;&lt;br /&gt;The worst part of it is, this totally defeats the point of serializing the page. You see, in Wicket, they are serializing the Page and things on the page to keep the server from bloating with lots of concurrent clients. But wait a sec, if the PersistenceManager has a cache of POJO's, isn't that cache going to be full of those very POJO's your trying to serialize. Right, but you can't serialize the PersistenceManager.......OK, right, so how do you keep things trim. So you , um "detach" from the persistence manager, and serialize your detached POJO. In the mean time, you have allowed your PersistenceManager to get garbage collected. Had to, otherwise there was no point in serializing your POJO's. I mean, you can't keep the whole cache of 'em lying around in memory. (and even if you keep your PersistenceManager around, it's not a real cache. If you've serialized out your POJO, it ain't gonna be in the cache when you deserialize the POJO. NOPE, it the POJO will have been garbage collected from the PersistenceManager, because the PM is a pseudo cache, with WeakReferences, not a hard cache).&lt;br /&gt;&lt;br /&gt;So, the architecture of detachment is fundamentally at odds with the notion of a cache. So when you re-attach, whoops, you have no cache. Been garbage collected. Nice knowing you. Bye bye cache.&lt;br /&gt;&lt;br /&gt;the solution to this, is to have a persistence manager that IS serializable, which is what Shades has. And shades doesn't have a pseudo-cache that's subject to garbage collection EVEN when you STILL HAVE references to the PersistenceManager. Shades has a REAL CACHE, with HARD REFERENCES to clean values for all the loaded fields of your pojo, for dirty checking when you do updates.  So you can serialize the POJO's with OR without also serializing the DatabaseSession (shades' version of a PersistenceManager, is called the DatabaseSession).&lt;br /&gt;&lt;br /&gt;If there is a downside to the Shades way of doing business, its that you have to manage the cache explicitely. Shades has a simple method, "clear()" in the DatabaseSession. My take on it, is that it's one hell of a lot easier to clear the database session after the user hits the SAVE button, or just allow the DatabaseSession to be garbage collected, forget about it, and create a new one for your next sequence of CRUD operations, than it is to work with a  pseudo cache.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-116235485179021567?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/116235485179021567/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2006/10/why-detachment-sucks.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/116235485179021567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/116235485179021567'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2006/10/why-detachment-sucks.html' title='Why detachment sucks'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-115842039662195660</id><published>2006-09-16T08:23:00.000-07:00</published><updated>2006-09-16T08:26:36.633-07:00</updated><title type='text'>some skate pics</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/1334/3501/1600/fsSmith.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://photos1.blogger.com/blogger/1334/3501/320/fsSmith.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Smithgrind at the Crib Ramp&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://photos1.blogger.com/blogger/1334/3501/1600/noseblunt.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://photos1.blogger.com/blogger/1334/3501/320/noseblunt.jpg" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;frontside noseblunt slide at 3rd and Army&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-115842039662195660?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/115842039662195660/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2006/09/some-skate-pics.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115842039662195660'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115842039662195660'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2006/09/some-skate-pics.html' title='some skate pics'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-115795156956491319</id><published>2006-09-10T22:05:00.000-07:00</published><updated>2006-09-10T23:14:52.776-07:00</updated><title type='text'>immutable queries</title><content type='html'>I got some feedback (see previous blog entry comments) that prompted me to implement "immutable queries". These are queries in which the SQL is 100% specified by the user.&lt;br /&gt;&lt;br /&gt;          String expr = "SELECT FNAME AS FNAME FROM STUDENT";&lt;br /&gt;          Query q = QueryFactory.newImmutableQuery(expr);&lt;br /&gt;          RecordCandidate cand = q.candidate(dict.getORM("STUDENT"));&lt;br /&gt;          cand.setFetchColumns("FNAME");&lt;br /&gt;          List students = new ArrayList();&lt;br /&gt;          sess.executeQuery(connection,q).populateList(students, Student.class);&lt;br /&gt;          System.out.println(students);&lt;br /&gt;&lt;br /&gt;Of course it is still parameterizable, like this:&lt;br /&gt;&lt;br /&gt;        String expr="SELECT FNAME AS FNAME FROM STUDENT WHERE "+&lt;br /&gt;                               "LNAME LIKE ${lname}";&lt;br /&gt;           Query q = QueryFactory.newImmutableQuery(expr);&lt;br /&gt;          RecordCandidate cand = q.candidate(dict.getORM("STUDENT"));&lt;br /&gt;           cand.setFetchColumns("FNAME");&lt;br /&gt;           List students = new ArrayList();&lt;br /&gt;            sess.setParameter("lname", "smith");&lt;br /&gt;          sess.executeQuery(connection,q).populateList(students, Student.class);&lt;br /&gt;           System.out.println(students);&lt;br /&gt;&lt;br /&gt;I'll update the Shades download sometime next week.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-115795156956491319?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/115795156956491319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2006/09/immutable-queries.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115795156956491319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115795156956491319'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2006/09/immutable-queries.html' title='immutable queries'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-115761224048166569</id><published>2006-09-06T23:55:00.000-07:00</published><updated>2006-09-06T23:57:20.496-07:00</updated><title type='text'>sourceforge project</title><content type='html'>I just created a project on sourceforge:&lt;br /&gt;&lt;a href="http://sourceforge.net/projects/shadesdb"&gt;http://sourceforge.net/projects/shadesdb&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;check it out!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-115761224048166569?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/115761224048166569/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2006/09/sourceforge-project.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115761224048166569'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115761224048166569'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2006/09/sourceforge-project.html' title='sourceforge project'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-115671161752389056</id><published>2006-08-27T13:46:00.000-07:00</published><updated>2006-08-27T13:51:04.293-07:00</updated><title type='text'>Questions from the Wicket world</title><content type='html'>&lt;pre style="font-family: arial;"&gt;Here are some answers to questions that came up on the Wicket user list, about using Shades with the Wicket "library example"&lt;br /&gt;&lt;br /&gt;1) how to do concise queries:&lt;br /&gt;&lt;br /&gt;Usually the query is defined in the ORMDictionary. In&lt;br /&gt;the example I showed, I defined the query on-the-fly.&lt;br /&gt;Most of the time you would just grab a query from the&lt;br /&gt;dicitonary. So it's this concise:&lt;br /&gt;&lt;br /&gt;dbSess.setParameter("author", "william gibson");&lt;br /&gt;dbSess.executeQuery(conn, dict.getQuery("q-by-auth"))&lt;br /&gt;&lt;br /&gt;2) how to do arbitrarily complex joins:&lt;br /&gt;&lt;br /&gt;There is no limit on how deep or complex the joins can&lt;br /&gt;be with Shades. Here is an example where we setup a&lt;br /&gt;query to find all books published by whatever&lt;br /&gt;publisher publishes the works of William Gibson.&lt;br /&gt;(again bear in mind that usually we would just grab&lt;br /&gt;this query from the dictionary, I am only defining it&lt;br /&gt;inline to be illustrative).&lt;br /&gt;&lt;br /&gt;aBook.relatedTo(anAuthor,"book-&gt;author");&lt;br /&gt;aBook.where("AUTHOR like 'william gibson');&lt;br /&gt;aBook.relatedTo(aPublisher,"book&lt;-&gt;publisher");&lt;br /&gt;anotherBook.relatedTo(aPublisher, "book&lt;-&gt;publisher");&lt;br /&gt;query.setFetchGroups(anotherBook);&lt;br /&gt;dbSess.excecuteQuery(conn, q);&lt;br /&gt;&lt;br /&gt;3) performance&lt;br /&gt;&lt;br /&gt;Ahhh, I am especially stoked on this. Shades uses&lt;br /&gt;batch updates and the other tricks common to ORM's. I&lt;br /&gt;learned most of these tricks doing JDOMax. I think the&lt;br /&gt;biggest reason shades has good performance is because&lt;br /&gt;the codebase is so tight. When it comes to defining&lt;br /&gt;queries on the fly, shades will be better than any&lt;br /&gt;language that compiles a query (for example JDOQL),&lt;br /&gt;because Shades bypasses the parse phase, and the&lt;br /&gt;translation of the AST from JDOQL to SQL. Shades does&lt;br /&gt;query caching like any other ORM. &lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-115671161752389056?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/115671161752389056/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2006/08/questions-from-wicket-world.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115671161752389056'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115671161752389056'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2006/08/questions-from-wicket-world.html' title='Questions from the Wicket world'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-115663086886736600</id><published>2006-08-26T15:15:00.000-07:00</published><updated>2006-08-27T12:12:37.896-07:00</updated><title type='text'>I'm a lover not a fighter</title><content type='html'>I've been asked, rightly so,  if Shades is 'better' than Hibernate or JDO implementations or EJB 3. The answer is no. It is not better. But it is different. It's also new, so it doubtless has too many bugs to even dream of playing in the same spaces as the excellent products like Kodo, Cocobase, and others, that implement a variety of standards.&lt;br /&gt;&lt;br /&gt;What I want to say, is that I didn't write Shades for anyone else's benefit. I wrote Shades because software, for me, is fun to write. It relaxes my mind after a long day at work, and let's me play with puzzles and art all rolled into one. It's not a competition, especially since I don't get paid!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-115663086886736600?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/115663086886736600/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2006/08/im-lover-not-fighter.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115663086886736600'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115663086886736600'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2006/08/im-lover-not-fighter.html' title='I&apos;m a lover not a fighter'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-115662933723452355</id><published>2006-08-26T14:20:00.000-07:00</published><updated>2006-08-27T10:08:58.050-07:00</updated><title type='text'>Queries</title><content type='html'>Shades has an interesting way of doing queries. It's based on the idea of a RecordCandidate. I find it much easier to explain this using code than with a paragraph.&lt;br /&gt;&lt;br /&gt;The following code returns all the Books, in a List;&lt;br /&gt;&lt;br /&gt;ORMDictionary dict = MyORMDict.getInstance();&lt;br /&gt;Query query = QueryFactory.newQuery(dict);&lt;br /&gt;RecordCandidate aBook = query.candidate(dict.getORM("BOOK"), "aBook");&lt;br /&gt;RecordSet rs =  dbSession.executeQuery(jdbcConn, query);&lt;br /&gt;List books = new ArrayList();&lt;br /&gt;rs.populateList(books, Book.class);&lt;br /&gt;&lt;br /&gt;There are several cool things:&lt;br /&gt;1) The books got put into MY list (not a proxy List created by the data access framework).&lt;br /&gt;2) There is no query language. Shades uses a new form of query-by-example. In the example&lt;br /&gt;above the query is told what to retrieve by requesting a candidate.&lt;br /&gt;3) I passed the jdbcConnection into the query (This means I control transactions using the JDBC transaction model).&lt;br /&gt;&lt;br /&gt;Why did we request a RecordCandidate if we did didn't use it for anything. Well OK then, let's use it for something. In the query below we retrieve only the books authored by william gibson.&lt;br /&gt;&lt;br /&gt;ORMDictionary dict = MyORMDict.getInstance();&lt;br /&gt;Query query = QueryFactory.newQuery(dict);&lt;br /&gt;RecordCandidate aBook = query.candidate(dict.getORM("BOOK"), "aBook");&lt;br /&gt;RecordCandidate anAuthor = query.candidate(dict.getORM("AUTHOR"), "anAuthor");&lt;br /&gt;anAuthor.where("NAME like 'william Gibson'");&lt;br /&gt;aBook.relatedTo(anAuthor, "book-&gt;author");&lt;br /&gt;RecordSet rs =  dbSession.executeQuery(jdbcConn, query);&lt;br /&gt;List books = new ArrayList();&lt;br /&gt;rs.populateList(books, Book.class);&lt;br /&gt;&lt;br /&gt;Shades let you bust into a query and insert your own SQL. You can see that on the line above that says "anAuthor.where...""&lt;br /&gt;Dangerous? maybe, but fear not. shades encourages you to encapsulate your queries inside the ORMDictionary, and to parameterize them. Once yo've done that, there is no hint of SQL in the code, which subsequently looks like this:&lt;br /&gt;&lt;br /&gt;ORMDictionary dict = MyORMDict.getInstance();&lt;br /&gt;dbSession.setParameter("authorName", "william gibson");&lt;br /&gt;RecordSet rs =  dbSession.executeQuery(jdbcConn, dict.getQuery("query:book-by-auth"));&lt;br /&gt;List books = new ArrayList();&lt;br /&gt;rs.populateList(books, Book.class);&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here is another very cool thing about Shades queries. They, by default, return ALL the candidates that participate in the relationship graph. So in fact, you can retrieve the Book AND its author from the RecordSet, like this:&lt;br /&gt;&lt;br /&gt;Book book = new Book();&lt;br /&gt;Author author = new Author();&lt;br /&gt;while(rs.hasNext()){&lt;br /&gt; rs.populate(book, aBook);&lt;br /&gt; rs.populate(author,anAuthor );&lt;br /&gt; System.out.println(book.title +" was authored by " + author.name);&lt;br /&gt;}&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-115662933723452355?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/115662933723452355/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2006/08/queries.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115662933723452355'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115662933723452355'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2006/08/queries.html' title='Queries'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-115622390093951162</id><published>2006-08-21T21:32:00.000-07:00</published><updated>2006-08-21T22:28:23.416-07:00</updated><title type='text'>cool things about shades</title><content type='html'>One of the most confusing aspects of persistence frameworks is persistant identity. Equals and hashcode typically must be implemented so that Object equalty amounts to a comparison between identity columns of the persistent instance. Since datastore identity is often implemented using autoincrementing primary keys, this leads to a framework dilema: to expose datastore identity in the pojo, or not. Some persistence frameworks force the pojo to hold onto the PK. Other frameworks use bytecode instrumentation to make it transparent.&lt;br /&gt;&lt;br /&gt;The situation is arguably simpler for "Object Identity". It is assumed that "Object Identity", as opposed to datastore identity, means that a unique set of column values is mirrored in the pojo's fields. So the pojo naturally posseses as set of fields, that taken together uniquely identify the record in the datastore. Here we again find ourselves bitten by the false equivalence between a pojo in memory, and a record in the database. Remember, equals and hashcode must be overridden to use exactly the identity fields of the Object. This makes it extremely tricky to support "change of identity" during a transaction.&lt;br /&gt;&lt;br /&gt;In implementing JDOMax I learned a lot about this issue. Change of identity is actually very common: changing a "User" Object's 'username' field, for example. Because most frameworks for transparent object persistence keep a cache, change of identity can have a devastating and unexpected effect on this cache. Because, equals and hashcode suddenly return different values at different times during the transaction, the cached pojos can appear to "dissappear" from cache.&lt;br /&gt;&lt;br /&gt;So one of my biggest issues with ORMapping that claims to be transparent is that it ain't transparent. If I have to override equals and hashCode in a particular way, the mapping is not transparent.&lt;br /&gt;&lt;br /&gt;Unlike any other O/R Mapping system that I know of, Shades does not impose any restrictions on how you have implement equals and hashcode. In fact, it doesn't care at all. Shades has a dynamic ORMapping system, as opposed to a static mapping. You can query a record from the database, and load it into a pojo whose equals and hashcode depends only on the 'lastname' field of the pojo. In the same transaction you can load a second record from the table into a pojo whose equals and hashcode depend only on "firstname". You can change the firstname or the lastname field of either pojo, during the same transaction. You can load a third record into yet another pojo whose equals and hashode depend on NONE of the fields of the object. Modifications to the objects are transparently tracked and flushed out to the database on a call to 'update'.&lt;br /&gt;&lt;br /&gt;Shades provides a dynamic ORMapping system, in which an ORMapping can be created or chosen, at runtime, to perform I/O from table to pojo. This has an advantage of allowing the "identity" of the pojo to depend on different columns of the database in different situations. Anyone who has ever built an app using straight SQL knows that these "perspectives" on a table surface in the variety of different columns that are retrieved in different situations. Shades is designed to be fluid and adaptable to these common situations. In fact, I thought of the name "Shades" because a good data access framework should recognize the shades of grey that permeate data access programming. Perhaps most of all, shades tries to minimize the number of rules, states, and do's and don'ts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-115622390093951162?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/115622390093951162/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2006/08/cool-things-about-shades.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115622390093951162'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115622390093951162'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2006/08/cool-things-about-shades.html' title='cool things about shades'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-115535426953732807</id><published>2006-08-11T19:54:00.000-07:00</published><updated>2006-08-26T13:02:48.796-07:00</updated><title type='text'>Lot's of progress</title><content type='html'>Well, I used to work for a guy who said writing software is a lot like baking waffles. The first waffle sticks to the iron and doesn't come out very well, but it primes the iron with just enough grease to make the second waffle perfect.&lt;br /&gt;&lt;br /&gt;So it seems I have just baked my second waffle. I'm putting the finishing touches on Shades, a framework for ORMapping. My first waffle was JDOMax. Why the hell does the world need yet another ORMapping framework? Let me tell you:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;   &lt;li&gt;Too much XML configuration&lt;/li&gt;   &lt;li&gt;Transparent object persistence misidentifed as necessary&lt;/li&gt;   &lt;li&gt;Relationships between records ARE NOT analogs to references between Objects.&lt;/li&gt;&lt;li&gt;Inheritance relationships are rarely natural in data models.&lt;/li&gt;   &lt;li&gt;Transitive closure persistence unnecessary&lt;/li&gt;   &lt;li&gt;Too many transactional states increases complexity beyond original problem&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;I learned all of the above the hard way! I'm not just pontificating on this crap. I spent roughly 3 years developing JDOMax and passing the Sun Test Compatibility Suite, so my first waffle was one mother of a waffle.&lt;br /&gt;&lt;ol&gt;    &lt;/ol&gt; Looking at 1, "Too much XML configuration", your first reaction might be to think this is an implementation detail; just a consequence of bad XML design. I argue that this configuration complexity is a natural reflection of inherent complexity. Unfortunately, the inherent complexity lies not in the problem you are trying to solve, but in the act of object relational mapping itself. It seems that a static specification of mapping fails to easily convey *contextually* relevant information. In other words, a "mapping" is too static. What is really needed is an Object/Relational Interface, the implementation of which is *code*, and therefore can, in a few lines, create contextually relevant decisions that make ORMapping decisions dynamic and flexible rather than static and ridgid.&lt;br /&gt;&lt;br /&gt;Shades has absolutely no XML nor annotation configuration. Rather, there's an interface called ORMapping that operated really a lot like a TableModel. A DefaultORMapping is usually extended by the program, and only a few methods need to be implemented. At first I was shocked by how easy it was but it's now apparent to me that O/R Mapping is better suited to programmetic configuration than document configuration. The reason XML configuration of O/R Mapping is so complex is because...well, because in THIS CASE  it's way more complex than just writing a few lines of code.&lt;br /&gt;&lt;br /&gt;Somewhere along the line we all just accepted that XML was the way to configure O/R mapping. We bought into a real big advantage of XML - that it's externalized, and can in theory be edited by this mythical "deployer" person. The problem is that this mythical deployer does not exist. In reality he's the programmer and it turns out, now that the wow cool factor has warn off, that the XML is harder to deal with than a few lines of code.&lt;br /&gt;&lt;br /&gt;2. Transparent Object Persistence Misidentified as Necessary&lt;br /&gt;This is a big deal. Transparent Object Persistence (TOP)is the idea that you operate on Objects with no concern for the fact that they may be persisted in a relational database. And even beyond that, TOP espouses that it is the Object AND it's references that are in the database. This just turns out to be wrong. THERE IS NO *INHERENT* MAPPING BETWEEN RELATIONSHIPS IN THE DATABASE AND REFERENCES IN THE JVM. But it is *possible* to relate object references to relationships in the datastore. The problem is that the mapping is not one-to-one, and again we are back to a solution that creates as least as many problems as it solves.&lt;br /&gt;&lt;br /&gt;Quick example. Teacher Object has a collection of Student Objects. Each Student Object has a field named teacher. Database has an FK in STUDENT_TABLE that points at the PK of teacher table. So in Java land you remove a student from a teacher's collection. This must immediately null the teacher field in the student Object. This is unexpected. And making it work leads to a complex implementation of proxy collections. When the transaction is committed, the FK in the student is set to null. It's simply not at all clear that removing an element from a collection in memory is the right way to remove a relationship from the database. It's just not an intentional way to program. In other words, in order to "forget" about the relational database, we have to learn more than we ever bargained for, and understand subtleties, that even for experts can be mind bending. And the transparency turns out to be nothing near transparent. Consider a STUDENT_TABLE that places a unique constraint on STUDENT_LNAME. If you created a new Student in memory, and added it to a Teacher Object's collection, when would you find out this was invalid? You'd find out when you committed, and a nested datastore exception was thrown. What's so transparent about that. The transparency is a myth. And how would you handle the exception when you created 19 other Students in the transaction? Yes, yes, it is *possible* to handle using an array of nested exceptions, blah blah blah. BUT FOLKS, IT'S NOT EASY. YOU HAVE TO LEARN MORE TO MAKE IT WORK THAN TO SOLVE YOUR ORIGINAL PROBLEM!!!!!!!!!!!!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-115535426953732807?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/115535426953732807/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2006/08/lots-of-progress.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115535426953732807'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115535426953732807'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2006/08/lots-of-progress.html' title='Lot&apos;s of progress'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-32093290.post-115456092542165053</id><published>2006-08-02T16:21:00.000-07:00</published><updated>2006-08-02T17:09:01.243-07:00</updated><title type='text'>getting our of 'nam for som R&amp;R</title><content type='html'>&lt;span style="color: rgb(102, 51, 255);font-family:arial;" &gt;A few weeks ago I read  an article on TSS called&lt;/span&gt;&lt;span style="color: rgb(102, 51, 255);"&gt; &lt;/span&gt;&lt;span style="font-style: italic; color: rgb(255, 255, 255);"&gt;&lt;span style="color: rgb(102, 51, 255);"&gt;Ted Neward explains ORM as "The Viet Nam of &lt;/span&gt;&lt;span style="color: rgb(102, 51, 255);font-family:arial;" &gt;Computer Science.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;&lt;span style="color: rgb(0, 0, 0);font-family:arial;" &gt;I have to say, from personal experience, that I agree with him.I got interested in O/R several years ago, and wound up writing an implementaiton of JSR 12, Java Data Object called JDOMax &lt;a href="http://www.jdomax.com"&gt;www.jdomax.com&lt;/a&gt;. It took about 2.5 years to write the software and pass the Sun Test Compatibility Kit. While I was writing the software, I often got the feeling I was going down into the rabbit hole. And after some time, just passing the TCK became a goal in and of itself. When all was said and done, roughly 50,000 lines of code had been written and debugged, and was being used by a few hundred downloaders. Then I got married and haven't looked back at my hobby since.&lt;br /&gt;&lt;br /&gt;My goal now is to produce some software that can be used to easily query , insert, and delete data from the relational database, with a small learning curve, and most of all a small internal codebase. Basically, I have to distill something that is vastly simpler than the fullblown JDO that I had implemented, if I am to have any hope of getting out of 'Nam for some R&amp;R.&lt;br /&gt;&lt;br /&gt;Over the last few years, there has been a lot of debate on "query by example" vs. "query language". Having written a JDOQL compiler using JavaCC, I knew that I was going to have dispatch with the query language. Too much complexity, and more code than I can maintain. The second thing I decided to do away with was transparent object persistence. Transitive closure persistence, simply isn't an essential feature, and it often confuses developers.&lt;br /&gt;&lt;br /&gt;In short, I had to be willing to do many things differently, even if it meant joining the Viet Cong. I hoped that by freeing my mind of dogma I could produce a system that leveraged the best and most essential features of several approaches.&lt;br /&gt;&lt;br /&gt;I began by writing lots of "fake programs". I wanted to be sure that no matter how I implemented the internals, that the software was easy to use, and produced tight code, with an absolute minimum of configuration.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="font-style: italic; color: rgb(255, 255, 255);"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/32093290-115456092542165053?l=notskateboarding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://notskateboarding.blogspot.com/feeds/115456092542165053/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://notskateboarding.blogspot.com/2006/08/getting-our-of-nam-for-som-rr.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115456092542165053'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/32093290/posts/default/115456092542165053'/><link rel='alternate' type='text/html' href='http://notskateboarding.blogspot.com/2006/08/getting-our-of-nam-for-som-rr.html' title='getting our of &apos;nam for som R&amp;R'/><author><name>Geoffrey Hendrey</name><uri>http://www.blogger.com/profile/12633667743374833424</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='26' height='32' src='http://4.bp.blogspot.com/_iJr6rK5UOFc/SR2qlEKc8XI/AAAAAAAAAFo/wT69dSIYaSQ/S220/headshot.png'/></author><thr:total>0</thr:total></entry></feed>
