<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xml:base="http://whijo.net" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
 <title>django</title>
 <link>http://whijo.net/taxonomy/term/62/feed</link>
 <description>The taxonomy view with a depth of 0.</description>
 <language>en</language>
<item>
 <title>Statistics logging for Django - part 2</title>
 <link>http://whijo.net/blog/brad/2007/07/29/statistics-logging-django-part-2.html</link>
 <description>&lt;p&gt;In &lt;a href=&quot;http://whijo.net/blog/brad/2007/07/19/statistics-logging-django.html&quot;&gt;part 1&lt;/a&gt; I explained how to build middleware and an associated model to capture page accesses, and tie them to a user session. Now that we have all this useful info logged we need to do something with it, like, display it. Unfortunately Django doesn&#039;t have a facility for using GROUP BY with mysql, so you have two major choices (there are more but we can ignore them): implement a custom request in a &lt;a href=&quot;http://www.djangoproject.com/documentation/model-api/#managers&quot;&gt;custom Manager&lt;/a&gt; (see &lt;a href=&quot;http://www.djangosnippets.org/snippets/236/&quot;&gt;snippet&lt;/a&gt; and &lt;a href=&quot;http://www.djangosnippets.org/snippets/1/&quot;&gt;snippet&lt;/a&gt;, or &lt;a href=&quot;http://www.djangosnippets.org/tags/group-by/&quot;&gt;tagged snippets&lt;/a&gt;), or exploit a &lt;a href=&quot;&quot;&gt;mysql view&lt;/a&gt; and model it in Django. Now for me I prefer the latter because it means my custom sql becomes a mysql customisation and as far as Django is concerned it is dealing with a normal table (but don&#039;t tell Django that it is read only), and thus the model code works, so subsequent queries and manipulations can exploit the &lt;acronym title=&quot;Object Relational Manager&quot;&gt;ORM&lt;/acronym&gt; easily. My subjective and non-scientific experience is that using views is a lot more efficient/quick than using custom queries in the manager (it probably has to do with whatever optimisations exist with views, and the fact that you only fetch items when Django decides you need to fetch a row). So, how the hell do we do it?&lt;/p&gt;
