<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4228702729472041146</id><updated>2024-09-07T17:17:39.295-07:00</updated><title type='text'>Unless I&#39;m Wrong</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>27</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-1101219395508111285</id><published>2014-07-25T11:02:00.004-07:00</published><updated>2014-07-25T11:02:55.835-07:00</updated><title type='text'>How to associate a file name extension with a darwin /linux/unix command-line executable on osx/macintosh.</title><content type='html'>One of the things one can do with&amp;nbsp;&lt;a href=&quot;https://github.com/BrentNoorda/self-serving&quot;&gt;self-serving&lt;/a&gt;&amp;nbsp;(a multi-platform command-line executable for making simple tools that employ the user&#39;s browser as the UI and javascript for the logic), is to bundle a bunch of resources into a file with the &quot;.slfsrv&quot; extension; for example &quot;morningMenu.slfsrv&quot;. &amp;nbsp;On my macintosh I could execute this from the command line &quot;self-serving morningMenu.slfsrv&quot; or on the Windows command line with &quot;self-serving.exe morningMenu.slfsrv&quot;.&lt;br /&gt;
&lt;br /&gt;
I wanted to associate the &quot;.slfsrv&quot; extension with the executable, so that one could run a .slfsrv program simply by double-clicking on the file in OSX&#39;s Finder or Windows&#39; explorer. This was very easy in Windows but on the Mac it took me quite a while to figure out. It turns out you can&#39;t associate a file extension with a simple executable, it has to be a &amp;nbsp;Mac App.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;How to mac a Mac App from a darwin executable&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
To make a Mac App from a darwin executable&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Launch the Automator application&lt;/li&gt;
&lt;li&gt;Click &quot;New Document&quot;&lt;/li&gt;
&lt;li&gt;For document type select Application&lt;/li&gt;
&lt;li&gt;From the Actions library on the left select select &quot;Run Shell Script&quot; and drag that to the workplace on the right&lt;/li&gt;
&lt;li&gt;Change the &quot;Pass input&quot; option to &quot;as arguments&quot;&lt;/li&gt;
&lt;li&gt;Edit the shell script for what to be something like one of these:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/path/to/my/exec/myexecutable &quot;$@&quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;or&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;for f in &quot;$@&quot;&lt;br /&gt;do&lt;br /&gt;&amp;nbsp; &amp;nbsp; /path/to/my/exec/myexecutable &quot;$f&quot;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;done&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Select File/Save and create a name and location for your &quot;.app&quot; file. In my case I called this &quot;SelfServing.app&quot; and put it in my &quot;~/bin&quot; folder&lt;/li&gt;
&lt;/ol&gt;
&lt;br /&gt;
You next want to associate a file extension with the .app you just created, as follows:&lt;br /&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;In the finder open a folder containing a file of that type. In my case I opened the folder containing the file morninMenu.slfsrv&lt;/li&gt;
&lt;li&gt;Right click on the file and select &quot;Get Info&quot;&lt;/li&gt;
&lt;li&gt;Under &quot;Open With&quot; select &quot;Other...&quot; and locate the .app file you created from Automator (you probably want to have all files with that extension opened with your app).&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;b&gt;Using it&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
That&#39;s it. Now you can run the command-line program on all files with that executable simply by double clicking that type of file in Finder, or from the command-line typing &quot;open &lt;i&gt;myfile.myextension&lt;/i&gt;&quot;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/1101219395508111285/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2014/07/how-to-associate-file-name-extension.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/1101219395508111285'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/1101219395508111285'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2014/07/how-to-associate-file-name-extension.html' title='How to associate a file name extension with a darwin /linux/unix command-line executable on osx/macintosh.'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-4861089652444299965</id><published>2014-06-12T20:12:00.000-07:00</published><updated>2014-06-12T20:46:51.251-07:00</updated><title type='text'>Sharing picasa photos, albums, and tags between Windows and Macintosh OSX computers</title><content type='html'>&lt;div style=&quot;font-size: large;&quot;&gt;
So, you have all your pictures on your computer, you view and tag them with Picasa, and your Windows-using spouse wants to have the same photos and tags and albums and such on her Windows machine. What do you do?&lt;br /&gt;
&lt;br /&gt;
First you share your picture folders between machines using BitTorrent Sync. That works great. Oh Joy!&lt;br /&gt;
&lt;br /&gt;
Next, after you&#39;ve spent hours on your Macintosh tagging people in all the photos, you want your spouse to see all those same tags on her Windows machine. So you play around with sharing the Picasa &quot;contacts&quot; folder, and you try sharing the &quot;db3&quot; folder, and you try the &quot;store name tags in photo&quot; Picasa options, and the experimental &quot;write faces to XMP&quot; and various combinations of the above. &amp;nbsp;No matter what you try, at best it doesn&#39;t share data between machines, and at worst it corrupts your data.&lt;br /&gt;
&lt;br /&gt;
So you stop syncing everything except the photo folders themselves. And you restore your &quot;contacts&quot; and &quot;db3&quot; folders (you did remember to back those up, didn&#39;t you), and you give up on you and your spouse ever having the benefit of being able to share your tagged people faces.&lt;br /&gt;
&lt;br /&gt;
Sigh.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/4861089652444299965/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2014/06/sharing-picasa-photos-albums-and-tags.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/4861089652444299965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/4861089652444299965'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2014/06/sharing-picasa-photos-albums-and-tags.html' title='Sharing picasa photos, albums, and tags between Windows and Macintosh OSX computers'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-2149654129935676128</id><published>2014-06-06T15:36:00.000-07:00</published><updated>2014-06-26T08:15:10.696-07:00</updated><title type='text'>Thinking about Brownian Motion, Air Molecules, and Airplane Wings</title><content type='html'>&lt;span style=&quot;font-size: large;&quot;&gt;This entry has moved to &lt;a href=&quot;http://brent-noorda.blogspot.com/2014/06/half-brownian-theory-of-flight.html&quot;&gt;my primary blog location&lt;/a&gt;.&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/2149654129935676128/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2014/06/half-brownian-theory-of-flight.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/2149654129935676128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/2149654129935676128'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2014/06/half-brownian-theory-of-flight.html' title='Thinking about Brownian Motion, Air Molecules, and Airplane Wings'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-5380954758701849644</id><published>2014-05-27T15:02:00.003-07:00</published><updated>2015-01-23T11:10:33.586-08:00</updated><title type='text'>How I use Google AdSense and Google Analytics with Meteor websites</title><content type='html'>Here is how I managed to get Google AdSense and Google Analytics into my Meteor websites: &lt;a href=&quot;http://www.airbnbconfessions.com/&quot;&gt;airbnbconfessions&lt;/a&gt; and &lt;a href=&quot;https://nomorepasswordsjustemail.meteor.com/&quot;&gt;NoMorePasswordsJustEmail&lt;/a&gt;.

&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Google Analytics is easy&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
It&#39;s not difficult getting Google Analytics into your Meteor web app. Simply take the Google Analytics startup code and put it in client-side of your Meteor source.&lt;br /&gt;
&lt;br /&gt;
Here, for example, is a file I have within the &lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;/client&lt;/span&gt; directory of my Meteor airbnbconfessions source code.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;Meteor.startup(function() {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; $(document).ready(function() {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // show google analytics if running on the live web site&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if ( -1 != document.URL.indexOf(&quot;www.airbnbconfessions.com&quot;) )&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (function(i,s,o,g,r,a,m){i[&#39;GoogleAnalyticsObject&#39;]=r;i[r]=i[r]||function(){&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; })(window,document,&#39;script&#39;,&#39;//www.google-analytics.com/analytics.js&#39;,&#39;ga&#39;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ga(&#39;create&#39;, &#39;UA-YOUR-CODE-HERE&#39;, &#39;airbnbconfessions.com&#39;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ga(&#39;send&#39;, &#39;pageview&#39;);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; });&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;});&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Note that I rely on jQuery and&amp;nbsp;&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;$(document).ready()&lt;/span&gt; but I assume &lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;Meteor.startup()&lt;/span&gt; probably would work as well.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Google Adsense is trickier&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Two problems: 1) Meteor really wants to be in controls of rendering all your HTML, and 2) Google really wants the page to exists as some raw HTML before rendering the ads.&lt;br /&gt;
&lt;br /&gt;
For (1), Meteor provides the &lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;/public&lt;/span&gt; directory. Anything in &lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;/public&lt;/span&gt;&amp;nbsp;bypassed the Meteor rendering system and is just available to the web client like any other raw internet file.&lt;br /&gt;
&lt;br /&gt;
For (2), the ads will be loaded within iframes, refereing to those&amp;nbsp;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;/public&lt;/span&gt;&amp;nbsp;files, from the main page.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Bringing Google Adsense and Meteor together&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
In NoMorePasswordsJustEmail, I want the ads to appear in the right for web browsers, but on the bottom for mobile browsers. So in my primary &lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;index.html&lt;/span&gt; file uses bootstrap classes in this code:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;div id=&quot;list-stuff&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;div class=&quot;row&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;div class=&quot;span9&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; ...page stuff...&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;div class=&quot;span3 hidden-phone&quot; style=&quot;text-align:center;&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;center&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {{&amp;gt; adsRight}}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/center&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;div class=&quot;row visible-phone&quot; style=&quot;margin-left:-20px;margin-right:-20px;&quot;&amp;gt;{{! style makes up for 20 pixels added to body }}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;div class=&quot;span10&quot; style=&quot;text-align:center;&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;center&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {{&amp;gt; adsBottom}}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/center&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
Those &lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;adsright&lt;/span&gt; and &lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;adsbottom&lt;/span&gt; templates render iframes that will load the files that were in &amp;nbsp;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace; font-size: x-small;&quot;&gt;/public&lt;/span&gt;&amp;nbsp;and look like this &lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;client/ads.html&lt;/span&gt; file.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;!-- google ads stuff --&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;!-- http://stackoverflow.com/questions/14389766/meteor-js-use-external-script --&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;lt;template name=&quot;adsRight&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;div id=&quot;adsRight&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;iframe src=&quot;/adright.html?v={{{unique}}}&quot; seamless width=&quot;160&quot; height=&quot;600&quot; scrolling=&quot;no&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;frameborder=&quot;0&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;style=&quot;margin:0;padding:0;border:none;width:160px;height:600px&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;lt;/template&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;lt;template name=&quot;adsBottom&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;div id=&quot;adsBottom&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;hr/&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;lt;iframe src=&quot;/adbottom.html?v={{{unique}}}&quot; seamless width=&quot;336&quot; height=&quot;280&quot; scrolling=&quot;no&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;frameborder=&quot;0&quot; marginheight=&quot;0&quot; marginwidth=&quot;0&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;style=&quot;margin:0;padding:0;border:none;width:336px;height:280px&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;lt;/template&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
That code refers to &lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;unique&lt;/span&gt;, just force Google to take a moment to check the text on the page each time, and provide a fresh ad as the text of the page changes with new reloads. &lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;client/ads.js&lt;/span&gt; provides that:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;Template.adsRight.unique = function() {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; return (new Date()).valueOf();&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;};&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;Template.adsBottom.unique = function() {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; return (new Date()).valueOf();&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;};&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
Finally, the two files that like to the ads themselves.&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;public/adbottom.html:&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;style type=&quot;text/css&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;* {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; margin: 0;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; padding: 0;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;script async src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;!-- nmpjebottom --&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;ins class=&quot;adsbygoogle&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;style=&quot;display:inline-block;width:336px;height:280px&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;data-ad-client=&quot;ca-pub-YOUR-GOOGLE-CODE&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;data-ad-slot=&quot;YOUR-GOOGLE-ADSLOT&quot;&amp;gt;&amp;lt;/ins&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;public/adright.html:&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;style type=&quot;text/css&quot;&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;* {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; margin: 0;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; padding: 0;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;div&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;script async src=&quot;//pagead2.googlesyndication.com/pagead/js/adsbygoogle.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;!-- nmpjeright --&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;ins class=&quot;adsbygoogle&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;style=&quot;display:inline-block;width:160px;height:600px&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;data-ad-client=&quot;ca-pub-YOUR-GOOGLE-CODE&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;data-ad-slot=&quot;YOUR-GOOGLE-ADSLOT&quot;&amp;gt;&amp;lt;/ins&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;script&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;(adsbygoogle = window.adsbygoogle || []).push({});&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: x-small;&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;That&#39;s all.&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Good luck. My fingers are crossed for you.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/5380954758701849644/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2014/05/how-i-use-google-adwords-and-google.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/5380954758701849644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/5380954758701849644'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2014/05/how-i-use-google-adwords-and-google.html' title='How I use Google AdSense and Google Analytics with Meteor websites'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-8955288520975543683</id><published>2013-12-11T07:53:00.001-08:00</published><updated>2013-12-11T07:53:28.688-08:00</updated><title type='text'>Setting up Bitnami tomcat stack on VirtualBox on OSX 10.9 (Mavericks), with a shared folder</title><content type='html'>I had such a hard time getting the Bitnami Tomcat stack to run on the latest VirtualBox (4.3.4), and especially with adding shared folders. I was all day long retrying over and over. Sheesh. These are the magic steps I took, recorded here in hopes that it can save someone else some time.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Creating the bitnami stack on OSX&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Install (a couple of times until it works, dagnabit) a new version of virtual box from &lt;a href=&quot;http://www.oracle.com/technetwork/server-storage/virtualbox/downloads/index.html&quot;&gt;http://www.oracle.com/technetwork/server-storage/virtualbox/downloads/index.html&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Download the bitnami tomcat vm image from &lt;a href=&quot;http://bitnami.com/stack/tomcat&quot;&gt;http://bitnami.com/stack/tomcat&lt;/a&gt; (the folder contains bitnami-tomcatstack...vmdk)&lt;br /&gt;
&lt;br /&gt;
When starting a new virtual box image, pay attention to settings here: &lt;a href=&quot;http://wiki.bitnami.com/Virtual_Appliances_Quick_Start_Guide#Virtual_Box&quot;&gt;http://wiki.bitnami.com/Virtual_Appliances_Quick_Start_Guide#Virtual_Box&lt;/a&gt;&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;type: Linux&lt;/li&gt;
&lt;li&gt;version: Ubuntu (64 bit)&lt;/li&gt;
&lt;li&gt;Use an existing virtual hard drive file (that bitnami-tomcatstack...vmdk file mentioned earlier)&lt;/li&gt;
&lt;li&gt;Create -&amp;gt;&lt;/li&gt;
&lt;li&gt;In settings, for Network, select Attached to: Bridged Adapter&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Press the big Start arrow&lt;/li&gt;
&lt;/ul&gt;
Shortly a new linux console will be running, with mysql, apache, tomcat, whooopee!&lt;br /&gt;
&lt;br /&gt;
On first login “bitnami” with password “bitnami”. Your first login will force you to select a new password.&lt;br /&gt;
&lt;br /&gt;
For java tools, I added this to ~/.bashrc&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;JAVA_HOME=/opt/bitnami/java&lt;br /&gt;export JAVA_HOME&lt;/span&gt;&lt;/blockquote&gt;
To verify the success, look in your local mac browser for the tomcat server at the address presented on the VM console (in my case “You can access the application at &lt;i&gt;&lt;span style=&quot;color: #999999;&quot;&gt;http://10.0.0.6/&lt;/span&gt;&lt;/i&gt; ***”)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Getting a shared folder that is ~/Desktop on both host and client (via Guest Additions):&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
1) download VBoxGuestAdditions_4.3.4.iso from here: &lt;a href=&quot;http://download.virtualbox.org/virtualbox/4.3.4/&quot;&gt;http://download.virtualbox.org/virtualbox/4.3.4/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
2) Then in virtual machine&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
$ sudo apt-get update&lt;br /&gt;$ sudo apt-get upgrade&lt;br /&gt;$ sudo apt-get install dkms&lt;br /&gt;$ sudo reboot&lt;/blockquote&gt;
3) then (partially from &lt;a href=&quot;http://wiki.bitnami.com/Virtual_Appliances_Quick_Start_Guide#How_to_install_VirtualBox_Guest_Additions_on_BitNami_Virtual_Appliances.3f&quot;&gt;http://wiki.bitnami.com/Virtual_Appliances_Quick_Start_Guide#How_to_install_VirtualBox_Guest_Additions_on_BitNami_Virtual_Appliances.3f&lt;/a&gt;)&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
$ uname -a &lt;i&gt;### to get kernel version, e.g. &lt;span style=&quot;color: #999999;&quot;&gt;3.2.0-53-virtual&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;$ sudo apt-get -y install dkms build-essential linux-headers-&lt;i&gt;&lt;span style=&quot;color: #999999;&quot;&gt;3.2.0-53-virtual&lt;/span&gt;&lt;/i&gt;&lt;br /&gt;$ sudo reboot&lt;/blockquote&gt;
4) use VBoxGuestAdditions.iso stuff from the vbox menu Devices -&amp;gt; CD/DVD Devices -&amp;gt; Choose a Virtual CD/DVD… as found at &lt;a href=&quot;http://wiki.bitnami.com/Virtual_Appliances_Quick_Start_Guide#How_to_install_VirtualBox_Guest_Additions_on_BitNami_Virtual_Appliances.3f&quot;&gt;http://wiki.bitnami.com/Virtual_Appliances_Quick_Start_Guide#How_to_install_VirtualBox_Guest_Additions_on_BitNami_Virtual_Appliances.3f&lt;/a&gt; to select “VBoxGuestAdditions.iso” (wherever you downloaded that to in step 1)&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
$ sudo mkdir /mnt/cdrom&lt;br /&gt;$ sudo mount /dev/cdrom /mnt/cdrom&lt;br /&gt;$ cd /mnt/cdrom&lt;br /&gt;$ sudo sh ./VBoxLinuxAdditions.run --nox11 &amp;nbsp;# ignore “could not find x.org…” error&lt;/blockquote&gt;
5) Recreate (or update or something) the VB guest addition modules:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
$ sudo /etc/init.d/vboxadd setup&lt;br /&gt;$ sudo reboot&lt;/blockquote&gt;
6) In the VB menu Devices -&amp;gt; “Shared Folders Settings...” set up ~/Desktop to be shared (auto-mounted, permanent, &amp;nbsp;and r/w) as “Desktop”&lt;br /&gt;
&lt;br /&gt;
7) Mount that Desktop menu that was mounted 23r2&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
$ mkdir ~/Desktop&lt;br /&gt;$ sudo mount -t vboxsf ~/Desktop Desktop&lt;/blockquote&gt;
8) In theory I should have been able to make that mounting automatic, even after reboots, via an entry in /etc/fstab but I was never able to get that working. So in the end, to get the mounting happen each time I log in, I added this line to ~/.bashrc&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;sudo mount -t vboxsf ~/Desktop Desktop&lt;/span&gt;&lt;/blockquote&gt;
Not that from the VM side, ~/Desktop is read-only for the bitnami user, and so “sudo” must be used for a bunch of the commands to read and copy files and such.&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;SSH to the bitnami machine&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
On the bitnami shell:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
$ sudo mv /etc/init/ssh.conf.back /etc/init/ssh.conf&lt;br /&gt;$ sudo start ssh&lt;/blockquote&gt;
On my mac:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
# ssh bitnami@&lt;i&gt;&lt;span style=&quot;color: #999999;&quot;&gt;10.0.0.6&lt;/span&gt;&lt;/i&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;That&#39;s what worked for me. Good Luck!&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/8955288520975543683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2013/12/setting-up-bitnami-tomcat-stack-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/8955288520975543683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/8955288520975543683'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2013/12/setting-up-bitnami-tomcat-stack-on.html' title='Setting up Bitnami tomcat stack on VirtualBox on OSX 10.9 (Mavericks), with a shared folder'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-5539737809712419790</id><published>2013-08-24T15:52:00.000-07:00</published><updated>2013-08-24T15:52:30.678-07:00</updated><title type='text'>Stripes jsp / jstl forms won&#39;t handle unicode / utf-8 characters. Yikes. What&#39;s wrong?</title><content type='html'>I don&#39;t know what&#39;s wrong in your case. But in my case stripes+tomcat+mysql case I had my database set up OK (from my.cnf)&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;[mysqld]&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;#default-character-set=utf8&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;#default-collation=utf8_general_ci&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;character-set-server=utf8&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;collation-server=utf8_general_ci&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;init-connect=&#39;SET NAMES utf8&#39;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;character-set-filesystem = UTF8&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;[client]&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;default-character-set=utf8&lt;/span&gt;&lt;/blockquote&gt;
and all my forms looked great:&lt;br /&gt;
&lt;s:form acceptcharset=&quot;utf-8&quot; beanclass=&quot;${actionBean.getClass().name}&quot;&gt;&lt;/s:form&gt;&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;lt;s:form beanclass=&quot;${actionBean.getClass().name}&quot; acceptcharset=&quot;utf-8&quot;&amp;gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;div&gt;
but unicode values would not return forms in utf-8 format.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
I tried all the solutions found at &lt;a href=&quot;http://cagan327.blogspot.com/2006/05/utf-8-encoding-fix-tomcat-jsp-etc.html&quot; target=&quot;_blank&quot;&gt;TechnologyNotes: UTF-8 Encoding fix (Tomcat, JSP, etc)&lt;/a&gt;, but those didn&#39;t work. So I undid most of them.&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
What did work for me was found within &lt;a href=&quot;http://www.stripesframework.org/display/stripes/Localization#Localization-DeterminingtheCharacterEncodingtouse&quot; target=&quot;_blank&quot;&gt;this Stripes HowTo&lt;/a&gt;. &amp;nbsp;I changed this:&lt;/div&gt;
&lt;div&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;init-param&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;param-name&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;LocalePicker.Locales&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/param-name&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;param-value&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;en:UTF-8, en_US:UTF-8&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/param-value&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/init-param&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;gt;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div&gt;
to this:&lt;/div&gt;
&lt;div&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;init-param&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;param-name&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;LocalePicker.Locales&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/param-name&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;param-value&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;en:UTF-8, en_US:UTF-8&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/param-value&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;/init-param&lt;/span&gt;&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span style=&quot;font-family: Courier New, Courier, monospace;&quot;&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div&gt;
And unicode characters in forms worked swell. Whoopee.&lt;/div&gt;
</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/5539737809712419790/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2013/08/stripes-jsp-jstl-forms-wont-handle.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/5539737809712419790'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/5539737809712419790'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2013/08/stripes-jsp-jstl-forms-wont-handle.html' title='Stripes jsp / jstl forms won&#39;t handle unicode / utf-8 characters. Yikes. What&#39;s wrong?'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-7102036182395604322</id><published>2012-07-27T14:41:00.001-07:00</published><updated>2012-07-27T16:12:20.213-07:00</updated><title type='text'>M. Dung, the KFOG host of the 80&#39;s is found!</title><content type='html'>I&#39;ve you&#39;ve sadly been missing M. Dung, the KFOG morning host from the mid 80&#39;s, like I was, be sad no more. He&#39;s still producing The Mutant Idiotshow every week. Here&#39;s more:&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.idiotshow.net/&quot; style=&quot;background-color: white;&quot; target=&quot;_blank&quot;&gt;idiotshow website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://idiotshow.podbean.com/feed/&quot; target=&quot;_blank&quot;&gt;podcast version of weekly idiotshow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.sfgate.com/default/article/Ex-DJ-M-Dung-plugging-aaywaay-on-podcast-3735480.php&quot; target=&quot;_blank&quot;&gt;S.F. Chronicle newspaper article&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/7102036182395604322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2012/07/m-dung-kfog-host-of-80s-is-found.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/7102036182395604322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/7102036182395604322'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2012/07/m-dung-kfog-host-of-80s-is-found.html' title='M. Dung, the KFOG host of the 80&#39;s is found!'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-2181150216952661815</id><published>2012-07-17T11:43:00.003-07:00</published><updated>2012-07-17T11:43:39.086-07:00</updated><title type='text'>how to adjust the macintosh startup sound</title><content type='html'>Mac startup sound is too loud? I&#39;ve wasted most of the morning trying to figure out how to make my apple macbook pro ess loud when I boot it, so that it doesn&#39;t wake everyone in the house. Here&#39;s the tool that worked for me:&amp;nbsp;&lt;a href=&quot;http://www5e.biglobe.ne.jp/~arcana/software.en.html&quot;&gt;StartupSound.prefPane&lt;/a&gt;</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/2181150216952661815/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2012/07/how-to-adjust-macintosh-startup-sound.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/2181150216952661815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/2181150216952661815'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2012/07/how-to-adjust-macintosh-startup-sound.html' title='how to adjust the macintosh startup sound'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-1593648316482051617</id><published>2012-06-11T14:23:00.000-07:00</published><updated>2012-06-11T19:21:15.380-07:00</updated><title type='text'>Building HelloSun, Step 6: Speech Bubbles</title><content type='html'>&lt;table bgcolor=&quot;#ffcc7f&quot; border=&quot;0&quot; style=&quot;width: 98%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;&lt;i&gt;HelloSun:
A guide to
creating a social networking empire, from scratch, for free, circa 2012.&lt;/i&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-5-clean-code-is.html&quot;&gt;⇐
Step 5&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;20%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html&quot;&gt;T.O.C.&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
I&#39;m not very happy with this scrolling &quot;chat&quot; part of the web page,
which so far looks like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw2IT1kkBuGq1cuigkcPzhDLcRHCQjNm1uurk7oaX2xX0JWqgvmK2gMZdeYr2IeTEixh7pZskkjHTlJaCRzhkUr8FiqQStt8EYYNkxG_ps9g9dAuLWDQbHdn7vRuZ7ux0g-CyPjH2uJelc/s1600/RealTimeChat.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw2IT1kkBuGq1cuigkcPzhDLcRHCQjNm1uurk7oaX2xX0JWqgvmK2gMZdeYr2IeTEixh7pZskkjHTlJaCRzhkUr8FiqQStt8EYYNkxG_ps9g9dAuLWDQbHdn7vRuZ7ux0g-CyPjH2uJelc/s400/RealTimeChat.png&quot; width=&quot;366&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
I&#39;d much prefer each person&#39;s comment to appear in a speech bubble, as
I&#39;ve sketched on this post-it note:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7YpAVZwni7VjznIw0zkWAV9u8dhmmJtY2WFdJw1zfsEeSV4PmgYap7acUD3xVFrI73VpDNX41pfI8hVpNPdtxrvJkDssncMarHK8f_3Dh0iIvxv5JbM5rzeqvzdB9yLvm3MmMbLRIdNJ1/s1600/postychat.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;313&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7YpAVZwni7VjznIw0zkWAV9u8dhmmJtY2WFdJw1zfsEeSV4PmgYap7acUD3xVFrI73VpDNX41pfI8hVpNPdtxrvJkDssncMarHK8f_3Dh0iIvxv5JbM5rzeqvzdB9yLvm3MmMbLRIdNJ1/s320/postychat.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;prototyping with newfangled css layout and rounded
corners&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
&lt;br /&gt;
Borrowing liberally from &lt;a href=&quot;http://nicolasgallagher.com/pure-css-speech-bubbles/demo/&quot;&gt;Pure
CSS speech bubbles&lt;/a&gt;, I tweaked this local html file:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;background-color: #eeeeee; margin-left: 1em;&quot;&gt;
&lt;code&gt;&amp;lt;html&amp;gt;&lt;br /&gt;
&amp;lt;head&amp;gt;&lt;br /&gt;
&amp;lt;style type=&quot;text/css&quot;&amp;gt;
&lt;br /&gt;
&lt;br /&gt;
.bubble-content {&lt;br /&gt;
&amp;nbsp; position:relative;&lt;br /&gt;
&amp;nbsp; padding:6px;&lt;br /&gt;
&amp;nbsp; margin:4px 0 0 0;&lt;br /&gt;
&amp;nbsp; color:#000;&lt;br /&gt;
&amp;nbsp; background:#f3961c; /* for browsers
without gradient
support */&lt;br /&gt;
&amp;nbsp; /* css3 */&lt;br /&gt;
&amp;nbsp; background:-webkit-gradient(linear, 0 0, 0 100%,
from(#f9d835),
to(#f3961c));&lt;br /&gt;
&amp;nbsp; background:-moz-linear-gradient(#f9d835, #f3961c);&lt;br /&gt;
&amp;nbsp; background:-o-linear-gradient(#f9d835, #f3961c);&lt;br /&gt;
&amp;nbsp; background:linear-gradient(#f9d835, #f3961c);&lt;br /&gt;
&amp;nbsp; -webkit-border-radius:10px;&lt;br /&gt;
&amp;nbsp; -moz-border-radius:10px;&lt;br /&gt;
&amp;nbsp; border-radius:10px;&lt;br /&gt;
&amp;nbsp; -webkit-border-bottom-left-radius:0;&lt;br /&gt;
&amp;nbsp; -moz-border-bottom-left-radius:0;&lt;br /&gt;
&amp;nbsp; border-bottom-left-radius:0;&lt;br /&gt;
&amp;nbsp; font-family: Arial;&lt;br /&gt;
&amp;nbsp; font-size: 12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.bubble-citation {&lt;br /&gt;
&amp;nbsp; margin:0 0 8px 0;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.whom {&lt;br /&gt;
&amp;nbsp; margin: -8px 0 0 14px;&lt;br /&gt;
&amp;nbsp; color:#000;&lt;br /&gt;
&amp;nbsp; font-family: Arial;&lt;br /&gt;
&amp;nbsp; font-size: 12px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.quote-tail {&lt;br /&gt;
&amp;nbsp; background:#f3961c;&lt;br /&gt;
&amp;nbsp; width:20px;&lt;br /&gt;
&amp;nbsp; height:16px;&lt;br /&gt;
&amp;nbsp; -webkit-border-radius:8px;&lt;br /&gt;
&amp;nbsp; -moz-border-radius:8px;&lt;br /&gt;
&amp;nbsp; border-radius:8px;&lt;br /&gt;
&amp;nbsp; margin:0;&lt;br /&gt;
&amp;nbsp; margin-top:-9px;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.quote-tail2 {&lt;br /&gt;
&amp;nbsp; background:#fff;&lt;br /&gt;
&amp;nbsp; width:14px;&lt;br /&gt;
&amp;nbsp; height:12px;&lt;br /&gt;
&amp;nbsp; -webkit-border-radius:6px;&lt;br /&gt;
&amp;nbsp; -moz-border-radius:6px;&lt;br /&gt;
&amp;nbsp; border-radius:6px;&lt;br /&gt;
&amp;nbsp; margin:0;&lt;br /&gt;
&amp;nbsp; margin-top:-12px;&lt;br /&gt;
&amp;nbsp; margin-left:8px;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/style&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/head&amp;gt;&lt;br /&gt;
&amp;lt;body&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;lt;div class=&quot;bubble-content&quot;&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; This is some bubble content I could just go on
and on and on&lt;br /&gt;
&amp;nbsp; &amp;nbsp; and maybe I will because, really, you know, I
have an awful&lt;br /&gt;
&amp;nbsp; &amp;nbsp; lot to say because I&#39;m just very verbose.&lt;br /&gt;
&amp;nbsp; &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;lt;div class=&quot;bubble-citation&quot;&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;lt;div
class=&quot;quote-tail&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;lt;div
class=&quot;quote-tail2&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;lt;div
class=&quot;whom&quot;&amp;gt;Tommy&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; &amp;lt;div class=&quot;bubble-content&quot;&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; This is some more bubble content.&lt;br /&gt;
&amp;nbsp; &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;lt;div class=&quot;bubble-citation&quot;&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;lt;div
class=&quot;quote-tail&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;lt;div
class=&quot;quote-tail2&quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;lt;div
class=&quot;whom&quot;&amp;gt;Sally&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;nbsp; &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/body&amp;gt;&lt;br /&gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/div&gt;
&lt;br /&gt;
In a modern browser the HTML above&amp;nbsp;produces this page&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH4fpBdVSUbGDdIsoGmypjrePWjOpia9gmfynKnCpf5WJSvGX2ElmJJIQXALdq9qgEwZB5F9LEqDR-k7F2YYsHHGEVLl8ZXx0oDy7cdxeed_3QpaXySIyi5GZNlxZbUh1McPPmWYGcukTZ/s1600/local_bubble_quotes.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;125&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH4fpBdVSUbGDdIsoGmypjrePWjOpia9gmfynKnCpf5WJSvGX2ElmJJIQXALdq9qgEwZB5F9LEqDR-k7F2YYsHHGEVLl8ZXx0oDy7cdxeed_3QpaXySIyi5GZNlxZbUh1McPPmWYGcukTZ/s320/local_bubble_quotes.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
That looks enough like the bubble quotes I drew on the post-it note
that I&#39;ll use it. (I may come to regret relying so much on the latest
CSS, when I get around to testing in different browsers--but since the
primary clients I&#39;m considering will be the most popular smartphones,
and they all support this level of CSS, I won&#39;t worry about this issue
yet.)&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;change the chat insertion code to use these
newfangled css bubble quotes&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
By adding the css classes from the local html prototype file into the
&quot;chatty.css&quot; file, and changing the &quot;appendMsg()&quot; function in
&quot;chatty.js to this:&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;background-color: #eeeeee; margin-left: 1em;&quot;&gt;
&lt;code&gt;function
appendMsg(msg) {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; $(&#39;#msgs&#39;).append(function() {&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; var div,
html;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; div =
$(&#39;&amp;lt;div&amp;gt;&#39;);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; html =
&#39;&amp;lt;div class=&quot;bubble-content&quot;&amp;gt;&#39; +&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; simple_html_escape(msg.message) +&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;
&#39;&amp;lt;/div&amp;gt;\r\n&#39; +&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;
&#39;&amp;lt;div class=&quot;quote-tail&quot;&amp;gt;&amp;lt;/div&amp;gt;\r\n&#39; +&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; &#39;&amp;lt;div
class=&quot;quote-tail2&quot;&amp;gt;&amp;lt;/div&amp;gt;\r\n&#39; +&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; &#39;&amp;lt;div class=&quot;whom&quot;&amp;gt;&#39; +&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;
simple_html_escape(msg.username) +&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; &#39;&amp;lt;/div&amp;gt;\r\n&#39; +&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;
&#39;&amp;lt;/div&amp;gt;\r\n&#39;;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp;
div.html(html);&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return
div;&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; });&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp; $(&#39;#msgs&#39;)[0].scrollTop =
$(&#39;#msgs&#39;)[0].scrollHeight;&lt;br /&gt;
}&lt;br /&gt;
&lt;/code&gt;&lt;/div&gt;
&lt;br /&gt;
the server now displays the chats within speech bubbles.&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;let&#39;s look better on an iPhone &lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
The primary client for HelloSun is expected to be mobile clients. A
couple of small adjustments can be made to make this code look better
on iphones. The primary change is adding a &quot;meta&quot; tag to the layout of
all files in this line added to layout.jade:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;
meta(name=&quot;viewport&quot;,content=&quot;width=device-width; initial-scale=1;
maximum-scale=1&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;check for blank inputs&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
The next little change for today&#39;s code is to prevent users from
submitting if they haven&#39;t entered either a name or a message, because
if those fields are blank it looks silly on the client displays. That&#39;s
done with a simple function to remove space from the beginning and end
of fields (the &quot;trim()&quot; method found at &lt;a href=&quot;http://www.somacon.com/p355.php&quot;&gt;Javascript Trim LTrim
and RTrim Functions&lt;/a&gt;), and a simple check in the &quot;sendMsg()&quot;
function of chatty.js to verify that the fields are not blank.&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;always scroll for new messages&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
The final change for today&#39;s code is to automatically scroll to the
bottom of the page when a new message comes. This ensures that users
are always seeing the latest messages from other users. This line in
&quot;chatty.js&quot; function &quot;appendMsg()&quot; replaces the old style to work with
the new type of page. (It&#39;s not particularly elegant, but it works.)&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; window.scrollTo(0, document.body.scrollHeight);&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;the new look&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
With all of today&#39;s changes, the chat program now looks something like
this:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQ53-f-Xfpju2Tuk0o16ibGwY0pqoYBpYT3cbYTXceOpJyRJHrNo4I0exlZcbEm3zB5HlT1-7dKlr26sAL98Tt6D6vvuiykVQ0G0jiECNUcXTrbaF81voc7ekZHlRTlXnnYt0Xw3MkfzUo/s1600/chattier.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;295&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhQ53-f-Xfpju2Tuk0o16ibGwY0pqoYBpYT3cbYTXceOpJyRJHrNo4I0exlZcbEm3zB5HlT1-7dKlr26sAL98Tt6D6vvuiykVQ0G0jiECNUcXTrbaF81voc7ekZHlRTlXnnYt0Xw3MkfzUo/s320/chattier.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
...and that&#39;s good enough for today.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;a href=&quot;http://www.blogger.com/blogger.g?blogID=4228702729472041146&quot; name=&quot;getcode&quot;&gt;&lt;/a&gt;Getting the code&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Today&#39;s code is labeled v0001.0005 and is available in these formats:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/tree/a23afff25ac3d919878d1e445a56f5005bdb9cd7&quot;&gt;browse the code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/compare/v0001.0004...v0001.0005&quot;&gt;all
v0001.0004...v0001.0005 code changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/zipball/v0001.0005&quot;&gt;https://github.com/BrentNoorda/hellosun-tutorial/zipball/v0001.0005&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tarball:
    &lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/tarball/v0001.0005&quot;&gt;https://github.com/BrentNoorda/hellosun-tutorial/tarball/v0001.0005&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;git:&lt;br /&gt;
&amp;nbsp;# git clone git@github.com:BrentNoorda/hellosun-tutorial.git&lt;br /&gt;
&amp;nbsp;# cd hellosun-tutorial&lt;br /&gt;
&amp;nbsp;# git checkout v0001.0005&lt;/li&gt;
&lt;/ul&gt;
&lt;table bgcolor=&quot;#ffcc7f&quot; border=&quot;0&quot; style=&quot;width: 98%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;&lt;i&gt;HelloSun:
A guide to
creating a social networking empire, from scratch, for free, circa 2012.&lt;/i&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-5-clean-code-is.html&quot;&gt;⇐
Step 5&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;20%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html&quot;&gt;T.O.C.&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/1593648316482051617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-6-speech-bubbles.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/1593648316482051617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/1593648316482051617'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-6-speech-bubbles.html' title='Building HelloSun, Step 6: Speech Bubbles'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw2IT1kkBuGq1cuigkcPzhDLcRHCQjNm1uurk7oaX2xX0JWqgvmK2gMZdeYr2IeTEixh7pZskkjHTlJaCRzhkUr8FiqQStt8EYYNkxG_ps9g9dAuLWDQbHdn7vRuZ7ux0g-CyPjH2uJelc/s72-c/RealTimeChat.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-2982204893594218286</id><published>2012-06-09T14:23:00.001-07:00</published><updated>2012-06-11T14:26:13.226-07:00</updated><title type='text'>Building HelloSun, Step 5: Clean Code is Happy Code</title><content type='html'>&lt;table bgcolor=&quot;#ffcc7f&quot; border=&quot;0&quot; style=&quot;width: 98%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;&lt;i&gt;HelloSun:
A guide to
creating a social networking empire, from scratch, for free, circa 2012.&lt;/i&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-4-real-time-chat.html&quot;&gt;⇐
Step 4&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;20%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html&quot;&gt;T.O.C.&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-6-speech-bubbles.html&quot;&gt;Step 6&amp;nbsp;⇒&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
So far the HelloSun code has been very sloppy, and sloppy code is bug-prone
code. So today we won&#39;t add any new functionality, but will just clean
up some areas of sloppiness. These are all small changes, but they&#39;ll
make me feel better (I&#39;m a bit anal-retentive that way).&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;use a lint tool&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
&lt;br /&gt;
lint tools look for obvious problems in source code. I don&#39;t see any
valid reason not to use them. I&#39;m using &lt;a href=&quot;http://www.jslint.com/&quot;&gt;JSLint&lt;/a&gt;, but there
are &lt;a href=&quot;http://stackoverflow.com/questions/3208604/js-validator-alternatives-to-jslint&quot;&gt;alternatives&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
This early in coding, JSLint recommended a few minor changes (all of
which I accepted, in one case using jQuery&#39;s &quot;each&quot; call to avoid using
&quot;hasOwnProperty&quot;), but found only one real bug: (the variable &quot;i&quot; was
not declared in &quot;chatty.jade&quot;, so would have overwritten any global &quot;i&quot;
and would also have been inefficient).&lt;br /&gt;
&lt;br /&gt;
At the top of all the JavaScript files are now lines similar to the
following, which are hints to the JSLint tool I&#39;m using.&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; /*jslint white:false plusplus:false nomen:false
*/&lt;br /&gt;
&amp;nbsp; /*globals $, io */&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
I won&#39;t be submitting any more javascript code before running lint on
it.&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;use a minimized version of jQuery&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://jquery.com/&quot;&gt;jQuery&lt;/a&gt; is nearly a
standard in client-side Javascript now, and is used in the &lt;a href=&quot;https://github.com/jmg/node-simple-chat&quot;&gt;node-simple-chat&lt;/a&gt;
example code we plagiarized in &lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-4-real-time-chat.html&quot;&gt;Step
4&lt;/a&gt;. To save a little download time I&#39;ve changed to jQuery
download in chatty.jade from&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;script(src=&quot;http://code.jquery.com/jquery-1.7.1.js&quot;,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;
&amp;nbsp;type=&quot;text/javascript&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
to&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;script(src=&quot;http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js&quot;,&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;
&amp;nbsp;type=&quot;text/javascript&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;move server-side javascript into its own
&quot;chatty.js&quot; file&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
&lt;br /&gt;
&quot;chatty.jade&quot; contained a few dozen lines of javascript code embedded
in the html file. I prefer to move this javascript code to its own
&quot;javascript/chatty.js&quot; file because it 1) let&#39;s me run lint against the
code, 2) treats the javascript as its own resource, and 3) is easier
for me to read.&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;don&#39;t alter Array.prototype&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
&lt;br /&gt;
The &lt;a href=&quot;https://github.com/jmg/node-simple-chat&quot;&gt;node-simple-chat&lt;/a&gt;
example code we plagiarized in &lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-4-real-time-chat.html&quot;&gt;Step
4&lt;/a&gt; used a trick of altering JavaScript&#39;s &quot;Array.prototype&quot;
simply to add an &quot;inject&quot; method used once. I find it very bothersome
to be altering a built-in Javascript object (&lt;i&gt;can we be sure
it&#39;s writable? can we be sure no other user of the Javascript global is
not using a similar function, or is not iterating over an expected list?&lt;/i&gt;).&lt;br /&gt;
&lt;br /&gt;
So I changed &quot;Array.prototype.inject&quot; in &quot;chatserver.js&quot; to a simple
&quot;inject_message&quot; function.&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;prevent users from injecting malicious html code&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
&lt;span style=&quot;color: red;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;color: red;&quot;&gt;This is the only serious problem
we&#39;re fixing today.&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
Whenever you&#39;re allowing user-generated as your source for output,
you&#39;re providing a big hole for malicious user to cause problems. In
our chat program so far, we take whatever text the user enters for
their name or their message, and display this text directly in the
browser of all users.&lt;br /&gt;
&lt;br /&gt;
Imagine that a user enters the message &quot;I like &amp;amp;lt;font
color=&quot;green&quot;&amp;gt;&amp;amp;lt;i&amp;gt;green
italics&amp;amp;lt;/i&amp;gt;&amp;amp;lt;font&amp;gt;.&quot; This would immediately
show up in every users window as:&lt;br /&gt;
&lt;blockquote&gt;
&lt;b&gt;myame:&lt;/b&gt; I like &lt;span style=&quot;color: green;&quot;&gt;&lt;i&gt;green italics&lt;/i&gt;&lt;/span&gt;.&lt;/blockquote&gt;
You
might think this innocent use of html codes is kind of cool. But if a
user weren&#39;t so innocent, they might be inserting code to links, or
uncouth images, or even malicious script that would be executed within
every user&#39;s browser.&lt;br /&gt;
&lt;blockquote&gt;
&lt;b&gt;&lt;code style=&quot;color: red;&quot;&gt;This
would allow any user of your service to deliver malicious functionality
to every other user of your service. Yikes!&lt;/code&gt;&lt;/b&gt;&lt;/blockquote&gt;
A very simple solution is just to escape a few special characters
(&quot;&amp;amp;lt;&quot;, &quot;&amp;gt;&quot;, and &quot;&amp;amp;&quot;) so that if they&#39;re part of
user input that we are injecting into html, they will not be seen as
raw html characters. This is done with the &quot;simple_html_escape&quot;
function added to chatty.js:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; function simple_html_escape(s)&lt;br /&gt;
&amp;nbsp; {&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; return
s.replace(/&amp;amp;/g,&#39;&amp;amp;amp;&#39;)&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;
&amp;nbsp;&amp;nbsp;.replace(/&amp;amp;lt;/g,&#39;&amp;amp;lt;&#39;)&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;
&amp;nbsp; .replace(/&amp;gt;/g,&#39;&amp;amp;gt;&#39;);&lt;br /&gt;
&amp;nbsp; }&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&quot;simple_html_escape()&quot; is then added to &quot;function appendMsg()&quot; wherever
the user-generated strings are display in the output page.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;a href=&quot;http://www.blogger.com/blogger.g?blogID=4228702729472041146&quot; name=&quot;getcode&quot;&gt;&lt;/a&gt;Getting the code&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Today&#39;s code is labeled v0001.0004 and is available in these formats:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/tree/fd89af7e32398bc7195364ce954b0469b3f9a487&quot;&gt;browse
the code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/compare/v0001.0003...v0001.0004&quot;&gt;all
v0001.0003...v0001.0004 code changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/zipball/v0001.0004&quot;&gt;https://github.com/BrentNoorda/hellosun-tutorial/zipball/v0001.0004&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tarball:
    &lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/tarball/v0001.0004&quot;&gt;https://github.com/BrentNoorda/hellosun-tutorial/tarball/v0001.0004&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;git:&lt;br /&gt;
&amp;nbsp;# git clone git@github.com:BrentNoorda/hellosun-tutorial.git&lt;br /&gt;
&amp;nbsp;# cd hellosun-tutorial&lt;br /&gt;
&amp;nbsp;# git checkout v0001.0004&lt;/li&gt;
&lt;/ul&gt;
&lt;table bgcolor=&quot;#ffcc7f&quot; border=&quot;0&quot; style=&quot;width: 98%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;&lt;i&gt;HelloSun:
A guide to
creating a social networking empire, from scratch, for free, circa 2012.&lt;/i&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-4-real-time-chat.html&quot;&gt;⇐
Step 4&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;20%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html&quot;&gt;T.O.C.&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-6-speech-bubbles.html&quot;&gt;Step 6&amp;nbsp;⇒&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/2982204893594218286/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-5-clean-code-is.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/2982204893594218286'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/2982204893594218286'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-5-clean-code-is.html' title='Building HelloSun, Step 5: Clean Code is Happy Code'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-7094842247046770859</id><published>2012-06-08T11:11:00.000-07:00</published><updated>2012-06-09T14:25:40.405-07:00</updated><title type='text'>Building HelloSun, Step 4: Real-Time Chat</title><content type='html'>&lt;table bgcolor=&quot;#ffcc7f&quot; border=&quot;0&quot; style=&quot;width: 98%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;&lt;i&gt;HelloSun:
A guide to
creating a social networking empire, from scratch, for free, circa 2012.&lt;/i&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-3-being-express.html&quot;&gt;⇐ Step 3&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;20%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html&quot;&gt;T.O.C.&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-5-clean-code-is.html&quot;&gt;Step 5 ⇒&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
HelloSun is going to be a kind of chat app, so for the next step let&#39;s
make a very very very basic real-time basic chat page. It seems that
the&amp;nbsp;first thing anyone does when doing a node server is a chat
app, so there are a whole lot of examples to &lt;i&gt;borrow&lt;/i&gt;
from.&lt;br /&gt;
&lt;br /&gt;
For the first chat page I’ll steal liberally from the example at &lt;a href=&quot;https://github.com/jmg/node-simple-chat&quot;&gt;https://github.com/jmg/node-simple-chat&lt;/a&gt;,
making only minimal changes to make it work with Heroku and with the
jade template language (for no other reason than I’m looking for
excuses to learn more about Heroku and jade).&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;choosing socket.io for real-time(ish) push&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
&lt;br /&gt;
A real-time chat app is one where as soon as somebody enters a message,
everyone else on the chat sees it right away. In the traditional browser
model, the browser client is not updated until the browser pulls data
from the server (e.g. through a page refresh), but in this use it makes
more sense to think of the browser &lt;i&gt;pushing&lt;/i&gt; data to
the client when it&#39;s available. Over the years many tricks have been
developed to make it seem like the server can push data (many
documented at &lt;a href=&quot;http://en.wikipedia.org/wiki/Push_technology&quot;&gt;Wikipedia
Push Technology&lt;/a&gt;), and even more options are available as &lt;a href=&quot;http://en.wikipedia.org/wiki/WebSocket&quot;&gt;WebSockets&lt;/a&gt;
become standardized.&lt;br /&gt;
&lt;br /&gt;
The existing push technologies are a big bag of kludgy tricks that
vary depending on the capabilities of the exact browser being used, and
so I&#39;m very glad that someone has bundled up a library of code to
manage all of these differences once and for all, in a library called &lt;a href=&quot;http://socket.io/&quot;&gt;socket.io&lt;/a&gt;. The the &lt;a href=&quot;http://socket.io/&quot;&gt;socket.io&lt;/a&gt; javascript
library provides a single simple interface to direct communication
between the client and the server, hiding whatever different methods
are used to pull off the trick. (&lt;i&gt;Thank you very much, &lt;a href=&quot;http://www.devthought.com/&quot;&gt;Guillermo Rauch&lt;/a&gt;!&lt;/i&gt;)
Another nice feature of socket.io is that the API for the client and
for the server are nearly identical (which is the &quot;client&quot; and which is
the &quot;server&quot; doesn&#39;t matter any more).&lt;br /&gt;
&lt;br /&gt;
socket.io has just two primary methods that we care the most about:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;emit()&lt;/b&gt; sends a message to the other end
of the connection&lt;/li&gt;
&lt;li&gt;&lt;b&gt;on()&lt;/b&gt; receives an event (usually a message
from the other end of the connection)&lt;/li&gt;
&lt;/ul&gt;
&lt;big&gt;&lt;b&gt;Installing socket.io&lt;/b&gt;&lt;br /&gt;
&lt;/big&gt;&lt;br /&gt;
socket.io is under rapid development, but I believe I&#39;ve found one that
works stably on Heroku. To use this version of socket.io add this
dependency line to your &quot;package.json&quot; file:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; &quot;socket.io&quot;: &quot;0.9.6&quot;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
then run “&lt;code&gt;npm install -d&lt;/code&gt;&quot; to cause the latest
version of socket.io to be installed.&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;chatserver.js - server-side chat code&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
The server side of this chat server is in the new file &quot;chatserver.js&quot;
(see&amp;nbsp;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-4-real-time-chat.html#getcode&quot;&gt;Getting the code&lt;/a&gt;
below, or &lt;a href=&quot;https://raw.github.com/BrentNoorda/hellosun-tutorial/8c7d239ee7d14c39ad4f17a5e066d6ab55cf30c6/chatserver.js&quot; target=&quot;_blank&quot;&gt;view chatserver.js&lt;/a&gt;).
&quot;chatserver.js&quot; is almost directly taken from the &quot;chat.js&quot; file at the
&lt;a href=&quot;https://github.com/jmg/node-simple-chat&quot;&gt;node-simple-chat&lt;/a&gt;
project we&#39;re plagiarizing. The primary change is in these lines:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; io.configure(function () { io.set(&quot;transports&quot;,
[&quot;xhr-polling&quot;]);&lt;br /&gt;
&amp;nbsp; io.set(&quot;polling duration&quot;, 10); });&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
which are taken from Heroku&#39;s advice at &lt;a href=&quot;https://devcenter.heroku.com/articles/using-socket-io-with-node-js-on-heroku&quot;&gt;Using
Socket.IO with Node.js on Heroku&lt;/a&gt; to prevent socket.io from
trying tricks that Heroku doesn&#39;t support.&lt;br /&gt;
&lt;br /&gt;
This &quot;chatserver.js&quot; code, after connecting with the client, simply
receives JSON strings labelled as &quot;msg&quot; (we could have picked any
label, so long as it matches label the client sends), and appends that
to the list of messages, and broadcasts the message to all connected
clients. Pretty straightforward. &amp;nbsp;&lt;i&gt;(I&#39;m not a fan of
the &quot;Array.prototype.inject&quot; trick in this code, but plagiarizers don&#39;t
have much right to complain.)&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
To load &quot;chatserver.js&quot;, the file &quot;app.js&quot; (see&amp;nbsp;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-4-real-time-chat.html#getcode&quot;&gt;Getting the code&lt;/a&gt;
below, or &lt;a href=&quot;https://raw.github.com/BrentNoorda/hellosun-tutorial/8c7d239ee7d14c39ad4f17a5e066d6ab55cf30c6/app.js&quot; target=&quot;_blank&quot;&gt;view app.js&lt;/a&gt;) gets this line added
at the end:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; var chatserver_io =
require(&#39;./chatserver&#39;).start(app);&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;chatty.jade - client-side chat code&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
The client side of the chat server is in the new file
&quot;views/chatty.jade&quot; (see &lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-4-real-time-chat.html#getcode&quot;&gt;Getting the code&lt;/a&gt; below, or &lt;a href=&quot;https://raw.github.com/BrentNoorda/hellosun-tutorial/8c7d239ee7d14c39ad4f17a5e066d6ab55cf30c6/views/chatty.jade&quot; target=&quot;_blank&quot;&gt;view views/chatty.jade&lt;/a&gt;)
&amp;nbsp;&quot;chatty.jade&quot; is almost directly taken from the &quot;chat.html&quot;
file at the &lt;a href=&quot;https://github.com/jmg/node-simple-chat&quot;&gt;node-simple-chat&lt;/a&gt;
project we&#39;re plagiarizing, only changed to support the jade templating
library.&lt;br /&gt;
&lt;br /&gt;
&quot;chatty.jade&quot; is straightforward. It collects input, sends it to the
server (with&amp;nbsp;&lt;code&gt;socket.emit(&#39;msg&#39;,...)&lt;/code&gt;),
and displays in the chat window any chat messages it received from the
server (with&amp;nbsp;&lt;code&gt;socket.on(&#39;msg&#39;)&lt;/code&gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;div style=&quot;background-color: #eeeeee; margin-left: 1em; padding: 5px;&quot;&gt;
&lt;b&gt;Warning:
including &#39;socket.io.js&#39; in the web page contains &lt;i&gt;magic&lt;/i&gt;&lt;br /&gt;
&lt;/b&gt;&lt;br /&gt;
In my opinion, the creators of &quot;socket.io&quot; were just a tiny bit too
clever in integrating socket.io with node.js, because the way it gets
included seems to much like magic. &amp;nbsp;In &quot;chatty.jade&quot; socket.io
is included with this single line:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; script(src=&quot;/socket.io/socket.io.js&quot;)&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
which jade turns into this line in the client html file:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; &amp;amp;lt;script
src=&quot;/socket.io/socket.io.js&quot;&amp;gt;&amp;amp;lt;/script&amp;gt;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
But if you look on the server under the directory where you expect
javascript files to be loaded, which is in &quot;/public/javascripts&quot;, there
is no &quot;socket.io.js&quot; file there. &amp;nbsp;So how does &quot;socket.io.js&quot;
get loaded in the client if the file doesn&#39;t exist on the server?
That&#39;s where the &lt;i&gt;magic&lt;/i&gt; comes in:&lt;br /&gt;
&lt;br /&gt;
When socket.io is initialized on the server (&lt;code&gt;require(&#39;socket.io&#39;).listen(app)&lt;/code&gt;
in chatserver.js) the socket.io adds a lot of code, much of which
alters the server socket code. Part of that alteration is to
specifically manage a request for the file &quot;socket.io/socket.io.js&quot;, at
which point the server-side socket.io code puts together an appropriate
socket.io.js file and delivers that to the client. &amp;nbsp;Magic!&lt;/div&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;SUMMARY OF CHANGES&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
Here&#39;s a summary of all the changes made in this version (see &lt;a href=&quot;http://www.blogger.com/blogger.g?blogID=4228702729472041146#getcode&quot;&gt;Getting the code&lt;/a&gt; below for full
source):&lt;br /&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;add chatserver.js (plagiarized) to use
socket.io, and initialize from apps.js&lt;/li&gt;
&lt;li&gt;create chatty.jade and chatty.css
(plagiarized) to be a page for the chatty client, and make express
render aware of it through changes to routes/index.js and app.js&lt;/li&gt;
&lt;li&gt;change layout.js to support block in
templates, and alter views/index.jade and apps.js to turn that on&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;Test and Deploy:&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
If you run this new code locally (&lt;code&gt;# foreman start&lt;/code&gt;)
and check http://localhost:3000/, or push this code to the live server
(commit with git, then&amp;nbsp;&lt;code&gt;# heroku restart web.1&lt;/code&gt;),
you should see a new chat window looking much like this:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw2IT1kkBuGq1cuigkcPzhDLcRHCQjNm1uurk7oaX2xX0JWqgvmK2gMZdeYr2IeTEixh7pZskkjHTlJaCRzhkUr8FiqQStt8EYYNkxG_ps9g9dAuLWDQbHdn7vRuZ7ux0g-CyPjH2uJelc/s1600/RealTimeChat.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw2IT1kkBuGq1cuigkcPzhDLcRHCQjNm1uurk7oaX2xX0JWqgvmK2gMZdeYr2IeTEixh7pZskkjHTlJaCRzhkUr8FiqQStt8EYYNkxG_ps9g9dAuLWDQbHdn7vRuZ7ux0g-CyPjH2uJelc/s400/RealTimeChat.png&quot; width=&quot;366&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
Now you have a chat-window, live on the web, that anyone can join at any time (from any browser?). &amp;nbsp;Whoopee!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;&lt;a href=&quot;http://www.blogger.com/blogger.g?blogID=4228702729472041146&quot; name=&quot;getcode&quot;&gt;&lt;/a&gt;Getting the code&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Today&#39;s code is labeled v0001.0003 and is available in these formats:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/tree/8c7d239ee7d14c39ad4f17a5e066d6ab55cf30c6&quot;&gt;browse the code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/compare/v0001.0002...v0001.0003&quot;&gt;all v0001.0002...v0001.0003 code changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;zip:
    &lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/zipball/v0001.0003&quot;&gt;https://github.com/BrentNoorda/hellosun-tutorial/zipball/v0001.0003&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tarball:
    &lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/tarball/v0001.0003&quot;&gt;https://github.com/BrentNoorda/hellosun-tutorial/tarball/v0001.0003&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;git:&lt;br /&gt;
&amp;nbsp;# git clone git@github.com:BrentNoorda/hellosun-tutorial.git&lt;br /&gt;
&amp;nbsp;# cd hellosun-tutorial&lt;br /&gt;
&amp;nbsp;# git checkout v0001.0003&lt;/li&gt;
&lt;/ul&gt;
&lt;table bgcolor=&quot;#ffcc7f&quot; border=&quot;0&quot; style=&quot;width: 98%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;&lt;i&gt;HelloSun:
A guide to
creating a social networking empire, from scratch, for free, circa 2012.&lt;/i&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-3-being-express.html&quot;&gt;⇐ Step 3&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;20%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html&quot;&gt;T.O.C.&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-5-clean-code-is.html&quot;&gt;Step 5 ⇒&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/7094842247046770859/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-4-real-time-chat.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/7094842247046770859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/7094842247046770859'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-4-real-time-chat.html' title='Building HelloSun, Step 4: Real-Time Chat'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw2IT1kkBuGq1cuigkcPzhDLcRHCQjNm1uurk7oaX2xX0JWqgvmK2gMZdeYr2IeTEixh7pZskkjHTlJaCRzhkUr8FiqQStt8EYYNkxG_ps9g9dAuLWDQbHdn7vRuZ7ux0g-CyPjH2uJelc/s72-c/RealTimeChat.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-8309303057154842812</id><published>2012-06-07T10:31:00.000-07:00</published><updated>2012-06-11T14:24:42.328-07:00</updated><title type='text'>Building HelloSun</title><content type='html'>&lt;table bgcolor=&quot;#ffcc7f&quot; border=&quot;0&quot; style=&quot;width: 98%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot;&gt;&lt;i&gt;HelloSun:
A guide to
creating a social networking empire, from scratch, for free, circa 2012.&lt;/i&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
The latest version of this application is always running at &lt;a href=&quot;http://hellosun.herokuapp.com/&quot;&gt;http://hellosun.herokuapp.com/&lt;/a&gt; &amp;nbsp;The code is also available &lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial&quot;&gt;on github&lt;/a&gt;.&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-1-planning.html&quot;&gt;Step 1: Planning&lt;/a&gt;&amp;nbsp;- What&#39;s the project? What are the Goals?&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-2-hello-node.html&quot;&gt;Step 2:&amp;nbsp;Hello Node &amp;amp; Heroku&lt;/a&gt;&amp;nbsp;- Choosing a PaaS and Server Technology&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-3-being-express.html&quot;&gt;Step 3:&amp;nbsp;Being Express-y&lt;/a&gt;&amp;nbsp;- Configuration the default Node framework: Express&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-4-real-time-chat.html&quot;&gt;Step 4:&amp;nbsp;Real-Time Chat&lt;/a&gt; - Adding a real-time chat page with socket.io&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-5-clean-code-is.html&quot;&gt;Step 5: Clean Code is Happy Code&lt;/a&gt; - Minor code cleanup; no new functionality&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-6-speech-bubbles.html&quot;&gt;Step 6: Speech Bubbles&lt;/a&gt; - Use speech bubbles, and css changes, to look like a better chat program, especially on a mobile phone&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Step 7: ???&lt;/li&gt;
&lt;/ul&gt;</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/8309303057154842812/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/8309303057154842812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/8309303057154842812'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html' title='Building HelloSun'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-92012301189058190</id><published>2012-06-07T10:22:00.001-07:00</published><updated>2012-06-09T10:36:40.389-07:00</updated><title type='text'>Building HelloSun, Step 3: Being Express-y</title><content type='html'>&lt;table bgcolor=&quot;#ffcc7f&quot; border=&quot;0&quot; style=&quot;width: 98%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;&lt;i&gt;HelloSun:
A guide to
creating a social networking empire, from scratch, for free, circa 2012.&lt;/i&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-2-hello-node.html&quot;&gt;⇐ Step 2&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;20%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html&quot;&gt;T.O.C.&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-4-real-time-chat.html&quot;&gt;Step 4 ⇒&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
In &lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-2-hello-node.html&quot;&gt;Step
2: Hello Node &amp;amp; Heroku&lt;/a&gt;, the Heroku setup and default
were a bit too basic. We&#39;re going to want to make something slightly
more complicated than a simple &quot;Hello World!&quot; page. We&#39;ll eventually
want multiple pages, with multiple HTML pages and related atrtibutes
(CSS,&amp;nbsp;Javasript, and images). We don&#39;t want to write any more
code than necessary, so we&#39;ll want to use some existing framework where
most of that grunt-work code has already been written. For this project
we&#39;ll use &lt;a href=&quot;http://expressjs.com/&quot;&gt;Express&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Why choose
Express?&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I put very little thought into choosing Express as my framework. A
version of Express was part of the default Heroku install, and a
cursory review of discussions about the topic make it look like Express
is currently the most active and popular. So I&#39;ll start there. If
Express turns out to be terrible... well, there&#39;s no better way to find
out that it sucks than to try it out for myself.&lt;br /&gt;
&lt;br /&gt;
In other words, I&#39;m using Express because everyone else is using it. (&lt;i&gt;And,
yes, if all my friends are jumping off a cliff then I&#39;m jumping off
with them.&lt;/i&gt;)&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;(Re)Installing Express&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
Even though the Heroku install used Express by default, it didn&#39;t use
Express in a standard &quot;Expressy&quot; way. So we&#39;ll do some quick changes to
convert the default Heroku install into something that looks normal for
default Express users. (&lt;i&gt;Let&#39;s try not to reinvent anything
fancy
yet, and stick to the defaults.&lt;/i&gt;)&lt;br /&gt;
&lt;br /&gt;
From within our application&#39;s directory (which we&#39;ve been calling
&quot;~/hellosunx444&quot;) let&#39;s generate a default express app as defined at &lt;a href=&quot;http://expressjs.com/guide.html&quot;&gt;http://expressjs.com/guide.html&lt;/a&gt;
with this command:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; # cd ~/hellosunx444&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;nbsp; # node_modules/express/bin/express .&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
This command will add a lot of default&amp;nbsp;directories that
Express depends on (e.g. &quot;views&quot;, &quot;public&quot;), will add some dependencies
on &lt;a href=&quot;http://jade-lang.com/&quot;&gt;Jade&lt;/a&gt; (the
default Express template engine--&lt;i&gt;we like starting with defaults&lt;/i&gt;),
and a new &quot;app.js&quot; file.&lt;br /&gt;
&lt;br /&gt;
This install will also have altered &quot;package.json&quot; in small ways, some
of which we want to fix, so that &quot;package.json&quot; now looks like this:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &quot;name&quot;: &quot;hellosun&quot;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; , &quot;version&quot;: &quot;0.0.1&quot;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; , &quot;private&quot;: true&lt;br /&gt;
&amp;nbsp; &amp;nbsp; , &quot;dependencies&quot;: {&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; &amp;nbsp; &quot;express&quot;: &quot;2.5.8&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; , &quot;jade&quot;: &quot;&amp;gt;= 0.0.1&quot;&lt;br /&gt;
&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp; , &quot;pg&quot;: &quot;0.5.4&quot;&lt;br /&gt;
&amp;nbsp; &amp;nbsp; }&lt;br /&gt;
&amp;nbsp; }&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
As we&#39;ll do after every change to &quot;package.json&quot;, run this command so
all our packages are updated:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; # npm install -d&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;Adjusting default Express files to run on Heroku&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
A couple of changes to the Heroku files will get us back on track to
have a standard Express layout be running on Heroku.&lt;br /&gt;
&lt;br /&gt;
Express&#39; default starting file is&amp;nbsp;“app.js”, while the original
heroku sample ran as “web.js”.&amp;nbsp;You want Heroku to be using
this “app.js” instead of the old “web.js” so edit the file “Procfile”
to be&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; web: node app.js&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
We only want one change from the previous &quot;web.js&quot; file, and that is
part that adjusts the port to be running on for the Heroku environment.
When running locally we can specify the port, but in the heroku
environment heroku will be selecting that port for us (it&#39;s background
system will have some kind of gateway and port 80, but that will be
redirecting to some port of its choosing). In &quot;web.js&quot; that line was:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; var port = process.env.PORT || 3000;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
In the “app.js” file created by Express the same can be done by
replacing:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; app.listen(3000);&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
with&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; app.listen(process.env.PORT || 3000);&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
If we test this code locally (&lt;code&gt;# foreman start&lt;/code&gt;)
and check &lt;a href=&quot;http://localhost:3000/&quot;&gt;http://localhost:3000/&lt;/a&gt;,
or push this code to the live server (&lt;code&gt;# heroku restart web.1&lt;/code&gt;),
then check &lt;a href=&quot;http://hellosunx444.herokuapp.com/&quot;&gt;http://hellosunx444.herokuapp.com/&lt;/a&gt;
we see it’s running the new Express code.&lt;br /&gt;
&lt;br /&gt;
Go ahead and delete the &quot;web.js&quot; file; it is no longer needed. (&lt;i&gt;I
don&#39;t like to keep files around that aren&#39;t being used--that&#39;s just
confusing.&lt;/i&gt;)&lt;br /&gt;
&lt;br /&gt;
&lt;big&gt;&lt;b&gt;Create the first HelloSun Express application&lt;br /&gt;
&lt;/b&gt;&lt;/big&gt;&lt;br /&gt;
The default home file that Express created is in “routes/index.js”
(more on how this resolves later). Change &quot;title&quot; to “HelloSun” to
match our program.&lt;br /&gt;
&lt;br /&gt;
After pushing to the server (&lt;code&gt;# heroku restart web.1&lt;/code&gt;),
we have an Express app named “HelloSun” that runs on Heroku. Yea!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Getting the code&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Today&#39;s code is labeled v0001.0002 and is available in these formats:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/tree/67626096f2955c1387329c7cdd42ca0ab74aa184&quot;&gt;browse the code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/compare/v0001.0001...v0001.0002&quot;&gt;all v0001.0001...v0001.0002 code changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;zip:
    &lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/zipball/v0001.0002&quot;&gt;https://github.com/BrentNoorda/hellosun-tutorial/zipball/v0001.0002&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tarball:
    &lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/tarball/v0001.0002&quot;&gt;https://github.com/BrentNoorda/hellosun-tutorial/tarball/v0001.0002&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;git:&lt;br /&gt;
&amp;nbsp;# git clone git@github.com:BrentNoorda/hellosun-tutorial.git&lt;br /&gt;
&amp;nbsp;# cd hellosun-tutorial&lt;br /&gt;
&amp;nbsp;# git checkout v0001.0002&lt;/li&gt;
&lt;/ul&gt;
&lt;table bgcolor=&quot;#ffcc7f&quot; border=&quot;0&quot; style=&quot;width: 98%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;&lt;i&gt;HelloSun:
A guide to
creating a social networking empire, from scratch, for free, circa 2012.&lt;/i&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-2-hello-node.html&quot;&gt;⇐ Step 2&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;20%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html&quot;&gt;T.O.C.&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-4-real-time-chat.html&quot;&gt;Step 4 ⇒&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/92012301189058190/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-3-being-express.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/92012301189058190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/92012301189058190'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-3-being-express.html' title='Building HelloSun, Step 3: Being Express-y'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-5464174609909628207</id><published>2012-06-05T14:02:00.000-07:00</published><updated>2012-06-11T13:59:05.750-07:00</updated><title type='text'>Building HelloSun, Step 2: Hello Node &amp; Heroku</title><content type='html'>&lt;table bgcolor=&quot;#ffcc7f&quot; border=&quot;0&quot; style=&quot;width: 98%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;&lt;i&gt;HelloSun:
A guide to
creating a social networking empire, from scratch, for free, circa 2012.&lt;/i&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-1-planning.html&quot;&gt;⇐ Step 1&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;20%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html&quot;&gt;T.O.C.&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-3-being-express.html&quot;&gt;Step 3 ⇒&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
In &lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-1-planning.html&quot;&gt;Step 1: Planning&lt;/a&gt;, part of the goal was to “use the latest &amp;amp; simplest techniques and tools, and zero upfront costs.”&lt;br /&gt;
&lt;br /&gt;
The “&lt;b&gt;simplest techniques&lt;/b&gt;” goal leads me to choose a &lt;a href=&quot;http://en.wikipedia.org/wiki/Platform_as_a_service&quot;&gt;Platform as a Service (PaaS)&lt;/a&gt; solution. With PaaS, the service provider handles most of the infrastructure involved in handling a web server. I simply must write the code that’s unique to my particular application. There is an &lt;a href=&quot;http://upon2020.com/2011/04/the-ever-growing-list-of-paas-companies-and-paas-projects/&quot;&gt;Ever-Growing List of PaaS Companies&lt;/a&gt; to choose from.&lt;br /&gt;
&lt;br /&gt;
The “&lt;b&gt;zero upfront costs&lt;/b&gt;” goal narrows down the list to those that offer a free option. Many of them offer free getting-started options, either for a limited time or for a limited amount of CPU and bandwidth.&lt;br /&gt;
&lt;br /&gt;
The “&lt;b&gt;latest techniques and tools&lt;/b&gt;” goal makes me want to chose &lt;a href=&quot;http://nodejs.org/&quot;&gt;Node.js&lt;/a&gt; as the server technology. Node.js is a javascript-based server that, because it almost totally event-driven and non-blocking, leads to efficiency, meaning: this model should allow me to support the most clients possible before having to move to a paid service. I almost went with Ruby, simply as an excuse to learn a new language, but it’s not quite “the latest thing” anymore, I had trouble installing it locally (more on that later), and I hear some disappointing things about its throughput. (I also am persuaded to choose Node.js because of a personal &lt;a href=&quot;https://docs.google.com/document/pub?id=1bRrq6mr3ocsNBloeDrBTLh6wT7JCfUZNFwU7E7P1UNk&quot;&gt;long history behind Javascript&lt;/a&gt;, as well as recent fun creating the &lt;a href=&quot;http://www.problemssolvingproblems.com/home/crappynet&quot;&gt;CrappyNet&lt;/a&gt; bad-networking RESTful stress tester.)&lt;br /&gt;
&lt;br /&gt;
I chose &lt;a href=&quot;http://www.heroku.com/&quot;&gt;Heroku&lt;/a&gt; as my PaaS for this project because it supports Node.js and has a nice free option: the equivalent of one server process (enough for Node.js to handle many clients) along with a small free database options (enough for a sunrise-limited window of chats, if that even needs to be part of a database), and because of these additional considerations:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Documentation – Heroku’s documentation seems concise and mostly correct.&lt;/li&gt;
&lt;li&gt;Local Development and Testing – With the Heroku stack I can easily run the app on my local computer very close to how it will run on the server. &lt;i&gt;Thing globally, develop and test locally.&lt;/i&gt;&lt;/li&gt;
&lt;li&gt;Easy Deployment – After testing locally, deploying to Heroku is as easy as a git push.&lt;/li&gt;
&lt;li&gt;Easy to Switch (no Heroku lock-in) – Because there is nothing special or proprietary to Heroku or the stack I’m using, I can easily stop using Heroku at any time and switch to many other PaaS or, if this service is doing spectacularly well, I can easily move to my own servers at any time.&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Get git&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
git version control is required for working with Heroku. Introducing git is outside the scope of this post, but if you’re doing anything in software these days you need to become familiar with it, so you may as well start at the &lt;a href=&quot;http://git-scm.com/&quot;&gt;Official git website&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Install Node locally&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Using the Node Installer is super simple. Just download from &lt;a href=&quot;http://nodejs.org/#download&quot;&gt;http://nodejs.org/#download&lt;/a&gt;. &amp;nbsp;I do not recommend getting the latest version of Node from their github repository because those versions are too new to match what is running on Heroku.&lt;br /&gt;
&lt;br /&gt;
After installing node I can run “node --version&quot; at the command line and see that I have “v0.6.18”. &amp;nbsp;This is close to what is on Heroku and hopefully will work fine.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Get a Heroku Account&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Sign Up for an account at &lt;a href=&quot;https://api.heroku.com/signup&quot;&gt;https://api.heroku.com/signup&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Install the Heroku Toolbelt Locally&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
The Heroku documentation is very straightforward at &lt;a href=&quot;https://devcenter.heroku.com/&quot;&gt;https://devcenter.heroku.com/&lt;/a&gt;. In particular, I followed the steps at &lt;a href=&quot;https://devcenter.heroku.com/articles/nodejs&quot;&gt;Getting Started with Node.js on Heroku/Cedar&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
In &lt;a href=&quot;https://devcenter.heroku.com/articles/nodejs#local_workstation_setup&quot;&gt;Local Workstation Setup&lt;/a&gt; you’ll install the &lt;a href=&quot;https://toolbelt.herokuapp.com/&quot;&gt;Heroku Toolbelt&lt;/a&gt;, which is what will let you run all the necessary Heroku tools from the command line on your local computer.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Write and test your first App&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Heroku’s &lt;a href=&quot;https://devcenter.heroku.com/articles/nodejs#write_your_app&quot;&gt;Write Your App&lt;/a&gt; instructions worked almost perfectly for me, except that the version of “express” in their example did not match the default I found with the heroku install, and I had a new name for my app. So my version of package.json is:&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;name&quot;: &quot;hellosun&quot;, // your name, e.g. &quot;hellosunx444&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;version&quot;: &quot;0.0.1&quot;,&lt;br /&gt;&amp;nbsp; &amp;nbsp; &quot;dependencies&quot;: {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;express&quot;: &quot;2.5.8&quot;&lt;br /&gt;&amp;nbsp; &amp;nbsp; },&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;nbsp; &amp;nbsp; &quot;engines&quot;: {&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;node&quot;: &quot;0.6.x&quot;,&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;npm&quot;: &amp;nbsp;&quot;1.1.x&quot;&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;&amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;&amp;nbsp; }&lt;/code&gt;&lt;br /&gt;
&lt;br /&gt;
After following the next set of the instruction at at &lt;a href=&quot;https://devcenter.heroku.com/articles/nodejs&quot;&gt;Getting Started with Node.js on Heroku/Cedar&lt;/a&gt; (create web.js, “npm install”, create .gitignore, create Procfile) you should be able to run the code locally with this command:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;$ foreman start&lt;/span&gt;&lt;/blockquote&gt;
Test this with a browser at &lt;a href=&quot;http://localhost:5000/&quot;&gt;http://localhost:5000/&lt;/a&gt;. If that shows “Hello World!” then you’ve got a local node server running the web.js code. Congratulations!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Deploy your first App to the World Wide Web&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Heroku’s &lt;a href=&quot;https://devcenter.heroku.com/articles/nodejs#deploy_to_herokucedar300&quot;&gt;Getting Started/Deploy&lt;/a&gt; instructions worked fine for me. They are:&lt;br /&gt;
&lt;blockquote class=&quot;tr_bq&quot;&gt;
&lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;$ git init&lt;br /&gt;$ git add .&lt;br /&gt;$ git commit -m &quot;init&quot;&lt;br /&gt;$ heroku create hellosunx444 --stack cedar&lt;br /&gt;$ git push heroku master&lt;br /&gt;$ heroku ps:scale web=1&lt;br /&gt;$ heroku config:add NODE_ENV=production&lt;/span&gt;&lt;/blockquote&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Testing your first App to the World Wide Web&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Browse to &lt;a href=&quot;http://hellosunx444.herokuapp.com/&quot;&gt;http://hellosunx444.herokuapp.com/&lt;/a&gt; and if you now see “Hello World!” then your application is now deployed to heroku. Congratulations!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Changing code and restarting&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
In step 3 through step X, we’ll be changing this code a lot. So let’s quickly cover how to change the code to “Hello Squirrel!” and redeploy:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Edit web.js to change “Hello World!” to “Hello Squirrel!”&lt;/li&gt;
&lt;li&gt;Test locally with “foreman start” and verify that &lt;a href=&quot;http://localhost:5000/&quot;&gt;http://localhost:5000/&lt;/a&gt; displays “Hello Squirrel!”&lt;/li&gt;
&lt;li&gt;Use git to push your change to web.js to the heroku git server (using your favorite git tools or commands, such as “$ git commit –a”, “$ git push”.&lt;/li&gt;
&lt;li&gt;Restart the heroku server with your new code: “$ heroku restart web.1”&lt;/li&gt;
&lt;li&gt;Verify that &lt;a href=&quot;http://hellosunx444.herokuapp.com/&quot;&gt;http://hellosunx444.herokuapp.com/&lt;/a&gt; now shows “Hello Squirrel!”&lt;/li&gt;
&lt;/ol&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Getting the code&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Today’s code is labeled v0001.0001 and is available in these formats:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/tree/c14e3cb460f8811a51fceb3beb163005cb659dd4&quot;&gt;browse the code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;zip: &lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/zipball/v0001.0001&quot;&gt;https://github.com/BrentNoorda/hellosun-tutorial/zipball/v0001.0001&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;tarball: &lt;a href=&quot;https://github.com/BrentNoorda/hellosun-tutorial/tarball/v0001.0001&quot;&gt;https://github.com/BrentNoorda/hellosun-tutorial/tarball/v0001.0001&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;git:&lt;br /&gt;&amp;nbsp;# git clone git@github.com:BrentNoorda/hellosun-tutorial.git&lt;br /&gt;&amp;nbsp;# cd hellosun-tutorial&lt;br /&gt;&amp;nbsp;# git checkout v0001.0001&lt;/li&gt;
&lt;/ul&gt;
&lt;table bgcolor=&quot;#ffcc7f&quot; border=&quot;0&quot; style=&quot;width: 98%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;&lt;i&gt;HelloSun:
A guide to
creating a social networking empire, from scratch, for free, circa 2012.&lt;/i&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-1-planning.html&quot;&gt;⇐ Step 1&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;20%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html&quot;&gt;T.O.C.&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-3-being-express.html&quot;&gt;Step 3 ⇒&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/5464174609909628207/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-2-hello-node.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/5464174609909628207'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/5464174609909628207'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-2-hello-node.html' title='Building HelloSun, Step 2: Hello Node &amp; Heroku'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-9127579117225569351</id><published>2012-06-04T11:50:00.003-07:00</published><updated>2012-06-09T10:13:09.092-07:00</updated><title type='text'>Building HelloSun, Step 1: Planning</title><content type='html'>&lt;table bgcolor=&quot;#ffcc7f&quot; border=&quot;0&quot; style=&quot;width: 98%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;&lt;i&gt;HelloSun:
A guide to
creating a social networking empire, from scratch, for free, circa 2012.&lt;/i&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;20%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html&quot;&gt;T.O.C.&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-2-hello-node.html&quot;&gt;Step 2 ⇒&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Background&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Much has changed since I wrote my first computer software in the late 1970s. Back then, if you’d told people you wanted to spend a couple of weeks creating a program that would instantaneously connect everyone in the world in a live experience, and that you intended to do it single handedly and for zero cost, they would have called you nuts.&lt;br /&gt;
&lt;br /&gt;
But now, in 2012, using the latest tools and languages, this should be a piece of cake. In this X-part series I intend to see if that’s true, and to document each step of the process.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Goal&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Use the latest &amp;amp; simplest techniques and tools, and zero upfront costs, to create a social networking app. And to document how it’s done.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;What is “HelloSun” (and why)?&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
First, I want to tackle something that contains most components of modern social software, but that is not too complex. “Chat” embodies a smallest-common-denominator component of social software, and does not introduce any radically new ideas.&lt;br /&gt;
&lt;br /&gt;
Second, I want something with a limited storage need, because I haven’t yet figured out how to stick to my “zero cost” goal if very much storage is involved (even though storage is very very cheap, anything beyond a fixed size is not yet free).&lt;br /&gt;
&lt;br /&gt;
Third, I want to explore the concept of the value of limitations. It seems that most applications or websites that catch on do so because they do so very little (at least initially), and that their virality is inversely proportional to their complexity. (Would Twitter have caught on if it allowed for long diatribes? Would Instagram have caught on if it didn’t have so few options? Would Facebook have ever reached the size it is now if it had started out as complicated-to-use as it is now?) So I want to create something that does as little as possible.&lt;br /&gt;
&lt;br /&gt;
To achieve the above goals I’m planning the “HelloSun” application. For most of the day (23+ hours of each day) HelloSun will do absolutely nothing. But during a few minutes before and after sunrise (whenever sunrise is for each user’s location), it will be a simple chat app shared by anyone in the world who is also experiencing sunrise. Then, for the rest of each day, it goes back to doing nothing, and the mornings chats are all gone forever (poof).&lt;br /&gt;
&lt;br /&gt;
HelloSun will be a brief chat window at the start of each day. That’s all!&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span style=&quot;font-size: large;&quot;&gt;Plan&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
I don’t know exactly what the plan is, since I haven’t started yet, but on day 1 here’s what I expect to do:&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Choose a PaaS (Platform as a service) provider that offers a free getting-started plan (probably Heroku).&lt;/li&gt;
&lt;li&gt;Choose a framework for writing server code (probably NodeJS because that seems to have all the latest buzz around it).&lt;/li&gt;
&lt;li&gt;Write a very basic web page (i.e. “hello world”).&lt;/li&gt;
&lt;li&gt;Write a basic chat server as a web page.&lt;/li&gt;
&lt;li&gt;Tie the server into a local (small) database of users (maybe) and chat info.&lt;/li&gt;
&lt;li&gt;Make the service use location information to only work at sunrise.&lt;/li&gt;
&lt;li&gt;Make the web-based chat server look pretty on multiple browser sizes (from desktop to mobile).&lt;/li&gt;
&lt;li&gt;Choose some framework for creating mobile apps (probably PhoneGap with Build).&lt;/li&gt;
&lt;li&gt;Create App version of HelloSun and get into the app stores (for iOS? Android? Etc…?)&lt;/li&gt;
&lt;li&gt;?&lt;/li&gt;
&lt;li&gt;Profit&lt;/li&gt;
&lt;/ol&gt;
&lt;i&gt;(Thanks to &quot;&lt;a href=&quot;http://www.southparkstudios.com/clips/151040/the-underpants-business&quot; target=&quot;_blank&quot;&gt;The Underpants Gnomes&lt;/a&gt;&quot; for the final phases of this business plan.)&lt;/i&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;table bgcolor=&quot;#ffcc7f&quot; border=&quot;0&quot; style=&quot;width: 98%;&quot;&gt;
  &lt;tbody&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; colspan=&quot;3&quot;&gt;&lt;i&gt;HelloSun:
A guide to
creating a social networking empire, from scratch, for free, circa 2012.&lt;/i&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;tr&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;20%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-table-of-contents.html&quot;&gt;T.O.C.&lt;/a&gt;
      &lt;/td&gt;
      &lt;td align=&quot;center&quot; width=&quot;40%&quot;&gt;&lt;a href=&quot;http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-2-hello-node.html&quot;&gt;Step 2 ⇒&lt;/a&gt;&lt;/td&gt;
    &lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/9127579117225569351/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-1-planning.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/9127579117225569351'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/9127579117225569351'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2012/06/building-hellosun-step-1-planning.html' title='Building HelloSun, Step 1: Planning'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-3252218309921555092</id><published>2010-06-10T19:08:00.001-07:00</published><updated>2012-06-02T17:24:13.613-07:00</updated><title type='text'>Code to convert .mp3 or .wav audio file to iPhone .caf format</title><content type='html'>iPhone likes to work with audio files compressed with &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_0&quot;&gt;ima&lt;/span&gt;4 and wrapped in the .&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_1&quot;&gt;caf&lt;/span&gt; format.  On OS X the &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_2&quot;&gt;afconvert&lt;/span&gt; command will do this, but I needed something for &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_3&quot;&gt;linux&lt;/span&gt;.  So I wrote some C code to do the conversion I needed: &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_4&quot;&gt;wav&lt;/span&gt;2&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_5&quot;&gt;caf&lt;/span&gt;.c&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_6&quot;&gt;wav&lt;/span&gt;2&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_7&quot;&gt;caf&lt;/span&gt; takes a &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_8&quot;&gt;wav&lt;/span&gt; file as input, and outputs an &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_9&quot;&gt;ima&lt;/span&gt;4-compressed .&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_10&quot;&gt;caf&lt;/span&gt; file suitable for playing on the &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_11&quot;&gt;iphone&lt;/span&gt;.  For source code, build, and install instructions, &lt;a href=&quot;http://dl.dropbox.com/u/41075/blogsupport/wav2caf.zip&quot;&gt;download here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Caveats: This source code expect the &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_12&quot;&gt;wav&lt;/span&gt; file to be 22050 Hz and single channel.  &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_13&quot;&gt;SOX&lt;/span&gt; will convert just about any audio file (e.g. mp3, m4a) to this format with a command such as &quot;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_14&quot;&gt;sox&lt;/span&gt; &lt;some&gt; -r 22050 -c 1 output.&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_15&quot;&gt;wav&lt;/span&gt;&quot;&lt;br /&gt;&lt;br /&gt;There&#39;s not much to the source file. &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_16&quot;&gt;wav&lt;/span&gt;2&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_17&quot;&gt;caf&lt;/span&gt;.c looks a bit like &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_18&quot;&gt;aifc&lt;/span&gt;2&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_19&quot;&gt;wav&lt;/span&gt;, because that&#39;s what I started with, then reversed it, sort of.  Good luck. If you make improvements let me know.&lt;/some&gt;</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/3252218309921555092/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2010/06/code-to-convert-mp3-or-wav-audo-file-to.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/3252218309921555092'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/3252218309921555092'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2010/06/code-to-convert-mp3-or-wav-audo-file-to.html' title='Code to convert .mp3 or .wav audio file to iPhone .caf format'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-432980510236229586</id><published>2010-05-06T21:22:00.000-07:00</published><updated>2010-05-06T21:57:53.929-07:00</updated><title type='text'>Help us move from Flash to HTML5 (part 1).</title><content type='html'>We found out that about 1 million internet users (those using an iPad) are unable to use our http://RadioWeave.com/ social/streaming radio site because it doesn&#39;t support Flash.&lt;br /&gt;&lt;br /&gt;So we&#39;ve tried to convert everything to HTML5, to get the same or good-enough functionality out of HTML5. There&#39;s no problem with the graphic stuff (HTML and Javascript can move images around just fine, thank you very much), but now we&#39;re down to replacing Flash audio with HTML5 audio, and it&#39;s giving us trouble.&lt;br /&gt;&lt;br /&gt;To make the very best audio experience (under even bad wifi connections), this is what we&#39;ve been doing with the Flash Sound and SoundChannel classes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;buffer the downloading of MP3 files, a few ahead of time&lt;/li&gt;&lt;li&gt;measure download rates (so we can download hifi or lofi files accordingly)&lt;/li&gt;&lt;li&gt;play during download&lt;br /&gt;&lt;/li&gt;&lt;li&gt;measure how much has been downloaded to display that information to the user&lt;/li&gt;&lt;li&gt;allow user to pause/play/pause&lt;br /&gt;&lt;/li&gt;&lt;li&gt;allow the user to reposition where in the track to play&lt;/li&gt;&lt;/ul&gt;With HTML5&#39;s &amp;lt;audio&amp;gt; tag and &amp;quot;HTMLAudioElement&amp;quot; we can download an MP3 file and make it play (although even this tends to crash Safari on OSX about as much as our Flash code would if pushed).  What we haven&#39;t figured out is how to know exactly when buffering has made progress, how much is buffered, how fast it is buffering, when playing starts, and how to restart play from any given position.&lt;br /&gt;&lt;br /&gt;We keep hearing that Flash is dead and no longer needed because HTML5 is ready to replace Flash.&lt;br /&gt;&lt;br /&gt;So, come on you Flash haters.  A little help, please?  Let us know (in the comments, so everyone can benefit) how to replace our Flash sound capabilities with HTML5.&lt;br /&gt;&lt;br /&gt;Thanks.</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/432980510236229586/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2010/05/help-us-move-from-flash-to-html5-part-1.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/432980510236229586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/432980510236229586'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2010/05/help-us-move-from-flash-to-html5-part-1.html' title='Help us move from Flash to HTML5 (part 1).'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-7496049801114721082</id><published>2009-02-26T16:21:00.000-08:00</published><updated>2009-02-26T17:07:43.307-08:00</updated><title type='text'>Django without cookies but putting the sessionid in the URL</title><content type='html'>&lt;span style=&quot;font-size:130%;&quot;&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Django sessions require cookies&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Django is written to assume that its client is a browser, and that its browser supports cookies.  The &quot;How to use sessions&quot; document makes it clear (&lt;a href=&quot;http://docs.djangoproject.com/en/dev/topics/http/sessions/?from=olddocs#session-ids-in-urls&quot; target=&quot;outty&quot;&gt;here&lt;/a&gt;) that this is an intentional design decision that use should be well aware of, especially if you want to break those rules as described here.  The reasons for that decision are clear and correct, but were not good for our uses.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;The Django cookie requirement was not good for our project&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;But in our own project, a community-based online radio network called &lt;span style=&quot;font-size:130%;&quot;&gt;&lt;a style=&quot;font-weight: bold;&quot; href=&quot;http://yiqyaq.com/&quot; target=&quot;_blank&quot;&gt;YiqYaq&lt;/a&gt;&lt;/span&gt;, which must support a wide range of client types, I found more and more reasons to want to use cookies.  These reasons were:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Our clients were often not browsers, but different tools.  We provide a simple url-based API to most functionality and forcing those clients to understand and support cookies too much work on the client&#39;s shoulders.  I.E. we want to make our API as easy as possible so more people will want to use it.&lt;/li&gt;&lt;li&gt;A surprising number of early testers (friends who we asked to preview our site and services) where on browsers that did not support cookies for random URLs, usually because that was IT corporate policy at their work, but sometimes because well-meaning any-malware supported that policy.&lt;/li&gt;&lt;li&gt;We were moving do Django from a tomcat implementation, and missed the convenence of having jsession id inserted and used (almost) automatically whenever cookies were not supported.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;So, for our project, we did the near-equivalent of tomcat&#39;s &quot;jsessionid&quot; for our web pages, and for our non-web clients expect them always to use jsessionid.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;Our implementation of &quot;jsessionid&quot; Django version 0.96.2&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Note: applies to Django version 0.96.2 -- I&#39;ve no idea what other versions this works with -- I also have not idea whether this is the best way to accomplish what I wanted, but it&#39;s the way that works for me&lt;br /&gt;&lt;br /&gt;I won&#39;t describe our utility functions for how we do the equivalent of tomcat&#39;s encodeURL, so that the sessionid is in the URL whenever cookies are not supported.  That is a fairly trivial issue, and is bound to be different on each site.  This article is about the primary problem, which is how to pass a string to the client to represent a session, how to get that string back from the client, and how to turn that string into a django session.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;1) Create the session_key magic value&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Once the authentication has happened, in standard django ways, we use this code to generate the &quot;session_key&quot; string&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;&lt;br /&gt;from django.contrib.sessions.models import Session&lt;br /&gt;from django.contrib.sessions.middleware import SessionWrapper&lt;br /&gt;...&lt;br /&gt;...&lt;br /&gt;...&lt;br /&gt;request.session = SessionWrapper(&quot;&quot;)&lt;br /&gt;auth.login(request, authuser)&lt;br /&gt;obj = Session.objects.get_new_session_object()&lt;br /&gt;session_key = obj.session_key&lt;br /&gt;new_session = Session.objects.save(session_key, request.session._session,&lt;br /&gt;       datetime.datetime.utcnow() + datetime.timedelta(seconds=(10 * 60 * 60)))&lt;br /&gt;# good for 10 hours&lt;/tt&gt;&lt;br /&gt;&lt;br /&gt;The session_key is then passed on to the client as the magic value to represent this session.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;2) Create the session_key magic value&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When the client contacts the server, and is not uing cookeis, it must then pass back the magic session_key value to the server as a parameter in its URL (or however else you want to pass it).  Turning that magic string into a session so that all your other django code can use it normally is trivial:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;    request.session = SessionWrapper(sessionid)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;what is less trivial is how to write data back to the session, in the same was as the cookie middleware would do it, so that changes to the session are preserved along with the magic cookie string.  In other words, the following code must be applied before your server returns to the client or else all the changes it may have made to the cookies will be lost:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 3em;font-family:courier new;&quot; &gt;    # sessions are written to work with browser cookies, but we don&#39;t want to work&lt;br /&gt;# with browswer cookies - so fake it&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 3em;font-family:courier new;&quot; &gt;    # this code is copied from django.contrib.session.middleware - the difference is&lt;br /&gt;# this code ignores cookies&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 3em;font-family:courier new;&quot; &gt;    # If request.session was modified, or if response.session was set, save&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 3em;font-family:courier new;&quot; &gt;    # those changes and set a session cookie.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 3em;font-family:courier new;&quot; &gt;    try:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 6em;font-family:courier new;&quot; &gt;        accessed = request.session.accessed&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 6em;font-family:courier new;&quot; &gt;        modified = request.session.modified&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 3em;font-family:courier new;&quot; &gt;    except AttributeError:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 6em;font-family:courier new;&quot; &gt;        pass&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 3em;font-family:courier new;&quot; &gt;    else:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 6em;font-family:courier new;&quot; &gt;        if modified:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 9em;font-family:courier new;&quot; &gt;            print &quot;MODIFIED!!!&quot;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 9em;font-family:courier new;&quot; &gt;            if request.session.session_key:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 12em;font-family:courier new;&quot; &gt;                print &quot;### USE OLD KEY ###&quot;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 12em;font-family:courier new;&quot; &gt;                session_key = request.session.session_key&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 9em;font-family:courier new;&quot; &gt;            else:&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 12em;font-family:courier new;&quot; &gt;                print &quot;### CREATE NEW KEY ###&quot;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 12em;font-family:courier new;&quot; &gt;                obj = Session.objects.get_new_session_object()&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 12em;font-family:courier new;&quot; &gt;                session_key = obj.session_key&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 9em;font-family:courier new;&quot; &gt;            print &quot;### AND SO ON ###&quot;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 9em;font-family:courier new;&quot; &gt;            new_session = Session.objects.save(session_key, request.session._session,&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;margin-left: 12em;font-family:courier new;&quot; &gt;                datetime.datetime.utcnow() + datetime.timedelta(seconds=(10 * 60 * 60)))&lt;br /&gt;  # good for 10 hours&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;&lt;br /&gt;Good luck&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;That&#39;s it.  I hope it works well for you.  It&#39;s been working well at &lt;a href=&quot;http://yiqyaq.com/&quot; target=&quot;outty&quot;&gt;YiqYaq&lt;/a&gt; so far.  And if you have better ways to do this I hope you let me know.</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/7496049801114721082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2009/02/django-without-cookies-but-putting.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/7496049801114721082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/7496049801114721082'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2009/02/django-without-cookies-but-putting.html' title='Django without cookies but putting the sessionid in the URL'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-1476558449337644977</id><published>2009-02-24T18:11:00.000-08:00</published><updated>2009-02-24T19:11:35.058-08:00</updated><title type='text'>Converting fom Screenflow .mov to Flash video .flv for our web site.</title><content type='html'>Over the weekend I did my first screencast demo for our &lt;a href=&quot;http://yiqyaq.com/&quot;  target=&quot;outty&quot;&gt;YiqYaq&lt;/a&gt; web-radio site, using Screenflow on Mac OS X.  The result was a big .mov file that had a couple of problems 1) it was too darn big, and 2) I could find lots of browser clients that would not play that .mov format.  Quick research showed that close to 100% of my audience could play flash videos.&lt;br /&gt;&lt;br /&gt;So my problem became, how to turn the Screenflow .mov file to a .flv playing on our web site.&lt;br /&gt;&lt;br /&gt;The first approach was to upload it to YouTube.  YouTube accepted the video, and converted it smoothly, but the final results was squashed down 360 pixels tall, which is too small to effectively show our demo.  (See the too-small youtube version &lt;a href=&quot;http://www.youtube.com/watch?v=D01rqGIz8M8&amp;amp;fmt=18&quot; target=&quot;outty&quot;&gt;here&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;After lots of trial and error, I did finally get to an acceptable embedded flash video .flv file, that I can embed on our web site.  Maybe there&#39;s a better approach, but these are the steps I took:&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-size:130%;&quot;&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;How I turned Screenflow into embedded Flash vide on our own web site (as seen &lt;a href=&quot;http://yiqyaq.com/v001/tutorials/intro_to_yy_video.mako&quot;&gt;here&lt;/a&gt;):&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;1) Record and edit with Screenflow&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I recorded the interraction of my browser along with audio.  The browser window happened to be set at 778x950 (widthxheight).  Editted the result, and did all the other demo stuff.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;2) Screenflow Export&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Selecting Screenflow Export I chose these settings:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;web high best quality&lt;/li&gt;&lt;li&gt;scale 74% to 576x702 (because 702 is short enough to fit on most computers yet tall enough to represent my screencast well, and also because 576 is divisible by 16--which turns out later to be important--and 702 is even; if these requirements had not been met I would have used a tiny bit of letterboxing to make sure they were matched)&lt;/li&gt;&lt;li&gt;enabled motion blur&lt;/li&gt;&lt;li&gt;change frame rate to 30 fps&lt;/li&gt;&lt;li&gt;change vide settings to optimize for streaming&lt;/li&gt;&lt;li&gt;change audio settings for best quality&lt;/li&gt;&lt;/ul&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;3) Compress and prepare with Stomp&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Stomp is software to compress video.  It costs a few dollars ($29).  For my purposes I didn&#39;t actually use it to compress so much as to reorder the audio/video so that the next phase (ffmpegX) doesn&#39;t have the jerky problems it gets from the way the Screenflow outputs audio in .mov files.&lt;br /&gt;&lt;br /&gt;For Stomp I used these settings always chooseing best quality versus lowest compression (which actually resulted in a larger file that what I started with, but I think that is taken care of later):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Make my own preset&lt;/li&gt;&lt;li&gt;30 fps&lt;/li&gt;&lt;li&gt;multipass&lt;/li&gt;&lt;li&gt;best compressor quality&lt;/li&gt;&lt;li&gt;audio best&lt;/li&gt;&lt;/ul&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;4) Convert to .flv with ffmpegX&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;ffmpegX is a minimal wrapper around a lot of open-source video software.  It&#39;s $15 shareware.  You can build all those video convert tools from the open source, but for me ffmpegX was worth it because, even though it was an effort to install, it was a whole lot less effort than installing all tools it&#39;s made from.&lt;br /&gt;&lt;br /&gt;From ffmpegX open the Stomped file and output to FLV format.  I used these options:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;From options selected &quot;High Quality&quot; and &quot;Two-pass encoding&quot;&lt;/li&gt;&lt;li&gt;video size 576x702&lt;/li&gt;&lt;li&gt;framerate 15 (which is half the framerate 30 used in steps up to this point)&lt;/li&gt;&lt;li&gt;play around with the video bitrate field until you get a value that ffmpegX shows up as green--sometimes it is slow to show this so you need to switch on different tabs to force it to update--in my case I ended up with video bitrate 1400&lt;/li&gt;&lt;/ul&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;5) AddFLV metadata with FLV MetaData Injector&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The file that results from ffmpegX does not have the metadata (especially for height and width) that the next step (JW Player) is going to need to display the video correctly (without the right metadata it will try to change the video to fit standard sizes).  To perform this step I downloaded the free windows tool &quot;FLV MetaData Injector&quot; and run the executable (&quot;flvmdi.exe&quot;) from a parallels session.  There are other FLV metadata injector source tools you can use and build, but this was the quickest way there that I found.&lt;br /&gt;&lt;br /&gt;The result of this step is a .FLV file suitable for any flash player.&lt;br /&gt;&lt;br /&gt;&lt;span style=&quot;font-weight: bold;&quot;&gt;6) Create web page and embed on web page with JW FLV Media Player&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Many users can play the FLV files directly, but they won&#39;t look very elegant.  It&#39;s also not very difficult to find a lot of FLV players, or even to roll your own.  But I was in a hurry and JW FLV Media Player did everything I wanted (at a cost--open source and free for non commercial but €39 for a commercial license on one web domain)&lt;br /&gt;&lt;br /&gt;Longtail provides very clear instructions for how to use their tool.  Remember to set the width and height to the video size of the .FLV file you&#39;ve been making, and to add at least 20 pixels to the height if you&#39;re going to use their control bar (which is the default).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;That&#39;s it.  Like I said, it may not be the best approach but it&#39;s the one I stumbled into and it worked for me (as seen &lt;a href=&quot;http://yiqyaq.com/v001/tutorials/intro_to_yy_video.mako&quot; target=&quot;outty&quot;&gt;here&lt;/a&gt;).</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/1476558449337644977/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2009/02/converting-fom-screenflow-mov-to-flash.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/1476558449337644977'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/1476558449337644977'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2009/02/converting-fom-screenflow-mov-to-flash.html' title='Converting fom Screenflow .mov to Flash video .flv for our web site.'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-640570436223965646</id><published>2008-05-24T19:45:00.000-07:00</published><updated>2008-05-25T11:26:23.482-07:00</updated><title type='text'>Using Django in command-line scripts</title><content type='html'>Over &lt;a href=&quot;http://surftrackr.net/blog/view/35/using-django-command-line-scripts/&quot;&gt;at this page&lt;/a&gt; is a reference to &quot;Using Django in command-line scripts&quot;.  Those tricks, which seem to load in enough of the django environment, weren&#39;t working for me in more complext db operations.   I made a little change to the setup described there, to force a loading of more of the django environment, and so far all of the operations that work rom within a django web-server can now be called from the command line, at least for me.&lt;br /&gt;&lt;br /&gt;In these cases, I&#39;m running the standalone pythong scripts (e.g. foo.py) from 2 directories below where the &quot;manage.py&quot; and &quot;settings.py&quot; scripts exist.&lt;br /&gt;&lt;br /&gt;Here&#39;s the code that starts all of the stand-alone python scripts running in that directory:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;##################################### BEGIN DJANGO PREAMBLE ####################################################################&lt;br /&gt;import os, sys&lt;br /&gt;# Preamble so we can use Django&#39;s DB API&lt;br /&gt;django_manager_dir = os.path.normpath(os.path.dirname(os.path.abspath(__file__)) + &quot;/../..&quot; ) + &quot;/&quot;;&lt;br /&gt;sys.path.append(django_manager_dir)&lt;br /&gt;from django.core.management import execute_manager&lt;br /&gt;import settings&lt;br /&gt;execute_manager(settings, argv=[&quot;blah&quot;,&quot;validate&quot;])&lt;br /&gt;###################################### END DJANGO PREAMBLE #####################################################################&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;After that preamble I seem to be able to use any of the django db calls without a problem.  Calling execute_manager(..&quot;validate&quot;) seems a little silly, since it should be like a no-op, but obviously it does something important for setting up the environment.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;FOLLOWUP: By using the suggestions at &lt;a href=&quot;http://www.b-list.org/weblog/2007/sep/22/standalone-django-scripts/&quot;&gt;http://www.b-list.org/weblog/2007/sep/22/standalone-django-scripts/&lt;/a&gt;  there&#39;s a better approach.  Replace the last three lines with these:&lt;br /&gt;&lt;code&gt;from django.core.management import setup_environ&lt;br /&gt;import settings&lt;br /&gt;setup_environ(settings)&lt;/code&gt;</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/640570436223965646/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2008/05/using-django-in-command-line-scripts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/640570436223965646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/640570436223965646'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2008/05/using-django-in-command-line-scripts.html' title='Using Django in command-line scripts'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-5646270145972023642</id><published>2008-05-16T12:31:00.001-07:00</published><updated>2008-05-16T12:32:08.460-07:00</updated><title type='text'>iTunes won&#39;t recognize iPhone after Leopard upgrade</title><content type='html'>I had this problem too.  Reinstalling iTunes solved it, and no data was lost.</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/5646270145972023642/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2008/05/itunes-wont-recognize-iphone-after.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/5646270145972023642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/5646270145972023642'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2008/05/itunes-wont-recognize-iphone-after.html' title='iTunes won&#39;t recognize iPhone after Leopard upgrade'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-4584882577038561160</id><published>2007-11-27T15:25:00.001-08:00</published><updated>2007-11-27T16:04:35.855-08:00</updated><title type='text'>Installing Java and Tomcat (without apache) on base Linux system (Amazon EC2 Fedora Core 4 image)</title><content type='html'>For YIQYAQ we&#39;re running Tomcat as the web server, on basic Linux Fedore Core 4 images at Amazon EC2.  These are the steps taken to install Java and Tomcat on those systems and get it running.  I&#39;m not much of a Linux, Java, or Tomcat expert, so I can&#39;t say these are the best steps to take, only that they&#39;re what I did and they seem to work.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Get java from http://java.sun.com/javase/downloads/index.jsp, install JRE self extracting file &lt;span style=&quot;font-family:courier new;&quot;&gt;jre-6u3-linux-i586.bin&lt;/span&gt; into the root of the linux system, then follow these command from the linux system&lt;br /&gt;&lt;/li&gt;&lt;ol&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;mkdir /java&lt;/li&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;mv /jre-6u3-linux-i586.bin /java/&lt;/li&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;cd /java&lt;/li&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;chmod 555 jre-6u3-linux-i586.bin&lt;/li&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;./jre-6u3-linux-i586.bin&lt;/li&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;rm jre-6u3-linux-i586.bin&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;Setup Java environment variables&lt;/li&gt;&lt;ol&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;cd ~&lt;/li&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;nano .bash_profile&lt;/li&gt;&lt;li&gt;add lines&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;JAVA_HOME=/java/jre1.6.0_03&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;export JAVA_HOME&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;JAVAHOME=/java/jre1.6.0_03&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;export JAVAHOME&lt;/span&gt;&lt;/li&gt;&lt;li&gt;lower down, change from&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;  PATH=$PATH:$HOME/bin&lt;/span&gt;&lt;br /&gt;to&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;  PATH=$PATH:$HOME/bin:$JAVA_HOME/bin&lt;/span&gt;&lt;/li&gt;&lt;li&gt;exit nano, exit shell, and restart shell to get new environment set up&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;Download tomcat 6.0.14 from http://tomcat.apache.org/download-60.cgi#6.0.14 to the root of your linux system as apache-tomcat-6.0.14.tar.gz, and follow these commands to install it&lt;/li&gt;&lt;ol style=&quot;font-family: courier new;&quot;&gt;&lt;li&gt;mkdir /tomcat&lt;/li&gt;&lt;li&gt;cd /tomcat&lt;/li&gt;&lt;li&gt;mv /apache-tomcat-6.0.14.tar.gz .&lt;/li&gt;&lt;li&gt;gunzip -c apache-tomcat-6.0.14.tar.gz | tar xopf –&lt;/li&gt;&lt;li&gt;rm apache-tomcat-6.0.14.tar.gz&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;Setup environment variables for tomcat&lt;/li&gt;&lt;ol&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;cd ~&lt;/li&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;nano .bash_profile&lt;/li&gt;&lt;li&gt;add lines&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;CATALINA_HOME=/tomcat/apache-tomcat-6.0.14&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;export CATALINA_HOME&lt;/span&gt;&lt;/li&gt;&lt;li&gt;exit nano, exit shell, and restart shell to get new environment set up&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;Test that tomcat is working.&lt;/li&gt;&lt;ol&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;cd ~CATALINA_HOME/bin&lt;/li&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;./startup.sh&lt;/li&gt;&lt;li&gt;From browser, verify that &lt;span style=&quot;font-family:courier new;&quot;&gt;http://your-web-domain-address:8080/&lt;/span&gt; returns the default tomcat page&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;Change tomcat to run on port 80 instead of 8080&lt;/li&gt;&lt;ol&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;cd $CATALINA_HOME&lt;/li&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;cp conf/server.xml conf/server.xml.original&lt;/li&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;nano conf/server.xml&lt;/li&gt;&lt;li&gt;replace all 8080 with 80, then exit and save&lt;/li&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;bin/shutdown.sh&lt;/li&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;bin/startup.sh&lt;/li&gt;&lt;li value=&quot;3&quot;&gt;From browser, verify that &lt;span style=&quot;font-family:courier new;&quot;&gt;http://your-web-domain-address/&lt;/span&gt; returns the default tomcat page&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;li&gt;Setup manager for Tomcat&lt;/li&gt;&lt;ol&gt;&lt;li style=&quot;font-family: courier new;&quot;&gt;nano $CATALINA_HOME/conf/tomcat-users.xml&lt;/li&gt;&lt;li&gt;add this user&lt;br /&gt;&lt;span style=&quot;font-family: courier new;font-family:courier new;&quot; &gt;&lt;tomcat-users&gt;&lt;/tomcat-users&gt;&lt;/span&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;&amp;lt;tomcat-users&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;role rolename=&quot;standard&quot;/&lt;/span&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;role rolename=&quot;manager&quot;/&lt;/span&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;  &lt;/span&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;user username=&quot;managername&quot; password=&quot;managerpwd&quot; roles=&quot;standard,manager&quot;/&lt;/span&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;/tomcat-users&lt;/span&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;replace &lt;span style=&quot;font-style: italic;font-family:courier new;&quot; &gt;managername&lt;/span&gt; and &lt;span style=&quot;font-style: italic;font-family:courier new;&quot; &gt;managerpwd&lt;/span&gt; with your real, super-duper top-secret values&lt;br /&gt;&lt;/li&gt;&lt;li&gt;restart tomcat&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;$CATALINA_HOME/bin/shutdown.sh&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;$CATALINA_HOME/bin/shutdown.sh&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/ol&gt;That&#39;s it.  All done.</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/4584882577038561160/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2007/11/installing-java-and-tomcat-without.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/4584882577038561160'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/4584882577038561160'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2007/11/installing-java-and-tomcat-without.html' title='Installing Java and Tomcat (without apache) on base Linux system (Amazon EC2 Fedora Core 4 image)'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-3127884603168027456</id><published>2007-11-27T14:46:00.000-08:00</published><updated>2007-11-27T15:08:13.434-08:00</updated><title type='text'>Installing ImageMagick with JPEG and PNG Support</title><content type='html'>&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_0&quot;&gt;ImageMagick&lt;/span&gt; is a set of command-line tools for manipulating image files.  By default it supports &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_1&quot;&gt;GIF&lt;/span&gt; but not the other command &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_2&quot;&gt;interweb&lt;/span&gt; formats of &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_3&quot;&gt;JPG&lt;/span&gt; (&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_4&quot;&gt;JPEG&lt;/span&gt;) and &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_5&quot;&gt;PNG&lt;/span&gt;.  These are the steps I followed to install &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_6&quot;&gt;ImageMagick&lt;/span&gt; on an Amazon EC2 Fedora core-4 Linux image.&lt;br /&gt;&lt;br /&gt;This process is also described at &lt;a href=&quot;http://www.randycullom.com/chatterbox/archives/2006/12/installing_imag.html&quot;&gt;Installing &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_7&quot;&gt;ImageMagick&lt;/span&gt; with &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_8&quot;&gt;JPEG&lt;/span&gt;, TIFF and &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_9&quot;&gt;PNG&lt;/span&gt; Support&lt;/a&gt;, but I had some problems with a couple of the commands there, it was using files older than the current, and it included TIFF support which I don&#39;t expect to be using.&lt;br /&gt;&lt;br /&gt;The first step was to get the required source files for each of the components required.  These are the files I retrieved, and the web addresses were I retrieved them.  (Note, the exact version numbers change over time.)  Each of the .tar.&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_10&quot;&gt;gz&lt;/span&gt; files I downloaded and copied to the &lt;span style=&quot;font-family:courier new;&quot;&gt;/&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_11&quot;&gt;usr&lt;/span&gt;/local/&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_12&quot;&gt;src&lt;/span&gt;&lt;/span&gt; directory of my EC2 &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_13&quot;&gt;linux&lt;/span&gt; system.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;ImageMagick.tar.gz&lt;/span&gt; from &lt;a href=&quot;http://imagemagick.org/script/install-source.php#unix&quot;&gt;http://imagemagick.org/script/install-source.php#unix&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;libpng-1.2.23.tar.gz&lt;/span&gt;  from &lt;a href=&quot;http://libpng.org/pub/png/libpng.html&quot;&gt;http://libpng.org/pub/png/libpng.html&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;jpegsrc.v6b.tar.gz&lt;/span&gt; from &lt;a href=&quot;http://www.ijg.org/files/&quot;&gt;http://www.ijg.org/files/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family: courier new;&quot;&gt;zlib-1.2.3.tar.gz&lt;/span&gt;  from &lt;a href=&quot;http://www.zlib.net/&quot;&gt;http://www.zlib.net/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;from my &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_14&quot;&gt;linux&lt;/span&gt; image I then performed these commands (and in this order) to unpack, compile, and install the components and &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_15&quot;&gt;ImageMagick&lt;/span&gt;.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_16&quot;&gt;cd&lt;/span&gt; /&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_17&quot;&gt;usr&lt;/span&gt;/local/&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_18&quot;&gt;src&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_19&quot;&gt;gunzip&lt;/span&gt; -c zlib-1.2.3.tar.gz | tar &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_20&quot;&gt;xvf&lt;/span&gt; -&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;rm zlib-1.2.3.tar.gz&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_21&quot;&gt;cd&lt;/span&gt; zlib-1.2.3&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;./configure&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;make&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;make install&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_22&quot;&gt;cd&lt;/span&gt; /&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_23&quot;&gt;usr&lt;/span&gt;/local/&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_24&quot;&gt;src&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_25&quot;&gt;gunzip&lt;/span&gt; -c libpng-1.2.23.tar.gz | tar &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_26&quot;&gt;xvf&lt;/span&gt; -&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;rm libpng-1.2.23.tar.gz&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_27&quot;&gt;cd&lt;/span&gt; libpng-1.2.23&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;./configure&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;make&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;make install&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_28&quot;&gt;cd&lt;/span&gt; /&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_29&quot;&gt;usr&lt;/span&gt;/local/&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_30&quot;&gt;src&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_31&quot;&gt;gunzip&lt;/span&gt; -c jpegsrc.v6b.tar.gz | tar &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_32&quot;&gt;xvf&lt;/span&gt; -&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;rm jpegsrc.v6b.tar.gz&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_33&quot;&gt;cd&lt;/span&gt; &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_34&quot;&gt;jpeg&lt;/span&gt;-6b&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;./configure --enable-shared&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;make&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;make install&lt;/span&gt;&lt;br /&gt;[may need to create man directories]&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_35&quot;&gt;cd&lt;/span&gt; /&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_36&quot;&gt;usr&lt;/span&gt;/local/&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_37&quot;&gt;src&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_38&quot;&gt;gunzip&lt;/span&gt; -c ImageMagick.tar.gz | tar &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_39&quot;&gt;xvf&lt;/span&gt; -&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;rm ImageMagick.tar.gz&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_40&quot;&gt;cd&lt;/span&gt; ImageMagick-6.3.7&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;./configure&lt;/span&gt;&lt;br /&gt;[verify that &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_41&quot;&gt;jpeg&lt;/span&gt; and &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_42&quot;&gt;png&lt;/span&gt; are on]&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;make&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;make install&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;Now run a simple test to see that &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_43&quot;&gt;ImageMagick&lt;/span&gt; is working&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_44&quot;&gt;cd&lt;/span&gt; /&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;identify –list Format&lt;/span&gt;&lt;br /&gt;[verify that &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_45&quot;&gt;jpeg&lt;/span&gt; and &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_46&quot;&gt;png&lt;/span&gt; are on]&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;convert logo: logo.&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_47&quot;&gt;gif&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;convert logo: logo.&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_48&quot;&gt;jpg&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;convert logo: logo.&lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_49&quot;&gt;png&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;[verify with separate viewer that this images are all OK]&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;That&#39;s it.  The &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_50&quot;&gt;ImageMagick&lt;/span&gt; command are now ready.</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/3127884603168027456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2007/11/installing-imagemagick-with-jpeg-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/3127884603168027456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/3127884603168027456'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2007/11/installing-imagemagick-with-jpeg-and.html' title='Installing ImageMagick with JPEG and PNG Support'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-84192292450121786</id><published>2007-11-27T14:38:00.000-08:00</published><updated>2007-11-28T15:23:39.049-08:00</updated><title type='text'>Installing GCC on Amazon EC2 fedora core 4 base</title><content type='html'>I&#39;m using the ec2-public-images/fedora-core4-base.manifest.xml image on Amazon&#39;s EC2 system.  (I don&#39;t know how this &lt;span class=&quot;blsp-spelling-corrected&quot; id=&quot;SPELLING_ERROR_0&quot;&gt;differs&lt;/span&gt; from the develop-image.manifest.xml, but wanted to start with something as basic as possible).&lt;br /&gt;&lt;br /&gt;This image comes without a &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_1&quot;&gt;GCC&lt;/span&gt; compiler.  There&#39;s almost nothing you can make out of Linux without a compiler.&lt;br /&gt;&lt;br /&gt;Adding a compiler is a piece of cake with this command&lt;ul&gt;&lt;span style=&quot;font-family:courier new;&quot;&gt;yum install &lt;span class=&quot;blsp-spelling-error&quot; id=&quot;SPELLING_ERROR_2&quot;&gt;gcc&lt;/span&gt;&lt;/span&gt;&lt;/ul&gt;That&#39;s it. super easy.  You can find more about yum (such as &lt;span style=&quot;font-family:courier new;&quot;&gt;yum update&lt;/span&gt;) &lt;a href=&quot;http://fedoranews.org/tchung/howto/2003-11-09-yum-intro.shtml&quot;&gt;here&lt;/a&gt;.</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/84192292450121786/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2007/11/installing-gcc-on-amazon-ec2-fedora.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/84192292450121786'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/84192292450121786'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2007/11/installing-gcc-on-amazon-ec2-fedora.html' title='Installing GCC on Amazon EC2 fedora core 4 base'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4228702729472041146.post-2930242690453993165</id><published>2007-10-01T20:27:00.000-07:00</published><updated>2007-10-01T20:41:40.363-07:00</updated><title type='text'>Portable MP3 in car sounds great via Cassette Adapter</title><content type='html'>We recently purchased a new adapter for playing our ipod / iphone in the car: the &lt;a href=&quot;http://catalog.belkin.com/IWCatProductPage.process?Product_Id=158168&quot;&gt;Belkin Mobile Cassette Adapter&lt;/a&gt;.  It sounds fantastic, especially compared to the old FM adapter we used to use.  Those FM mp3 &amp;amp; ipod adapters require finding an empty band, squashing music, sound yucky, and cost a lot more.  This cassette adapter was only about $15 at &lt;a href=&quot;http://www.frys.com/&quot;&gt;Fry&#39;s&lt;/a&gt;.  Any quality FM adapter costs a whole lot more and doesn&#39;t sound nearly as good.&lt;br /&gt;&lt;br /&gt;This cassette adapter worked right off with our old ipod mini.  For the iPhone I used a razor blade to trim away the last eighth-inch or so of rubber off the end of the plug, so it fits into the recessed iphone ear jack, and it works great.</content><link rel='replies' type='application/atom+xml' href='http://unlessimwrong.blogspot.com/feeds/2930242690453993165/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://unlessimwrong.blogspot.com/2007/10/portable-mp3-in-car-sounds-great-via.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/2930242690453993165'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4228702729472041146/posts/default/2930242690453993165'/><link rel='alternate' type='text/html' href='http://unlessimwrong.blogspot.com/2007/10/portable-mp3-in-car-sounds-great-via.html' title='Portable MP3 in car sounds great via Cassette Adapter'/><author><name>Brent Noorda</name><uri>http://www.blogger.com/profile/12692273208368568290</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGhIEOb_he8wXgG3PcoIjmQWRPRUBjlk2CiyIYL_LI9LpvgpxyLDjDYRS3Qq1V4uIge61i5HiZQuwv0agO_lRmzph3gfsmJjTWUb8btThDTPX1sOiEdy2IDMqXIVMbyg/s32/favicon.ico'/></author><thr:total>0</thr:total></entry></feed>