<?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>Code Iteratively &#187; source</title>
	<atom:link href="http://iterat.ive.ly/index.php/tag/source/feed/" rel="self" type="application/rss+xml" />
	<link>http://iterat.ive.ly</link>
	<description>Hi there. I&#039;m Christopher Gooley. I build technology. I like to share technology musings and products on this blog. I also like to ramble about non-technology topics. Besides coding, this is my main outlet for sharing and creativity.</description>
	<lastBuildDate>Mon, 19 Dec 2011 23:23:19 +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>Four Steps to Turbocharge Rails + AJAX Development with Nginx and&#160;Foreman</title>
		<link>http://iterat.ive.ly/index.php/2011/06/30/four-steps-to-turbocharge-local-ajax-rails-development-with-nginx-and-foreman/</link>
		<comments>http://iterat.ive.ly/index.php/2011/06/30/four-steps-to-turbocharge-local-ajax-rails-development-with-nginx-and-foreman/#comments</comments>
		<pubDate>Fri, 01 Jul 2011 05:54:30 +0000</pubDate>
		<dc:creator>Christopher Gooley</dc:creator>
				<category><![CDATA[programming]]></category>
		<category><![CDATA[ruby on rails]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[tech]]></category>
		<category><![CDATA[earbits]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[rails3]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[ruby-on-rails]]></category>
		<category><![CDATA[source]]></category>

		<guid isPermaLink="false">http://iterat.ive.ly/?p=579</guid>
		<description><![CDATA[If you&#8217;re developing a chatty AJAX app on Rails and using a single mongrel to run it on your workstation, you probably are a bit annoyed with delays waiting for requests to be fulfilled one-at-a-time. So, here I&#8217;ll walk through the steps to run your own &#8220;cluster&#8221; on your OS X workstation using Foreman and [...]]]></description>
			<content:encoded><![CDATA[<p>If you&#8217;re developing a chatty AJAX app on Rails and using a single mongrel to run it on your workstation, you probably are a bit annoyed with delays waiting for requests to be fulfilled one-at-a-time.  So, here I&#8217;ll walk through the steps to run your own &#8220;cluster&#8221; on your OS X workstation using Foreman and Nginx.</p>
<p>In the course of building the frontend application for <a href="http://www.earbits.com/play">Earbits</a>, I&#8217;ve been constantly annoyed with the responsiveness of my local development server.  As a pretty complex AJAX application, there are lots of little (and some bigger) calls to the Rails backend APIs to do <a href="#slow-things">lots of potentially slow things</a>. This means that there are lots of calls that are originating in the browser and being served by one mongrel, so the server ends up handling requests too slowly. Which leads to me being frustrated.  Which leads to me finding a nice solution to the problem.</p>
<p><span id="more-579"></span><br />
<h4>Warning: This May Not Apply To You</h4>
<p>If you have slow running requests that have to run in series, or if you&#8217;re not doing AJAX-y things, this isn&#8217;t going to help you much.  This setup is only useful if your app sends a bunch of parallel requests to the backend. For instance, if after your main page loads, you need to do AJAX requests to a) load the user&#8217;s friends, b) get their comment history, c) calculate some suggestions, and d) check to see if you should show a popup promo to the user, then this might help you out.  But if you need the results of request (a) to get (b) and the results of (b) to get (c), then you&#8217;re out of luck and this will be a waste of your time.</p>
<p>Ok, ready to do this?</p>
<h2>Step 1 &#8211; Install Nginx</h2>
<p>This is much simpler if you have <a href="http://www.macports.org/">macports</a> installed.  So go do that first if you haven&#8217;t already. If the first step below doesn&#8217;t do anything, you don&#8217;t have macports. Once you have macports, it&#8217;s a simple two-command process to install nginx.</p>
<p><code>$ sudo port -d selfupdate<br />
$ sudo port install nginx +ssl +debug</code></p>
<p>Now, while nginx is installing you can open a new terminal window and keep going. The install will take a few minutes.</p>
<h2>Step 2 &#8211; Configure Foreman</h2>
<p><a href="http://blog.daviddollar.org/2011/05/06/introducing-foreman.html">Foreman</a> is a great tool released by David Dollar to make running web processes and workers crazy easy.  It uses a Procfile to define the different things it controls and you should refer to his blog or a Google search to learn about the finer points of Foreman.  We use a pretty simplistic file here as an example.</p>
<p>To get started just run:<br />
<code>$ gem install foreman</code></p>
<p>Then create a file called Procfile in the root of your project using the text editor of your choice.  My Procfile has just one line that define a web process using the standard Rails server:</p>
<pre class="brush:html;">
web:    bundle exec rails server -p $PORT
</pre>
<h2>Step 3 &#8211; Configure Nginx</h2>
<p>Now that nginx is probably finished installing, we can get it configured to act as a local Load Balancer for our Rails server. I&#8217;m going to set it up using port 80 locally. If you are running an HTTP server locally already on port 80, then you should adjust your configuration accordingly.  But if you&#8217;re not using port 80, Rails redirects might cause you some headaches.  So I suggest you stick with the standard port.</p>
<p>First, you&#8217;ll need to find your nginx.conf configuration file.  If you used macports to install it, it&#8217;s probably in <code>/opt/local/etc/nginx/nginx.conf</code> but if you can&#8217;t find it, run <code>nginx -V</code> to see where it&#8217;s hiding.</p>
<p>If you&#8217;re not familiar with nginx at all, there are two main directives that you&#8217;ll be using, <code>server</code> and <code>upstream</code>. The server directive defines the front-end part of nginx (i.e. where it listens for incoming requests).  The upstream directive defines the back-end (i.e. where to send requests so that Rails can handle them).  Both of these snippets should exist within the <code>http</code> section of your config file. <em>I&#8217;ll provide a complete nginx.conf at the end of this section so that you can just replace the default file and then tweak it if necessary.</em></p>
<h4>Upstream section</h4>
<p>This is the configuration that I&#8217;m using, I will explain it in a second:</p>
<pre class="brush:plain;">
upstream foreman4000 {
  server localhost:4000;
  server localhost:4001;
  server localhost:4002;
  server localhost:4003;
  server localhost:4004;
}
</pre>
<p>Here on line 1 we&#8217;re defining the upstream which we will reference later. Note that &#8220;foreman4000&#8243; is just an arbitrary name used to reference it within the config. Then since we plan on running 5 web processes starting at port 4000, we list out each of the ports where our Foreman will be listening for requests.</p>
<h4>Server section</h4>
<p>This will define a server so that nginx will listen to requests on port 80 and direct them to the <code>upstream</code> we created above (line 6).  We also pass the real IP of the request and the hostname along to the server (lines 7-9, in case you need either of these bits of data.</p>
<pre class="brush:plain;">
 server {
    listen       80;
    server_name  localhost;
    access_log  /opt/local/var/log/nginx/foreman4000.access.log  main;
    location / {
      proxy_pass http://foreman4000;
      proxy_set_header Host $host;
      proxy_set_header X-Real-IP $remote_addr;
      proxy_set_header X-Forwarded-For $remote_addr;
    }
 }
</pre>
<h4>Test the config</h4>
<p>After you&#8217;re done making the changes above (or if you <a href="http://ive.ly/cPj" target="_blank">download my nginx.conf example file</a>), you should run <code>$ sudo nginx -t</code> to test the config and make sure it&#8217;s all good. If it fails, double check everything. If it&#8217;s good, you&#8217;re ready to start it up.</p>
<h2>Step 4 &#8211; Start your Engines</h2>
<p>Now all we have to do is start everything up. In your Rails project directory:<br />
<code>$ sudo nginx<br />
$ foreman start -p 4000 -c web=5</code></p>
<p>Note: I use the non-standard port 4000 as the starting point so that other random servers can run on 3000 (rails default) and 5000 (foreman default) without conflicting with this setup.</p>
<p>If it&#8217;s working you should be able to open up http://localhost in your browser and your Rails site should load. In the terminal running Foreman, you should see it handing requests to each of the 5 web processes (web.1 &#8211; web.5) like this:</p>
<p><a href="http://iterat.ive.ly/wp-content/uploads/2011/06/Screen-shot-2011-06-30-at-9.34.04-PM.png"><img src="http://iterat.ive.ly/wp-content/uploads/2011/06/Screen-shot-2011-06-30-at-9.34.04-PM.png" alt="" title="Screen shot 2011-06-30 at 9.34.04 PM" width="336" height="226" class="aligncenter size-full wp-image-597" /></a></p>
<p>Now, enjoy your new, super-responsive AJAX server! I know I do.</p>
<h2 id="slow-things">Notes and Extras</h2>
<p>There are a few reasons my local development environment is slow.  Firstly, I&#8217;m using a <a href="https://mongohq.com/home" target="_blank">hosted mongodb</a> that is shared among a few of our developers so that we can more easily collaborate on work. It makes it possible for me to add a new feature and seed the database with some good example data, then hand it off to our UI guy to style it up with zero configuration on his end other than a <code>git pull</code>. Secondly, we make heavy use of the Facebook Graph APIs which can at times be sluggish over my mere-mortal internet connection.  Getting someone&#8217;s friends might take a full second, posting something to a wall might take a couple seconds.  You can imagine how with just one process running, it would get a bit slow.</p>
<p>The third reason our site is slow in development is the simple fact that it&#8217;s designed to be chatty.  Instead of large monolithic views getting rendered for the user, we do a lot of client-side template rendering using <a href="http://documentcloud.github.com/underscore/" target="_blank">underscore.js</a> based on json data requested by the client app (which leverages <a href="http://documentcloud.github.com/backbone/" target="_blank">backbone.js</a> for much of the interaction logic).  In production, this works great because we can fire up a bunch of web processes and everything scales on out.  But in development, between the slow database access and the numerous calls, things can take seemingly forever to fully load.  But not anymore!</p>
<p>BTW &#8211; if you haven&#8217;t tried <a href="http://www.earbits.com/play" title="free online radio">Earbits</a> out for your online radio needs, you absolutely should. Great way to discover new music, share with your friends and really just have a great time. And you should stop listening to so much Genesis anyway. It&#8217;s time for something fresher.</p>
]]></content:encoded>
			<wfw:commentRss>http://iterat.ive.ly/index.php/2011/06/30/four-steps-to-turbocharge-local-ajax-rails-development-with-nginx-and-foreman/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>A User Friend Relationship Model in&#160;Rails</title>
		<link>http://iterat.ive.ly/index.php/2010/08/31/a-user-friend-relationship-model-in-rails/</link>
		<comments>http://iterat.ive.ly/index.php/2010/08/31/a-user-friend-relationship-model-in-rails/#comments</comments>
		<pubDate>Wed, 01 Sep 2010 03:30:22 +0000</pubDate>
		<dc:creator>Christopher Gooley</dc:creator>
				<category><![CDATA[ruby on rails]]></category>
		<category><![CDATA[learning-ror]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[source]]></category>

		<guid isPermaLink="false">http://iterat.ive.ly/?p=341</guid>
		<description><![CDATA[In building my first Ruby on Rails app, I needed to create a facebook / social-networking style friend relationship between users. The simple requirements were that it the friendship should require approval (e.g. a friend request followed by an accept or ignore) and it should be lightweight (not using two records for a single relationship). [...]]]></description>
			<content:encoded><![CDATA[<p>In building my first Ruby on Rails app, I needed to create a facebook / social-networking style friend relationship between users. The simple requirements were that it the friendship should require approval (e.g. a friend request followed by an accept or ignore) and it should be lightweight (not using two records for a single relationship).</p>
<p>This method and code is inspired by two <a href="http://www.railsforum.com/viewtopic.php?id=16760">blog</a> <a href="http://railscasts.com/episodes/163-self-referential-association">posts</a>, which got me started but neither of which really fulfilled my complete requirement. The first used two records per friendship and the second was a twitter-style friend/follower without the approval process.</p>
<p>So, here I break down my Friendship model which hopefully you will find useful and/or insightful as a complete solution or a starting point for your own implementation.</p>
<p><span id="more-341"></span><br />
First step is to generate a new model that we&#8217;ll call Friendship.  A Friendship will connect two users, tracking who made the request, who the friend is, and whether the request has been approved. So we generate it like so:</p>
<pre class="brush:ruby; gutter:false; toolbar:false">$ script/generate model Friendship user_id:integer friend_id:integer approved:boolean</pre>
<p>This will create the db migration script and the app/models/friendship.rb file which we&#8217;re going to edit to include relationships to the User model. When first created, the Friendship model will be mostly empty so we need to add two lines.</p>
<pre class="brush:ruby">class Friendship &lt; ActiveRecord::Base
  belongs_to :user
  belongs_to :friend, :class_name =&gt; "User", :foreign_key =&gt; "friend_id"
end</pre>
<p>The first line is obviously creating a relationship to the User model, but the second line is a little more complex. It also needs to create a relationship to the User model (there isn&#8217;t a Friend model) but we want to refer to this as the friend. So we have to specify both the :class_name and the :foreign_key so that Rails knows how to hook up this :friend field to actual models.</p>
<p>Now that we have a Friendship, we need to configure the User model to allow for these self-referential relationship through the Friendship model. Before we hit the code, let&#8217;s walk through the concepts here that define the state of friendships and friends.</p>
<p>A friendship is a two-way relationship which is initiated by one user and approved by the other user. So, we have two states of a friendship (not-approved-yet or approved) and we have two directions of friendship relative to the current user: friendships requested <strong>by</strong> the current user (we&#8217;ll call these &#8220;direct&#8221; friendships), and friendships requested <strong>to</strong> the current user (we&#8217;ll call these &#8220;inverse&#8221; friendships).</p>
<p>So using this terminology, we have 4 possible states of Friendship:<br />
1) direct approved<br />
2) indirect approved<br />
3) direct not-approved<br />
4) indirect not-approved</p>
<p>States #1 and #2 are simply what we will be calling &#8220;friends&#8221; &#8211; they are approved relationships, no matter the direction.  Because we don&#8217;t care who requested the friendship once it&#8217;s approved, we will group these together.</p>
<p>State #3 is what we call &#8220;pending friends&#8221; &#8211; other users whom the current user has requested to be friends with and which are awaiting the other user&#8217;s approval. These are out of the control of the current user, and just waiting to be approved or rejected.</p>
<p>State #4 is what we&#8217;ll call &#8220;requested friends&#8221; &#8211; other users who have requested that the current user be their friend, and are awaiting the current user&#8217;s approval. These are the actionable items for the current user to approve. Ignoring a friend request simply deletes the non-approved Friendship, which is the Facebook method (doesn&#8217;t tell the other person they were rejected, but allows them to send another request if they want.)</p>
<p>Now that we have that groundwork, here is the User model:</p>
<pre class="brush:ruby;class-name:'nowrap'">class User &lt; ActiveRecord::Base
  [...]
  has_many :friendships
  has_many :inverse_friendships, :class_name =&gt; "Friendship", :foreign_key =&gt; "friend_id"
  has_many :direct_friends, :through =&gt; :friendships, :conditions =&gt; "approved = true", :source =&gt; :friend
  has_many :inverse_friends, :through =&gt; :inverse_friendships, :conditions =&gt; "approved = true", :source =&gt; :user

  has_many :pending_friends, :through =&gt; :friendships, :conditions =&gt; "approved = false", :foreign_key =&gt; "user_id", :source =&gt; :user
  has_many :requested_friendships, :class_name =&gt; "Friendship", :foreign_key =&gt; "friend_id", :conditions =&gt; "approved = false"

  def friends
    direct_friends | inverse_friends
  end
  [...]
end</pre>
<p>The first two lines are pretty self-explanatory as the first references our &#8220;direct&#8221; Friendships and the second our &#8220;inverse&#8221; Friendships which we&#8217;ll be using as the basis of all of our friend lists.  Lines 5 and 6 simply create our direct and inverse friend lists, only looking at friendships which have been approved. These are states #1 and #2 from our discussion above and are complete, approved bi-directional friends lists.</p>
<p>Line 8 here creates the list of pending friends (state #3 above) by looking for direct friendships which have not been approved.  Then finally in line 9 we handle state #4 which are the &#8220;requested friendship&#8221; waiting for us to approve them, by taking all the non-approved Friendships where the current user is the target of the request (which is why we specify the foreign_key of &#8220;friend_id&#8221;).</p>
<p>And finally, because it would be a hassle to deal with two lists of approved friends, we create a method to simply combine them under the name of &#8220;friends&#8221;, in lines 11-13.</p>
<p>That&#8217;s it! You should be able to create and manage facebook-style friend requests now.</p>
<p>I&#8217;m not going to cover creation of the Friendship controller here in this post, but I may in the future if people would find it helpful.  In short, the controller needs to handle just five actions: index, create, approve, ignore, delete.  In my implementation, all actions except for index are used only for ajax calls through link_to_remote, so they&#8217;re pretty lightweight.</p>
<p><strong>Updated</strong>: the direct_friends line in the User model above was incorrectly using &#8220;:source =&gt; :user&#8221; when it should be &#8220;:source =&gt; :friend&#8221; so that the returned models are the Friends you requested, not yourself the requestor.</p>
]]></content:encoded>
			<wfw:commentRss>http://iterat.ive.ly/index.php/2010/08/31/a-user-friend-relationship-model-in-rails/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Sphinx Search C# .NET Client&#160;API</title>
		<link>http://iterat.ive.ly/index.php/2008/01/05/sphinx-search-c-net-client-api/</link>
		<comments>http://iterat.ive.ly/index.php/2008/01/05/sphinx-search-c-net-client-api/#comments</comments>
		<pubDate>Sun, 06 Jan 2008 06:04:03 +0000</pubDate>
		<dc:creator>Christopher Gooley</dc:creator>
				<category><![CDATA[dot.net]]></category>
		<category><![CDATA[software]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[free]]></category>
		<category><![CDATA[search]]></category>
		<category><![CDATA[source]]></category>
		<category><![CDATA[sphinx]]></category>

		<guid isPermaLink="false">http://iterat.ive.ly/index.php/2008/01/05/sphinx-search-c-net-client-api/</guid>
		<description><![CDATA[Need a C# native client API for Sphinx Search to use in your C# or VB ASP.NET projects? So did I, so I wrote one. Yesterday, I found Sphinx Search and decided to try implementing it in place of the (horrid) MySql Fulltext searching for my Photocore project. After downloading the binaries and indexing a [...]]]></description>
			<content:encoded><![CDATA[<p>Need a C# native client API for <a href="http://sphinxsearch.com">Sphinx Search</a> to use in your C# or VB ASP.NET projects?  So did I, so I wrote one.</p>
<p>Yesterday, I found Sphinx Search and decided to try implementing it in place of the (horrid) MySql Fulltext searching for my <a href="http://photocore.us">Photocore</a> project.  After downloading the binaries and indexing a couple million rows of metadata, I was amazed at how well it performs.  It indexed all my data in less than a minute (compared to the 30 minutes required by MySql Fulltext) and I haven&#8217;t come up with a search that takes longer than 0.005 seconds. I was hooked immediately.  So I needed a .NET API because I didn&#8217;t want to patch my database server to use the Sphinx plugin.</p>
<p>Source download after the jump.<br />
<span id="more-36"></span></p>
<p class="download">Download v0.2 <a href="http://files.thegooley.com/SphinxSearchApiSrc-0.9.8-dev-2.zip">source</a> | <a href="http://files.thegooley.com/SphinxSearchApiBin-0.9.8-dev-2.zip">binaries</a></p>
<p>Download has no warranties, blah, blah, blah.  It&#8217;s based on the Java API and is released under the GNU GPL license.</p>
<p><strong>Important Note</strong><br />
It does not have all the features implemented.  Most notably, it does not have support for Exceprts.  If you modify code to make it work, send it back and I&#8217;ll post the updated version here.  Or, if I get enough requests to implement it, I might.  But my use of Sphinx does not include excerpts, so I didn&#8217;t bother at this point.</p>
<p><strong>Other Notes</strong><br />
This is a pretty quick-and-dirty project, I&#8217;ll proabably clean it up over time and repost new versions, but for now make sure you test it thoroughly before putting it into production on your own sites.  That&#8217;s your responsibility&#8230;</p>
<p>It is tested against the Sphinx searchd server version 0.9.8-dev running on both linux (ubuntu) and windows (vista) with simple queries only.  I didn&#8217;t do anything fancy in my queries.</p>
<p>It does not work against 0.9.7 or earlier because those did not support multiple queries.  It <em>should</em> work against future versions of Sphinx server.  No promises though.</p>
<p><strong>Usage</strong><br />
Super-simple to use after you have a searchd server running with an index.  Three lines will do a search for &#8220;rose bowl gooley&#8221; matching any index (&#8220;*&#8221;) and will get the second page of results (items 41-80) with a max result count of 10,000 documents.</p>
<pre>
// set hostname and port defaults
SphinxClient cli = new SphinxClient(hostname, 3312);

// set the pagination params
// (this is page 2, 40 per page, 10000 max)
cli.SetLimits(40, 40, 10000);

// define the query and index
// ("*" means any index)
cli.AddQuery("rose bowl gooley", "*");

// run the query and get the results
SphinxResult[] results = cli.RunQueries();
</pre>
<p>The SphinxResult object contains an array of SphinxMatches which will provide you with the DocumentId numbers for all matches.  Simple as that.</p>
<p>Happy searching!</p>
]]></content:encoded>
			<wfw:commentRss>http://iterat.ive.ly/index.php/2008/01/05/sphinx-search-c-net-client-api/feed/</wfw:commentRss>
		<slash:comments>27</slash:comments>
		</item>
		<item>
		<title>Build your own modded&#160;System.Web.Extensions.dll</title>
		<link>http://iterat.ive.ly/index.php/2007/01/31/build-your-own-modded-systemwebextensionsdll/</link>
		<comments>http://iterat.ive.ly/index.php/2007/01/31/build-your-own-modded-systemwebextensionsdll/#comments</comments>
		<pubDate>Wed, 31 Jan 2007 09:01:01 +0000</pubDate>
		<dc:creator>Christopher Gooley</dc:creator>
				<category><![CDATA[dot.net]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[source]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://iterat.ive.ly/index.php/2007/01/31/build-your-own-modded-systemwebextensionsdll/</guid>
		<description><![CDATA[Earlier today Microsoft released the source code to the AJAX 1.0 release System.Web.Extensions library. I was in the apparently unique position of needing to modify parts of the code for a special case application, so I downloaded the source right away ready to modify, compile and deploy. I guess I was pretty naive to think [...]]]></description>
			<content:encoded><![CDATA[<p>Earlier today Microsoft released the source code to the <a href="http://ajax.asp.net/about/default.aspx?tabid=47">AJAX</a> 1.0 release System.Web.Extensions library.  I was in the <em>apparently</em> unique position of needing to modify parts of the code for a special case application, so I downloaded the source right away ready to modify, compile and deploy.</p>
<p>I guess I was pretty naive to think that it would be that easy.  The distribution doesn&#8217;t include some pretty important parts.  A .csproj file for one.  The entire Resources class for another.</p>
<p>So I had to work my way through the process of getting a compile-able version of the library ready to replace the official System.Web.Extensions binary in my project.  The server code Reference License prevents me from simply providing the project to you, but here are the high points if you need to do the same.<br />
<span id="more-28"></span></p>
<p class="alert">Be aware:<br />
This is neither easy nor straightforward and I probably forgot a few steps when I was writing this.  You&#8217;re gonna have to be diligent to get it to work, even with this howto.</p>
<p><strong>Getting Started</strong><br />
1) <a href="http://go.microsoft.com/fwlink/?LinkID=82291">Download</a> and install the source<br />
2) Create a new C# project in Visual Studio.  You can call it whatever you want but I would suggest you avoid using the same namespace because the System.Web namespace is strongly named and exists in several assemblies.  I called mine Dave.Web.Ajax<br />
3) Copy all the files and folders from the source installed directory <code>(C:Program Files (x86)Microsoft ASP.NETASP.NET 2.0 AJAX Extensionsv1.0.61025SourceSystem.Web.Extensions on my computer)</code> into your new project directory and include them in the project.<br />
4) Make sure your Default Namespace on the project is something good &#8211; again Dave.Web.Ajax in my case.</p>
<p><strong>Get the Missing Files</strong><br />
1) Start the <a href="http://www.aisto.com/roeder/dotnet/">.Net Reflector</a> (if you&#8217;re a serious .Net developer, you should have downloaded this to your computer long ago, btw)<br />
2) Open the official System.Web.Extensions.dll file<br />
3) Save all the Resources into a new Resources folder in your project. When you save them, drop the &#8220;System.Web.Resources&#8221; part of the filename if it&#8217;s there.<br />
4) You should now have a file called AtlasWeb.resources in your folder<br />
5) Open a VS Command Prompt and in your resources folder run<br />
<code>resgen AtlasWeb.resources AtlasWeb.resx</code>.  This will generate the resx file that you need in visual studio to dynamically generate the class.</p>
<p><strong>Setup your Embedded Resources</strong><br />
1) In VS, include all the files in the Resources in your project (except the *.resources files) if you haven&#8217;t already.<br />
2) Select them all and set the Build Action to Embedded Resource<br />
3) Click on the AtlasWeb.resx file and set the Custom Tool property to &#8220;ResXFileCodeGenerator&#8221;.  This will generate the AtlasWeb.Designer.cs file which gives you a real class with properties for each item in the resource file.<br />
NOTE) You might need to repeat this process (and the resgen.exe process) for the other *.resources files, but I haven&#8217;t done it and havn&#8217;t had any issues yet.</p>
<p><strong>Rename the Namespace and cleanup</strong><br />
If you are going to stick with using the System.Web.* namespace, then you can skip this step.<br />
1) Basically, I handled this in an iterative fashion.  I did a project Find-and-Replace for &#8220;System.Web.&#8221; and replaced with &#8220;Dave.Web.Ajax.&#8221;  Of course this process will break stuff because now objects that are really in the System.Web namespace (and not in the System.Web.Extensions assembly) will dissappear.<br />
2) Get your iteration on: compile, add &#8220;using System.Web.something;&#8221; to a file with the error, compile, repeat.</p>
<p><strong>Fix the Embedded Resource references</strong><br />
At this point, your project should compile and if you reference it in a web project in place of the System.Web.Extensions.dll file (or the GAC reference) the web project should compile too.  But as soon as you load up a page with AJAX controls on it, you will get a runtime error saying the Resource File could not be found.</p>
<p>Update the reference names of your embedded .js files to be fully qualified.  Your new fully qualified resource name will be &#8220;DefaultNamespace.Resources.Filename.js&#8221;  Mine is &#8220;Dave.Web.Ajax.Resources.MicrosoftAjax.js&#8221; for example.</p>
<p>There are references in these files<br />
UIScriptManager.cs:931,935<br />
UIWebResourceUtil.cs:64+<br />
UITimer.cs:147</p>
<p>Update those references to use the fully qualified names.  After that, in WebResourceUtil.cs there is an optimization in the SystemWebExtensionsContainsWebResource(string) function that you have to modify.  It does a switch statement on the length of the input string before comparing to the resource name string. Update each case conditional to be the length of the string in that case statement.  <strong>If you forget this step you will be very confused why it says it can&#8217;t find a resource that you <em>know</em> is there&#8230;</strong></p>
<p>Now, all embedded resources need an assembly reference so that they can be detected using reflection (which is how the AJAX library looks for a valid embedded resource).  I just created a dummy class called Scripts.cs inside the Resources file so I could include the assembly attributes:</p>
<p><code>[assembly: System.Web.UI.WebResource("Dave.Web.Ajax.Resources.MicrosoftAjax.debug.js", "text/javascript")]<br />
[assembly: System.Web.UI.WebResource("Dave.Web.Ajax.Resources.MicrosoftAjax.js", "text/javascript")]<br />
[assembly: System.Web.UI.WebResource("Dave.Web.Ajax.Resources.MicrosoftAjaxTimer.debug.js", "text/javascript")]<br />
[assembly: System.Web.UI.WebResource("Dave.Web.Ajax.Resources.MicrosoftAjaxTimer.js", "text/javascript")]<br />
[assembly: System.Web.UI.WebResource("Dave.Web.Ajax.Resources.MicrosoftAjaxWebForms.debug.js", "text/javascript")]<br />
[assembly: System.Web.UI.WebResource("Dave.Web.Ajax.Resources.MicrosoftAjaxWebForms.js", "text/javascript")]<br />
namespace Dave.Web.Ajax.Resources<br />
{<br />
    class Scripts<br />
    {<br />
    }<br />
}</code></p>
<p>Just make sure you have a WebResource attribute for each of the javascript files in the project.</p>
<p><strong>That&#8217;s it</strong><br />
Assuming you&#8217;ve gotten this far, you must be dedicated or desperate.  Now you can go in and make your mods to any of the AJAX files and you&#8217;re good to go.  Hopefully this was helpful and I wish I could just post the project, but rules is rules.</p>
<p>Its been about 6 hours since I finished my conversion, so its pretty fresh in my head, but I may have forgotten a step somewhere.  I&#8217;ll try to answer questions in the comments but I&#8217;m pretty busy these days and I just blew half my day because the release of AJAX doesn&#8217;t play well inside iframes (which is the whole reason I had to do this mod).</p>
<p>Good luck to you.</p>
]]></content:encoded>
			<wfw:commentRss>http://iterat.ive.ly/index.php/2007/01/31/build-your-own-modded-systemwebextensionsdll/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>GCalendarSync&#160;- Update</title>
		<link>http://iterat.ive.ly/index.php/2006/12/25/gcalendarsync-update/</link>
		<comments>http://iterat.ive.ly/index.php/2006/12/25/gcalendarsync-update/#comments</comments>
		<pubDate>Tue, 26 Dec 2006 06:55:11 +0000</pubDate>
		<dc:creator>Christopher Gooley</dc:creator>
				<category><![CDATA[software]]></category>
		<category><![CDATA[free]]></category>
		<category><![CDATA[gcalsync]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[source]]></category>

		<guid isPermaLink="false">http://iterat.ive.ly/index.php/2006/12/25/gcalendarsync-update/</guid>
		<description><![CDATA[Bugs fixed in this release: All-Day events now are imported onto the correct day (instead of a day early) Non @gmail.com usernames are accepted. If you use &#8220;thegooley&#8221; it will assume &#8220;thegooley@gmail.com&#8221;, but you can also use &#8220;thegooley@hotmail.com&#8221; by providing your entire email address The FAILED error message has been modified to display the actual [...]]]></description>
			<content:encoded><![CDATA[<p>Bugs fixed in this release:</p>
<ul>
<li>All-Day events now are imported onto the correct day (instead of a day early)</li>
<li>Non @gmail.com usernames are accepted.  If you use &#8220;thegooley&#8221; it will assume &#8220;thegooley@gmail.com&#8221;, but you can also use &#8220;thegooley@hotmail.com&#8221; by providing your entire email address</li>
<li>The FAILED error message has been modified to display the actual error text, so please report what it says when you post about a problem</li>
<li>Error log file changed from ApplicationDataGCalSyncGCalSyncErrors.<em>xml</em> to GCalSyncErrors.<em>txt</em> (it was never actually an XML file, but was named that due to an oversight by me)</li>
</ul>
<p>Download after the jump<br />
<span id="more-20"></span></p>
<p class="download">
Download <a href="http://files.thegooley.com/gcal/GCalSyncSetup.CAB">installer cab</a> | <a href="http://files.thegooley.com/gcal/GCalSync_source.zip">source</a>
</p>
<p>Source zip file now includes the <a href="http://code.google.com/apis/gdata/calendar.html">Google API library</a> with my modification described <a href="/index.php/2006/12/15/gcalendarsync-v02-fix/">here</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://iterat.ive.ly/index.php/2006/12/25/gcalendarsync-update/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>GCalendarSync&#160;v0.2 Fix</title>
		<link>http://iterat.ive.ly/index.php/2006/12/15/gcalendarsync-v02-fix/</link>
		<comments>http://iterat.ive.ly/index.php/2006/12/15/gcalendarsync-v02-fix/#comments</comments>
		<pubDate>Fri, 15 Dec 2006 23:48:02 +0000</pubDate>
		<dc:creator>Christopher Gooley</dc:creator>
				<category><![CDATA[software]]></category>
		<category><![CDATA[gcalsync]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[source]]></category>

		<guid isPermaLink="false">http://iterat.ive.ly/index.php/2006/12/15/gcalendarsync-v02-fix/</guid>
		<description><![CDATA[This is going to sound a little presumptuous, but it looks like something Google is doing changed last night and broke their code library for their API. Download installer cab (updated 12/25/06) What happened? In the gauthrequest.cs file, provided by Google, lines 408-9 look like this // check the content type, it must be text [...]]]></description>
			<content:encoded><![CDATA[<p>This is going to sound a little presumptuous, but it looks like something Google is doing changed last night and broke their code library for their API.</p>
<p class="download">
Download <a href="http://files.thegooley.com/gcal/GCalSyncSetup.CAB">installer cab</a> <small>(updated 12/25/06)</small>
</p>
<p><em>What happened?</em><br />
In the gauthrequest.cs file, provided by Google, lines 408-9 look like this</p>
<p><code>// check the content type, it must be text<br />
if (!response.ContentType.Equals(HttpFormPost.ContentType))</code></p>
<p>and this was working until last night. In this case HttpFormPost.ContentType = &#8220;text/plain&#8221;. Problem appears that now, the response.ContentType of the authrequest is being returned as &#8220;text/plain; charset=utf-8&#8243;. So that .Equals conditional no longer does the right thing, thus the authentication breaks.</p>
<p>To fix, I change line 409 to</p>
<p><code>...ContentType.<strong>StartsWith</strong>(HttpFormPost...</code></p>
<p>Now all is well again. Re-install and give it a go. I guess this is going to be standard for interfacing with a &#8220;beta&#8221; Google API. And we&#8217;ll just have to get used to it&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://iterat.ive.ly/index.php/2006/12/15/gcalendarsync-v02-fix/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>GCalendarSync v0.2&#160;Release + Source</title>
		<link>http://iterat.ive.ly/index.php/2006/12/13/gcalendarsync-v02-release-source/</link>
		<comments>http://iterat.ive.ly/index.php/2006/12/13/gcalendarsync-v02-release-source/#comments</comments>
		<pubDate>Thu, 14 Dec 2006 06:33:43 +0000</pubDate>
		<dc:creator>Christopher Gooley</dc:creator>
				<category><![CDATA[software]]></category>
		<category><![CDATA[free]]></category>
		<category><![CDATA[gcalsync]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[source]]></category>

		<guid isPermaLink="false">http://iterat.ive.ly/index.php/2006/12/13/gcalendarsync-v02-release-source/</guid>
		<description><![CDATA[What is GCalendarSync? Go to the project page&#8230; Download installer cab &#124; source If you just want to use it on your mobile, hit that binary cab link from pocket IE and it will install for you. No, I didn&#8217;t sign my assemblies (i don&#8217;t have a real certificate), so be prepared to click through [...]]]></description>
			<content:encoded><![CDATA[<p>What is GCalendarSync? Go to the <a href="/index.php/projects/gcalendarsync">project page</a>&#8230;</p>
<p class="download">Download <a href="http://files.thegooley.com/gcal/GCalSyncSetup.CAB">installer cab</a> | <a href="http://files.thegooley.com/gcal/gcalsync_source.zip">source</a></p>
<p>If you just want to use it on your mobile, hit that binary cab link from pocket IE and it will install for you. No, I didn&#8217;t sign my assemblies (i don&#8217;t have a real certificate), so be prepared to click through some warnings. <em>You&#8217;ll need the .NET 2.0 Compact Framework installed for this app and you can get it from Microsoft <a href="http://www.microsoft.com/downloads/details.aspx?familyid=0C1B0A88-59E2-4EBA-A70E-4CD851C5FCC4&#038;displaylang=en">here</a>.</em></p>
<p>I have been using it for a day now with no issues but all the usual disclaimers apply. Use it at your own risk. I&#8217;m releasing this under the <a href="http://creativecommons.org/licenses/by-sa/2.5/">Creative Commons Attribution-ShareAlike 2.5 License</a>. Share it and Remix it, but let me know what you&#8217;re doing with it so we can enjoy it too.</p>
<div>Oops&#8230; It just came to my attention that there&#8217;s already something out there called GCalSync. Wow it&#8217;s a small world. That app is *shiver* in java, so I need a new name for this app! Suggestions please :-)</div>
<p>More detailed release notes after the jump&#8230;<br />
<span id="more-7"></span><br />
<strong>Important Note</strong><br />
<em>Make sure your device timezone is set correctly.</em><br />
When the app launches, the status bar will show your timezone, if it&#8217;s not correct go fix it before you sync. Google stores in GMT, and the app has to convert to local time for you. If your timezone isn&#8217;t right you&#8217;ll get wierd times on all your appointments, then you&#8217;ll have to delete them all off your device and re-sync. Not fun. Trust me.</p>
<p><strong>Basic Usage</strong></p>
<ol>
<li>After you put in your account information and click Pick Calendars, it will connect and attempt to list your available calendars for you</li>
<li>Check off one or more calendars.</li>
<li>Make sure you go to Options-&gt;Choose Default. This will allow events created on the mobile device to be exported back to the google calendar.</li>
<li>Click Done and then Yes to do the initial import.</li>
<li>Import will take a little while, depending on how many events you have in the calendar. (All events are imported, this will be more flexible in the future)</li>
</ol>
<p><strong>Notes</strong><br />
<em>Persistent Storage</em><br />
All user settings are stored in plaintext in an xml file in the application directory. If you click the &#8220;Save Password&#8221; checkbox, then your password will also be stored in plaintext. I am minimally concerned about this myself, if that bothers you consider not saving your password, though you will have diminished functionality if you do that. There are a few places where the app uses the stored password instead of the text box value (an oversight on my part, this will be changed in the next release).</p>
<p><em>Sync Functions</em><br />
New events created either on the Mobile or Online are synced. Changes made Online to dates and titles will be reflected on the mobile device. Other changes will not be merged. Date/Title changes on the mobile device to events already existing online will be overwritten by the online data. I need to write a better sync/merge function and that will come in the next release.</p>
<p><em>Authentication Issues</em><br />
It appears that on occasion there is a random authentication failure to the API. I am guessing this happens if you try to sync too often, but couldn&#8217;t find any supporting documentation from google. If anyone wants to track that down, I&#8217;d be grateful.</p>
<p><em>Error Reporting</em><br />
Errors which occur during runtime are recorded in a file somewhere near <code>\applicationData\GCalSync\GCalSyncErrors.xml</code> &#8211; this will help developers, and if you want to report bugs to me, include the stack trace from the error when you do.</p>
<p><em>Outlook</em><br />
If you sync using ActiveSync or the Vista Sync Center, events added to your mobile calendar by this application will be merged back into your outlook calendar on the desktop. I don&#8217;t use Outlook, so I don&#8217;t think it&#8217;s a big deal, but it might affect you so you should know about it.</p>
<p><strong>Future Plans</strong><br />
<em>Merge Sync</em><br />
As mentioned above, this feature is in progress.</p>
<p><em>Import Date Range Selection</em><br />
To allow user to specify which events to import. i.e. everything from one week ago through two months in the future. or something.</p>
<p><em>Deletion Handling</em><br />
Right now I have no way to detect and mirror event deletions, if you delete something from your mobile calendar, it will be re-imported at the next scheduled time. If you delete something online, it won&#8217;t be deleted off the mobile but will be orphaned instead. To handle this will require a more persistent state mechanism so that I know when an online event that used to be there doesn&#8217;t show up in the event list anymore.</p>
<p><em>Public Calendar URL Support</em><br />
Right now you can import public calendars by just adding them to your Google Calender collection of calendars. Public calendars are also visible via a direct URL and I want to add a function so you can anonymously connect to calendars (even if you don&#8217;t have a Google Calendar account at all, you should still be able to import events from the Georgia Tech Basketball 06-07 public calendar for instance)</p>
<p><strong>That&#8217;s it for now</strong><br />
If you have suggestions for improvements and features, leave me a comment and I&#8217;ll see what I can do. If you take the source and do something cool with it, drop a note so that everyone can check out your take on it.</p>
]]></content:encoded>
			<wfw:commentRss>http://iterat.ive.ly/index.php/2006/12/13/gcalendarsync-v02-release-source/feed/</wfw:commentRss>
		<slash:comments>38</slash:comments>
		</item>
		<item>
		<title>GCalendarSync v0.1 Screenshots</title>
		<link>http://iterat.ive.ly/index.php/2006/12/13/gcalendarsync-v01-screenshots/</link>
		<comments>http://iterat.ive.ly/index.php/2006/12/13/gcalendarsync-v01-screenshots/#comments</comments>
		<pubDate>Wed, 13 Dec 2006 21:26:52 +0000</pubDate>
		<dc:creator>Christopher Gooley</dc:creator>
				<category><![CDATA[software]]></category>
		<category><![CDATA[free]]></category>
		<category><![CDATA[gcalsync]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[source]]></category>

		<guid isPermaLink="false">http://iterat.ive.ly/index.php/2006/12/13/gcalendarsync-v01-screenshots/</guid>
		<description><![CDATA[GCalendarSync allows you to import events from one or more of your Google Calendars directly to your Windows Mobile PDA or Smartphone over the air using GPRS, without docking or using Outlook or the desktop computer in any way. Release + Source is coming later today. Coming in a couple days is the reverse-sync feature [...]]]></description>
			<content:encoded><![CDATA[<p>GCalendarSync allows you to import events from one or more of your <a href="http://www.google.com/calendar/">Google Calendars</a> directly to your Windows Mobile PDA or <a href="http://www.microsoft.com/windowsmobile/smartphone/default.mspx">Smartphone</a> over the air using GPRS, without docking or using Outlook or the desktop computer in any way. Release + Source is coming later today. Coming in a couple days is the reverse-sync feature so that you can make changes to your google calendar directly on the Smartphone and changes will sync back up to Google.</p>
<p>I&#8217;m not quite ready to release it this second, so here are some screenshots of the process of using the app. Like all Windows Mobile apps, after you close it it can still run in the background, so that allows it to run scheduled imports. Basically every minute it hits a timer interval and checks to see if it should import again (default time between imports is 60 minutes). Right now it is more of an Import than a &#8220;Sync&#8221; tool. But in the next release I will should have two-way syncro going so that you can make changes right on your phone and have those changes sent back up to Google&#8230;</p>
<p>And now, the screenshots (after the jump)<br />
<span id="more-6"></span><br />
Step 1: Enter your username and password<br />
<img alt="Step1" src="http://thegooley.wordpress.com/files/2006/12/gcal1.gif" /></p>
<p>Step 2: Click &#8220;Pick Calendars&#8221; &#8211; at this point, we connect to the Google API to list all the calendars you own and those you subscribe to<br />
<img alt="Step2" src="http://thegooley.wordpress.com/files/2006/12/gcal2.gif" /></p>
<p>Step 3: Check off the calendars you wish to import<br />
<img alt="gcal3.gif" src="http://thegooley.wordpress.com/files/2006/12/gcal3.gif" /></p>
<p>Step 4: Click &#8220;Done&#8221;, then it asks if you want to do an immediate import. Say &#8220;Yes&#8221;<br />
<img alt="gcal4.gif" src="http://thegooley.wordpress.com/files/2006/12/gcal4.gif" /></p>
<p>Step 5: Import in progress<br />
<img alt="gcal5.gif" src="http://thegooley.wordpress.com/files/2006/12/gcal5.gif" /></p>
<p>Step 6: Done, # of events is reported. You can now close the app and it will continue to import/update every 60 minutes in the background.<br />
<img alt="gcal6.gif" src="http://thegooley.wordpress.com/files/2006/12/gcal6.gif" /></p>
<p>Binaries and source coming tonight.</p>
]]></content:encoded>
			<wfw:commentRss>http://iterat.ive.ly/index.php/2006/12/13/gcalendarsync-v01-screenshots/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
	</channel>
</rss>

