[Catalyst-commits] r7189 - / trunk/examples/CatalystAdvent/root/2007 trunk/examples/CatalystAdvent/root/2007/pen

zarquon at dev.catalyst.perl.org zarquon at dev.catalyst.perl.org
Sat Dec 1 21:33:28 GMT 2007


Author: zarquon
Date: 2007-12-01 21:33:28 +0000 (Sat, 01 Dec 2007)
New Revision: 7189

Added:
   trunk/examples/CatalystAdvent/root/2007/pen/
   trunk/examples/CatalystAdvent/root/2007/pen/1.pod
   trunk/examples/CatalystAdvent/root/2007/pen/10.pod
   trunk/examples/CatalystAdvent/root/2007/pen/11.pod
   trunk/examples/CatalystAdvent/root/2007/pen/12.pod
   trunk/examples/CatalystAdvent/root/2007/pen/15.pod
   trunk/examples/CatalystAdvent/root/2007/pen/17.pod
   trunk/examples/CatalystAdvent/root/2007/pen/2.pod
   trunk/examples/CatalystAdvent/root/2007/pen/24.pod
   trunk/examples/CatalystAdvent/root/2007/pen/3.pod
   trunk/examples/CatalystAdvent/root/2007/pen/4.pod
   trunk/examples/CatalystAdvent/root/2007/pen/5.pod
   trunk/examples/CatalystAdvent/root/2007/pen/6.pod
   trunk/examples/CatalystAdvent/root/2007/pen/7.pod
   trunk/examples/CatalystAdvent/root/2007/pen/8.pod
Removed:
   trunk/examples/CatalystAdvent/root/2007/1.pod
   trunk/examples/CatalystAdvent/root/2007/10.pod
   trunk/examples/CatalystAdvent/root/2007/11.pod
   trunk/examples/CatalystAdvent/root/2007/12.pod
   trunk/examples/CatalystAdvent/root/2007/15.pod
   trunk/examples/CatalystAdvent/root/2007/17.pod
   trunk/examples/CatalystAdvent/root/2007/2.pod
   trunk/examples/CatalystAdvent/root/2007/24.pod
   trunk/examples/CatalystAdvent/root/2007/3.pod
   trunk/examples/CatalystAdvent/root/2007/4.pod
   trunk/examples/CatalystAdvent/root/2007/5.pod
   trunk/examples/CatalystAdvent/root/2007/6.pod
   trunk/examples/CatalystAdvent/root/2007/7.pod
   trunk/examples/CatalystAdvent/root/2007/8.pod
Modified:
   /
Log:
 r12064 at zaphod:  kd | 2007-12-02 08:24:12 +1100
 staging area for advent entries in 2007/pen



Property changes on: 
___________________________________________________________________
Name: svk:merge
   - 1b129c88-ebf4-0310-add9-f09427935aba:/local/catalyst:4278
1c72fc7c-9ce4-42af-bf25-3bfe470ff1e8:/local/Catalyst:11938
3b9770f9-e80c-0410-a7de-cd203d167417:/local/catalyst:3514
dd8ad9ea-0304-0410-a433-df5f223e7bc0:/local/Catalyst:6909
   + 1b129c88-ebf4-0310-add9-f09427935aba:/local/catalyst:4278
1c72fc7c-9ce4-42af-bf25-3bfe470ff1e8:/local/Catalyst:12064
3b9770f9-e80c-0410-a7de-cd203d167417:/local/catalyst:3514
dd8ad9ea-0304-0410-a433-df5f223e7bc0:/local/Catalyst:6909

Deleted: trunk/examples/CatalystAdvent/root/2007/1.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/1.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/1.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,5 +0,0 @@
-=head1 Day 1 - Catalyst Application Design
-
-=head1 AUTHOR
-
-Jon Rockway

Deleted: trunk/examples/CatalystAdvent/root/2007/10.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/10.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/10.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,5 +0,0 @@
-=head1 Day 10 - Rapid CRUD with Catalyst
-
-=head1 AUTHOR
-
-Peter Karman

Deleted: trunk/examples/CatalystAdvent/root/2007/11.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/11.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/11.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,5 +0,0 @@
-=head1 Catalyst Base Classes
-
-=head1 AUTHOR
-
-claco

Deleted: trunk/examples/CatalystAdvent/root/2007/12.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/12.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/12.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,5 +0,0 @@
-=head1 local::lib and Catalyst
-
-=head1 AUTHOR
-
-John Goulah

