<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	
	xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Streamhead</title>
	<atom:link href="http://www.streamhead.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.streamhead.com</link>
	<description>multimedia webapplication thoughts and experiments</description>
	<lastBuildDate>Wed, 18 Apr 2012 12:58:33 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>Taking over the Codebase, Solving the Spaghetti Crisis</title>
		<link>http://www.streamhead.com/the-spaghetti-crisis/</link>
		<comments>http://www.streamhead.com/the-spaghetti-crisis/#comments</comments>
		<pubDate>Tue, 10 Apr 2012 14:00:47 +0000</pubDate>
		<dc:creator>Peter Backx</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.streamhead.com/?p=3428</guid>
		<description><![CDATA[We&#8217;ve all been there. Somebody asks if you can take a look at their website that has been stagnant for a while. Something small needs to be changed. You feel up for a challenge, so you dive in. What you find is a mess. It&#8217;s really nobody&#8217;s fault. Things evolved over time, different developers and [...]<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></description>
			<content:encoded><![CDATA[<img width="300" height="250" src="http://www.streamhead.com/wp-content/uploads/2012/04/spaghetti.png" class="attachment-post-thumbnail wp-post-image" alt="spaghetti" title="spaghetti" /><p>We&#8217;ve all been there. Somebody asks if you can take a look at their website that has been stagnant for a while. Something small needs to be changed. You feel up for a challenge, so you dive in. What you find is a mess. It&#8217;s really nobody&#8217;s fault. Things evolved over time, different developers and designers have done their thing at various times. Nobody meant any ill will, everybody just did their best. But here you are.</p>
<p><span id="more-3428"></span></p>
<p>Those problems come in many forms, but the one that pops up the most is the shared server that&#8217;s running a website for that shop next door. Over the years the owner became more and more reliant on the site. Maybe it contains his master inventory, maybe his contact database. It started out as nice novelty that nobody depended on, but now it&#8217;s quickly becoming mission critical.</p>
<p>So there you are, you&#8217;ve just opened the public HTML folder in your FTP client and you&#8217;ve got PHPMyAdmin opened in the browser.</p>
<p>This is my current action plan, feel free to add and suggest tools.</p>
<h2>Backup the entire site</h2>
<p><strong>For the love of god, make a backup now!</strong> Chances are good that you are looking at<strong> the only copy of the site in existence</strong>. If anything happens with the server, if you mess up something small, you&#8217;re going to be very very sorry.</p>
<p>Both cPanel and Plesk, the most popular domain control panels offer backup solutions out of the box. They are not perfect, but they allow you to create a full dump of the entire site. If you can schedule a daily backup, that&#8217;s a plus. If you can send the backup somewhere off site, another plus.</p>
<p>If you have shell access to the server, there are a whole slew of other tools available that may or may not be easier to use than the above.</p>
<p>Whatever you do, also check the backup. Does it contain a database dump? Does it contain all files? If you&#8217;re going to be messing with DNS and e-mail, you may want to check if that&#8217;s backed up too.</p>
<p>You&#8217;re now at a point where you can start developing/debugging with some confidence. It&#8217;s not perfect, but at least you have something to fall back on. I&#8217;d take it at least one step further.</p>
<h2>Get the files under version control</h2>
<p>If you&#8217;re going to be making multiple changes for multiple different tasks, you&#8217;re going to want to have all the code under version control. The easiest way: just put the entire public HTML folder under version control. You may be versioning too many files there, but at least you&#8217;re not missing anything.</p>
<p>One typical issue that pops up is the fact that not every one is going to be using version control. For instance, even the simplest WordPress blog can cause issues, because it is possible to edit some of the files from within the administration console.</p>
<p>If you have shell access, you could install and use version control on the server itself. But that doesn&#8217;t work for shared hosting.</p>
<p>I haven&#8217;t found the perfect, automated, solution but there are a few tools out there that allow you to view the difference between an FTP directory and a local on. Beyond Compare 3 is a pretty good one, once you get past its archaic interface.</p>
<p>You&#8217;re now at a pretty good place. Major disasters will be solved by the backup and smaller issues can be resolved by rolling back the change that caused them.</p>
<p>There&#8217;s still one wildcard: the database. Especially if your work involves structural changes to the database, you may want to look into &#8230;</p>
<h2>Version control for the database</h2>
<p>Few people do database version control and when it happens, it doesn&#8217;t always work quite right. But if you want to feel save doing that normalization operation on a few tables, there&#8217;s no way around it. You have to get the database in your version control system.</p>
<p><a title="Get your database under version control" href="http://www.codinghorror.com/blog/2008/02/get-your-database-under-version-control.html">Start here</a> and if you want to take it further, there have been many tools written since that post that will make your life easier.</p>
<h2>(Unit) Test the code</h2>
<p>Depending on the language of the application, you may just automatically be writing tests, even before you considered creating a backup. If it&#8217;s a PHP site however, chances are nobody has thought of this before.</p>
<p>You may think testing isn&#8217;t important for your particular application, but do me a favor: get at least one test in there, so that you&#8217;ve got the structure set up. If you ever add new code, you will be much more likely to add more tests.</p>
<p><a href="http://twitter.com/share?url=http://www.streamhead.com/the-spaghetti-crisis/&text=Start the test suite with a single test and let it grow from there.&via=pbackx&related=pbackx" rel="nofollow" title="Click here to tweet this." target="_blank" class="tweetherder"  >Start the test suite with a single test and let it grow from there.</a></p>
<h2>Integration/GUI testing &amp; Continuous integration</h2>
<p>If you get through the previous steps, you&#8217;re doing better than most. Automated GUI testing, a continuous integration server or even a continuous deployment environment, etc. it&#8217;s all icing on the cake. But if you&#8217;ve got the time and budget to set this up, you&#8217;re going to be a very happy developer down the road.</p>
<h2>Conclusion</h2>
<p>Many sites out there are still alive only by the mere fact that nothing bad ever happened until now. If you&#8217;re going to be updating such a site, chances are good that you will be held responsible if anything goes wrong. Even if it is completely beyond your control. The above steps will make sure that you are prepared and that you can start refactoring the code without worrying.</p>
<p>This is an evolving article, I will be updating it as I go along. Tips are more than welcome.</p>
<p>(<a href="http://www.flickr.com/photos/avlxyz/5996764291/">image credit</a>)</p>
<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.streamhead.com/the-spaghetti-crisis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:thumbnail url="http://www.streamhead.com/wp-content/uploads/2012/04/spaghetti.png" />
		<media:content url="http://www.streamhead.com/wp-content/uploads/2012/04/spaghetti.png" medium="image">
			<media:title type="html">spaghetti</media:title>
		</media:content>
		<media:content url="http://www.streamhead.com/wp-content/uploads/2012/04/spaghetti.png" medium="image">
			<media:title type="html">spaghetti</media:title>
		</media:content>
	</item>
		<item>
		<title>Try These 3 WordPress Plugins, by GrasshopperHerder</title>
		<link>http://www.streamhead.com/try-these-3-wordpress-plugins-by-grasshopperherder/</link>
		<comments>http://www.streamhead.com/try-these-3-wordpress-plugins-by-grasshopperherder/#comments</comments>
		<pubDate>Mon, 19 Mar 2012 14:00:39 +0000</pubDate>
		<dc:creator>Peter Backx</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.streamhead.com/?p=3403</guid>
		<description><![CDATA[Over the last few months, I&#8217;ve developed three plugins for Tristan Kromer of GrasshopperHerder.com. He has gracefully donated these to the community, so now they are available to all: Easily create tweetable text, manage ads and monitor their performance, integrate KissMetrics. There&#8217; something for every one. These are the first 3 plugins I created that [...]<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></description>
			<content:encoded><![CDATA[<img width="300" height="250" src="http://www.streamhead.com/wp-content/uploads/2012/03/grasshopperherder-wordpress-plugins.png" class="attachment-post-thumbnail wp-post-image" alt="GrasshopperHerder WordPress plugins" title="GrasshopperHerder WordPress plugins" /><p>Over the last few months, I&#8217;ve developed three plugins for <a title="@TriKro" href="https://twitter.com/#!/TriKro">Tristan Kromer</a> of <a title="Lean Startups and Customer Development" href="http://grasshopperherder.com/">GrasshopperHerder.com</a>. He has gracefully donated these to the community, so now they are available to all: Easily create tweetable text, manage ads and monitor their performance, integrate KissMetrics. There&#8217; something for every one.</p>
<p><span id="more-3403"></span>These are the first 3 plugins I created that are publicly available. It doesn&#8217;t happen a lot that some one who pays for development decides to make it available to every one. So don&#8217;t forget to thank <a title="Contact Tristan Kromer" href="http://tristankromer.com/contact">Tristan</a>.</p>
<h2><a title="TweetHerder" href="http://wordpress.org/extend/plugins/tweetherder/">TweetHerder</a></h2>
<p>From a technical point, this is the easiest plugin of the three. But I think it will be the most popular. It allows you to easily add &#8220;tweet this&#8221; buttons to quotes in your posts. Like this one:</p>
<p><a href="http://twitter.com/share?url=http://www.streamhead.com/try-these-3-wordpress-plugins-by-grasshopperherder/&text=If you have a WordPress blog, you should try the TweetHerder plugin.&via=pbackx&related=pbackx" rel="nofollow" title="Click here to tweet this." target="_blank" class="tweetherder"  >If you have a WordPress blog, you should try the TweetHerder plugin.</a></p>
<h2><a title="KissHerder" href="http://wordpress.org/extend/plugins/kissherder/">KissHerder</a></h2>
<p>This plugin allows you to add the KissMetrics code to your blog. It is different than the other plugins available, because it instruments many of your blogs functions. For instance, it will send events when a user enters a comment. There is also code available for tracking Facebook, Google+ and Twitter buttons. <a title="integrating with all kinds of social buttons" href="http://wordpress.org/extend/plugins/kissherder/faq/">Check the FAQ for the details</a> and if you have something that isn&#8217;t supported yet, please let us know.</p>
<h2><a title="AdHerder" href="http://wordpress.org/extend/plugins/adherder/">AdHerder</a></h2>
<p>Easily the most complicated plugin of the 3, this one allows you to define different adds and run A/B tests. It tracks user behavior and you can configure the plugin so that a user does not get to see an ad again if he has already clicked on it.</p>
<p>There are many options and it requires some tweaking to get the most out of it, but it is very powerful and the results can be very enlightening.</p>
<p>Due to its nature, it requires a little power from your blog server. So I would not suggest it to blogs that are already flirting with the limits of their shared hosting plan. Any one on a VPS or dedicated server should be fine.</p>
<h2>Feedback</h2>
<p>If you try any of the plugins. We&#8217;d love to hear from you. Is something not clear? Is there a bug? Do you like it? Let us know.</p>
<p>&nbsp;</p>
<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.streamhead.com/try-these-3-wordpress-plugins-by-grasshopperherder/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:thumbnail url="http://www.streamhead.com/wp-content/uploads/2012/03/grasshopperherder-wordpress-plugins.png" />
		<media:content url="http://www.streamhead.com/wp-content/uploads/2012/03/grasshopperherder-wordpress-plugins.png" medium="image">
			<media:title type="html">GrasshopperHerder WordPress plugins</media:title>
		</media:content>
		<media:content url="http://www.streamhead.com/wp-content/uploads/2012/03/grasshopperherder-wordpress-plugins.png" medium="image">
			<media:title type="html">GrasshopperHerder WordPress plugins</media:title>
		</media:content>
	</item>
		<item>
		<title>Boonex Dolphin Development: Integrating with the Spy Module</title>
		<link>http://www.streamhead.com/boonex-dolphin-spy-module-integration/</link>
		<comments>http://www.streamhead.com/boonex-dolphin-spy-module-integration/#comments</comments>
		<pubDate>Sun, 19 Feb 2012 13:42:45 +0000</pubDate>
		<dc:creator>Peter Backx</dc:creator>
				<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.streamhead.com/?p=3394</guid>
		<description><![CDATA[Boonex&#8217; Dolphin platform is widely used to support various communities. By itself it is fairly full-featured and can, for instance, be used to quickly build a private Facebook clone. It&#8217;s also pretty well programmed and can be extended in various ways. However, its development documentation is lacking. In this post I show how to integrate [...]<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></description>
			<content:encoded><![CDATA[<p>Boonex&#8217; Dolphin platform is widely used to support various communities. By itself it is fairly full-featured and can, for instance, be used to quickly build a private Facebook clone. It&#8217;s also pretty well programmed and can be extended in various ways. However, its development documentation is lacking. In this post I show how to integrate your module with the Spy module that shows user activity.</p>
<p><span id="more-3394"></span></p>
<p>Although not as widely known as, for instance, WordPress, <a title="Boonex Dolphin" href="http://www.boonex.com/dolphin">Boonex&#8217; Dolphin</a> is used on many private community sites. It&#8217;s no secret that it is a hit for any kind of dating site, but it can be adapted to any community you want. In this regard, it is a pretty cheap alternative to <a title="Ning community sites" href="http://www.ning.com/">Ning.com</a>.</p>
<p>Dolphin can be extended through modules, however the documentation is sorely lacking. <a title="First Dolphin module" href="http://www.boonex.com/trac/dolphin/wiki/DolphinTutorialMyFirstModule">The tutorial is a good start</a>, but what follows next took me a lot of backtracing and debugging of existing code.</p>
<h2>The Spy Module</h2>
<p>The Spy module is a popular Dolphin module that allows a user to track the activity of his friends and other users. Although it appears to be popular, it is completely undocumented. <a title="Installing the Spy module" href="http://www.youtube.com/watch?v=AeVC6dAXqu4">This YouTube movie is the best I could come up with</a>.</p>
<p>Obviously, if you are to try what follows, you need to activate the Spy module (it comes prepackaged with Dolphin)</p>
<h2>Integration</h2>
<p>Lets say you have an existing module, and want to see activity from your module on the Spy screens. Here are the different steps you need to take (see the end of this post for a fully example):</p>
<h3>1. BxDolAlerts</h3>
<p>Use BxDolAlerts for every action that you want to track. This has the added benefit that your module will nicely integrate with all other modules that use alerts, not just the Spy one.</p>
<p>You give an alert as follows:</p>

<div class="wp_codebox"><table><tr id="p33944"><td class="line_numbers"><pre>1
2
3
</pre></td><td class="code" id="p3394code4"><pre class="php" style="font-family:monospace;">bx_import<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'BxDolAlerts'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$alert</span> <span style="color: #339933;">=</span> <span style="color: #000000; font-weight: bold;">new</span> BxDolAlerts<span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'my_module_unit'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'action_name'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$objectId</span><span style="color: #339933;">,</span> <span style="color: #000088;">$memberId</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$alert</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">alert</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<div>The different variables in there are:</div>
<div>
<ul>
<li>my_module_unit: this is the unit name to which you want to alert to belong. Pick whatever you like for your entire module, but make sure it&#8217;s unique (I wouldn&#8217;t use things like &#8220;photos&#8221; for instance)</li>
<li>action_name: the name of the action the user performed.</li>
<li>objectId: this is an id of the object associated with the action. This may be left blank or 0, but it&#8217;s always useful to fill it. For instance, say the user created a new blog post: use the id of that blog post.</li>
<li>memberId: the id of the user performing the action.</li>
</ul>
<h3>2. Installation</h3>
<p>At module installation time, the alerts you give are connected to the spy module. This means that whenever you add or change alerts, you need to re-install the module. This can be a hassle for your users, so pick names wisely.</p>
<p>To enable recompilation of alerts, add &#8220;&#8216;recompile_alerts&#8217; =&gt; 1&#8243; to the install section of your config.php.</p>
<p>The Spy module will also need to update his handlers. This is done in the installer.php file:</p>

<div class="wp_codebox"><table><tr id="p33945"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
</pre></td><td class="code" id="p3394code5"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> install<span style="color: #009900;">&#40;</span><span style="color: #000088;">$aParams</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$aResult</span> <span style="color: #339933;">=</span> parent<span style="color: #339933;">::</span><span style="color: #004000;">install</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aParams</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aResult</span><span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'result'</span><span style="color: #009900;">&#93;</span> <span style="color: #339933;">&amp;&amp;</span> BxDolRequest<span style="color: #339933;">::</span><span style="color: #004000;">serviceExists</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'spy'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'update_handlers'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        BxDolService<span style="color: #339933;">::</span><span style="color: #004000;">call</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'spy'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'update_handlers'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_aConfig<span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'home_uri'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
   <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$aResult</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">function</span> uninstall<span style="color: #009900;">&#40;</span><span style="color: #000088;">$aParams</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span>BxDolRequest<span style="color: #339933;">::</span><span style="color: #004000;">serviceExists</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'spy'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'update_handlers'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        BxDolService<span style="color: #339933;">::</span><span style="color: #004000;">call</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'spy'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'update_handlers'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span>_aConfig<span style="color: #009900;">&#91;</span><span style="color: #0000ff;">'home_uri'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">false</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> parent<span style="color: #339933;">::</span><span style="color: #004000;">uninstall</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$aParams</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<h3>3. Spy integration services</h3>
<p>The final step is adding 2 services to your module. Here are 2 minimal implementations:</p>

<div class="wp_codebox"><table><tr id="p33946"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
</pre></td><td class="code" id="p3394code6"><pre class="php" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">function</span> serviceGetSpyData<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
        <span style="color: #0000ff;">'handlers'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'alert_unit'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'my_module_unit'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'alert_action'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'action_name'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'module_uri'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'my_uri'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'module_class'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'Module'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'module_method'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'get_spy_post'</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span>
        <span style="color: #0000ff;">'alerts'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
            <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'unit'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'my_module_unit'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'action'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">'action_name'</span><span style="color: #009900;">&#41;</span>
        <span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span>
<span style="color: #000000; font-weight: bold;">function</span> serviceGetSpyPost<span style="color: #009900;">&#40;</span><span style="color: #000088;">$action</span><span style="color: #339933;">,</span> <span style="color: #000088;">$objectId</span><span style="color: #339933;">,</span> <span style="color: #000088;">$memberId</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000088;">$spyPost</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
    <span style="color: #b1b100;">switch</span><span style="color: #009900;">&#40;</span><span style="color: #000088;">$action</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #b1b100;">case</span> <span style="color: #0000ff;">'action_name'</span> <span style="color: #339933;">:</span>
            <span style="color: #000088;">$spyPost</span> <span style="color: #339933;">=</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
                <span style="color: #0000ff;">'lang_key'</span> <span style="color: #339933;">=&gt;</span> <span style="color: #0000ff;">&quot;action_name was executed&quot;</span>
            <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
            <span style="color: #b1b100;">break</span><span style="color: #339933;">;</span>
    <span style="color: #009900;">&#125;</span>
    <span style="color: #b1b100;">return</span> <span style="color: #000088;">$spyPost</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span></pre></td></tr></table></div>

<p>The first one is used to register the alerts and handlers. Its parameters should be copied from your BxDolAlerts. The second one is called when the spy module wants to render its messages. As you can see, you get the same parameters back as you used when generating the alert. So you can use the objectId to load all details you&#8217;d like to show in the spy message.</p>
<p>And that&#8217;s really all there is to it.</p>
</div>
<h2>Full Example</h2>
<p>If the explanation was not enough for you and you&#8217;d like to see a fully working example, I also offer a full module project that you can use as a basis to work on. It does not contain any kind of additional code. Everything in there is shown in the article. It&#8217;s just conveniently all put into one place.</p>
<div class="buynow">
Full example module with support, lifetime upgrades and 100% money back guarantee, only $5 for immediate download access<br />

				<script type="text/javascript">
					var active_bbb269e4a708cc27a60fa0786e6864924 = "paypal_bbb269e4a708cc27a60fa0786e6864924";
					function paiddownloads_bbb269e4a708cc27a60fa0786e6864924() {
						if (jQuery("#method_paypal_bbb269e4a708cc27a60fa0786e6864924").attr("checked")) active_bbb269e4a708cc27a60fa0786e6864924 = "paypal_bbb269e4a708cc27a60fa0786e6864924";
						else if (jQuery("#method_alertpay_bbb269e4a708cc27a60fa0786e6864924").attr("checked")) active_bbb269e4a708cc27a60fa0786e6864924 = "alertpay_bbb269e4a708cc27a60fa0786e6864924";
						else if (jQuery("#method_interkassa_bbb269e4a708cc27a60fa0786e6864924").attr("checked")) active_bbb269e4a708cc27a60fa0786e6864924 = "interkassa_bbb269e4a708cc27a60fa0786e6864924";
						if (active_bbb269e4a708cc27a60fa0786e6864924 == "interkassa_bbb269e4a708cc27a60fa0786e6864924") {
							if (!jQuery("#paiddownloads_email_bbb269e4a708cc27a60fa0786e6864924")) {
								alert("Please enter valid e-mail. Download link will be sent to this e-mail address.");
								return;
							}
							var paiddownloads_email = jQuery("#paiddownloads_email_bbb269e4a708cc27a60fa0786e6864924").val();
							var re = /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/;
							if (!paiddownloads_email.match(re)) {
								alert("Please enter valid e-mail. Download link will be sent to this e-mail address.");
								return;
							}
							jQuery("#ik_baggage_fields_bbb269e4a708cc27a60fa0786e6864924").val(paiddownloads_email);
						}
						jQuery("#" + active_bbb269e4a708cc27a60fa0786e6864924).click();
						return;
					}
					function paiddownloads_toggle_paiddownloads_email_bbb269e4a708cc27a60fa0786e6864924() {
						if (jQuery("#paiddownloads_email_container_bbb269e4a708cc27a60fa0786e6864924")) {
							if (jQuery("#method_interkassa_bbb269e4a708cc27a60fa0786e6864924").attr("checked")) jQuery("#paiddownloads_email_container_bbb269e4a708cc27a60fa0786e6864924").slideDown(100);
							else  jQuery("#paiddownloads_email_container_bbb269e4a708cc27a60fa0786e6864924").slideUp(100);
						}
					}
				</script>
				<form action="https://www.paypal.com/cgi-bin/webscr" method="post" style="display:none;">
					<input type="hidden" name="cmd" value="_xclick">
					<input type="hidden" name="business" value="peter.backx@gmail.com">
					<input type="hidden" name="no_shipping" value="1">
					<input type="hidden" name="rm" value="2">
					<input type="hidden" name="item_name" value="Boonex Dolphin Spy integration example module">
					<input type="hidden" name="item_number" value="1">
					<input type="hidden" name="amount" value="5">
					<input type="hidden" name="currency_code" value="USD">
					<input type="hidden" name="custom" value="">
					<input type="hidden" name="charset" value="utf-8">					
					<input type="hidden" name="bn" value="PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest">
					<input type="hidden" name="return" value="http://www.streamhead.com/feed/">
					<input type="hidden" name="cancel_return" value="http://www.streamhead.com/feed/">
					<input type="hidden" name="notify_url" value="http://www.streamhead.com/?paiddownloads_ipn=paypal">
					<input id="paypal_bbb269e4a708cc27a60fa0786e6864924" type="submit" value="Buy Now" style="margin: 0px; padding: 0px;">
				</form><input type="image" src="http://www.streamhead.com/wp-content/plugins/paid-downloads/images/btn_buynow_LG.gif" name="submit" alt="Boonex Dolphin Spy integration example module" style="margin: 5px 0px; padding: 0px; border: 0px;" onclick="paiddownloads_bbb269e4a708cc27a60fa0786e6864924(); return false;">
</div>
<p>Future updates might include internationalization (i18n), if there is interest. <a title="Why buy from Streamhead" href="http://www.streamhead.com/about/why-buy-from-streamhead/">Please also see my article on why I charge for some things</a>.</p>
<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.streamhead.com/boonex-dolphin-spy-module-integration/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
	</item>
		<item>
		<title>A Case Study: Save Money, Invest in Software Development</title>
		<link>http://www.streamhead.com/save-money-with-software/</link>
		<comments>http://www.streamhead.com/save-money-with-software/#comments</comments>
		<pubDate>Tue, 07 Feb 2012 15:58:52 +0000</pubDate>
		<dc:creator>Peter Backx</dc:creator>
				<category><![CDATA[Java and JavaScript]]></category>

		<guid isPermaLink="false">http://www.streamhead.com/?p=3383</guid>
		<description><![CDATA[One question many small business owners struggle with is how much to spend on software. Should you get existing software off the shelf? Open Source or proprietary? Or should you invest in custom development? But how much does that cost and is it worth it? Many of the smaller companies I&#8217;ve worked with over the [...]<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></description>
			<content:encoded><![CDATA[<img width="300" height="250" src="http://www.streamhead.com/wp-content/uploads/2012/02/invest.png" class="attachment-post-thumbnail wp-post-image" alt="Invest in Software" title="invest" /><p>One question many small business owners struggle with is how much to spend on software. Should you get existing software off the shelf? Open Source or proprietary? Or should you invest in custom development? But how much does that cost and is it worth it?</p>
<p><span id="more-3383"></span>Many of <a title="Peter Backx on Elance, my profile" href="http://pbackx.elance.com">the smaller companies I&#8217;ve worked with over the last year</a> have similar problems. At some point they decided they needed a website and just went with whatever their cousin recommended. This wasn&#8217;t a bad choice, because the site has brought them new clients and kept them in touch with existing clients.</p>
<p>In short: <strong>the site has made them money</strong>.</p>
<p>Programmer&#8217;s and lean startup aficionados would say that their <a title="Minimum Viable Product" href="http://en.wikipedia.org/wiki/Minimum_viable_product">minimum viable product</a> has validated their assumptions.</p>
<p>The other side of the coin, is that a site like this usually requires a lot of manual maintenance. So now the business is at a point where they want to invest in the improvement and the expansion of the website.</p>
<p>But what to do?</p>
<p>Lets study a fictional example: Huey Bobbie&#8217;s company &#8220;Server Certified Studios&#8221; has a website containing a few modules:</p>
<ul>
<li>A content management system that was created by his nephew as a homework assignment. It works, but for every update to the site, Huey needs to figure out what file to change and if he makes even the smallest error, the entire site goes offline.</li>
<li>An open source application that manages his mailing list.</li>
</ul>
<h2>Calculating expenses</h2>
<p>Huey&#8217;s expenses for the site are:</p>
<ul>
<li>A shared hosting account and a domain name. For about $150/year you can get <strong><a title="Lunarpages web hosting (affiliate link)" href="http://www.lunarpages.com/id/pbackx">a decent package deal</a></strong>.</li>
<li>Initial programming and template for the site. Those are <a title="Sunk costs" href="http://en.wikipedia.org/wiki/Sunk_costs">sunk costs</a>, so they won&#8217;t play into any calculation here.</li>
<li>Every month Huey needs to add a few products to the site, add a bunch of news items and update one or more page. Writing all of those things takes about 1 hour weekly. But because he has to search through the files and be very careful with the syntax, this takes him another 1 hour weekly. Lets assume Huey, as a business owner, values his time at about $100/hour (which is conservative, he could be doing other stuff to make more money).</li>
</ul>
<p>Everything combined, the website costs Huey on a yearly basis:</p>
<p>$150 + 50 (working weeks) * $200 = <strong>$10150 / year</strong></p>
<p>I think this is a fairly realistic number of the cost of a typical small business website that is maintained regularly.</p>
<h2>Profit</h2>
<p>For the sake of argument, lets say Huey has calculated that the site is generating a revenue that is exactly double of what it cost him: $20300 / year.</p>
<p>Or the site is making <strong>a profit of $10150 / year, or a 50% profit margin</strong>.</p>
<p>Just to make this more concrete: $20300 means 203 customers buy $100 worth of product over a year. Or about 17 customers find Server Certified Studios through his website. Not at all impossible.</p>
<h2>Room for Improvement</h2>
<p>That&#8217;s not a bad extra profit to add to the bottom line. But lets see how we can do better.</p>
<p>For instance, lets believe in magic and assume there is <strong>no additional work required</strong> to get a news item that is written on the website. So Huey only need to write 1 hour / week and whatever he has written magically appears on the site.</p>
<p>In that case, the website cost is:</p>
<p>$150 + 50 * $100 = $5150/year</p>
<p><strong>The profit is $15150 or a margin of 75%</strong>. That&#8217;s huge improvement!</p>
<p>But lets try something more realistic. We automate the website a little and improve it&#8217;s administrative interface. Now Huey only needs an hour each month to update the site.</p>
<p>The cost: $150 + 50 * $100 + 12 * $100 = $6350 / year</p>
<p>That&#8217;s <strong>$13950 profit or a margin of 69%</strong>. A nice increase.</p>
<h2>Getting There: Investing</h2>
<p>If Huey wants to recoup this improvement in a year. The investment may not be over $3800 (this is the additional profit over a year: $13950 &#8211; $10150)</p>
<p>Given the size of this website, $3800 can buy a lot. A few example investment opportunities are:</p>
<ul>
<li>Find a WordPress theme expert and let them convert the existing site layout to a WordPress theme: Site maintenance will be drastically easier and finding cheap developers afterwards easier (the WordPress dev community is probably one of the most saturated)</li>
<li>Go on Elance and find a PHP developer that can create a script that automatically converts the input text to the XML format of the site: Not as future proof, but could be even cheaper if you find a good Asian developer.</li>
<li>Hire a Virtual Assistant to put everything online at about 1/10 the cost of you: Easy to set up, but requires continuous payment.</li>
</ul>
<p>If Huey would ask me what to do, I would most certainly recommend the WordPress solution. It&#8217;s a one time investment that will create a site that is ready for further expansion. And the numbers support it.</p>
<p>Huey will find a WordPress theme company that can create this for $1000. Which will repay itself in 4 months. Furthermore, the WordPress powered site will probably have better SEO than whatever was there previously. Thus delivering even more clients to Server Certified Studios.</p>
<h2>Conclusion</h2>
<p>If you are a small business owner and feel your website is sucking up way to much of your energy, it&#8217;s time to evaluate your options. Write down the numbers and see what kind of time and money you are spending and how much it is making you.</p>
<p><strong>Even small investments can tremendously improve your profit margin and reduce your frustration</strong>.</p>
<p>(<a title="Invest on Flickr" href="http://www.flickr.com/photos/wonderwebby/2723279741/">image credit</a>)</p>
<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.streamhead.com/save-money-with-software/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:thumbnail url="http://www.streamhead.com/wp-content/uploads/2012/02/invest.png" />
		<media:content url="http://www.streamhead.com/wp-content/uploads/2012/02/invest.png" medium="image">
			<media:title type="html">invest</media:title>
		</media:content>
		<media:content url="http://www.streamhead.com/wp-content/uploads/2012/02/invest.png" medium="image">
			<media:title type="html">invest</media:title>
		</media:content>
	</item>
		<item>
		<title>Review and Preview, Streamhead 2012 Goals</title>
		<link>http://www.streamhead.com/review-and-preview-2012/</link>
		<comments>http://www.streamhead.com/review-and-preview-2012/#comments</comments>
		<pubDate>Tue, 27 Dec 2011 14:00:47 +0000</pubDate>
		<dc:creator>Peter Backx</dc:creator>
				<category><![CDATA[On Streamhead]]></category>

		<guid isPermaLink="false">http://www.streamhead.com/?p=3356</guid>
		<description><![CDATA[2011 has been a transformative year for Streamhead. Due to some major work and planning behind the scenes, I haven&#8217;t been able to post as much as I would have liked. But all this hard work is about to pay off and you, my dear reader, will enjoy the fruits of it. In 2012, I [...]<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></description>
			<content:encoded><![CDATA[<img width="300" height="250" src="http://www.streamhead.com/wp-content/uploads/2011/12/streamhead_goals_2012.png" class="attachment-post-thumbnail wp-post-image" alt="It&#039;s always good to have goals" title="streamhead_goals_2012" /><p>2011 has been a transformative year for Streamhead. Due to some major work and planning behind the scenes, I haven&#8217;t been able to post as much as I would have liked. But all this hard work is about to pay off and you, my dear reader, will enjoy the fruits of it. In 2012, I plan to double down on in-depth articles, tutorials and case studies. All practical hands-on information. Read on for a review of 2011 and my goals for 2012.</p>
<p><span id="more-3356"></span>Before I start making plans, it&#8217;s good to look back at the goals I had a year ago. In 2011, I finally managed to focus on just a few projects and not be so random, which is why I don&#8217;t score too good on <a title="Looking Forward, Streamhead in 2011" href="http://www.streamhead.com/streamhead-in-2011/">the goals I set for myself</a>:</p>
<ol>
<li><strong>HTML5, CSS3, etc.</strong>: I wanted to learn new enabling technologies for the web. And, in a way, I did, but not like I imagined. I learned PHP and got into the WordPress plugin business (a post on that is forthcoming). <a title="Rapid web app development with Node.JS" href="http://www.streamhead.com/expensesspreadsheet-net-node-js/">I also used Node.js to launch my latest personal project</a> and I&#8217;m glad I did.</li>
<li><strong>Mobile</strong>: Sadly, I wasn&#8217;t able to create anything worth showing on the mobile front. Apart from some very small experiments, I got nowhere.</li>
<li><strong>Online Marketing</strong>: For the last few months I&#8217;ve had an Adwords campaign running. It&#8217;s been slow learning, but I am getting better at finding keywords and convincing Google my ads are relevant. And I managed to get a site to position 7 in Google for my target keywords in about a month. Nothing major, but I&#8217;m pretty happy with this evolution. <em>I haven&#8217;t written about any of this, because I feel I got very little to add to the discussion at the moment. That might change, though</em>.</li>
<li><strong>Game Modding</strong>: A big zero on this one. I launched two small experiments early in the year. There was little interest and I wasn&#8217;t convinced myself, so I didn&#8217;t promote anything. <a title="ActionScript Ticket to Ride clone" href="http://www.streamhead.com/actionscript-3-ticket-to-ride/">I did manage to pull of a half-assed ticket to ride clone</a>, which convinced me I shouldn&#8217;t invest further in ActionScript. Adobe killing of Flash has only strengthened that opinion.</li>
</ol>
<p>What you haven&#8217;t seen is my search for a sustainable business model for Streamhead and my other projects. Making money with a blog is, for all intents and purposes, impossible. Unless you want to churn out a few long-form articles a day, like Tuts+ (A great resource BTW), you can&#8217;t live of of advertising or ebook sales. Furthermore, I realized a full-time writing gig is not my thing. <em>I want to be in the trenches, developing, not writing about developing</em>.</p>
<h2>Plans for 2012</h2>
<p>Most developers tend to stay away from sites like elance. I did discover that there is good work out there, with good clients that want to pay for quality. And the further my reputation improves, the easier it is to find that work. It&#8217;s very easy to phase in and out small projects as time permits.</p>
<p>There is a lot of work out there in the widest possible range of technologies, but it is most profitable to stay focused on just a few. Which is a major pain point for me, so in 2012 I intend to <strong>focus on a few core technologies</strong>.</p>
<p>Currently, I&#8217;m trying to limit my programming languages to <strong>Java, JavaScript and PHP</strong>. I might try out something related (Groovy, Clojure, Coffeescript), but I&#8217;m going to try to not stray too far from the path.</p>
<h3>Java</h3>
<p>Although there are now other cheap options, I still like the AppEngine platform for Java web application deployment. Libraries, such as Vaadin, are what keep the platform young. However, I do feel that there&#8217;s going to be a turning point soon when one of the other JVM languages really goes mainstream. It&#8217;s probably not going to be Clojure, maybe Scala?</p>
<p>I also still have that Android in Action book I want to go through.</p>
<h3>PHP</h3>
<p>PHP is a great source of small project work. It&#8217;s an interesting language I will continue to use. However, I am going to narrow it down to WordPress development and possibly a few other applications.</p>
<h3>JavaScript</h3>
<p>Like it or not, JavaScript is the language of the future. It&#8217;s everywhere and there&#8217;s no reason why it would go away. And now it has also invaded the server side. I was pleasantly surprised with Node.JS. It&#8217;s a very robust programming module that is going to stay in my tool-belt. On the client side, I do hope to get some game programming in and maybe some cross-platform mobile programming.</p>
<h3>Non-technical</h3>
<p>Of course, 2012 isn&#8217;t going to be just programming. I will continue with my Internet marketing efforts and if I feel it&#8217;s worth sharing, you&#8217;ll be the first to know.</p>
<h2>Conclusion</h2>
<p>I value input. Do you have a great topic you want me to write about? A question you can&#8217;t find the answer to? Get in touch with me and I&#8217;ll make it happen in 2012.</p>
<p>(<a title="Two goals on Flickr" href="http://www.flickr.com/photos/danieldslee/5425899591/">photo credit</a>)</p>
<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.streamhead.com/review-and-preview-2012/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:thumbnail url="http://www.streamhead.com/wp-content/uploads/2011/12/streamhead_goals_2012.png" />
		<media:content url="http://www.streamhead.com/wp-content/uploads/2011/12/streamhead_goals_2012.png" medium="image">
			<media:title type="html">streamhead_goals_2012</media:title>
		</media:content>
		<media:content url="http://www.streamhead.com/wp-content/uploads/2011/12/streamhead_goals_2012.png" medium="image">
			<media:title type="html">streamhead_goals_2012</media:title>
		</media:content>
	</item>
		<item>
		<title>ExpensesSpreadsheet.net, Rapid Web App Development with Node.js</title>
		<link>http://www.streamhead.com/expensesspreadsheet-net-node-js/</link>
		<comments>http://www.streamhead.com/expensesspreadsheet-net-node-js/#comments</comments>
		<pubDate>Wed, 23 Nov 2011 14:00:46 +0000</pubDate>
		<dc:creator>Peter Backx</dc:creator>
				<category><![CDATA[Java and JavaScript]]></category>

		<guid isPermaLink="false">http://www.streamhead.com/?p=3343</guid>
		<description><![CDATA[My latest project is ExpensesSpreadsheet.NET. It is the simplest and easiest solution I could come up with to track and categorize expenses &#8230; in a spreadsheet. Let&#8217;s call it a niche web application, so it&#8217;s probably not for every one, but it should fit some extremely well. It runs on Heroku&#8217;s Node.js stack. Over the [...]<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></description>
			<content:encoded><![CDATA[<p>My latest project is <a title="Track your expenses the smart way" href="http://www.expensesspreadsheet.net">ExpensesSpreadsheet.NET</a>. It is the simplest and easiest solution I could come up with to track and categorize expenses &#8230; in a spreadsheet. Let&#8217;s call it a niche web application, so it&#8217;s probably not for every one, but it should fit some extremely well. It runs on Heroku&#8217;s Node.js stack.</p>
<p><span id="more-3343"></span>Over the last month or two, I&#8217;ve been very busy with a few projects. And it was about time to present some. I have many more ideas on how to extend <strong><a title="Track your expenses the smart way" href="http://www.expensesspreadsheet.net">ExpensesSpreadsheet</a></strong>, but I thought it wise to first gauge the reaction of people.</p>
<p>It uses the following technology:</p>
<ul>
<li><strong>Node.js</strong>, the JavaScript event machine that is all the rage now.</li>
<li><strong>RailwayJS</strong>, a Rails-like web framework.</li>
<li><strong>connect-auth</strong> for Facebook integration (and a lot more)</li>
<li><strong>MongoDB</strong> for data storage. Mostly because it was so easy to get started with compared to traditional related databases. But in hindsight, I think it&#8217;s an ok choice. I really don&#8217;t safe any relations anyway.</li>
<li><strong>EJS</strong> JavaScript templates. Although in hindsight, I think I like Jade better.</li>
<li><strong>Heroku</strong>, cloud hosting done right.</li>
</ul>
<p>This was my first experiment with Node.js and Heroku and it was extremely enlightening. JavaScript is not my favorite programming language, but it certainly has a way of reducing boiler plate code (stuff I&#8217;m really starting to hate in Java). Combined with deployment to Heroku, the time between idea and deployed application is so short, it will make any developer smile.</p>
<p>If your day-to-day life involves lots of Java, you owe it to yourself to try out this stack. It&#8217;s not your average hacked together client side JavaScript. It takes a little time to wrap your head around the Node model, but it&#8217;s all worth it.</p>
<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.streamhead.com/expensesspreadsheet-net-node-js/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
	</item>
		<item>
		<title>Permanent Redirect Non-WWW to WWW in Node.JS on Heroku</title>
		<link>http://www.streamhead.com/nodejs-permanent-redirect/</link>
		<comments>http://www.streamhead.com/nodejs-permanent-redirect/#comments</comments>
		<pubDate>Fri, 04 Nov 2011 12:00:41 +0000</pubDate>
		<dc:creator>Peter Backx</dc:creator>
				<category><![CDATA[Java and JavaScript]]></category>

		<guid isPermaLink="false">http://www.streamhead.com/?p=3329</guid>
		<description><![CDATA[For SEO reasons it&#8217;s important to make sure that users only visit your site through a single domain name. Either www.example.com or example.com, but not both. In most cases a .htaccess change is the easiest fix. But not when you&#8217;re deploying to an environment that doesn&#8217;t have Apache, like Heroku. Here&#8217;s a quick way to [...]<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></description>
			<content:encoded><![CDATA[<p>For SEO reasons it&#8217;s important to make sure that users only visit your site through a single domain name. Either www.example.com or example.com, but not both. In most cases a .htaccess change is the easiest fix. But not when you&#8217;re deploying to an environment that doesn&#8217;t have Apache, like Heroku. Here&#8217;s a quick way to get this functionality using Express on Node.JS</p>
<p><span id="more-3329"></span>Since you probably only want to do this in a production environment, I suggest you place this in <a title="Express configuration" href="http://expressjs.com/guide.html#configuration">that configure block</a>.</p>
<p>Before you add any middleware add the following route:</p>

<div class="wp_codebox"><table><tr id="p332911"><td class="line_numbers"><pre>1
2
3
4
5
6
7
</pre></td><td class="code" id="p3329code11"><pre class="javascript" style="font-family:monospace;">app.<span style="color: #660066;">get</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'*'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>req<span style="color: #339933;">,</span> res<span style="color: #339933;">,</span> next<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000066; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>req.<span style="color: #660066;">headers</span>.<span style="color: #660066;">host</span>.<span style="color: #660066;">slice</span><span style="color: #009900;">&#40;</span><span style="color: #CC0000;">0</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">3</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #3366CC;">'www'</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    res.<span style="color: #660066;">redirect</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'http://www.'</span> <span style="color: #339933;">+</span> req.<span style="color: #660066;">headers</span>.<span style="color: #660066;">host</span> <span style="color: #339933;">+</span> req.<span style="color: #660066;">url</span><span style="color: #339933;">,</span> <span style="color: #CC0000;">301</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span> <span style="color: #000066; font-weight: bold;">else</span> <span style="color: #009900;">&#123;</span>
    next<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>That&#8217;s really all there is to it. Since most frameworks have similar routing options, you should be able to adapt this to other frameworks, such as Geddy.</p>
<p>BTW I&#8217;m planning to launch a Node.JS app in November as part of <a title="Launch an app month" href="http://news.ycombinator.com/item?id=3180321">Hacker News&#8217; Launch an App Month</a>.</p>
<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.streamhead.com/nodejs-permanent-redirect/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
	</item>
		<item>
		<title>Updated PayPal AppEngine Servlet</title>
		<link>http://www.streamhead.com/updated-paypal-appengine-servlet/</link>
		<comments>http://www.streamhead.com/updated-paypal-appengine-servlet/#comments</comments>
		<pubDate>Mon, 03 Oct 2011 14:00:24 +0000</pubDate>
		<dc:creator>Peter Backx</dc:creator>
				<category><![CDATA[Java and JavaScript]]></category>

		<guid isPermaLink="false">http://www.streamhead.com/?p=3322</guid>
		<description><![CDATA[If you want to integrate PayPal with your Google AppEngine application, there are a limited number of options available. My own open source project offers a servlet that can parse and log IPN messages. This will quickly get you up and running with PayPal Payments Standard. Since I launched the PayPal servlet, I&#8217;ve had many [...]<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></description>
			<content:encoded><![CDATA[<p>If you want to integrate PayPal with your Google AppEngine application, there are a limited number of options available. My own open source project offers a servlet that can parse and log IPN messages. This will quickly get you up and running with <a title="PayPal payments standard guides" href="https://www.x.com/developers/paypal/development-and-integration-guides#wps">PayPal Payments Standard</a>.</p>
<p><span id="more-3322"></span><a title="Java AppEngine PayPal IPN servlet" href="http://www.streamhead.com/java-paypal-ipn-servlet/">Since I launched the PayPal servlet</a>, I&#8217;ve had many inquiries and I know of at least 2 production deployments of the code. It was about time that I started handling the project a little more professionally.</p>
<p>The first step in this process was completed last weekend: the project is now a Maven project and the Eclipse specific configuration has been removed. I have decided to make this part of my <a title="Powered by Reindeer, quick appengine development" href="http://www.streamhead.com/vaadin-app-engine-in-5-minutes/">Powered by Reindeer initiative</a>. Although it can be used completely independent and will remain so, I believe that there are going to be some nice synergies in the future that I&#8217;ll want to exploit.</p>
<p>My next step will be cleaning up the actual code. I&#8217;m not sure when I&#8217;ll get around to it, but this will involve changing the package names a little to be more in line with the Powered by Reindeer structure. If you think there&#8217;s a good reason to keep the old names, please let me know. Also let me know if you&#8217;d like to get a personal e-mail when the changes will take place.</p>
<p><a title="Java AppEngine PayPal IPN servlet" href="https://github.com/pbackx/PayPalIPNServlet">See the GitHub page for all details</a>.</p>
<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.streamhead.com/updated-paypal-appengine-servlet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
	</item>
		<item>
		<title>AZERTY Keyboard and jMonkeyEngine Quick Tip</title>
		<link>http://www.streamhead.com/azerty-jmonkeyengine/</link>
		<comments>http://www.streamhead.com/azerty-jmonkeyengine/#comments</comments>
		<pubDate>Wed, 31 Aug 2011 14:00:26 +0000</pubDate>
		<dc:creator>Peter Backx</dc:creator>
				<category><![CDATA[Java and JavaScript]]></category>
		<category><![CDATA[jMonkeyEngine]]></category>

		<guid isPermaLink="false">http://www.streamhead.com/?p=3314</guid>
		<description><![CDATA[If you&#8217;ve ever created anything using jMonkeyEngine&#8217;s SimpleApplication and you use something other than the American standard QWERTY keyboard, you might have had the same frustration as me: Why isn&#8217;t there quick way to switch the keyboard layout? The SimpleApplication base class is supposed to make your life easier, yet there you are, completely stuck [...]<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></description>
			<content:encoded><![CDATA[<img width="300" height="250" src="http://www.streamhead.com/wp-content/uploads/2011/08/jMonkeEngine_showcase.png" class="attachment-post-thumbnail wp-post-image" alt="jMonkeEngine_showcase" title="jMonkeEngine_showcase" /><p>If you&#8217;ve ever created anything using jMonkeyEngine&#8217;s SimpleApplication and you use something other than the American standard QWERTY keyboard, you might have had the same frustration as me: Why isn&#8217;t there quick way to switch the keyboard layout? The SimpleApplication base class is supposed to make your life easier, yet there you are, completely stuck with that unnatural keyboard layout. Read on for a quick copy-and-paste solution.</p>
<p><span id="more-3314"></span>The keyboard mapping that SimpleApplication uses for its camera movement is defined in the FlyByCamera. The mapping is hardcoded and the mapping names don&#8217;t even use constant strings. Clearly, no one ever thought about international users. <a title="jMonkeyEngine.org" href="http://jmonkeyengine.org/">jMonkeyEngine</a> does so many things right, yet on this one, it really misses the ball.</p>
<p>Luckily, with a little searching, it&#8217;s fairly easy to redefine the correct mappings. It&#8217;s something I now do in all my experiments.</p>
<p>I just copy and paste the following at the start of every simpleInitApp:</p>

<div class="wp_codebox"><table><tr id="p331414"><td class="line_numbers"><pre>1
2
3
4
5
6
7
8
9
10
</pre></td><td class="code" id="p3314code14"><pre class="java" style="font-family:monospace;">inputManager.<span style="color: #006633;">deleteMapping</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;FLYCAM_Forward&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
inputManager.<span style="color: #006633;">deleteMapping</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;FLYCAM_Lower&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
inputManager.<span style="color: #006633;">deleteMapping</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;FLYCAM_StrafeLeft&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
inputManager.<span style="color: #006633;">deleteMapping</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;FLYCAM_Rise&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
inputManager.<span style="color: #006633;">addMapping</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;FLYCAM_Forward&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> KeyTrigger<span style="color: #009900;">&#40;</span>KeyInput.<span style="color: #006633;">KEY_Z</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
inputManager.<span style="color: #006633;">addMapping</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;FLYCAM_Lower&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> KeyTrigger<span style="color: #009900;">&#40;</span>KeyInput.<span style="color: #006633;">KEY_W</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
inputManager.<span style="color: #006633;">addMapping</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;FLYCAM_StrafeLeft&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> KeyTrigger<span style="color: #009900;">&#40;</span>KeyInput.<span style="color: #006633;">KEY_Q</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
inputManager.<span style="color: #006633;">addMapping</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;FLYCAM_Rise&quot;</span>, <span style="color: #000000; font-weight: bold;">new</span> KeyTrigger<span style="color: #009900;">&#40;</span>KeyInput.<span style="color: #006633;">KEY_A</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
inputManager.<span style="color: #006633;">addListener</span><span style="color: #009900;">&#40;</span>flyCam, <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">String</span><span style="color: #009900;">&#91;</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#123;</span><span style="color: #0000ff;">&quot;FLYCAM_Forward&quot;</span>, <span style="color: #0000ff;">&quot;FLYCAM_Lower&quot;</span>, <span style="color: #0000ff;">&quot;FLYCAM_StrafeLeft&quot;</span>, <span style="color: #0000ff;">&quot;FLYCAM_Rise&quot;</span><span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
flyCam.<span style="color: #006633;">setMoveSpeed</span><span style="color: #009900;">&#40;</span>10f<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></td></tr></table></div>

<p>(Note that I&#8217;ve also sped up the movement to more easily move around)</p>
<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.streamhead.com/azerty-jmonkeyengine/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:thumbnail url="http://www.streamhead.com/wp-content/uploads/2011/08/jMonkeEngine_showcase.png" />
		<media:content url="http://www.streamhead.com/wp-content/uploads/2011/08/jMonkeEngine_showcase.png" medium="image">
			<media:title type="html">jMonkeEngine_showcase</media:title>
		</media:content>
		<media:content url="http://www.streamhead.com/wp-content/uploads/2011/08/jMonkeEngine_showcase.png" medium="image">
			<media:title type="html">jMonkeEngine_showcase</media:title>
		</media:content>
	</item>
		<item>
		<title>Website Wireframes and Mock Tools Comparison</title>
		<link>http://www.streamhead.com/mock-tools/</link>
		<comments>http://www.streamhead.com/mock-tools/#comments</comments>
		<pubDate>Tue, 16 Aug 2011 14:00:20 +0000</pubDate>
		<dc:creator>Peter Backx</dc:creator>
				<category><![CDATA[Tools]]></category>

		<guid isPermaLink="false">http://www.streamhead.com/?p=3279</guid>
		<description><![CDATA[Whenever you&#8217;re proposing a web site or application to a client, showing him what it&#8217;s going to look like can work wonders. It avoids confusion and can fix doubts. But how do you show off a website when you haven&#8217;t written one line of code and HTML? Wireframe tools and website mocks are the answer. [...]<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></description>
			<content:encoded><![CDATA[<img width="300" height="250" src="http://www.streamhead.com/wp-content/uploads/2011/08/facebook_mockup.png" class="attachment-post-thumbnail wp-post-image" alt="Facebook mockup" title="facebook_mockup" /><p>Whenever you&#8217;re proposing a web site or application to a client, showing him what it&#8217;s going to look like can work wonders. It avoids confusion and can fix doubts. But how do you show off a website when you haven&#8217;t written one line of code and HTML? Wireframe tools and website mocks are the answer. This article compares a few of the many tools available.</p>
<p><span id="more-3279"></span>In this article I compare:</p>
<ul>
<li><a title="Balsamiq" href="http://balsamiq.com/">Balsamiq</a>. The de-facto standard for creating mocks.</li>
<li><a title="Rapid wireframing tool, for teams - WireframeSkechter" href="http://wireframesketcher.com/">WireframeSkechter</a>. A new kid on the block, based on Eclipse. The author generously donated a free license for this review.</li>
<li><a title="Website wireframes: Mockingbird" href="https://gomockingbird.com/">Mockingbird</a>. A completely web-based tool.</li>
</ul>
<p>All three of the tools offer a similar feature set and are all very capable. So if you don&#8217;t feel like reading on, just pick one, and I&#8217;m sure you&#8217;ll be happy.</p>
<p>Of course, if you look closely, there are many small differences that might suite you and your workflow better.</p>
<p><strong>Mockingbird</strong>&#8216;s visual style is cleaner and different than most other tools. And the way you can arrange components by snapping them to guidelines and other components is equaled by no other tool. It&#8217;s easy to quickly create a well-aligned and well-spaced layout.</p>
<p><strong>Balsamiq </strong> is the most widely known mocking tool. It is popular for a reason. With a solid standard set of components and many ways to extend its functionality through custom components and third party tools, you&#8217;ll certainly find what you need. I tested the desktop version, but since this is a Flex application, the online version is exactly the same.</p>
<p><strong>WireframeSketcher</strong> has a similar sketchy look as Balsamiq. Which is great way to communicate to your client that these are just temporary mockups. WireframeSketcher&#8217;s main selling point is the wiki-like syntax that allows you to deeply customize the standard components, such as the table. My main gripe is the small up and down arrows to navigate through the component library. I know this is a very minor annoyance, but the idea of mockups is to quickly sketch a layout and this held me back somewhat.</p>
<p>None of the three tools have an intuitive way of adding arrows. I like to attach yellow sticky notes to certain areas to explain different parts and have arrows point out the details. None of the tools made this easy.</p>
<p>The following spreadsheet gives an overview of some of the features of the different tools. You&#8217;ll notice that they are very close, so in the end it&#8217;s probably going to come down to personal preference.</p>
<p><iframe src="https://docs.google.com/spreadsheet/pub?hl=en_US&amp;hl=en_US&amp;key=0AimAxoLiivAfdDFzOWpYUDBBTGYxRWhqNlR0U2d6THc&amp;single=true&amp;gid=0&amp;range=A1%3AD19&amp;output=html&amp;widget=true" frameborder="0" width="530" height="530"></iframe></p>
<p><a href="http://www.streamhead.com/dirt-cheap-node-js-web-apps/">NEW: $199 for a Node.js web app by Streamhead</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.streamhead.com/mock-tools/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:thumbnail url="http://www.streamhead.com/wp-content/uploads/2011/08/facebook_mockup.png" />
		<media:content url="http://www.streamhead.com/wp-content/uploads/2011/08/facebook_mockup.png" medium="image">
			<media:title type="html">facebook_mockup</media:title>
		</media:content>
		<media:content url="http://www.streamhead.com/wp-content/uploads/2011/08/facebook_mockup.png" medium="image">
			<media:title type="html">facebook_mockup</media:title>
		</media:content>
	</item>
	</channel>
</rss>

<!-- Dynamic page generated in 3.030 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2012-05-18 05:00:22 -->
<!-- Compression = gzip -->
