<?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>Views From The Hill &#187; Web</title>
	<atom:link href="http://dustint.com/archives/category/web/feed" rel="self" type="application/rss+xml" />
	<link>http://dustint.com</link>
	<description>Tales Of A (Former) SFU Computing Scientist</description>
	<lastBuildDate>Thu, 17 Jun 2010 20:14:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>Enable Xdebug HTML Output</title>
		<link>http://dustint.com/archives/234</link>
		<comments>http://dustint.com/archives/234#comments</comments>
		<pubDate>Fri, 28 May 2010 02:28:31 +0000</pubDate>
		<dc:creator>Dustin</dc:creator>
				<category><![CDATA[How-To]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://dustint.com/?p=234</guid>
		<description><![CDATA[I recently updated to Ubuntu 10.04 which includes PHP-5.3 by default. Ever since that upgrade I&#8217;ve had trouble with Xdebug not displaying HTML in its output: instead it would output human-readable text which becomes quite unreadable when rendered in the browser without &#60;pre&#62; tags. Turns out when PHP was upgraded, the php.ini file was replaced, [...]]]></description>
			<content:encoded><![CDATA[<p>I recently updated to Ubuntu 10.04 which includes PHP-5.3 by default. Ever since that upgrade I&#8217;ve had trouble with Xdebug not displaying HTML in its output: instead it would output human-readable text which becomes quite <em>unreadable</em> when rendered in the browser without  &lt;pre&gt; tags.</p>
<p>Turns out when PHP was upgraded, the php.ini file was replaced, and in the new version, it has the production value for <strong>html_errors</strong> which is Off. Once I set <strong>html_errors=On</strong> in /etc/php5/apache, colourful HTML-formatted output was producted by Xdebug.</p>
<p>For the Curious reader, I&#8217;m using the following xdebug configuration file, which I&#8217;ve located in <em>/etc/php5/conf.d/xdebug.ini</em> to prevent any php.ini changes from overwriting my Xdebug directives. Please note that this is a slightly modified version of the default xdebug configuration included in <a href="http://www.wampserver.com/">wamp</a>, which I find to be quite nice:</p>

<div class="wp_syntax"><div class="code"><pre class="ini" style="font-family:monospace;"><span style="color: #000099;">zend_extension</span><span style="color: #000066; font-weight:bold;">=</span><span style="color: #933;">&quot;/usr/lib/php5/20090626/xdebug.so&quot;</span>
xdebug.remote_enable<span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">1</span>
xdebug.remote_host<span style="color: #000066; font-weight:bold;">=</span><span style="color: #933;">&quot;127.0.0.1&quot;</span>
xdebug.remote_port<span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">9000</span>
xdebug.remote_handler<span style="color: #000066; font-weight:bold;">=</span><span style="color: #933;">&quot;dbgp&quot;</span>
xdebug.remote_mode<span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">req</span>
xdebug.profiler_enable<span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">1</span>
xdebug.profiler_output_dir<span style="color: #000066; font-weight:bold;">=</span><span style="color: #933;">&quot;/tmp/xprofile/&quot;</span>
xdebug.collect_params<span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">On</span>
xdebug.show_local_vars<span style="color: #000066; font-weight:bold;">=</span><span style="color: #660066;">On</span></pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://dustint.com/archives/234/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WordPress Plugin: Save FTP Information</title>
		<link>http://dustint.com/archives/164</link>
		<comments>http://dustint.com/archives/164#comments</comments>
		<pubDate>Fri, 04 Sep 2009 20:33:42 +0000</pubDate>
		<dc:creator>Dustin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://dustint.com/?p=164</guid>
		<description><![CDATA[When WordPress cannot directly access the filesystem to do plugin updates / installs, it falls back to using FTP to preform the changes. However, this commonly requires the user to enter their FTP information on each change. I have created a wordpress plugin that will permanently save the FTP information without the need to edit [...]]]></description>
			<content:encoded><![CDATA[<p>When WordPress cannot directly access the filesystem to do plugin updates / installs, it falls back to using FTP to preform the changes. However, this commonly requires the user to enter their FTP information on each change. I have created a wordpress plugin that will permanently save the FTP information without the need to edit the wp-config.php file.</p>
<p>Check it out <a href="http://dustint.com/projects/ftpinfo">Here</a></p>
]]></content:encoded>
			<wfw:commentRss>http://dustint.com/archives/164/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fakemail for Developers</title>
		<link>http://dustint.com/archives/27</link>
		<comments>http://dustint.com/archives/27#comments</comments>
		<pubDate>Sat, 07 Jun 2008 07:34:18 +0000</pubDate>
		<dc:creator>Dustin</dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Unix]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://dustint.com/?p=27</guid>
		<description><![CDATA[The other day when I was setting up email notifications for a Zend Framework application, I stumbled across Fakemail. From the developers website: fakemail is a fake mail server that captures emails as files for acceptance testing. This avoids the excessive configuration of setting up a real mail server and trying to extract mail queue [...]]]></description>
			<content:encoded><![CDATA[<p>The other day when I was setting up email notifications for a Zend Framework application, I stumbled across Fakemail.</p>
<p>From the developers website:</p>
<blockquote><p>fakemail is a fake mail server that captures emails as files for acceptance testing. This avoids the excessive configuration of setting up a real mail server and trying to extract mail queue content.</p></blockquote>
<p>I am quite impressed with this handy little script (written in both Python and Perl), as it works exactly as advertised: taking out the time required to properly configure a SMTP server and saving the hassle of having dozens of test messages showered across inboxes. Instead of forwarding emails on to their recipients, it simply saves a raw copy of the email to the specified directory.</p>
<p>The script has a windows installer that bundles the script with python and will run on all flavors of Linux and Unix assuming that they have perl or python installed.</p>
<p>To configure Zend_Mail use fakemail place the following in your bootstrapper or common config file:<br />
[php]Zend_Mail::setDefaultTransport(new Zend_Mail_Transport_Smtp(&#8216;localhost&#8217;,array(<br />
&#8216;port&#8217; =&gt; 10025<br />
)));[/php]</p>
<p>The &#8216;localhost&#8217; variable is the address of the computer that fakemail is running on (likely the local machine). The port number is the port that is specified when fakemail is run on the command line.</p>
<p>For more information about fakemail, binaries, and a usage guide. Visit the developers website at Sourceforce: <a href="http://www.lastcraft.com/fakemail.php">http://www.lastcraft.com/fakemail.php</a></p>
]]></content:encoded>
			<wfw:commentRss>http://dustint.com/archives/27/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cache-Control with Zend Framework</title>
		<link>http://dustint.com/archives/25</link>
		<comments>http://dustint.com/archives/25#comments</comments>
		<pubDate>Fri, 06 Jun 2008 02:45:37 +0000</pubDate>
		<dc:creator>Dustin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Cache-Control]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://dustint.com/?p=25</guid>
		<description><![CDATA[Today I was optimizing a site that uses heavy PHP and Ajax. I wanted to reduce the amount of data that was being sent from the server. To put this in perspective, if there were no cache hits in a page load there would be a total of 755 KB pulled down over 123 requests. [...]]]></description>
			<content:encoded><![CDATA[<p>Today I was optimizing a site that uses heavy PHP and Ajax. I wanted to reduce the amount of data that was being sent from the server. To put this in perspective, if there were no cache hits in a page load there would be a total of 755 KB pulled down over 123 requests.<br />
<span id="more-25"></span><br />
The first step was throwing a .htaccess into the dojo folder that sets the Cache-Control header on the library files being pulled down.</p>

<div class="wp_syntax"><div class="code"><pre class="apache" style="font-family:monospace;">&lt;<span style="color: #000000; font-weight:bold;">IfModule</span> mod_expires.c&gt;
     <span style="color: #00007f;">Header</span> set Cache-Control <span style="color: #7f007f;">&quot;max-age=3600, public&quot;</span>
&lt;/<span style="color: #000000; font-weight:bold;">IfModule</span>&gt;</pre></div></div>

<p>The above checks to ensure the mod_expires module is loaded in apache, and if it is the Cache is set to expire 3600 seconds from now: 1 hour. Furthermore, the page can be cached in a publicly accessible (shared) cache.</p>
<p>Getting caching working with Zend was a little more challenging. By default Zend (or PHP) writes caching information to headers disabling caching. However, the code snippit below (to be placed inside an Action Controller) blanks out the expires header, sets the cache-control header so that the page expires in one hour, and blanks out the Pragma header. </p>
<p>The expires header allows the server to specify a date when the cache expires (Rather than setting the max-age offset) and the Pragma indicates if the page can be cached in a proxy. I found, with Firefox 3, if Expires and Pragma weren&#8217;t blanked out, they would take preference over the Cache-Control header, disabling caching of the page.</p>

<div class="wp_syntax"><div class="code"><pre class="php" style="font-family:monospace;"><span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getResponse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setHeader</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Expires'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getResponse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setHeader</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Cache-Control'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'public'</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getResponse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setHeader</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Cache-Control'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">'max-age=3800'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #000088;">$this</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">getResponse</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">-&gt;</span><span style="color: #004000;">setHeader</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">'Pragma'</span><span style="color: #339933;">,</span> <span style="color: #0000ff;">''</span><span style="color: #339933;">,</span> <span style="color: #009900; font-weight: bold;">true</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>After the addition of caching, the page load was reduced to 8Kb of data pulled down over 9 requests: about a 90% optimization.</p>
]]></content:encoded>
			<wfw:commentRss>http://dustint.com/archives/25/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Zend JSON-RPC with Dojo Howto</title>
		<link>http://dustint.com/archives/20</link>
		<comments>http://dustint.com/archives/20#comments</comments>
		<pubDate>Tue, 03 Jun 2008 02:50:54 +0000</pubDate>
		<dc:creator>Dustin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Dojo]]></category>
		<category><![CDATA[JSON]]></category>
		<category><![CDATA[RPC]]></category>
		<category><![CDATA[Zend Framework]]></category>

		<guid isPermaLink="false">http://dustint.com/?p=20</guid>
		<description><![CDATA[I have been using the Dojo toolkit as my Javascript library of choice since back in early 2006 when it was still around version 0.4. Since then, the project has made tremendous strides including the release of version 1.0 and 1.1 with 1.2 on the way. At the beginning of 2008 I started using the [...]]]></description>
			<content:encoded><![CDATA[<p><!--[if !mso]></p>
<style>
v\:* {behavior:url(#default#VML);}
o\:* {behavior:url(#default#VML);}
w\:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
</style>
<p><![endif]--><!--[if gte mso 9]><xml> Normal   0   false            false   false   false      EN-CA   X-NONE   X-NONE                                                     MicrosoftInternetExplorer4 </xml><![endif]--><!--[if gte mso 9]><xml> </xml><![endif]--> <!--[if gte mso 10]></p>
<style>
/* Style Definitions */
table.MsoNormalTable
{mso-style-name:"Table Normal";
mso-tstyle-rowband-size:0;
mso-tstyle-colband-size:0;
mso-style-noshow:yes;
mso-style-priority:99;
mso-style-qformat:yes;
mso-style-parent:"";
mso-padding-alt:0cm 5.4pt 0cm 5.4pt;
mso-para-margin-top:0cm;
mso-para-margin-right:0cm;
mso-para-margin-bottom:10.0pt;
mso-para-margin-left:0cm;
line-height:115%;
mso-pagination:widow-orphan;
font-size:11.0pt;
font-family:"Calibri","sans-serif";
mso-ascii-font-family:Calibri;
mso-ascii-theme-font:minor-latin;
mso-hansi-font-family:Calibri;
mso-hansi-theme-font:minor-latin;
mso-fareast-language:EN-US;}
</style>
<p><![endif]--></p>
<p>I have been using the Dojo toolkit as my Javascript library of choice since back in early 2006 when it was still around version 0.4. Since then, the project has made tremendous strides including the release of version 1.0 and 1.1 with 1.2 on the way. At the beginning of 2008 I started using the Zend Framework to build MVC PHP applications and, with the release of 1.5, it has become my PHP framework of choice.</p>
<p>To my delight, the Zend Framework and Dojo have recently <a href="http://dojotoolkit.org/2008/05/21/announcing-zend-framework-integration-dojo-1-x-0">announced</a> a partnership which will lead to tighter integration of these two great open source frameworks.</p>
<p>One of the most exciting additions to the Zend Framework is the <a href="http://framework.zend.com/wiki/display/ZFPROP/Zend_Json_Server+to+support+JSON-RPC">Zend_Json_Server support for JSON-RPC</a>. I have been using JSON-RPC with Dojo for quite some time and, up until now, it has been challenging to find a design pattern that plays nice with the Model View Controller implementation in the Zend Framework. However, with the addition of the Zend_Json_Server this is no longer the case.<span id="more-20"></span></p>
<h2>Prerequisites:</h2>
<p>This tutorial assumes you are familiar with developing in PHP and javascript and are experienced with dojo and the Zend Framework using the MVC paradigm.</p>
<h2>Common Pitfalls</h2>
<ul class="unIndentedList">
<li> Absolute paths are used in the code examples. Ensure that you modify them to reflect your server&#8217;s directory structure. This tutorial assumes that you are working with a ZF project whose /html/ directory corresponds to the root of your webserver</li>
<li> Ensure you place a .htaccess file in /html/scripts/ that disables the re-write engine. If you fail to do this step, when trying to load dojo libraries, ZF will be trying to find controllers that match the requests and throwing exceptions.</li>
</ul>
<h2>Patching Zend Framework</h2>
<p>At the time of writing, the Json-RPC component has not been accepted into the Zend Framework (although it will be soon). To get the Zend Framework (ZF) working with Json-RPC we must download code from the incubator area of SVN. If you don&#8217;t know how to use a SVN client to check out code, read about it <a href="http://framework.zend.com/manual/en/introduction.installation.html">here</a>. Download the current version of ZF and then, using an SVN client, download <a href="http://framework.zend.com/svn/framework/standard/incubator/library/Zend/Json/">http://framework.zend.com/svn/framework/standard/incubator/library/Zend/Json/ </a>and place it in the json directory of your local copy of ZF.</p>
<h2>Setting up the Directories</h2>
<p>For the purpose of this tutorial I will be using code and examples from <a href="../../../../../nickel">Nickel</a>: the application that will eventually run SFU Bookswap V.3. I use a fairly standard MVC directory structure as recommended by the ZF docs:</p>
<pre>application
	|-default
	|-controllers
	|-views
html
	|-images
	|-scripts
		|-nickel
			|-RPC
library
	|-Nickel
		|-Models
		|-RPC
	|-Zend
		| .... Framework checkout
</pre>
<p>The reasoning behind placing the Nickel folder in the library is so we can use Zend_Loader to load classes on demand. Also, as a condition of this, the classes in the Nickel folder follow the ZF naming convention: so, say, the class for a book model would be named, Nickel_Model_Book.</p>
<p>Similarly, there is a corresponding directory structure in the scripts folder. This is to be used with the Dojo packaging system. So, to access the RPC handle for the book model we would call a function such as nickel.rpc.book.getAuthor()</p>
<h2>Creating the RPC Controller</h2>
<p>The next step is to actually create the RPC controller. I have created a file in /application/default/controllers/RpcController.php which contains the RpcController action controller class. RpcController has two actions: one which will return the SMD (simple method declaration) to dojo when the JSON-RPC object is instantiated. The second action, the service action, actually processes the RPC request and returns the result. So, we have:</p>
<pre>/application/default/controllers/RpcController.php
[php]<?php
class RpcController extends Zend_Controller_Action {

	public function smdAction(){
		$class = $this->_getParam('class');

		$server = new Zend_Json_Server();

		$server->getServiceMap()->setDojoCompatible(true);
		$server->getServiceMap()->setTransport('POST')
       		->setTarget($this->getHelper('url')->url(array('controller'=>'rpc', 'action'=>'service')))
       		->setId($this->getHelper('url')->url(array('controller'=>'rpc', 'action'=>'service'))); 

       	$server->setClass($class);

       	$this->view->data = $server->getServiceMap();
		$this->render('service');
	}

	public function serviceAction(){
		$class = $this->_getParam('class');

		$server = new Zend_Json_Server();
		$server->setClass($class);
		$server->setAutoEmitResponse(true);

		$server->handle();
	}
}[/php]
</pre>
<p>The smd Action takes ‘class&#8217; as a parameter. This is the name of the class that we wish to expose via Json-RPC, such as Nickel_Rpc_Book. Please note the function call setDojoCompatible(true) which forces the server to generate dojo-compatible SMD definitions. The target function call sets the target of the function calls (the service url) to the service action defined below.</p>
<p>The service action simply processes the RPC request by calling the specified function with the sent parameters.</p>
<p>There is a fairly large security hole opened by this implementation. Since any value can be passed to the ‘class&#8217; argument, it is possible to remotely call functions for any class that can be auto-loaded. A ‘safer&#8217; implementation would simply concatenate the class parameter with &#8220;Nickel_Rpc_&#8221;. This way is less likely that an attacker could compromise your server by calling a dangerous function.</p>
<h2>Writing a RPC Class</h2>
<p>Now that we have the RPC server set up we need some classes in Nickel_RPC to call. For the purpose of this example we will use a very simple Book class that has basic functionality:</p>
<pre>/library/Nickel/Model/Book.php
[php]<?php
class Nickel_RPC_Book {
	public static function simpleEcho(){
		return “Hello World”;
	}
	public static function getTitle($bookId){
		$book = new Nickel_Model_Book($bookId);
		return $book->getTitle();
	}
	public static function setTitle($bookId, $title){
		$book = new Nickel_Model_Book($bookId);
		$book->setTitle($title);
		$book->update();
		return true;
	}
}
[/php]</pre>
<p>In the above RPC class, in addition to the simpleEcho function, we have two static functions: one that reads the title from the Book Model, and the second which writes a new title back to the database via the Book model. Notice that the functions are static: this is because, in the case of our book anyways, a notion of $this doesn&#8217;t really make since, as we don&#8217;t actually know what book we want the title for unless we pass the book ID from dojo.</p>
<h2>Writing the RPC Front-end</h2>
<p>Now that we have the backend written, it is fairly quick to write the frontend.</p>
<p>The first step is to create the book rpc file so we can include nickel.rpc.book using a dojo.require statement:</p>
<pre>/html/scripts/nickel/RPC/book.js
[js]dojo.provide(‘nickel.rpc.book’);
dojo.require(‘dojo.rpc.JsonService’);

nickel.rpc.book = new dojo.rpc.JsonService(‘/rpc/smd/class/Nickel_RPC_Book’);
[/js]</pre>
<p>The above code snippet should be saved as book.js and placed in /html/scripts/nickel/rpc. When this file is included, a new JsonService object is created with functions populated from the SMD generated by the RPC controller class. As a result, nickel.rpc.book will now contain three functions: simpleEcho, getTitle and setTitle.</p>
<h2>Using The Front-end.</h2>
<p>Finally, we have the opportunity to see the fruit of our labour. Create an indexController and the accompanying view. In the view, after including dojo.js, create a new script block:</p>
<pre>/application/default/views/index/index.phtml
...
[js]<script type=”text/javascript”>
	dojo.registerModulePath(‘nickel’, ‘/scripts/nickel’);
	dojo.require(‘nickel.rpc.book’);

	dojo.addOnLoad(function(){
		nickel.rpc.book.simpleEcho().addCallback(function(msg){
			alert(msg);		//Alert: Hello World
	});

	nickel.rpc.book.getTitle(1).addCallback(function(title){
		alert(title);	//Alert: title of book with ID 1 in database
	});

	nickel.rpc.book.setTitle(1, ‘Foo’).addCallback(function(result){
		alert(‘success’);	//Sets the title of book with ID 1 to ‘Foo’
	});
});
</script>
...
[/js]</pre>
<p>dojo.registerModulePath adds a module path to the dojo loader. This allows us to include our custom nickel modules easily and on-demand.</p>
<h2>Conclusion</h2>
<p>The Dojo Toolkit and Zend Framework provide a highly structured, maintainable JSON RPC system when used together. This can be used to easily propagate dirty javascript data objects to persistent storage in the backend, as well as expose PHP function calls to javascript to return useful data.</p>
<p>I hope you have enjoyed this tutorial. If you find any typos, mistakes or just wish to leave a message, please add a comment below.</p>
<p>I also encourage you to link to this post if you have found it at all useful in developing your web-application.</p>
]]></content:encoded>
			<wfw:commentRss>http://dustint.com/archives/20/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>What Central Authentication Can Do For You</title>
		<link>http://dustint.com/archives/15</link>
		<comments>http://dustint.com/archives/15#comments</comments>
		<pubDate>Fri, 04 Apr 2008 19:22:53 +0000</pubDate>
		<dc:creator>Dustin</dc:creator>
				<category><![CDATA[Web]]></category>
		<category><![CDATA[CAS]]></category>
		<category><![CDATA[central authentication]]></category>

		<guid isPermaLink="false">http://dustint.com/archives/15</guid>
		<description><![CDATA[Imagine the following scenario: you are the operator of a small website that has a private user’s area which requires visitors to login to view. A few months later, you want to add a gallery application which also requires users to login and, finally, you want users to be able to edit a community wiki, [...]]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal">Imagine the following scenario: you are the operator of a small website that has a private user’s area which requires visitors to login to view. A few months later, you want to add a gallery application which also requires users to login and, finally, you want users to be able to edit a community wiki, but not allow non-members to make changes.</p>
<p class="MsoNormal">We can see that we have two choices: force the users to login to each separate application separately, or somehow combine all the applications under a single login.</p>
<p class="MsoNormal"><span id="more-15"></span></p>
<h1>A Central Authentication Service</h1>
<p class="MsoNormal">Central Authentication Services allow a user to share a single login across multiple applications and even websites. OpenID and Yahoo are examples of large CAS hybrids that are becoming increasingly popular amongst social networking sites. However, CAS does not have to be so global in scope, many universities and companies use CAS when their services are best provided by several applications.</p>
<h2>How it works</h2>
<p class="MsoNoSpacing">The series of events that occur during a CAS authentication session are as follows:</p>
<ol>
<li>User attempts to gain access to the secure area of a photo gallery</li>
<li>The gallery detects that this user is not authenticated to view this content</li>
<li>The user is re-directed to the login page of the Central Authentication Service. A callback URL is passed to the CAS by means of a GET variable</li>
<li>The user enters their login information and it is verified. A cookie is set to identify this user as authenticated in the future</li>
<li>The CAS redirects the user to the callback passed by the photo gallery. A ticket is passed to the photo gallery callback page by means of a GET variable</li>
<li>The photo gallery establishes a secure connection to the CAS and checks to ensure the ticket is valid, if it is, the user has been successfully authenticated</li>
</ol>
<p class="MsoNormal">Depending on the CAS setup, when the user enters another secure area of the website, say the wiki, they will be redirected to CAS, then transparently redirected back to the wiki callback page. This occurs because the user has already authenticated themselves with CAS, so there is no need to re-enter login credentials. To the user, it appears as if they were immediately authenticated by the wiki.</p>
<p class="MsoNormal">A Central Authentication Service also reduces some aspects of user information management as, if the user wishes to update their password; they need only do it once. However, CAS does not solve the problem of propagating other types of user information, such as the users name and contact information to the various applications. Furthermore, the authentication routines of the participating applications much be refactored to authenticate the user via CAS, then load the user information out of the local application database.</p>
<h2>In Conclusion:</h2>
<p class="MsoNormal">Central Authentication is a good way to improve the user experience if you are currently forcing users to authenticate multiple times. Furthermore, from a developers standpoint, it is a clean and safe way to pass authentication tokens between applications, especially if these applications may reside on separate domains.</p>
<p class="MsoNormal">For more information on CAS, including a JAVA server implementation, protocol descriptions and clients in multiple languages visit <a href="http://www.ja-sig.org/products/cas/index.html">http://www.ja-sig.org/products/cas/index.html</a></p>
]]></content:encoded>
			<wfw:commentRss>http://dustint.com/archives/15/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cookie Injection Using Greasemonkey</title>
		<link>http://dustint.com/archives/12</link>
		<comments>http://dustint.com/archives/12#comments</comments>
		<pubDate>Thu, 31 Jan 2008 05:46:34 +0000</pubDate>
		<dc:creator>Dustin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[How-To]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Cookie Stealing]]></category>
		<category><![CDATA[Cookies]]></category>
		<category><![CDATA[Ethereal]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[Greasemonkey]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Javascript]]></category>
		<category><![CDATA[TCP]]></category>
		<category><![CDATA[Wireshark]]></category>

		<guid isPermaLink="false">http://dustint.com/?p=12</guid>
		<description><![CDATA[There are several Firefox plugins which allow the user to manipulate their browser cookies. However, most of these plugins force the user to manipulate cookies individually. This can become tedious if the user is simply “importing” cookies from, say, a wireshark dump. The CookieInjector userscript simplifies this process, by allowing the user to copy-paste the [...]]]></description>
			<content:encoded><![CDATA[<p style="margin-bottom: 0cm">There are several Firefox plugins which allow the user to manipulate their browser cookies. However, most of these plugins force the user to manipulate cookies individually. This can become tedious if the user is simply “importing” cookies from, say, a wireshark dump.</p>
<p style="margin-bottom: 0cm">The CookieInjector userscript simplifies this process, by allowing the user to copy-paste the cookie portion of the dump and have the cookies from the dump automatically created on the currently viewed web page.</p>
<p style="margin-bottom: 0cm">
<h3>To Use The Script:</h3>
<p style="margin-bottom: 0cm">Fire up Wireshark, formally Ethereal, if you don&#8217;t have Wireshark you can grab it from: <a href="http://www.wireshark.org/" target="_blank">http://www.wireshark.org/</a>. Start listening for traffic on the same interface you use to access the internet. To cut down on extra packets, enter <em>tcp</em> as a capture filter. <a title="Wikipedia: TCP" href="http://en.wikipedia.org/wiki/TCP">TCP</a> is a transport layer protocol featuring reliable transport, congestion control and connection oriented transfers. Since HTTP uses connections between client and server and therefore the TCP protocol, is is safe to filter out all non-TCP packets. To further filter the packets that Wireshark is displaying enter <em>http.cookie</em> in the filter field. This will filter out all packets which are not using the HTTP application layer protocol and all HTTP packets which do not contain cookies.</p>
<p style="margin-bottom: 0cm">Next go to a website that uses cookies. Most websites which support user logins or shopping carts use cookies for these purposes. Make sure that the website that you visit does not encrypt the entire session (such as a banking website), otherwise the packets will be encrypted and not viewable in wireshark. After capturing a couple packets which contain cookies scroll down to the <em>Hypertext Transfer Protocol</em><span style="font-style: normal"> portion of the packet preview, expand it, and scroll down to the cookie line. Right click on the line, and select copy-&gt;Bytes (Printable Text Only). This will copy the human-readable portion of the packet which represents the Cookies associated with this website.</span></p>
<p style="margin-bottom: 0cm"><span style="font-style: normal">If you haven&#8217;t already, install <a href="https://addons.mozilla.org/en-US/firefox/addon/748" target="_blank">Greasemonkey,</a> and the CookieInjector userscript. Clear your private data, ensuring that the </span><em>Cookies</em><span style="font-style: normal"> and </span><em>Authenticated Sessions</em><span style="font-style: normal"> options are selected. This will delete all your cookies, so we can see the script in action. Press </span><em>alt-c</em><span style="font-style: normal"> to view the CookieInjector dialogue, paste the cookie string from wireshark into the text box and click OK. </span></p>
<p style="margin-bottom: 0cm; font-style: normal">Congratulations! Your cookies have now been restored!</p>
<p style="margin-bottom: 0cm; font-style: normal">
<h3>How The Script Works:</h3>
<p style="margin-bottom: 0cm; font-style: normal">After the page has loaded the CookieInjector class is initialized. This involves setting up the dialogue and binding a function to the onkeydown event. When the user presses the ALT-C key combination, the CookieInjector keyPress function is called, which checks to see if the correct key combination has been triggered. If it is valid, the dialogue&#8217;s display style is changed, making it visible in the middle of the page.</p>
<p style="margin-bottom: 0cm; font-style: normal">After the user enters the cookie that was copied from Wireshark, the script does a quick cleanup of the string, and then adds the cookies to the browsing session.</p>
<p style="margin-bottom: 0cm; font-style: normal">Note that the cookie&#8217;s host will be the domain that is loaded in the browser when the cookie is injected. The root path will be used for the root of the cookie to ensure that the cookie is persistent across the entire domain. Finally, the cookie is a session cookie, which means that the cookie will expire when the browser is closed.</p>
<p style="margin-bottom: 0cm; font-style: normal">
<h3>Security Implications Of Cookies</h3>
<p style="margin-bottom: 0cm; font-style: normal">The use of cookies for identification and authentication presents a dangerous security risk for un-encrypted connections. Most websites (such as Hotmail, Facebook and Gmail), only encrypt the username and password when initially authenticating the user and all traffic following the initial handshake is un-encrypted. As a result, the cookie information is readable by anyone who is listening with appropriate software, and malicious users can steal the cookies of other users on the network, possibly gaining access to their accounts. Un-encrypted or weakly encrypted wireless connections (those which do not use WPA or stronger encryption schemes) are especially susceptible to cookie stealing. This is because anyone with a wireless card can simply listen to all network traffic as it is broadcast through the air, intercepting cookies, images, web pages and any other traffic which may or not be intended for them. Intercepting traffic on a switched network (most LANs) is more complex, but can be accomplished using <a title="Wikipedia: ARP Spoofing" href="http://en.wikipedia.org/wiki/ARP_spoofing" target="_blank">ARP Poisoning</a> or software such as <a href="http://ettercap.sourceforge.net/" target="_blank">Ettercap</a></p>
<p style="margin-bottom: 0cm; font-style: normal">The take-home lesson is to use encrypted connections, like https, whenever privacy is important. Always remember that if the connection is not encrypted anyone could be listening in.</p>
<p style="margin-bottom: 0cm; font-style: normal"><a href="/code/cookieinjector.user.js">Download CookieInjection Userscript</a></p>
<p style="margin-bottom: 0cm; font-style: normal">
<h3>External Links:</h3>
<p style="margin-bottom: 0cm; font-style: normal">Greasemonkey: <a href="https://addons.mozilla.org/en-US/firefox/addon/748" target="_blank">https://addons.mozilla.org/en-US/firefox/addon/748</a><br />
HTTP Protocol: <a href="http://en.wikipedia.org/wiki/HTTP" target="_blank">http://en.wikipedia.org/wiki/HTTP</a><br />
TCP Protocol: <a href="http://en.wikipedia.org/wiki/TCP" target="_blank">http://en.wikipedia.org/wiki/TCP</a><br />
Cookies: <a href="http://en.wikipedia.org/wiki/HTTP_cookie" target="_blank">http://en.wikipedia.org/wiki/HTTP_cookie</a><br />
Wireshark: <a href="http://www.wireshark.org/" target="_blank">http://www.wireshark.org/</a><br />
Ettercap: <a href="http://ettercap.sourceforge.net/" target="_blank">http://ettercap.sourceforge.net/</a><br />
ARP Poisoning: <a href="http://en.wikipedia.org/wiki/ARP_spoofing" target="_blank">http://en.wikipedia.org/wiki/ARP_spoofing</a><br />
Ethereal: <a href="http://www.ethereal.com/" target="_blank">http://www.ethereal.com/</a></p>
<div id="cookieInjectorDiv" style="background: #dddddd none repeat scroll 0% 0%; display: none; position: fixed; opacity: 0.9; top: 40%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial; left: 40%; width: 20%;">
<div>Wireshark Cookie Dump:</p>
<input id="cookieInjectorCookie" type="text" />
<button onclick="cookieInjector.writeCookie();">OK</button><button onclick="cookieInjector.hide();">Cancel</button></div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://dustint.com/archives/12/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>SFU ULife Calendar Refactor</title>
		<link>http://dustint.com/archives/13</link>
		<comments>http://dustint.com/archives/13#comments</comments>
		<pubDate>Mon, 14 Jan 2008 08:09:08 +0000</pubDate>
		<dc:creator>Dustin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[SFU]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Calendar]]></category>
		<category><![CDATA[Community]]></category>
		<category><![CDATA[ULife]]></category>

		<guid isPermaLink="false">http://dustint.com/?p=13</guid>
		<description><![CDATA[This weekend I was working on some SFU community sites and I decided it would be nice to display the SFU ULife calendar on one website in particular. SFU ULife is a community building initiative which aims to increase the visibility of the community and events at SFU in a pledge to increase student involvement [...]]]></description>
			<content:encoded><![CDATA[<p> This weekend I was working on some SFU community sites and I decided it would be nice to display the SFU ULife calendar on one website in particular. SFU ULife is a community building initiative which aims to increase the visibility of the community and events at SFU in a pledge to increase student involvement and awareness. Read more about ULife&#8217;s goals <a href="http://www.sfu.ca/ulife/AboutUs/TheUlifeInitiative/index.html" title="SFU ULife" target="_blank">Here</a>.</p>
<p>As part of this initiative ULife maintains an events calendar that is available both in HTML and RSS formats. I was much more interested in the RSS feed as it can be easily parsed and manipulated by server-side PHP.</p>
<h3>How The Refactor Works (In A Nutshell)</h3>
<p>The basic operation of the script is very straight-forward.</p>
<ol>
<li>A copy of the ULife calendar RSS feed is downloaded and cached from <a href="https://events.sfu.ca/rss/calendar_id/3.xml">https://events.sfu.ca/rss/calendar_id/3.xml</a>.</li>
<li>The RSS feed is parsed by a slightly modified version of <a href="http://lastrss.oslab.net/">Last RSS</a> which converts the feed into PHP associative arrays.</li>
<li>The arrays are then passed to the <a href="http://www.smarty.net/">Smarty Template Engine</a> which makes the output look all pretty</li>
</ol>
<p>Simple eh? There is a little bit more of business logic, as the user is able to specify the template file to use, the CSS file to use, the number of days to display as well as indicate if the script is to output a full HTML page or just the HTML code needed for the calendar.</p>
<p>Currently the preferred way to include the calendar on a dynamic web-page is to use the PHP readfile (or equivalent) command with the argument being the path to the Refactor script. If the page is not dynamically generated the other option is to use a Javascript include, which uses cross site scripting to fetch the content and write it to the screen.</p>
<p>Right now there is only a single template available &#8211; a vertically aligned one, and a single style &#8211; a dark one. Users of the script can of course come up with their own style-sheets by simply downloading and editing the dark style sheet to their liking. If there is demand for it, I will write more templates, starting with a horizontally aligned template, along with a couple more style sheets.</p>
<p>To play around with the Calendar Refactor take a look at <a href="http://ulife.dustint.com">http://ulife.dustint.com</a></p>
]]></content:encoded>
			<wfw:commentRss>http://dustint.com/archives/13/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>SFU Bookswap v2.0</title>
		<link>http://dustint.com/archives/10</link>
		<comments>http://dustint.com/archives/10#comments</comments>
		<pubDate>Sun, 23 Dec 2007 20:43:49 +0000</pubDate>
		<dc:creator>Dustin</dc:creator>
				<category><![CDATA[SFU]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Bookswap]]></category>
		<category><![CDATA[Google]]></category>

		<guid isPermaLink="false">http://dustint.com/?p=10</guid>
		<description><![CDATA[I recently re-launched the SFU Bookswap website at a new address: http://sfubookswap.com. It is still reachable from the old address of http://books.sfu-rha.ca. The new address will provide fast, dedicated hosting which is a step up from the less than reliable system that was previously used. The new version of the Bookswap website also sports some [...]]]></description>
			<content:encoded><![CDATA[<p class="MsoNormal"><span lang="EN-CA">I recently re-launched the SFU Bookswap website at a new address: <a href="http://sfubookswap.com/">http://sfubookswap.com</a>. It is still reachable from the old address of <a href="http://books.sfu-rha.ca/">http://books.sfu-rha.ca</a>. The new address will provide fast, dedicated hosting which is a step up from the less than reliable system that was previously used.</span></p>
<p class="MsoNormal"><span lang="EN-CA">The new version of the Bookswap website also sports some new features and improved functionality. The process for making an offer has changed slightly: now the seller of the book is immediately notified of offers via email, rather than when the posting expires. This is intended to provide sellers with up-to-date information on people interested in their postings so they can make informed decisions if they are considering selling their book via another means.</span></p>
<p class="MsoNormal"><span lang="EN-CA">Since sellers are notified of offers immediately, it is less important for postings to expire in a timely matter. As a result, the restriction on the time before the posting expires has been removed. This way, sellers can choose to have high-value books expire quickly if they intend on selling them to the bookstore and have books which may take longer to sell persistent on the site.</span></p>
<p class="MsoNormal"><span lang="EN-CA">The interface for selling a book has also been improved. The page has been divided into several steps with additional descriptions of all fields. This is an attempt to help new users navigate the process for the first time while, at the same time, not negatively impacting the speed of experienced users.</span></p>
<p class="MsoNormal"><span lang="EN-CA">Perhaps the greatest change in the new version is the integration of the Google Books Database. Previously, when a user was adding a new book to the database, ISBNDB was queried for the book information and the cover image was searched in a separate step. Now Google Books is the data provider for both book information and cover information. This improves data integrity as there is a lower probability of a title / cover mismatches and, furthermore, the Google Books interface provides better searching over a variety of keyword types.</span></p>
<p class="MsoNormal"><span lang="EN-CA">Check out the new site! Get some cash for your texts:<br />
<a href="http://books.sfu-rha.ca/">http://bookswap.dustint.com</p>
<p>http://books.sfu-rha.ca</a></span></p>
]]></content:encoded>
			<wfw:commentRss>http://dustint.com/archives/10/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Greasemonkey And Dojo Integration</title>
		<link>http://dustint.com/archives/4</link>
		<comments>http://dustint.com/archives/4#comments</comments>
		<pubDate>Sun, 18 Nov 2007 22:35:11 +0000</pubDate>
		<dc:creator>Dustin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Dojo]]></category>
		<category><![CDATA[Greasemonkey]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://dustint.com/?p=4</guid>
		<description><![CDATA[Dojo (http://dojotoolkit.org/) is a wonderful javascript toolkit which just reached version 1.0 at the beginning of November. I have been watching and developing with Dojo for a couple years now and I can&#8217;t tell you how excited I am to have passed the version 1 milestone Greasemonkey (http://www.greasespot.net/) is a handy Firefox extension which allows [...]]]></description>
			<content:encoded><![CDATA[<p>Dojo (<a href="http://dojotoolkit.org/" title="Dojo Toolkit" target="_blank">http://dojotoolkit.org/</a>) is a wonderful javascript toolkit which just reached version 1.0 at the beginning of November. I have been watching and developing with Dojo for a couple years now and I can&#8217;t tell you how excited I am to have passed the version 1 milestone</p>
<p>Greasemonkey (<a href="http://www.greasespot.net/" title="Greasemonkey">http://www.greasespot.net/</a>) is a handy Firefox extension which allows the injection of javascript (called userscripts) into the webpage currently being viewed. This allows for the customization of the look and feel of a website: improving the user interface or adding additional functionality.</p>
<p>In this example, we are going to use greasemonkey and Dojo to display a dialog widget on an arbitrary website.</p>
<p>To simplify the deployment of a userscript we are going to use the AOL Content Distribution Network to pull in a crossdomain build of the dojo toolkit. This is helpful to us as developers as we don&#8217;t have to build or maintain Dojo ourselves and is useful to the user as they get an optimized download from a distributed CDN.</p>
<p>First thing&#8217;s first: If you haven&#8217;t already, download and install the Greasemonkey extension, and create a new user script.</p>
<p>To access the power of Dojo, we must include the Dojo crossdomain build on the page we are visiting. To do this, we will dynamically create a new script element containing the address of the build and append it to the document head:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> script <span style="color: #339933;">=</span> document.<span style="color: #660066;">createElement</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'script'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
script.<span style="color: #660066;">src</span><span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js&quot;</span><span style="color: #339933;">;</span>
document.<span style="color: #660066;">getElementsByTagName</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'head'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">appendChild</span><span style="color: #009900;">&#40;</span>script<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Next, since we are going to need a Dijit Dialog object, we will need to also include the Tundra Theme CSS file by appending it to the head object:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;"><span style="color: #003366; font-weight: bold;">var</span> link <span style="color: #339933;">=</span> document.<span style="color: #660066;">createElement</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'link'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
link.<span style="color: #660066;">rel</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;stylesheet&quot;</span><span style="color: #339933;">;</span>
link.<span style="color: #660066;">type</span><span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;text/css&quot;</span><span style="color: #339933;">;</span>
link.<span style="color: #660066;">href</span><span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/tundra.css&quot;</span><span style="color: #339933;">;</span>
document.<span style="color: #660066;">getElementsByTagName</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'head'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">appendChild</span><span style="color: #009900;">&#40;</span>link<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Great! Now we have the Dojo javascript file included on the page as well as the Dijit Tundra theme setup and ready to use. Next, we will actually include the Dojo dependencies we need and display our Dialog!</p>
<p>To ensure that the Dojo Javascript file and the Tundra Stylesheet  have been downloaded and parsed we must include the rest of the code in a function that will run when the window fires the &#8220;load&#8221; event To do this, we will add an event listener to the window object with the function as an argument:</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">window.<span style="color: #660066;">addEventListener</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'load'</span><span style="color: #339933;">,</span> <span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span>event<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
<span style="color: #003366; font-weight: bold;">var</span> dojo <span style="color: #339933;">=</span>  unsafeWindow<span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;dojo&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
dojo.<span style="color: #660066;">require</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">&quot;dijit.Dialog&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Also notice that we have created a local variable called Dojo which is a refrence to the unsafeWindow dojo object. Greasemonkey runs all userscripts in a sandbox which provides enhanced security as well as ensures that they do not conflict with any preexisting scripts already on the page. Because, by default, Dojo is instantiated with a visibility relative to the window object it is not visible to our script. By creating a reference to it in a local variable, this allows us to access its functionality.</p>
<p>Also important is the dojo.require statement. This will pull in the dijit.Dialog object which we will be instantiating later on in our script. To ensure that all the dependences have been loaded before we try to create a dialog, we must wait until dojo knows that the external resource has been loaded.</p>

<div class="wp_syntax"><div class="code"><pre class="javascript" style="font-family:monospace;">dojo.<span style="color: #660066;">addOnLoad</span><span style="color: #009900;">&#40;</span><span style="color: #003366; font-weight: bold;">function</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
<span style="color: #003366; font-weight: bold;">var</span> dijit <span style="color: #339933;">=</span> unsafeWindow<span style="color: #009900;">&#91;</span><span style="color: #3366CC;">&quot;dijit&quot;</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">;</span>
dojo.<span style="color: #660066;">addClass</span><span style="color: #009900;">&#40;</span>document.<span style="color: #660066;">getElementsByTagName</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'body'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">&quot;tundra&quot;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003366; font-weight: bold;">var</span> pane <span style="color: #339933;">=</span> document.<span style="color: #660066;">createElement</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'div'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
pane.<span style="color: #660066;">id</span> <span style="color: #339933;">=</span> <span style="color: #3366CC;">&quot;floatingPane&quot;</span><span style="color: #339933;">;</span>
pane.<span style="color: #660066;">innerHTML</span><span style="color: #339933;">=</span><span style="color: #3366CC;">&quot;Dojo Lives... In GreaseMonkey!&quot;</span><span style="color: #339933;">;</span>
document.<span style="color: #660066;">getElementsByTagName</span><span style="color: #009900;">&#40;</span><span style="color: #3366CC;">'body'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#91;</span><span style="color: #CC0000;">0</span><span style="color: #009900;">&#93;</span>.<span style="color: #660066;">appendChild</span><span style="color: #009900;">&#40;</span>pane<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
dialog <span style="color: #339933;">=</span> <span style="color: #003366; font-weight: bold;">new</span> dijit.<span style="color: #660066;">Dialog</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span>
title<span style="color: #339933;">:</span> <span style="color: #3366CC;">&quot;Dojo Integration Test&quot;</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span>pane<span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
dialog.<span style="color: #660066;">show</span><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;">&#41;</span><span style="color: #339933;">;</span>
<span style="color: #009900;">&#125;</span><span style="color: #339933;">,</span> <span style="color: #3366CC;">'false'</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>A lot of stuff happens in the above code snippit:<br />
First we grab a local reference to the global dijit object, next we assign a &#8220;tundra&#8221; class to the body tag, which will allow us to have the correct theme for our Dialog. We create a div node which will eventually become our Dialog, populate it with appropriate attributes and append it to the document&#8217;s body tag. Finally we create a new dialog object with a catchy title and the previously created div node as the contents, and display it on screen. Lastly, we close the window.addEventListener object that we created in the previous step.</p>
<p>Downloaded the complete userscript here:<br />
<del datetime="2010-05-02T02:12:43+00:00"><a href="http://dustint.com/code/dojointegrationtest.user.js">Dojo Integration Userscript</a></del> This script has been updated and is available <a href="http://dustint.com/archives/206">here</a></p>
<p>Special Thanks to Shane Sullivan&#8217;s <a href="http://userscripts.org/scripts/show/9424">Dojo Debug Script</a> which shows how to access the Dojo object from the Greasemonkey sandbox.</p>
]]></content:encoded>
			<wfw:commentRss>http://dustint.com/archives/4/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>