&lt;p&gt;First I created a model that describes what information I want to deal with (something which maps neatly on to our other model):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;class UserActivity(models.Model):
        session = models.OneToOneField(Session,
                                        db_index=True, 
                                        null=True,blank=True,
                                        primary_key=True)
        user = models.ForeignKey(User,null=True,blank=True)
        date = models.DateTimeField(
                       help_text=&quot;Date Request started processing&quot;,
                       auto_now_add=True,
                       db_index=True)
        processing_time = models.IntegerField(
                       help_text=&quot;Total time spent on this user&quot;)
        requests = models.IntegerField(
                       help_text=&quot;Total Requests in this session&quot;)
        stats = UserActivityManager()
        def __str__(self):
                return &#039;%s: %s %s - %s - %s&#039; % (self.user,self.session,self.date,self.processing_time,self.requests)
        class Admin:
                list_display= (&#039;user&#039;,&#039;session&#039;,&#039;date&#039;,&#039;processing_time&#039;,&#039;requests&#039;)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;
The nice thing about this set up is when we aggregate our activity logs we can pull out random stuff like total processing time for requests for a user/session, along with number of requests/user/session (and thus average request time)&lt;/p&gt;
&lt;p&gt;But that is just our model, we still need the magic. To implement the magic nicely I put some custom initial SQL into the sql directory of my application (in my case the housing application for this is called accounts, so I make a file called accounts/sql/useractivity.sql), you can read more about initial data &lt;a href=&quot;http://www.djangoproject.com/documentation/model-api/#providing-initial-sql-data&quot;&gt;here&lt;/a&gt;, &lt;a href=&quot;http://www.djangoproject.com/documentation/models/fixtures/&quot;&gt;Django fixtures&lt;/a&gt;).My SQL looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;DROP TABLE accounts_useractivity;
CREATE OR REPLACE VIEW accounts_useractivity AS 
SELECT i.session_id,
       i.user_id,
       MAX(i.date) as date,
       sum(i.request_time) AS processing_time, 
       count(*) AS requests 
FROM accounts_activitylog i 
GROUP BY 1 
ORDER BY NULL;
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So first I tell mysql to drop the table that django just created (accounts_useractivity), and create a view in it&#039;s place. The view is very simple, in that it just GROUP BY the session_id. The real hair puller for me was figuring out that I needed to use the MAX(i.date) (see more about &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html&quot;&gt;aggregate functions&lt;/a&gt;) to get the most recent access to float to the top when it normalises the data (otherwise the GROUP BY normally ORDER BY the session_id, which helps no one), the ORDER BY NULL is &lt;a href=&quot;http://dev.mysql.com/doc/refman/5.0/en/group-by-optimization.html&quot;&gt;an optimisation&lt;/a&gt; to tell GROUP BY not to ORDER BY. I am hoping that because date is an INDEX (from our logging model) it shouldn&#039;t cost too much to do a MAX. (I would like someone with Much MYSQL-fu to point out any further optimisations to this, or even alternative approaches to the whole thing).&lt;/p&gt;
&lt;p&gt;So now we have an aggregating VIEW which Django maps using it&#039;s ORM, so that to figure out sessions which have been active in the last x minutes (where x is a datetime.timedelta object) we simply do a:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;UserActivity.objects.get_query_set().filter(date__gte=datetime.now()-x)&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;
I wrote a custom manager for getting recent sessions etc., but that is an exercise for the reader. What I did include in my model is something which returns a stepped &quot;request_weight&quot; i.e. session requests / largest session request x steps, which in my case defaults to 6. This means I can style my users like one would a &quot;&lt;a href=&quot;http://en.wikipedia.org/wiki/Tag_cloud&quot;&gt;tag cloud&lt;/a&gt;&quot;, so very active sessions will grow bigger than less active sessions. I needed to implement a helper function in the custom manager to return the session with the most requests.&lt;/p&gt;
&lt;p&gt;The final tip is to use a &lt;a href=&quot;http://www.djangoproject.com/documentation/templates_python/#subclassing-context-requestcontext&quot;&gt;context processor&lt;/a&gt; to make the information available to all your templates, although you could do it with middleware (maybe middleware is the proper way to do it?).&lt;/p&gt;
</description>
 <comments>http://whijo.net/blog/brad/2007/07/29/statistics-logging-django-part-2.html#comments</comments>
 <category domain="http://whijo.net/geek-tags/django">django</category>
 <category domain="http://whijo.net/tags/geek">geek</category>
 <category domain="http://whijo.net/geek-tags/middleware">middleware</category>
 <category domain="http://whijo.net/geek-tags/mysql">mysql</category>
 <category domain="http://whijo.net/geek-tags/mysql-views">mysql views</category>
 <category domain="http://whijo.net/geek-tags/python">python</category>
 <category domain="http://whijo.net/geek-tags/statistics">statistics</category>
 <pubDate>Sun, 29 Jul 2007 21:52:25 +0200</pubDate>
 <dc:creator>brad</dc:creator>
 <guid isPermaLink="false">110 at http://whijo.net</guid>
</item>
<item>
 <title>Statistics logging for Django</title>
 <link>http://whijo.net/blog/brad/2007/07/19/statistics-logging-django.html</link>
 <description>&lt;p&gt;Last night I built some middleware/models for a django application to log visitor/user activity on the site. The intention is to be able to do better user tracking, and build more comprehensive statistics stored in the mysql db (obviously I am also logging everything with apache). The current set up still needs some periodical scripts to conflate data into statistics. I was thinking of doing a daily-weekly-monthly routine (i.e. once a day stats are conflated for yesterday&#039;s stats, and once a week they are turned into weekly stats, and once a month they are minimised into a monthly overview. It was actually really simple to implement, but I butted my head against some django issues (more at the end).&lt;/p&gt;
&lt;p&gt;So, first we build a model to represent a request:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
class UserActivity(models.Model):
        user = models.ForeignKey(
                      User,
                      null=True, blank=True,
                      db_index=True
               )
        session = models.ForeignKey(
                      Session,
                      db_index=True,
                      null=True, blank=True
                  )
        date = models.DateTimeField(
                      help_text=&quot;Date Request started processing&quot;,
                      auto_now_add=True,
                      db_index=True)
        request_time = models.IntegerField(
                              help_text=&quot;Processing time (in ms)&quot;,
                              null=True, blank=True)
        request_url = models.CharField(maxlength=800,db_index=True)
        referer_url = models.URLField(
                              verify_exists=False,
                              db_index=True,
                              blank=True, null=True)
        client_address = models.IPAddressField(
                              blank=True,null=True)
        client_host = models.CharField(
                              maxlength=256,
                              blank=True,null=True)
        browser_info = models.TextField(null=True,blank=True)
        error = models.TextField(null=True,blank=True)
        def set_request_time(self):
                from datetime import datetime
                self.request_time = (
                                      datetime.now() - 
                                      self.date 
                                    ).microseconds
                self.save()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(download &lt;a href=&quot;http://whijo.net/files/models.py_.txt&quot; title=&quot;Download: models.py_.txt (1.17 KB)&quot;&gt;models.py_.txt&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;I think the model captures all the relevant info (we tie a request to a session and user, we have the time they made the request (and using middleware we can calculate how long the request took), the referer, and some info about the client).&lt;/p&gt;
&lt;p&gt;Most of the fields can be blank/null because we are not always going to have a session (see below), etc.&lt;/p&gt;
&lt;p&gt;The function set_request_time is called by the outgoing middleware function (process_response) and just notes how long the request took, and saves the object.&lt;/p&gt;
&lt;p&gt;Next we need some middleware to handle the object creation:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
from datetime import datetime
from django.conf import settings
from my_app.models import UserActivity

class Activity(object):
        def process_request(self,request):
                if request.META.has_key(&#039;HTTP_REFERER&#039;):
                        referer = request.META[&#039;HTTP_REFERER&#039;]
                else:
                        referer = &#039;&#039;

                self.activity = UserActivity(
                        user = request.user,
                        session = request.session,
                        date = datetime.now(),
                        request_url = request.META[&#039;PATH_INFO&#039;],
                        referer_url = referer,
                        client_address = request.META[&#039;REMOTE_ADDR&#039;],
                        client_host = request.META[&#039;REMOTE_HOST&#039;],
                        browser_info = request.META[&#039;HTTP_USER_AGENT&#039;]
                )

        def process_exception(self,request,exception):
                self.activity.error = exception
                self.activity.save()

        def process_response(self,request,response):
                self.activity.set_request_time()
                return response
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;(download &lt;a href=&quot;http://whijo.net/files/middleware.py_.txt&quot; title=&quot;Download: middleware.py_.txt (825 bytes)&quot;&gt;middleware.py_.txt&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;You may (or may not) have noticed that we only actually save our model on the outgoing response, so we only have one db write per request. The middleware system is very easy to build for, and is &lt;a href=&quot;http://www.djangoproject.com/documentation/middleware/&quot;&gt;documented here&lt;/a&gt;. The nice thing is the process_exception will keep a record of the exception (but I am not sure if this could be done so it stores more information than just the exception.__str__()?)&lt;/p&gt;
&lt;p&gt;To install this you would need to have your model within in an app that is &quot;installed&quot; and &quot;syncdb&quot;. The middleware needs to be placed after the session middleware, for e.g. in settings.py (in MIDDLEWARE_CLASSES):&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    
    &quot;django.middleware.common.CommonMiddleware&quot;,
    &quot;django.contrib.sessions.middleware.SessionMiddleware&quot;,
    &quot;django.contrib.auth.middleware.AuthenticationMiddleware&quot;,
    &quot;league.middleware.Activity&quot;,
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;
The next step is to build a context_processor that will include some useful stats like who is logged in etc. but that will need a more models, or mysql view or UserActivityManager that does a custom sql request with some &quot;group by&quot; magic. I have not built those parts yet, so I won&#039;t speak about them yet.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;My gripes about this implementation&lt;/strong&gt; doing regular user activity stats is a relatively costly request (you need to do a SELECT COUNT(*) WHERE date&amp;gt;now()-(20 minutes) GROUP BY user). This could be cheapened by having a OneToOne join table with the user table which just has an indexed recent_activity field against a User which is touched every request from that user. To get anonymous user activity we can only really rely on ip addresses, since sessions are not set until a user logs in/logs out, so we would need to do a similar system to the user OneToOne table, and use the REPLACE syntax of mysql (not sure if this is possible using django).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;My gripes about the session middleware&lt;/strong&gt; is that users do not get sessions until they log in/log out. This is good because once of visitor etc. do not get sent a cookie, and you don&#039;t allocate them a session in the DB, but it means unique sessions are more difficult to track because anonymous, first time visitors are only unique by their IP address, and nothing else. I can obviously change this, by setting any session variable for visitors without a session in the process_request of the activity middleware. This is neat because it is an opt in db hit, but after wrestling for ages with session middleware appreciating opt in is something to be done in the sober light of day.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;My gripes about Django&#039;s ORM&lt;/strong&gt; are that there is no neat way to do custom sql requests (the nicest group by sql snippet I have seen is &lt;a href=&quot;http://www.djangosnippets.org/snippets/1/&quot;&gt;this one&lt;/a&gt; because it uses django&#039;s _meta to get the table names). Newer changes in Django introduced the &lt;a href=&quot;http://www.djangoproject.com/documentation/db-api/#extra-select-none-where-none-params-none-tables-none&quot;&gt;extra&lt;/a&gt; parameter, which means less completely custom sql (i.e. you can just append your customisations to the existing sql statement), but it still doesn&#039;t allow you to use very specific stuff like GROUP BY (which not all DBs support). The way to remedy this is to figure out some way you can still send sanitised sql to a db server in an extra statement, while allowing more appended customisations for developers. The alternative is to build group_by functions which either translate to DB specific requests, or do it virtually (much like the transactions infrastructure). I prefer the latter solution because I think GROUP BY is very relevant and very useful, but the latter solution does mean that if your DB doesnt support it, then it could be a very costly operation in python-space.&lt;/p&gt;
</description>
 <comments>http://whijo.net/blog/brad/2007/07/19/statistics-logging-django.html#comments</comments>
 <category domain="http://whijo.net/tags/development">development</category>
 <category domain="http://whijo.net/geek-tags/django">django</category>
 <category domain="http://whijo.net/tags/geek">geek</category>
 <category domain="http://whijo.net/geek-tags/logging">logging</category>
 <category domain="http://whijo.net/geek-tags/middleware">middleware</category>
 <category domain="http://whijo.net/geek-tags/python">python</category>
 <category domain="http://whijo.net/geek-tags/statistics">statistics</category>
 <enclosure url="http://whijo.net/files/middleware.py_.txt" length="825" type="text/plain" />
 <pubDate>Thu, 19 Jul 2007 12:05:13 +0200</pubDate>
 <dc:creator>brad</dc:creator>
 <guid isPermaLink="false">108 at http://whijo.net</guid>
</item>
<item>
 <title>Even when you are winning (Drupal vs. Mambo, Germalism, Django, Schools, more bean)</title>
 <link>http://whijo.net/blog/brad/2006/08/05/even-when-you-are-winning-drupal-vs-mambo-germalism-django-schools-more-bean.ht</link>
 <description>&lt;p&gt;You haven&#039;t heard from me in a while because I have been pretty darn busy. So, what have I been busy with? lots...and to be a dork, I will lump the unrelated together in this monumental post:

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Drupal and MamboJoomla?&lt;/strong&gt;
&lt;p&gt;I have been doing some free-lance work here and there. Lots of CMS setting up, notably, lots of Drupal. After using Mambo for a long time, and dealing with hacks here and there to get it to behave in a sane manner wears one down. I cannot vouch for if Joomla has improved the sif codebase that Mambo runs on, but I know &lt;a href=&quot;http://drupal.org&quot;&gt;Drupal&lt;/a&gt; is the closest you can come to a good multi-purpose CMS that &lt;em&gt;Doesnt make your head burn when problem solving&lt;/em&gt;. I don&#039;t want to say that the many hours that went into making Mambo were wasted. It is very clear that Mambo started as something, grew into something else, got released as open source, and became something else, split into two competing products (Mambo/Joomla), etc. Drupal, on the other hand, is community plumbing. It started out as community plumbing, grew into better community plumbing, and has a very interactive community, built using...Drupal. If you want a clear illustration of where Mambo/Joomla fails download yourself a mambo module, and a drupal module. Open the two codebases (in parallel, or series), and notice how the joomla/module has &lt;strong&gt;&lt;under&gt;No&lt;/under&gt;&lt;/strong&gt; style, no API it is adhering to, behaving generally like a wild west php script. Notice how drupal module has an API it adheres to, notice how it can augment many different areas in the engine. Drupal starts as an engine, you plug modules into it, and it becomes a CMS, or a Blog, or a community advocacy site. Mambo/Joomla is a piece of bad ex-commercial monolithic code which heard about plugins during one of it&#039;s augmentations.&lt;/p&gt;
&lt;p&gt; What I do know is that Drupal is incredibly easy to work with, well documented, stable, and current. It cuts my web development time in half. In fact the work I normally have to do lands in building a theme (using any one of the templating engines available), installing and configuring a few specific modules, and smiling a lot. I think there is probably enough business in just building themes for drupal. For web development...Inkscape++, Drupal++. &lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Germalisms&lt;/strong&gt;
&lt;p&gt;I have been lecturing some Germalisms (or Journalists) in XHTML and CSS (plus some mentions of Web 2.0.1b rc3 stuffs). I have been using our local &lt;a href=&quot;http://moodle.ru.ac.za&quot;&gt;Moodle&lt;/a&gt; installation to build up the course and so on. Obviously I did my homework, and being an advocate of standards where possible, I looked into using &lt;a href=&quot;http://meyerweb.com/eric/tools/s5/&quot;&gt;s5: A Simple, Standards-Based, Slide Show System&lt;/a&gt; within moodle. Good news is it is possible. What does all that jibber jabber mean? well, using an s5 plugin for moodle means I can create lecture slides on moodle, and they will run in any web browser. I don&#039;t need a proprietry product, I don&#039;t even need a fancy web browser, I can actually build the slides using my cellphone (if the urge gripped me) from anywhere in the world. Sure it doesnt have fancy effects (it can be easily augmented to have some fancy effects), but it allows me to build good looking slides quickly and easily, without ever leaving my browser. that is k-rad. Up yours proprietry-vendor-of-your-choice.&lt;/p&gt;
&lt;p&gt; The kids are cool, but we have only had two lectures so far, what with me being in Dwesa last week, and them being in jhb this week. It is going well though. We have pet names and everything. Well, not so much, but we could. Some may take offense at me calling them Germalisms, but it is a pet name some of us have for Journalists, I am a victim of circumstances.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Djangalising&lt;/strong&gt;
&lt;p&gt;Another highlight in my life has been wrapping my keys around some &lt;a href=&quot;http://djangoproject.com&quot;&gt;Django&lt;/a&gt;. Django is a web application framework written in the (imho) best-language-around python. I am currently writing a custom app for the &lt;a href=&quot;http://www.freedomleague.org.za&quot;&gt;Freedom League&lt;/a&gt;. Mambo has been seriously deficient at this task, and I felt that building a custom app was the way to go. Django makes a lot of life easy. It does take ten minutes to do the basic core code, but it obviously takes longer to develop an application, with bells and whistles. I have been bad in not posting any code snippets etc. but I haven&#039;t had the inclination to spend the time on such things. The project is going to be open sourced as soon as possible, but i want to get it up and running, have a people use the site, improve it, get some peeps to review it, and then release it. Either way, python, and Django, have improved my outlook on webdevelopment even more. The exciting things about Django include easy scaling up, high response times (i.e. higher than any web framework in php, j2ee, etc.), easy interactions with multiple database backends, abstracted modelling code, plenty of freebies (like the admin module, comments, multiple markdown syntaxes, powerful templating). There are arguments for different web frameworks, and they are nice, but Django is a comfort zone that I like. I tried Ruby on Rails, knowing no ruby, and got pretty far, but very frustrated. I tried Django, knowing no python, and got most places I wanted to get. Django++&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Schools&lt;/strong&gt;
&lt;p&gt;A significant portion of my time has been dedicated to the &lt;a href=&quot;http://schools.coe.ru.ac.za&quot;&gt;e-Yethu schools project&lt;/a&gt;. Besides the technical side of things (helping schools get things done), the project is having increasing interactions with the Department of Education in the Eastern Cape. We are starting to produce documents which are of use to the department. They have to cater for lots of schools getting computer labs by 2013, like all of them. We can, and are, presenting them with research and knowledge which has grown from our actual experience working with the schools in grahamstown. We can discuss multiple lab setups with expertise (Thin clients, Fat clients, Dual boot thick and thin clients, Windows networks managed by Open source software, school relevant open source software on linux and windows), as well as connectivity issues (Modem, DSL, Wireless (wifi and wimax), GPRS/EDGE/HDPSISASAAS). It is nice that we are producing something worthwhile, building our own experience and knowledge. Without the work that came before us we would be nowhere, and now we are trying to ensure that the work we and others are doing can be used to the benefit of lots of school kids.
&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;strong&gt;Bean&lt;/strong&gt; and Amanda are the underlying current of my life. We have a reasonably strong indication that Bean is a girl, although I think people are seeing chickens before the eggs crack. Becoming a parent brings a whole wealth of experiences and worries, but it seems like together we are getting somewhere. I cannot wait till bean is born and I take the time off to spend with Mandy and bean. The prospect of a long holiday at the end of the year, spent getting to know my spawn and all of it&#039;s crying-spitting-shitting-ness is going to be rad. It seems like everyone else is more worried about what-is-going-to-happen than me, or worrying for me. The nice thing is that there is nothing to worry about, because it will work out fine in the end. I think people will only believe me when I am old enough to embarrass bean. I am already old enough to. I will know my work is paid off when my child tells me &quot;you are such a dork&quot;. Because, I am ;)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;</description>
 <comments>http://whijo.net/blog/brad/2006/08/05/even-when-you-are-winning-drupal-vs-mambo-germalism-django-schools-more-bean.ht#comments</comments>
 <category domain="http://whijo.net/tags/bean">bean</category>
 <category domain="http://whijo.net/geek-tags/content-management">content management</category>
 <category domain="http://whijo.net/geek-tags/django">django</category>
 <category domain="http://whijo.net/geek-tags/drupal">drupal</category>
 <category domain="http://whijo.net/tags/e-yethu">e-yethu</category>
 <category domain="http://whijo.net/tags/finley">finley</category>
 <category domain="http://whijo.net/tags/geek">geek</category>
 <category domain="http://whijo.net/tags/germalism">germalism</category>
 <category domain="http://whijo.net/geek-tags/joomla">joomla</category>
 <category domain="http://whijo.net/tags/journalism">journalism</category>
 <category domain="http://whijo.net/tags/lecturing">lecturing</category>
 <category domain="http://whijo.net/geek-tags/mambo">mambo</category>
 <pubDate>Sat, 05 Aug 2006 15:45:25 +0200</pubDate>
 <dc:creator>brad</dc:creator>
 <guid isPermaLink="false">393 at http://whijo.net</guid>
</item>
</channel>
</rss>
