<?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/"
	>

<channel>
	<title>CB1, INC. &#187; Blog</title>
	<atom:link href="http://www.cb1inc.com/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.cb1inc.com</link>
	<description></description>
	<lastBuildDate>Sat, 08 May 2010 17:20:40 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>How to Fix Wake Up Freezing on MacBook Pros</title>
		<link>http://www.cb1inc.com/2010/05/07/how-to-fix-wake-up-freezing-on-macbook-pros/</link>
		<comments>http://www.cb1inc.com/2010/05/07/how-to-fix-wake-up-freezing-on-macbook-pros/#comments</comments>
		<pubDate>Sat, 08 May 2010 03:09:47 +0000</pubDate>
		<dc:creator>Chris Barber</dc:creator>
				<category><![CDATA[mac os x]]></category>

		<guid isPermaLink="false">http://www.cb1inc.com/?p=1439</guid>
		<description><![CDATA[If you have a MacBook Pro with several gigabytes of RAM, you may have noticed that Mac OS X will lock up when you try to wake the laptop up. This can be very frustrating and requires you to hold the power button in for 5 seconds and turning it back on. I run 2 [...]]]></description>
			<content:encoded><![CDATA[<p>If you have a MacBook Pro with several gigabytes of RAM, you may have noticed that Mac OS X will lock up when you try to wake the laptop up.  This can be very frustrating and requires you to hold the power button in for 5 seconds and turning it back on.</p>
<p>I run 2 or 3 VMware Fusion virtual machines at the same time and that eats up a ton of RAM, but it&#8217;s OK since my laptop has 8GB of memory.  My machine would lock up when I tried to wake it up.  I found that it would sometimes be OK leaving 1 virtual machine running, but if I left 2 running, it would almost always lock up.</p>
<p>So, I did some research and discovered the problem has to do with Mac OS X&#8217;s power management, specifically the <em>hibernatemode</em>.  The value is a bitfield that has the following options:</p>
<ul>
<li>0 (0000) Disables SafeSleep. Memory state is maintained until battery power is gone in which case the computer turns off completely.</li>
<li>1 (0001) Enables hibernation, writes memory contents to hibernation image, and immediately goes to sleep.</li>
<li>3 (0011) Maintains memory state while sleeping, but when the battery power is nearly gone, it will write the contents of the memory to hibernation image.</li>
</ul>
<p>On laptops, the default value is 3.  On desktops, the default is 0.</p>
<p>To fix the problem, you simply need to set the <em>hibernatemode</em> to 0.  From a Mac OS X terminal, run the following:</p>
<pre class="brush: plain;">
sudo pmset -a hibernatemode 0
</pre>
<p>Then reboot your laptop and enjoy lock-free waking up!</p>
<p>At this point, hibernation is disabled and that means you can delete the hibernation file and free up a couple gigs of disk space!</p>
<pre class="brush: plain;">
sudo rm -f /var/vm/sleepimage
</pre>
<p>One side note, Microsoft Windows actually disables hibernating on computers with 4GB or more of RAM.  They claim that it took longer to restore the memory state from disk than to just do a normal boot.  I disagree since it takes a long time to spin up all your apps, virtual machines, and start being productive.  I wonder if they discovered some technical issue that is what is causing the issues on Macs.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cb1inc.com/2010/05/07/how-to-fix-wake-up-freezing-on-macbook-pros/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Cassandra Presentation Slides</title>
		<link>http://www.cb1inc.com/2010/05/07/cassandra-presentation-slides/</link>
		<comments>http://www.cb1inc.com/2010/05/07/cassandra-presentation-slides/#comments</comments>
		<pubDate>Fri, 07 May 2010 05:27:31 +0000</pubDate>
		<dc:creator>Chris Barber</dc:creator>
				<category><![CDATA[cassandra]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[presentations]]></category>

		<guid isPermaLink="false">http://www.cb1inc.com/?p=1431</guid>
		<description><![CDATA[Tonight I gave a talk about Cassandra at the Minnesota PHP User Group. I would hope that everyone that came out learned a little something. I have to admit the talk was a bit unorganized, but hey, I love to talk. It also didn&#8217;t help that there was major construction going on at the meeting [...]]]></description>
			<content:encoded><![CDATA[<p>Tonight I gave a talk about <a href="http://cassandra.apache.org/" target="_blank">Cassandra</a> at the Minnesota PHP User Group. I would hope that everyone that came out learned a little something. I have to admit the talk was a bit unorganized, but hey, I love to talk. It also didn&#8217;t help that there was major construction going on at the meeting venue that made it hard for people to hear me.</p>
<div style="margin:0 auto;width:425px" id="__ss_4002175"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/cb1kenobi/cassandra-say-goodbye-to-the-relational-database-562010" title="Cassandra - Say Goodbye to the Relational Database (5-6-2010)">Cassandra &#8211; Say Goodbye to the Relational Database (5-6-2010)</a></strong><object id="__sse4002175" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=cassandra-saygoodbyetotherelationaldatabase5-6-2010-100506234446-phpapp02&#038;rel=0&#038;stripped_title=cassandra-say-goodbye-to-the-relational-database-562010" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse4002175" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=cassandra-saygoodbyetotherelationaldatabase5-6-2010-100506234446-phpapp02&#038;rel=0&#038;stripped_title=cassandra-say-goodbye-to-the-relational-database-562010" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></div>
<p>After rambling for an hour and a half, I finally ran out of Cassandra-related stuff to talk about.  Since some people were interested in some new features of PHP 5.3, I showed off my MVC framework I&#8217;ve been working on called <a href="http://github.com/cb1kenobi/elevate" target="_blank">Elevate</a>.  In Elevate&#8217;s code, I use some of PHP 5.3&#8242;s new features such as closures, namespaces, and the ternary operator (?:).  I also showed Elevate&#8217;s super cool Gearman worker daemon that I used for sending e-mails.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cb1inc.com/2010/05/07/cassandra-presentation-slides/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cassandra Talk at the May Twin Cities PHP User Group</title>
		<link>http://www.cb1inc.com/2010/05/03/cassandra-talk-at-the-may-twin-cities-php-user-group/</link>
		<comments>http://www.cb1inc.com/2010/05/03/cassandra-talk-at-the-may-twin-cities-php-user-group/#comments</comments>
		<pubDate>Mon, 03 May 2010 23:45:55 +0000</pubDate>
		<dc:creator>Chris Barber</dc:creator>
				<category><![CDATA[cassandra]]></category>
		<category><![CDATA[php]]></category>

		<guid isPermaLink="false">http://www.cb1inc.com/?p=1413</guid>
		<description><![CDATA[This Thursday, May 6th, at 6pm I&#8217;ll be giving a talk about Cassandra at the Minnesota PHP User Group. I&#8217;ll be covering Cassandra&#8217;s architecture and how it scales to handle tons of data and still be fast and fault tolerant. I&#8217;ll also cover Cassandra&#8217;s API and data modeling, specifically with PHP. The user group will [...]]]></description>
			<content:encoded><![CDATA[<p>This Thursday, May 6th, at 6pm I&#8217;ll be giving a talk about <a href="http://cassandra.apache.org/">Cassandra</a> at the Minnesota PHP User Group.</p>
<p><a href="http://www.mnphp.org/calendar/13353590/"><img src="/wp-content/uploads/2010/05/cassandra_logo.png" alt="Cassandra" width="500" height="100" class="aligncenter size-full wp-image-1415" /></a></p>
<p>I&#8217;ll be covering Cassandra&#8217;s architecture and how it scales to handle tons of data and still be fast and fault tolerant.  I&#8217;ll also cover Cassandra&#8217;s API and data modeling, specifically with PHP.</p>
<p>The user group will meet at Nerdery Interactive Labs (<a href="http://maps.google.com/maps?f=q&#038;source=s_q&#038;hl=en&#038;geocode=&#038;q=9555+James+Ave+S,+Suite+245,+Bloomington,+MN+55431&#038;sll=37.0625,-95.677068&#038;sspn=62.61328,131.572266&#038;ie=UTF8&#038;hq=&#038;hnear=9555+James+Ave+S+%23245,+Minneapolis,+Hennepin,+Minnesota&#038;ll=44.830826,-93.298731&#038;spn=0.027909,0.064244&#038;z=15">9555 James Ave S, Suite 245, Bloomington, MN 55431</a>). It will surely be packed with tons of awesome, so be sure to <a href="http://www.mnphp.org/calendar/13353590/">RSVP</a>!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cb1inc.com/2010/05/03/cassandra-talk-at-the-may-twin-cities-php-user-group/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>T-Minus Two Months to Open Source Bridge</title>
		<link>http://www.cb1inc.com/2010/03/31/t-minus-two-months-to-open-source-bridge/</link>
		<comments>http://www.cb1inc.com/2010/03/31/t-minus-two-months-to-open-source-bridge/#comments</comments>
		<pubDate>Wed, 31 Mar 2010 08:38:56 +0000</pubDate>
		<dc:creator>Chris Barber</dc:creator>
				<category><![CDATA[conferences]]></category>

		<guid isPermaLink="false">http://www.cb1inc.com/?p=1364</guid>
		<description><![CDATA[This year, Portland gets not one, but two open source conferences: OSCON and Open Source Bridge (OSB). I attended OSCON in both 2008 and 2009, but this year the cycle may break. Instead I&#8217;ve opted to go to OSB in hopes that it will be more technical and less commercial. Not to mention, OSB is [...]]]></description>
			<content:encoded><![CDATA[<p>This year, Portland gets not one, but two open source conferences: <a href="http://www.oscon.com/oscon2010">OSCON</a> and <a href="http://opensourcebridge.org/">Open Source Bridge</a> (OSB). I attended OSCON in both 2008 and 2009, but this year the cycle may break. Instead I&#8217;ve opted to go to OSB in hopes that it will be more technical and less commercial. Not to mention, OSB is 20% the cost of OSCON.</p>
<p>The cutoff date for this years OSB proposals was just a few days ago and there are about 400 submissions. I considered submitting a talk about Dojo, but due to time constraints, I had to pass this year. Regardless, there are several talks that are pretty interesting and I hope they get selected. The topics that I&#8217;m most interested in are:</p>
<ul>
<li>Distributed databases and data modeling</li>
<li>Cloud deployment and management</li>
<li>PHP tricks</li>
<li>Drizzle</li>
<li>Websockets</li>
<li>Concurrency and threading</li>
<li>Geolocation</li>
<li>Scalability and performance</li>
</ul>
<p>A little disappointed there weren&#8217;t more JavaScript or C/C++ talks. For a complete list of sessions that I&#8217;d like to attend, check out <a href="http://opensourcebridge.org/users/431/favorites">my favorites sessions</a>.</p>
<p>April 1st, 2010 is the last day to get the early bird discount for $225, otherwise it goes up to a whopping $300. You can register on their site: <a href="http://opensourcebridge.org/attend/">http://opensourcebridge.org/attend/</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cb1inc.com/2010/03/31/t-minus-two-months-to-open-source-bridge/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Debugging Dojo Applications Presentation</title>
		<link>http://www.cb1inc.com/2010/02/10/debugging-dojo-applications-presentation/</link>
		<comments>http://www.cb1inc.com/2010/02/10/debugging-dojo-applications-presentation/#comments</comments>
		<pubDate>Thu, 11 Feb 2010 02:33:00 +0000</pubDate>
		<dc:creator>Chris Barber</dc:creator>
				<category><![CDATA[conferences]]></category>
		<category><![CDATA[dojo]]></category>
		<category><![CDATA[presentations]]></category>

		<guid isPermaLink="false">http://www.cb1inc.com/?p=1321</guid>
		<description><![CDATA[Today I gave a talk at dojo.connect about debugging dojo applications. The talk actually covered a few thing that weren&#8217;t necessarily &#8220;debugging&#8221; related, but still had some good tips. Besure to check out the slides!]]></description>
			<content:encoded><![CDATA[<p>Today I gave a talk at dojo.connect about debugging dojo applications. The talk actually covered a few thing that weren&#8217;t necessarily &#8220;debugging&#8221; related, but still had some good tips. Besure to check out the slides!</p>
<div style="margin:0 auto;width:425px;"><object style="margin:0;" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=debuggingdojoapplications2-10-2010-100210141004-phpapp01&#038;stripped_title=debugging-dojo-applications-2102010" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=debuggingdojoapplications2-10-2010-100210141004-phpapp01&#038;stripped_title=debugging-dojo-applications-2102010" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></div>
]]></content:encoded>
			<wfw:commentRss>http://www.cb1inc.com/2010/02/10/debugging-dojo-applications-presentation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Speaking at dojo.connect Online Conference</title>
		<link>http://www.cb1inc.com/2010/02/08/speaking-at-dojo-connect-online-conference/</link>
		<comments>http://www.cb1inc.com/2010/02/08/speaking-at-dojo-connect-online-conference/#comments</comments>
		<pubDate>Mon, 08 Feb 2010 17:03:05 +0000</pubDate>
		<dc:creator>Chris Barber</dc:creator>
				<category><![CDATA[conferences]]></category>
		<category><![CDATA[dojo]]></category>

		<guid isPermaLink="false">http://www.cb1inc.com/?p=1313</guid>
		<description><![CDATA[The first dojo.connect online conference is coming up this week February 10-12, 2010. I&#8217;ll be giving a talk about Debugging Dojo Applications. I&#8217;ll be covering the following: Common mistakes and how to avoid them Web browser debug tools Built-in Dojo debugging tools Methods for finding and fixing syntax issues or malformed data Writing tests to [...]]]></description>
			<content:encoded><![CDATA[<p style="text-align: center;"><img class="aligncenter" title="dojo-connect-2010" src="/wp-content/uploads/2010/02/dojo-connect-2010.jpg" alt="dojo.connect" width="600" height="188" /></p>
<p>The first dojo.connect online conference is coming up this week February 10-12, 2010.  I&#8217;ll be giving a talk about <a href="http://www.widespreadconferences.com/#Speaker/cbarber">Debugging Dojo Applications</a>.  I&#8217;ll be covering the following:</p>
<ul>
<li>Common mistakes and how to avoid them</li>
<li>Web browser debug tools</li>
<li>Built-in Dojo debugging tools</li>
<li>Methods for finding and fixing syntax issues or malformed data</li>
<li>Writing tests to trap specific bugs</li>
</ul>
<p>There is still room left, so head over to <a href="http://www.widespreadconferences.com/">http://www.widespreadconferences.com/</a> and sign up today!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cb1inc.com/2010/02/08/speaking-at-dojo-connect-online-conference/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing the LightboxNano for Dojo!</title>
		<link>http://www.cb1inc.com/2008/10/14/introducing-the-lightboxnano-for-dojo/</link>
		<comments>http://www.cb1inc.com/2008/10/14/introducing-the-lightboxnano-for-dojo/#comments</comments>
		<pubDate>Tue, 14 Oct 2008 20:36:34 +0000</pubDate>
		<dc:creator>Chris Barber</dc:creator>
				<category><![CDATA[dojo]]></category>
		<category><![CDATA[lightboxnano]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[<p>I saw a really neat lightweight lightbox a while ago and decided to make a version for Dojo.  I've dubbed this version the LightboxNano because it is under 2K over the wire after a build and being gzip'd.</p>

<p>The LightboxNano is <em>not</em> a <code>dijit._Widget</code>.  It is designed to be very lightweight and only requires Dojo core and <code>dojo.fx</code>. The LightboxNano was coded for Dojo 1.2, but should work with past versions with little or no modifications.</p>

<h3>Features</h3>

<p>For being so small, it packs a handful of features:</p>

<ul>
<li>Automatically resizes large images to fit in browser window.</li>
<li>Preloads the larger image to make loading faster.</li>
<li>Keyboard accessible.</li>
<li>Instantly makes your website awesome.</li>
</ul>

<h3>Example</h3>

<p>The LightboxNano is really easy to use.  Here's an example:</p>

<pre><code>&#60;script src="/path/to/dojo.js" type="text/javascript"&#62;&#60;/script&#62;
&#60;script type="text/javascript"&#62;
    dojo.require("dojo.parser");
    dojo.require("dojox.image.LightboxNano");
&#60;/script&#62;

&#60;a dojoType="dojox.image.LightboxNano" href="/path/to/large/image.jpg"&#62;
    &#60;img src="/path/to/small/image.jpg"&#62;
&#60;/a&#62;</code></pre>

<p>To see it in action, click the image below:</p>

<?
$url = 'http://farm4.static.flickr.com/3270/2881707822_46f76966e4.jpg';
if(strtolower(arg(0)) == 'rss.xml'){
    $url = 'http://www.cb1inc.com/2008/10/14/introducing-the-lightboxnano-for-dojo';
}
?>

<div align="center"><a dojoType="dojox.image.LightboxNano" 
href="<?= $url ?>" id="exampleLightboxNano" style="width:240px;height:180px;"><img src="http://farm4.static.flickr.com/3270/2881707822_46f76966e4_m.jpg" width="240" height="180"></a></div>

<h3>Styling</h3>

<p>When the LightboxNano is created, it adds two <code>&#60;div&#62;</code> tags inside the anchor tag: one for the enlarge icon and one for the loading icon. For example, you can define styles like this:</p>

<pre><code>a:hover .dojoxEnlarge {
    display: block !important;
}
.dojoxEnlarge {
    background: url(images/enlarge.png) no-repeat 0 0;
    top: -5px;
    left: -5px;
    margin: 0 !important;
    width: 16px;
    height: 16px;
}
.dojoxLoading {
    background: #333 url(images/loading-dark.gif) no-repeat center center;
    border-radius: 5px;
    -moz-border-radius: 5px;
    -webkit-border-radius: 5px;
    border: 2px solid #000;
    height: 24px;
    opacity: 0.8;
    filter: alpha(opacity=80);
    padding: 6px;
    width: 24px;
}</code></pre>

<h3>Usage</h3>

<p>You can declaratively create the LightboxNano using a dojoType on an <code>&#60;a&#62;</code> or <code>&#60;img&#62;</code> tag.  Or you can choose to programatically create the LightboxNano:</p>

<pre><code>&#60;script type="text/javascript"&#62;
    dojo.addOnLoad(function(){
        new LightboxNano({
            href: "/path/to/large/image.jpg"
        }, "myLink");
    });
&#60;/script&#62;

&#60;a id="myLink" href="/path/to/large/image.jpg"&#62;
    &#60;img src="/path/to/small/image.jpg"&#62;
&#60;/a&#62;</code></pre>

<p>If you want to access it for some reason, you'll need to use its <code><a href="http://dojocampus.org/content/2008/05/06/jsid-dijitbyid-and-dojobyid/">jsId</a></code>.</p>

<h3>Parameters</h3>

<p><b>href</b> - String<br />
URL to the large image to show in the lightbox.</p>

<p><b>duration</b> - int<br />
The delay in milliseconds of the LighboxNano open and close animation.</p>

<p><b>preloadDelay</b> - int<br />
The delay in milliseconds after the LightboxNano is created before preloading the larger image.</p>

<h3>File Sizes</h3>

<p>The LightboxNano is pretty small, but it relies on several other core Dojo components.  If you do a custom Dojo build containing the LightboxNano and <code>dojo.parser</code>, the <code>dojo.js</code> is 96KB. If you enable HTTP compression on the web server, you can get that down to a nice 32KB.</p>

<h3>Limitations</h3>

<ul>
<li>The LightboxNano does not reposition itself when the browser window is resize or scrolled.</li>
<li>In IE6, drop down select lists bleed through the LighboxNano layer. This can be fixed with an iframe shim.  This was skipped to keep the size down and because we all want IE6 to just go away.</li>
</ul>

<h3>Future Improvements</h3>

<p>There's always things that can be done to improve the LightboxNano.  Here's a couple ideas and you're welcome to make suggestions in the comments.</p>

<ul>
<li>Add support for displaying a caption.</li>
<li>Add support for <code>dojox.embed</code> to play Flash or Quicktime movies.</li>
</ul>

<h3>Try it Today!</h3>

<p>You can download the LightboxNano files here: <a href="http://www.cb1inc.com/files/LightboxNano.tar.gz">LightboxNano.tar.gz</a> [594KB].  Soon, the LightboxNano will be in dojox, so you won't need to install it separately.</p>

<p>You can view the original test page here: <a href="http://www.cb1inc.com/dojo-1.2/dojox/image/tests/test_LightboxNano.html">http://www.cb1inc.com/dojo-1.2/dojox/image/tests/test_LightboxNano.html</a>.</p>

<p>If you end up using the LightboxNano, feel free to link to your site so everyone can see your new awesome website!</p>
]]></description>
			<content:encoded><![CDATA[<p>I saw a really neat lightweight lightbox a while ago and decided to make a version for Dojo.  I&#8217;ve dubbed this version the LightboxNano because it is under 2K over the wire after a build and being gzip&#8217;d.</p>
<p>The LightboxNano is <em>not</em> a <code>dijit._Widget</code>.  It is designed to be very lightweight and only requires Dojo core and <code>dojo.fx</code>. The LightboxNano was coded for Dojo 1.2, but should work with past versions with little or no modifications.</p>
<h3>Features</h3>
<p>For being so small, it packs a handful of features:</p>
<ul>
<li>Automatically resizes large images to fit in browser window.</li>
<li>Preloads the larger image to make loading faster.</li>
<li>Keyboard accessible.</li>
<li>Instantly makes your website awesome.</li>
</ul>
<h3>Example</h3>
<p>The LightboxNano is really easy to use.  Here&#8217;s an example:</p>
<pre class="brush: jscript;">
&lt;script src=&quot;/path/to/dojo.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
    dojo.require(&quot;dojo.parser&quot;);
    dojo.require(&quot;dojox.image.LightboxNano&quot;);
&lt;/script&gt;

&lt;a dojoType=&quot;dojox.image.LightboxNano&quot; href=&quot;/path/to/large/image.jpg&quot;&gt;
    &lt;img src=&quot;/path/to/small/image.jpg&quot;&gt;
&lt;/a&gt;
</pre>
<p>To see it in action, click the image below:</p>
<p><script type="text/javascript">
dojo.addOnLoad(function(){
  var n=dojo.byId("exampleLightboxNano");
  new dojox.image.LightboxNano({href:"http://farm4.static.flickr.com/3270/2881707822_46f76966e4.jpg"}, n);
});
</script></p>
<div align="center"><a href="/2008/10/14/introducing-the-lightboxnano-for-dojo" id="exampleLightboxNano" style="width:240px;height:180px;"><img src="http://farm4.static.flickr.com/3270/2881707822_46f76966e4_m.jpg" width="240" height="180"></a></div>
<h3>Styling</h3>
<p>When the LightboxNano is created, it adds two <code>&lt;div&gt;</code> tags inside the anchor tag: one for the enlarge icon and one for the loading icon. For example, you can define styles like this:</p>
<pre class="brush: css;">
a:hover .dojoxEnlarge {
    display: block !important;
}
.dojoxEnlarge {
    background: url(images/enlarge.png) no-repeat 0 0;
    top: -5px;
    left: -5px;
    margin: 0 !important;
    width: 16px;
    height: 16px;
}
.dojoxLoading {
    background: #333 url(images/loading-dark.gif) no-repeat center center;
    border-radius: 5px;
    -moz-border-radius: 5px;
    -webkit-border-radius: 5px;
    border: 2px solid #000;
    height: 24px;
    opacity: 0.8;
    filter: alpha(opacity=80);
    padding: 6px;
    width: 24px;
}
</pre>
<h3>Usage</h3>
<p>You can declaratively create the LightboxNano using a dojoType on an <code>&lt;a&gt;</code> or <code>&lt;img&gt;</code> tag.  Or you can choose to programatically create the LightboxNano:</p>
<pre class="brush: jscript;">
&lt;script type=&quot;text/javascript&quot;&gt;
    dojo.addOnLoad(function(){
        new LightboxNano({
            href: &quot;/path/to/large/image.jpg&quot;
        }, &quot;myLink&quot;);
    });
&lt;/script&gt;

&lt;a id=&quot;myLink&quot; href=&quot;/path/to/large/image.jpg&quot;&gt;
    &lt;img src=&quot;/path/to/small/image.jpg&quot;&gt;
&lt;/a&gt;
</pre>
<p>If you want to access it for some reason, you&#8217;ll need to use its <code><a href="http://dojocampus.org/content/2008/05/06/jsid-dijitbyid-and-dojobyid/">jsId</a></code>.</p>
<h3>Parameters</h3>
<p><b>href</b> &#8211; String<br />
URL to the large image to show in the lightbox.</p>
<p><b>duration</b> &#8211; int<br />
The delay in milliseconds of the LighboxNano open and close animation.</p>
<p><b>preloadDelay</b> &#8211; int<br />
The delay in milliseconds after the LightboxNano is created before preloading the larger image.</p>
<h3>File Sizes</h3>
<p>The LightboxNano is pretty small, but it relies on several other core Dojo components.  If you do a custom Dojo build containing the LightboxNano and <code>dojo.parser</code>, the <code>dojo.js</code> is 96KB. If you enable HTTP compression on the web server, you can get that down to a nice 32KB.</p>
<h3>Limitations</h3>
<ul>
<li>The LightboxNano does not reposition itself when the browser window is resize or scrolled.</li>
<li>In IE6, drop down select lists bleed through the LighboxNano layer. This can be fixed with an iframe shim.  This was skipped to keep the size down and because we all want IE6 to just go away.</li>
</ul>
<h3>Future Improvements</h3>
<p>There&#8217;s always things that can be done to improve the LightboxNano.  Here&#8217;s a couple ideas and you&#8217;re welcome to make suggestions in the comments.</p>
<ul>
<li>Add support for displaying a caption.</li>
<li>Add support for <code>dojox.embed</code> to play Flash or Quicktime movies.</li>
</ul>
<h3>Try it Today!</h3>
<p>You can download the LightboxNano files here: <a href="/files/LightboxNano.tar.gz">LightboxNano.tar.gz</a> [594KB].  Soon, the LightboxNano will be in dojox, so you won&#8217;t need to install it separately.</p>
<p>You can view the original test page here: <a href="http://download.dojotoolkit.org/release-1.3.1/dojo-release-1.3.1/dojox/image/tests/test_LightboxNano.html">http://download.dojotoolkit.org/release-1.3.1/dojo-release-1.3.1/dojox/image/tests/test_LightboxNano.html</a>.</p>
<p>If you end up using the LightboxNano, feel free to link to your site so everyone can see your new awesome website!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cb1inc.com/2008/10/14/introducing-the-lightboxnano-for-dojo/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>CB1, INC. Site Refresh and Kimura Framework Site Launched</title>
		<link>http://www.cb1inc.com/2008/10/12/cb1-inc-site-refresh-and-kimura-framework-site-launched/</link>
		<comments>http://www.cb1inc.com/2008/10/12/cb1-inc-site-refresh-and-kimura-framework-site-launched/#comments</comments>
		<pubDate>Sun, 12 Oct 2008 10:30:09 +0000</pubDate>
		<dc:creator>Chris Barber</dc:creator>
				<category><![CDATA[kimura]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Over 2 months in the making and the CB1, INC. website refresh is finally launched. Whoo! The site has been upgraded to Drupal 6, the interface has been cleaned up a bit and lots old content has been removed. Now that the <a href="http://code.google.com/p/dojo-toolkit-module/">Dojo Toolkit Module</a> is hosted over at Google Code, I removed the documentation.

I've also set up a dedicated site for my side project, the Kimura Framework, and it is awesome.  Kimura is a PHP powered framework with several out of the box features for things such as content management, blogs, forums, and more.  It is still heavily under development and I've got a bit of cleanup on the existing code.  For more information, visit http://www.kimuraframework.org.

I still have hopes for building a Comet server.  I've written some great code for it, but I never got around to dumping into a public repo.  That will be my goal for next year. :)]]></description>
			<content:encoded><![CDATA[<p>Over 2 months in the making and the CB1, INC. website refresh is finally launched. Whoo! The site has been upgraded to Drupal 6, the interface has been cleaned up a bit and lots old content has been removed. Now that the <a href="http://code.google.com/p/dojo-toolkit-module/">Dojo Toolkit Module</a> is hosted over at Google Code, I removed the documentation.</p>
<p>I&#8217;ve also set up a dedicated site for my side project, the Kimura Framework, and it is awesome.  Kimura is a PHP powered framework with several out of the box features for things such as content management, blogs, forums, and more.  It is still heavily under development and I&#8217;ve got a bit of cleanup on the existing code.  For more information, visit http://www.kimuraframework.org.</p>
<p>I still have hopes for building a Comet server.  I&#8217;ve written some great code for it, but I never got around to dumping into a public repo.  That will be my goal for next year. <img src='http://www.cb1inc.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
]]></content:encoded>
			<wfw:commentRss>http://www.cb1inc.com/2008/10/12/cb1-inc-site-refresh-and-kimura-framework-site-launched/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Virtual Hosts and Wildcard SSL Certificates with Apache 2.2</title>
		<link>http://www.cb1inc.com/2008/09/11/virtual-hosts-and-wildcard-ssl-certificates-with-apache-2-2/</link>
		<comments>http://www.cb1inc.com/2008/09/11/virtual-hosts-and-wildcard-ssl-certificates-with-apache-2-2/#comments</comments>
		<pubDate>Thu, 11 Sep 2008 07:00:15 +0000</pubDate>
		<dc:creator>Chris Barber</dc:creator>
				<category><![CDATA[apache]]></category>
		<category><![CDATA[ssl]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[It is possible with Apache to host multiple websites with a single static IP address.  However, you can only have one SSL certificate per static IP.  This post describes setting up Apache with multiple secure virtual hosts and a single self-signed wildcard certificate.  To learn about creating the certificate, check out <a href="http://www.cb1inc.com/2007/05/13/creating-self-signed-certs-on-apache-2.2">Creating Self-Signed Certs on Apache 2.2</a>.

Here's a table of our example hosts:

<table>
<thead><tr>
<th>Domain</th><th>Force SSL?</th><th>Trusted?</th><th>Valid Domain?</th>
</tr></thead>
<tbody>
<tr><td>www.site-a.com</td><td>No</td><td>No</td><td>Yes</td></tr>
<tr><td>secure.site-a.com</td><td>Yes</td><td>No</td><td>Yes</td></tr>
<tr><td>test.site-a.com</td><td>No</td><td>No</td><td>Yes</td></tr>
<tr><td>www.site-b.com</td><td>No</td><td>No</td><td>No</td></tr>
<tr><td>secure.site-b.com</td><td>Yes</td><td>No</td><td>No</td></tr>
</tbody></table>

In order for the certificate to be trusted, you need to obtain the certificate from a trusted <a href="http://en.wikipedia.org/wiki/Certificate_Authority">certificate authority</a>. Since we are using self-signed certificates, they are not trusted and we will see some warning messages. The data will still be encrypted.

For this to work, we are going to use <a href="http://httpd.apache.org/docs/2.2/vhosts/name-based.html">name-based virtual hosts</a>.

The name and location of Apache's configuration files vary based on which platform you use.  This post assumes Ubuntu in which case the configuration files in the <code>/etc/apache2</code> directory.

For starters, we need to tell Apache which ports to listen on by editing the file <code>/etc/apache2/ports.conf</code>.

<pre><code>Listen 80
&#60;IfModule mod_ssl.c&#62;
    Listen 443
&#60;/IfModule&#62;</code></pre>

Next we need to add our virtual hosts.  They are kept in the <code>/etc/apache2/sites-available</code> directory.  For organization purposes, separate your sites into separate config files, then run <code>a2ensite</code> for each site to generate a symbolic link in the <code>/etc/apache2/sites-enabled</code> directory.

Here is the configuration for the sites:

<pre><code>NameVirtualHost 192.168.1.200:80
NameVirtualHost 192.168.1.200:443

# http://site-a.com
# https://site-a.com -- Throws warning because cert is for *.site-a.com... see bottom
# http://www.site-a.com
# https://www.site-a.com
&#60;VirtualHost 192.168.1.200:80 192.168.1.200:443&#62;
  ServerName site-a.com
  ServerAlias www.site-a.com
  DocumentRoot /path/to/www.site-a
  # Note: SSL settings only need to be defined once!
  SSLEngine On
  SSLCertificateFile /path/to/thecert.crt
  SSLCertificateKeyFile /path/to/thecert.key
&#60;/VirtualHost&#62;

# Not SSL, redirect to https://secure.site-a.com
&#60;VirtualHost 192.168.1.200:80&#62;
  ServerName secure.site-a.com
  Redirect / https://secure.site-a.com/
&#60;/VirtualHost&#62;

# https://secure.site-a.com
&#60;VirtualHost 192.168.1.200:443&#62;
  ServerName secure.site-a.com
  DocumentRoot /path/to/secure.site-a
&#60;/VirtualHost&#62;

# http://test.site-a.com
# https://test.site-a.com
&#60;VirtualHost 192.168.1.200:80 192.168.1.200:443&#62;
  ServerName test.site-a.com
  DocumentRoot /path/to/test.site-a
&#60;/VirtualHost&#62;

# http://www.site-b.com
# https://www.site-b.com -- Throws warning because cert is for *.site-a.com
&#60;VirtualHost 192.168.1.200:80 192.168.1.200:443&#62;
  ServerName www.site-b.com
  DocumentRoot /path/to/secure.site-b
&#60;/VirtualHost&#62;

# Not SSL, redirect to https://secure.site-b.com
&#60;VirtualHost *:80&#62;
  ServerName secure.site-b.com
  Redirect / https://secure.site-b.com/
&#60;/VirtualHost&#62;

# https://secure.site-b.com -- Throws warning because cert is for *.site-a.com
&#60;VirtualHost 192.168.1.200:443&#62;
  ServerName secure.site-b.com
  DocumentRoot /path/to/secure.site-b
&#60;/VirtualHost&#62;</code></pre>

Despite having a wildcard certificate for <code>*.site-a.com</code>, you will get an invalid domain message when you don't supply the subdomain (i.e.  http://site-a.com).  The only way I know of to solve this is with 2 static IPs and 2 certs where one cert is for <code>site-a.com</code> and the other is for <code>*.site-a.com</code>.

I'm using 192.168.1.200 for the server's IP address behind the firewall.  You could try using * instead of 192.168.1.200 in the <code>&#60;VirtualHost&#62;</code> blocks, but I haven't tested this.  Leave a comment if you happen to test this. :)

Assuming the stars have aligned, you should have several secured virtual hosts!]]></description>
			<content:encoded><![CDATA[<p>It is possible with Apache to host multiple websites with a single static IP address.  However, you can only have one SSL certificate per static IP.  This post describes setting up Apache with multiple secure virtual hosts and a single self-signed wildcard certificate.  To learn about creating the certificate, check out <a href="/2008/05/13/creating-self-signed-certs-on-apache-2.2">Creating Self-Signed Certs on Apache 2.2</a>.</p>
<p>Here&#8217;s a table of our example hosts:</p>
<table>
<thead>
<tr>
<th>Domain</th>
<th>Force SSL?</th>
<th>Trusted?</th>
<th>Valid Domain?</th>
</tr>
</thead>
<tbody>
<tr>
<td>www.site-a.com</td>
<td>No</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>secure.site-a.com</td>
<td>Yes</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>test.site-a.com</td>
<td>No</td>
<td>No</td>
<td>Yes</td>
</tr>
<tr>
<td>www.site-b.com</td>
<td>No</td>
<td>No</td>
<td>No</td>
</tr>
<tr>
<td>secure.site-b.com</td>
<td>Yes</td>
<td>No</td>
<td>No</td>
</tr>
</tbody>
</table>
<p>In order for the certificate to be trusted, you need to obtain the certificate from a trusted <a href="http://en.wikipedia.org/wiki/Certificate_Authority">certificate authority</a>. Since we are using self-signed certificates, they are not trusted and we will see some warning messages. The data will still be encrypted.</p>
<p>For this to work, we are going to use <a href="http://httpd.apache.org/docs/2.2/vhosts/name-based.html">name-based virtual hosts</a>.</p>
<p>The name and location of Apache&#8217;s configuration files vary based on which platform you use.  This post assumes Ubuntu in which case the configuration files in the <code>/etc/apache2</code> directory.</p>
<p>For starters, we need to tell Apache which ports to listen on by editing the file <code>/etc/apache2/ports.conf</code>.</p>
<pre class="brush: xml;">
Listen 80
&lt;IfModule mod_ssl.c&gt;
    Listen 443
&lt;/IfModule&gt;
</pre>
<p>Next we need to add our virtual hosts.  They are kept in the <code>/etc/apache2/sites-available</code> directory.  For organization purposes, separate your sites into separate config files, then run <code>a2ensite</code> for each site to generate a symbolic link in the <code>/etc/apache2/sites-enabled</code> directory.</p>
<p>Here is the configuration for the sites:</p>
<pre class="brush: xml;">
NameVirtualHost 192.168.1.200:80
NameVirtualHost 192.168.1.200:443

# http://site-a.com
# https://site-a.com -- Throws warning because cert is for *.site-a.com... see bottom
# http://www.site-a.com
# https://www.site-a.com
&lt;VirtualHost 192.168.1.200:80 192.168.1.200:443&gt;
  ServerName site-a.com
  ServerAlias www.site-a.com
  DocumentRoot /path/to/www.site-a
  # Note: SSL settings only need to be defined once!
  SSLEngine On
  SSLCertificateFile /path/to/thecert.crt
  SSLCertificateKeyFile /path/to/thecert.key
&lt;/VirtualHost&gt;

# Not SSL, redirect to https://secure.site-a.com
&lt;VirtualHost 192.168.1.200:80&gt;
  ServerName secure.site-a.com
  Redirect / https://secure.site-a.com/
&lt;/VirtualHost&gt;

# https://secure.site-a.com
&lt;VirtualHost 192.168.1.200:443&gt;
  ServerName secure.site-a.com
  DocumentRoot /path/to/secure.site-a
&lt;/VirtualHost&gt;

# http://test.site-a.com
# https://test.site-a.com
&lt;VirtualHost 192.168.1.200:80 192.168.1.200:443&gt;
  ServerName test.site-a.com
  DocumentRoot /path/to/test.site-a
&lt;/VirtualHost&gt;

# http://www.site-b.com
# https://www.site-b.com -- Throws warning because cert is for *.site-a.com
&lt;VirtualHost 192.168.1.200:80 192.168.1.200:443&gt;
  ServerName www.site-b.com
  DocumentRoot /path/to/secure.site-b
&lt;/VirtualHost&gt;

# Not SSL, redirect to https://secure.site-b.com
&lt;VirtualHost *:80&gt;
  ServerName secure.site-b.com
  Redirect / https://secure.site-b.com/
&lt;/VirtualHost&gt;

# https://secure.site-b.com -- Throws warning because cert is for *.site-a.com
&lt;VirtualHost 192.168.1.200:443&gt;
  ServerName secure.site-b.com
  DocumentRoot /path/to/secure.site-b
&lt;/VirtualHost&gt;
</pre>
<p>Despite having a wildcard certificate for <code>*.site-a.com</code>, you will get an invalid domain message when you don&#8217;t supply the subdomain (i.e.  http://site-a.com).  The only way I know of to solve this is with 2 static IPs and 2 certs where one cert is for <code>site-a.com</code> and the other is for <code>*.site-a.com</code>.</p>
<p>I&#8217;m using 192.168.1.200 for the server&#8217;s IP address behind the firewall.  You could try using * instead of 192.168.1.200 in the <code>&lt;VirtualHost&gt;</code> blocks, but I haven&#8217;t tested this.  Leave a comment if you happen to test this. <img src='http://www.cb1inc.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Assuming the stars have aligned, you should have several secured virtual hosts!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.cb1inc.com/2008/09/11/virtual-hosts-and-wildcard-ssl-certificates-with-apache-2-2/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Integrating Google AJAX Search API on Your Website</title>
		<link>http://www.cb1inc.com/2008/09/11/integrating-google-ajax-search-api-on-your-website/</link>
		<comments>http://www.cb1inc.com/2008/09/11/integrating-google-ajax-search-api-on-your-website/#comments</comments>
		<pubDate>Thu, 11 Sep 2008 02:47:40 +0000</pubDate>
		<dc:creator>Chris Barber</dc:creator>
				<category><![CDATA[dojo]]></category>
		<category><![CDATA[google]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[I recently had to integrate search capabilities into a website I worked on.  I chose to use the <a href="http://code.google.com/apis/ajaxsearch/">Google AJAX Search API</a>.  I needed the form field display to be very customized and clean.  I do leverage the <a href="http://dojotoolkit.org">Dojo Javascript Toolkit</a> to help with the boilerplate DOM and event stuff.

<div align="center"><img alt="Search Form" src="/sites/default/blog/20080910-searchform.gif"/></div>

The first thing you need to do is <a href="http://code.google.com/apis/ajaxsearch/signup.html">sign up for a new key</a>:

<div align="center"><a href="http://code.google.com/apis/ajaxsearch/signup.html"><img alt="Sign-up for an AJAX Search API Key" src="/sites/default/blog/20080910-signuppage.gif"/></a></div>

Once you get the key, you're ready to start coding your own custom search form.

Begin by adding the the following to your <code>&#60;head&#62;</code> tag:

<pre><code>&#60;script src="http://www.google.com/jsapi?key=&#60;KEY GOES HERE&#62;"
    type="text/javascript"&#62;&#60;/script&#62;</code></pre>

Since my example uses Dojo, you need to include Dojo for my code to work.  If you don't already use Dojo, you can simply include it by adding the following to the &#60;head&#62;:

<pre><code>&#60;script src="http://o.aolcdn.com/dojo/1.1.1/dojo/dojo.xd.js"
    type="text/javascript"&#62;&#60;/script&#62;</code></pre>

Next we need to add our code that performs the search. First tell the Google API to load the search API:

<pre><code>&#60;script type="text/javascript"&#62;
google.load("search", "1", {"nocss":true,"nooldnames":true});</code></pre>

Next we need to initialize our page when the page loads:

<pre><code>dojo.addOnLoad(function(){
    var results = dojo.byId("results");
    var cursor = dojo.byId("cursor");
    var ws = new google.search.WebSearch();
    ws.setNoHtmlGeneration();</code></pre>

Be sure to set the domain you want to search.  The LARGE_RESULTSET will return the maximum number of results Google allows, which is usually 8 results.

<pre><code>    ws.setSiteRestriction("example.com");
    ws.setResultSetSize(google.search.Search.LARGE_RESULTSET);</code></pre>

Next we need to tell the <code>WebSearch</code> object the function we want called after the results are returned.  The 3rd argument to <code>setSearchCompleteCallback()</code> is an array with a reference to our <code>WebSearch</code> instance.  This array gets passed to our callback function when the callback is fired.

<pre><code>    ws.setSearchCompleteCallback(null, function(w){
        if(!w.results){return;}
        results.innerHTML = "";
        cursor.innerHTML = "";
        var d = dojo.doc.createElement("div");
        results.appendChild(d);
        for(var i=0,len=w.results.length; i&#60;len; i++){
            var r = w.results[i];</code></pre>

Our <code>WebSearch</code> object has a <code>createResultHtml()</code> function that creates an the DOM nodes of our result, but it adds a bunch of crap and forces the result to open in a new window.  So, to fix that, we use Dojo to go clean up the nodes before adding them to the page.

<pre><code>            w.createResultHtml(r);
            if(r.html){
                var n = r.html.cloneNode(true);
                dojo.query(".gs-visibleUrl", n).forEach(function(p){
                    p.parentNode.removeChild(p);
                });
                dojo.query(".gs-watermark", n).forEach(function(p){
                    p.parentNode.removeChild(p);
                });
                dojo.query("a", n).forEach(function(p){
                    if(p.getAttribute("target")){
                        p.removeAttribute("target");
                    }
                });
                results.appendChild(n);
            }
        }
        if(w.cursor){
            var cn = dojo.doc.createElement("div");
            cn.className = "gsc-cursor";
            var label = dojo.doc.createElement("div");
            label.innerHTML = "Pages:";
            label.className = "label";
            cn.appendChild(label);
            for(var i=0, len=w.cursor.pages.length; i&#60;len; i++){
                var pn = dojo.doc.createElement("div");
                pn.className = "gsc-cursor-page";
                if(i == w.cursor.currentPageIndex){
                    pn.className += " gsc-cursor-current-page";
                }
                pn.innerHTML = w.cursor.pages[i].label;
                pn.idx = i;
                dojo.connect(pn, "onclick", function(evt){
                    ws.gotoPage(evt.target.idx);
                });
                cn.appendChild(pn);
            }
            cursor.appendChild(cn);
        }
    }, [ws]);</code></pre>

If you want to execute a search when the page loads, then you can fire <code>execute()</code> with the criteria.

<pre><code>    ws.execute("");</code></pre>

Finally we need to wire up the search button and form.  We don't care about the event details, we just want to execute the search for the current value in the search criteria field.

<pre><code>    function query(evt){
        dojo.stopEvent(evt);
        ws.execute(dojo.trim(dojo.byId("searchCriteria").value));
    }
    dojo.connect(dojo.byId("searchButton"), "onclick", query);
    dojo.connect(dojo.byId("searchForm"), "onsubmit", query);
});
&#60;/script&#62;</code></pre>

In the body of your page, add the following markup to define the form:

<pre><code>&#60;div&#62;
    &#60;form id="searchForm"&#62;
        &#60;input type="text" autocomplete="off" id="searchCriteria" value=""/&#62;
        &#60;a href="#" id="searchButton"&#62;&#60;span&#62;Search&#60;/span&#62;&#60;/a&#62;
    &#60;/form&#62;
&#60;/div&#62;
&#60;div id="results"&#62;&#60;/div&#62;
&#60;div id="cursor"&#62;&#60;/div&#62;</code></pre>

For clarity, I removed all styling.  One thing you'll notice is the "Search" button is an <code>&#60;a&#62;</code> tag instead of an <code>&#60;input&#62;</code> tag so that it could be more easily be styled.

Aside from our text field and search button, there are some CSS styles you can tweak for the search results and pagination:

<pre><code>&#60;style type="text/css"&#62;
.gs-result{padding:6px 0;}
.gsc-cursor{display:inline;padding:10px 0;}
.gsc-cursor .label{color:#000;display:inline;font-weight:bold;margin-right:8px;}
.gsc-cursor-page{cursor:pointer;color:#00F;display:inline;margin-right:8px;
text-decoration:underline;}
.gsc-cursor-current-page{color:#000;font-weight:bold;text-decoration:none;}
&#60;/style&#62;</code></pre>

That's all there is to it.  Load the page up and do a search!

<div align="center"><img alt="Search Results" src="/sites/default/blog/20080910-searchresults.gif"/></div>
]]></description>
			<content:encoded><![CDATA[<p>I recently had to integrate search capabilities into a website I worked on.  I chose to use the <a href="http://code.google.com/apis/ajaxsearch/">Google AJAX Search API</a>.  I needed the form field display to be very customized and clean.  I do leverage the <a href="http://dojotoolkit.org">Dojo Javascript Toolkit</a> to help with the boilerplate DOM and event stuff.</p>
<div align="center"><img alt="Search Form" src="/wp-content/uploads/2009/12/20080910-searchform.gif"/></div>
<p>The first thing you need to do is <a href="http://code.google.com/apis/ajaxsearch/signup.html">sign up for a new key</a>:</p>
<div align="center"><a href="http://code.google.com/apis/ajaxsearch/signup.html"><img alt="Sign-up for an AJAX Search API Key" src="/wp-content/uploads/2009/12/20080910-signuppage.gif"/></a></div>
<p>Once you get the key, you&#8217;re ready to start coding your own custom search form.</p>
<p>Begin by adding the the following to your <code>&lt;head&gt;</code> tag:</p>
<pre class="brush: xml;">
&lt;script src=&quot;http://www.google.com/jsapi?key=&lt;KEY GOES HERE&gt;&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
</pre>
<p>Since my example uses Dojo, you need to include Dojo for my code to work.  If you don&#8217;t already use Dojo, you can simply include it by adding the following to the &lt;head&gt;:</p>
<pre class="brush: xml;">
&lt;script src=&quot;http://o.aolcdn.com/dojo/1.1.1/dojo/dojo.xd.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
</pre>
<p>Next we need to add our code that performs the search. First tell the Google API to load the search API:</p>
<pre class="brush: xml;">
&lt;script type=&quot;text/javascript&quot;&gt;
google.load(&quot;search&quot;, &quot;1&quot;, {&quot;nocss&quot;:true,&quot;nooldnames&quot;:true});
</pre>
<p>Next we need to initialize our page when the page loads:</p>
<pre class="brush: jscript;">
dojo.addOnLoad(function(){
    var results = dojo.byId(&quot;results&quot;);
    var cursor = dojo.byId(&quot;cursor&quot;);
    var ws = new google.search.WebSearch();
    ws.setNoHtmlGeneration();
</pre>
<p>Be sure to set the domain you want to search.  The LARGE_RESULTSET will return the maximum number of results Google allows, which is usually 8 results.</p>
<pre class="brush: jscript;">
    ws.setSiteRestriction(&quot;example.com&quot;);
    ws.setResultSetSize(google.search.Search.LARGE_RESULTSET);
</pre>
<p>Next we need to tell the <code>WebSearch</code> object the function we want called after the results are returned.  The 3rd argument to <code>setSearchCompleteCallback()</code> is an array with a reference to our <code>WebSearch</code> instance.  This array gets passed to our callback function when the callback is fired.</p>
<pre class="brush: jscript;">
    ws.setSearchCompleteCallback(null, function(w){
        if(!w.results){return;}
        results.innerHTML = &quot;&quot;;
        cursor.innerHTML = &quot;&quot;;
        var d = dojo.doc.createElement(&quot;div&quot;);
        results.appendChild(d);
        for(var i=0,len=w.results.length; i&amp;lt;len; i++){
            var r = w.results[i];
</pre>
<p>Our <code>WebSearch</code> object has a <code>createResultHtml()</code> function that creates an the DOM nodes of our result, but it adds a bunch of crap and forces the result to open in a new window.  So, to fix that, we use Dojo to go clean up the nodes before adding them to the page.</p>
<pre class="brush: jscript;">
            w.createResultHtml(r);
            if(r.html){
                var n = r.html.cloneNode(true);
                dojo.query(&quot;.gs-visibleUrl&quot;, n).forEach(function(p){
                    p.parentNode.removeChild(p);
                });
                dojo.query(&quot;.gs-watermark&quot;, n).forEach(function(p){
                    p.parentNode.removeChild(p);
                });
                dojo.query(&quot;a&quot;, n).forEach(function(p){
                    if(p.getAttribute(&quot;target&quot;)){
                        p.removeAttribute(&quot;target&quot;);
                    }
                });
                results.appendChild(n);
            }
        }
        if(w.cursor){
            var cn = dojo.doc.createElement(&quot;div&quot;);
            cn.className = &quot;gsc-cursor&quot;;
            var label = dojo.doc.createElement(&quot;div&quot;);
            label.innerHTML = &quot;Pages:&quot;;
            label.className = &quot;label&quot;;
            cn.appendChild(label);
            for(var i=0, len=w.cursor.pages.length; i&amp;lt;len; i++){
                var pn = dojo.doc.createElement(&quot;div&quot;);
                pn.className = &quot;gsc-cursor-page&quot;;
                if(i == w.cursor.currentPageIndex){
                    pn.className += &quot; gsc-cursor-current-page&quot;;
                }
                pn.innerHTML = w.cursor.pages[i].label;
                pn.idx = i;
                dojo.connect(pn, &quot;onclick&quot;, function(evt){
                    ws.gotoPage(evt.target.idx);
                });
                cn.appendChild(pn);
            }
            cursor.appendChild(cn);
        }
    }, [ws]);
</pre>
<p>If you want to execute a search when the page loads, then you can fire <code>execute()</code> with the criteria.</p>
<pre class="brush: jscript;">
    ws.execute(&quot;&quot;);
</pre>
<p>Finally we need to wire up the search button and form.  We don&#8217;t care about the event details, we just want to execute the search for the current value in the search criteria field.</p>
<pre class="brush: jscript;">
    function query(evt){
        dojo.stopEvent(evt);
        ws.execute(dojo.trim(dojo.byId(&quot;searchCriteria&quot;).value));
    }
    dojo.connect(dojo.byId(&quot;searchButton&quot;), &quot;onclick&quot;, query);
    dojo.connect(dojo.byId(&quot;searchForm&quot;), &quot;onsubmit&quot;, query);
});
&lt;/script&gt;
</pre>
<p>In the body of your page, add the following markup to define the form:</p>
<pre class="brush: xml;">
&lt;div&gt;
    &lt;form id=&quot;searchForm&quot;&gt;
        &lt;input type=&quot;text&quot; autocomplete=&quot;off&quot; id=&quot;searchCriteria&quot; value=&quot;&quot;/&gt;
        &lt;a href=&quot;#&quot; id=&quot;searchButton&quot;&gt;&lt;span&gt;Search&lt;/span&gt;&lt;/a&gt;
    &lt;/form&gt;
&lt;/div&gt;
&lt;div id=&quot;results&quot;&gt;&lt;/div&gt;
&lt;div id=&quot;cursor&quot;&gt;&lt;/div&gt;
</pre>
<p>For clarity, I removed all styling.  One thing you&#8217;ll notice is the &#8220;Search&#8221; button is an <code>&lt;a&gt;</code> tag instead of an <code>&lt;input&gt;</code> tag so that it could be more easily be styled.</p>
<p>Aside from our text field and search button, there are some CSS styles you can tweak for the search results and pagination:</p>
<pre class="brush: css;">
&lt;style type=&quot;text/css&quot;&gt;
.gs-result{padding:6px 0;}
.gsc-cursor{display:inline;padding:10px 0;}
.gsc-cursor .label{color:#000;display:inline;font-weight:bold;margin-right:8px;}
.gsc-cursor-page{cursor:pointer;color:#00F;display:inline;margin-right:8px;
text-decoration:underline;}
.gsc-cursor-current-page{color:#000;font-weight:bold;text-decoration:none;}
&lt;/style&gt;
</pre>
<p>That&#8217;s all there is to it.  Load the page up and do a search!</p>
<div align="center"><img alt="Search Results" src="/wp-content/uploads/2009/12/20080910-searchresults.gif"/></div>
]]></content:encoded>
			<wfw:commentRss>http://www.cb1inc.com/2008/09/11/integrating-google-ajax-search-api-on-your-website/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>
