<?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</title>
	<atom:link href="http://www.chickenwingsw.com/feed" rel="self" type="application/rss+xml" />
	<link>http://www.chickenwingsw.com</link>
	<description>Developing ideas on developing.</description>
	<lastBuildDate>Sat, 06 Feb 2010 13:58:21 +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>New version of PayPal on Python</title>
		<link>http://www.chickenwingsw.com/scratches/uncategorized/new-version-of-paypal-on-python</link>
		<comments>http://www.chickenwingsw.com/scratches/uncategorized/new-version-of-paypal-on-python#comments</comments>
		<pubDate>Sat, 06 Feb 2010 13:53:21 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.chickenwingsw.com/?p=175</guid>
		<description><![CDATA[I've published version 0.6 of my Python implementation of the PayPal NVP interface. You can download PayPal on Python here.

The recent changes include:

	Fixed handling of dates. You can now use a Python datetime.date object anywhere the API calls for a date.
	Implemented recurring payments.
	Implemented Fraud Management Filters.
	Implement reference transactions.
	Changed the license from the Affero Public License [...]]]></description>
			<content:encoded><![CDATA[I've published version 0.6 of my Python implementation of the PayPal NVP interface. You can <a title="PayPal on Python – a Python interface to PayPal’s NVP API " href="http://www.chickenwingsw.com/paypal-on-python">download PayPal on Python here</a>.

The recent changes include:
<ul>
	<li>Fixed handling of dates. You can now use a Python <em>datetime.date</em> object anywhere the API calls for a date.</li>
	<li>Implemented recurring payments.</li>
	<li>Implemented Fraud Management Filters.</li>
	<li>Implement reference transactions.</li>
	<li>Changed the license from the Affero Public License to the GPL.</li>
</ul>
Enjoy! And, as usual, please feel free to <a title="Contact Eddie Sullivan" href="http://www.chickenwingsw.com/contact">contact me </a>with any questions or issues.]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/uncategorized/new-version-of-paypal-on-python/feed</wfw:commentRss>
		<slash:comments>0</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>2</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>Introducing Best Texas Hold&#8217;em!</title>
		<link>http://www.chickenwingsw.com/scratches/uncategorized/introducing-best-texas-holdem</link>
		<comments>http://www.chickenwingsw.com/scratches/uncategorized/introducing-best-texas-holdem#comments</comments>
		<pubDate>Sun, 12 Jul 2009 18:17:08 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://www.chickenwingsoftware.com/?p=104</guid>
		<description><![CDATA[My Texas Hold'em poker site is now fully operational! It's called Best Texas Hold'em and you can play now at www.bettorbest.com.
Fun features include:

	Play online for FREE in your browser - no Flash or downloads required.
	Play against your friends, or meet new friends.
	Log in using your Twitter, Hotmail, or MySpace account.
	Challenge yourself against artificial intelligence robots.
	Get [...]]]></description>
			<content:encoded><![CDATA[<img src="/media/texas-holdem.png" class="pf-right" alt="Texas Hold&amp;em" />My <a href="http://www.bettorbest.com">Texas Hold'em poker site</a> is now fully operational! It's called <a href="http://www.bettorbest.com">Best Texas Hold'em</a> and you can play now at <a href="http://www.bettorbest.com">www.bettorbest.com</a>.
Fun features include:
<ul>
	<li>Play online for FREE in your browser - no Flash or downloads required.</li>
	<li>Play against your friends, or meet new friends.</li>
	<li>Log in using your Twitter, Hotmail, or MySpace account.</li>
	<li>Challenge yourself against artificial intelligence robots.</li>
	<li>Get 1,000 free chips just for joining, plus another 500 chips for every day you log in.</li>
</ul>
In addition, there is a thorough help system where you can <a href="http://www.bettorbest.com/static/doc/help.html">learn to play Texas Hold'em</a>, learn all about the <a href="http://www.bettorbest.com/static/doc/diags.html">Moving Button rule</a>, and even get some <a href="http://www.bettorbest.com/static/doc/strategy.html">poker strategy tips</a>. And check back often as new pages are constantly being added.

And more great features to come! The site is still under active development, so you can expect lots of great changes and ideas.
<ul></ul>]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/uncategorized/introducing-best-texas-holdem/feed</wfw:commentRss>
		<slash:comments>0</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>
	</channel>
</rss>
