<?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>Chicken Scratches &#187; programming</title>
	<atom:link href="http://www.chickenwingsw.com/scratches/category/programming/feed" rel="self" type="application/rss+xml" />
	<link>http://www.chickenwingsw.com</link>
	<description>Developing ideas on developing.</description>
	<lastBuildDate>Thu, 01 Apr 2010 17:24:59 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Dev Ideas Episode 1: Haxe: What Makes It Cool</title>
		<link>http://www.chickenwingsw.com/scratches/programming/devideas-1-haxe</link>
		<comments>http://www.chickenwingsw.com/scratches/programming/devideas-1-haxe#comments</comments>
		<pubDate>Thu, 01 Apr 2010 17:22:19 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[flash]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.chickenwingsw.com/scratches/uncategorized/dev-ideas-episode-1-haxe-what-makes-it-cool</guid>
		<description><![CDATA[ I’m very excited to tell you about Dev Ideas, a new video and slide presentation series where I will be drawing on my decade-plus of industry experience to discuss cutting edge concepts in the field of software development. For the first few episodes, I’ll be addressing some of the lesser known programming languages and [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.devideas.com/shows/haxe"><img style="border-bottom: 0px; border-left: 0px; display: inline; margin-left: 0px; border-top: 0px; margin-right: 0px; border-right: 0px" title="Dev Ideas Episode 1: Haxe: What Makes It Cool" border="0" alt="Dev Ideas Episode 1: Haxe: What Makes It Cool" align="right" src="http://www.chickenwingsw.com/wp-content/uploads/2010/04/haxepresthumbsimple1.jpg" width="224" height="178" /></a> I’m very excited to tell you about <a href="http://www.devideas.com/">Dev Ideas</a>, a new video and slide presentation series where I will be drawing on my decade-plus of industry experience to discuss cutting edge concepts in the field of software development. For the first few episodes, I’ll be addressing some of the lesser known programming languages and techniques. This is a very exciting time to be in software, as new languages and paradigms are emerging and ideas that were previously limited to academics and research projects are now becoming mainstream.</p>  <p>In today’s first episode of Dev Ideas, I delve into the <a href="http://www.haxe.org">Haxe programming language</a>. Haxe’s main claim to fame is as a free open-source alternative to the Flash development environment, but it is really a multiplatform language and toolkit. In addition to Flash .<strong>swf</strong> files, Haxe can target JavaScript, <a href="http://nekovm.org">NekoVM</a>, PHP, or C++ source code, making it possible to use the same language for all phases of a project. Haxe also gives you access to advanced language features like closures, type inference, and algebraic types. Come join me as I give a quick (23 minute) overview of what makes Haxe interesting and worth learning.</p>  <p><a href="http://www.devideas.com/shows/haxe">Watch the presentation now</a></p>]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/programming/devideas-1-haxe/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Open Source Projects</title>
		<link>http://www.chickenwingsw.com/scratches/programming/open-source-projects</link>
		<comments>http://www.chickenwingsw.com/scratches/programming/open-source-projects#comments</comments>
		<pubDate>Wed, 09 Dec 2009 20:18:40 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.chickenwingsw.com/scratches/programming/open-source-projects</guid>
		<description><![CDATA[I've created a new section of the chickenwingsw.com website dedicated to listing some of the open source projects created or maintained by Chicken Wing Software. They run the gamut from a metronome for the desktop musician to a Flash video player to a Python implementation of the PayPal API. I have previously blogged about most [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.chickenwingsw.com/open-source"><img style="float:right;width:200px;border:none" alt="Chicken Wing Software Open Source Projects" src="http://www.chickenwingsw.com/media/all-open-source.jpg" /></a>I've created a new section of the chickenwingsw.com website dedicated to listing some of the open source projects created or maintained by Chicken Wing Software. They run the gamut from a metronome for the desktop musician to a Flash video player to a Python implementation of the PayPal API. I have previously blogged about most of these, but now they're all collected in one place.</p>
<p>Why not <a href="http://www.chickenwingsw.com/open-source">head over there</a> now and check it out?</p>
<p><a href="http://www.chickenwingsw.com/open-source">Chicken Wing Software's Open Source Projects</a></p>
<p style="clear:both"></p>]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/programming/open-source-projects/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Eddie&#8217;s FLV Player</title>
		<link>http://www.chickenwingsw.com/scratches/programming/eddies-flv-player</link>
		<comments>http://www.chickenwingsw.com/scratches/programming/eddies-flv-player#comments</comments>
		<pubDate>Fri, 18 Sep 2009 21:50:04 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[flash]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[flv]]></category>
		<category><![CDATA[swf]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://www.chickenwingsw.com/?p=137</guid>
		<description><![CDATA[I've created a modified and updated version of Neolao's FLV Player. This is a very useful video player for FLV files that you can embed on your web site.
There were some features that I wanted added and some bugs that needed fixing, but there did not seem to be much activity on the original app's [...]]]></description>
			<content:encoded><![CDATA[<p>I've created a modified and updated version of <a href="http://flv-player.net/">Neolao's FLV Player</a>. This is a very useful video player for FLV files that you can embed on your web site.</p>
<p>There were some features that I wanted added and some bugs that needed fixing, but there did not seem to be much activity on the original app's <a href="http://groups.google.com/group/flvplayer">message board</a> (at least the English language version), so I decided to make the changes myself.</p>
<p>I took the "MAXI" version of the player, and added in some more JavaScript support, improved some performance issues, and fixed a couple bugs.</p>
<p>Here is what I changed:</p>
<span id="more-137"></span>
<ul>
<li>Fixed some bugs with the slider control.</li>
<li>Added to the JavaScript interface the following functions: 
<ul>
<li><strong>playVideo</strong></li>
<li><strong>pauseVideo</strong></li>
<li><strong>getVolume</strong> - Gets the volume as a percentage.</li>
<li><strong>setVolume</strong> - Sets the volume as a percentage.</li>
<li><strong>getCurrentTime</strong> - Gets the current time in seconds.</li>
<li><strong>setCurrentTime</strong> - Seeks: takes a new time in seconds</li>
<li><strong>isSeeking</strong> - Returns true or false</li>
<li><strong>isPaused</strong> - Returns true or false</li>
<li><strong>getDuration</strong> - Gets the video length in seconds</li></ul></li>
<li>In the flashVars, you can set a percentage width or height by appending a percent sign to the value. If you set just width percentage and don't set height, the height will be automatically calculated to keep the aspect ratio. Be sure to escape the percent sign as %25. Something like: <em>width=50%25</em></li>
<li>Made seeking more efficient when using <em>phpStream</em>. Now doesn't<br />
initiate a new connection to the server unless necessary.</li></ul>
<p><a href="/static/player_flv_maxi.swf">Download the player</a></p>
<p><a href="/static/flashPlayer.zip">Download the source code</a></p>
<p>Here's the <a href="http://flv-player.net/players/maxi/documentation/">original documentation</a> as well as an <a href="http://flv-player.net/players/maxi/generator/">HTML code generator</a>.</p>
<p>If you have any issues or feature requests, feel free to <a href="/contact">contact me</a>. Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/programming/eddies-flv-player/feed</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>The Future of Online Presentations &#8211; Mixing Video and Slides</title>
		<link>http://www.chickenwingsw.com/scratches/programming/video-and-slides</link>
		<comments>http://www.chickenwingsw.com/scratches/programming/video-and-slides#comments</comments>
		<pubDate>Wed, 02 Sep 2009 22:26:48 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.chickenwingsw.com/?p=127</guid>
		<description><![CDATA[
I am excited to announce Chicken Wing Software's online multimedia presentation system. The pilot presentation, created by Christine Perfetti of  Perfetti Media, is online now. Facilitating a Usability Test is the first in what will be a series of presentations on usability testing techniques gleaned from her ten-plus years of experience in the field.
The [...]]]></description>
			<content:encoded><![CDATA[<p><img alt="uxideas3" align="right" src="http://www.chickenwingsw.com/wp-content/uploads/2009/09/uxideas3.jpg" width="405" height="349" /></p>
<p>I am excited to announce Chicken Wing Software's online multimedia presentation system. The pilot presentation, created by Christine Perfetti of  <a href="http://www.perfettimedia.com">Perfetti Media</a>, is online now. <a href="http://uxideas.com">Facilitating a Usability Test</a> is the first in what will be a series of presentations on usability testing techniques gleaned from her ten-plus years of experience in the field.</p>
<p>The system combines video with PowerPoint slides and text, all tied together with Dynamic HTML and JavaScript for a fully interactive experience. You can click on a slide thumbnail to advance the video to that spot in the presentation, and the displayed slide stays in synch with the video.</p>
<p>Even now, with only the first presentation, the system's potential is inspiring, and we are brimming with ideas for new features to add!</p>
<p>If you would be interested in using this technology for your own presentations, please <a href="http://www.chickenwingsw.com/contact">contact us</a>.</p>
<p>&raquo; <a href="http://uxideas.com">Watch the presentation</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/programming/video-and-slides/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Introducing Eddie&#8217;s Fantasy Draught</title>
		<link>http://www.chickenwingsw.com/scratches/python/introducing-eddies-fantasy-draught</link>
		<comments>http://www.chickenwingsw.com/scratches/python/introducing-eddies-fantasy-draught#comments</comments>
		<pubDate>Fri, 21 Aug 2009 20:45:18 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.chickenwingsw.com/?p=119</guid>
		<description><![CDATA[Get it? It's a fantasy sports draft application, but it's spelled draught. Like draught beer. I like to watch football with a beer or two, and everyone loves a good pun. So there you go.
In my fantasy football and baseball leagues, we wanted to do a live draft, but we have players who live on [...]]]></description>
			<content:encoded><![CDATA[<p>Get it? It's a <a href="http://draft.bettorbest.com">fantasy sports draft application</a>, but it's spelled draught. Like draught beer. I like to watch football with a beer or two, and everyone loves a good pun. So there you go.</p>
<p>In my fantasy football and baseball leagues, we wanted to do a live draft, but we have players who live on both coasts, who work varying schedules, and some of whom have kids. Plus one of our rules is we allow keeping two to four players from year to year, to give some continuity.</p>
<p>Because of those two factors, it's impossible for us to use Yahoo!'s live draft or autodraft. So what does your trusty software engineer do? He codes up his own draft application, of course!</p>
<span id="more-119"></span>
<p>It's worked well for us for the last few years, so I thought I'd clean up the interface a bit and open it up to you, the public. It's free and has no ads or anything. Hopefully if you're in a similar situation as us, you will find it useful. It's still undergoing some updates, so if you find anything that doesn't work or you have any ideas on how to improve it, please <a href="/contact">let me know</a>.</p>
<p>Technical details: This is written in Python using the Django framework running on my own lightweight single-threaded web server I wrote in C++. The front end is dynamic HTML and JavaScript, using the web technologies of AJAX and Comet.</p>
<p>Here is a link: <a href="http://draft.bettorbest.com">Eddie's Fantasy Draught</a></p>
<h1>Features</h1>
<ul>
<li>Revolutionary three-tiered queue, to keep the draft moving. If you know you're not going to be around on your turn, you can set it up to draft some players automatically. The three tiers make sure you get only the players you want.</li>
<li>Draft a large league on your own timeframe.</li>
<li>Chat while the draft is going on.</li>
<li>All stats available.</li>
<li>League manager can enter "keepers" for each team before the draft.</li></ul>
<h1>To Get Started</h1>
<ol>
<li><a href="http://draft.bettorbest.com/accounts/new/">Create an account</a>.</li>
<li>Create a league.</li>
<li>Invite your league members to come draft.</li></ol>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/python/introducing-eddies-fantasy-draught/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>PayPal on Python &#8211; a Python interface to PayPal&#8217;s NVP API</title>
		<link>http://www.chickenwingsw.com/scratches/python/paypal-on-python</link>
		<comments>http://www.chickenwingsw.com/scratches/python/paypal-on-python#comments</comments>
		<pubDate>Mon, 17 Aug 2009 19:39:58 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[paypal]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.chickenwingsw.com/?p=110</guid>
		<description><![CDATA[

As of version 0.6, click here for the new home of PayPal on Python.
Thanks!
]]></description>
			<content:encoded><![CDATA[<img class="pf-left" src="/media/paypal-python.png" alt="PayPal on Python" />

<p>As of version 0.6, <a href="http://www.chickenwingsw.com/paypal-on-python" style="font-size:120%">click here for the new home of PayPal on Python</a>.</p>
<p>Thanks!</p>
<p style="clear:both"></p>]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/python/paypal-on-python/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Help test my new Texas Hold&#8217;em poker site</title>
		<link>http://www.chickenwingsw.com/scratches/python/help-test-my-new-texas-holdem-poker-site</link>
		<comments>http://www.chickenwingsw.com/scratches/python/help-test-my-new-texas-holdem-poker-site#comments</comments>
		<pubDate>Fri, 17 Apr 2009 16:53:25 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.chickenwingsoftware.com/scratches/python/help-test-my-new-texas-holdem-poker-site</guid>
		<description><![CDATA[After many months of hard work, I'm proud to announce that my new poker site, Best Texas Hold'em, is now up and ready for a Beta test. You can play now at www.bettorbest.com.
It's still in its early stages, but gameplay is working. You can log in with a Yahoo, MySpace, or Hotmail account, or your [...]]]></description>
			<content:encoded><![CDATA[<p>After many months of hard work, I'm proud to announce that my new poker site, <a href="http://www.bettorbest.com">Best Texas Hold'em</a>, is now up and ready for a Beta test. You can play now at <u><font color="blue"><a href="http://www.bettorbest.com">www.bettorbest.com</a>.</font></u></p>
<p>It's still in its early stages, but gameplay is working. You can log in with a Yahoo, MySpace, or Hotmail account, or your email address (Facebook support coming soon).</p>
<p>Since it's brand new, there may not be anybody to play against right away, so you may have to check back, or better yet invite a friend, if there is nobody there. Soon enough there will be artificial intelligence support to fill in when necessary.</p>
<p>For the technically interested, the site is programmed in the Python programming language using the Django web framework, and hosted on a Slicehost server. The front end is pure JavaScript with no downloads or plugins required.</p>
<p>Give it a try if you get a chance, and please <a href="http://www.chickenwingsoftware.com/contact">let me know</a> if you find any<br />
problems.<br />
Thanks!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/python/help-test-my-new-texas-holdem-poker-site/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>OpenID is useless</title>
		<link>http://www.chickenwingsw.com/scratches/programming/openid-is-useless</link>
		<comments>http://www.chickenwingsw.com/scratches/programming/openid-is-useless#comments</comments>
		<pubDate>Mon, 16 Mar 2009 14:44:37 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.chickenwingsoftware.com/scratches/programming/openid-is-useless</guid>
		<description><![CDATA[I've been very busy lately working on my next project: an online Texas Hold'em poker site. It's been a lot of fun, and I have most of the actual gameplay functionality working. Now I'm working on the less-fun but just as necessary part: the authentication and login infrastructure.

Since I'm using Django, I can piggyback on [...]]]></description>
			<content:encoded><![CDATA[<p>I've been very busy lately working on my next project: an <a title="Best Texas Hold'em" href="http://www.bettorbest.com">online Texas Hold'em poker site</a>. It's been a lot of fun, and I have most of the actual gameplay functionality working. Now I'm working on the less-fun but just as necessary part: the authentication and login infrastructure.

<p>Since I'm using Django, I can piggyback on its useful authentication module. That's a nice start, but users still need to choose a username and password before they can use the site, not to mention filling out their name, email address, and date of birth. My goal is to lower the barriers to potential users - both psychologically and in terms of effort. Folks are hesitant to sign up for yet another login and password, and to go through a lengthy registration process

<p>Enter <a href="http://www.openid.net">OpenID</a>. OpenID sounds like a very promising standard. Unfortunately, the standard promises more than the implementations deliver. Or rather, the standard doesn't quite promise what it seems to.

<span id="more-89"></span>

<p>The idea is that our buddy "Frank the User," instead of having to create a new account on our site, can log in securely using his Google account, or his Yahoo! account, or any of a number of <em>OpenID Providers</em>. At our site, he enters a URL, gets redirected to the provider's site for authentication, then redirected back to our site, all nicely logged in.

<p>Fine. The problem is we need more than just "logged in." After that whole dance of typing in <em>yahoo.com</em>, signing in to Yahoo!, then coming back, all we at the cient site have available to us is a randomly generated token and assurance from the provider site that the user is indeed logged in -- somewhere. We don't know that his name is Frank, we don't know he was born in 1962, we don't know his email address. In other words, we know nothing more than we did before the dance. On my Texas Hold'em site, as is the case on most sites, I need more. I need a way to identify the user to other users. Something like, oh, I don't know, a NAME? I'm shocked that not even the user's name is available from most OpenID providers.

<p>The OpenID specification includes provisions for exchanging profile information. There is a long list of possible attributes. Unfortunately, none of these things are required, so each Provider can choose to share as much or as little as it wants. Google shares an email address, and nothing more. Yahoo! shares absolutely nothing. AOL has the potential to share a good set of information, but the user needs to individually enable each piece of data through a series of checkboxes.

<p>What would be useful is if there were a defined minimum set of information, or even a way for the Client Site to request a certain set of information. And if that info is not available or the user does not want to share it, the login should fail.

<p>Until that happens, OpenID is going to stay a nice idea with no real use in the real world.]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/programming/openid-is-useless/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Making a Facebook app (with Django) &#8211; part 3: Python &amp; FBML</title>
		<link>http://www.chickenwingsw.com/scratches/python/django-facebook-3</link>
		<comments>http://www.chickenwingsw.com/scratches/python/django-facebook-3#comments</comments>
		<pubDate>Mon, 29 Sep 2008 21:17:57 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.chickenwingsoftware.com/?p=61</guid>
		<description><![CDATA[   
      Welcome to the third part in my series of posts about creating a
      Facebook application. I am using Django as my web development
      framework, and this post will focus on some of the backend
   [...]]]></description>
			<content:encoded><![CDATA[   <p>
      Welcome to the third part in my series of posts about creating a
      Facebook application. I am using Django as my web development
      framework, and this post will focus on some of the backend
      techniques I have worked out to make this work easier. This is
      not a tutorial, but a set of tools that I have developed. This
      is a long post, with a lot of source code; I hope you find at
      least some of it useful.
    </p>
    <p>
      Keep in mind as you read this that the Facebook platform is
      still very new, and likely to change. In fact, if you're a FB
      user, you are probably aware they recently completed a major
      transition to a new profile design. This included many changes
      behind the scenes for developers, some of which are still
      playing out. I recommend keeping up with
      the <a href="http://forum.developers.facebook.com/">Facebook
      Platform Developer Forum</a> and
      the <a href="http://developers.facebook.com/news.php?tab=blog">Facebook
      Developer Blog</a>.
    </p>
    <p>
      Also, I will assume you have already read
      the <a href="http://wiki.developers.facebook.com/index.php/API">API
      Documentation</a> and the documentation
      for <a href="http://wiki.developers.facebook.com/index.php/Python">PyFacebook</a>,
      and that you know how to create a web app
      using <a href="http://www.djangoproject.com">Django</a>. If not,
      you will want to start there.
    </p>
<span id="more-61"></span>
    <p>
      PyFacebook is very useful and includes some documentation on
      getting up and running with Django. You do still need an
      understanding of how Django works and how URLs are mapped.
    </p>
    <h4>
      My goal
    </h4>
    <p>
      My goal with these code snippets and techniques is to make
      developing a Facebook app as close as possible to developing a
      regular web app. The application I am using to develop and test
      these features is <a href="http://limericks.four32one.com">The
      Limerick Book</a>. Compare that page
      to <a href="http://apps.facebook.com/limericks">The Limerick
      Book Facebook App</a>. In fact, they are the same application,
      sharing the same code. I also have developed
      a <a href="http://apps.facebook.com/playscopa">multiplayer card
      game</a> based on the traditional Italian
      game <a href="http://apps.facebook.com/playscopa">Scopa</a>. This
      is a Facebook-only application, but I wanted to be able to test
      it outside of Facebook.
    </p>
    <p>
      Ideally, we would be able to write code and templates that can
      work equally well both inside Facebook and outside.  This is
      important even if you want users to only see your application
      within Facebook, because it makes testing infinitely easier. You
      want to be able to test on your local machine before publishing
      content, and you want to be able to test things out free from
      the limitations and frequent bugginess of the Facebook platform.
    </p>
    <h4>
      First steps
    </h4>
    <p>
      Here are some simple helper functions to make life as a Facebook
      Python developer easier.
    </p>
    <p>
      I am making a conscious decision here not to package all these
      helper functions into a downloadable library. My point here
      to <i>explain</i> code, rather than just hand it out. Many of
      these things are specific to my needs, and may not fit exactly
      what you want, so some tweaking may be required. I have most of
      these functions in a file called <i>fbUtil.py</i> that I import
      from most of my Django view code (except for the template tags,
      which need to be in a specific place, per Django). Feel free to
      do the same, or to copy and paste the code for your own use, but
      I recommend reading through the code, as your needs may not be
      the same as mine.
    <p>
      <b>inFb</b> is a simple function that takes a Request object and
      returns a boolean telling whether the request is taking place
      within the context of a Facebook canvas page.
    </p>
    <pre>
<span class="keyword">def</span> <span class="function-name">inFb</span>(request):
    <span class="keyword">return</span> (request.facebook <span class="keyword">and</span>
            (request.facebook.check_session(request) <span class="keyword">or</span>
             request.facebook.in_canvas))
</pre>
    <p>
      Once we have this, we can create some more useful functions.
    </p>
    <pre class="codeSnippet">
facebookUrl = settings.FACEBOOK_URL
<span class="keyword">def</span> <span class="function-name">fbReverse</span>(view, args=<span class="py-pseudo-keyword">None</span>, kwargs=<span class="py-pseudo-keyword">None</span>):
    '''<span class="string">
    Much like django.core.urlresolvers.reverse, except works
    in Facebook. Returns an absolute URL to a Facebook canvas
    page.
    </span>'''
    ret = reverse(view, args=args, kwargs=kwargs)
    <span class="keyword">return</span> facebookUrl + ret[1:] <span class="comment"># Remove leading slash
</span>
<span class="keyword">def</span> <span class="function-name">makeReverse</span>(request, view, args = <span class="py-pseudo-keyword">None</span>):
    '''<span class="string">
    Returns the URL of a the specified view, either in or out of Facebook.
    </span>'''
    <span class="keyword">if</span> inFb(request):
        <span class="keyword">return</span> fbReverse(view, args)
    <span class="keyword">return</span> reverse(view, args=args)

<span class="keyword">def</span> <span class="function-name">makeRedirect</span>(request, view, args = <span class="py-pseudo-keyword">None</span>, extra = ''):
    '''<span class="string">
    Returns a Response object for a HTTP redirect, either in or out of
    Facebook.
    </span>'''
    <span class="keyword">if</span> inFb(request):
        <span class="keyword">return</span> request.facebook.redirect(fbReverse(view, args) + extra)
    <span class="keyword">return</span> HttpResponseRedirect(reverse(view, args=args) + extra)
</pre>
    <p>
      These are designed to simplify URL calculations. See the
      comments in the code for explanations of what they do.
    </p>
    <pre class="codeSnippet">
<span class="keyword">def</span> <span class="function-name">makeResponse</span>(request, template, context, common=<span class="py-pseudo-keyword">False</span>):
    context['<span class="string">pageName</span>'] = template
    <span class="keyword">if</span> (<span class="keyword">not</span> common) <span class="keyword">and</span> inFb(request):
        tmpl = '<span class="string">fb/%s.fbml</span>' % template
    <span class="keyword">else:</span>
        tmpl = template + '<span class="string">.tmpl</span>'
    <span class="keyword">return</span> render_to_response(tmpl,
                              context,
                              context_instance=RequestContext(request))
</pre>      
    <p>
      This one is a little different, and may need updating depending
      on how your code is organized. I keep my templates in the
      directory 'mySite/myApp/templates' and give them names like
      'myTemplate.tmpl'. I put my Facebook-specific templates in the
      subdirectory called 'fb' and give them names like
      'myTemplate.fbml'. This function allows me to create two
      templates for a view: one for inside Facebook and one for
      outside. The function will detect which one to use and render it
      into a Response object. <b>request</b> is the Request object
      that is passed to the view function. <b>template</b> is a string
      holding the base-name of the template file, for example
      'myTemplate'. <b>context</b> is a dictionary with the template
      context variables. And if <b>common</b> is <b>True</b>, the
      function will use the main non-Facebook version of the template
      no matter what (because ideally we would be able to share even
      these as much as possible).
    </p>
    <p>
      One extra little bit that the function does is add an extra
      template variable called <b>pageName</b> with the base-name of
      the template. I find this useful for code re-use within
      templates, though it's not actually a Facebook-related feature.
    </p>
    <h4>
      Authentication
    </h4>
    <p>
      The next thing I wanted to do was to tie in Facebook's user
      information with Django's authentication mechanism. Depending on
      your application, you may or may not want to do this. If you
      want to remember information about user-contributed content, it
      is useful. The way I did it was to create a <i>UserProfile</i>
      model, tied in to the User model by a ForeignKey one-to-one
      relationship, and with a <b>facebookId</b> field (among other,
      app-specific fields). Then I created a Django authentication
      backend to allow authenticating by facebook ID. Here is my code
      for the authentication back end. If a user does not exist with
      the given facebook ID, a new one is created. (That, of course,
      may not be what you want, so you may have to modify that code.)
    </p>
    <p>
      This code assumes that Python's logging facilities have been set
      up, for error reporting.
    </p>
    <pre class="codeSnippet">
<span class="keyword">class</span> <span class="type">FacebookBackend</span>:
    '''<span class="string">
    Authenticate against Facebook.
    </span>'''

    <span class="keyword">def</span> <span class="function-name">authenticate</span>(<span class="py-pseudo-keyword">self</span>, facebookId=<span class="py-pseudo-keyword">None</span>):
        <span class="keyword">if</span> <span class="keyword">not</span> facebookId: <span class="keyword">return</span> <span class="py-pseudo-keyword">None</span>
        <span class="keyword">try:</span>
            profile = UserProfile.objects.get(facebookId=facebookId)
            UpdateFbUserDetails(profile.user, facebookId)
            <span class="keyword">return</span> profile.user
        <span class="keyword">except</span> UserProfile.DoesNotExist:
            <span class="comment"># No user. Create one.
</span>            <span class="keyword">pass</span>
        username = '<span class="string">fb_%s</span>' % facebookId
        <span class="keyword">try:</span>
            user = User.objects.get(username=username)
            <span class="comment"># This shouldn't really happen. Log an error.
</span>            logging.error('<span class="string">Strange: user %s already exists.</span>' % username)
        <span class="keyword">except</span> User.DoesNotExist:
            user = User.objects.create_user('<span class="string">fb_%s</span>' % facebookId, '')
        <span class="keyword">if</span> <span class="keyword">not</span> UpdateFbUserDetails(user, facebookId):
            <span class="keyword">return</span> <span class="py-pseudo-keyword">None</span>
        user.save()
        profile, created = UserProfile.objects.get_or_create(user=user)
        profile.facebookId = facebookId
        profile.save()
        <span class="keyword">return</span> user

    <span class="keyword">def</span> <span class="function-name">get_user</span>(<span class="py-pseudo-keyword">self</span>, user_id):
        <span class="keyword">try:</span>
            <span class="keyword">return</span> User.objects.get(pk=user_id)
        <span class="keyword">except</span> User.DoesNotExist:
            <span class="keyword">return</span> <span class="py-pseudo-keyword">None</span>

<span class="keyword">def</span> <span class="function-name">UpdateFbUserDetails</span>(user, fbId):
    """
<span class="string">    Fill in a user's first and last name, from Facebook.
    "</span>""
    <span class="keyword">if</span> (<span class="keyword">not</span> user.first_name) <span class="keyword">or</span> (<span class="keyword">not</span> user.last_name) :
        <span class="keyword">try:</span>
            fb = get_facebook_client()
            userDetails = fb.users.getInfo(fbId, ['<span class="string">last_name</span>', '<span class="string">first_name</span>'])
            user.first_name = userDetails[0]['<span class="string">first_name</span>'][:30]
            user.last_name = userDetails[0]['<span class="string">last_name</span>'][:30]
            user.save()
            <span class="keyword">return</span> <span class="py-pseudo-keyword">True</span>
        <span class="keyword">except</span> Exception, ex:
            logging.error('<span class="string">Error updating user: %s</span>' % ex)
            <span class="keyword">return</span> <span class="py-pseudo-keyword">False</span>
    <span class="keyword">return</span> <span class="py-pseudo-keyword">True</span>
</pre>
    <p>
      Now here is a function decorator you can use on your view
      functions. It will perform Facebook authentication if
      possible. It can also be used to require a login - either via
      Facebook or through a login page. With a parameter
      of <b>True</b>, it is equivalent to Django's
      built-in <b>login_required</b> decorator or to
      PyFacebook's <b>facebook.require_login</b> decorator, depending
      on whether the view is accessed inside or outside of Facebook.
    </p>
    <pre class="codeSnippet">
<span class="keyword">def</span> <span class="function-name">facebookView</span>(requireLogin=<span class="py-pseudo-keyword">False</span>):
    <span class="keyword">def</span> <span class="function-name">decorator</span>(func):
        <span class="keyword">def</span> <span class="function-name">wrapper</span>(request, *listArgs, **kwArgs):
            facebookLogin(request)
            fb = request.facebook
            <span class="keyword">if</span> requireLogin <span class="keyword">and</span> (<span class="keyword">not</span> request.user.is_authenticated()):
                <span class="keyword">if</span> inFb(request):
                    <span class="keyword">return</span> fb.redirect(fb.get_login_url(next=request.path))
                <span class="keyword">else:</span>
                    <span class="keyword">return</span> HttpResponseRedirect(settings.LOGIN_URL + '<span class="string">?next=%s</span>' % request.path)
            <span class="keyword">else:</span>
                <span class="keyword">return</span> func(request, *listArgs, **kwArgs)
        wrapper.__name__ = func.__name__
        wrapper.__doc__ = func.__doc__
        wrapper.__dict__ = func.__dict__
        wrapper.__module__ = func.__module__
        <span class="keyword">return</span> wrapper
    <span class="keyword">return</span> decorator

<span class="keyword">def</span> <span class="function-name">facebookLogin</span>(request):
    '''<span class="string">
    Attempt to login the user based on their Facebook credentials.
    Does nothing outside of Facebook.
    </span>'''
    facebook = get_facebook_client()
    <span class="keyword">if</span> (<span class="keyword">not</span> request.user.is_authenticated()) <span class="keyword">or</span> UserProfile.Get(request.user).facebookId != facebook.uid:
        <span class="keyword">if</span> request.facebook <span class="keyword">and</span> request.facebook.check_session(request):
            user = authenticate(facebookId=facebook.uid)
            login(request, user)
</pre>
    <p>
      And here is a very simple example of how to use it:
    </p>
    <pre class="codeSnippet">
@facebookView(<span class="py-pseudo-keyword">True</span>) <span class="comment"># Require login, in and out of Facebook
</span><span class="keyword">def</span> <span class="function-name">myView</span>(request):
    <span class="comment"># Put important view processing here.
</span>    <span class="keyword">return</span> makeResponse(request, '<span class="string">myTemplate</span>', {'<span class="string">templateVar</span>':'<span class="string">important data</span>'})
</pre>
    <h4>
      Templates
    </h4>
    <p>
      We are getting closer to the holy grail of being able to write
      one set of code that can run both in and out of Facebook. It
      would also be useful to be able to share templates, so I have
      worked out several mechanisms to facilitate this.
    </p>
    <h5>
      The Context Processor
    </h5>
    <p>
      Django has the useful concept of a "Context Processor," which
      allows pre-processing of a RequestContext object before the
      rendering of any template. I take advantage of this quite a
      bit. I already discussed the <b>cacheBreaker</b> variable in
      my <a href="http://www.chickenwingsoftware.com/scratches/python/django-facebook-2">post
      about Facebook and JavaScript</a>. Here are a couple more
      variables I've found useful:
    </p>
    <ul>
      <li>
	<b>fb</b> - The <i>facebook</i> object, for accessing the
	Facebook API, or <b>None</b> outside of Facebook.
      </li>
      <li>
	<b>profile</b> - The <i>UserProfile</i> object, if the user is
	logged in, or <b>None</b> otherwise.
      </li>
      <li>
	<b>baseTemplate</b> - The template to <i>extend</i> - either
	"base.tmpl" outside of Facebook or "fb/base.fbml" inside of
	Facebook.
      </li>
      <li>
	<b>loginRequired</b> - A useful string for including in
	hyperlinks. Within Facebook, it contains
	'loginrequired=true'. Outside of Facebook, it contains
	something like 'onclick="return checkLogin()"', which is some
	custom JavaScript to require the user to login before
	following the link. Of course, if the link already has an
	"onclick" event, this cannot be used.
      </li>
    </ul>
    <p>
      I'll leave it to you to write your custom template processor, as
      they can be very site-specific, but the above should get you
      started. Here
      is <a href="http://docs.djangoproject.com/en/dev/ref/templates/api/?from=olddocs#id1">Django's
      context processor documentation</a>.
    </p>
    <h5>
      Template tags
    </h5>
    <p>
      To allow more sharing, I've defined a couple of useful template
      tags. These must be defined in a file in a "templatetags"
      directory under your application directory, as described in
      the <a href="http://docs.djangoproject.com/en/dev//howto/custom-template-tags/#howto-custom-template-tags">Django
      custom tag and filter documentation</a>.
    </p>
    <p>
      The first is <b>fbUrl</b>. It is the equivalent of the built-in
      Django <b>url</b> tag, except that when used inside Facebook it
      produces an absolute link to the requested page within the
      context of the Facebook canvas. In fact, the code is copied
      directly from the Django implementation
      of <b>url</b>. <b>fbUrl</b> relies on the <b>fb</b> context
      variable, and the <b>fbReverse</b> function, as described above.
    </p>
    <pre class="codeSnippet">
<span class="keyword">from</span> django.template <span class="keyword">import</span> Node
<span class="keyword">class</span> <span class="type">FBURLNode</span>(Node):
    <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, view_name, args, kwargs):
        <span class="py-pseudo-keyword">self</span>.view_name = view_name
        <span class="py-pseudo-keyword">self</span>.args = args
        <span class="py-pseudo-keyword">self</span>.kwargs = kwargs

    <span class="keyword">def</span> <span class="function-name">render</span>(<span class="py-pseudo-keyword">self</span>, context):
        fb = template.Variable('<span class="string">fb</span>').resolve(context)
        <span class="keyword">if</span> fb:
            reverseFunc = fbReverse
        <span class="keyword">else:</span>
            reverseFunc = django.core.urlresolvers.reverse

        <span class="keyword">from</span> django.core.urlresolvers <span class="keyword">import</span> reverse, NoReverseMatch
        args = [arg.resolve(context) <span class="keyword">for</span> arg <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.args]
        kwargs = <span class="py-builtins">dict</span>([(smart_str(k,'<span class="string">ascii</span>'), v.resolve(context))
                       <span class="keyword">for</span> k, v <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.kwargs.items()])
        <span class="keyword">try:</span>
            <span class="keyword">return</span> reverseFunc(<span class="py-pseudo-keyword">self</span>.view_name, args=args, kwargs=kwargs)
        <span class="keyword">except</span> NoReverseMatch:
            <span class="keyword">try:</span>
                project_name = settings.SETTINGS_MODULE.split('<span class="string">.</span>')[0]
                <span class="keyword">return</span> reverseFunc(project_name + '<span class="string">.</span>' + <span class="py-pseudo-keyword">self</span>.view_name,
                                   args=args, kwargs=kwargs)
            <span class="keyword">except</span> NoReverseMatch:
                <span class="keyword">return</span> ''

<span class="keyword">def</span> <span class="function-name">fbUrl</span>(parser, token):
    """<span class="string">
    Just like Django's url tag, except also works inside Facebook.
    "</span>""
    bits = token.contents.split('<span class="string"> </span>', 2)
    <span class="keyword">if</span> <span class="py-builtins">len</span>(bits) &lt; 2:
        <span class="keyword">raise</span> TemplateSyntaxError("<span class="string">'%s' takes at least one argument</span>"
                                  "<span class="string"> (path to a view)</span>" % bits[0])
    args = []
    kwargs = {}
    <span class="keyword">if</span> <span class="py-builtins">len</span>(bits) &gt; 2:
        <span class="keyword">for</span> arg <span class="keyword">in</span> bits[2].split('<span class="string">,</span>'):
            <span class="keyword">if</span> '<span class="string">=</span>' <span class="keyword">in</span> arg:
                k, v = arg.split('<span class="string">=</span>', 1)
                k = k.strip()
                kwargs[k] = parser.compile_filter(v)
            <span class="keyword">else:</span>
                args.append(parser.compile_filter(arg))
    <span class="keyword">return</span> FBURLNode(bits[1], args, kwargs)
fbUrl = register.tag(fbUrl)
                        
</pre>
    <p>
      Next is <b>fbName</b>. This is to provide the same functionality
      as Facebook's <i>fb:name</i> FBML tag, except also useable
      outside of Facebook.
    </p>
    <p>
      The basic use of it looks like <i>{% fbName user %}</i>, where
      "user" is a template variable containing the user whose name to
      display. Then you can add options like <i>linked=false</i>,
      or <i>useyou=false</i>, as described in the Facebook
      documentation.
    </p>
    <p>
      Some differences from the FBML version are:
    </p>
    <ul>
      <li>
	<i>shownetwork</i>, <i>ifcantsee</i>, and <i>subjectid</i> are
	ignored outside of Facebook.
      </li>
      <li>
	<i>linked</i> behaves slightly differently. Outside of
	Facebook, or if its value is set to <i>internal</i>, the
	user's name will be linked to an app-specific profile
	page. The view for this page is specified in the
	variable <b>userProfileView</b>. The view is expected to take
	one parameter: the user ID.
      </li>
    </ul>
    <p>
      Here is the code:
    </p>
    <pre class="codeSnippet">
userProfileView = '<span class="string">userProfile</span>'
<span class="keyword">class</span> <span class="type">FbNameNode</span>(Node):
    <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, user, args, kwArgs):
        <span class="py-pseudo-keyword">self</span>.user = template.Variable(user)
        <span class="py-pseudo-keyword">self</span>.args = args
        <span class="py-pseudo-keyword">self</span>.kwArgs = kwArgs

    <span class="keyword">def</span> <span class="function-name">getBoolArg</span>(<span class="py-pseudo-keyword">self</span>, name, default=<span class="py-pseudo-keyword">False</span>):
        val = <span class="py-pseudo-keyword">self</span>.kwArgs.get(name, default)
        <span class="keyword">if</span> <span class="py-builtins">type</span>(val) <span class="keyword">is</span> <span class="keyword">not</span> bool:
            <span class="keyword">return</span> (val.lower() == '<span class="string">true</span>')
        <span class="keyword">return</span> val

    <span class="keyword">def</span> <span class="function-name">render</span>(<span class="py-pseudo-keyword">self</span>, context):
        user = <span class="py-pseudo-keyword">self</span>.user.resolve(context)
        fb = template.Variable('<span class="string">fb</span>').resolve(context)
        loggedInUser = template.Variable('<span class="string">user</span>').resolve(context)
        request = template.Variable('<span class="string">request</span>').resolve(context)
        <span class="keyword">if</span> fb:
            fbUserId = UserFbId(user)
            <span class="keyword">if</span> fbUserId:
                <span class="comment"># In Facebook
</span>                internalLink = <span class="py-pseudo-keyword">False</span>
                ret = '<span class="string">&lt;fb:name uid="%s" </span>' % fbUserId
                <span class="keyword">for</span> item, val <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.kwArgs.items():
                    <span class="keyword">if</span> item == '<span class="string">linked</span>' <span class="keyword">and</span> val == '<span class="string">internal</span>':
                        internalLink = <span class="py-pseudo-keyword">True</span>
                        ret += '<span class="string">linked="false" </span>'
                    <span class="keyword">else:</span>
                        <span class="keyword">if</span> <span class="py-builtins">type</span>(val) <span class="keyword">is</span> bool:
                            <span class="keyword">if</span> val:
                                val = '<span class="string">true</span>'
                            <span class="keyword">else:</span>
                                val = '<span class="string">false</span>'
                        ret += '<span class="string">%s="%s" </span>' % (item, val)
                ret += '<span class="string">/&gt;</span>'
                <span class="keyword">if</span> internalLink:
                    ret = '<span class="string">&lt;a href="%s"&gt;%s&lt;/a&gt;</span>' % (fbReverse(userProfileView, [user.id]), ret)
                <span class="keyword">return</span> mark_safe(ret)
        <span class="comment"># Not in Facebook
</span>        <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">useyou</span>', <span class="py-pseudo-keyword">True</span>) <span class="keyword">and</span> user == loggedInUser:
            <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">capitalize</span>'):
                ret = '<span class="string">You</span>'
            <span class="keyword">else:</span>
                ret = '<span class="string">you</span>'
            <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">possessive</span>'):
                ret += '<span class="string">r</span>'
            <span class="keyword">elif</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">reflexive</span>'):
                ret += '<span class="string">rself</span>'
            <span class="comment"># ES: How to handle subjectid?
</span>        <span class="keyword">else:</span>
            ret = UserDisplayName(user)
            <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">firstnameonly</span>'):
                ret = user.first_name <span class="keyword">or</span> user.username
            <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">lastnameonly</span>'):
                ret = user.last_name <span class="keyword">or</span> user.username
            <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">possessive</span>'):
                ret += "<span class="string">'s</span>"
        <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">linked</span>', <span class="py-pseudo-keyword">True</span>) <span class="keyword">or</span> <span class="py-pseudo-keyword">self</span>.kwArgs.get('<span class="string">linked</span>', <span class="py-pseudo-keyword">None</span>) == '<span class="string">internal</span>':
            ret = '<span class="string">&lt;a href="%s"&gt;%s&lt;/a&gt;</span>' % \
                (makeReverse(request, userProfileView, args=[user.id]),
                 ret)
        <span class="keyword">return</span> mark_safe(ret)
            

@register.tag
<span class="keyword">def</span> <span class="function-name">fbName</span>(parser, token):
    '''<span class="string">
    Returns the name for the given user, based on the parameters.

    Acts much like the fb:name FBML tag, except can work in or out of
    Facebook.
    </span>'''
    <span class="keyword">try:</span>
        bits = token.split_contents()[1:]
    <span class="keyword">except</span> ValueError:
        <span class="keyword">raise</span> template.TemplateSyntaxError, "<span class="string">%r tag requires at least 1 argument: the user (%s)</span>" %\
            (token.contents.split()[0], token.split_contents())
    args = []
    kwArgs = {}
    <span class="keyword">for</span> b <span class="keyword">in</span> bits:
        <span class="keyword">if</span> '<span class="string">=</span>' <span class="keyword">in</span> b:
            name,val = b.split('<span class="string">=</span>', 1)
            kwArgs[name.strip()] = val.strip()
        <span class="keyword">else:</span>
            args.append(b.strip())
    <span class="keyword">if</span> <span class="py-builtins">len</span>(args) &lt; 1:
        <span class="keyword">raise</span> template.TemplateSyntaxError, "<span class="string">%r tag requires at least one argument: the user</span>" %\
            token.contents.split()[0]

    <span class="keyword">return</span> FbNameNode(args[0], args[1:], kwArgs)

<span class="keyword">def</span> <span class="function-name">UserFbId</span>(user):
    <span class="keyword">try:</span>
        <span class="keyword">return</span> UserProfile.objects.get(user=user).facebookId
    <span class="keyword">except</span> UserProfile.DoesNotExist:
        <span class="keyword">return</span> <span class="py-pseudo-keyword">None</span>
</pre>
    <h4>
      Moving on
    </h4>
    <p>
      I think that should be enough to work with for now. Next time,
      I'll discuss publishing stories to news feeds and all that
      social good stuff. Until then, please feel free to post any
      comments, questions, or improvements below.
    </p>
]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/python/django-facebook-3/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Making a Facebook app (with Django) &#8211; part 2: JavaScript and FBJS</title>
		<link>http://www.chickenwingsw.com/scratches/python/django-facebook-2</link>
		<comments>http://www.chickenwingsw.com/scratches/python/django-facebook-2#comments</comments>
		<pubDate>Sun, 17 Aug 2008 14:45:10 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.chickenwingsoftware.com/?p=54</guid>
		<description><![CDATA[    
      Welcome to the second part in my series of posts about creating
      a Facebook application. I am using Django as my web development
      framework, but this post doesn't have much to do with Django,
  [...]]]></description>
			<content:encoded><![CDATA[    <p>
      Welcome to the second part in my series of posts about creating
      a Facebook application. I am using Django as my web development
      framework, but this post doesn't have much to do with Django,
      since it deals with the front end. In particular, it talks about
      how to write JavaScript that can work both in and out of
      Facebook.
    </p>
    <p>
      As I mentioned last time, Facebook lets developers use a subset
      of JavaScript, which they call FBJS. The FBJS is transformed on
      the fly into JavaScript as the page is loaded. All variables and
      functions you define or reference are prepended with a string
      like "a123456789_", including calls
      to <span class="code">document.getElementById</span>
      and <span class="code">setTimer</span> and the like. This is
      done in order to restrict what you can do with DOM elements, to
      avoid cross-site-scripting attacks and unwanted user-hostile
      behavior. <a href="http://wiki.developers.facebook.com/index.php/FBJS">FBJS is fairly well documented</a>, so if you plan to do
      some Facebook JavaScript development, you should start there.
    </p>
    <p>
      The biggest restriction that FBJS imposes is that you can no
      longer access the attributes of DOM elements directly, but must
      go through an abstraction API consisting of a series of setters
      and getters. For example, instead of saying something like
      <span class="code">imageEl.src = myImageUrl</span>, you instead need
      to call imageEl.setSrc(myImageUrl).
    </p>
<span id="more-54"></span>
    <p>
      This is not too big of an adjustment, if you are accustomed to
      writing raw JavaScript. It actually has some advantages, because
      FBJS abstracts away some of browser-dependent aspects into a
      standard API.
    </p>
    <p>
      The challenge, however, becomes apparent when you try debugging
      your JavaScript. With Internet Explorer and its horrendously
      useless error messages and debugging facilities, it's pretty
      much hopeless, since the line numbers don't correspond to line
      numbers in your source code. However, even with Firefox and the
      wonderful Firebug debugger, all the name mangling and rewriting
      makes tracking down problems more difficult. Ideally you would
      want to debug as much as possible <em>outside</em> of Facebook,
      before then testing on the real site.
    </p>
    <p>
      To make this easier, I developed some useful code to simulate as
      much as possible the FBJS environment when running locally or
      outside of Facebook. The idea was to re-create all the accessor
      functions on all DOM objects. You can <a href="http://www.chickenwingsoftware.com/static/fbHelper.js">download the file
      here</a>. You're free to use it, but please don't link directly to
      the file on my site - copy it to your site and use it there. And
      read the description below first.
    </p>
    <p>
      I considered several different approaches before settling on the
      final version. I considered trade-offs of performance and
      possible side-effects. Rejected approach number one was to
      modify Object.prototype to contain the new getters and
      setters. This would have been the fastest, but can cause
      problems with code like the following:
    </p>
    <pre>
<span class="keyword">for</span> (var param <span class="type">in</span> <span class="variable-name">obj</span>) {
  <span class="comment">// Do something with obj[param]
</span>}

</pre>
    <p>
      This would end up enumerating all of the added functions as well
      as the properties of the object in question. This is why it is
      generally considered a bad idea to modify Object.prototype.
    </p>
    <p>
      The second rejected approach was to create a wrapper class with
      all the accessor functions, that performs the requisite getting
      and setting on a member variable containing the actual DOM
      object. This one could have worked well, but it would have been
      a lot of code to implement, and would have made debugging with
      Firebug more difficult because of the added layer of
      indirection.
    </p>
    <p>
      The approach I settled on was to simply provide wrapper
      functions for document.getElementById and
      document.createElement, and for each element that is "getted" or
      created, to copy in the required member functions. This has a
      perfomance penalty during the getting or creation of elements,
      but the calls themselves are speedy. There is likely to be a lot
      more manipulation than getting, I would think.
    </p>
    <h3>
      How to use this code
    </h3>
    <p>
      To use this code, just reference this file from your web page
      before any of your own JavaScript, but only when you are outside
      of Facebook. Make sure to call fbGetEl and fbCreateEl instead of
      document.getElementById and document.createElement. In the
      version of your page that is intended to be run inside of
      Facebook, include this code:
    </p>
        <pre>
<span class="type">function</span> <span class="function-name">fbGetEl</span>(elId) {
  <span class="keyword">return</span> document.getElementById(elId);
}
<span class="type">function</span> <span class="function-name">fbCreateEl</span>(elType) {
  <span class="keyword">return</span> document.createElement(elType);
}
</pre>
    <p>
      Alternatively, if you are feeling a little tricky, you can add
      in some code like this to the end of fbHelper.js
    </p>
        <pre>
document.getElementById = fbGetEl;
document.createElement = fbGetEl;
</pre>
    <p>
      Then you can continue to use document.getElementById and
      document.createElement. (Note that I have not tested this
      approach.)
    </p>
    <p>
      I hope this comes in handy for some people.
    </p>
    <h3>
      More FBJS tips
    </h3>
    <h4>
      Beware of the cache!
    </h4>
    <p>
       If you make a change to your .js file and
      don't notice any difference in your app's behavior, chances are
      you are getting bitten by the cache bug. To get around this,
      Facebook recommends adding "cache-breaker" code to the URL. For
      example, instead of linking to "myFile.js", link to
      "myFile.js?v=2". The extra text from the question mark on is
      usually ignored by web servers for static files. In my Django
      context processor, I have code like the following:
    </p>
    <pre>
<span class="keyword">from</span> svnVersion <span class="keyword">import</span> svnVersion

<span class="comment"># Add this function to your TEMPLATE_CONTEXT_PROCESSORS
# list in settings.py
</span><span class="keyword">def</span> <span class="function-name">fbContextProcessor</span>(request):
    <span class="keyword">return</span> { <span class="comment"># Add any other template vars you want here.
</span>        '<span class="string">cacheBreaker</span>':'<span class="string">?v=%s</span>' % svnVersion }

</pre>
    <p>
      Then in my template, whenever a have a link, I do something like:
    </p>
    <pre>
&lt;a href="http://example.com/myFile.js{{ cacheBreaker }}"&gt;Click here!&lt;/a&gt;
    </pre>
      Then every time I update my code, I run a shell script that does
      something like:
    </p>
    <pre>
      #!/bin/sh
      echo "svnVersion = '`svnversion -n .`'" > svnVersion.py
    </pre>

    <p>
      That way, every time I update my code, I make sure to break the
      Facebook cache. Alternatively, you could call svnversion
      straight from Python.
    </p>
    <h4>
       console.log is your friend! 
    </h4>
    <p>
     This is true in general when
      JavaScript programming, but especially so with Facebook. Take
      the time to put in some extra logging messages while you're
      developing, and testing and debugging will be much easier. And
      read up on Firebug as much as possible.
    </p>
    <h4>
      Check out the <a href="http://wiki.developers.facebook.com/index.php/FBJS/Animation">Animation library</a>.
    </h4>
    <p>
      It's pretty cool, and it works outside of Facebook, too.
    </p>
    <h4>
      Beware the limitations.
    </h4>
    <p>
      Facebook only allows up to five external
      script files, so keep that in mind. You may unfortunately have
      to combine two or more .js files into one to work around this
      restriction. Also, FBJS doesn't run on profile pages until the
      user has interacted with the app.
    </p>]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/python/django-facebook-2/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