Deleted: trunk/examples/CatalystAdvent/root/2007/15.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/15.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/15.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,252 +0,0 @@
-=head1 Advanced Search in web DBIx::Class based applications (with tags, full text search and searching by location)
-
-There is a bit of irony that I write that article, for people to learn from it,
-while in fact it is my failing to properly wrap my head around the problem and encapsulate 
-my solution into a CPAN library that forces me to write an article in the first
-place.  But maybe someone smarter then me will read it and write that CPAN
-module?
-
-=head2 The Problem
-
-It is a common case that on a web site you need an 'advanced search' feature
-that let's the user combine simple predicates into more elaborated queries.
-Usually all the predicates are joined with an 'AND' - and the technique I
-describe here is based on this assumption.  At first this task looks pretty
-simple.  You have a list of parameters from the web form, corresponding the the
-columns of some database table, you have the values of those parameters and you
-need to find all the records in that table that have those values in those
-columns.  You just do: 
-
-    my @records = $schema->ResultSet( 'MyTable' )->search( 
-        $reqest->params, 
-        { page => 1, rows => 5 } 
-    );
-
-Simple.
-
-Then of course you add parameter validation and filtering - but this is outside
-of the scope of this article.
-
-Then you need to add checks on columns not only in the searched table, but also
-on columns from related records and things become more complicated.  What I
-propose here is a solution that works for the simple case, solves the related
-tables case, and also is easily extendable to cover more complicated predicates
-like searching by a conjunction of tags, full text searches or searches by
-location. I also add implementation of those 'advanced' predicates (using the
-PostgreSQL extensions for full text search and location based search).
-
-=head2 The Solution
-
-The solution I propose is this simple module:
-
-    package Ymogen2::DB::RSSearchBase;
-    
-    use strict;
-    use warnings;
-    
-    use base qw( DBIx::Class::ResultSet );
-    
-    sub advanced_search {
-        my ( $self, $params, $attrs ) = @_;
-        for my $column ( keys %$params ){
-            if( my $search = $self->can( 'search_for_' . $column ) ){ 
-                $self = $self->$search( $params );
-                next;
-            }
-            my ( $full_name, $relation ) = simple_predicate( $column );
-            my $join;
-            $join = { join => [ $relation ] } if $relation;
-            $self = $self->search( 
-                    { $full_name => $params->{$column} }, 
-                    $join,
-            );
-        }
-        $self = $self->search( {}, $attrs );
-        return (wantarray ? $self->all : $self)
-    }
-
-You use it like that:
-
-    my @records = $schema->ResultSet( 'MyTable' )->advanced_search( 
-        \%search_params, 
-        { page => 1, rows => 5 } 
-    );
-
-But first you need to make your ResultSet class inherit from it.  This can be
-done in several ways, what we do is adding:
-
-    __PACKAGE__->resultset_class(__PACKAGE__ . '::ResultSet');
-    
-    package Ymogen2::DB::Schema::Users::ResultSet;
-
-    use base qw( Ymogen2::DB::RSSearchBase );
-
-
-
-to MyTable.pm.
-
-For the simple case it works just like the familiar 'search' method of the
-L<DBIx::Class::ResultSet class>. But it also works for searching in related
-records.  For that we have the simple_predicate function. It looks like that: 
-
-    sub simple_predicate {
-        my $field = shift;
-        if( $field =~ /(.*?)\.(.*)/ ){
-            my $first = $1;
-            my $rest  = $2;
-            my( $column, $join ) = simple_predicate( $rest );
-            if ( $join ) {
-                return $column, { $first => $join };
-            }else{
-                return $first . '.' . $column, $first;
-            }
-        }elsif( $field ){ 
-            return $field;
-        }else{
-            return;
-        }
-
-What it does is parsing column names of the format:
-'relationship1.relationship2.relationship3.column' into 'relationship3.column'
-- the fully qualified column name and a 
-'{ relationship1 => { relationship2 => relationship3 } }' hash used for joining
-the appriopriate tables.
-
-(I had also a non-recursive version - but it was not simpler)
-
-So now you can do this:
-
-    my @records = $schema->ResultSet( 'MyTable' )->advanced_search( 
-        {
-            column1 => 'value1',
-            column2 => 'value2', 
-            some_relation.column => 'value3',
-            some_other_relation.some_third_relation.column => 'value4', 
-        },
-        { page => 1, rows => 5 }
-    );
-    
-Useful?
-We use it.
-
-=head2 The Extensions
-
-But the real advantage of this approach is how easily it can be extended.  
-
-=head3 Tags
-
-For example let say we need to search by conjunction of tags like that:
-
-    my @records = $schema->ResultSet( 'MyTable' )->advanced_search( {
-        column1 => 'value1',
-        some_other_relation.some_third_relation.column => 'value4',
-        tags => [ qw/ tag1 tag2 tag3/ ],
-    });
- 
-What we need is a method called 'search_for_tags' that will do the search.  The
-nice thing is that we don't need to warry how this will be combined with the
-rest of the predicates - DBIC will do the right thing (for and 'AND' relation).
-
-Here is the method:
-
-    sub search_for_tags {
-        my ( $self, $params ) = @_;
-        my @tags = @{$params->{tags}};
-        my %search_params;
-        my $suffix = '';
-        my $i = 1;
-        for my $tag ( @tags ){
-            $search_params{'tags' . $suffix .  '.name'} = $tag;
-            $suffix = '_' . ++$i;
-        }
-        my @joins = ( 'tags' ) x scalar( @tags );
-        $self = $self->search( \%search_params, { 
-                join => \@joins,
-            } 
-        );
-        return $self;
-    }
-
-It builds a query like that:
-
-    SELECT * FROM MyTable me, Tags tags, Tags tags_2, Tags tags_3
-    WHERE tags.mytable_id = me.id AND tags.tag = 'tag1' AND
-    tags_2.mytable_id = me.id AND tags_2.tag = 'tag2' AND
-    tags_3.mytable_id = me.id AND tags_3.tag = 'tag3' 
-
-This query will use indices and should be fast (a more detailed cover of this
-technique you can find at my blog at:
-http://perlalchemy.blogspot.com/2006/10/tags-and-search-and-dbixclass.html).
-
-*Attention:* You need the 0.08008 version of DBIx::Class for this to work properly.
-
-=head3 Full Text Search
-
-For full text search I use the PostgreSQL tsearch2 engine here.
-
-=head3 Search by Proximity
-
-For searching by proximity I use the PostgreSQL geometric functions 
-(http://www.postgresql.org/docs/8.2/interactive/functions-geometry.html).
-There is 
-one problem with it - the distance operator assumes planar coordinates, 
-while for the interesting thing is to search geografic data with the standard
-latitude/longitude coordinates.  In our solution we just don't care about
-being exact and just multiply the 'distance' in degrees by 50 to get approximate
-distance in miles.  The actual proportion is about 43 for latitude and 69 for
-longitude at about the London's longitude, it would be possible to get quite 
-good results by dividing the latitude and longitude by those numbers in the
-database - but I would rather have good data in the database then more exact
-results.  Maybe at some point we shell switch to use some real geografic 
-distance functions (I've seen a PosgreSQL extension to do that - but I was
-scared a bit by it's experimental status).
-
-So here is the function used to filter the results by proximity to a place:
-
-sub search_for_distance {
-    my ( $self, $rs, $params ) = @_;
-    my $lat_long = $params->{lat_long};
-    my $distance = $params->{distance} / 50;  
-    # around London the actual proportions are around 43 for latitude 
-    # and 69 for longitude 
-    return $rs->search( 
-        { "(lat_long <-> '$lat_long'::POINT) < " => \$distance },
-        { join => 'location' }
-    );
-}
-
-This function assumes there are two parameters on the $params hash: distance
-and lat_long (lattitude/logintude coordinates).  The location data in our
-database are in a separate table called 'location'.
-
-We also use another search extension:
-
-sub search_for_lat_long {
-    my ( $self, $rs, $params ) = @_;
-    my $lat_long = $params->{lat_long};
-    $rs = $rs->search( undef,        
-        { 
-            join => 'location',
-            '+select' => [ \"(lat_long <-> '$lat_long'::POINT) AS distance" ],
-            '+as' => 'distance',
-            order_by => 'distance ASC',
-        }
-    );
-    return $rs;
-}
-
-This function sorts the results by proximity to the point determined by the
-lat_long coordinates.  This way the user does not need to specify the
-maximum distance - the closest results are displayed on the first pages
-anyway - and that is enough for most of the searches.
-
-=head2 And Beyond
-
-In the search by proximity extension I've used ordering of the results.  There
-is one problem with this.  We use many 'search' calls on the resultset
-to cumulate the predicates - but we cannot do this with the order.  Only the 
-last 'order_by' parameter used in the 'search' calls is effective.  I believe
-it would be useful to have a similar 'cumulative' behaviour for 'order_by' 
-and we can add this to 'advanced_search' (or perhaps it can be added to
-the core DBIC search method).
-

Deleted: trunk/examples/CatalystAdvent/root/2007/17.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/17.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/17.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,5 +0,0 @@
-=head1 Catalyst with Ext+Ajax: Editable Data Grids
-
-=head1 AUTHOR
-
-jasonk

Deleted: trunk/examples/CatalystAdvent/root/2007/2.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/2.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/2.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,244 +0,0 @@
-=head1 Day 2 - Getting started with ExtJS screen library
-
-Today we take a look at the ExtJS screen library and how to get started
-using it within a Catalyst web application.
-
-Don't forget to come back on Day 17 for a more advanced example by jasonk in 
-"Catalyst with Ext+Ajax: Editable Data Grids" 
-L<http://catalyst.perl.org/calendar/2007/17>
-
-=head2 What is ExtJS?
-
-ExtJS L<http://www.extjs.com/> is a cross-browser Javascript library for web 
-pages. You can use it to achieve Web 2.0 effects without writing too much 
-Javascript code (always a good idea!). It offers abstracted handling for HTML 
-elements, Document Object Model (DOM), event handling and AJAX (client-server) 
-calls. ExtJS also provides styling (blue, aero and Vista, you can write more) 
-and a good selection of widgets including:
-
-=over 2
-
-=item * window
-
-=item * layout
-
-=item * tabs
-
-=item * form
-
-=item * toolbar
-
-=item * menu
-
-=item * tree
-
-=item * combobox
-
-=item * grid
-
-=back 
-
-The full range is listed here L<http://extjs.com/learn/Ext_Extensions>
-
-
-The easiest way to see what is possible is to watch it in action:
-
-=over 2
-
-=item * desktop L<http://extjs.com/deploy/dev/examples/desktop/desktop.html>
-
-=item * feed viewer L<http://extjs.com/deploy/dev/examples/feed-viewer/view.html>
-
-=item * photo organiser L<http://extjs.com/deploy/dev/examples/organizer/organizer.html>
-
-=back
-
-For more examples see L<http://extjs.com/deploy/dev/examples/>
-
-
-
-=head2 What web browsers does it work on?
-
-=over 2
-
-=item * Internet Explorer 6+
-
-=item * Firefox 1.5+ (PC, Mac)
-
-=item * Safari 2+
-
-=item * Opera 9+ (PC, Mac)
-
-=back
-
-=head2 What about other Javascript libraries - I've got legacy code
-
-Because it grew out of Yahoo's YUI library and its developers
-wanted to support legacy code, ExtJS has a tiered design that
-allows you to choose the base Javascript adapter library
-
-=over 2
-
-=item * native Ext
-
-=item * YUI
-
-=item * jQuery
-
-=item * Prototype/Script.aculo.us
-
-=back 
-
-For new code, I'd recommend native Ext as it is faster to load.
-
-There are more details and a pretty picture of the design at
-L<http://extjs.com/learn/Ext_FAQ#What_other_libraries_are_required_to_run_Ext.3F>
-
-
-=head2 Downloading and installing the ExtJS library
-
-Download ExtJS 1.1.1 from L<http://extjs.com/download>
-
-The stable release, used in this article, is 1.1.1 and that's the one you need.
-The latest development release is Ext 2.0 but be aware that it has a different 
-object model to Ext 1.1 and many of the tutorials, docs and code on the site
-still relate to 1.1. 
-Once the widgets and documentation have been done for 2.0 I expect there will 
-be a rapid shift over in the user community.
-More details at L<http://extjs.com/learn/Ext_1_to_2_Migration_Guide>
-
-=head3 Installation
-
-If you're on Linux, install ExtJS to your web server document root, e.g. 
-/var/www/html/ext-1.1. When you want to use it in a Catalyst project create a 
-symbolic link from your root/static directory
-
- $ ln -s /var/www/html/ext-1.1.1 root/static/
-
-Otherwise, you can simply unzip the whole lot below root/static.
-
-When running the Catalyst test server, it will expect to find the files there.
-
-For production use, use absolute URLs to the ExtJS javascript files from your 
-templates, e.g. http://myserver/ext-1.1.1/ext-core.js, and allow your web server 
-to serve them rather than Catalyst. It's much faster.
-
-=head2 Manuals and learning materials
-
-Visit L<http://extjs.com/learn/>. You will find tutorials at 
-L<http://extjs.com/learn/Tutorials>.
-
-Bookmark and early on read through the community manual 
-L<http://extjs.com/learn/Ext_Manual>.
-
-The archive comes with an ExtJS API reference manual. You can open ext-
-1.1.1/docs/index.html in a browser or if you installed it under your Linux web 
-server root it should be accessible at L<http://myserver/ext-1.1.1/docs/>. It's 
-also online at L<http://extjs.com/deploy/ext/docs/index.html>. Use this to look 
-up methods and attributes for ExtJS objects.
-
-
-=head2 Adding ExtJS to a web page
-
-Firstly you need to include the ExtJS Javascript libraries and stylesheets in 
-the <head> section of your HTML page
-
- <link rel="stylesheet" type="text/css" href="/ext-1.1/resources/css/ext-all.css" />
- <script type="text/javascript" src="/ext-1.1/adapter/ext/ext-base.js"></script>
- <script type="text/javascript" src="/ext-1.1/ext-all.js"></script>
-
-In the body section use classes for styling
-
- <body class="xtheme-gray" >
-
-Use named <div> tags to identify content that ExtJS will enhance
-
- <div id="container"><div id="content" class="welcome">
- ...
- </div></div>
-
-Then supply Javascript to tell ExtJS what to do. The following creates a layout 
-with one panel called 'content' after the HTML page has finished loading
-
- <script type="text/javascript">
- Thescreen = function(){
-   return {
-     init: function(){
-       var layout = new Ext.BorderLayout(document.body, {
-         center: {
-           autoScroll: true,
-           minTabWidth: 50,
-           preferredTabWidth: 150,
-           titlebar: true
-         }
-       });
-            
-       layout.beginUpdate();
-       layout.add('center', new Ext.ContentPanel('content', {title:'ExtJS demo app'}));
-       layout.endUpdate();
-     }  
-   }
- }();
- Ext.EventManager.onDocumentReady(Thescreen.init, Thescreen, true);
- </script>
-
-Note the prototype object-based approach used to create the 'Thescreen' object.
-This helps standardise objects and avoid memory leaks. 
-See L<http://extjs.com/learn/Manual:Intro:Class_Design> for further explanation.
-
-
-=head2 Simple Example
-
-I've provided a simple working example you can use as a starting point for
-writing ExtJS Catalyst applications. It provides code, a menu, a couple of pages
-and a set of templates initially generated using the Catalyst helpers to give
-a portal page.
-
-
-=head2 Example application code
-
-You can check out the code from the Catalyst repository with
-
- svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/ExtJS
-
-
-=head2 Form Architecture Considerations
-
-You have a choice between implementing traditional "round trip" web pages
-and client-server AJAX dynamic web pages seen on Web 2.0 sites.
-
-In the "round trip" case, the user browses to a page, clicks a submit button to 
-post data to a server, HTML is sent back then the new page displays. You can 
-continue to do this with templates and use ExtJS to enhance the appearance and 
-add auto-completers to input fields.
-
-In the second case, you send HTML back once for the first page and then use 
-ExtJS to respond to events like button clicks to trigger display changes and 
-send/retrieve data to the server via asynchronous data transfers. The ExtJS Form 
-widget L<http://extjs.com/learn/Ext_Manual#Forms> handles this and can 
-automatically perform front-end data validation and display input warnings from 
-the backend. See L<http://extjs.com/deploy/dev/examples/#sample-7> and look at 
-the .js files. It's also possible to generate a form dynamically from an XML or 
-JSON definition in a data source, so you could hold your form definitions in a 
-database and serve them up from a Catalyst data handler.
-
-The choice will depend on how slick a user interface you want and your available 
-time, as writing Javascript can be time-consuming. AJAX screens often look better 
-but are less accessible for blind visitors and can be harder to debug. For 
-testing you would need to consider using a tool like Selenium. Check out 
-L<http://www.infoq.com/articles/testing-ajax-selenium> 
-L<http://www.infoq.com/news/2007/09/selenium-grid-parallel-testing>
-L<http://search.cpan.org/~lukec/Test-WWW-Selenium-1.13/lib/WWW/Selenium.pm>
-
-
-=head2 Comma Gotcha
-
-If you leave a trailing comma in a Javascript data structure, which is very easy 
-to do if you're used to programming Perl, it stops Internet Explorer's parser. 
-You'll get a blank page! It's easily spotted by running your output HTML code 
-through HTML Tidy.
-
-
-=head1 AUTHOR
-
-peterdragon - Peter Edwards <peter at dragonstaff.co.uk>

Deleted: trunk/examples/CatalystAdvent/root/2007/24.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/24.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/24.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,5 +0,0 @@
-=head1 This Year in Catalyst
-
-=head1 AUTHOR
-
-kd

Deleted: trunk/examples/CatalystAdvent/root/2007/3.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/3.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/3.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,184 +0,0 @@
-=head1 Get more REST - Using YUI and JavaScript for REST
-
-Today, we'll look into building a fully capable REST client in YUI that allows
-record creation, retrieving, updating and deletion (CRUD) as well as searching.
-
-=head2 Start Here First
-
-To make the most of this article, it is important to not only understand the
-basic idea of REST but to also see how it works within Catalyst.
-
-To start out understanding REST, read the excellent article by Ryan Tomayko 
-L<http://tomayko.com/articles/2004/12/12/rest-to-my-wife>, about explaining
-REST in simple terms that a non technical person is able to understand.  It will
-help a technical person understand it even more.
-
-Up next is to get a good understanding for how REST works inside of Catalyst,
-using Adam Jacob's excellent L<Catalyst::Action::REST> package.  The best way
-to get up to speed is to review Day 9 from the 2006 Advent Calendar, at
-L<http://www.catalystframework.org/calendar/2006/9.pod>.
-
-=head2 Following Along
-
-The examples that are listed here are available from the Catalyst subversion
-repository, available via:
-
- svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/RestYUI
-
-It is a good idea to check out the sources of the sample application to better
-follow along with the examples.  Included is the necessary YUI javascript files
-to enhance this application as you go.
-
-=head2 Why use JavaScript?
-
-The reason why we're required to use JavaScript for a full REST service is
-because of the limited vocabulary that a browser coupled with plain HTML is
-allowed to speak.  The browser will only ever send GET and POST requests in
-response to user interaction with an HTML document.  However, when using the
-C<XmlHttpRequest> method that is a standard in all Grade A browsers the 
-vocabulary is extended to support PUT, DELETE and HEAD.
-
-=head2 The Connection to REST
-
-REST is based off of getting what you ask for.  In the simplest form, an
-C<XmlHttpRequest> isn't enough to talk to a REST webservice.  There are a few
-major components that fit together to make everything work:
-
-=over
-
-=item Content Type
-
-=item Request Method
-
-=item 
-
-=back
-
-=head2 Starting the Catalyst Application
-
-We're taking last year's AdventREST example app and slightly modifying it to
-add support for YUI.
-
-So, to get started you can check out that application from subversion by doing:
- 
- svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/AdventREST
-
-Or check out the completed RestYUI application.
-
-The only fundamental change to the application is adding the Template Toolkit
-view:
-
- script/adventrest_create.pl view TT TT
-
-Also, we have to grab the static files for YUI itself.  As of writing this,
-version 2.3.1 is available from L<http://sourceforge.net/project/downloading.php?group_id=165715&filename=yui_2.3.1.zip>.  Check the latest version at
-L<http://developer.yahoo.com/yui/>
-
-After extracting the files from the zip archive, just copy over the .js files to
-the root/static directory.
-
-=head2 Preparing the REST WebService
-
-To gain access to the REST services, we'll be accessing both the C<list> and the
-C<item> actions.  The list is going to be pulled by using a customized YUI
-DataSource object.
-
-This will ask the REST service for a list of our people objects, and in a simple
-form is nothing more than a L<DBIx::Class> search:
-
-   sub user_list_GET {
-       my ( $self, $c ) = @_;
-
-       my %user_list;
-       my $user_rs = $c->model('DB::User')->search;
-       while ( my $user_row = $user_rs->next ) {
-           $user_list{ $user_row->user_id } =
-             $c->uri_for( '/user/' . $user_row->user_id )->as_string;
-       }
-       $self->status_ok( $c, entity => \%user_list );
-   }
-
-That is from the original REST article, and to make the most of the list we're
-going to enhance the listing to provide some additional meta information that 
-enhances the webservice with features such as pagination and other contextual
-information.  We'll add in pagination with a CGI parameter "page" and a param
-for the number of items per page called "per_page"
-
-   sub user_list_GET {
-       my ( $self, $c ) = @_;
-       my $page     = $c->req->params->{page} || 1;
-       my $per_page = $c->req->params->{per_page} || 10;
-
-       # We'll use an array now:
-       my @user_list;
-       my $rs = $c->model('DB::User')
-           ->search(undef, { rows => $per_page })->page( $page );
-       while ( my $user_row = $rs->next ) {
-           push @user_list, {
-               $user_row->get_columns,
-               uri => $c->uri_for( '/user/' . $user_row->user_id )->as_string
-           };
-       }
-
-       $self->status_ok( $c, entity => {
-           result_set => {
-               totalResultsAvailable => $rs->pager->total_entries,
-               totalResultsReturned  => $rs->pager->entries_on_this_page,
-               firstResultPosition   => $rs->pager->current_page,
-               result => [ @user_list ]
-           }
-       });
-   };
-
-So now we have a serialized structure that looks like this in JSON:
-
-=head2 Connecting with YUI
-
-After the webservice is up, it is time to setup the Yahoo DataSource object.
-
-We'll create a simple template off of the index action in C<Root.pm>, so
-create this action in Root.pm:
-
- sub index : Private {
-     my ( $self, $c ) = @_;
-     $c->forward( $c->view('TT') );
- }
-
-That will just direct the action for "/" to go to TT, and render an "index.tt"
-template.
-
-The C<index.tt> file is pretty basic, and after the HTML tags this is the crux
-of what gets the job done:
-
-    /* Create the YAHOO.util.DataSource object, the parameter is the
-       URI to your REST service
-    */
-    this.myDataSource = new YAHOO.util.DataSource("[%
-         c.uri_for( c.controller('User').action_for('user_list') ) %]");
-    this.myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
-    this.myDataSource.connXhrMode = "queueRequests";
-    this.myDataSource.responseSchema = {
-    	resultsList: "result_set.result",
-        /* We have to define the fields for usage elsewhere */
-        fields: [
-            "pk1", "token", "default_lang", "languages",
-            "url", "t_created", "t_updated", "actions"
-        ]
-     };
-
-After this, we have a functional DataSource object that can be tied into a
-DataTable:
-
-        myDataTable = new YAHOO.widget.DataTable(
-            "kb_list", myColumnDefs,
-            this.myDataSource, {
-                /* The initialRequest is appended to the URI to set params */
-                initialRequest: "page=1&content-type=text/x-json"
-            }
-        );
-
-=cut
-
-=head1 AUTHOR
-
-J. Shirley

Deleted: trunk/examples/CatalystAdvent/root/2007/4.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/4.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/4.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,7 +0,0 @@
-=head1 Catalyst Configuration
-
-=head1 AUTHOR
-
-???
-
-jayk?

Deleted: trunk/examples/CatalystAdvent/root/2007/5.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/5.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/5.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,5 +0,0 @@
-=head1 $c->uri_for fun
-
-=head1 AUTHOR
-
-purge

Deleted: trunk/examples/CatalystAdvent/root/2007/6.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/6.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/6.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,5 +0,0 @@
-=head1 Mango Overview
-
-=head1 AUTHOR 
-
-claco

Deleted: trunk/examples/CatalystAdvent/root/2007/7.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/7.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/7.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,5 +0,0 @@
-=head1 Catalyst Authentication
-
-=head1 AUTHOR
-
-jayk

Deleted: trunk/examples/CatalystAdvent/root/2007/8.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/8.pod	2007-12-01 20:14:18 UTC (rev 7188)
+++ trunk/examples/CatalystAdvent/root/2007/8.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -1,235 +0,0 @@
-
-=head1 Catalyst + Open Flash Chart: Fancy graphs with minimal fuss
-
-=head2 About Open Flash Chart
-
-Open Flash Chart is a flash application that prudoces some very nice-looking,
-interactive (and in some cases animated) charts and graphs for your web
-application.  It's also completely free and open source, released under the
-GNU General Public License.
-
-For examples of the kinds of graphs you can produce, visit the home page
-at L<http://teethgrinder.co.uk/open-flash-chart/>.
-
-=head2 Getting Started
-
-This tutorial assumes you already have some Catalyst experience, so we won't
-go into too much detail with the basics of creating an application...
-
-  % catalyst.pl AdventOFC
-  ...
-  % cd AdventOFC
-  ...
-  % script/adventofc_create.pl view TT TTSite
-  ...
-
-=head2 Installing Chart::OFC
-
-The Open Flash Chart application uses a difficult to work with format for it's
-data structure.  Fortunately the perl community has guys like Dave Rolsky, who
-recently made a nice perl library called L<Chart::OFC> that makes it easier to
-work with.  We're going to install L<Chart::OFC> first, because it includes the
-pieces you need from Open Flash Chart, so you only need to download once...
-
-Assuming you are using L<CPANPLUS>, you can install it like this...
-
-  % cpanp
-  ...
-  CPAN Terminal> i Chart::OFC
-  
-  Installing Chart::OFC (0.02)
-  ...
-  Module 'Chart::OFC' installed successfully
-  No errors installing all modules
-  
-  CPAN Terminal> q
-
-Once you have it installed, you need to get the .swf file and copy it into
-your application root directory.  If you installed from L<CPANPLUS>, something
-like the following will work.
-
-  % cd root/static
-  % unzip ~/.cpanplus/*/build/Chart-OFC-*/ofc/*.zip open-flash-chart.swf
-
-If you don't have the L<Chart::OFC> source directory any more, you can
-download the .swf from the Open Flash Chart web site at
-L<http://teethgrinder.co.uk/open-flash-chart/download.php>.
-
-Whether you use the copy from the L<Chart::OFC> source directory, or download
-it from the web site, you will get a .zip file that includes the source as
-well as adapter libraries for various langages.  You only need the .swf file
-from the archive though, you won't need any of the other files.
-
-=head2 Adding Open Flash Chart support to your application
-
-Now that you have a basic application, we'll add some charting capabilities
-with OpenFlashChart.  The HTML code required to embed a chart is long and
-repetitive, so I like to make a component template to do the boring work
-for me.  Create a file in root/lib called 'ofc_swf_object' with the
-following contents:
-
-  [%
-    DEFAULT
-        width    = '500'
-        height   = '300'
-        id       = 'ofc_chart'
-        bgcolor  = '#FFFFFF'
-        name     = 'ofc_chart';
-
-    SET swf_url = Catalyst.uri_for( 
-        '/static/open-flash-chart.swf',
-        {
-            width  = width
-            height = height
-            data   = data
-        }
-    );
-
-    # This is just to keep the html below from being
-    # too wide for the sake of the demo, you could always
-    # just put this inline if you wanted
-    SET cab_download = [
-        'http://fpdownload.macromedia.com'
-        '/pub/shockwave/cabs/flash/swflash.cab'
-        '#version=8,0,0,0'
-    ];
-  %]
-  [% FILTER collapse %]
-  <object
-    classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
-    codebase="[% cab_download.join( '' ) %]"
-    width="[% width %]" height="[% height %]"
-    id="[% id %]" align="middle">
-      <param name="allowScriptAccess" value="sameDomain" />
-      <param name="movie" value="[% swf_url %]" />
-      <param name="quality" value="high" />
-      <param name="bgcolor" value="[% bgcolor %]" />
-      <embed
-        src="[% swf_url %]" quality="high"
-        bgcolor="[% bgcolor %]" width="[% width %]"
-        height="[% height %]" name="[% name %]"
-        align="middle" allowScriptAccess="sameDomain"
-        type="application/x-shockwave-flash"
-        pluginspage="http://www.macromedia.com/go/getflashplayer"
-      />
-  </object>
-  [% END %]
-
-You might notice that there are two copies of basically every configuration
-parameter in this block of code.  Like many other things on the web, this is
-because Internet Explorer does it one way (the object part) and everything
-else does it differently (with embed.)
-
-=head2 Using your new Open Flash Chart tools
-
-Now that you have the support pieces you need, it's time to put them to use.
-For the purposes of the demo we're just going to add charts to the home page
-of the application, so we'll be editing the Root controller.  To get started,
-add a method to the root controller for the index page...
-
-  =head2 index
-  
-  The index page for our charts.
-  
-  =cut
-  
-  sub index : Private {
-      my ( $self, $c ) = @_;
-  
-      $c->stash->{ 'template' } = 'index.tt2';
-  }
-
-Next we need to create a template to go along with the index.  Since we took
-the time to setup a helper template, this one will be rather small.  Put this
-code into your root/src/index.tt2.
-
-  [% INCLUDE ofc_swf_object data = Catalyst.uri_for( '/graph' ) %]
-
-If you run script/adventofc_server.pl at this point, you should get a nice
-graph display, although it won't contain any data.  In order to get nice
-charts, we need to move onto the next step, the data!
-
-=head2 Generating appropriate data
-
-Next we need to create a controller to produce the appropriate graph
-information.  Edit the root controller again, add a new method for the
-graph data (make sure you add C<use Chart::OFC> to the top of your
-controller as well.)
-
-  =head2 graph
-  
-  Data provider for Open Flash Chart graphs.
-  
-  =cut
-  
-  sub graph : Local {
-    my ( $self, $c ) = @_;
-
-Open Flash Chart can display pie charts, lines and/or bars on a grid, and
-area charts on a grid.  You can determine which types of graphs to use by
-which L<Chart::OFC::Dataset> subclasses you provide your data to.  For
-the purposes of this demo, we'll create a chart with lines, but first we
-need some sample data.
-
-    my %data = (
-        Date    => [ map { "11/$_" } 1 .. 14 ],
-        Ninja   => [ map { int( rand( 10 ) ) } 1 .. 14 ],
-        Pirate  => [ map { int( rand( 10 ) ) } 1 .. 14 ],
-    );
-
-For each data point you want to graph, you create an object that is an
-instance of one of the L<Chart::OFC::Dataset> subclasses.
-
-    my $ninjas = Chart::OFC::Dataset::LineWithDots->new(
-        color       => 'black',
-        label       => 'Ninjas',
-        solid_dots  => 0,
-        values      => $data{ 'Ninja' },
-    );
-    my $pirates = Chart::OFC::Dataset::LineWithDots->new(
-        color       => 'red',
-        label       => 'Pirates',
-        solid_dots  => 1,
-        values      => $data{ 'Pirate' },
-    );
-
-Once you have your datasets, you need to create X and Y axis objects that
-provide the information necessary to label the graph.
-
-    my $x_axis = Chart::OFC::XAxis->new(
-        axis_label  => 'Date',
-        labels      => $data{ 'Date' },
-    );
-    my $y_axis = Chart::OFC::YAxis->new(
-        axis_label  => 'Sightings',
-        max         => 11,
-        label_steps => 1,
-    );
-
-Now that all the pieces are assembled, we can use them to build a graph.
-
-    my $grid = Chart::OFC::Grid->new(
-        title       => 'Observer Reports',
-        datasets    => [ $ninjas, $pirates ],
-        x_axis      => $x_axis,
-        y_axis      => $y_axis,
-    );
-
-Then all that is left is to send this data to the browser.
-
-    $c->response->body( $grid->as_ofc_data );
-  }
-
-=head2 Done!
-
-Now just run C<script/adventofc_server.pl>, point your browser at
-L<http://localhost:3000/>, and celebrate your fancy graphs!
-
-=head3 AUTHOR
-
-Jason Kohles, E<lt>email at jasonkohles.comE<gt>
-
-L<http://www.jasonkohles.com/>
-
-=cut
-

Added: trunk/examples/CatalystAdvent/root/2007/pen/1.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/1.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/1.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,5 @@
+=head1 Day 1 - Catalyst Application Design
+
+=head1 AUTHOR
+
+Jon Rockway

Added: trunk/examples/CatalystAdvent/root/2007/pen/10.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/10.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/10.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,5 @@
+=head1 Day 10 - Rapid CRUD with Catalyst
+
+=head1 AUTHOR
+
+Peter Karman

Added: trunk/examples/CatalystAdvent/root/2007/pen/11.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/11.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/11.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,5 @@
+=head1 Catalyst Base Classes
+
+=head1 AUTHOR
+
+claco

Added: trunk/examples/CatalystAdvent/root/2007/pen/12.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/12.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/12.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,5 @@
+=head1 local::lib and Catalyst
+
+=head1 AUTHOR
+
+John Goulah

Added: trunk/examples/CatalystAdvent/root/2007/pen/15.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/15.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/15.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,252 @@
+=head1 Advanced Search in web DBIx::Class based applications (with tags, full text search and searching by location)
+
+There is a bit of irony that I write that article, for people to learn from it,
+while in fact it is my failing to properly wrap my head around the problem and encapsulate 
+my solution into a CPAN library that forces me to write an article in the first
+place.  But maybe someone smarter then me will read it and write that CPAN
+module?
+
+=head2 The Problem
+
+It is a common case that on a web site you need an 'advanced search' feature
+that let's the user combine simple predicates into more elaborated queries.
+Usually all the predicates are joined with an 'AND' - and the technique I
+describe here is based on this assumption.  At first this task looks pretty
+simple.  You have a list of parameters from the web form, corresponding the the
+columns of some database table, you have the values of those parameters and you
+need to find all the records in that table that have those values in those
+columns.  You just do: 
+
+    my @records = $schema->ResultSet( 'MyTable' )->search( 
+        $reqest->params, 
+        { page => 1, rows => 5 } 
+    );
+
+Simple.
+
+Then of course you add parameter validation and filtering - but this is outside
+of the scope of this article.
+
+Then you need to add checks on columns not only in the searched table, but also
+on columns from related records and things become more complicated.  What I
+propose here is a solution that works for the simple case, solves the related
+tables case, and also is easily extendable to cover more complicated predicates
+like searching by a conjunction of tags, full text searches or searches by
+location. I also add implementation of those 'advanced' predicates (using the
+PostgreSQL extensions for full text search and location based search).
+
+=head2 The Solution
+
+The solution I propose is this simple module:
+
+    package Ymogen2::DB::RSSearchBase;
+    
+    use strict;
+    use warnings;
+    
+    use base qw( DBIx::Class::ResultSet );
+    
+    sub advanced_search {
+        my ( $self, $params, $attrs ) = @_;
+        for my $column ( keys %$params ){
+            if( my $search = $self->can( 'search_for_' . $column ) ){ 
+                $self = $self->$search( $params );
+                next;
+            }
+            my ( $full_name, $relation ) = simple_predicate( $column );
+            my $join;
+            $join = { join => [ $relation ] } if $relation;
+            $self = $self->search( 
+                    { $full_name => $params->{$column} }, 
+                    $join,
+            );
+        }
+        $self = $self->search( {}, $attrs );
+        return (wantarray ? $self->all : $self)
+    }
+
+You use it like that:
+
+    my @records = $schema->ResultSet( 'MyTable' )->advanced_search( 
+        \%search_params, 
+        { page => 1, rows => 5 } 
+    );
+
+But first you need to make your ResultSet class inherit from it.  This can be
+done in several ways, what we do is adding:
+
+    __PACKAGE__->resultset_class(__PACKAGE__ . '::ResultSet');
+    
+    package Ymogen2::DB::Schema::Users::ResultSet;
+
+    use base qw( Ymogen2::DB::RSSearchBase );
+
+
+
+to MyTable.pm.
+
+For the simple case it works just like the familiar 'search' method of the
+L<DBIx::Class::ResultSet class>. But it also works for searching in related
+records.  For that we have the simple_predicate function. It looks like that: 
+
+    sub simple_predicate {
+        my $field = shift;
+        if( $field =~ /(.*?)\.(.*)/ ){
+            my $first = $1;
+            my $rest  = $2;
+            my( $column, $join ) = simple_predicate( $rest );
+            if ( $join ) {
+                return $column, { $first => $join };
+            }else{
+                return $first . '.' . $column, $first;
+            }
+        }elsif( $field ){ 
+            return $field;
+        }else{
+            return;
+        }
+
+What it does is parsing column names of the format:
+'relationship1.relationship2.relationship3.column' into 'relationship3.column'
+- the fully qualified column name and a 
+'{ relationship1 => { relationship2 => relationship3 } }' hash used for joining
+the appriopriate tables.
+
+(I had also a non-recursive version - but it was not simpler)
+
+So now you can do this:
+
+    my @records = $schema->ResultSet( 'MyTable' )->advanced_search( 
+        {
+            column1 => 'value1',
+            column2 => 'value2', 
+            some_relation.column => 'value3',
+            some_other_relation.some_third_relation.column => 'value4', 
+        },
+        { page => 1, rows => 5 }
+    );
+    
+Useful?
+We use it.
+
+=head2 The Extensions
+
+But the real advantage of this approach is how easily it can be extended.  
+
+=head3 Tags
+
+For example let say we need to search by conjunction of tags like that:
+
+    my @records = $schema->ResultSet( 'MyTable' )->advanced_search( {
+        column1 => 'value1',
+        some_other_relation.some_third_relation.column => 'value4',
+        tags => [ qw/ tag1 tag2 tag3/ ],
+    });
+ 
+What we need is a method called 'search_for_tags' that will do the search.  The
+nice thing is that we don't need to warry how this will be combined with the
+rest of the predicates - DBIC will do the right thing (for and 'AND' relation).
+
+Here is the method:
+
+    sub search_for_tags {
+        my ( $self, $params ) = @_;
+        my @tags = @{$params->{tags}};
+        my %search_params;
+        my $suffix = '';
+        my $i = 1;
+        for my $tag ( @tags ){
+            $search_params{'tags' . $suffix .  '.name'} = $tag;
+            $suffix = '_' . ++$i;
+        }
+        my @joins = ( 'tags' ) x scalar( @tags );
+        $self = $self->search( \%search_params, { 
+                join => \@joins,
+            } 
+        );
+        return $self;
+    }
+
+It builds a query like that:
+
+    SELECT * FROM MyTable me, Tags tags, Tags tags_2, Tags tags_3
+    WHERE tags.mytable_id = me.id AND tags.tag = 'tag1' AND
+    tags_2.mytable_id = me.id AND tags_2.tag = 'tag2' AND
+    tags_3.mytable_id = me.id AND tags_3.tag = 'tag3' 
+
+This query will use indices and should be fast (a more detailed cover of this
+technique you can find at my blog at:
+http://perlalchemy.blogspot.com/2006/10/tags-and-search-and-dbixclass.html).
+
+*Attention:* You need the 0.08008 version of DBIx::Class for this to work properly.
+
+=head3 Full Text Search
+
+For full text search I use the PostgreSQL tsearch2 engine here.
+
+=head3 Search by Proximity
+
+For searching by proximity I use the PostgreSQL geometric functions 
+(http://www.postgresql.org/docs/8.2/interactive/functions-geometry.html).
+There is 
+one problem with it - the distance operator assumes planar coordinates, 
+while for the interesting thing is to search geografic data with the standard
+latitude/longitude coordinates.  In our solution we just don't care about
+being exact and just multiply the 'distance' in degrees by 50 to get approximate
+distance in miles.  The actual proportion is about 43 for latitude and 69 for
+longitude at about the London's longitude, it would be possible to get quite 
+good results by dividing the latitude and longitude by those numbers in the
+database - but I would rather have good data in the database then more exact
+results.  Maybe at some point we shell switch to use some real geografic 
+distance functions (I've seen a PosgreSQL extension to do that - but I was
+scared a bit by it's experimental status).
+
+So here is the function used to filter the results by proximity to a place:
+
+sub search_for_distance {
+    my ( $self, $rs, $params ) = @_;
+    my $lat_long = $params->{lat_long};
+    my $distance = $params->{distance} / 50;  
+    # around London the actual proportions are around 43 for latitude 
+    # and 69 for longitude 
+    return $rs->search( 
+        { "(lat_long <-> '$lat_long'::POINT) < " => \$distance },
+        { join => 'location' }
+    );
+}
+
+This function assumes there are two parameters on the $params hash: distance
+and lat_long (lattitude/logintude coordinates).  The location data in our
+database are in a separate table called 'location'.
+
+We also use another search extension:
+
+sub search_for_lat_long {
+    my ( $self, $rs, $params ) = @_;
+    my $lat_long = $params->{lat_long};
+    $rs = $rs->search( undef,        
+        { 
+            join => 'location',
+            '+select' => [ \"(lat_long <-> '$lat_long'::POINT) AS distance" ],
+            '+as' => 'distance',
+            order_by => 'distance ASC',
+        }
+    );
+    return $rs;
+}
+
+This function sorts the results by proximity to the point determined by the
+lat_long coordinates.  This way the user does not need to specify the
+maximum distance - the closest results are displayed on the first pages
+anyway - and that is enough for most of the searches.
+
+=head2 And Beyond
+
+In the search by proximity extension I've used ordering of the results.  There
+is one problem with this.  We use many 'search' calls on the resultset
+to cumulate the predicates - but we cannot do this with the order.  Only the 
+last 'order_by' parameter used in the 'search' calls is effective.  I believe
+it would be useful to have a similar 'cumulative' behaviour for 'order_by' 
+and we can add this to 'advanced_search' (or perhaps it can be added to
+the core DBIC search method).
+

Added: trunk/examples/CatalystAdvent/root/2007/pen/17.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/17.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/17.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,5 @@
+=head1 Catalyst with Ext+Ajax: Editable Data Grids
+
+=head1 AUTHOR
+
+jasonk

Added: trunk/examples/CatalystAdvent/root/2007/pen/2.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/2.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/2.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,244 @@
+=head1 Day 2 - Getting started with ExtJS screen library
+
+Today we take a look at the ExtJS screen library and how to get started
+using it within a Catalyst web application.
+
+Don't forget to come back on Day 17 for a more advanced example by jasonk in 
+"Catalyst with Ext+Ajax: Editable Data Grids" 
+L<http://catalyst.perl.org/calendar/2007/17>
+
+=head2 What is ExtJS?
+
+ExtJS L<http://www.extjs.com/> is a cross-browser Javascript library for web 
+pages. You can use it to achieve Web 2.0 effects without writing too much 
+Javascript code (always a good idea!). It offers abstracted handling for HTML 
+elements, Document Object Model (DOM), event handling and AJAX (client-server) 
+calls. ExtJS also provides styling (blue, aero and Vista, you can write more) 
+and a good selection of widgets including:
+
+=over 2
+
+=item * window
+
+=item * layout
+
+=item * tabs
+
+=item * form
+
+=item * toolbar
+
+=item * menu
+
+=item * tree
+
+=item * combobox
+
+=item * grid
+
+=back 
+
+The full range is listed here L<http://extjs.com/learn/Ext_Extensions>
+
+
+The easiest way to see what is possible is to watch it in action:
+
+=over 2
+
+=item * desktop L<http://extjs.com/deploy/dev/examples/desktop/desktop.html>
+
+=item * feed viewer L<http://extjs.com/deploy/dev/examples/feed-viewer/view.html>
+
+=item * photo organiser L<http://extjs.com/deploy/dev/examples/organizer/organizer.html>
+
+=back
+
+For more examples see L<http://extjs.com/deploy/dev/examples/>
+
+
+
+=head2 What web browsers does it work on?
+
+=over 2
+
+=item * Internet Explorer 6+
+
+=item * Firefox 1.5+ (PC, Mac)
+
+=item * Safari 2+
+
+=item * Opera 9+ (PC, Mac)
+
+=back
+
+=head2 What about other Javascript libraries - I've got legacy code
+
+Because it grew out of Yahoo's YUI library and its developers
+wanted to support legacy code, ExtJS has a tiered design that
+allows you to choose the base Javascript adapter library
+
+=over 2
+
+=item * native Ext
+
+=item * YUI
+
+=item * jQuery
+
+=item * Prototype/Script.aculo.us
+
+=back 
+
+For new code, I'd recommend native Ext as it is faster to load.
+
+There are more details and a pretty picture of the design at
+L<http://extjs.com/learn/Ext_FAQ#What_other_libraries_are_required_to_run_Ext.3F>
+
+
+=head2 Downloading and installing the ExtJS library
+
+Download ExtJS 1.1.1 from L<http://extjs.com/download>
+
+The stable release, used in this article, is 1.1.1 and that's the one you need.
+The latest development release is Ext 2.0 but be aware that it has a different 
+object model to Ext 1.1 and many of the tutorials, docs and code on the site
+still relate to 1.1. 
+Once the widgets and documentation have been done for 2.0 I expect there will 
+be a rapid shift over in the user community.
+More details at L<http://extjs.com/learn/Ext_1_to_2_Migration_Guide>
+
+=head3 Installation
+
+If you're on Linux, install ExtJS to your web server document root, e.g. 
+/var/www/html/ext-1.1. When you want to use it in a Catalyst project create a 
+symbolic link from your root/static directory
+
+ $ ln -s /var/www/html/ext-1.1.1 root/static/
+
+Otherwise, you can simply unzip the whole lot below root/static.
+
+When running the Catalyst test server, it will expect to find the files there.
+
+For production use, use absolute URLs to the ExtJS javascript files from your 
+templates, e.g. http://myserver/ext-1.1.1/ext-core.js, and allow your web server 
+to serve them rather than Catalyst. It's much faster.
+
+=head2 Manuals and learning materials
+
+Visit L<http://extjs.com/learn/>. You will find tutorials at 
+L<http://extjs.com/learn/Tutorials>.
+
+Bookmark and early on read through the community manual 
+L<http://extjs.com/learn/Ext_Manual>.
+
+The archive comes with an ExtJS API reference manual. You can open ext-
+1.1.1/docs/index.html in a browser or if you installed it under your Linux web 
+server root it should be accessible at L<http://myserver/ext-1.1.1/docs/>. It's 
+also online at L<http://extjs.com/deploy/ext/docs/index.html>. Use this to look 
+up methods and attributes for ExtJS objects.
+
+
+=head2 Adding ExtJS to a web page
+
+Firstly you need to include the ExtJS Javascript libraries and stylesheets in 
+the <head> section of your HTML page
+
+ <link rel="stylesheet" type="text/css" href="/ext-1.1/resources/css/ext-all.css" />
+ <script type="text/javascript" src="/ext-1.1/adapter/ext/ext-base.js"></script>
+ <script type="text/javascript" src="/ext-1.1/ext-all.js"></script>
+
+In the body section use classes for styling
+
+ <body class="xtheme-gray" >
+
+Use named <div> tags to identify content that ExtJS will enhance
+
+ <div id="container"><div id="content" class="welcome">
+ ...
+ </div></div>
+
+Then supply Javascript to tell ExtJS what to do. The following creates a layout 
+with one panel called 'content' after the HTML page has finished loading
+
+ <script type="text/javascript">
+ Thescreen = function(){
+   return {
+     init: function(){
+       var layout = new Ext.BorderLayout(document.body, {
+         center: {
+           autoScroll: true,
+           minTabWidth: 50,
+           preferredTabWidth: 150,
+           titlebar: true
+         }
+       });
+            
+       layout.beginUpdate();
+       layout.add('center', new Ext.ContentPanel('content', {title:'ExtJS demo app'}));
+       layout.endUpdate();
+     }  
+   }
+ }();
+ Ext.EventManager.onDocumentReady(Thescreen.init, Thescreen, true);
+ </script>
+
+Note the prototype object-based approach used to create the 'Thescreen' object.
+This helps standardise objects and avoid memory leaks. 
+See L<http://extjs.com/learn/Manual:Intro:Class_Design> for further explanation.
+
+
+=head2 Simple Example
+
+I've provided a simple working example you can use as a starting point for
+writing ExtJS Catalyst applications. It provides code, a menu, a couple of pages
+and a set of templates initially generated using the Catalyst helpers to give
+a portal page.
+
+
+=head2 Example application code
+
+You can check out the code from the Catalyst repository with
+
+ svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/ExtJS
+
+
+=head2 Form Architecture Considerations
+
+You have a choice between implementing traditional "round trip" web pages
+and client-server AJAX dynamic web pages seen on Web 2.0 sites.
+
+In the "round trip" case, the user browses to a page, clicks a submit button to 
+post data to a server, HTML is sent back then the new page displays. You can 
+continue to do this with templates and use ExtJS to enhance the appearance and 
+add auto-completers to input fields.
+
+In the second case, you send HTML back once for the first page and then use 
+ExtJS to respond to events like button clicks to trigger display changes and 
+send/retrieve data to the server via asynchronous data transfers. The ExtJS Form 
+widget L<http://extjs.com/learn/Ext_Manual#Forms> handles this and can 
+automatically perform front-end data validation and display input warnings from 
+the backend. See L<http://extjs.com/deploy/dev/examples/#sample-7> and look at 
+the .js files. It's also possible to generate a form dynamically from an XML or 
+JSON definition in a data source, so you could hold your form definitions in a 
+database and serve them up from a Catalyst data handler.
+
+The choice will depend on how slick a user interface you want and your available 
+time, as writing Javascript can be time-consuming. AJAX screens often look better 
+but are less accessible for blind visitors and can be harder to debug. For 
+testing you would need to consider using a tool like Selenium. Check out 
+L<http://www.infoq.com/articles/testing-ajax-selenium> 
+L<http://www.infoq.com/news/2007/09/selenium-grid-parallel-testing>
+L<http://search.cpan.org/~lukec/Test-WWW-Selenium-1.13/lib/WWW/Selenium.pm>
+
+
+=head2 Comma Gotcha
+
+If you leave a trailing comma in a Javascript data structure, which is very easy 
+to do if you're used to programming Perl, it stops Internet Explorer's parser. 
+You'll get a blank page! It's easily spotted by running your output HTML code 
+through HTML Tidy.
+
+
+=head1 AUTHOR
+
+peterdragon - Peter Edwards <peter at dragonstaff.co.uk>

Added: trunk/examples/CatalystAdvent/root/2007/pen/24.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/24.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/24.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,5 @@
+=head1 This Year in Catalyst
+
+=head1 AUTHOR
+
+kd

Added: trunk/examples/CatalystAdvent/root/2007/pen/3.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/3.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/3.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,184 @@
+=head1 Get more REST - Using YUI and JavaScript for REST
+
+Today, we'll look into building a fully capable REST client in YUI that allows
+record creation, retrieving, updating and deletion (CRUD) as well as searching.
+
+=head2 Start Here First
+
+To make the most of this article, it is important to not only understand the
+basic idea of REST but to also see how it works within Catalyst.
+
+To start out understanding REST, read the excellent article by Ryan Tomayko 
+L<http://tomayko.com/articles/2004/12/12/rest-to-my-wife>, about explaining
+REST in simple terms that a non technical person is able to understand.  It will
+help a technical person understand it even more.
+
+Up next is to get a good understanding for how REST works inside of Catalyst,
+using Adam Jacob's excellent L<Catalyst::Action::REST> package.  The best way
+to get up to speed is to review Day 9 from the 2006 Advent Calendar, at
+L<http://www.catalystframework.org/calendar/2006/9.pod>.
+
+=head2 Following Along
+
+The examples that are listed here are available from the Catalyst subversion
+repository, available via:
+
+ svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/RestYUI
+
+It is a good idea to check out the sources of the sample application to better
+follow along with the examples.  Included is the necessary YUI javascript files
+to enhance this application as you go.
+
+=head2 Why use JavaScript?
+
+The reason why we're required to use JavaScript for a full REST service is
+because of the limited vocabulary that a browser coupled with plain HTML is
+allowed to speak.  The browser will only ever send GET and POST requests in
+response to user interaction with an HTML document.  However, when using the
+C<XmlHttpRequest> method that is a standard in all Grade A browsers the 
+vocabulary is extended to support PUT, DELETE and HEAD.
+
+=head2 The Connection to REST
+
+REST is based off of getting what you ask for.  In the simplest form, an
+C<XmlHttpRequest> isn't enough to talk to a REST webservice.  There are a few
+major components that fit together to make everything work:
+
+=over
+
+=item Content Type
+
+=item Request Method
+
+=item 
+
+=back
+
+=head2 Starting the Catalyst Application
+
+We're taking last year's AdventREST example app and slightly modifying it to
+add support for YUI.
+
+So, to get started you can check out that application from subversion by doing:
+ 
+ svn co http://dev.catalystframework.org/repos/Catalyst/trunk/examples/AdventREST
+
+Or check out the completed RestYUI application.
+
+The only fundamental change to the application is adding the Template Toolkit
+view:
+
+ script/adventrest_create.pl view TT TT
+
+Also, we have to grab the static files for YUI itself.  As of writing this,
+version 2.3.1 is available from L<http://sourceforge.net/project/downloading.php?group_id=165715&filename=yui_2.3.1.zip>.  Check the latest version at
+L<http://developer.yahoo.com/yui/>
+
+After extracting the files from the zip archive, just copy over the .js files to
+the root/static directory.
+
+=head2 Preparing the REST WebService
+
+To gain access to the REST services, we'll be accessing both the C<list> and the
+C<item> actions.  The list is going to be pulled by using a customized YUI
+DataSource object.
+
+This will ask the REST service for a list of our people objects, and in a simple
+form is nothing more than a L<DBIx::Class> search:
+
+   sub user_list_GET {
+       my ( $self, $c ) = @_;
+
+       my %user_list;
+       my $user_rs = $c->model('DB::User')->search;
+       while ( my $user_row = $user_rs->next ) {
+           $user_list{ $user_row->user_id } =
+             $c->uri_for( '/user/' . $user_row->user_id )->as_string;
+       }
+       $self->status_ok( $c, entity => \%user_list );
+   }
+
+That is from the original REST article, and to make the most of the list we're
+going to enhance the listing to provide some additional meta information that 
+enhances the webservice with features such as pagination and other contextual
+information.  We'll add in pagination with a CGI parameter "page" and a param
+for the number of items per page called "per_page"
+
+   sub user_list_GET {
+       my ( $self, $c ) = @_;
+       my $page     = $c->req->params->{page} || 1;
+       my $per_page = $c->req->params->{per_page} || 10;
+
+       # We'll use an array now:
+       my @user_list;
+       my $rs = $c->model('DB::User')
+           ->search(undef, { rows => $per_page })->page( $page );
+       while ( my $user_row = $rs->next ) {
+           push @user_list, {
+               $user_row->get_columns,
+               uri => $c->uri_for( '/user/' . $user_row->user_id )->as_string
+           };
+       }
+
+       $self->status_ok( $c, entity => {
+           result_set => {
+               totalResultsAvailable => $rs->pager->total_entries,
+               totalResultsReturned  => $rs->pager->entries_on_this_page,
+               firstResultPosition   => $rs->pager->current_page,
+               result => [ @user_list ]
+           }
+       });
+   };
+
+So now we have a serialized structure that looks like this in JSON:
+
+=head2 Connecting with YUI
+
+After the webservice is up, it is time to setup the Yahoo DataSource object.
+
+We'll create a simple template off of the index action in C<Root.pm>, so
+create this action in Root.pm:
+
+ sub index : Private {
+     my ( $self, $c ) = @_;
+     $c->forward( $c->view('TT') );
+ }
+
+That will just direct the action for "/" to go to TT, and render an "index.tt"
+template.
+
+The C<index.tt> file is pretty basic, and after the HTML tags this is the crux
+of what gets the job done:
+
+    /* Create the YAHOO.util.DataSource object, the parameter is the
+       URI to your REST service
+    */
+    this.myDataSource = new YAHOO.util.DataSource("[%
+         c.uri_for( c.controller('User').action_for('user_list') ) %]");
+    this.myDataSource.responseType = YAHOO.util.DataSource.TYPE_JSON;
+    this.myDataSource.connXhrMode = "queueRequests";
+    this.myDataSource.responseSchema = {
+    	resultsList: "result_set.result",
+        /* We have to define the fields for usage elsewhere */
+        fields: [
+            "pk1", "token", "default_lang", "languages",
+            "url", "t_created", "t_updated", "actions"
+        ]
+     };
+
+After this, we have a functional DataSource object that can be tied into a
+DataTable:
+
+        myDataTable = new YAHOO.widget.DataTable(
+            "kb_list", myColumnDefs,
+            this.myDataSource, {
+                /* The initialRequest is appended to the URI to set params */
+                initialRequest: "page=1&content-type=text/x-json"
+            }
+        );
+
+=cut
+
+=head1 AUTHOR
+
+J. Shirley

Added: trunk/examples/CatalystAdvent/root/2007/pen/4.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/4.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/4.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,7 @@
+=head1 Catalyst Configuration
+
+=head1 AUTHOR
+
+???
+
+jayk?

Added: trunk/examples/CatalystAdvent/root/2007/pen/5.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/5.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/5.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,5 @@
+=head1 $c->uri_for fun
+
+=head1 AUTHOR
+
+purge

Added: trunk/examples/CatalystAdvent/root/2007/pen/6.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/6.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/6.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,5 @@
+=head1 Mango Overview
+
+=head1 AUTHOR 
+
+claco

Added: trunk/examples/CatalystAdvent/root/2007/pen/7.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/7.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/7.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,5 @@
+=head1 Catalyst Authentication
+
+=head1 AUTHOR
+
+jayk

Added: trunk/examples/CatalystAdvent/root/2007/pen/8.pod
===================================================================
--- trunk/examples/CatalystAdvent/root/2007/pen/8.pod	                        (rev 0)
+++ trunk/examples/CatalystAdvent/root/2007/pen/8.pod	2007-12-01 21:33:28 UTC (rev 7189)
@@ -0,0 +1,235 @@
+
+=head1 Catalyst + Open Flash Chart: Fancy graphs with minimal fuss
+
+=head2 About Open Flash Chart
+
+Open Flash Chart is a flash application that prudoces some very nice-looking,
+interactive (and in some cases animated) charts and graphs for your web
+application.  It's also completely free and open source, released under the
+GNU General Public License.
+
+For examples of the kinds of graphs you can produce, visit the home page
+at L<http://teethgrinder.co.uk/open-flash-chart/>.
+
+=head2 Getting Started
+
+This tutorial assumes you already have some Catalyst experience, so we won't
+go into too much detail with the basics of creating an application...
+
+  % catalyst.pl AdventOFC
+  ...
+  % cd AdventOFC
+  ...
+  % script/adventofc_create.pl view TT TTSite
+  ...
+
+=head2 Installing Chart::OFC
+
+The Open Flash Chart application uses a difficult to work with format for it's
+data structure.  Fortunately the perl community has guys like Dave Rolsky, who
+recently made a nice perl library called L<Chart::OFC> that makes it easier to
+work with.  We're going to install L<Chart::OFC> first, because it includes the
+pieces you need from Open Flash Chart, so you only need to download once...
+
+Assuming you are using L<CPANPLUS>, you can install it like this...
+
+  % cpanp
+  ...
+  CPAN Terminal> i Chart::OFC
+  
+  Installing Chart::OFC (0.02)
+  ...
+  Module 'Chart::OFC' installed successfully
+  No errors installing all modules
+  
+  CPAN Terminal> q
+
+Once you have it installed, you need to get the .swf file and copy it into
+your application root directory.  If you installed from L<CPANPLUS>, something
+like the following will work.
+
+  % cd root/static
+  % unzip ~/.cpanplus/*/build/Chart-OFC-*/ofc/*.zip open-flash-chart.swf
+
+If you don't have the L<Chart::OFC> source directory any more, you can
+download the .swf from the Open Flash Chart web site at
+L<http://teethgrinder.co.uk/open-flash-chart/download.php>.
+
+Whether you use the copy from the L<Chart::OFC> source directory, or download
+it from the web site, you will get a .zip file that includes the source as
+well as adapter libraries for various langages.  You only need the .swf file
+from the archive though, you won't need any of the other files.
+
+=head2 Adding Open Flash Chart support to your application
+
+Now that you have a basic application, we'll add some charting capabilities
+with OpenFlashChart.  The HTML code required to embed a chart is long and
+repetitive, so I like to make a component template to do the boring work
+for me.  Create a file in root/lib called 'ofc_swf_object' with the
+following contents:
+
+  [%
+    DEFAULT
+        width    = '500'
+        height   = '300'
+        id       = 'ofc_chart'
+        bgcolor  = '#FFFFFF'
+        name     = 'ofc_chart';
+
+    SET swf_url = Catalyst.uri_for( 
+        '/static/open-flash-chart.swf',
+        {
+            width  = width
+            height = height
+            data   = data
+        }
+    );
+
+    # This is just to keep the html below from being
+    # too wide for the sake of the demo, you could always
+    # just put this inline if you wanted
+    SET cab_download = [
+        'http://fpdownload.macromedia.com'
+        '/pub/shockwave/cabs/flash/swflash.cab'
+        '#version=8,0,0,0'
+    ];
+  %]
+  [% FILTER collapse %]
+  <object
+    classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
+    codebase="[% cab_download.join( '' ) %]"
+    width="[% width %]" height="[% height %]"
+    id="[% id %]" align="middle">
+      <param name="allowScriptAccess" value="sameDomain" />
+      <param name="movie" value="[% swf_url %]" />
+      <param name="quality" value="high" />
+      <param name="bgcolor" value="[% bgcolor %]" />
+      <embed
+        src="[% swf_url %]" quality="high"
+        bgcolor="[% bgcolor %]" width="[% width %]"
+        height="[% height %]" name="[% name %]"
+        align="middle" allowScriptAccess="sameDomain"
+        type="application/x-shockwave-flash"
+        pluginspage="http://www.macromedia.com/go/getflashplayer"
+      />
+  </object>
+  [% END %]
+
+You might notice that there are two copies of basically every configuration
+parameter in this block of code.  Like many other things on the web, this is
+because Internet Explorer does it one way (the object part) and everything
+else does it differently (with embed.)
+
+=head2 Using your new Open Flash Chart tools
+
+Now that you have the support pieces you need, it's time to put them to use.
+For the purposes of the demo we're just going to add charts to the home page
+of the application, so we'll be editing the Root controller.  To get started,
+add a method to the root controller for the index page...
+
+  =head2 index
+  
+  The index page for our charts.
+  
+  =cut
+  
+  sub index : Private {
+      my ( $self, $c ) = @_;
+  
+      $c->stash->{ 'template' } = 'index.tt2';
+  }
+
+Next we need to create a template to go along with the index.  Since we took
+the time to setup a helper template, this one will be rather small.  Put this
+code into your root/src/index.tt2.
+
+  [% INCLUDE ofc_swf_object data = Catalyst.uri_for( '/graph' ) %]
+
+If you run script/adventofc_server.pl at this point, you should get a nice
+graph display, although it won't contain any data.  In order to get nice
+charts, we need to move onto the next step, the data!
+
+=head2 Generating appropriate data
+
+Next we need to create a controller to produce the appropriate graph
+information.  Edit the root controller again, add a new method for the
+graph data (make sure you add C<use Chart::OFC> to the top of your
+controller as well.)
+
+  =head2 graph
+  
+  Data provider for Open Flash Chart graphs.
+  
+  =cut
+  
+  sub graph : Local {
+    my ( $self, $c ) = @_;
+
+Open Flash Chart can display pie charts, lines and/or bars on a grid, and
+area charts on a grid.  You can determine which types of graphs to use by
+which L<Chart::OFC::Dataset> subclasses you provide your data to.  For
+the purposes of this demo, we'll create a chart with lines, but first we
+need some sample data.
+
+    my %data = (
+        Date    => [ map { "11/$_" } 1 .. 14 ],
+        Ninja   => [ map { int( rand( 10 ) ) } 1 .. 14 ],
+        Pirate  => [ map { int( rand( 10 ) ) } 1 .. 14 ],
+    );
+
+For each data point you want to graph, you create an object that is an
+instance of one of the L<Chart::OFC::Dataset> subclasses.
+
+    my $ninjas = Chart::OFC::Dataset::LineWithDots->new(
+        color       => 'black',
+        label       => 'Ninjas',
+        solid_dots  => 0,
+        values      => $data{ 'Ninja' },
+    );
+    my $pirates = Chart::OFC::Dataset::LineWithDots->new(
+        color       => 'red',
+        label       => 'Pirates',
+        solid_dots  => 1,
+        values      => $data{ 'Pirate' },
+    );
+
+Once you have your datasets, you need to create X and Y axis objects that
+provide the information necessary to label the graph.
+
+    my $x_axis = Chart::OFC::XAxis->new(
+        axis_label  => 'Date',
+        labels      => $data{ 'Date' },
+    );
+    my $y_axis = Chart::OFC::YAxis->new(
+        axis_label  => 'Sightings',
+        max         => 11,
+        label_steps => 1,
+    );
+
+Now that all the pieces are assembled, we can use them to build a graph.
+
+    my $grid = Chart::OFC::Grid->new(
+        title       => 'Observer Reports',
+        datasets    => [ $ninjas, $pirates ],
+        x_axis      => $x_axis,
+        y_axis      => $y_axis,
+    );
+
+Then all that is left is to send this data to the browser.
+
+    $c->response->body( $grid->as_ofc_data );
+  }
+
+=head2 Done!
+
+Now just run C<script/adventofc_server.pl>, point your browser at
+L<http://localhost:3000/>, and celebrate your fancy graphs!
+
+=head3 AUTHOR
+
+Jason Kohles, E<lt>email at jasonkohles.comE<gt>
+
+L<http://www.jasonkohles.com/>
+
+=cut
+


Property changes on: trunk/examples/CatalystAdvent/root/2007/pen/8.pod
___________________________________________________________________
Name: keywords
   + Id Author Rev Date URL
Name: svn:eol-style
   + native




More information about the Catalyst-commits mailing list