[kune-commits] r1010 - in trunk/src/main: java/org/ourproject/kune/app/server rails/publicspace/app/controllers rails/publicspace/app/models rails/publicspace/app/views/layouts rails/publicspace/db/migrate rails/publicspace/public rails/publicspace/public/templates rails/publicspace/public/templates/basic rails/publicspace/test/fixtures rails/publicspace/test/unit webapp webapp/WEB-INF/gems/bin webapp/WEB-INF/gems/cache webapp/WEB-INF/gems/gems webapp/WEB-INF/gems/gems/hoe-1.8.2 webapp/WEB-INF/gems/gems/hoe-1.8.2/bin webapp/WEB-INF/gems/gems/hoe-1.8.2/lib webapp/WEB-INF/gems/gems/hoe-1.8.2/test webapp/WEB-INF/gems/gems/liquid-1.9.0 webapp/WEB-INF/gems/gems/liquid-1.9.0/example webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/templates webapp/WEB-INF/gems/gems/liquid-1.9.0/lib webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/extras webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags webapp/WEB-INF/gems/gems/liquid-1.9.0/test webapp/WEB-INF/gems/gems/liquid-1.9.0/test/extra webapp/WEB-INF/gems/gems/rubyforge-1.0.1 webapp/WEB-INF/gems/gems/rubyforge-1.0.1/bin webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test webapp/WEB-INF/gems/specifications

dani matas danigb at ourproject.org
Sun Dec 21 17:12:18 CET 2008


Author: danigb
Date: 2008-12-21 17:12:07 +0100 (Sun, 21 Dec 2008)
New Revision: 1010

Added:
   trunk/src/main/rails/publicspace/app/models/container.rb
   trunk/src/main/rails/publicspace/app/models/templater.rb
   trunk/src/main/rails/publicspace/db/migrate/20081221140600_create_containers.rb
   trunk/src/main/rails/publicspace/public/templates/
   trunk/src/main/rails/publicspace/public/templates/basic/
   trunk/src/main/rails/publicspace/public/templates/basic/basic.css
   trunk/src/main/rails/publicspace/public/templates/basic/docs.liquid.html
   trunk/src/main/rails/publicspace/test/fixtures/containers.yml
   trunk/src/main/rails/publicspace/test/unit/container_test.rb
   trunk/src/main/webapp/WEB-INF/gems/bin/rubyforge
   trunk/src/main/webapp/WEB-INF/gems/bin/sow
   trunk/src/main/webapp/WEB-INF/gems/cache/hoe-1.8.2.gem
   trunk/src/main/webapp/WEB-INF/gems/cache/liquid-1.9.0.gem
   trunk/src/main/webapp/WEB-INF/gems/cache/rubyforge-1.0.1.gem
   trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/
   trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/History.txt
   trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/Manifest.txt
   trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/README.txt
   trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/Rakefile
   trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/bin/
   trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/bin/sow
   trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/lib/
   trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/lib/hoe.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/test/
   trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/test/test_hoe.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/CHANGELOG
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/History.txt
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/MIT-LICENSE
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/Manifest.txt
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/README.txt
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/Rakefile
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/example_servlet.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/liquid_servlet.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/server.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/templates/
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/templates/index.liquid
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/templates/products.liquid
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/init.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/extras/
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/extras/liquid_view.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/block.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/condition.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/context.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/document.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/drop.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/errors.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/extensions.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/file_system.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/htmltags.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/module_ex.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/standardfilters.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/strainer.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tag.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/assign.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/capture.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/case.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/comment.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/cycle.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/for.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/if.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/ifchanged.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/include.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/unless.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/template.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/variable.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/block_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/condition_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/context_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/drop_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/error_handling_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/extra/
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/extra/breakpoint.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/extra/caller.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/file_system_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/filter_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/helper.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/html_tag_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/if_else_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/include_tag_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/module_ex_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/output_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/parsing_quirks_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/regexp_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/security_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/standard_filter_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/standard_tag_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/statements_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/strainer_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/template_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/test_helper.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/unless_else_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/variable_test.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/History.txt
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/Manifest.txt
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/README.txt
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/Rakefile
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/bin/
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/bin/rubyforge
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge/
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge/client.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge/cookie_manager.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test/
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test/test_rubyforge.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test/test_rubyforge_client.rb
   trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test/test_rubyforge_cookie_manager.rb
   trunk/src/main/webapp/WEB-INF/gems/specifications/hoe-1.8.2.gemspec
   trunk/src/main/webapp/WEB-INF/gems/specifications/liquid-1.9.0.gemspec
   trunk/src/main/webapp/WEB-INF/gems/specifications/rubyforge-1.0.1.gemspec
   trunk/src/main/webapp/templates
Modified:
   trunk/src/main/java/org/ourproject/kune/app/server/KuneRackModule.java
   trunk/src/main/rails/publicspace/app/controllers/application.rb
   trunk/src/main/rails/publicspace/app/controllers/contents_controller.rb
   trunk/src/main/rails/publicspace/app/controllers/kunedbg_controller.rb
   trunk/src/main/rails/publicspace/app/models/content.rb
   trunk/src/main/rails/publicspace/app/views/layouts/kunedbg.html.erb
Log:
liquid templates on public side (rails)

Modified: trunk/src/main/java/org/ourproject/kune/app/server/KuneRackModule.java
===================================================================
--- trunk/src/main/java/org/ourproject/kune/app/server/KuneRackModule.java	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/java/org/ourproject/kune/app/server/KuneRackModule.java	2008-12-21 16:12:07 UTC (rev 1010)
@@ -90,9 +90,10 @@
 	builder.exclude("/http-bind.*");
 	builder.exclude("/services/fileupload.*");
 	builder.exclude("/public/.*");
-	// builder.exclude("/images/.*");
-	// builder.exclude("/stylesheets/.*");
-	// builder.exclude("/javascripts/.*");
+	builder.exclude("/images/.*");
+	builder.exclude("/stylesheets/.*");
+	builder.exclude("/javascripts/.*");
+	builder.exclude("/templates/.*");
 	builder.at(".*").install(new LogFilter());
 	builder.at(".*").install(new GuiceFilter());
 

Modified: trunk/src/main/rails/publicspace/app/controllers/application.rb
===================================================================
--- trunk/src/main/rails/publicspace/app/controllers/application.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/rails/publicspace/app/controllers/application.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -12,4 +12,9 @@
   # Uncomment this to filter the contents of submitted sensitive data parameters
   # from your application log (in this case, all fields with names like "password"). 
   # filter_parameter_logging :password
+
+  def template(template, tool, ctx)
+    @templater ||= Templater.new
+    render :text => @templater.render(template, tool, ctx)
+  end
 end

Modified: trunk/src/main/rails/publicspace/app/controllers/contents_controller.rb
===================================================================
--- trunk/src/main/rails/publicspace/app/controllers/contents_controller.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/rails/publicspace/app/controllers/contents_controller.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -1,10 +1,11 @@
 class ContentsController < ApplicationController
-
+  
   def show
     @group = Group.find_by_shortName!(params[:group])
     @tool = params[:tool]
     @folder = params[:folder]
     @content = params[:content]
+
+    template(:basic, :docs,  { "content" => Content.find(params[:content]) } )
   end
-
 end

Modified: trunk/src/main/rails/publicspace/app/controllers/kunedbg_controller.rb
===================================================================
--- trunk/src/main/rails/publicspace/app/controllers/kunedbg_controller.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/rails/publicspace/app/controllers/kunedbg_controller.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -12,6 +12,17 @@
   def model_types
     MODELS.keys
   end
+
+  def find
+    content = Content.find params[:id]
+    tool = 'doc'
+    group = content.container.owner
+    folder = content.container.id
+    redirect_to :controller => 'contents', :action => 'show',
+      :tool => tool, :group => group.shortName, :folder => folder.id, :content => content.id
+  rescue ActiveRecord::RecordNotFound
+    redirect_to :action => 'index'
+  end
   
   def list
     @mclass = MODELS[params[:model].to_sym]

Added: trunk/src/main/rails/publicspace/app/models/container.rb
===================================================================
--- trunk/src/main/rails/publicspace/app/models/container.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/rails/publicspace/app/models/container.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,4 @@
+class Container < ActiveRecord::Base
+  has_many :contents
+  belongs_to :owner, :class_name => 'Group', :foreign_key => 'owner_id'
+end

Modified: trunk/src/main/rails/publicspace/app/models/content.rb
===================================================================
--- trunk/src/main/rails/publicspace/app/models/content.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/rails/publicspace/app/models/content.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -1,3 +1,25 @@
+
+require 'liquid'
+
 class Content < ActiveRecord::Base
   belongs_to :last_revision, :class_name => 'Revision', :foreign_key => 'lastRevision_id'
+  belongs_to :container
+
+  def to_liquid
+    return ContentDrop.new(self)
+  end
 end
+
+class ContentDrop < Liquid::Drop
+  def initialize(content)
+    @content = content
+  end
+
+  def title
+    @content.last_revision.title
+  end
+
+  def body
+    @content.last_revision.body
+  end
+end

Added: trunk/src/main/rails/publicspace/app/models/templater.rb
===================================================================
--- trunk/src/main/rails/publicspace/app/models/templater.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/rails/publicspace/app/models/templater.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,52 @@
+
+require 'liquid'
+
+module KuneTemplates
+  FILE_ROOT = "#{RAILS_ROOT}/public/templates"
+  URL_ROOT = "/templates"
+end
+
+module KuneDrops
+  class DocumentDrop < Liquid::Drop
+    
+  end
+end
+
+module KuneTags
+  class Asset < Liquid::Tag
+    def initialize(tag_name, name, tokens)
+      super
+      @name = name
+    end
+
+    def render(context)
+      %Q(<link href="#{context['url_root']}/#{@name}" media="screen" rel="stylesheet" type="text/css" />)
+    end
+  end
+end
+
+module KuneFilters
+  include KuneTemplates
+
+  #FIXME: inject the template name!!!!!!!!!!
+  def asset(name)
+    "#{URL_ROOT}/basic/#{name}"
+  end
+end
+
+class Templater
+  include KuneTemplates
+  
+  def initialize
+    Liquid::Template.register_filter(KuneFilters)
+    Liquid::Template.register_tag('asset', KuneTags::Asset)
+    @parsed = {}
+  end
+
+  def render(template, tool, ctx)
+    file = "#{FILE_ROOT}/#{template}/#{tool}.liquid.html"
+    tmpl = File.read file
+    parsed = Liquid::Template.parse(tmpl)
+    parsed.render({"url_root" => "#{URL_ROOT}/#{template}"}.merge ctx)
+  end
+end

Modified: trunk/src/main/rails/publicspace/app/views/layouts/kunedbg.html.erb
===================================================================
--- trunk/src/main/rails/publicspace/app/views/layouts/kunedbg.html.erb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/rails/publicspace/app/views/layouts/kunedbg.html.erb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -27,6 +27,7 @@
         <% for mtype in  model_types -%>
           <li><%= link_to mtype, :action => 'list', :model => mtype %></li>
         <% end -%>
+        <li>contenido por id:<br/><% form_tag :action => 'find' do  -%><%= text_field_tag 'id' %><% end -%></li>
       </ul>
       <div class="content">
         <%= yield %>

Added: trunk/src/main/rails/publicspace/db/migrate/20081221140600_create_containers.rb
===================================================================
--- trunk/src/main/rails/publicspace/db/migrate/20081221140600_create_containers.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/rails/publicspace/db/migrate/20081221140600_create_containers.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,12 @@
+class CreateContainers < ActiveRecord::Migration
+  def self.up
+    create_table :containers do |t|
+
+      t.timestamps
+    end
+  end
+
+  def self.down
+    drop_table :containers
+  end
+end

Added: trunk/src/main/rails/publicspace/public/templates/basic/basic.css
===================================================================
--- trunk/src/main/rails/publicspace/public/templates/basic/basic.css	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/rails/publicspace/public/templates/basic/basic.css	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,7 @@
+
+html {background-color: #D6FF2F;}
+
+.page {width: 60em; margin: 2em auto; padding: 1em; background-color: #fff; overflow: hidden;}
+h1 { color: black; font-size:3em; letter-spacing:-0.05em; line-height:1em; margin:1em 0 0.5em 4em; }
+.page .menu {float: left; padding: 1em; width: 9em; background-color: #efefef; margin-right: 1em;}
+.page .content {}
\ No newline at end of file

Added: trunk/src/main/rails/publicspace/public/templates/basic/docs.liquid.html
===================================================================
--- trunk/src/main/rails/publicspace/public/templates/basic/docs.liquid.html	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/rails/publicspace/public/templates/basic/docs.liquid.html	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,17 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+"http://www.w3.org/TR/html4/strict.dtd">
+<html>
+    <head>
+        <title>Kune cositas</title>
+        <link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.6.0/build/reset/reset-min.css">
+        <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js" type="text/javascript"></script>
+        <link rel="stylesheet" type="text/css" href="{{ 'basic.css' | asset }}">
+    </head>
+    <body>
+        <div class="page">
+            <h1>{{ content.title }}</h1>
+            <div class="menu">aquí va el menu</div>
+            <div class="content">{{ content.body }}</div>
+        </div>
+    </body>
+</html>

Added: trunk/src/main/rails/publicspace/test/fixtures/containers.yml
===================================================================
--- trunk/src/main/rails/publicspace/test/fixtures/containers.yml	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/rails/publicspace/test/fixtures/containers.yml	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,7 @@
+# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
+
+# one:
+#   column: value
+#
+# two:
+#   column: value

Added: trunk/src/main/rails/publicspace/test/unit/container_test.rb
===================================================================
--- trunk/src/main/rails/publicspace/test/unit/container_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/rails/publicspace/test/unit/container_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,8 @@
+require 'test_helper'
+
+class ContainerTest < ActiveSupport::TestCase
+  # Replace this with your real tests.
+  test "the truth" do
+    assert true
+  end
+end

Added: trunk/src/main/webapp/WEB-INF/gems/bin/rubyforge
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/bin/rubyforge	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/bin/rubyforge	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,19 @@
+#!/usr/bin/ruby1.8
+#
+# This file was generated by RubyGems.
+#
+# The application 'rubyforge' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require 'rubygems'
+
+version = ">= 0"
+
+if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
+  version = $1
+  ARGV.shift
+end
+
+gem 'rubyforge', version
+load 'rubyforge'


Property changes on: trunk/src/main/webapp/WEB-INF/gems/bin/rubyforge
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/src/main/webapp/WEB-INF/gems/bin/sow
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/bin/sow	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/bin/sow	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,19 @@
+#!/usr/bin/ruby1.8 -ws
+#
+# This file was generated by RubyGems.
+#
+# The application 'hoe' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require 'rubygems'
+
+version = ">= 0"
+
+if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
+  version = $1
+  ARGV.shift
+end
+
+gem 'hoe', version
+load 'sow'


Property changes on: trunk/src/main/webapp/WEB-INF/gems/bin/sow
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/src/main/webapp/WEB-INF/gems/cache/hoe-1.8.2.gem
===================================================================
(Binary files differ)


Property changes on: trunk/src/main/webapp/WEB-INF/gems/cache/hoe-1.8.2.gem
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/src/main/webapp/WEB-INF/gems/cache/liquid-1.9.0.gem
===================================================================
(Binary files differ)


Property changes on: trunk/src/main/webapp/WEB-INF/gems/cache/liquid-1.9.0.gem
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/src/main/webapp/WEB-INF/gems/cache/rubyforge-1.0.1.gem
===================================================================
(Binary files differ)


Property changes on: trunk/src/main/webapp/WEB-INF/gems/cache/rubyforge-1.0.1.gem
___________________________________________________________________
Name: svn:mime-type
   + application/octet-stream

Added: trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/History.txt
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/History.txt	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/History.txt	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,280 @@
+=== 1.8.2 / 2008-10-24:
+
+* 1 minor enhancement:
+
+  * Now asks Inline for known inlined classes if you package w/ INLINE=1.
+
+=== 1.8.1 / 2008-10-22
+
+* 1 bug fix:
+
+  * Fixes for windows compatibility from Luis Lavena.
+
+=== 1.8.0 / 2008-10-09
+
+* 5 minor enhancements:
+
+  * Added Hoe.add_include_dirs to make setting up rake deps easier.
+  * Removed unused optional group arg in sow.
+  * Added testlib variable so you can specify what test library to use.
+  * Added deps:list to help you review dependent projects.
+  * Added deps:email to help you communicate with dependent projects.
+  * Added deps:fetch to help you search through dependent projects.
+
+=== 1.7.0 / 2008-06-30
+
+* 3 minor enhancements:
+
+  * Use rdoc 2.x gem if available. Eric likes his backslashes.
+  * Added extra_dev_deps for new rubygems developer dependencies.
+    * Switched hoe to dev dep. Fork off, bitches.
+  * Finally got a sane test that does something. Hey... it's a start.
+
+=== 1.6.0 / 2008-06-18
+
+* 1 minor enhancement
+
+  * blog categories! Defaults to array with project's name. Thanks Aaron!
+
+=== 1.5.3 / 2008-05-20
+
+* 1 Bug Fix
+
+  * hoe really really needs better tests. I suck. :/
+
+=== 1.5.2 / 2008-05-20
+
+* 4 Minor Enhancements:
+
+  * Added multiruby_skip attribute for 'rake multi' version invalidation.
+  * Improved error messages when files are missing.
+  * Added rubygems post_install_message accessor. Thanks to Dr. Nic.
+  * Cleaned up alternative_name... I didn't get it.
+
+* 1 Bug Fix:
+
+  * Removed require of rake/contrib/sshpublisher to fix 1.9.
+
+=== 1.5.1 / 2008-03-04
+
+* 2 Minor Enhancements:
+
+  * Removed install/uninstall tasks. Too buggy. Gems do a better job.
+  *	Added cleaning of rbc files to default list
+
+* 5 Bug Fixes:
+
+  * Correctly deal with errors intuiting history and readme files. Thanks Aaron!
+  * Fixed rdoc title. Thanks, Sander!
+  * Fixed sow to match new Rakefile and History format. Thanks, me!
+  *	Moved test/unit to the front for rake test. Fixes use of miniunit.
+  * Renamed shadowed variable.
+
+=== 1.5.0 / 2008-01-30
+
+* 9 Minor Enhancements:
+
+  * Added autopopulation of changes from History.txt.
+  * Added autopopulation of urls from History.txt.
+  * Added autopopulation of description from History.txt
+  * Added autopopulation of summary from description.
+  * Added description_sections to declare what sections of readme to use.
+  * Added summary_sentences to declare how many sentences you want in summary.
+  * Added developer(name, email) to cleanly populate both author/email arrays.
+  * author and email now default to "doofus".
+  * author and email warn that they'll blow up on 2008-04-01.
+
+=== 1.4.0 / 2007-12-20
+
+* 1 Major Enhancement:
+
+  * rake package now supports INLINE=1 and FORCE_PLATFORM=whatever.
+    * Supports ruby_inline extensions.
+    * Contributed by Luis Lavena. Thanks Luis!
+
+=== 1.3.0 / 2007-08-13
+
+* 1 Major Enhancement:
+
+  * Hoe now builds signed gems automatically.  Run the generate_key task to
+    automatically create a signing key.
+
+* 4 Minor Enhancements:
+
+  * Extended rdoc pattern to include ext dirs.
+  * Fixed dependency adding for versionless dependencies.
+  * Added NODOT env var to disable RDoc diagram generation.
+  * The config_hoe task automatically merges in new config entries.
+
+=== 1.2.2 / 2007-07-23
+
+* 2 Minor Enhancements:
+
+  * Added exclude parameter for check_manifest filtering to .hoerc.
+  * Documented .hoerc stuffs.
+
+* 1 Bug Fix:
+
+  * Various (untested) fixes for windows compatibility.
+
+=== 1.2.1 / 2007-05-21
+
+* 8 Minor Enhancements:
+
+  * Allow for spaces in filenames in manifest. Thanks to Aaron Patterson.
+  * Allow rsync flags to be set.
+  * Allow rdoc destination directory to be set.
+  * Deal with bad line-endings. Stupid windoze users... :(
+  * Added WINDOZE check for diff.exe and look for gdiff first.
+  * Use gdiff if available, diff otherwise. Allows to work on borked Solaris.
+  * Move RDoc to attr* from big 'ol chunk at the top of the class.
+  * Basic conversion of history/urls from rdoc to markdown.
+
+* 1 Bug Fix:
+
+  * Fixed executables regexp to /^bin/.
+
+=== 1.2.0 / 2007-02-13
+
+* 4 Minor Enhancements:
+
+  * Added more support for ext dirs.
+  * Added a simple config file (yaml). Use 'rake config_hoe' to edit.
+  * Added post_blog task (thanks Aaron!), configured via config_hoe.
+  * Announce task now posts to your blogs and/or publishes API
+    depending on config.
+
+=== 1.1.7 / 2007-01-10
+
+* 5 Minor Enhancements:
+
+  * extra_deps is now self-healing, and ensures no (direct) cycles.
+  * cleans check_manifest for CVS projects.
+  * rubyforge changes for config.
+  * Now uses rsync for publish_docs. YAY for fast!
+  * Bug #7193 fix spelling of 'synopsys'.  Submitted by Jacob Atzen.
+
+=== 1.1.6 / 2006-11-29
+
+* 1 Bug Fix:
+
+  * Fix release to work correctly with need_zip and need_tar.
+
+=== 1.1.5 / 2006-11-29
+
+* 2 Minor Enhancements:
+
+  * Reduced check_manifest dependencies to just diff for windows.
+  * Don't use default author in summary, description or changes.
+
+=== 1.1.4 / 2006-11-12
+
+* 3 Minor Enhancements:
+
+  * Added need_tar and need_zip to customize package requirements. Stupid windoze.
+  * Extended spec_extras to take procs as values. Passes in named parameter.
+  * Removed test from require_paths. I thought I already parameterized this. :/
+
+=== 1.1.3 / 2006-11-09
+
+* 6 Minor Enhancements:
+
+  * Added test_deps, now you can automatically discover test dependency ommisions.
+  * Added ext support! Build C extensions with hoe!
+  * Gemspec uses test_all.rb or result of test_globs. Tweak those tests.
+  * Now uses https to login to rubyforge. Rubyforge crackers beware!
+  * Fixed doco and automated updating of it.
+  * Added rdoc_pattern. Go doco go!
+
+=== 1.1.2 / 2006-10-22
+
+* 4 Minor Enhancements:
+
+  * Added -d and -t flags to sow to make dev or trunk subdirs for p4
+    and svn projects.
+  * Added install_gem to further test gem builds.
+  * Added test_globs to customize your test file list.
+  * Removed demo.rb from clean_globs. I'm torn on this one.
+
+* 1 Bug Fix:
+
+  * Fixed bug in install rule.
+
+=== 1.1.1 / 2006-10-11
+
+* 2 Bug Fixes:
+
+  * Fixed minor problem with subject of email.
+  * Fixed problem in test.
+
+=== 1.1.0 / 2006-10-04
+
+* 1 Major Enhancement:
+
+  * Added sow, a command-line tool for quickly creating new projects.
+
+* 1 Minor Enhancement:
+
+  * Added check_manifest task
+
+=== 1.0.5 / 2006-10-03
+
+* 8 Minor Enhancements:
+
+  * Doco cleanup.
+  * Removed Manifest.txt from rdoc and added title.
+  * Added changeset support.
+  * Added spec_extras for easy gemspec attribute setting.
+  * Added release_notes, changeset setting for releases.
+  * Added paragraphs_of utility method.
+  * Added email and rubyforge news announcement tasks.
+  * Url attribute may now be an array of urls.
+
+=== 1.0.4 / 2006-09-23
+
+* 1 Bug Fix:
+
+  * Damnit... I messed up. There is no rubygems gem to be dependent upon. Duh.
+
+=== 1.0.3 / 2006-09-23
+
+* 9 Minor Enhancements:
+
+  * Added debug_gem rule.
+  * Added lots of doco.
+  * Added proper deps to hoe for other's gems, and
+    rake/rubyforge/rubygems for hoe.
+  * Added ridocs to generate ri locally for testing.
+  * Added support for multiple authors.
+  * Rdoc now includes any top level .txt files.
+  * Renamed deploy to release.
+  * Renamed upload to publish_docs.
+  * publish_docs is now smart about subprojects and missing subdirectories.
+
+* 1 Bug Fix:
+
+  * Fixed include paths.
+
+=== 1.0.2 / 2006-09-20
+
+* 2 Minor Enhancements:
+
+  * Wee little tests.
+  * Fixed up gemspec's require_paths.
+
+=== 1.0.1 / 2006-09-20
+
+* 5 Minor Enhancements:
+
+  * Finally got deployment straightened out. Maybe. Some might be on
+    rubyforge.org.
+  * Added default description and summary.
+  * Added dependency mechanism.
+  * Improved gemspec debugging.
+  * Swapped gem with tgz in deploy... we'd rather screw up on tgz
+
+=== 1.0.0 / 2006-09-19
+
+* 1 Major Enhancement:
+
+  * Birthday!

Added: trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/Manifest.txt
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/Manifest.txt	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/Manifest.txt	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,7 @@
+History.txt
+Manifest.txt
+README.txt
+Rakefile
+bin/sow
+lib/hoe.rb
+test/test_hoe.rb

Added: trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/README.txt
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/README.txt	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/README.txt	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,95 @@
+= Hoe
+
+* http://rubyforge.org/projects/seattlerb/
+* http://seattlerb.rubyforge.org/hoe/
+* mailto:ryand-ruby at zenspider.com
+
+== DESCRIPTION:
+
+Hoe is a simple rake/rubygems helper for project Rakefiles. It
+generates all the usual tasks for projects including rdoc generation,
+testing, packaging, and deployment.
+
+Tasks Provided:
+
+* announce         - Create news email file and post to rubyforge.
+* audit            - Run ZenTest against the package.
+* check_manifest   - Verify the manifest.
+* clean            - Clean up all the extras.
+* config_hoe       - Create a fresh ~/.hoerc file.
+* debug_gem        - Show information about the gem.
+* default          - Run the default tasks.
+* deps:email       - Print a contact list for gems dependent on this gem
+* deps:fetch       - Fetch all the dependent gems of this gem into tarballs
+* deps:list        - List all the dependent gems of this gem
+* docs             - Build the docs HTML Files
+* email            - Generate email announcement file.
+* gem              - Build the gem file hoe-1.8.0.gem
+* generate_key     - Generate a key for signing your gems.
+* install_gem      - Install the package as a gem.
+* multi            - Run the test suite using multiruby.
+* package          - Build all the packages
+* post_blog        - Post announcement to blog.
+* post_news        - Post announcement to rubyforge.
+* publish_docs     - Publish RDoc to RubyForge.
+* release          - Package and upload the release to rubyforge.
+* ridocs           - Generate ri locally for testing.
+* tasks            - Generate a list of tasks for doco.
+* test             - Run the test suite.
+* test_deps        - Show which test files fail when run alone.
+
+See class rdoc for help. Hint: ri Hoe
+
+== FEATURES/PROBLEMS:
+
+* Provides 'sow' for quick project directory creation.
+* Make making and maintaining Rakefiles fun and easy.
+
+== SYNOPSIS:
+
+  % sow [group] project
+
+or
+
+  require 'hoe'
+  
+  Hoe.new(projectname, version) do |p|
+    # ... project specific data ...
+  end
+
+  # ... project specific tasks ...
+
+== REQUIREMENTS:
+
+* rake
+* rubyforge
+* rubygems
+
+== INSTALL:
+
+* sudo gem install hoe
+
+== LICENSE:
+
+(The MIT License)
+
+Copyright (c) Ryan Davis, Zen Spider Software
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Added: trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/Rakefile
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/Rakefile	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/Rakefile	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,28 @@
+# -*- ruby -*-
+
+require './lib/hoe.rb'
+
+Hoe.new("hoe", Hoe::VERSION) do |hoe|
+  hoe.rubyforge_name = "seattlerb"
+
+  hoe.developer("Ryan Davis", "ryand-ruby at zenspider.com")
+
+  hoe.blog_categories << "Seattle.rb" << "Ruby"
+end
+
+desc "Generate a list of tasks for doco. RDOC=1 for commented output"
+task :tasks do
+  tasks = `rake -T`.scan(/rake (\w+)\s+# (.*)/)
+  tasks.reject! { |t,d| t =~ /^(clobber|tasks|re(package|docs))/ }
+  max   = tasks.map { |x,y| x.size }.max
+
+  tasks.each do |t,d|
+    if ENV['RDOC'] then
+      puts "# %-#{max+2}s %s" % [t + "::", d]
+    else
+      puts "* %-#{max}s - %s" % [t, d]
+    end
+  end
+end
+
+# vim: syntax=Ruby

Added: trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/bin/sow
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/bin/sow	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/bin/sow	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,74 @@
+#!/usr/bin/env ruby -ws
+
+$t ||= false
+$d ||= false
+
+if defined? $h then
+  puts "usage: #{File.dirname($0)} [-d|-t] project"
+  puts "  -t = add project to subdir under 'trunk'"
+  puts "  -d = add project to subdir under 'dev'"
+end
+
+abort "You must specify only one of -t or -d" if $t and $d
+
+project = ARGV.shift
+
+# prevents false positives on my tag reporter
+X = 'FI' + 'X'
+
+abort "You must supply a project name on the commandline" unless project
+abort "Project #{project} seems to exist" if test ?d, project
+puts "creating project #{project}"
+
+case project
+when /_/ then
+  file_name = project
+  project = project.capitalize.gsub(/_([a-z])/) {$1.upcase}
+  klass = project
+else
+  file_name = project.gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, '')
+  klass = project.capitalize.gsub(/_([a-z])/) {$1.upcase}
+end
+
+Dir.mkdir project
+Dir.chdir project do
+
+  if $d then
+    Dir.mkdir "dev"
+    Dir.chdir "dev"
+  elsif $t then
+    Dir.mkdir "trunk"
+    Dir.chdir "trunk"
+  end
+
+  %w(bin lib test).each do |path|
+    Dir.mkdir path
+  end
+
+  files = {
+    "History.txt" => "=== 1.0.0 / #{Time.new.strftime("%Y-%m-%d")}\n\n* 1 major enhancement\n\n  * Birthday!\n\n",
+    "README.txt" => "= #{project}\n\n* #{X} (url)\n\n== DESCRIPTION:\n\n#{X} (describe your package)\n\n== FEATURES/PROBLEMS:\n\n* #{X} (list of features or problems)\n\n== SYNOPSIS:\n\n  #{X} (code sample of usage)\n\n== REQUIREMENTS:\n\n* #{X} (list of requirements)\n\n== INSTALL:\n\n* #{X} (sudo gem install, anything else)\n\n== LICENSE:\n\n(The MIT License)\n\nCopyright (c) #{Time.new.strftime("%Y")} #{X}\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n",
+    "Manifest.txt" => "",
+    "bin/#{file_name}" => "",
+    "lib/#{file_name}.rb" => "class #{klass}\n  VERSION = '1.0.0'\nend",
+    "test/test_#{file_name}.rb" => "",
+    "Rakefile" => "# -*- ruby -*-\n\nrequire 'rubygems'\nrequire 'hoe'\nrequire './lib/#{file_name}.rb'\n\nHoe.new('#{project}', #{klass}::VERSION) do |p|\n  # p.rubyforge_name = '#{project}x' # if different than lowercase project name\n  # p.developer('#{X}', '#{X}@example.com')\nend\n\n# vim: syntax=Ruby\n"
+  }
+
+  files["Manifest.txt"] = files.keys.sort.join("\n")
+
+  files.each do |file, content|
+    File.open(file, "w") do |f|
+      f.write content
+    end
+  end
+end
+
+WINDOZE = /mswin|mingw/ =~ RUBY_PLATFORM
+
+puts "... done, now go fix all occurrences of '#{X}'"
+if WINDOZE then
+  puts `findstr /N /S /C:#{X} #{project}\\*`
+else
+  puts `find #{project} -type f | xargs grep -n #{X}`.gsub(/\A|\n/, "\n  ")
+end


Property changes on: trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/bin/sow
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/lib/hoe.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/lib/hoe.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/lib/hoe.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,1030 @@
+# -*- ruby -*-
+
+require 'rubygems'
+require 'rake'
+require 'rake/gempackagetask'
+require 'rake/rdoctask'
+require 'rake/testtask'
+require 'rbconfig'
+require 'rubyforge'
+require 'yaml'
+
+begin
+  gem 'rdoc'
+rescue Gem::LoadError
+end
+
+##
+# hoe - a tool to help rake
+#
+# Hoe is a simple rake/rubygems helper for project Rakefiles. It
+# generates all the usual tasks for projects including rdoc generation,
+# testing, packaging, and deployment.
+#
+# == Using Hoe
+#
+# === Basics
+#
+# Use this as a minimal starting point:
+#
+#   require 'hoe'
+#
+#   Hoe.new("project_name", '1.0.0') do |p|
+#     p.rubyforge_name = "rf_project"
+#     # add other details here
+#   end
+#
+#   # add other tasks here
+#
+# === Tasks Provided:
+#
+# announce::          Create news email file and post to rubyforge.
+# audit::             Run ZenTest against the package.
+# check_manifest::    Verify the manifest.
+# clean::             Clean up all the extras.
+# config_hoe::        Create a fresh ~/.hoerc file.
+# debug_gem::         Show information about the gem.
+# default::           Run the default tasks.
+# deps:email::        Print a contact list for gems dependent on this gem
+# deps:fetch::        Fetch all the dependent gems of this gem into tarballs
+# deps:list::         List all the dependent gems of this gem
+# docs::              Build the docs HTML Files
+# email::             Generate email announcement file.
+# gem::               Build the gem file hoe-1.8.0.gem
+# generate_key::      Generate a key for signing your gems.
+# install_gem::       Install the package as a gem.
+# multi::             Run the test suite using multiruby.
+# package::           Build all the packages
+# post_blog::         Post announcement to blog.
+# post_news::         Post announcement to rubyforge.
+# publish_docs::      Publish RDoc to RubyForge.
+# release::           Package and upload the release to rubyforge.
+# ridocs::            Generate ri locally for testing.
+# tasks::             Generate a list of tasks for doco.
+# test::              Run the test suite.
+# test_deps::         Show which test files fail when run alone.
+#
+# === Extra Configuration Options:
+#
+# Run +config_hoe+ to generate a new ~/.hoerc file. The file is a
+# YAML formatted config file with the following settings:
+#
+# exclude::             A regular expression of files to exclude from
+#                       +check_manifest+.
+# publish_on_announce:: Run +publish_docs+ when you run +release+.
+# signing_key_file::    Signs your gems with this private key.
+# signing_cert_file::   Signs your gem with this certificate.
+# blogs::               An array of hashes of blog settings.
+#
+# Run +config_hoe+ and see ~/.hoerc for examples.
+#
+# === Signing Gems:
+#
+# Run the 'generate_key' task.  This will:
+#
+# 1. Configure your ~/.hoerc.
+# 2. Generate a signing key and certificate.
+# 3. Install the private key and public certificate files into ~/.gem.
+# 4. Upload the certificate to RubyForge.
+#
+# Hoe will now generate signed gems when the package task is run.  If you have
+# multiple machines you build gems on, be sure to install your key and
+# certificate on each machine.
+#
+# Keep your private key secret!  Keep your private key safe!
+#
+# To make sure your gems are signed run:
+#
+#   rake package; tar tf pkg/yourproject-1.2.3.gem
+#
+# If your gem is signed you will see:
+#
+#   data.tar.gz
+#   data.tar.gz.sig
+#   metadata.gz
+#   metadata.gz.sig
+#
+# === Platform awareness
+#
+# Hoe allows bundling of pre-compiled extensions in the +package+ task.
+#
+# To create a package for your current platform:
+#
+#   rake package INLINE=1
+#
+# This will force Hoe analize your +Inline+ already compiled
+# extensions and include them in your gem.
+#
+# If somehow you need to force a specific platform:
+#
+#   rake package INLINE=1 FORCE_PLATFORM=mswin32
+#
+# This will set the +Gem::Specification+ platform to the one indicated in
+# +FORCE_PLATFORM+ (instead of default Gem::Platform::CURRENT)
+#
+
+class Hoe
+  VERSION = '1.8.2'
+  GEMURL = URI.parse 'http://gems.rubyforge.org' # for namespace :deps below
+
+  ruby_prefix = Config::CONFIG['prefix']
+  sitelibdir = Config::CONFIG['sitelibdir']
+
+  ##
+  # Used to specify a custom install location (for rake install).
+
+  PREFIX = ENV['PREFIX'] || ruby_prefix
+
+  ##
+  # Used to add extra flags to RUBY_FLAGS.
+
+  RUBY_DEBUG = ENV['RUBY_DEBUG']
+
+  default_ruby_flags = "-w -I#{%w(lib ext bin test).join(File::PATH_SEPARATOR)}" +
+    (RUBY_DEBUG ? " #{RUBY_DEBUG}" : '')
+
+  ##
+  # Used to specify flags to ruby [has smart default].
+
+  RUBY_FLAGS = ENV['RUBY_FLAGS'] || default_ruby_flags
+
+  ##
+  # Used to add flags to test_unit (e.g., -n test_borked).
+
+  FILTER = ENV['FILTER'] # for tests (eg FILTER="-n test_blah")
+
+  # :stopdoc:
+
+  RUBYLIB = if PREFIX == ruby_prefix then
+              sitelibdir
+            else
+              File.join(PREFIX, sitelibdir[ruby_prefix.size..-1])
+            end
+
+  DLEXT = Config::CONFIG['DLEXT']
+
+  WINDOZE = /mswin|mingw/ =~ RUBY_PLATFORM unless defined? WINDOZE
+
+  DIFF = if WINDOZE
+           'diff.exe'
+         else
+           if system("gdiff", __FILE__, __FILE__)
+             'gdiff' # solaris and kin suck
+           else
+             'diff'
+           end
+         end unless defined? DIFF
+
+  # :startdoc:
+
+  ##
+  # *Recommended*: The author(s) of the package. (can be array)
+  # Really. Set this or we'll tease you.
+
+  attr_accessor :author
+
+  ##
+  # Populated automatically from the manifest. List of executables.
+
+  attr_accessor :bin_files # :nodoc:
+
+  ##
+  # *Optional*: An array of the project's blog categories. Defaults to project name.
+
+  attr_accessor :blog_categories
+
+  ##
+  # Optional: A description of the release's latest changes. Auto-populates.
+
+  attr_accessor :changes
+
+  ##
+  # Optional: An array of file patterns to delete on clean.
+
+  attr_accessor :clean_globs
+
+  ##
+  # Optional: A description of the project. Auto-populates.
+
+  attr_accessor :description
+
+  ##
+  # Optional: What sections from the readme to use for auto-description. Defaults to %w(description).
+
+  attr_accessor :description_sections
+
+  ##
+  # *Recommended*: The author's email address(es). (can be array)
+
+  attr_accessor :email
+
+  ##
+  # Optional: An array of rubygem dependencies.
+
+  attr_accessor :extra_deps
+
+  ##
+  # Optional: An array of rubygem developer dependencies.
+
+  attr_accessor :extra_dev_deps
+
+  ##
+  # Populated automatically from the manifest. List of library files.
+
+  attr_accessor :lib_files # :nodoc:
+
+  ##
+  # Optional: Array of incompatible versions for multiruby filtering. Used as a regex.
+
+  attr_accessor :multiruby_skip
+
+  ##
+  # *MANDATORY*: The name of the release.
+
+  attr_accessor :name
+
+  ##
+  # Optional: Should package create a tarball? [default: true]
+
+  attr_accessor :need_tar
+
+  ##
+  # Optional: Should package create a zipfile? [default: false]
+
+  attr_accessor :need_zip
+
+  ##
+  # Optional: A post-install message to be displayed when gem is installed.
+
+  attr_accessor :post_install_message
+
+  ##
+  # Optional: A regexp to match documentation files against the manifest.
+
+  attr_accessor :rdoc_pattern
+
+  ##
+  # Optional: Name of RDoc destination directory on Rubyforge. [default: +name+]
+
+  attr_accessor :remote_rdoc_dir
+
+  ##
+  # Optional: Flags for RDoc rsync. [default: "-av --delete"]
+
+  attr_accessor :rsync_args
+
+  ##
+  # Optional: The name of the rubyforge project. [default: name.downcase]
+
+  attr_accessor :rubyforge_name
+
+  ##
+  # The Gem::Specification.
+
+  attr_accessor :spec # :nodoc:
+
+  ##
+  # Optional: A hash of extra values to set in the gemspec. Value may be a proc.
+
+  attr_accessor :spec_extras
+
+  ##
+  # Optional: A short summary of the project. Auto-populates.
+
+  attr_accessor :summary
+
+  ##
+  # Optional: Number of sentences from description for summary. Defaults to 1.
+
+  attr_accessor :summary_sentences
+
+  ##
+  # Populated automatically from the manifest. List of tests.
+
+  attr_accessor :test_files # :nodoc:
+
+  ##
+  # Optional: An array of test file patterns [default: test/**/test_*.rb]
+
+  attr_accessor :test_globs
+
+  ##
+  # Optional: What test library to require [default: test/unit]
+
+  attr_accessor :testlib
+
+  ##
+  # Optional: The url(s) of the project. (can be array). Auto-populates.
+
+  attr_accessor :url
+
+  ##
+  # *MANDATORY*: The version. Don't hardcode! use a constant in the project.
+
+  attr_accessor :version
+
+  ##
+  # Add extra dirs to both $: and RUBY_FLAGS (for test runs)
+
+  def self.add_include_dirs(*dirs)
+    dirs = dirs.flatten
+    $:.unshift(*dirs)
+    s = File::PATH_SEPARATOR
+    Hoe::RUBY_FLAGS.sub!(/-I/, "-I#{dirs.join(s)}#{s}")
+  end
+
+  def normalize_deps deps
+    Array(deps).map { |o| String === o ? [o] : o }
+  end
+
+  def missing name
+    warn "** #{name} is missing or in the wrong format for auto-intuiting."
+    warn "   run `sow blah` and look at its text files"
+  end
+
+  def initialize(name, version) # :nodoc:
+    self.name = name
+    self.version = version
+
+    # Defaults
+    self.author = []
+    self.clean_globs = %w(diff diff.txt email.txt ri deps .source_index
+                          *.gem *~ **/*~ *.rbc **/*.rbc)
+    self.description_sections = %w(description)
+    self.blog_categories = [name]
+    self.email = []
+    self.extra_deps = []
+    self.extra_dev_deps = []
+    self.multiruby_skip = []
+    self.need_tar = true
+    self.need_zip = false
+    self.rdoc_pattern = /^(lib|bin|ext)|txt$/
+    self.remote_rdoc_dir = name
+    self.rsync_args = '-av --delete'
+    self.rubyforge_name = name.downcase
+    self.spec_extras = {}
+    self.summary_sentences = 1
+    self.test_globs = ['test/**/test_*.rb']
+    self.testlib = 'test/unit'
+    self.post_install_message = nil
+
+    yield self if block_given?
+
+    # Intuit values:
+
+    readme   = File.read("README.txt").split(/^(=+ .*)$/)[1..-1] rescue ''
+    unless readme.empty? then
+      sections = readme.map { |s|
+        s =~ /^=/ ? s.strip.downcase.chomp(':').split.last : s.strip
+      }
+      sections = Hash[*sections]
+      desc = sections.values_at(*description_sections).join("\n\n")
+      summ = desc.split(/\.\s+/).first(summary_sentences).join(". ")
+
+      self.description ||= desc
+      self.summary ||= summ
+      self.url ||= readme[1].gsub(/^\* /, '').split(/\n/).grep(/\S+/)
+    else
+      missing 'README.txt'
+    end
+
+    self.changes ||= begin
+                       h = File.read("History.txt")
+                       h.split(/^(===.*)/)[1..2].join.strip
+                     rescue
+                       missing 'History.txt'
+                       ''
+                     end
+
+    %w(email author).each do |field|
+      value = self.send(field)
+      if value.nil? or value.empty? then
+        if Time.now < Time.local(2008, 4, 1) then
+          warn "Hoe #{field} value not set - Fix by 2008-04-01!"
+          self.send "#{field}=", "doofus"
+        else
+          abort "Hoe #{field} value not set. aborting"
+        end
+      end
+    end
+
+    hoe_deps = {
+      'rake' => ">= #{RAKEVERSION}",
+      'rubyforge' => ">= #{::RubyForge::VERSION}",
+    }
+
+    self.extra_deps     = normalize_deps extra_deps
+    self.extra_dev_deps = normalize_deps extra_dev_deps
+
+    if name == 'hoe' then
+      hoe_deps.each do |pkg, vers|
+        extra_deps << [pkg, vers]
+      end
+    else
+      extra_dev_deps << ['hoe', ">= #{VERSION}"] unless hoe_deps.has_key? name
+    end
+
+    define_tasks
+  end
+
+  def developer name, email
+    self.author << name
+    self.email << email
+  end
+
+  def with_config # :nodoc:
+    rc = File.expand_path("~/.hoerc")
+    exists = File.exist? rc
+    config = exists ? YAML.load_file(rc) : {}
+    yield(config, rc)
+  end
+
+  def define_tasks # :nodoc:
+    desc 'Run the default tasks.'
+    task :default => :test
+
+    desc 'Run the test suite. Use FILTER to add to the command line.'
+    task :test do
+      run_tests
+    end
+
+    desc 'Show which test files fail when run alone.'
+    task :test_deps do
+      tests = Dir["test/**/test_*.rb"]  +  Dir["test/**/*_test.rb"]
+
+      paths = ['bin', 'lib', 'test'].join(File::PATH_SEPARATOR)
+      null_dev = WINDOZE ? '> NUL 2>&1' : '&> /dev/null'
+
+      tests.each do |test|
+        if not system "ruby -I#{paths} #{test} #{null_dev}" then
+          puts "Dependency Issues: #{test}"
+        end
+      end
+    end
+
+    desc 'Run the test suite using multiruby.'
+    task :multi do
+      run_tests :multi
+    end
+
+    ############################################################
+    # Packaging and Installing
+
+    signing_key = nil
+    cert_chain = []
+
+    with_config do |config, path|
+      break unless config['signing_key_file'] and config['signing_cert_file']
+      key_file = File.expand_path config['signing_key_file'].to_s
+      signing_key = key_file if File.exist? key_file
+
+      cert_file = File.expand_path config['signing_cert_file'].to_s
+      cert_chain << cert_file if File.exist? cert_file
+    end
+
+    self.spec = Gem::Specification.new do |s|
+      s.name = name
+      s.version = version
+      s.summary = summary
+      case author
+      when Array
+        s.authors = author
+      else
+        s.author = author
+      end
+      s.email = email
+      s.homepage = Array(url).first
+      s.rubyforge_project = rubyforge_name
+
+      s.description = description
+
+      extra_deps.each do |dep|
+        s.add_dependency(*dep)
+      end
+
+      extra_dev_deps.each do |dep|
+        s.add_development_dependency(*dep)
+      end
+
+      s.files = File.read("Manifest.txt").delete("\r").split(/\n/)
+      s.executables = s.files.grep(/^bin/) { |f| File.basename(f) }
+
+      s.bindir = "bin"
+      dirs = Dir['{lib,ext}']
+      s.require_paths = dirs unless dirs.empty?
+
+      s.rdoc_options = ['--main', 'README.txt']
+      s.extra_rdoc_files = s.files.grep(/txt$/)
+      s.has_rdoc = true
+
+      s.post_install_message = post_install_message
+
+      if test ?f, "test/test_all.rb" then
+        s.test_file = "test/test_all.rb"
+      else
+        s.test_files = Dir[*test_globs]
+      end
+
+      if signing_key and cert_chain then
+        s.signing_key = signing_key
+        s.cert_chain = cert_chain
+      end
+
+      ############################################################
+      # Allow automatic inclusion of compiled extensions
+      if ENV['INLINE'] then
+        s.platform = ENV['FORCE_PLATFORM'] || Gem::Platform::CURRENT
+
+        # Try collecting Inline extensions for +name+
+        if defined?(Inline) then
+          directory 'lib/inline'
+
+          Inline.registered_inline_classes.each do |cls|
+            name = cls.name # TODO: what about X::Y::Z?
+            # name of the extension is CamelCase
+            alternate_name = if name =~ /[A-Z]/ then
+                               name.gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, '')
+                             elsif name =~ /_/ then
+                               name.capitalize.gsub(/_([a-z])/) { $1.upcase }
+                             end
+
+            extensions = Dir.chdir(Inline::directory) {
+              Dir["Inline_{#{name},#{alternate_name}}_*.#{DLEXT}"]
+            }
+
+            extensions.each do |ext|
+              # add the inlined extension to the spec files
+              s.files += ["lib/inline/#{ext}"]
+
+              # include the file in the tasks
+              file "lib/inline/#{ext}" => ["lib/inline"] do
+                cp File.join(Inline::directory, ext), "lib/inline"
+              end
+            end
+          end
+        end
+      end
+
+      # Do any extra stuff the user wants
+      spec_extras.each do |msg, val|
+        case val
+        when Proc
+          val.call(s.send(msg))
+        else
+          s.send "#{msg}=", val
+        end
+      end
+    end
+
+    desc 'Show information about the gem.'
+    task :debug_gem do
+      puts spec.to_ruby
+    end
+
+    self.lib_files = spec.files.grep(/^(lib|ext)/)
+    self.bin_files = spec.files.grep(/^bin/)
+    self.test_files = spec.files.grep(/^test/)
+
+    Rake::GemPackageTask.new spec do |pkg|
+      pkg.need_tar = @need_tar
+      pkg.need_zip = @need_zip
+    end
+
+    desc 'Install the package as a gem.'
+    task :install_gem => [:clean, :package] do
+      gem = Dir['pkg/*.gem'].first
+      sh "#{'sudo ' unless WINDOZE}gem install --local #{gem}"
+    end
+
+    desc 'Package and upload the release to rubyforge.'
+    task :release => [:clean, :package] do |t|
+      v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
+      abort "Versions don't match #{v} vs #{version}" if v != version
+      pkg = "pkg/#{name}-#{version}"
+
+      if $DEBUG then
+        puts "release_id = rf.add_release #{rubyforge_name.inspect}, #{name.inspect}, #{version.inspect}, \"#{pkg}.tgz\""
+        puts "rf.add_file #{rubyforge_name.inspect}, #{name.inspect}, release_id, \"#{pkg}.gem\""
+      end
+
+      rf = RubyForge.new.configure
+      puts "Logging in"
+      rf.login
+
+      c = rf.userconfig
+      c["release_notes"] = description if description
+      c["release_changes"] = changes if changes
+      c["preformatted"] = true
+
+      files = [(@need_tar ? "#{pkg}.tgz" : nil),
+               (@need_zip ? "#{pkg}.zip" : nil),
+               "#{pkg}.gem"].compact
+
+      puts "Releasing #{name} v. #{version}"
+      rf.add_release rubyforge_name, name, version, *files
+    end
+
+    ############################################################
+    # Doco
+
+    Rake::RDocTask.new(:docs) do |rd|
+      rd.main = "README.txt"
+      rd.options << '-d' if
+        `which dot` =~ /\/dot/ unless ENV['NODOT'] unless WINDOZE
+      rd.rdoc_dir = 'doc'
+      files = spec.files.grep(rdoc_pattern)
+      files -= ['Manifest.txt']
+      rd.rdoc_files.push(*files)
+
+      title = "#{name}-#{version} Documentation"
+      title = "#{rubyforge_name}'s " + title if rubyforge_name != name
+
+      rd.options << "-t #{title}"
+    end
+
+    desc 'Generate ri locally for testing.'
+    task :ridocs => :clean do
+      sh %q{ rdoc --ri -o ri . }
+    end
+
+    desc 'Publish RDoc to RubyForge.'
+    task :publish_docs => [:clean, :docs] do
+      config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
+      host = "#{config["username"]}@rubyforge.org"
+
+      remote_dir = "/var/www/gforge-projects/#{rubyforge_name}/#{remote_rdoc_dir}"
+      local_dir = 'doc'
+
+      sh %{rsync #{rsync_args} #{local_dir}/ #{host}:#{remote_dir}}
+    end
+
+    # no doco for this one
+    task :publish_on_announce do
+      with_config do |config, _|
+        Rake::Task['publish_docs'].invoke if config["publish_on_announce"]
+      end
+    end
+
+    ############################################################
+    # Dependencies:
+
+    namespace :deps do
+      require 'zlib' # HACK for rubygems 1.3.0
+      require 'rubygems/remote_fetcher'
+
+      @@index = nil
+
+      def self.get_source_index
+        return @@index if @@index
+
+        dump = unless File.exist? '.source_index' then
+                 url = GEMURL + "Marshal.#{Gem.marshal_version}.Z"
+                 dump = Gem::RemoteFetcher.fetcher.fetch_path url
+                 dump = Gem.inflate dump
+                 open '.source_index', 'wb' do |io| io.write dump end
+                 dump
+               else
+                 open '.source_index', 'rb' do |io| io.read end
+               end
+
+        @@index = Marshal.load dump
+      end
+
+      def self.get_latest_gems
+        @@cache ||= get_source_index.latest_specs
+      end
+
+      def self.get_gems_by_name
+        @@by_name ||= Hash[*get_latest_gems.map { |gem|
+                             [gem.name, gem, gem.full_name, gem]
+                           }.flatten]
+      end
+
+      def self.dependent_upon name
+        get_latest_gems.find_all { |gem|
+          gem.dependencies.any? { |dep| dep.name == name }
+        }
+      end
+
+
+      desc "List all the dependent gems of this gem"
+      task :list do
+        gems = self.get_gems_by_name
+        gem  = gems[self.name]
+
+        abort "Couldn't find gem: #{self.name}" unless gem
+
+        deps = self.dependent_upon self.name
+        max  = deps.map { |s| s.full_name.size }.max
+
+        puts "  dependents:"
+        unless deps.empty? then
+          deps.sort_by { |spec| spec.full_name }.each do |spec|
+            vers = spec.dependencies.find {|s| s.name == name }.requirement_list
+            puts "    %-*s - %s" % [max, spec.full_name, vers.join(", ")]
+          end
+        else
+          puts "    none"
+        end
+      end
+
+      desc "Print a contact list for gems dependent on this gem"
+      task :email do
+        gems = self.get_gems_by_name
+        gem  = gems[self.name]
+
+        abort "Couldn't find gem: #{self.name}" unless gem
+
+        deps = self.dependent_upon self.name
+
+        email = deps.map { |s| s.email }.flatten.sort.uniq
+        email = email.map { |s| s.split(/,\s*/) }.flatten.sort.uniq
+
+        email.map! { |s| # don't you people realize how easy this is?
+          s.gsub(/ at | _at_ |\s*(atmark|@nospam@|-at?-|@at?@|<at?>|\[at?\]|\(at?\))\s*/i, '@').gsub(/\s*(dot|\[d(ot)?\]|\.dot\.)\s*/i, '.').gsub(/\s+com$/, '.com')
+        }
+
+        bad, good = email.partition { |e| e !~ /^[\w.+-]+\@[\w.+-]+$/ }
+
+        warn "Rejecting #{bad.size} email. I couldn't unmunge them." unless
+          bad.empty?
+
+        puts good.join(", ")
+      end
+
+      desc "Fetch all the dependent gems of this gem into tarballs"
+      task :fetch do
+        gems = self.get_gems_by_name
+        gem  = gems[self.name]
+        deps = self.dependent_upon self.name
+
+        mkdir "deps" unless File.directory? "deps"
+        Dir.chdir "deps" do
+          begin
+            deps.sort_by { |spec| spec.full_name }.each do |spec|
+              full_name = spec.full_name
+              tgz_name  = "#{full_name}.tgz"
+              gem_name  = "#{full_name}.gem"
+
+              next if File.exist? tgz_name
+              FileUtils.rm_rf [full_name, gem_name]
+
+              begin
+                warn "downloading #{full_name}"
+                Gem::RemoteFetcher.fetcher.download(spec, GEMURL, Dir.pwd)
+                FileUtils.mv "cache/#{gem_name}", '.'
+              rescue Gem::RemoteFetcher::FetchError
+                warn "  failed"
+                next
+              end
+
+              warn "converting #{gem_name} to tarball"
+
+              system "gem unpack #{gem_name} 2> /dev/null"
+              system "gem spec -l #{gem_name} > #{full_name}/gemspec.rb"
+              system "tar zmcf #{tgz_name} #{full_name}"
+              FileUtils.rm_rf [full_name, gem_name, "cache"]
+            end
+          ensure
+            FileUtils.rm_rf "cache"
+          end
+        end
+      end
+    end
+
+    ############################################################
+    # Misc/Maintenance:
+
+    desc 'Run ZenTest against the package.'
+    task :audit do
+      libs = %w(lib test ext).join(File::PATH_SEPARATOR)
+      sh "zentest -I=#{libs} #{spec.files.grep(/^(lib|test)/).join(' ')}"
+    end
+
+    desc 'Clean up all the extras.'
+    task :clean => [ :clobber_docs, :clobber_package ] do
+      clean_globs.each do |pattern|
+        files = Dir[pattern]
+        rm_rf files, :verbose => true unless files.empty?
+      end
+    end
+
+    desc 'Create a fresh ~/.hoerc file.'
+    task :config_hoe do
+      with_config do |config, path|
+        default_config = {
+          "exclude" => /tmp$|CVS|\.svn/,
+          "publish_on_announce" => false,
+          "signing_key_file" => "~/.gem/gem-private_key.pem",
+          "signing_cert_file" => "~/.gem/gem-public_cert.pem",
+          "blogs" => [ {
+                         "user" => "user",
+                         "url" => "url",
+                         "extra_headers" => {
+                           "mt_convert_breaks" => "markdown"
+                         },
+                         "blog_id" => "blog_id",
+                         "password"=>"password",
+                       } ],
+        }
+        File.open(path, "w") do |f|
+          YAML.dump(default_config.merge(config), f)
+        end
+
+        editor = ENV['EDITOR'] || 'vi'
+        system "#{editor} #{path}" if ENV['SHOW_EDITOR'] != 'no'
+      end
+    end
+
+    desc 'Generate email announcement file.'
+    task :email do
+      require 'rubyforge'
+      subject, title, body, urls = announcement
+
+      File.open("email.txt", "w") do |mail|
+        mail.puts "Subject: [ANN] #{subject}"
+        mail.puts
+        mail.puts title
+        mail.puts
+        mail.puts urls
+        mail.puts
+        mail.puts body
+        mail.puts
+        mail.puts urls
+      end
+      puts "Created email.txt"
+    end
+
+    desc 'Post announcement to blog.'
+    task :post_blog do
+      require 'xmlrpc/client'
+
+      with_config do |config, path|
+        break unless config['blogs']
+
+        subject, title, body, urls = announcement
+        body += "\n\n#{urls}"
+
+        config['blogs'].each do |site|
+          server = XMLRPC::Client.new2(site['url'])
+          content = site['extra_headers'].merge(:title => title,
+                                                :description => body,
+                                                :categories => blog_categories)
+
+          result = server.call('metaWeblog.newPost',
+                               site['blog_id'],
+                               site['user'],
+                               site['password'],
+                               content,
+                               true)
+        end
+      end
+    end
+
+    desc 'Post announcement to rubyforge.'
+    task :post_news do
+      require 'rubyforge'
+      subject, title, body, urls = announcement
+
+      rf = RubyForge.new.configure
+      rf.login
+      rf.post_news(rubyforge_name, subject, "#{title}\n\n#{body}")
+      puts "Posted to rubyforge"
+    end
+
+    desc 'Create news email file and post to rubyforge.'
+    task :announce => [:email, :post_news, :post_blog, :publish_on_announce ]
+
+    desc 'Verify the manifest.'
+    task :check_manifest => :clean do
+      f = "Manifest.tmp"
+      require 'find'
+      files = []
+      with_config do |config, _|
+        exclusions = config["exclude"]
+        abort "exclude entry missing from .hoerc. Aborting." if exclusions.nil?
+        Find.find '.' do |path|
+          next unless File.file? path
+          next if path =~ exclusions
+          files << path[2..-1]
+        end
+        files = files.sort.join "\n"
+        File.open f, 'w' do |fp| fp.puts files end
+        system "#{DIFF} -du Manifest.txt #{f}"
+        rm f
+      end
+    end
+
+    desc 'Generate a key for signing your gems.'
+    task :generate_key do
+      email = spec.email
+      abort "No email in your gemspec" if email.nil? or email.empty?
+
+      key_file = with_config { |config, _| config['signing_key_file'] }
+      cert_file = with_config { |config, _| config['signing_cert_file'] }
+
+      if key_file.nil? or cert_file.nil? then
+        ENV['SHOW_EDITOR'] ||= 'no'
+        Rake::Task['config_hoe'].invoke
+
+        key_file = with_config { |config, _| config['signing_key_file'] }
+        cert_file = with_config { |config, _| config['signing_cert_file'] }
+      end
+
+      key_file = File.expand_path key_file
+      cert_file = File.expand_path cert_file
+
+      unless File.exist? key_file or File.exist? cert_file then
+        sh "gem cert --build #{email}"
+        mv "gem-private_key.pem", key_file, :verbose => true
+        mv "gem-public_cert.pem", cert_file, :verbose => true
+
+        puts "Installed key and certificate."
+
+        rf = RubyForge.new.configure
+        rf.login
+
+        cert_package = "#{rubyforge_name}-certificates"
+
+        begin
+          rf.lookup 'package', cert_package
+        rescue
+          rf.create_package rubyforge_name, cert_package
+        end
+
+        begin
+          rf.lookup('release', cert_package)['certificates']
+          rf.add_file rubyforge_name, cert_package, 'certificates', cert_file
+        rescue
+          rf.add_release rubyforge_name, cert_package, 'certificates', cert_file
+        end
+
+        puts "Uploaded certificate to release \"certificates\" in package #{cert_package}"
+      else
+        puts "Keys already exist."
+      end
+    end
+
+  end # end define
+
+  def announcement # :nodoc:
+    changes = self.changes.rdoc_to_markdown
+    subject = "#{name} #{version} Released"
+    title   = "#{name} version #{version} has been released!"
+    body    = "#{description}\n\nChanges:\n\n#{changes}".rdoc_to_markdown
+    urls    = Array(url).map { |s| "* <#{s.strip.rdoc_to_markdown}>" }.join("\n")
+
+    return subject, title, body, urls
+  end
+
+  def run_tests(multi=false) # :nodoc:
+    msg = multi ? :sh : :ruby
+    cmd = if test ?f, 'test/test_all.rb' then
+            "#{RUBY_FLAGS} test/test_all.rb #{FILTER}"
+          else
+            tests = ["rubygems", self.testlib] +
+              test_globs.map { |g| Dir.glob(g) }.flatten
+            tests.map! {|f| %Q(require "#{f}")}
+            "#{RUBY_FLAGS} -e '#{tests.join("; ")}' #{FILTER}"
+          end
+
+    excludes = multiruby_skip.join(":")
+    ENV['EXCLUDED_VERSIONS'] = excludes
+    cmd = "multiruby #{cmd}" if multi
+
+    send msg, cmd
+  end
+
+  ##
+  # Reads a file at +path+ and spits out an array of the +paragraphs+ specified.
+  #
+  #   changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
+  #   summary, *description = p.paragraphs_of('README.txt', 3, 3..8)
+
+  def paragraphs_of(path, *paragraphs)
+    File.read(path).delete("\r").split(/\n\n+/).values_at(*paragraphs)
+  end
+end
+
+# :enddoc:
+
+class ::Rake::SshDirPublisher # :nodoc:
+  attr_reader :host, :remote_dir, :local_dir
+end
+
+class String
+  def rdoc_to_markdown
+    self.gsub(/^mailto:/, '').gsub(/^(=+)/) { "#" * $1.size }
+  end
+end
+
+if $0 == __FILE__ then
+  out = `rake -T | egrep -v "redocs|repackage|clobber|trunk"`
+  if ARGV.empty? then
+    # # default::        Run the default tasks.
+    puts out.gsub(/(\s*)\#/, '::\1').gsub(/^rake /, '# ')
+  else
+    # * default        - Run the default tasks.
+    puts out.gsub(/\#/, '-').gsub(/^rake /, '* ')
+  end
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/test/test_hoe.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/test/test_hoe.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/hoe-1.8.2/test/test_hoe.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,97 @@
+
+require 'test/unit/testcase'
+require 'hoe'
+
+$rakefile = nil # shuts up a warning in rdoctask.rb
+
+class TestHoe < Test::Unit::TestCase
+  def setup
+    Rake.application.clear
+  end
+
+  ##
+  # Yes, these tests suck, but it is damn hard to test this since
+  # everything is forked out.
+
+  def test_basics
+    boring   = %w(clobber_docs clobber_package gem redocs repackage)
+    expected = %w(audit
+                  announce
+                  check_manifest
+                  clean
+                  config_hoe
+                  debug_gem
+                  default
+                  deps:email
+                  deps:fetch
+                  deps:list
+                  docs
+                  email
+                  generate_key
+                  install_gem
+                  multi
+                  package
+                  post_blog
+                  post_news
+                  publish_docs
+                  release
+                  ridocs
+                  test
+                  test_deps)
+    expected += boring
+
+    spec = Hoe.new('blah', '1.0.0') do |h|
+      h.developer("name", "email")
+    end
+
+    assert_equal ["name"], spec.author
+    assert_equal ["email"], spec.email
+
+    tasks = Rake.application.tasks
+    public_tasks = tasks.reject { |t| t.comment.nil? }.map { |t| t.name }.sort
+
+    assert_equal expected.sort, public_tasks
+  end
+
+  def test_possibly_better
+    t = Gem::Specification::TODAY
+    hoe = Hoe.new("blah", '1.2.3') do |h|
+      h.developer 'author', 'email'
+    end
+
+    files = File.read("Manifest.txt").split(/\n/)
+
+    spec = hoe.spec
+
+    assert_equal 'blah', spec.name
+    assert_equal '1.2.3', spec.version.to_s
+    assert_equal '>= 0', spec.required_rubygems_version.to_s
+
+    assert_equal ['author'], spec.authors
+    assert_equal t, spec.date
+    assert_equal 'sow', spec.default_executable
+    assert_match(/Hoe.*Rakefiles/, spec.description)
+    assert_equal ['email'], spec.email
+    assert_equal ['sow'], spec.executables
+    assert_equal files.grep(/txt$/), spec.extra_rdoc_files
+    assert_equal files, spec.files
+    assert_equal true, spec.has_rdoc
+    assert_equal "http://rubyforge.org/projects/seattlerb/", spec.homepage
+    assert_equal ['--main', 'README.txt'], spec.rdoc_options
+    assert_equal ['lib'], spec.require_paths
+    assert_equal 'blah', spec.rubyforge_project
+    assert_equal Gem::RubyGemsVersion, spec.rubygems_version
+    assert_match(/^Hoe.*Rakefiles$/, spec.summary)
+    assert_equal files.grep(/^test/), spec.test_files
+
+    deps = spec.dependencies
+
+    assert_equal 1, deps.size
+
+    dep = deps.first
+
+    assert_equal 'hoe', dep.name
+    assert_equal :development, dep.type
+    assert_equal ">= #{Hoe::VERSION}", dep.version_requirements.to_s
+  end
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/CHANGELOG
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/CHANGELOG	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/CHANGELOG	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,40 @@
+* Fixed gem install rake task
+* Improve Error encapsulation in liquid by maintaining a own set of exceptions instead of relying on ruby build ins
+
+* Added If with or / and expressions
+
+* Implemented .to_liquid for all objects which can be passed to liquid like Strings Arrays Hashes Numerics and Booleans. To export new objects to liquid just implement .to_liquid on them and return objects which themselves have .to_liquid methods. 
+
+* Added more tags to standard library
+
+* Added include tag ( like partials in rails )
+
+* [...] Gazillion of detail improvements
+
+* Added strainers as filter hosts for better security [Tobias Luetke]
+
+* Fixed that rails integration would call filter with the wrong "self" [Michael Geary]
+
+* Fixed bad error reporting when a filter called a method which doesn't exist. Liquid told you that it couldn't find the filter which was obviously misleading [Tobias Luetke]
+
+* Removed count helper from standard lib. use size [Tobias Luetke]
+
+* Fixed bug with string filter parameters failing to tolerate commas in strings. [Paul Hammond]
+
+* Improved filter parameters. Filter parameters are now context sensitive; Types are resolved according to the rules of the context. Multiple parameters are now separated by the Liquid::ArgumentSeparator: , by default [Paul Hammond]
+	
+	{{ 'Typo' | link_to: 'http://typo.leetsoft.com', 'Typo - a modern weblog engine' }}
+	
+
+* Added Liquid::Drop. A base class which you can use for exporting proxy objects to liquid which can acquire more data when used in liquid. [Tobias Luetke] 
+
+  class ProductDrop < Liquid::Drop
+    def top_sales
+       Shop.current.products.find(:all, :order => 'sales', :limit => 10 )
+    end
+  end   
+  t = Liquid::Template.parse( ' {% for product in product.top_sales %} {{ product.name }} {% endfor %} '  )
+  t.render('product' => ProductDrop.new )
+
+
+* Added filter parameters support. Example: {{ date | format_date: "%Y" }} [Paul Hammond]

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/History.txt
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/History.txt	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/History.txt	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,44 @@
+1.9.0 / 2008-03-04
+
+* Fixed gem install rake task
+* Improve Error encapsulation in liquid by maintaining a own set of exceptions instead of relying on ruby build ins
+
+Before 1.9.0
+
+* Added If with or / and expressions
+
+* Implemented .to_liquid for all objects which can be passed to liquid like Strings Arrays Hashes Numerics and Booleans. To export new objects to liquid just implement .to_liquid on them and return objects which themselves have .to_liquid methods. 
+
+* Added more tags to standard library
+
+* Added include tag ( like partials in rails )
+
+* [...] Gazillion of detail improvements
+
+* Added strainers as filter hosts for better security [Tobias Luetke]
+
+* Fixed that rails integration would call filter with the wrong "self" [Michael Geary]
+
+* Fixed bad error reporting when a filter called a method which doesn't exist. Liquid told you that it couldn't find the filter which was obviously misleading [Tobias Luetke]
+
+* Removed count helper from standard lib. use size [Tobias Luetke]
+
+* Fixed bug with string filter parameters failing to tolerate commas in strings. [Paul Hammond]
+
+* Improved filter parameters. Filter parameters are now context sensitive; Types are resolved according to the rules of the context. Multiple parameters are now separated by the Liquid::ArgumentSeparator: , by default [Paul Hammond]
+	
+	{{ 'Typo' | link_to: 'http://typo.leetsoft.com', 'Typo - a modern weblog engine' }}
+	
+
+* Added Liquid::Drop. A base class which you can use for exporting proxy objects to liquid which can acquire more data when used in liquid. [Tobias Luetke] 
+
+  class ProductDrop < Liquid::Drop
+    def top_sales
+       Shop.current.products.find(:all, :order => 'sales', :limit => 10 )
+    end
+  end   
+  t = Liquid::Template.parse( ' {% for product in product.top_sales %} {{ product.name }} {% endfor %} '  )
+  t.render('product' => ProductDrop.new )
+
+
+* Added filter parameters support. Example: {{ date | format_date: "%Y" }} [Paul Hammond]

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/MIT-LICENSE
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/MIT-LICENSE	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/MIT-LICENSE	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,20 @@
+Copyright (c) 2005, 2006 Tobias Luetke
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/Manifest.txt
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/Manifest.txt	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/Manifest.txt	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,65 @@
+CHANGELOG
+History.txt
+MIT-LICENSE
+Manifest.txt
+README.txt
+Rakefile
+example/server/example_servlet.rb
+example/server/liquid_servlet.rb
+example/server/server.rb
+example/server/templates/index.liquid
+example/server/templates/products.liquid
+init.rb
+lib/extras/liquid_view.rb
+lib/liquid.rb
+lib/liquid/block.rb
+lib/liquid/condition.rb
+lib/liquid/context.rb
+lib/liquid/document.rb
+lib/liquid/drop.rb
+lib/liquid/errors.rb
+lib/liquid/extensions.rb
+lib/liquid/file_system.rb
+lib/liquid/htmltags.rb
+lib/liquid/module_ex.rb
+lib/liquid/standardfilters.rb
+lib/liquid/strainer.rb
+lib/liquid/tag.rb
+lib/liquid/tags/assign.rb
+lib/liquid/tags/capture.rb
+lib/liquid/tags/case.rb
+lib/liquid/tags/comment.rb
+lib/liquid/tags/cycle.rb
+lib/liquid/tags/for.rb
+lib/liquid/tags/if.rb
+lib/liquid/tags/ifchanged.rb
+lib/liquid/tags/include.rb
+lib/liquid/tags/unless.rb
+lib/liquid/template.rb
+lib/liquid/variable.rb
+test/block_test.rb
+test/condition_test.rb
+test/context_test.rb
+test/drop_test.rb
+test/error_handling_test.rb
+test/extra/breakpoint.rb
+test/extra/caller.rb
+test/file_system_test.rb
+test/filter_test.rb
+test/helper.rb
+test/html_tag_test.rb
+test/if_else_test.rb
+test/include_tag_test.rb
+test/module_ex_test.rb
+test/output_test.rb
+test/parsing_quirks_test.rb
+test/regexp_test.rb
+test/security_test.rb
+test/standard_filter_test.rb
+test/standard_tag_test.rb
+test/statements_test.rb
+test/strainer_test.rb
+test/template_test.rb
+test/test_helper.rb
+test/unless_else_test.rb
+test/variable_test.rb

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/README.txt
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/README.txt	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/README.txt	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,38 @@
+= Liquid template engine
+
+Liquid is a template engine which I wrote for very specific requirements
+
+* It has to have beautiful and simple markup. 
+  Template engines which don't produce good looking markup are no fun to use. 
+* It needs to be non evaling and secure. Liquid templates are made so that users can edit them. You don't want to run code on your server which your users wrote. 
+* It has to be stateless. Compile and render steps have to be seperate so that the expensive parsing and compiling can be done once and later on you can 
+  just render it   passing in a hash with local variables and objects.
+
+== Why should i use Liquid
+
+* You want to allow your users to edit the appearance of your application but don't want them to run insecure code on your server.
+* You want to render templates directly from the database
+* You like smarty style template engines 
+* You need a template engine which does HTML just as well as Emails
+* You don't like the markup of your current one
+
+== What does it look like?
+
+	<ul id="products">  
+	  {% for product in products %}
+	    <li>
+	      <h2>{{product.name}}</h2>
+	      Only {{product.price | price }}
+  
+	      {{product.description | prettyprint | paragraph }}
+ 	    </li>      
+	  {% endfor %}  
+	</ul>
+
+== Howto use Liquid
+
+Liquid supports a very simple API based around the Liquid::Template class.
+For standard use you can just pass it the content of a file and call render with a parameters hash. 
+
+	@template = Liquid::Template.parse("hi {{name}}") # Parses and compiles the template
+	@template.render( 'name' => 'tobi' )              # => "hi tobi" 
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/Rakefile
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/Rakefile	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/Rakefile	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,24 @@
+#!/usr/bin/env ruby
+require 'rubygems'
+require 'rake'
+require 'hoe'
+
+PKG_VERSION = "1.9.0"
+PKG_NAME    = "liquid"
+PKG_DESC    = "A secure non evaling end user template engine with aesthetic markup."
+
+Rake::TestTask.new(:test) do |t|
+  t.libs << "lib"
+  t.libs << "test"
+  t.pattern = 'test/*_test.rb'
+  t.verbose = false
+end
+
+Hoe.new(PKG_NAME, PKG_VERSION) do |p|
+  p.rubyforge_name = PKG_NAME
+  p.summary        = PKG_DESC
+  p.description    = PKG_DESC
+  p.author         = "Tobias Luetke"
+  p.email          = "tobi at leetsoft.com"
+  p.url            = "http://www.liquidmarkup.org"    
+end
\ No newline at end of file


Property changes on: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/Rakefile
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/example_servlet.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/example_servlet.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/example_servlet.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,37 @@
+module ProductsFilter
+  def price(integer)
+    sprintf("$%.2d USD", integer / 100.0)
+  end
+  
+  def prettyprint(text)
+    text.gsub( /\*(.*)\*/, '<b>\1</b>' )
+  end
+  
+  def count(array)
+    array.size
+  end
+  
+  def paragraph(p)
+    "<p>#{p}</p>"
+  end
+end
+
+class Servlet < LiquidServlet
+  
+  def index
+    { 'date' => Time.now }
+  end
+  
+  def products    
+    { 'products' => products_list, 'section' => 'Snowboards', 'cool_products' => true}    
+  end
+  
+  private
+  
+  def products_list
+    [{'name' => 'Arbor Draft', 'price' => 39900, 'description' => 'the *arbor draft* is a excellent product' },
+    {'name' => 'Arbor Element', 'price' => 40000, 'description' => 'the *arbor element* rocks for freestyling'},
+    {'name' => 'Arbor Diamond', 'price' => 59900, 'description' => 'the *arbor diamond* is a made up product because im obsessed with arbor and have no creativity'}]
+  end
+  
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/liquid_servlet.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/liquid_servlet.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/liquid_servlet.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,28 @@
+class LiquidServlet < WEBrick::HTTPServlet::AbstractServlet
+
+  def do_GET(req, res)
+    handle(:get, req, res)
+  end
+
+  def do_POST(req, res)
+    handle(:post, req, res)
+  end
+  
+  private
+  
+  def handle(type, req, res)
+    @request, @response = req, res
+    
+    @request.path_info =~ /(\w+)$/
+    @action = $1 || 'index'    
+    @assigns = send(@action) if respond_to?(@action)    
+
+    @response['Content-Type'] = "text/html"
+    @response.status = 200
+    @response.body = Liquid::Template.parse(read_template).render(@assigns, :filters => [ProductsFilter])      
+  end
+  
+  def read_template(filename = @action)
+    File.read( File.dirname(__FILE__) + "/templates/#{filename}.liquid" )
+  end
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/server.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/server.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/server.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,12 @@
+require 'webrick'
+require 'rexml/document'
+
+require File.dirname(__FILE__) + '/../../lib/liquid'
+require File.dirname(__FILE__) + '/liquid_servlet'
+require File.dirname(__FILE__) + '/example_servlet'
+
+# Setup webrick
+server = WEBrick::HTTPServer.new( :Port => ARGV[1] || 3000 )
+server.mount('/', Servlet)
+trap("INT"){ server.shutdown }
+server.start
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/templates/index.liquid
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/templates/index.liquid	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/templates/index.liquid	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,6 @@
+<p>Hello world!</p>
+
+<p>It is {{date}}</p>
+
+
+<p>Check out the <a href="http://localhost:3000/products">Products</a> screen </p>
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/templates/products.liquid
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/templates/products.liquid	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/example/server/templates/products.liquid	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
+	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+	<head>
+		<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+		<meta http-equiv="Content-Language" content="en-us" />
+		
+		<title>products</title>
+		
+		<meta name="ROBOTS" content="ALL" />
+		<meta http-equiv="imagetoolbar" content="no" />
+		<meta name="MSSmartTagsPreventParsing" content="true" />
+		<meta name="Copyright" content="(c) 2005 Copyright content:  Copyright design: Tobias Luetke" />
+		<!-- (c) Copyright 2005 by Tobias Luetke All Rights Reserved. -->
+	</head>
+	
+	<body>
+	  
+	  <h1>There are currently {{products | count}} products in the {{section}} catalog</h1>
+
+    {% if cool_products %}
+      Cool products :) 
+    {% else %}
+      Uncool products :(    
+    {% endif %}
+
+    <ul id="products">
+      
+      {% for product in products %}
+        <li>
+          <h2>{{product.name}}</h2>
+          Only {{product.price | price }}
+      
+          {{product.description | prettyprint | paragraph }}
+          
+          {{ 'it rocks!' | paragraph }}
+          
+        </li>      
+      {% endfor %}
+      
+    </ul>
+	
+	</body>
+</html>

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/init.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/init.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/init.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,8 @@
+require 'liquid'
+require 'extras/liquid_view'
+
+if defined? ActionView::Template and ActionView::Template.respond_to? :register_template_handler
+  ActionView::Template
+else
+  ActionView::Base
+end.register_template_handler(:liquid, LiquidView)

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/extras/liquid_view.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/extras/liquid_view.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/extras/liquid_view.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,27 @@
+# LiquidView is a action view extension class. You can register it with rails
+# and use liquid as an template system for .liquid files
+#
+# Example
+# 
+#   ActionView::Base::register_template_handler :liquid, LiquidView
+class LiquidView
+
+  def initialize(action_view)
+    @action_view = action_view
+  end
+  
+
+  def render(template, local_assigns)
+    @action_view.controller.headers["Content-Type"] ||= 'text/html; charset=utf-8'
+    assigns = @action_view.assigns.dup
+    
+    if content_for_layout = @action_view.instance_variable_get("@content_for_layout")
+      assigns['content_for_layout'] = content_for_layout
+    end
+    assigns.merge!(local_assigns)
+    
+    liquid = Liquid::Template.parse(template)
+    liquid.render(assigns, :filters => [@action_view.controller.master_helper_module], :registers => {:action_view => @action_view, :controller => @action_view.controller})
+  end
+
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/block.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/block.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/block.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,98 @@
+module Liquid
+  
+  class Block < Tag
+
+    def parse(tokens)
+      @nodelist ||= []
+      @nodelist.clear
+
+      while token = tokens.shift 
+
+        case token
+        when /^#{TagStart}/                   
+          if token =~ /^#{TagStart}\s*(\w+)\s*(.*)?#{TagEnd}$/
+
+            # if we found the proper block delimitor just end parsing here and let the outer block
+            # proceed                               
+            if block_delimiter == $1
+              end_tag
+              return
+            end
+
+            # fetch the tag from registered blocks
+            if tag = Template.tags[$1]
+              @nodelist << tag.new($1, $2, tokens)
+            else
+              # this tag is not registered with the system 
+              # pass it to the current block for special handling or error reporting
+              unknown_tag($1, $2, tokens)
+            end              
+          else
+            raise SyntaxError, "Tag '#{token}' was not properly terminated with regexp: #{TagEnd.inspect} "
+          end
+        when /^#{VariableStart}/
+          @nodelist << create_variable(token)
+        when ''
+          # pass
+        else
+          @nodelist << token
+        end
+      end       
+      
+      # Make sure that its ok to end parsing in the current block. 
+      # Effectively this method will throw and exception unless the current block is 
+      # of type Document 
+      assert_missing_delimitation!
+    end                     
+    
+    def end_tag      
+    end
+
+    def unknown_tag(tag, params, tokens)
+      case tag 
+      when 'else'
+        raise SyntaxError, "#{block_name} tag does not expect else tag"
+      when 'end'
+        raise SyntaxError, "'end' is not a valid delimiter for #{block_name} tags. use #{block_delimiter}"
+      else
+        raise SyntaxError, "Unknown tag '#{tag}'"
+      end
+    end
+
+    def block_delimiter
+      "end#{block_name}"
+    end                           
+
+    def block_name
+      @tag_name
+    end
+
+    def create_variable(token)
+      token.scan(/^#{VariableStart}(.*)#{VariableEnd}$/) do |content|
+        return Variable.new(content.first)
+      end
+      raise SyntaxError.new("Variable '#{token}' was not properly terminated with regexp: #{VariableEnd.inspect} ")
+    end
+
+    def render(context)
+      render_all(@nodelist, context)
+    end
+    
+    protected
+
+    def assert_missing_delimitation!
+      raise SyntaxError.new("#{block_name} tag was never closed")
+    end
+
+    def render_all(list, context)
+      list.collect do |token|
+        begin        
+          token.respond_to?(:render) ? token.render(context) : token
+        rescue Exception => e          
+          context.handle_error(e)
+        end
+          
+      end      
+    end
+  end  
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/condition.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/condition.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/condition.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,123 @@
+module Liquid
+  # Container for liquid nodes which conveniently wraps decision making logic
+  #
+  # Example:
+  #
+  #   c = Condition.new('1', '==', '1') 
+  #   c.evaluate #=> true
+  #
+  class Condition #:nodoc:
+    @@operators = {
+      '==' => lambda { |cond, left, right|  cond.send(:equal_variables, left, right) },
+      '!=' => lambda { |cond, left, right| !cond.send(:equal_variables, left, right) },
+      '<>' => lambda { |cond, left, right| !cond.send(:equal_variables, left, right) },
+      '<'  => :<,
+      '>'  => :>,
+      '>=' => :>=,
+      '<=' => :<=,
+      'contains' => lambda { |cond, left, right| left.include?(right) },
+    }
+    
+    def self.operators
+      @@operators
+    end
+
+    attr_reader :attachment
+    attr_accessor :left, :operator, :right
+  
+    def initialize(left = nil, operator = nil, right = nil)
+      @left, @operator, @right = left, operator, right
+      @child_relation  = nil
+      @child_condition = nil
+    end
+    
+    def evaluate(context = Context.new)
+      result = interpret_condition(left, right, operator, context)        
+      
+      case @child_relation
+      when :or 
+        result || @child_condition.evaluate(context)
+      when :and 
+        result && @child_condition.evaluate(context)
+      else
+        result
+      end      
+    end                    
+    
+    def or(condition)
+      @child_relation, @child_condition = :or, condition
+    end
+
+    def and(condition)
+      @child_relation, @child_condition = :and, condition
+    end
+  
+    def attach(attachment)
+      @attachment = attachment
+    end
+  
+    def else?
+      false
+    end                          
+    
+    def inspect
+      "#<Condition #{[@left, @operator, @right].compact.join(' ')}>"
+    end
+    
+    private
+  
+    def equal_variables(left, right)
+      if left.is_a?(Symbol)
+        if right.respond_to?(left)
+          return right.send(left.to_s) 
+        else
+          return nil
+        end
+      end
+
+      if right.is_a?(Symbol)
+        if left.respond_to?(right)
+          return left.send(right.to_s) 
+        else
+          return nil
+        end
+      end
+
+      left == right      
+    end    
+
+    def interpret_condition(left, right, op, context)
+
+      # If the operator is empty this means that the decision statement is just 
+      # a single variable. We can just poll this variable from the context and 
+      # return this as the result.
+      return context[left] if op == nil      
+
+      left, right = context[left], context[right]
+            
+
+      operation = self.class.operators[op] || raise(ArgumentError.new("Unknown operator #{op}"))
+
+      if operation.respond_to?(:call)
+        operation.call(self, left, right)
+      elsif left.respond_to?(operation) and right.respond_to?(operation)        
+        left.send(operation, right)
+      else
+        nil
+      end
+    end    
+  end           
+
+
+  class ElseCondition < Condition
+      
+    def else? 
+      true
+    end
+  
+    def evaluate(context)
+      true
+    end
+  end
+
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/context.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/context.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/context.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,242 @@
+module Liquid
+  
+  # Context keeps the variable stack and resolves variables, as well as keywords
+  #
+  #   context['variable'] = 'testing'
+  #   context['variable'] #=> 'testing'
+  #   context['true']     #=> true
+  #   context['10.2232']  #=> 10.2232
+  #   
+  #   context.stack do 
+  #      context['bob'] = 'bobsen'
+  #   end
+  #
+  #   context['bob']  #=> nil  class Context
+  class Context
+    attr_reader :scopes
+    attr_reader :errors, :registers
+    
+    def initialize(assigns = {}, registers = {}, rethrow_errors = false)
+      @scopes     = [(assigns || {})]
+      @registers  = registers
+      @errors     = []
+      @rethrow_errors = rethrow_errors
+    end    
+           
+    def strainer
+      @strainer ||= Strainer.create(self)
+    end  
+               
+    # adds filters to this context. 
+    # this does not register the filters with the main Template object. see <tt>Template.register_filter</tt> 
+    # for that
+    def add_filters(filters)
+      filters = [filters].flatten.compact
+      
+      filters.each do |f|         
+        raise ArgumentError, "Expected module but got: #{f.class}" unless f.is_a?(Module)
+        strainer.extend(f)
+      end      
+    end
+    
+    def handle_error(e)
+      errors.push(e)
+      raise if @rethrow_errors
+      
+      case e
+      when SyntaxError then "Liquid syntax error: #{e.message}"        
+      else "Liquid error: #{e.message}"
+      end
+    end
+    
+                              
+    def invoke(method, *args)
+      if strainer.respond_to?(method)
+        strainer.__send__(method, *args)
+      else
+        args.first
+      end        
+    end
+
+    # push new local scope on the stack. use <tt>Context#stack</tt> instead
+    def push
+      @scopes.unshift({})
+    end
+    
+    # merge a hash of variables in the current local scope
+    def merge(new_scopes)
+      @scopes[0].merge!(new_scopes)
+    end
+  
+    # pop from the stack. use <tt>Context#stack</tt> instead
+    def pop
+      raise ContextError if @scopes.size == 1 
+      @scopes.shift
+    end
+    
+    # pushes a new local scope on the stack, pops it at the end of the block
+    #
+    # Example:
+    #
+    #   context.stack do 
+    #      context['var'] = 'hi'
+    #   end
+    #   context['var]  #=> nil
+    #
+    def stack(&block)
+      result = nil
+      push
+      begin
+        result = yield
+      ensure 
+        pop
+      end
+      result      
+    end
+  
+    # Only allow String, Numeric, Hash, Array, Proc, Boolean or <tt>Liquid::Drop</tt>
+    def []=(key, value)
+      @scopes[0][key] = value
+    end
+  
+    def [](key)
+      resolve(key)
+    end
+  
+    def has_key?(key)
+      resolve(key) != nil
+    end
+        
+    private
+    
+    # Look up variable, either resolve directly after considering the name. We can directly handle 
+    # Strings, digits, floats and booleans (true,false). If no match is made we lookup the variable in the current scope and 
+    # later move up to the parent blocks to see if we can resolve the variable somewhere up the tree.
+    # Some special keywords return symbols. Those symbols are to be called on the rhs object in expressions
+    #
+    # Example: 
+    #
+    #   products == empty #=> products.empty?
+    #
+    def resolve(key)
+      case key
+      when nil, 'nil', 'null', ''
+        nil
+      when 'true'
+        true
+      when 'false'
+        false               
+      when 'blank'
+        :blank?        
+      when 'empty'
+        :empty?
+      # Single quoted strings
+      when /^'(.*)'$/
+        $1.to_s
+      # Double quoted strings
+      when /^"(.*)"$/
+        $1.to_s        
+      # Integer and floats
+      when /^(\d+)$/ 
+        $1.to_i
+      # Ranges
+      when /^\((\S+)\.\.(\S+)\)$/        
+        (resolve($1).to_i..resolve($2).to_i)
+      # Floats
+      when /^(\d[\d\.]+)$/ 
+        $1.to_f
+      else
+        variable(key)
+      end      
+    end
+    
+    # fetches an object starting at the local scope and then moving up 
+    # the hierachy 
+    def find_variable(key)
+      @scopes.each do |scope|        
+        if scope.has_key?(key)
+          variable = scope[key] 
+          variable = scope[key] = variable.call(self) if variable.is_a?(Proc)
+          variable = variable.to_liquid
+          variable.context = self if variable.respond_to?(:context=)
+          return variable
+        end
+      end
+      nil
+    end
+
+    # resolves namespaced queries gracefully.
+    # 
+    # Example
+    # 
+    #  @context['hash'] = {"name" => 'tobi'}
+    #  assert_equal 'tobi', @context['hash.name']
+    #  assert_equal 'tobi', @context['hash[name]']
+    #
+    def variable(markup)
+      parts = markup.scan(VariableParser)
+      square_bracketed = /^\[(.*)\]$/
+      
+      first_part = parts.shift
+      if first_part =~ square_bracketed
+        first_part = resolve($1)
+      end
+      
+      if object = find_variable(first_part)
+            
+        parts.each do |part|        
+
+          # If object is a hash we look for the presence of the key and if its available 
+          # we return it
+          
+          if part =~ square_bracketed
+            part = resolve($1)
+            
+            object[pos] = object[part].call(self) if object[part].is_a?(Proc) and object.respond_to?(:[]=)
+            object      = object[part].to_liquid
+            
+          else
+
+            # Hash
+            if object.respond_to?(:has_key?) and object.has_key?(part)
+          
+              # if its a proc we will replace the entry in the hash table with the proc
+              res = object[part]
+              res = object[part] = res.call(self) if res.is_a?(Proc) and object.respond_to?(:[]=)
+              object = res.to_liquid
+
+            # Array
+            elsif object.respond_to?(:fetch) and part =~ /^\d+$/ 
+              pos = part.to_i
+
+              object[pos] = object[pos].call(self) if object[pos].is_a?(Proc) and object.respond_to?(:[]=)
+              object = object[pos].to_liquid
+          
+            # Some special cases. If no key with the same name was found we interpret following calls
+            # as commands and call them on the current object
+            elsif object.respond_to?(part) and ['size', 'first', 'last'].include?(part)
+          
+              object = object.send(part.intern).to_liquid
+        
+            # No key was present with the desired value and it wasn't one of the directly supported
+            # keywords either. The only thing we got left is to return nil
+            else
+              return nil
+            end
+          end
+                
+          # If we are dealing with a drop here we have to         
+          object.context = self if object.respond_to?(:context=)
+        end
+      end
+            
+      object
+    end                                       
+    
+    private
+    
+    def execute_proc(proc)
+      proc.call(self)
+    end
+  end
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/document.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/document.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/document.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,17 @@
+module Liquid
+  class Document < Block                                                             
+    # we don't need markup to open this block
+    def initialize(tokens)
+      parse(tokens)
+    end                                                                        
+  
+    # There isn't a real delimter   
+    def block_delimiter
+      []
+    end
+  
+    # Document blocks don't need to be terminated since they are not actually opened
+    def assert_missing_delimitation!
+    end    
+  end
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/drop.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/drop.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/drop.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,48 @@
+module Liquid
+  
+  # A drop in liquid is a class which allows you to to export DOM like things to liquid
+  # Methods of drops are callable. 
+  # The main use for liquid drops is the implement lazy loaded objects. 
+  # If you would like to make data available to the web designers which you don't want loaded unless needed then 
+  # a drop is a great way to do that
+  #
+  # Example:
+  #
+  # class ProductDrop < Liquid::Drop
+  #   def top_sales
+  #      Shop.current.products.find(:all, :order => 'sales', :limit => 10 )
+  #   end
+  # end
+  #  
+  # tmpl = Liquid::Template.parse( ' {% for product in product.top_sales %} {{ product.name }} {%endfor%} '  )
+  # tmpl.render('product' => ProductDrop.new ) # will invoke top_sales query. 
+  #
+  # Your drop can either implement the methods sans any parameters or implement the before_method(name) method which is a 
+  # catch all
+  class Drop
+    attr_writer :context
+
+    # Catch all for the method 
+    def before_method(method)
+      nil
+    end
+    
+    # called by liquid to invoke a drop
+    def invoke_drop(method)      
+      result = before_method(method)
+      result ||= send(method.to_sym) if self.class.public_instance_methods.include?(method.to_s)
+      result
+    end
+    
+    def has_key?(name)
+      true
+    end
+    
+    def to_liquid
+      self
+    end
+
+    alias :[] :invoke_drop
+  end
+  
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/errors.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/errors.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/errors.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,10 @@
+module Liquid
+  class Error < ::StandardError; end
+  
+  class ArgumentError < Error; end
+  class ContextError < Error; end
+  class FilterNotFound < Error; end
+  class FileSystemError < Error; end
+  class StandardError < Error; end
+  class SyntaxError < Error; end
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/extensions.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/extensions.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/extensions.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,56 @@
+require 'time'
+require 'date'
+
+class String # :nodoc:
+  def to_liquid
+    self
+  end
+end
+
+class Array  # :nodoc:
+  def to_liquid
+    self
+  end
+end
+
+class Hash  # :nodoc:
+  def to_liquid
+    self
+  end
+end
+
+class Numeric  # :nodoc:
+  def to_liquid
+    self
+  end
+end
+
+class Time  # :nodoc:
+  def to_liquid
+    self
+  end
+end
+
+class DateTime < Date  # :nodoc:
+  def to_liquid
+    self
+  end
+end
+
+class Date  # :nodoc:
+  def to_liquid
+    self
+  end
+end
+
+def true.to_liquid  # :nodoc:
+  self
+end
+
+def false.to_liquid # :nodoc:
+  self
+end
+
+def nil.to_liquid # :nodoc:
+  self
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/file_system.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/file_system.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/file_system.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,62 @@
+module Liquid
+  # A Liquid file system is way to let your templates retrieve other templates for use with the include tag.
+  #
+  # You can implement subclasses that retrieve templates from the database, from the file system using a different 
+  # path structure, you can provide them as hard-coded inline strings, or any manner that you see fit.
+  #
+  # You can add additional instance variables, arguments, or methods as needed.
+  #
+  # Example:
+  #
+  # Liquid::Template.file_system = Liquid::LocalFileSystem.new(template_path)
+  # liquid = Liquid::Template.parse(template)
+  #
+  # This will parse the template with a LocalFileSystem implementation rooted at 'template_path'.
+  class BlankFileSystem
+    # Called by Liquid to retrieve a template file
+    def read_template_file(template_path)
+      raise FileSystemError, "This liquid context does not allow includes."
+    end
+  end
+  
+  # This implements an abstract file system which retrieves template files named in a manner similar to Rails partials,
+  # ie. with the template name prefixed with an underscore. The extension ".liquid" is also added.
+  #
+  # For security reasons, template paths are only allowed to contain letters, numbers, and underscore.
+  #
+  # Example:
+  #
+  # file_system = Liquid::LocalFileSystem.new("/some/path")
+  # 
+  # file_system.full_path("mypartial")       # => "/some/path/_mypartial.liquid"
+  # file_system.full_path("dir/mypartial")   # => "/some/path/dir/_mypartial.liquid"
+  #
+  class LocalFileSystem
+    attr_accessor :root
+    
+    def initialize(root)
+      @root = root
+    end
+    
+    def read_template_file(template_path)
+      full_path = full_path(template_path)
+      raise FileSystemError, "No such template '#{template_path}'" unless File.exists?(full_path)
+      
+      File.read(full_path)
+    end
+    
+    def full_path(template_path)
+      raise FileSystemError, "Illegal template name '#{template_path}'" unless template_path =~ /^[^.\/][a-zA-Z0-9_\/]+$/
+      
+      full_path = if template_path.include?('/')
+        File.join(root, File.dirname(template_path), "_#{File.basename(template_path)}.liquid")
+      else
+        File.join(root, "_#{template_path}.liquid")
+      end
+      
+      raise FileSystemError, "Illegal template path '#{File.expand_path(full_path)}'" unless File.expand_path(full_path) =~ /^#{File.expand_path(root)}/
+      
+      full_path
+    end
+  end
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/htmltags.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/htmltags.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/htmltags.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,74 @@
+module Liquid
+  class TableRow < Block                                             
+    Syntax = /(\w+)\s+in\s+(#{VariableSignature}+)/   
+    
+    def initialize(tag_name, markup, tokens)
+      if markup =~ Syntax
+        @variable_name = $1
+        @collection_name = $2
+        @attributes = {}
+        markup.scan(TagAttributes) do |key, value|
+          @attributes[key] = value
+        end
+      else
+        raise SyntaxError.new("Syntax Error in 'table_row loop' - Valid syntax: table_row [item] in [collection] cols=3")
+      end
+      
+      super      
+    end
+    
+    def render(context)        
+      collection = context[@collection_name] or return ''
+      
+      if @attributes['limit'] or @attributes['offset']
+        limit = context[@attributes['limit']] || -1
+        offset = context[@attributes['offset']] || 0
+        collection = collection[offset.to_i..(limit.to_i + offset.to_i - 1)]
+      end
+            
+      length = collection.length
+      
+      cols = context[@attributes['cols']].to_i
+
+      row = 1
+      col = 0
+
+      result = ["<tr class=\"row1\">\n"]
+      context.stack do 
+
+        collection.each_with_index do |item, index|
+          context[@variable_name] = item
+          context['tablerowloop'] = {
+            'length'  => length,
+            'index'   => index + 1, 
+            'index0'  => index, 
+            'col'     => col + 1, 
+            'col0'    => col, 
+            'index0'  => index, 
+            'rindex'  => length - index,
+            'rindex0' => length - index -1,
+            'first'   => (index == 0),
+            'last'    => (index == length - 1),
+            'col_first' => (col == 0),
+            'col_last'  => (col == cols - 1)
+          }  
+          
+            
+          col += 1
+                                
+          result << ["<td class=\"col#{col}\">"] + render_all(@nodelist, context) + ['</td>']
+
+          if col == cols and not (index == length - 1)                        
+            col  = 0
+            row += 1
+            result << ["</tr>\n<tr class=\"row#{row}\">"] 
+          end
+          
+        end
+      end
+      result + ["</tr>\n"]
+    end    
+  end
+  
+  Template.register_tag('tablerow', TableRow)  
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/module_ex.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/module_ex.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/module_ex.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,62 @@
+# Copyright 2007 by Domizio Demichelis
+# This library is free software. It may be used, redistributed and/or modified
+# under the same terms as Ruby itself
+#
+# This extension is usesd in order to expose the object of the implementing class
+# to liquid as it were a Drop. It also limits the liquid-callable methods of the instance
+# to the allowed method passed with the liquid_methods call
+# Example:
+#
+# class SomeClass
+#   liquid_methods :an_allowed_method
+#
+#   def an_allowed_method
+#     'this comes from an allowed method'
+#   end
+#   def unallowed_method
+#     'this will never be an output'
+#   end
+# end
+#
+# if you want to extend the drop to other methods you can defines more methods 
+# in the class <YourClass>::LiquidDropClass
+#
+#   class SomeClass::LiquidDropClass
+#     def another_allowed_method
+#       'and this from another allowed method'
+#     end
+#   end
+# end
+#
+# usage:
+# @something = SomeClass.new
+#
+# template:
+# {{something.an_allowed_method}}{{something.unallowed_method}} {{something.another_allowed_method}}
+#
+# output:
+# 'this comes from an allowed method and this from another allowed method'
+#
+# You can also chain associations, by adding the liquid_method call in the 
+# association models.
+#
+class Module
+  
+  def liquid_methods(*allowed_methods)
+    drop_class = eval "class #{self.to_s}::LiquidDropClass < Liquid::Drop; self; end"
+    define_method :to_liquid do
+      drop_class.new(self)
+    end
+    drop_class.class_eval do
+      def initialize(object)
+        @object = object
+      end
+      allowed_methods.each do |sym|
+        define_method sym do
+          @object.send sym
+        end
+      end
+    end
+  end
+  
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/standardfilters.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/standardfilters.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/standardfilters.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,164 @@
+require 'cgi'
+
+module Liquid
+  
+  module StandardFilters
+    
+    # Return the size of an array or of an string
+    def size(input)
+      
+      input.respond_to?(:size) ? input.size : 0
+    end         
+    
+    # convert a input string to DOWNCASE
+    def downcase(input)
+      input.to_s.downcase
+    end         
+
+    # convert a input string to UPCASE
+    def upcase(input)
+      input.to_s.upcase
+    end
+    
+    # capitalize words in the input centence
+    def capitalize(input)
+      input.to_s.capitalize
+    end
+        
+    def escape(input)
+      CGI.escapeHTML(input) rescue input
+    end
+    
+    alias_method :h, :escape
+    
+    # Truncate a string down to x characters
+    def truncate(input, length = 50, truncate_string = "...")
+      if input.nil? then return end
+      l = length.to_i - truncate_string.length
+      l = 0 if l < 0
+      input.length > length.to_i ? input[0...l] + truncate_string : input
+    end
+
+    def truncatewords(input, words = 15, truncate_string = "...")
+      if input.nil? then return end
+      wordlist = input.to_s.split
+      l = words.to_i - 1
+      l = 0 if l < 0
+      wordlist.length > l ? wordlist[0..l].join(" ") + truncate_string : input 
+    end
+    
+    def strip_html(input)
+      input.to_s.gsub(/<.*?>/, '')
+    end       
+    
+    # Remove all newlines from the string
+    def strip_newlines(input)        
+      input.to_s.gsub(/\n/, '')      
+    end
+    
+    
+    # Join elements of the array with certain character between them
+    def join(input, glue = ' ')
+      [input].flatten.join(glue)
+    end
+
+    # Sort elements of the array
+    def sort(input)
+      [input].flatten.sort
+    end               
+            
+    # Replace occurrences of a string with another
+    def replace(input, string, replacement = '')
+      input.to_s.gsub(string, replacement)
+    end
+                                                 
+    # Replace the first occurrences of a string with another
+    def replace_first(input, string, replacement = '')
+      input.to_s.sub(string, replacement)
+    end              
+                                                           
+    # remove a substring
+    def remove(input, string)
+      input.to_s.gsub(string, '')      
+    end
+                        
+    # remove the first occurrences of a substring
+    def remove_first(input, string)
+      input.to_s.sub(string, '')      
+    end            
+                                             
+    # Add <br /> tags in front of all newlines in input string
+    def newline_to_br(input)        
+      input.to_s.gsub(/\n/, "<br />\n")      
+    end
+    
+    # Reformat a date
+    #
+    #   %a - The abbreviated weekday name (``Sun'')
+    #   %A - The  full  weekday  name (``Sunday'')
+    #   %b - The abbreviated month name (``Jan'')
+    #   %B - The  full  month  name (``January'')
+    #   %c - The preferred local date and time representation
+    #   %d - Day of the month (01..31)
+    #   %H - Hour of the day, 24-hour clock (00..23)
+    #   %I - Hour of the day, 12-hour clock (01..12)
+    #   %j - Day of the year (001..366)
+    #   %m - Month of the year (01..12)
+    #   %M - Minute of the hour (00..59)
+    #   %p - Meridian indicator (``AM''  or  ``PM'')
+    #   %S - Second of the minute (00..60)
+    #   %U - Week  number  of the current year,
+    #           starting with the first Sunday as the first
+    #           day of the first week (00..53)
+    #   %W - Week  number  of the current year,
+    #           starting with the first Monday as the first
+    #           day of the first week (00..53)
+    #   %w - Day of the week (Sunday is 0, 0..6)
+    #   %x - Preferred representation for the date alone, no time
+    #   %X - Preferred representation for the time alone, no date
+    #   %y - Year without a century (00..99)
+    #   %Y - Year with century
+    #   %Z - Time zone name
+    #   %% - Literal ``%'' character
+    def date(input, format)
+      
+      if format.to_s.empty?
+        return input.to_s
+      end
+      
+      date = case input
+      when String
+        Time.parse(input)
+      when Date, Time, DateTime
+        input
+      else
+        return input
+      end
+              
+      date.strftime(format.to_s)
+    rescue => e 
+      input
+    end
+    
+    # Get the first element of the passed in array 
+    # 
+    # Example:
+    #    {{ product.images | first | to_img }}
+    #  
+    def first(array)
+      array.first if array.respond_to?(:first)
+    end
+
+    # Get the last element of the passed in array 
+    # 
+    # Example:
+    #    {{ product.images | last | to_img }}
+    #  
+    def last(array)
+      array.last if array.respond_to?(:last)
+    end
+    
+  end
+   
+  Template.register_filter(StandardFilters)
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/strainer.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/strainer.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/strainer.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,52 @@
+require 'set'
+
+module Liquid
+  
+  
+  parent_object = if defined? BlankObject
+    BlankObject
+  else
+    Object
+  end
+
+  # Strainer is the parent class for the filters system. 
+  # New filters are mixed into the strainer class which is then instanciated for each liquid template render run. 
+  #
+  # One of the strainer's responsibilities is to keep malicious method calls out 
+  class Strainer < parent_object #:nodoc:
+    INTERNAL_METHOD = /^__/ 
+    @@required_methods = Set.new([:__send__, :__id__, :respond_to?, :extend, :methods, :class])
+    
+    @@filters = {}
+    
+    def initialize(context)
+      @context = context
+    end
+              
+    def self.global_filter(filter)
+      raise ArgumentError, "Passed filter is not a module" unless filter.is_a?(Module)
+      @@filters[filter.name] = filter
+    end
+    
+    def self.create(context)
+      strainer = Strainer.new(context)
+      @@filters.each { |k,m| strainer.extend(m) }
+      strainer
+    end
+    
+    def respond_to?(method)
+      method_name = method.to_s
+      return false if method_name =~ INTERNAL_METHOD
+      return false if @@required_methods.include?(method_name)
+      super
+    end
+    
+    # remove all standard methods from the bucket so circumvent security 
+    # problems 
+    instance_methods.each do |m| 
+      unless @@required_methods.include?(m.to_sym) 
+        undef_method m
+      end
+    end    
+  end
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tag.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tag.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tag.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,26 @@
+module Liquid
+  
+  class Tag
+    attr_accessor :nodelist
+    
+    def initialize(tag_name, markup, tokens)
+      @tag_name   = tag_name
+      @markup     = markup
+      parse(tokens)
+    end
+    
+    def parse(tokens)
+    end
+    
+    def name
+      self.class.name.downcase
+    end
+        
+    def render(context)
+      ''
+    end    
+  end
+   
+
+end
+   
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/assign.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/assign.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/assign.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,33 @@
+module Liquid
+
+  # Assign sets a variable in your template.
+  #
+  #   {% assign foo = 'monkey' %}
+  #
+  # You can then use the variable later in the page.
+  #
+  #  {{ monkey }}
+  #
+  class Assign < Tag
+    Syntax = /(#{VariableSignature}+)\s*=\s*(#{QuotedFragment}+)/   
+  
+    def initialize(tag_name, markup, tokens)          
+      if markup =~ Syntax
+        @to = $1
+        @from = $2
+      else
+        raise SyntaxError.new("Syntax Error in 'assign' - Valid syntax: assign [var] = [source]")
+      end
+      
+      super      
+    end
+  
+    def render(context)
+       context.scopes.last[@to.to_s] = context[@from]
+       ''
+    end 
+  
+  end  
+  
+  Template.register_tag('assign', Assign)  
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/capture.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/capture.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/capture.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,35 @@
+module Liquid
+  
+  # Capture stores the result of a block into a variable without rendering it inplace.
+  #
+  #   {% capture heading %}
+  #     Monkeys!
+  #   {% endcapture %}
+  #   ...
+  #   <h1>{{ monkeys }}</h1>
+  #
+  # Capture is useful for saving content for use later in your template, such as 
+  # in a sidebar or footer.
+  #
+  class Capture < Block
+    Syntax = /(\w+)/
+
+    def initialize(tag_name, markup, tokens)      
+      if markup =~ Syntax
+        @to = $1
+      else
+        raise SyntaxError.new("Syntax Error in 'capture' - Valid syntax: capture [var]")
+      end
+      
+      super       
+    end
+
+    def render(context)
+      output = super
+      context[@to] = output.to_s
+      ''
+    end
+  end  
+  
+  Template.register_tag('capture', Capture)
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/case.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/case.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/case.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,83 @@
+module Liquid
+  class Case < Block
+    Syntax     = /(#{QuotedFragment})/
+    WhenSyntax = /(#{QuotedFragment})(?:(?:\s+or\s+|\s*\,\s*)(#{QuotedFragment}.*))?/
+
+    def initialize(tag_name, markup, tokens)      
+      @blocks = []
+      
+      if markup =~ Syntax
+        @left = $1
+      else
+        raise SyntaxError.new("Syntax Error in tag 'case' - Valid syntax: case [condition]")
+      end
+            
+      super
+    end
+
+    def unknown_tag(tag, markup, tokens)
+      @nodelist = []
+      case tag
+      when 'when'
+        record_when_condition(markup)
+      when 'else'
+        record_else_condition(markup)
+      else
+        super
+      end
+    end
+
+    def render(context)      
+      context.stack do          
+        execute_else_block = true
+        
+        @blocks.inject([]) do |output, block|
+      
+          if block.else? 
+            
+            return render_all(block.attachment, context) if execute_else_block
+            
+          elsif block.evaluate(context)
+            
+            execute_else_block = false        
+            output += render_all(block.attachment, context)                    
+          end            
+      
+          output
+        end
+      end          
+    end
+    
+    private
+    
+    def record_when_condition(markup)                
+      while markup
+      	# Create a new nodelist and assign it to the new block
+      	if not markup =~ WhenSyntax
+      	  raise SyntaxError.new("Syntax Error in tag 'case' - Valid when condition: {% when [condition] [or condition2...] %} ")
+      	end
+
+      	markup = $2
+
+      	block = Condition.new(@left, '==', $1)        
+      	block.attach(@nodelist)
+      	@blocks.push(block)
+      end
+    end
+
+    def record_else_condition(markup)            
+
+      if not markup.strip.empty?
+        raise SyntaxError.new("Syntax Error in tag 'case' - Valid else condition: {% else %} (no parameters) ")
+      end
+         
+      block = ElseCondition.new            
+      block.attach(@nodelist)
+      @blocks << block
+    end
+    
+        
+  end    
+  
+  Template.register_tag('case', Case)
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/comment.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/comment.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/comment.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,9 @@
+module Liquid
+  class Comment < Block                                             
+    def render(context)
+      ''
+    end    
+  end
+  
+  Template.register_tag('comment', Comment)  
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/cycle.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/cycle.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/cycle.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,60 @@
+module Liquid
+  
+  # Cycle is usually used within a loop to alternate between values, like colors or DOM classes.
+  #
+  #   {% for item in items %}
+  #     <div class="{% cycle 'red', 'green', 'blue' %}"> {{ item }} </div>
+  #   {% end %}
+  #
+  #    <div class="red"> Item one </div>
+  #    <div class="green"> Item two </div>
+  #    <div class="blue"> Item three </div>
+  #    <div class="red"> Item four </div>
+  #    <div class="green"> Item five</div>
+  #
+  class Cycle < Tag
+    SimpleSyntax = /#{QuotedFragment}/        
+    NamedSyntax = /(#{QuotedFragment})\s*\:\s*(.*)/
+  
+    def initialize(tag_name, markup, tokens)      
+      case markup
+      when NamedSyntax
+      	@variables = variables_from_string($2)
+      	@name = $1
+      when SimpleSyntax
+        @variables = variables_from_string(markup)
+      	@name = "'#{@variables.to_s}'"
+      else
+        raise SyntaxError.new("Syntax Error in 'cycle' - Valid syntax: cycle [name :] var [, var2, var3 ...]")
+      end
+
+      super    
+    end    
+  
+    def render(context)
+      context.registers[:cycle] ||= Hash.new(0)
+    
+      context.stack do
+        key = context[@name]	
+        iteration = context.registers[:cycle][key]
+        result = context[@variables[iteration]]
+        iteration += 1    
+        iteration  = 0  if iteration >= @variables.size 
+        context.registers[:cycle][key] = iteration
+        result 
+      end
+    end
+  
+    private
+  
+    def variables_from_string(markup)
+      markup.split(',').collect do |var|
+    	  var =~ /\s*(#{QuotedFragment})\s*/
+    	  $1 ? $1 : nil
+    	end.compact
+    end
+  
+  end
+  
+  Template.register_tag('cycle', Cycle)
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/for.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/for.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/for.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,118 @@
+module Liquid
+
+  # "For" iterates over an array or collection. 
+  # Several useful variables are available to you within the loop.
+  #
+  # == Basic usage:
+  #    {% for item in collection %}
+  #      {{ forloop.index }}: {{ item.name }}
+  #    {% endfor %}
+  #
+  # == Advanced usage:
+  #    {% for item in collection %}
+  #      <div {% if forloop.first %}class="first"{% endif %}>
+  #        Item {{ forloop.index }}: {{ item.name }}
+  #      </div>
+  #    {% endfor %}
+  #
+  # You can also define a limit and offset much like SQL.  Remember
+  # that offset starts at 0 for the first item.
+  #
+  #    {% for item in collection limit:5 offset:10 %}
+  #      {{ item.name }}
+  #    {% end %}
+  #
+  # == Available variables:
+  #
+  # forloop.name:: 'item-collection'
+  # forloop.length:: Length of the loop
+  # forloop.index:: The current item's position in the collection;
+  #                 forloop.index starts at 1. 
+  #                 This is helpful for non-programmers who start believe
+  #                 the first item in an array is 1, not 0.
+  # forloop.index0:: The current item's position in the collection
+  #                  where the first item is 0
+  # forloop.rindex:: Number of items remaining in the loop
+  #                  (length - index) where 1 is the last item.
+  # forloop.rindex0:: Number of items remaining in the loop
+  #                   where 0 is the last item.
+  # forloop.first:: Returns true if the item is the first item.
+  # forloop.last:: Returns true if the item is the last item.
+  #
+  class For < Block                                             
+    Syntax = /(\w+)\s+in\s+(#{VariableSignature}+)/   
+  
+    def initialize(tag_name, markup, tokens)
+      if markup =~ Syntax
+        @variable_name = $1
+        @collection_name = $2
+        @name = "#{$1}-#{$2}"
+        @attributes = {}
+        markup.scan(TagAttributes) do |key, value|
+          @attributes[key] = value
+        end        
+      else
+        raise SyntaxError.new("Syntax Error in 'for loop' - Valid syntax: for [item] in [collection]")
+      end
+
+      super
+    end
+  
+    def render(context)        
+      context.registers[:for] ||= Hash.new(0)
+    
+      collection = context[@collection_name]
+      collection = collection.to_a if collection.is_a?(Range)
+    
+      return '' if collection.nil? or collection.empty?
+    
+      range = (0..collection.length)
+    
+      if @attributes['limit'] or @attributes['offset']
+        offset = 0
+        if @attributes['offset'] == 'continue'
+          offset = context.registers[:for][@name] 
+        else          
+          offset = context[@attributes['offset']] || 0
+        end
+        limit  = context[@attributes['limit']]
+
+        range_end = limit ? offset + limit : collection.length
+        range = (offset..range_end-1)
+      
+        # Save the range end in the registers so that future calls to 
+        # offset:continue have something to pick up
+        context.registers[:for][@name] = range_end
+      end
+            
+      result = []
+      segment = collection[range]
+      return '' if segment.nil?        
+
+      context.stack do 
+        length = segment.length
+      
+        segment.each_with_index do |item, index|
+          context[@variable_name] = item
+          context['forloop'] = {
+            'name'    => @name,
+            'length'  => length,
+            'index'   => index + 1, 
+            'index0'  => index, 
+            'rindex'  => length - index,
+            'rindex0' => length - index -1,
+            'first'   => (index == 0),
+            'last'    => (index == length - 1) }
+        
+          result << render_all(@nodelist, context)
+        end
+      end
+    
+      # Store position of last element we rendered. This allows us to do 
+    
+      result 
+    end           
+  end
+
+  Template.register_tag('for', For)
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/if.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/if.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/if.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,79 @@
+module Liquid
+
+  # If is the conditional block
+  #
+  #   {% if user.admin %}
+  #     Admin user!
+  #   {% else %}
+  #     Not admin user
+  #   {% endif %}
+  #
+  #    There are {% if count < 5 %} less {% else %} more {% endif %} items than you need.
+  #
+  #
+  class If < Block
+    SyntaxHelp = "Syntax Error in tag 'if' - Valid syntax: if [expression]"
+    Syntax = /(#{QuotedFragment})\s*([=!<>a-z_]+)?\s*(#{QuotedFragment})?/
+    
+    def initialize(tag_name, markup, tokens)    
+    
+      @blocks = []
+      
+      push_block('if', markup)
+      
+      super      
+    end
+    
+    def unknown_tag(tag, markup, tokens)
+      if ['elsif', 'else'].include?(tag)
+        push_block(tag, markup)
+      else
+        super
+      end
+    end
+    
+    def render(context)
+      context.stack do
+        @blocks.each do |block|
+          if block.evaluate(context)            
+            return render_all(block.attachment, context)            
+          end
+        end 
+        ''
+      end
+    end
+    
+    private
+    
+    def push_block(tag, markup)            
+      block = if tag == 'else'
+        ElseCondition.new
+      else        
+        
+        expressions = markup.split(/\b(and|or)\b/).reverse
+        raise SyntaxHelp unless expressions.shift =~ Syntax 
+
+        condition = Condition.new($1, $2, $3)               
+        
+        while not expressions.empty?
+          operator = expressions.shift 
+          
+          raise SyntaxHelp unless expressions.shift.to_s =~ Syntax    
+          
+          new_condition = Condition.new($1, $2, $3)
+          new_condition.send(operator.to_sym, condition)     
+          condition = new_condition          
+        end                        
+                  
+        condition
+      end
+            
+      @blocks.push(block)      
+      @nodelist = block.attach(Array.new) 
+    end
+    
+    
+  end
+
+  Template.register_tag('if', If)
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/ifchanged.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/ifchanged.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/ifchanged.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,20 @@
+module Liquid
+  class Ifchanged < Block
+            
+    def render(context)
+      context.stack do 
+        
+        output = render_all(@nodelist, context)
+        
+        if output != context.registers[:ifchanged]
+          context.registers[:ifchanged] = output
+          output
+        else
+          ''
+        end              
+      end
+    end
+  end  
+  
+  Template.register_tag('ifchanged', Ifchanged)  
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/include.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/include.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/include.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,55 @@
+module Liquid
+  class Include < Tag
+    Syntax = /(#{QuotedFragment}+)(\s+(?:with|for)\s+(#{QuotedFragment}+))?/
+  
+    def initialize(tag_name, markup, tokens)      
+      if markup =~ Syntax
+
+        @template_name = $1        
+        @variable_name = $3
+        @attributes    = {}
+
+        markup.scan(TagAttributes) do |key, value|
+          @attributes[key] = value
+        end
+
+      else
+        raise SyntaxError.new("Error in tag 'include' - Valid syntax: include '[template]' (with|for) [object|collection]")
+      end
+
+      super
+    end
+  
+    def parse(tokens)      
+    end
+  
+    def render(context)      
+      source  = Liquid::Template.file_system.read_template_file(context[@template_name])      
+      partial = Liquid::Template.parse(source)      
+      
+      variable = context[@variable_name || @template_name[1..-2]]
+      
+      context.stack do
+        @attributes.each do |key, value|
+          context[key] = context[value]
+        end
+
+        if variable.is_a?(Array)
+          
+          variable.collect do |variable|            
+            context[@template_name[1..-2]] = variable
+            partial.render(context)
+          end
+
+        else
+                    
+          context[@template_name[1..-2]] = variable
+          partial.render(context)
+          
+        end
+      end
+    end
+  end
+
+  Template.register_tag('include', Include)  
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/unless.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/unless.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/tags/unless.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,33 @@
+require File.dirname(__FILE__) + '/if'
+
+module Liquid
+
+  # Unless is a conditional just like 'if' but works on the inverse logic.
+  #
+  #   {% unless x < 0 %} x is greater than zero {% end %}
+  #
+  class Unless < If
+    def render(context)
+      context.stack do
+        
+        # First condition is interpreted backwards ( if not )
+        block = @blocks.first
+        unless block.evaluate(context)
+          return render_all(block.attachment, context)            
+        end
+        
+        # After the first condition unless works just like if
+        @blocks[1..-1].each do |block|
+          if block.evaluate(context)            
+            return render_all(block.attachment, context)            
+          end
+        end 
+        
+        ''
+      end
+    end    
+  end
+  
+
+  Template.register_tag('unless', Unless)
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/template.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/template.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/template.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,145 @@
+module Liquid
+
+  # Templates are central to liquid. 
+  # Interpretating templates is a two step process. First you compile the 
+  # source code you got. During compile time some extensive error checking is performed. 
+  # your code should expect to get some SyntaxErrors. 
+  #
+  # After you have a compiled template you can then <tt>render</tt> it. 
+  # You can use a compiled template over and over again and keep it cached. 
+  #
+  # Example: 
+  #   
+  #   template = Liquid::Template.parse(source)
+  #   template.render('user_name' => 'bob')
+  #
+  class Template
+    attr_accessor :root
+    @@file_system = BlankFileSystem.new
+    
+    class <<self
+      def file_system
+        @@file_system
+      end
+    
+      def file_system=(obj)
+        @@file_system = obj
+      end
+          
+      def register_tag(name, klass)      
+        tags[name.to_s] = klass
+      end                        
+    
+      def tags
+        @tags ||= {}
+      end
+        
+      # Pass a module with filter methods which should be available 
+      # to all liquid views. Good for registering the standard library
+      def register_filter(mod)      
+        Strainer.global_filter(mod)
+      end                        
+            
+      # creates a new <tt>Template</tt> object from liquid source code
+      def parse(source)
+        template = Template.new
+        template.parse(source)
+        template
+      end                           
+    end
+
+    # creates a new <tt>Template</tt> from an array of tokens. Use <tt>Template.parse</tt> instead
+    def initialize
+    end
+    
+    # Parse source code. 
+    # Returns self for easy chaining    
+    def parse(source)
+      @root = Document.new(tokenize(source))
+      self
+    end
+    
+    def registers 
+      @registers ||= {}
+    end
+    
+    def assigns
+      @assigns ||= {}
+    end
+    
+    def errors
+      @errors ||= []
+    end
+        
+    # Render takes a hash with local variables.
+    #
+    # if you use the same filters over and over again consider registering them globally 
+    # with <tt>Template.register_filter</tt>
+    # 
+    # Following options can be passed:
+    #  
+    #  * <tt>filters</tt> : array with local filters
+    #  * <tt>registers</tt> : hash with register variables. Those can be accessed from 
+    #    filters and tags and might be useful to integrate liquid more with its host application  
+    #
+    def render(*args)
+      return '' if @root.nil?
+
+      context = case args.first
+      when Liquid::Context
+        args.shift
+      when Hash
+        self.assigns.merge!(args.shift)        
+        Context.new(assigns, registers, @rethrow_errors)
+      when nil
+        Context.new(assigns, registers, @rethrow_errors)
+      else
+        raise ArgumentError, "Expect Hash or Liquid::Context as parameter"
+      end
+      
+      case args.last
+      when Hash
+        options = args.pop
+        
+        if options[:registers].is_a?(Hash)
+          self.registers.merge!(options[:registers])  
+        end
+
+        if options[:filters]
+          context.add_filters(options[:filters])
+        end
+      when Module
+        context.add_filters(args.pop)    
+      when Array
+        context.add_filters(args.pop)            
+      end
+                              
+                              
+      # render the nodelist.
+      # for performance reasons we get a array back here. to_s will make a string out of it
+      begin
+        @root.render(context).join
+      ensure
+        @errors = context.errors
+      end
+    end
+    
+    def render!(*args)
+      @rethrow_errors = true; render(*args)
+    end
+       
+    private
+    
+    # Uses the <tt>Liquid::TemplateParser</tt> regexp to tokenize the passed source
+    def tokenize(source)      
+      return [] if source.to_s.empty?
+      tokens = source.split(TemplateParser)
+
+      # removes the rogue empty element at the beginning of the array
+      tokens.shift if tokens[0] and tokens[0].empty? 
+
+      tokens
+    end
+     
+  end  
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/variable.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/variable.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid/variable.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,52 @@
+module Liquid
+  
+  # Holds variables. Variables are only loaded "just in time"
+  # and are not evaluated as part of the render stage
+  #
+  #   {{ monkey }}
+  #   {{ user.name }}
+  #
+  # Variables can be combined with filters:
+  #
+  #   {{ user | link }}
+  #
+  class Variable    
+    attr_accessor :filters, :name
+    
+    def initialize(markup)
+      @markup  = markup                            
+      @name    = nil
+      @filters = []
+      if match = markup.match(/\s*(#{QuotedFragment})/)
+        @name = match[1]
+        if markup.match(/#{FilterSperator}\s*(.*)/)
+          filters = Regexp.last_match(1).split(/#{FilterSperator}/)
+        
+          filters.each do |f|    
+            if matches = f.match(/\s*(\w+)/)
+              filtername = matches[1]
+              filterargs = f.scan(/(?:#{FilterArgumentSeparator}|#{ArgumentSeparator})\s*(#{QuotedFragment})/).flatten            
+              @filters << [filtername.to_sym, filterargs]
+            end
+          end
+        end
+      end
+    end                        
+
+    def render(context)      
+      return '' if @name.nil?
+      output = context[@name]
+      @filters.inject(output) do |output, filter|
+        filterargs = filter[1].to_a.collect do |a|
+         context[a]
+        end
+        begin
+          output = context.invoke(filter[0], output, *filterargs)
+        rescue FilterNotFound
+          raise FilterNotFound, "Error - filter '#{filter[0]}' in '#{@markup.strip}' could not be found."
+        end
+      end  
+      output
+    end
+  end
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/lib/liquid.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,68 @@
+# Copyright (c) 2005 Tobias Luetke
+# 
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+# 
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+
+module Liquid
+  FilterSperator              = /\|/
+  ArgumentSeparator           = ','
+  FilterArgumentSeparator     = ':'
+  VariableAttributeSeparator  = '.'
+  TagStart                    = /\{\%/
+  TagEnd                      = /\%\}/
+  VariableSignature           = /\(?[\w\-\.\[\]]\)?/
+  VariableSegment             = /[\w\-]\??/
+  VariableStart               = /\{\{/
+  VariableEnd                 = /\}\}/
+  VariableIncompleteEnd       = /\}\}?/
+  QuotedFragment              = /"[^"]+"|'[^']+'|[^\s,|]+/
+  TagAttributes               = /(\w+)\s*\:\s*(#{QuotedFragment})/
+  TemplateParser              = /(#{TagStart}.*?#{TagEnd}|#{VariableStart}.*?#{VariableIncompleteEnd})/
+  VariableParser              = /\[[^\]]+\]|#{VariableSegment}+/
+end
+
+require 'liquid/drop'
+require 'liquid/extensions'
+require 'liquid/errors'
+require 'liquid/strainer'
+require 'liquid/context'
+require 'liquid/tag'
+require 'liquid/block'
+require 'liquid/document'
+require 'liquid/variable'
+require 'liquid/file_system'
+require 'liquid/template'
+require 'liquid/htmltags'
+require 'liquid/standardfilters'
+require 'liquid/condition'
+require 'liquid/module_ex'
+
+# Load all the tags of the standard library 
+#
+Dir[File.dirname(__FILE__) + '/liquid/tags/*.rb'].each { |f| require f }
+
+
+
+
+
+
+
+

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/block_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/block_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/block_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,58 @@
+require File.dirname(__FILE__) + '/helper'
+
+class VariableTest < Test::Unit::TestCase
+  include Liquid
+
+  def test_blankspace
+    template = Liquid::Template.parse("  ")
+    assert_equal ["  "], template.root.nodelist
+  end
+
+  def test_variable_beginning
+    template = Liquid::Template.parse("{{funk}}  ")
+    assert_equal 2, template.root.nodelist.size
+    assert_equal Variable, template.root.nodelist[0].class
+    assert_equal String, template.root.nodelist[1].class
+  end
+
+  def test_variable_end
+    template = Liquid::Template.parse("  {{funk}}")
+    assert_equal 2, template.root.nodelist.size
+    assert_equal String, template.root.nodelist[0].class
+    assert_equal Variable, template.root.nodelist[1].class
+  end
+
+  def test_variable_middle
+    template = Liquid::Template.parse("  {{funk}}  ")
+    assert_equal 3, template.root.nodelist.size
+    assert_equal String, template.root.nodelist[0].class
+    assert_equal Variable, template.root.nodelist[1].class
+    assert_equal String, template.root.nodelist[2].class
+  end
+
+  def test_variable_many_embedded_fragments
+    template = Liquid::Template.parse("  {{funk}} {{so}} {{brother}} ")
+    assert_equal 7, template.root.nodelist.size
+    assert_equal [String, Variable, String, Variable, String, Variable, String], block_types(template.root.nodelist)
+  end
+  
+  def test_with_block
+    template = Liquid::Template.parse("  {% comment %} {% endcomment %} ")
+    assert_equal [String, Comment, String], block_types(template.root.nodelist)    
+    assert_equal 3, template.root.nodelist.size
+  end
+  
+  def test_with_custom_tag 
+    Liquid::Template.register_tag("testtag", Block) 
+     
+    assert_nothing_thrown do 
+      template = Liquid::Template.parse( "{% testtag %} {% endtesttag %}") 
+    end 
+  end
+  
+  private
+  
+  def block_types(nodelist)
+    nodelist.collect { |node| node.class }
+  end
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/condition_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/condition_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/condition_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,109 @@
+require File.dirname(__FILE__) + '/helper'
+
+class ConditionTest < Test::Unit::TestCase
+  include Liquid
+  
+  def test_basic_condition
+    assert_equal false, Condition.new('1', '==', '2').evaluate
+    assert_equal true,  Condition.new('1', '==', '1').evaluate
+  end
+
+  def test_default_operators_evalute_true
+    assert_evalutes_true '1', '==', '1'
+    assert_evalutes_true '1', '!=', '2'
+    assert_evalutes_true '1', '<>', '2'
+    assert_evalutes_true '1', '<', '2'
+    assert_evalutes_true '2', '>', '1'
+    assert_evalutes_true '1', '>=', '1'
+    assert_evalutes_true '2', '>=', '1'
+    assert_evalutes_true '1', '<=', '2'
+    assert_evalutes_true '1', '<=', '1'
+  end
+
+  def test_default_operators_evalute_false
+    assert_evalutes_false '1', '==', '2'
+    assert_evalutes_false '1', '!=', '1'
+    assert_evalutes_false '1', '<>', '1'
+    assert_evalutes_false '1', '<', '0'
+    assert_evalutes_false '2', '>', '4'
+    assert_evalutes_false '1', '>=', '3'
+    assert_evalutes_false '2', '>=', '4'
+    assert_evalutes_false '1', '<=', '0'
+    assert_evalutes_false '1', '<=', '0'
+  end
+
+  def test_contains_works_on_strings
+    assert_evalutes_true "'bob'", 'contains', "'o'"
+    assert_evalutes_true "'bob'", 'contains', "'b'"
+    assert_evalutes_true "'bob'", 'contains', "'bo'"
+    assert_evalutes_true "'bob'", 'contains', "'ob'"
+    assert_evalutes_true "'bob'", 'contains', "'bob'"
+
+    assert_evalutes_false "'bob'", 'contains', "'bob2'"
+    assert_evalutes_false "'bob'", 'contains', "'a'"
+    assert_evalutes_false "'bob'", 'contains', "'---'"
+  end
+
+  def test_contains_works_on_arrays
+    @context = Liquid::Context.new
+    @context['array'] = [1,2,3,4,5]
+            
+    assert_evalutes_false "array", 'contains', '0'
+    assert_evalutes_true "array", 'contains', '1'
+    assert_evalutes_true "array", 'contains', '2'
+    assert_evalutes_true "array", 'contains', '3'
+    assert_evalutes_true "array", 'contains', '4'
+    assert_evalutes_true "array", 'contains', '5'
+    assert_evalutes_false "array", 'contains', '6'
+    
+    assert_evalutes_false "array", 'contains', '"1"'        
+    
+  end  
+
+  def test_or_condition     
+    condition = Condition.new('1', '==', '2')
+
+    assert_equal false, condition.evaluate
+
+    condition.or Condition.new('2', '==', '1')
+    
+    assert_equal false, condition.evaluate
+
+    condition.or Condition.new('1', '==', '1')  
+    
+    assert_equal true, condition.evaluate
+  end
+  
+  def test_and_condition     
+    condition = Condition.new('1', '==', '1')
+
+    assert_equal true, condition.evaluate
+
+    condition.and Condition.new('2', '==', '2')
+    
+    assert_equal true, condition.evaluate
+
+    condition.and Condition.new('2', '==', '1')  
+    
+    assert_equal false, condition.evaluate
+  end
+  
+
+  def test_should_allow_custom_proc_operator
+    Condition.operators['starts_with'] = Proc.new { |cond, left, right| left =~ %r{^#{right}}}
+    
+    assert_evalutes_true "'bob'", 'starts_with', "'b'"
+    assert_evalutes_false "'bob'", 'starts_with', "'o'"
+  ensure
+    Condition.operators.delete 'starts_with'
+  end
+
+  private
+    def assert_evalutes_true(left, op, right)
+      assert Condition.new(left, op, right).evaluate(@context || Liquid::Context.new), "Evaluated false: #{left} #{op} #{right}"
+    end
+    
+    def assert_evalutes_false(left, op, right)
+      assert !Condition.new(left, op, right).evaluate(@context || Liquid::Context.new), "Evaluated true: #{left} #{op} #{right}"
+    end
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/context_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/context_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/context_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,418 @@
+require File.dirname(__FILE__) + '/helper'
+class HundredCentes
+  def to_liquid
+    100
+  end
+end
+
+class CentsDrop < Liquid::Drop
+  def amount
+    HundredCentes.new
+  end
+  
+  def non_zero?
+    true
+  end
+end
+
+class ContextSensitiveDrop < Liquid::Drop
+  def test
+    @context['test']
+  end
+end
+
+class Category < Liquid::Drop
+  attr_accessor :name
+
+  def initialize(name)
+    @name = name
+  end
+
+  def to_liquid
+    CategoryDrop.new(self)
+  end
+end
+
+class CategoryDrop
+  attr_accessor :category, :context
+  def initialize(category)
+    @category = category
+  end
+end
+
+
+class ContextTest < Test::Unit::TestCase
+  include Liquid
+
+  def setup
+    @template = Liquid::Template.new
+    @context = Liquid::Context.new(@template.assigns, @template.registers)
+  end
+
+  def test_variables
+    @context['string'] = 'string'
+    assert_equal 'string', @context['string']
+    
+    @context['num'] = 5
+    assert_equal 5, @context['num']
+    
+    @context['time'] = Time.parse('2006-06-06 12:00:00')
+    assert_equal Time.parse('2006-06-06 12:00:00'), @context['time']
+    
+    @context['date'] = Date.today
+    assert_equal Date.today, @context['date']
+    
+    now = DateTime.now
+    @context['datetime'] = now
+    assert_equal now, @context['datetime']    
+    
+    @context['bool'] = true
+    assert_equal true, @context['bool']    
+    
+    @context['bool'] = false
+    assert_equal false, @context['bool']
+    
+    @context['nil'] = nil
+    assert_equal nil, @context['nil']
+    assert_equal nil, @context['nil']    
+  end
+  
+  def test_variables_not_existing
+    assert_equal nil, @context['does_not_exist']
+  end
+  
+  def test_scoping
+    assert_nothing_raised do
+      @context.push
+      @context.pop
+    end
+    
+    assert_raise(Liquid::ContextError) do
+      @context.pop
+    end
+
+    assert_raise(Liquid::ContextError) do
+      @context.push
+      @context.pop
+      @context.pop
+    end
+  end
+  
+  def test_length_query
+    
+    @context['numbers'] = [1,2,3,4]
+    
+    assert_equal 4, @context['numbers.size']
+
+    @context['numbers'] = {1 => 1,2 => 2,3 => 3,4 => 4}
+
+    assert_equal 4, @context['numbers.size']
+    
+    @context['numbers'] = {1 => 1,2 => 2,3 => 3,4 => 4, 'size' => 1000}
+
+    assert_equal 1000, @context['numbers.size']
+    
+  end           
+  
+  def test_hyphenated_variable
+
+    @context['oh-my'] = 'godz'
+    assert_equal 'godz', @context['oh-my']
+    
+  end
+  
+  def test_add_filter
+    
+    filter = Module.new do 
+      def hi(output)
+        output + ' hi!'
+      end
+    end
+    
+    context = Context.new(@template)
+    context.add_filters(filter)
+    assert_equal 'hi? hi!', context.invoke(:hi, 'hi?')
+    
+    context = Context.new(@template)
+    assert_equal 'hi?', context.invoke(:hi, 'hi?')
+
+    context.add_filters(filter)
+    assert_equal 'hi? hi!', context.invoke(:hi, 'hi?')
+        
+  end
+  
+  def test_override_global_filter
+    global = Module.new do 
+      def notice(output)
+        "Global #{output}"
+      end
+    end
+    
+    local = Module.new do 
+      def notice(output)
+        "Local #{output}"
+      end
+    end
+        
+    Template.register_filter(global)    
+    assert_equal 'Global test', Template.parse("{{'test' | notice }}").render
+    assert_equal 'Local test', Template.parse("{{'test' | notice }}").render({}, :filters => [local])
+  end
+    
+  def test_only_intended_filters_make_it_there
+
+    filter = Module.new do 
+      def hi(output)
+        output + ' hi!'
+      end
+    end
+
+    context = Context.new(@template)
+    methods = context.strainer.methods
+    context.add_filters(filter)
+    assert_equal (methods + ['hi']).sort, context.strainer.methods.sort
+  end
+  
+  def test_add_item_in_outer_scope
+    @context['test'] = 'test'
+    @context.push
+    assert_equal 'test', @context['test']
+    @context.pop    
+    assert_equal 'test', @context['test']    
+  end
+
+  def test_add_item_in_inner_scope
+    @context.push
+    @context['test'] = 'test'
+    assert_equal 'test', @context['test']
+    @context.pop    
+    assert_equal nil, @context['test']    
+  end
+  
+  def test_hierachical_data
+    @context['hash'] = {"name" => 'tobi'}
+    assert_equal 'tobi', @context['hash.name']
+  end
+  
+  def test_keywords
+    assert_equal true, @context['true']
+    assert_equal false, @context['false']
+  end
+
+  def test_digits
+    assert_equal 100, @context['100']
+    assert_equal 100.00, @context['100.00']
+  end
+  
+  def test_strings
+    assert_equal "hello!", @context['"hello!"']
+    assert_equal "hello!", @context["'hello!'"]
+  end  
+  
+  def test_merge
+    @context.merge({ "test" => "test" })
+    assert_equal 'test', @context['test']
+    @context.merge({ "test" => "newvalue", "foo" => "bar" })
+    assert_equal 'newvalue', @context['test']
+    assert_equal 'bar', @context['foo']    
+  end
+  
+  def test_array_notation
+    @context['test'] = [1,2,3,4,5]
+
+    assert_equal 1, @context['test[0]']
+    assert_equal 2, @context['test[1]']
+    assert_equal 3, @context['test[2]']
+    assert_equal 4, @context['test[3]']
+    assert_equal 5, @context['test[4]']    
+  end
+  
+  def test_recoursive_array_notation
+    @context['test'] = {'test' => [1,2,3,4,5]}
+
+    assert_equal 1, @context['test.test[0]']
+   
+    @context['test'] = [{'test' => 'worked'}]
+
+    assert_equal 'worked', @context['test[0].test']    
+  end
+  
+  def test_hash_to_array_transition
+    @context['colors'] = {
+     'Blue'    => ['003366','336699', '6699CC', '99CCFF'],
+     'Green'   => ['003300','336633', '669966', '99CC99'],
+     'Yellow'  => ['CC9900','FFCC00', 'FFFF99', 'FFFFCC'],
+     'Red'     => ['660000','993333', 'CC6666', 'FF9999']
+    } 
+
+    assert_equal '003366', @context['colors.Blue[0]']
+    assert_equal 'FF9999', @context['colors.Red[3]']
+  end
+  
+  def test_try_first
+    @context['test'] = [1,2,3,4,5]
+
+    assert_equal 1, @context['test.first']
+    assert_equal 5, @context['test.last']
+    
+    @context['test'] = {'test' => [1,2,3,4,5]}
+        
+    assert_equal 1, @context['test.test.first']
+    assert_equal 5, @context['test.test.last']    
+    
+    @context['test'] = [1]
+    assert_equal 1, @context['test.first']
+    assert_equal 1, @context['test.last']        
+  end
+
+  def test_access_hashes_with_hash_notation
+    
+    @context['products'] = {'count' => 5, 'tags' => ['deepsnow', 'freestyle'] }
+    @context['product'] = {'variants' => [ {'title' => 'draft151cm'}, {'title' => 'element151cm'}  ]}
+
+
+    assert_equal 5, @context['products["count"]']
+    assert_equal 'deepsnow', @context['products["tags"][0]']
+    assert_equal 'deepsnow', @context['products["tags"].first']
+    assert_equal 'draft151cm', @context['product["variants"][0]["title"]']
+    assert_equal 'element151cm', @context['product["variants"][1]["title"]']
+    assert_equal 'draft151cm', @context['product["variants"][0]["title"]']
+    assert_equal 'element151cm', @context['product["variants"].last["title"]']
+  end
+  
+  def test_access_variable_with_hash_notation
+    @context['foo'] = 'baz'
+    @context['bar'] = 'foo'
+    
+    assert_equal 'baz', @context['["foo"]']
+    assert_equal 'baz', @context['[bar]']
+  end
+  
+  def test_access_hashes_with_hash_access_variables
+    
+    @context['var'] = 'tags'
+    @context['nested'] = {'var' => 'tags'}
+    @context['products'] = {'count' => 5, 'tags' => ['deepsnow', 'freestyle'] }
+
+    assert_equal 'deepsnow', @context['products[var].first']
+    assert_equal 'freestyle', @context['products[nested.var].last']
+  end
+  
+
+  def test_first_can_appear_in_middle_of_callchain
+
+    @context['product'] = {'variants' => [ {'title' => 'draft151cm'}, {'title' => 'element151cm'}  ]}
+
+    assert_equal 'draft151cm', @context['product.variants[0].title']
+    assert_equal 'element151cm', @context['product.variants[1].title']
+    assert_equal 'draft151cm', @context['product.variants.first.title']
+    assert_equal 'element151cm', @context['product.variants.last.title']
+    
+  end
+  
+  def test_cents
+    @context.merge( "cents" => HundredCentes.new )
+    assert_equal 100, @context['cents']
+  end
+
+  def test_nested_cents
+    @context.merge( "cents" => { 'amount' => HundredCentes.new} )
+    assert_equal 100, @context['cents.amount']    
+
+    @context.merge( "cents" => { 'cents' => { 'amount' => HundredCentes.new} } )
+    assert_equal 100, @context['cents.cents.amount']    
+  end
+  
+  def test_cents_through_drop
+    @context.merge( "cents" => CentsDrop.new )
+    assert_equal 100, @context['cents.amount']     
+  end
+  
+  def test_nested_cents_through_drop
+    @context.merge( "vars" => {"cents" => CentsDrop.new} )
+    assert_equal 100, @context['vars.cents.amount']     
+  end
+  
+  def test_drop_methods_with_question_marks
+    @context.merge( "cents" => CentsDrop.new )
+    assert @context['cents.non_zero?']     
+  end
+
+  def test_context_from_within_drop
+    @context.merge( "test" => '123', "vars" => ContextSensitiveDrop.new )
+    assert_equal '123', @context['vars.test']     
+  end
+
+  def test_nested_context_from_within_drop
+    @context.merge( "test" => '123', "vars" => {"local" => ContextSensitiveDrop.new }  )
+    assert_equal '123', @context['vars.local.test']     
+  end
+  
+  def test_ranges
+    @context.merge( "test" => '5' )
+    assert_equal (1..5), @context['(1..5)']
+    assert_equal (1..5), @context['(1..test)']
+    assert_equal (5..5), @context['(test..test)']
+  end
+
+  def test_cents_through_drop_nestedly
+    @context.merge( "cents" => {"cents" => CentsDrop.new} )
+    assert_equal 100, @context['cents.cents.amount']     
+
+    @context.merge( "cents" => { "cents" => {"cents" => CentsDrop.new}} )
+    assert_equal 100, @context['cents.cents.cents.amount']     
+  end
+  
+  def test_proc_as_variable
+    @context['dynamic'] = Proc.new { 'Hello' }
+    
+    assert_equal 'Hello', @context['dynamic']
+  end
+
+  def test_lambda_as_variable
+    @context['dynamic'] = lambda { 'Hello' }
+    
+    assert_equal 'Hello', @context['dynamic']
+  end
+
+  def test_nested_lambda_as_variable
+    @context['dynamic'] = { "lambda" => lambda { 'Hello' } }
+    
+    assert_equal 'Hello', @context['dynamic.lambda']
+  end
+  
+  def test_lambda_is_called_once
+    @context['callcount'] = lambda { @global ||= 0; @global += 1; @global.to_s }
+    
+    assert_equal '1', @context['callcount']
+    assert_equal '1', @context['callcount']
+    assert_equal '1', @context['callcount']    
+    
+    @global = nil
+  end
+
+  def test_nested_lambda_is_called_once
+    @context['callcount'] = { "lambda" => lambda { @global ||= 0; @global += 1; @global.to_s } }
+    
+    assert_equal '1', @context['callcount.lambda']
+    assert_equal '1', @context['callcount.lambda']
+    assert_equal '1', @context['callcount.lambda']    
+
+    @global = nil
+  end
+  
+  def test_access_to_context_from_proc
+    @context.registers[:magic] = 345392
+    
+    @context['magic'] = lambda { @context.registers[:magic] }
+    
+    assert_equal 345392, @context['magic']    
+  end
+  
+  def test_to_liquid_and_context_at_first_level
+    @context['category'] = Category.new("foobar")
+    assert_kind_of CategoryDrop, @context['category']
+    assert_equal @context, @context['category'].context
+  end
+
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/drop_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/drop_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/drop_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,141 @@
+
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/helper'
+
+class ContextDrop < Liquid::Drop
+  def scopes
+    @context.scopes.size
+  end
+
+  def scopes_as_array
+    (1.. at context.scopes.size).to_a
+  end
+  
+  def loop_pos
+    @context['forloop.index']
+  end
+
+  def break
+    Breakpoint.breakpoint
+  end
+  
+  def before_method(method)
+    return @context[method]
+  end
+end
+
+
+class ProductDrop < Liquid::Drop
+
+  class TextDrop < Liquid::Drop
+    def array
+      ['text1', 'text2']
+    end
+
+    def text
+      'text1'
+    end
+  end
+
+  class CatchallDrop < Liquid::Drop
+    def before_method(method)
+      return 'method: ' << method
+    end
+  end
+
+  def texts
+    TextDrop.new
+  end
+
+  def catchall
+    CatchallDrop.new
+  end
+  
+  def context
+    ContextDrop.new
+  end
+  
+  protected
+    def callmenot
+      "protected"
+    end
+end
+
+
+class DropsTest < Test::Unit::TestCase
+  include Liquid
+  
+  def test_product_drop
+    
+    assert_nothing_raised do
+      tpl = Liquid::Template.parse( '  '  )
+      tpl.render('product' => ProductDrop.new)
+    end
+  end
+  
+  def test_text_drop
+    output = Liquid::Template.parse( ' {{ product.texts.text }} '  ).render('product' => ProductDrop.new)
+    assert_equal ' text1 ', output
+
+  end
+
+  def test_text_drop
+    output = Liquid::Template.parse( ' {{ product.catchall.unknown }} '  ).render('product' => ProductDrop.new)
+    assert_equal ' method: unknown ', output
+
+  end
+
+  def test_text_array_drop
+    output = Liquid::Template.parse( '{% for text in product.texts.array %} {{text}} {% endfor %}'  ).render('product' => ProductDrop.new)
+    assert_equal ' text1  text2 ', output
+  end
+  
+  def test_context_drop
+    output = Liquid::Template.parse( ' {{ context.bar }} '  ).render('context' => ContextDrop.new, 'bar' => "carrot")
+    assert_equal ' carrot ', output
+  end
+  
+  def test_nested_context_drop
+    output = Liquid::Template.parse( ' {{ product.context.foo }} '  ).render('product' => ProductDrop.new, 'foo' => "monkey")
+    assert_equal ' monkey ', output
+  end  
+
+  def test_protected
+    output = Liquid::Template.parse( ' {{ product.callmenot }} '  ).render('product' => ProductDrop.new)
+    assert_equal '  ', output    
+  end
+  
+  def test_scope
+    assert_equal '1', Liquid::Template.parse( '{{ context.scopes }}'  ).render('context' => ContextDrop.new)    
+    assert_equal '2', Liquid::Template.parse( '{%for i in dummy%}{{ context.scopes }}{%endfor%}'  ).render('context' => ContextDrop.new, 'dummy' => [1])
+    assert_equal '3', Liquid::Template.parse( '{%for i in dummy%}{%for i in dummy%}{{ context.scopes }}{%endfor%}{%endfor%}'  ).render('context' => ContextDrop.new, 'dummy' => [1])
+  end
+  
+  def test_scope_though_proc
+    assert_equal '1', Liquid::Template.parse( '{{ s }}'  ).render('context' => ContextDrop.new, 's' => Proc.new{|c| c['context.scopes'] })    
+    assert_equal '2', Liquid::Template.parse( '{%for i in dummy%}{{ s }}{%endfor%}'  ).render('context' => ContextDrop.new, 's' => Proc.new{|c| c['context.scopes'] }, 'dummy' => [1])
+    assert_equal '3', Liquid::Template.parse( '{%for i in dummy%}{%for i in dummy%}{{ s }}{%endfor%}{%endfor%}'  ).render('context' => ContextDrop.new, 's' => Proc.new{|c| c['context.scopes'] }, 'dummy' => [1])
+  end
+  
+  def test_scope_with_assigns
+    assert_equal 'variable', Liquid::Template.parse( '{% assign a = "variable"%}{{a}}'  ).render('context' => ContextDrop.new)    
+    assert_equal 'variable', Liquid::Template.parse( '{% assign a = "variable"%}{%for i in dummy%}{{a}}{%endfor%}'  ).render('context' => ContextDrop.new, 'dummy' => [1])    
+    assert_equal 'test', Liquid::Template.parse( '{% assign header_gif = "test"%}{{header_gif}}'  ).render('context' => ContextDrop.new)    
+    assert_equal 'test', Liquid::Template.parse( "{% assign header_gif = 'test'%}{{header_gif}}"  ).render('context' => ContextDrop.new)    
+  end
+    
+  def test_scope_from_tags
+    assert_equal '1', Liquid::Template.parse( '{% for i in context.scopes_as_array %}{{i}}{% endfor %}'  ).render('context' => ContextDrop.new, 'dummy' => [1])    
+    assert_equal '12', Liquid::Template.parse( '{%for a in dummy%}{% for i in context.scopes_as_array %}{{i}}{% endfor %}{% endfor %}'  ).render('context' => ContextDrop.new, 'dummy' => [1])    
+    assert_equal '123', Liquid::Template.parse( '{%for a in dummy%}{%for a in dummy%}{% for i in context.scopes_as_array %}{{i}}{% endfor %}{% endfor %}{% endfor %}'  ).render('context' => ContextDrop.new, 'dummy' => [1])                
+  end
+  
+  def test_access_context_from_drop
+    assert_equal '123', Liquid::Template.parse( '{%for a in dummy%}{{ context.loop_pos }}{% endfor %}'  ).render('context' => ContextDrop.new, 'dummy' => [1,2,3])            
+  end
+  
+  
+  
+end
+
+

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/error_handling_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/error_handling_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/error_handling_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,78 @@
+
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/helper'
+
+class ErrorDrop < Liquid::Drop
+  def standard_error
+    raise Liquid::StandardError, 'standard error'
+  end  
+
+  def argument_error
+    raise Liquid::ArgumentError, 'argument error'
+  end  
+  
+  def syntax_error
+    raise Liquid::SyntaxError, 'syntax error'
+  end  
+  
+end
+
+
+class ErrorHandlingTest < Test::Unit::TestCase
+  include Liquid
+  
+  def test_standard_error
+    assert_nothing_raised do 
+      template = Liquid::Template.parse( ' {{ errors.standard_error }} '  )
+      assert_equal ' Liquid error: standard error ', template.render('errors' => ErrorDrop.new)
+      
+      assert_equal 1, template.errors.size
+      assert_equal StandardError, template.errors.first.class
+    end
+  end
+  
+  def test_syntax    
+
+    assert_nothing_raised do 
+    
+      template = Liquid::Template.parse( ' {{ errors.syntax_error }} '  )
+      assert_equal ' Liquid syntax error: syntax error ', template.render('errors' => ErrorDrop.new)
+      
+      assert_equal 1, template.errors.size
+      assert_equal SyntaxError, template.errors.first.class
+      
+    end
+    
+  end
+  
+  def test_argument
+
+    assert_nothing_raised do 
+    
+      template = Liquid::Template.parse( ' {{ errors.argument_error }} '  )
+      assert_equal ' Liquid error: argument error ', template.render('errors' => ErrorDrop.new)
+      
+      assert_equal 1, template.errors.size
+      assert_equal ArgumentError, template.errors.first.class
+      
+    end
+    
+  end
+  
+  def test_unrecognized_operator
+    
+    assert_nothing_raised do
+      
+      template = Liquid::Template.parse(' {% if 1 =! 2 %}ok{% endif %} ')
+      assert_equal ' Liquid error: Unknown operator =! ', template.render
+      
+      assert_equal 1, template.errors.size
+      assert_equal Liquid::ArgumentError, template.errors.first.class
+      
+    end
+    
+  end
+  
+end
+
+

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/extra/breakpoint.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/extra/breakpoint.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/extra/breakpoint.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,547 @@
+# The Breakpoint library provides the convenience of
+# being able to inspect and modify state, diagnose
+# bugs all via IRB by simply setting breakpoints in
+# your applications by the call of a method.
+#
+# This library was written and is supported by me,
+# Florian Gross. I can be reached at flgr at ccan.de
+# and enjoy getting feedback about my libraries.
+#
+# The whole library (including breakpoint_client.rb
+# and binding_of_caller.rb) is licensed under the
+# same license that Ruby uses. (Which is currently
+# either the GNU General Public License or a custom
+# one that allows for commercial usage.) If you for
+# some good reason need to use this under another
+# license please contact me.
+
+require 'irb'
+require 'caller'
+require 'drb'
+require 'drb/acl'
+require 'thread'
+
+module Breakpoint
+  id = %q$Id: breakpoint.rb 52 2005-02-26 19:43:19Z flgr $
+  current_version = id.split(" ")[2]
+  unless defined?(Version)
+    # The Version of ruby-breakpoint you are using as String of the
+    # 1.2.3 form where the digits stand for release, major and minor
+    # version respectively.
+    Version = "0.5.0"
+  end
+
+  extend self
+
+  # This will pop up an interactive ruby session at a
+  # pre-defined break point in a Ruby application. In
+  # this session you can examine the environment of
+  # the break point.
+  #
+  # You can get a list of variables in the context using
+  # local_variables via +local_variables+. You can then
+  # examine their values by typing their names.
+  #
+  # You can have a look at the call stack via +caller+.
+  #
+  # The source code around the location where the breakpoint
+  # was executed can be examined via +source_lines+. Its
+  # argument specifies how much lines of context to display.
+  # The default amount of context is 5 lines. Note that
+  # the call to +source_lines+ can raise an exception when
+  # it isn't able to read in the source code.
+  #
+  # breakpoints can also return a value. They will execute
+  # a supplied block for getting a default return value.
+  # A custom value can be returned from the session by doing
+  # +throw(:debug_return, value)+.
+  #
+  # You can also give names to break points which will be
+  # used in the message that is displayed upon execution 
+  # of them.
+  #
+  # Here's a sample of how breakpoints should be placed:
+  #
+  #   class Person
+  #     def initialize(name, age)
+  #       @name, @age = name, age
+  #       breakpoint("Person#initialize")
+  #     end
+  #
+  #     attr_reader :age
+  #     def name
+  #       breakpoint("Person#name") { @name }
+  #     end
+  #   end
+  #
+  #   person = Person.new("Random Person", 23)
+  #   puts "Name: #{person.name}"
+  #
+  # And here is a sample debug session:
+  #
+  #   Executing break point "Person#initialize" at file.rb:4 in `initialize'
+  #   irb(#<Person:0x292fbe8>):001:0> local_variables
+  #   => ["name", "age", "_", "__"]
+  #   irb(#<Person:0x292fbe8>):002:0> [name, age]
+  #   => ["Random Person", 23]
+  #   irb(#<Person:0x292fbe8>):003:0> [@name, @age]
+  #   => ["Random Person", 23]
+  #   irb(#<Person:0x292fbe8>):004:0> self
+  #   => #<Person:0x292fbe8 @age=23, @name="Random Person">
+  #   irb(#<Person:0x292fbe8>):005:0> @age += 1; self
+  #   => #<Person:0x292fbe8 @age=24, @name="Random Person">
+  #   irb(#<Person:0x292fbe8>):006:0> exit
+  #   Executing break point "Person#name" at file.rb:9 in `name'
+  #   irb(#<Person:0x292fbe8>):001:0> throw(:debug_return, "Overriden name")
+  #   Name: Overriden name
+  #
+  # Breakpoint sessions will automatically have a few
+  # convenience methods available. See Breakpoint::CommandBundle
+  # for a list of them.
+  #
+  # Breakpoints can also be used remotely over sockets.
+  # This is implemented by running part of the IRB session
+  # in the application and part of it in a special client.
+  # You have to call Breakpoint.activate_drb to enable
+  # support for remote breakpoints and then run
+  # breakpoint_client.rb which is distributed with this
+  # library. See the documentation of Breakpoint.activate_drb
+  # for details.
+  def breakpoint(id = nil, context = nil, &block)
+    callstack = caller
+    callstack.slice!(0, 3) if callstack.first["breakpoint"]
+    file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
+
+    message = "Executing break point " + (id ? "#{id.inspect} " : "") +
+              "at #{file}:#{line}" + (method ? " in `#{method}'" : "")
+
+    if context then
+      return handle_breakpoint(context, message, file, line, &block)
+    end
+
+    Binding.of_caller do |binding_context|
+      handle_breakpoint(binding_context, message, file, line, &block)
+    end
+  end
+
+  # These commands are automatically available in all breakpoint shells.
+  module CommandBundle
+    # Proxy to a Breakpoint client. Lets you directly execute code
+    # in the context of the client.
+    class Client
+      def initialize(eval_handler) # :nodoc:
+        eval_handler.untaint
+        @eval_handler = eval_handler
+      end
+
+      instance_methods.each do |method|
+        next if method[/^__.+__$/]
+        undef_method method
+      end
+
+      # Executes the specified code at the client.
+      def eval(code)
+        @eval_handler.call(code)
+      end
+
+      # Will execute the specified statement at the client.
+      def method_missing(method, *args, &block)
+        if args.empty? and not block
+          result = eval "#{method}"
+        else
+          # This is a bit ugly. The alternative would be using an
+          # eval context instead of an eval handler for executing
+          # the code at the client. The problem with that approach
+          # is that we would have to handle special expressions
+          # like "self", "nil" or constants ourself which is hard.
+          remote = eval %{
+            result = lambda { |block, *args| #{method}(*args, &block) }
+            def result.call_with_block(*args, &block)
+              call(block, *args)
+            end
+            result
+          }
+          remote.call_with_block(*args, &block)
+        end
+
+        return result
+      end
+    end
+
+    # Returns the source code surrounding the location where the
+    # breakpoint was issued.
+    def source_lines(context = 5, return_line_numbers = false)
+      lines = File.readlines(@__bp_file).map { |line| line.chomp }
+
+      break_line = @__bp_line
+      start_line = [break_line - context, 1].max
+      end_line = break_line + context
+
+      result = lines[(start_line - 1) .. (end_line - 1)]
+
+      if return_line_numbers then
+        return [start_line, break_line, result]
+      else
+        return result
+      end
+    end
+
+    # Lets an object that will forward method calls to the breakpoint
+    # client. This is useful for outputting longer things at the client
+    # and so on. You can for example do these things:
+    #
+    #   client.puts "Hello" # outputs "Hello" at client console
+    #   # outputs "Hello" into the file temp.txt at the client
+    #   client.File.open("temp.txt", "w") { |f| f.puts "Hello" } 
+    def client()
+      if Breakpoint.use_drb? then
+        sleep(0.5) until Breakpoint.drb_service.eval_handler
+        Client.new(Breakpoint.drb_service.eval_handler)
+      else
+        Client.new(lambda { |code| eval(code, TOPLEVEL_BINDING) })
+      end
+    end
+  end
+
+  def handle_breakpoint(context, message, file = "", line = "", &block) # :nodoc:
+    catch(:debug_return) do |value|
+      eval(%{
+        @__bp_file = #{file.inspect}
+        @__bp_line = #{line}
+        extend Breakpoint::CommandBundle
+        extend DRbUndumped if self
+      }, context) rescue nil
+
+      if not use_drb? then
+        puts message
+        IRB.start(nil, IRB::WorkSpace.new(context))
+      else
+        @drb_service.add_breakpoint(context, message)
+      end
+
+      block.call if block
+    end
+  end
+
+  # These exceptions will be raised on failed asserts
+  # if Breakpoint.asserts_cause_exceptions is set to
+  # true.
+  class FailedAssertError < RuntimeError
+  end
+
+  # This asserts that the block evaluates to true.
+  # If it doesn't evaluate to true a breakpoint will
+  # automatically be created at that execution point.
+  #
+  # You can disable assert checking in production
+  # code by setting Breakpoint.optimize_asserts to
+  # true. (It will still be enabled when Ruby is run
+  # via the -d argument.)
+  #
+  # Example:
+  #   person_name = "Foobar"
+  #   assert { not person_name.nil? }
+  #
+  # Note: If you want to use this method from an
+  # unit test, you will have to call it by its full
+  # name, Breakpoint.assert.
+  def assert(context = nil, &condition)
+    return if Breakpoint.optimize_asserts and not $DEBUG
+    return if yield
+
+    callstack = caller
+    callstack.slice!(0, 3) if callstack.first["assert"]
+    file, line, method = *callstack.first.match(/^(.+?):(\d+)(?::in `(.*?)')?/).captures
+
+    message = "Assert failed at #{file}:#{line}#{" in `#{method}'" if method}."
+
+    if Breakpoint.asserts_cause_exceptions and not $DEBUG then
+      raise(Breakpoint::FailedAssertError, message)
+    end
+
+    message += " Executing implicit breakpoint."
+
+    if context then
+      return handle_breakpoint(context, message, file, line)
+    end
+
+    Binding.of_caller do |context|
+      handle_breakpoint(context, message, file, line)
+    end
+  end
+
+  # Whether asserts should be ignored if not in debug mode.
+  # Debug mode can be enabled by running ruby with the -d
+  # switch or by setting $DEBUG to true.
+  attr_accessor :optimize_asserts
+  self.optimize_asserts = false
+
+  # Whether an Exception should be raised on failed asserts
+  # in non-$DEBUG code or not. By default this is disabled.
+  attr_accessor :asserts_cause_exceptions
+  self.asserts_cause_exceptions = false
+  @use_drb = false
+
+  attr_reader :drb_service # :nodoc:
+
+  class DRbService # :nodoc:
+    include DRbUndumped
+
+    def initialize
+      @handler = @eval_handler = @collision_handler = nil
+
+      IRB.instance_eval { @CONF[:RC] = true }
+      IRB.run_config
+    end
+
+    def collision
+      sleep(0.5) until @collision_handler
+
+      @collision_handler.untaint
+
+      @collision_handler.call
+    end
+
+    def ping() end
+
+    def add_breakpoint(context, message)
+      workspace = IRB::WorkSpace.new(context)
+      workspace.extend(DRbUndumped)
+
+      sleep(0.5) until @handler
+
+      @handler.untaint
+      @handler.call(workspace, message)
+    rescue Errno::ECONNREFUSED, DRb::DRbConnError
+      raise if Breakpoint.use_drb? 
+    end
+
+    attr_accessor :handler, :eval_handler, :collision_handler
+  end
+
+  # Will run Breakpoint in DRb mode. This will spawn a server
+  # that can be attached to via the breakpoint-client command
+  # whenever a breakpoint is executed. This is useful when you
+  # are debugging CGI applications or other applications where
+  # you can't access debug sessions via the standard input and
+  # output of your application.
+  #
+  # You can specify an URI where the DRb server will run at.
+  # This way you can specify the port the server runs on. The
+  # default URI is druby://localhost:42531.
+  #
+  # Please note that breakpoints will be skipped silently in
+  # case the DRb server can not spawned. (This can happen if
+  # the port is already used by another instance of your
+  # application on CGI or another application.)
+  #
+  # Also note that by default this will only allow access
+  # from localhost. You can however specify a list of
+  # allowed hosts or nil (to allow access from everywhere).
+  # But that will still not protect you from somebody
+  # reading the data as it goes through the net.
+  #
+  # A good approach for getting security and remote access
+  # is setting up an SSH tunnel between the DRb service
+  # and the client. This is usually done like this:
+  #
+  # $ ssh -L20000:127.0.0.1:20000 -R10000:127.0.0.1:10000 example.com
+  # (This will connect port 20000 at the client side to port
+  # 20000 at the server side, and port 10000 at the server
+  # side to port 10000 at the client side.)
+  #
+  # After that do this on the server side: (the code being debugged)
+  # Breakpoint.activate_drb("druby://127.0.0.1:20000", "localhost")
+  #
+  # And at the client side:
+  # ruby breakpoint_client.rb -c druby://127.0.0.1:10000 -s druby://127.0.0.1:20000
+  #
+  # Running through such a SSH proxy will also let you use 
+  # breakpoint.rb in case you are behind a firewall.
+  #
+  # Detailed information about running DRb through firewalls is
+  # available at http://www.rubygarden.org/ruby?DrbTutorial
+  #
+  # == Security considerations
+  # Usually you will be fine when using the default druby:// URI and the default
+  # access control list. However, if you are sitting on a machine where there are
+  # local users that you likely can not trust (this is the case for example on
+  # most web hosts which have multiple users sitting on the same physical machine)
+  # you will be better off by doing client/server communication through a unix
+  # socket. This can be accomplished by calling with a drbunix:/ style URI, e.g.
+  # <code>Breakpoint.activate_drb('drbunix:/tmp/breakpoint_server')</code>. This
+  # will only work on Unix based platforms.
+  def activate_drb(uri = nil, allowed_hosts = ['localhost', '127.0.0.1', '::1'],
+    ignore_collisions = false)
+
+    return false if @use_drb
+
+    uri ||= 'druby://localhost:42531'
+
+    if allowed_hosts then
+      acl = ["deny", "all"]
+
+      Array(allowed_hosts).each do |host|
+        acl += ["allow", host]
+      end
+
+      DRb.install_acl(ACL.new(acl))
+    end
+
+    @use_drb = true
+    @drb_service = DRbService.new
+    did_collision = false
+    begin
+      @service = DRb.start_service(uri, @drb_service)
+    rescue Errno::EADDRINUSE
+      if ignore_collisions then
+        nil
+      else
+        # The port is already occupied by another
+        # Breakpoint service. We will try to tell
+        # the old service that we want its port.
+        # It will then forward that request to the
+        # user and retry.
+        unless did_collision then
+          DRbObject.new(nil, uri).collision
+          did_collision = true
+        end
+        sleep(10)
+        retry
+      end
+    end
+
+    return true
+  end
+
+  # Deactivates a running Breakpoint service.
+  def deactivate_drb
+    Thread.exclusive do
+      @service.stop_service unless @service.nil?
+      @service = nil
+      @use_drb = false
+      @drb_service = nil
+    end
+  end
+
+  # Returns true when Breakpoints are used over DRb.
+  # Breakpoint.activate_drb causes this to be true.
+  def use_drb?
+    @use_drb == true
+  end
+end
+
+module IRB # :nodoc:
+  class << self; remove_method :start; end
+  def self.start(ap_path = nil, main_context = nil, workspace = nil)
+    $0 = File::basename(ap_path, ".rb") if ap_path
+
+    # suppress some warnings about redefined constants
+    old_verbose, $VERBOSE = $VERBOSE, nil
+    IRB.setup(ap_path)
+    $VERBOSE = old_verbose
+
+    if @CONF[:SCRIPT] then
+      irb = Irb.new(main_context, @CONF[:SCRIPT])
+    else
+      irb = Irb.new(main_context)
+    end
+
+    if workspace then
+      irb.context.workspace = workspace
+    end
+
+    @CONF[:IRB_RC].call(irb.context) if @CONF[:IRB_RC]
+    @CONF[:MAIN_CONTEXT] = irb.context
+
+    old_sigint = trap("SIGINT") do
+      begin
+        irb.signal_handle
+      rescue RubyLex::TerminateLineInput
+        # ignored
+      end
+    end
+    
+    catch(:IRB_EXIT) do
+      irb.eval_input
+    end
+  ensure
+    trap("SIGINT", old_sigint)
+  end
+
+  class << self
+    alias :old_CurrentContext :CurrentContext
+    remove_method :CurrentContext
+    remove_method :parse_opts
+  end
+
+  def IRB.CurrentContext
+    if old_CurrentContext.nil? and Breakpoint.use_drb? then
+      result = Object.new
+      def result.last_value; end
+      return result
+    else
+      old_CurrentContext
+    end
+  end
+  def IRB.parse_opts() end
+
+  class Context # :nodoc:
+    alias :old_evaluate :evaluate
+    def evaluate(line, line_no)
+      if line.chomp == "exit" then
+        exit
+      else
+        old_evaluate(line, line_no)
+      end
+    end
+  end
+
+  class WorkSpace # :nodoc:
+    alias :old_evaluate :evaluate
+
+    def evaluate(*args)
+      if Breakpoint.use_drb? then
+        result = old_evaluate(*args)
+        if args[0] != :no_proxy and
+          not [true, false, nil].include?(result)
+        then
+          result.extend(DRbUndumped) rescue nil
+        end
+        return result
+      else
+        old_evaluate(*args)
+      end
+    end
+  end
+
+  module InputCompletor # :nodoc:
+    def self.eval(code, context, *more)
+      # Big hack, this assumes that InputCompletor
+      # will only call eval() when it wants code
+      # to be executed in the IRB context.
+      IRB.conf[:MAIN_CONTEXT].workspace.evaluate(:no_proxy, code, *more)
+    end
+  end
+end
+
+module DRb # :nodoc:
+  class DRbObject # :nodoc:
+    undef :inspect if method_defined?(:inspect)
+    undef :clone if method_defined?(:clone)
+  end
+end
+
+# See Breakpoint.breakpoint
+def breakpoint(id = nil, &block)
+  Binding.of_caller do |context|
+    Breakpoint.breakpoint(id, context, &block)
+  end
+end
+
+# See Breakpoint.assert
+def assert(&block)
+  Binding.of_caller do |context|
+    Breakpoint.assert(context, &block)
+  end
+end


Property changes on: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/extra/breakpoint.rb
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/extra/caller.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/extra/caller.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/extra/caller.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,80 @@
+class Continuation # :nodoc:
+  def self.create(*args, &block) # :nodoc:
+    cc = nil; result = callcc {|c| cc = c; block.call(cc) if block and args.empty?}
+    result ||= args
+    return *[cc, *result]
+  end
+end
+
+class Binding; end # for RDoc
+# This method returns the binding of the method that called your
+# method. It will raise an Exception when you're not inside a method.
+#
+# It's used like this:
+#   def inc_counter(amount = 1)
+#     Binding.of_caller do |binding|
+#       # Create a lambda that will increase the variable 'counter'
+#       # in the caller of this method when called.
+#       inc = eval("lambda { |arg| counter += arg }", binding)
+#       # We can refer to amount from inside this block safely.
+#       inc.call(amount)
+#     end
+#     # No other statements can go here. Put them inside the block.
+#   end
+#   counter = 0
+#   2.times { inc_counter }
+#   counter # => 2
+#
+# Binding.of_caller must be the last statement in the method.
+# This means that you will have to put everything you want to
+# do after the call to Binding.of_caller into the block of it.
+# This should be no problem however, because Ruby has closures.
+# If you don't do this an Exception will be raised. Because of
+# the way that Binding.of_caller is implemented it has to be
+# done this way.
+def Binding.of_caller(&block)
+  old_critical = Thread.critical
+  Thread.critical = true
+  count = 0
+  cc, result, error, extra_data = Continuation.create(nil, nil)
+  error.call if error
+
+  tracer = lambda do |*args|
+    type, context, extra_data = args[0], args[4], args
+    if type == "return"
+      count += 1
+      # First this method and then calling one will return --
+      # the trace event of the second event gets the context
+      # of the method which called the method that called this
+      # method.
+      if count == 2
+        # It would be nice if we could restore the trace_func
+        # that was set before we swapped in our own one, but
+        # this is impossible without overloading set_trace_func
+        # in current Ruby.
+        set_trace_func(nil)
+        cc.call(eval("binding", context), nil, extra_data)
+      end
+    elsif type == "line" then
+      nil
+    elsif type == "c-return" and extra_data[3] == :set_trace_func then
+      nil
+    else
+      set_trace_func(nil)
+      error_msg = "Binding.of_caller used in non-method context or " +
+        "trailing statements of method using it aren't in the block."
+      cc.call(nil, lambda { raise(ArgumentError, error_msg) }, nil)
+    end
+  end
+
+  unless result
+    set_trace_func(tracer)
+    return nil
+  else
+    Thread.critical = old_critical
+    case block.arity
+      when 1 then yield(result)
+      else yield(result, extra_data)        
+    end
+  end
+end


Property changes on: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/extra/caller.rb
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/file_system_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/file_system_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/file_system_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,30 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/helper'
+
+class FileSystemTest < Test::Unit::TestCase
+  include Liquid
+  
+  def test_default
+    assert_raise(FileSystemError) do
+      BlankFileSystem.new.read_template_file("dummy")
+    end
+  end
+  
+  def test_local
+    file_system = Liquid::LocalFileSystem.new("/some/path")
+    assert_equal "/some/path/_mypartial.liquid"    , file_system.full_path("mypartial")   
+    assert_equal "/some/path/dir/_mypartial.liquid", file_system.full_path("dir/mypartial")
+
+    assert_raise(FileSystemError) do
+      file_system.full_path("../dir/mypartial")
+    end
+
+    assert_raise(FileSystemError) do
+      file_system.full_path("/dir/../../dir/mypartial")      
+    end
+
+    assert_raise(FileSystemError) do
+      file_system.full_path("/etc/passwd")
+    end
+  end
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/filter_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/filter_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/filter_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,98 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/helper'
+
+
+module MoneyFilter
+  def money(input)
+    sprintf(' %d$ ', input)
+  end
+  
+  def money_with_underscore(input)
+    sprintf(' %d$ ', input)
+  end
+end
+
+module CanadianMoneyFilter
+  def money(input)
+    sprintf(' %d$ CAD ', input)
+  end
+end
+
+
+class FiltersTest < Test::Unit::TestCase
+  include Liquid
+  
+  def setup
+    @context = Context.new
+  end
+    
+  def test_local_filter    
+    @context['var'] = 1000
+    @context.add_filters(MoneyFilter)
+    assert_equal ' 1000$ ', Variable.new("var | money").render(@context)
+  end  
+  
+  def test_underscore_in_filter_name
+    @context['var'] = 1000
+    @context.add_filters(MoneyFilter)
+    assert_equal ' 1000$ ', Variable.new("var | money_with_underscore").render(@context)
+  end
+
+  def test_second_filter_overwrites_first    
+    @context['var'] = 1000
+    @context.add_filters(MoneyFilter)
+    @context.add_filters(CanadianMoneyFilter)  
+    assert_equal ' 1000$ CAD ', Variable.new("var | money").render(@context)    
+  end
+  
+  def test_size
+    @context['var'] = 'abcd'
+    @context.add_filters(MoneyFilter)
+    assert_equal 4, Variable.new("var | size").render(@context)
+  end
+
+  def test_join
+    @context['var'] = [1,2,3,4]
+    assert_equal "1 2 3 4", Variable.new("var | join").render(@context)    
+  end
+
+  def test_sort
+    @context['value'] = 3
+    @context['numbers'] = [2,1,4,3]
+    @context['words'] = ['expected', 'as', 'alphabetic']
+    @context['arrays'] = [['flattened'], ['are']]
+    assert_equal [1,2,3,4], Variable.new("numbers | sort").render(@context)
+    assert_equal ['alphabetic', 'as', 'expected'],
+      Variable.new("words | sort").render(@context)
+    assert_equal [3], Variable.new("value | sort").render(@context)
+    assert_equal ['are', 'flattened'], Variable.new("arrays | sort").render(@context)
+  end
+  
+  def test_strip_html
+    @context['var'] = "<b>bla blub</a>"
+    assert_equal "bla blub", Variable.new("var | strip_html").render(@context)    
+  end
+
+  def test_capitalize
+    @context['var'] = "blub"
+    assert_equal "Blub", Variable.new("var | capitalize").render(@context)    
+  end
+end
+
+class FiltersInTemplate < Test::Unit::TestCase
+  include Liquid
+
+  def test_local_global
+    Template.register_filter(MoneyFilter)
+    
+    assert_equal " 1000$ ", Template.parse("{{1000 | money}}").render(nil, nil)
+    assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, :filters => CanadianMoneyFilter)
+    assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, :filters => [CanadianMoneyFilter])
+  end
+  
+  def test_local_filter_with_deprecated_syntax
+    assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, CanadianMoneyFilter)
+    assert_equal " 1000$ CAD ", Template.parse("{{1000 | money}}").render(nil, [CanadianMoneyFilter])
+  end
+  
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/helper.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/helper.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/helper.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+$LOAD_PATH.unshift(File.dirname(__FILE__)+ '/extra')
+
+require 'test/unit'
+require 'test/unit/assertions'
+require 'caller'
+require 'breakpoint'
+require File.dirname(__FILE__) + '/../lib/liquid'
+
+
+module Test
+  module Unit
+    module Assertions
+        include Liquid
+        def assert_template_result(expected, template, assigns={}, message=nil)
+          assert_equal expected, Template.parse(template).render(assigns)
+        end 
+    end
+  end
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/html_tag_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/html_tag_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/html_tag_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,31 @@
+require File.dirname(__FILE__) + '/helper'
+
+class HtmlTagTest < Test::Unit::TestCase
+  include Liquid
+  
+  def test_html_table
+    
+    assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 4 </td><td class=\"col2\"> 5 </td><td class=\"col3\"> 6 </td></tr>\n",
+                           '{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}', 
+                           'numbers' => [1,2,3,4,5,6])
+
+    assert_template_result("<tr class=\"row1\">\n</tr>\n",
+                            '{% tablerow n in numbers cols:3%} {{n}} {% endtablerow %}', 
+                            'numbers' => [])
+  end
+  
+  def test_html_table_with_different_cols
+    assert_template_result("<tr class=\"row1\">\n<td class=\"col1\"> 1 </td><td class=\"col2\"> 2 </td><td class=\"col3\"> 3 </td><td class=\"col4\"> 4 </td><td class=\"col5\"> 5 </td></tr>\n<tr class=\"row2\"><td class=\"col1\"> 6 </td></tr>\n",
+                           '{% tablerow n in numbers cols:5%} {{n}} {% endtablerow %}', 
+                           'numbers' => [1,2,3,4,5,6])
+    
+  end
+  
+  def test_html_col_counter
+    assert_template_result("<tr class=\"row1\">\n<td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n<tr class=\"row2\"><td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n<tr class=\"row3\"><td class=\"col1\">1</td><td class=\"col2\">2</td></tr>\n",
+                           '{% tablerow n in numbers cols:2%}{{tablerowloop.col}}{% endtablerow %}', 
+                           'numbers' => [1,2,3,4,5,6])
+    
+  end
+  
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/if_else_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/if_else_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/if_else_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,127 @@
+require File.dirname(__FILE__) + '/helper'
+
+class IfElseTest < Test::Unit::TestCase
+  include Liquid
+
+  def test_if
+    assert_template_result('  ',' {% if false %} this text should not go into the output {% endif %} ')
+    assert_template_result('  this text should go into the output  ',
+              ' {% if true %} this text should go into the output {% endif %} ')
+    assert_template_result('  you rock ?','{% if false %} you suck {% endif %} {% if true %} you rock {% endif %}?')
+  end
+
+  def test_if_else
+    assert_template_result(' YES ','{% if false %} NO {% else %} YES {% endif %}')
+    assert_template_result(' YES ','{% if true %} YES {% else %} NO {% endif %}')
+    assert_template_result(' YES ','{% if "foo" %} YES {% else %} NO {% endif %}')
+  end
+  
+  def test_if_boolean
+    assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => true)    
+  end        
+  
+  def test_if_or
+    assert_template_result(' YES ','{% if a or b %} YES {% endif %}', 'a' => true, 'b' => true)    
+    assert_template_result(' YES ','{% if a or b %} YES {% endif %}', 'a' => true, 'b' => false)    
+    assert_template_result(' YES ','{% if a or b %} YES {% endif %}', 'a' => false, 'b' => true)    
+    assert_template_result('',     '{% if a or b %} YES {% endif %}', 'a' => false, 'b' => false)        
+
+    assert_template_result(' YES ','{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => true)    
+    assert_template_result('',     '{% if a or b or c %} YES {% endif %}', 'a' => false, 'b' => false, 'c' => false)        
+  end
+  
+  def test_if_or_with_operators
+    assert_template_result(' YES ','{% if a == true or b == true %} YES {% endif %}', 'a' => true, 'b' => true)    
+    assert_template_result(' YES ','{% if a == true or b == false %} YES {% endif %}', 'a' => true, 'b' => true)    
+    assert_template_result('','{% if a == false or b == false %} YES {% endif %}', 'a' => true, 'b' => true)    
+  end     
+  
+  def test_if_and
+    assert_template_result(' YES ','{% if true and true %} YES {% endif %}')    
+    assert_template_result('','{% if false and true %} YES {% endif %}')    
+    assert_template_result('','{% if false and true %} YES {% endif %}')    
+  end
+  
+  
+  def test_hash_miss_generates_false
+    assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => {})
+  end
+  
+  def test_if_from_variable
+    assert_template_result('','{% if var %} NO {% endif %}', 'var' => false)
+    assert_template_result('','{% if var %} NO {% endif %}', 'var' => nil)
+    assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => {'bar' => false})
+    assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => {})
+    assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => nil)
+    assert_template_result('','{% if foo.bar %} NO {% endif %}', 'foo' => true)
+    
+    assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => "text")
+    assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => true)
+    assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => 1)
+    assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => {})
+    assert_template_result(' YES ','{% if var %} YES {% endif %}', 'var' => [])
+    assert_template_result(' YES ','{% if "foo" %} YES {% endif %}')
+    assert_template_result(' YES ','{% if foo.bar %} YES {% endif %}', 'foo' => {'bar' => true})
+    assert_template_result(' YES ','{% if foo.bar %} YES {% endif %}', 'foo' => {'bar' => "text"})
+    assert_template_result(' YES ','{% if foo.bar %} YES {% endif %}', 'foo' => {'bar' => 1 })
+    assert_template_result(' YES ','{% if foo.bar %} YES {% endif %}', 'foo' => {'bar' => {} })
+    assert_template_result(' YES ','{% if foo.bar %} YES {% endif %}', 'foo' => {'bar' => [] })
+    
+    assert_template_result(' YES ','{% if var %} NO {% else %} YES {% endif %}', 'var' => false)
+    assert_template_result(' YES ','{% if var %} NO {% else %} YES {% endif %}', 'var' => nil)
+    assert_template_result(' YES ','{% if var %} YES {% else %} NO {% endif %}', 'var' => true)
+    assert_template_result(' YES ','{% if "foo" %} YES {% else %} NO {% endif %}', 'var' => "text")
+    
+    assert_template_result(' YES ','{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => {'bar' => false})
+    assert_template_result(' YES ','{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => {'bar' => true})
+    assert_template_result(' YES ','{% if foo.bar %} YES {% else %} NO {% endif %}', 'foo' => {'bar' => "text"})
+    assert_template_result(' YES ','{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => {'notbar' => true})
+    assert_template_result(' YES ','{% if foo.bar %} NO {% else %} YES {% endif %}', 'foo' => {})
+    assert_template_result(' YES ','{% if foo.bar %} NO {% else %} YES {% endif %}', 'notfoo' => {'bar' => true})
+  end
+  
+  def test_nested_if
+    assert_template_result('', '{% if false %}{% if false %} NO {% endif %}{% endif %}')
+    assert_template_result('', '{% if false %}{% if true %} NO {% endif %}{% endif %}')
+    assert_template_result('', '{% if true %}{% if false %} NO {% endif %}{% endif %}')
+    assert_template_result(' YES ', '{% if true %}{% if true %} YES {% endif %}{% endif %}')
+    
+    assert_template_result(' YES ', '{% if true %}{% if true %} YES {% else %} NO {% endif %}{% else %} NO {% endif %}')
+    assert_template_result(' YES ', '{% if true %}{% if false %} NO {% else %} YES {% endif %}{% else %} NO {% endif %}')
+    assert_template_result(' YES ', '{% if false %}{% if true %} NO {% else %} NONO {% endif %}{% else %} YES {% endif %}')
+    
+  end
+  
+  def test_comparisons_on_null
+    assert_template_result('','{% if null < 10 %} NO {% endif %}')
+    assert_template_result('','{% if null <= 10 %} NO {% endif %}')
+    assert_template_result('','{% if null >= 10 %} NO {% endif %}')
+    assert_template_result('','{% if null > 10 %} NO {% endif %}')
+
+    assert_template_result('','{% if 10 < null %} NO {% endif %}')
+    assert_template_result('','{% if 10 <= null %} NO {% endif %}')
+    assert_template_result('','{% if 10 >= null %} NO {% endif %}')
+    assert_template_result('','{% if 10 > null %} NO {% endif %}')
+  end
+  
+  def test_else_if
+    assert_template_result('0','{% if 0 == 0 %}0{% elsif 1 == 1%}1{% else %}2{% endif %}')
+    assert_template_result('1','{% if 0 != 0 %}0{% elsif 1 == 1%}1{% else %}2{% endif %}')
+    assert_template_result('2','{% if 0 != 0 %}0{% elsif 1 != 1%}1{% else %}2{% endif %}')
+    
+    assert_template_result('elsif','{% if false %}if{% elsif true %}elsif{% endif %}')    
+  end
+  
+  def test_syntax_error_no_variable
+    assert_raise(SyntaxError){ assert_template_result('', '{% if jerry == 1 %}')}
+  end
+  
+  def test_if_with_custom_condition
+    Condition.operators['contains'] = :[]
+    
+    assert_template_result('yes', %({% if 'bob' contains 'o' %}yes{% endif %}))
+    assert_template_result('no', %({% if 'bob' contains 'f' %}yes{% else %}no{% endif %}))
+  ensure
+    Condition.operators.delete 'contains'
+  end
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/include_tag_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/include_tag_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/include_tag_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,114 @@
+require File.dirname(__FILE__) + '/helper'
+
+class TestFileSystem 
+  def read_template_file(template_path)
+    case template_path
+    when "product"
+      "Product: {{ product.title }} "
+
+    when "locale_variables"
+      "Locale: {{echo1}} {{echo2}}"
+
+    when "variant"
+      "Variant: {{ variant.title }}"
+      
+    when "nested_template"
+      "{% include 'header' %} {% include 'body' %} {% include 'footer' %}"
+      
+    when "body"
+      "body {% include 'body_detail' %}"
+      
+    when "nested_product_template"
+      "Product: {{ nested_product_template.title }} {%include 'details'%} "
+
+    when "recursively_nested_template"
+      "-{% include 'recursively_nested_template' %}"
+      
+    else
+      template_path
+    end
+  end
+end
+
+class IncludeTagTest < Test::Unit::TestCase
+  include Liquid
+  
+  def setup
+    Liquid::Template.file_system = TestFileSystem.new    
+  end
+  
+
+  def test_include_tag_with    
+    assert_equal "Product: Draft 151cm ", 
+                 Template.parse("{% include 'product' with products[0] %}").render( "products" => [ {'title' => 'Draft 151cm'}, {'title' => 'Element 155cm'} ]  )
+  end
+
+  def test_include_tag_with_default_name    
+    assert_equal "Product: Draft 151cm ", 
+                 Template.parse("{% include 'product' %}").render( "product" => {'title' => 'Draft 151cm'}  )
+  end
+
+  def test_include_tag_for
+    
+    assert_equal "Product: Draft 151cm Product: Element 155cm ", 
+                 Template.parse("{% include 'product' for products %}").render( "products" => [ {'title' => 'Draft 151cm'}, {'title' => 'Element 155cm'} ]  )
+  end
+
+  def test_include_tag_with_local_variables    
+    assert_equal "Locale: test123 ", 
+                 Template.parse("{% include 'locale_variables' echo1: 'test123' %}").render
+  end
+
+  def test_include_tag_with_multiple_local_variables    
+    assert_equal "Locale: test123 test321", 
+                 Template.parse("{% include 'locale_variables' echo1: 'test123', echo2: 'test321' %}").render
+  end
+
+  def test_include_tag_with_multiple_local_variables_from_context    
+    assert_equal "Locale: test123 test321", 
+                 Template.parse("{% include 'locale_variables' echo1: echo1, echo2: more_echos.echo2 %}").render('echo1' => 'test123', 'more_echos' => { "echo2" => 'test321'})
+  end
+
+  def test_nested_include_tag
+    assert_equal "body body_detail", 
+                 Template.parse("{% include 'body' %}").render
+
+    assert_equal "header body body_detail footer", 
+                 Template.parse("{% include 'nested_template' %}").render
+  end
+  
+  def test_nested_include_with_variable
+
+    assert_equal "Product: Draft 151cm details ", 
+                 Template.parse("{% include 'nested_product_template' with product %}").render("product" => {"title" => 'Draft 151cm'})
+
+    assert_equal "Product: Draft 151cm details Product: Element 155cm details ", 
+                 Template.parse("{% include 'nested_product_template' for products %}").render("products" => [{"title" => 'Draft 151cm'}, {"title" => 'Element 155cm'}])
+    
+  end
+  
+  def test_recursively_included_template_does_not_produce_endless_loop
+        
+    infinite_file_system = Class.new do  
+      def read_template_file(template_path)
+        "-{% include 'loop' %}"
+      end
+    end                   
+    
+    Liquid::Template.file_system = infinite_file_system.new
+    
+    assert_match /-{552}Liquid error: stack level too deep$/, 
+      Template.parse("{% include 'loop' %}").render                 
+    
+  end
+            
+  def test_dynamically_choosen_template
+
+    assert_equal "Test123", Template.parse("{% include template %}").render("template" => 'Test123')
+    assert_equal "Test321", Template.parse("{% include template %}").render("template" => 'Test321')
+
+    assert_equal "Product: Draft 151cm ", Template.parse("{% include template for product %}").render("template" => 'product', 'product' => { 'title' => 'Draft 151cm'})
+    
+  end
+  
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/module_ex_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/module_ex_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/module_ex_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,89 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/helper'
+
+class TestClassA
+  liquid_methods :allowedA, :chainedB
+  def allowedA
+    'allowedA'
+  end
+  def restrictedA
+    'restrictedA'
+  end
+  def chainedB
+    TestClassB.new
+  end
+end
+
+class TestClassB
+  liquid_methods :allowedB, :chainedC
+  def allowedB
+    'allowedB'
+  end
+  def chainedC
+    TestClassC.new
+  end
+end
+
+class TestClassC
+  liquid_methods :allowedC
+  def allowedC
+    'allowedC'
+  end
+end
+
+class TestClassC::LiquidDropClass
+  def another_allowedC
+    'another_allowedC'
+  end
+end
+
+class ModuleExTest < Test::Unit::TestCase
+  include Liquid
+  
+  def setup
+    @a = TestClassA.new
+    @b = TestClassB.new
+    @c = TestClassC.new
+  end
+  
+  def test_should_create_LiquidDropClass
+    assert TestClassA::LiquidDropClass
+    assert TestClassB::LiquidDropClass
+    assert TestClassC::LiquidDropClass
+  end
+  
+  def test_should_respond_to_liquid
+    assert @a.respond_to?(:to_liquid)
+    assert @b.respond_to?(:to_liquid)
+    assert @c.respond_to?(:to_liquid)
+  end
+  
+  def test_should_return_LiquidDropClass_object
+    assert @a.to_liquid.is_a?(TestClassA::LiquidDropClass)
+    assert @b.to_liquid.is_a?(TestClassB::LiquidDropClass)
+    assert @c.to_liquid.is_a?(TestClassC::LiquidDropClass)
+  end
+  
+  def test_should_respond_to_liquid_methods
+    assert @a.to_liquid.respond_to?(:allowedA)
+    assert @a.to_liquid.respond_to?(:chainedB)
+    assert @b.to_liquid.respond_to?(:allowedB)
+    assert @b.to_liquid.respond_to?(:chainedC)
+    assert @c.to_liquid.respond_to?(:allowedC)
+    assert @c.to_liquid.respond_to?(:another_allowedC)
+  end
+
+  def test_should_not_respond_to_restricted_methods
+    assert ! @a.to_liquid.respond_to?(:restricted)
+  end
+
+  def test_should_use_regular_objects_as_drops
+    assert_equal 'allowedA', Liquid::Template.parse("{{ a.allowedA }}").render('a'=>@a)
+    assert_equal 'allowedB', Liquid::Template.parse("{{ a.chainedB.allowedB }}").render('a'=>@a)
+    assert_equal 'allowedC', Liquid::Template.parse("{{ a.chainedB.chainedC.allowedC }}").render('a'=>@a)
+    assert_equal 'another_allowedC', Liquid::Template.parse("{{ a.chainedB.chainedC.another_allowedC }}").render('a'=>@a)
+    assert_equal '', Liquid::Template.parse("{{ a.restricted }}").render('a'=>@a)
+    assert_equal '', Liquid::Template.parse("{{ a.unknown }}").render('a'=>@a)
+ end
+
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/output_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/output_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/output_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,121 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/helper'
+
+module FunnyFilter
+  
+  def make_funny(input)
+    'LOL'             
+  end
+
+  def cite_funny(input)
+    "LOL: #{input}"
+  end             
+
+  def add_smiley(input, smiley = ":-)")
+    "#{input} #{smiley}"
+  end
+  
+  def add_tag(input, tag = "p", id = "foo")
+    %|<#{tag} id="#{id}">#{input}</#{tag}>|
+  end
+
+  def paragraph(input)
+    "<p>#{input}</p>"
+  end
+  
+  def link_to(name, url)
+    %|<a href="#{url}">#{name}</a>|
+  end
+end                 
+
+
+class OutputTest < Test::Unit::TestCase
+  include Liquid
+
+  def setup
+    @assigns = {     
+      'best_cars' => 'bmw',
+      'car' => {'bmw' => 'good', 'gm' => 'bad'}
+      }
+
+  end
+
+  def test_variable  
+    text = %| {{best_cars}} |
+
+    expected = %| bmw |
+    assert_equal expected, Template.parse(text).render(@assigns)
+  end
+
+  def test_variable_traversing
+    text = %| {{car.bmw}} {{car.gm}} {{car.bmw}} |
+
+    expected = %| good bad good |
+    assert_equal expected, Template.parse(text).render(@assigns)
+  end               
+  
+  def test_variable_piping
+    text = %( {{ car.gm | make_funny }} )
+    expected = %| LOL |               
+    
+    assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
+  end
+
+  def test_variable_piping_with_input
+    text = %( {{ car.gm | cite_funny }} )
+    expected = %| LOL: bad |               
+
+    assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
+  end
+  
+  def test_variable_piping_with_args
+    text = %! {{ car.gm | add_smiley : ':-(' }} !
+    expected = %| bad :-( |
+
+    assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
+  end
+  
+  def test_variable_piping_with_no_args
+    text = %! {{ car.gm | add_smiley }} !
+    expected = %| bad :-) |
+
+    assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
+  end
+  
+  def test_multiple_variable_piping_with_args
+    text = %! {{ car.gm | add_smiley : ':-(' | add_smiley : ':-('}} !
+    expected = %| bad :-( :-( |
+
+    assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
+  end
+
+  def test_variable_piping_with_args
+    text = %! {{ car.gm | add_tag : 'span', 'bar'}} !
+    expected = %| <span id="bar">bad</span> |
+
+    assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
+  end
+
+  def test_variable_piping_with_variable_args
+    text = %! {{ car.gm | add_tag : 'span', car.bmw}} !
+    expected = %| <span id="good">bad</span> |
+
+    assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
+  end
+
+  def test_multiple_pipings
+    text = %( {{ best_cars | cite_funny | paragraph }} )
+    expected = %| <p>LOL: bmw</p> |               
+
+    assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])
+  end
+  
+  def test_link_to
+    text = %( {{ 'Typo' | link_to: 'http://typo.leetsoft.com' }} )
+    expected = %| <a href="http://typo.leetsoft.com">Typo</a> |               
+
+    assert_equal expected, Template.parse(text).render(@assigns, :filters => [FunnyFilter])    
+  end
+  
+
+end 
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/parsing_quirks_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/parsing_quirks_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/parsing_quirks_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,29 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/helper'
+
+class ParsingQuirksTest < Test::Unit::TestCase
+  include Liquid
+
+  def test_error_with_css
+    text = %| div { font-weight: bold; } |
+    template = Template.parse(text)
+                                                    
+    assert_equal text, template.render
+    assert_equal [String], template.root.nodelist.collect {|i| i.class}
+  end
+  
+  def test_raise_on_single_close_bracet
+    assert_raise(SyntaxError) do
+      Template.parse("text {{method} oh nos!")      
+    end
+  end
+  
+  
+  def test_error_on_empty_filter
+    assert_nothing_raised do
+      Template.parse("{{test |a|b|}}")      
+      Template.parse("{{test}}")      
+      Template.parse("{{|test|}}")      
+    end
+  end
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/regexp_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/regexp_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/regexp_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,40 @@
+require File.dirname(__FILE__) + '/helper'
+   
+class RegexpTest < Test::Unit::TestCase
+  include Liquid
+
+  def test_empty
+    assert_equal [], ''.scan(QuotedFragment)
+  end
+  
+  def test_quote
+    assert_equal ['"arg 1"'], '"arg 1"'.scan(QuotedFragment)
+  end
+  
+
+  def test_words
+    assert_equal ['arg1', 'arg2'], 'arg1 arg2'.scan(QuotedFragment)
+  end
+
+  def test_quoted_words
+    assert_equal ['arg1', 'arg2', '"arg 3"'], 'arg1 arg2 "arg 3"'.scan(QuotedFragment)
+  end
+
+  def test_quoted_words
+    assert_equal ['arg1', 'arg2', "'arg 3'"], 'arg1 arg2 \'arg 3\''.scan(QuotedFragment)
+  end
+
+  def test_quoted_words_in_the_middle
+    assert_equal ['arg1', 'arg2', '"arg 3"', 'arg4'], 'arg1 arg2 "arg 3" arg4   '.scan(QuotedFragment)
+  end
+  
+  def test_variable_parser
+    assert_equal ['var'],                 'var'.scan(VariableParser)
+    assert_equal ['var', 'method'],       'var.method'.scan(VariableParser)
+    assert_equal ['var', '[method]'],       'var[method]'.scan(VariableParser)
+    assert_equal ['var', '[method]', '[0]'],  'var[method][0]'.scan(VariableParser)
+    assert_equal ['var', '["method"]', '[0]'],  'var["method"][0]'.scan(VariableParser)
+    assert_equal ['var', '[method]', '[0]', 'method'],  'var[method][0].method'.scan(VariableParser)    
+  end
+ 
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/security_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/security_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/security_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,41 @@
+require File.dirname(__FILE__) + '/helper'
+
+module SecurityFilter
+  def add_one(input)
+    "#{input} + 1"
+  end
+end
+
+class SecurityTest < Test::Unit::TestCase
+  include Liquid
+
+  def test_no_instance_eval
+    text = %( {{ '1+1' | instance_eval }} )
+    expected = %| 1+1 |
+        
+    assert_equal expected, Template.parse(text).render(@assigns)
+  end
+  
+  def test_no_existing_instance_eval
+    text = %( {{ '1+1' | __instance_eval__ }} )
+    expected = %| 1+1 |
+        
+    assert_equal expected, Template.parse(text).render(@assigns)
+  end
+  
+
+  def test_no_instance_eval_after_mixing_in_new_filter
+    text = %( {{ '1+1' | instance_eval }} )
+    expected = %| 1+1 |
+  
+    assert_equal expected, Template.parse(text).render(@assigns)
+  end
+
+
+  def test_no_instance_eval_later_in_chain
+    text = %( {{ '1+1' | add_one | instance_eval }} )
+    expected = %| 1+1 + 1 |
+  
+    assert_equal expected, Template.parse(text).render(@assigns, :filters => SecurityFilter)
+  end
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/standard_filter_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/standard_filter_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/standard_filter_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,126 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/helper'
+
+
+class Filters
+  include Liquid::StandardFilters
+end
+
+
+class StandardFiltersTest < Test::Unit::TestCase
+  include Liquid
+  
+  def setup
+    @filters = Filters.new
+  end
+  
+  def test_size
+    assert_equal 3, @filters.size([1,2,3])
+    assert_equal 0, @filters.size([])
+    assert_equal 0, @filters.size(nil)
+  end
+  
+  def test_downcase
+    assert_equal 'testing', @filters.downcase("Testing")
+    assert_equal '', @filters.downcase(nil)
+  end
+  
+  def test_upcase
+    assert_equal 'TESTING', @filters.upcase("Testing")
+    assert_equal '', @filters.upcase(nil)
+  end
+  
+  def test_upcase
+    assert_equal 'TESTING', @filters.upcase("Testing")
+    assert_equal '', @filters.upcase(nil)
+  end
+  
+  def test_truncate
+    assert_equal '1234...', @filters.truncate('1234567890', 7)
+    assert_equal '1234567890', @filters.truncate('1234567890', 20)
+    assert_equal '...', @filters.truncate('1234567890', 0)
+    assert_equal '1234567890', @filters.truncate('1234567890')
+  end
+  
+  def test_escape
+    assert_equal '&lt;strong&gt;', @filters.escape('<strong>')
+    assert_equal '&lt;strong&gt;', @filters.h('<strong>')    
+  end
+  
+  def test_truncatewords
+    assert_equal 'one two three', @filters.truncatewords('one two three', 4)
+    assert_equal 'one two...', @filters.truncatewords('one two three', 2)
+    assert_equal 'one two three', @filters.truncatewords('one two three')
+    assert_equal 'Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221;...', @filters.truncatewords('Two small (13&#8221; x 5.5&#8221; x 10&#8221; high) baskets fit inside one large basket (13&#8221; x 16&#8221; x 10.5&#8221; high) with cover.', 15)    
+  end
+  
+  def test_strip_html
+    assert_equal 'test', @filters.strip_html("<div>test</div>")    
+    assert_equal 'test', @filters.strip_html("<div id='test'>test</div>")    
+    assert_equal '', @filters.strip_html(nil)    
+  end
+  
+  def test_join
+    assert_equal '1 2 3 4', @filters.join([1,2,3,4])    
+    assert_equal '1 - 2 - 3 - 4', @filters.join([1,2,3,4], ' - ')    
+  end
+  
+  def test_sort
+    assert_equal [1,2,3,4], @filters.sort([4,3,2,1])    
+  end
+  
+  def test_date
+    assert_equal 'May', @filters.date(Time.parse("2006-05-05 10:00:00"), "%B")    
+    assert_equal 'June', @filters.date(Time.parse("2006-06-05 10:00:00"), "%B")    
+    assert_equal 'July', @filters.date(Time.parse("2006-07-05 10:00:00"), "%B")    
+
+    assert_equal 'May', @filters.date("2006-05-05 10:00:00", "%B")    
+    assert_equal 'June', @filters.date("2006-06-05 10:00:00", "%B")    
+    assert_equal 'July', @filters.date("2006-07-05 10:00:00", "%B")    
+
+    assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "")    
+    assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "")    
+    assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", "")    
+    assert_equal '2006-07-05 10:00:00', @filters.date("2006-07-05 10:00:00", nil)    
+
+    assert_equal '07/05/2006', @filters.date("2006-07-05 10:00:00", "%m/%d/%Y")    
+    
+    assert_equal "07/16/2004", @filters.date("Fri Jul 16 01:00:00 EDT 2004", "%m/%d/%Y")
+    
+    assert_equal nil, @filters.date(nil, "%B")    
+  end
+  
+  
+  def test_first_last
+    assert_equal 1, @filters.first([1,2,3])    
+    assert_equal 3, @filters.last([1,2,3])    
+    assert_equal nil, @filters.first([])    
+    assert_equal nil, @filters.last([])    
+  end
+  
+  def test_replace
+    assert_equal 'b b b b', @filters.replace("a a a a", 'a', 'b')    
+    assert_equal 'b a a a', @filters.replace_first("a a a a", 'a', 'b')
+    assert_template_result 'b a a a', "{{ 'a a a a' | replace_first: 'a', 'b' }}"        
+  end
+  
+  def test_remove
+    assert_equal '   ', @filters.remove("a a a a", 'a')    
+    assert_equal 'a a a', @filters.remove_first("a a a a", 'a ')        
+    assert_template_result 'a a a', "{{ 'a a a a' | remove_first: 'a ' }}"
+  end
+                                                                                     
+  def test_strip_newlines
+    assert_template_result 'abc', "{{ source | strip_newlines }}", 'source' => "a\nb\nc"
+  end
+  
+  def test_newlines_to_br
+    assert_template_result "a<br />\nb<br />\nc", "{{ source | newline_to_br }}", 'source' => "a\nb\nc"
+  end
+  
+  
+  
+  
+  
+end
+

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/standard_tag_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/standard_tag_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/standard_tag_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,383 @@
+require File.dirname(__FILE__) + '/helper'
+
+
+class StandardTagTest < Test::Unit::TestCase
+  include Liquid
+  
+  
+  def test_tag 
+    tag = Tag.new('tag', [], [])
+    assert_equal 'liquid::tag', tag.name 
+    assert_equal '', tag.render(Context.new)    
+  end
+  
+  def test_no_transform
+    assert_template_result('this text should come out of the template without change...',
+                           'this text should come out of the template without change...')
+    assert_template_result('blah','blah')
+    assert_template_result('<blah>','<blah>')
+    assert_template_result('|,.:','|,.:')
+    assert_template_result('','')
+    
+    text = %|this shouldnt see any transformation either but has multiple lines
+              as you can clearly see here ...|
+    assert_template_result(text,text)
+  end
+  
+  def test_has_a_block_which_does_nothing
+    assert_template_result(%|the comment block should be removed  .. right?|,
+                           %|the comment block should be removed {%comment%} be gone.. {%endcomment%} .. right?|)
+    
+    assert_template_result('','{%comment%}{%endcomment%}')
+    assert_template_result('','{%comment%}{% endcomment %}')
+    assert_template_result('','{% comment %}{%endcomment%}')
+    assert_template_result('','{% comment %}{% endcomment %}')
+    assert_template_result('','{%comment%}comment{%endcomment%}')
+    assert_template_result('','{% comment %}comment{% endcomment %}')
+    
+    assert_template_result('foobar','foo{%comment%}comment{%endcomment%}bar')
+    assert_template_result('foobar','foo{% comment %}comment{% endcomment %}bar')
+    assert_template_result('foobar','foo{%comment%} comment {%endcomment%}bar')
+    assert_template_result('foobar','foo{% comment %} comment {% endcomment %}bar')
+    
+    assert_template_result('foo  bar','foo {%comment%} {%endcomment%} bar')
+    assert_template_result('foo  bar','foo {%comment%}comment{%endcomment%} bar')
+    assert_template_result('foo  bar','foo {%comment%} comment {%endcomment%} bar')
+    
+    assert_template_result('foobar','foo{%comment%}
+                                     {%endcomment%}bar')
+  end
+  
+  def test_for
+    assert_template_result(' yo  yo  yo  yo ','{%for item in array%} yo {%endfor%}','array' => [1,2,3,4])
+    assert_template_result('yoyo','{%for item in array%}yo{%endfor%}','array' => [1,2])
+    assert_template_result(' yo ','{%for item in array%} yo {%endfor%}','array' => [1])
+    assert_template_result('','{%for item in array%}{%endfor%}','array' => [1,2])
+    expected = <<HERE
+  
+  yo
+  
+  yo
+  
+  yo
+  
+HERE
+    template = <<HERE
+{%for item in array%}  
+  yo
+{%endfor%}  
+HERE
+    assert_template_result(expected,template,'array' => [1,2,3])
+  end
+  
+  def test_for_with_range
+    assert_template_result(' 1  2  3 ','{%for item in (1..3) %} {{item}} {%endfor%}')    
+  end
+
+  def test_for_with_variable
+    assert_template_result(' 1  2  3 ','{%for item in array%} {{item}} {%endfor%}','array' => [1,2,3])
+    assert_template_result('123','{%for item in array%}{{item}}{%endfor%}','array' => [1,2,3])
+    assert_template_result('123','{% for item in array %}{{item}}{% endfor %}','array' => [1,2,3])
+    assert_template_result('abcd','{%for item in array%}{{item}}{%endfor%}','array' => ['a','b','c','d'])
+    assert_template_result('a b c','{%for item in array%}{{item}}{%endfor%}','array' => ['a',' ','b',' ','c'])
+    assert_template_result('abc','{%for item in array%}{{item}}{%endfor%}','array' => ['a','','b','','c'])
+  end
+  
+  def test_for_helpers
+    assigns = {'array' => [1,2,3] }
+    assert_template_result(' 1/3  2/3  3/3 ','{%for item in array%} {{forloop.index}}/{{forloop.length}} {%endfor%}',assigns)
+    assert_template_result(' 1  2  3 ','{%for item in array%} {{forloop.index}} {%endfor%}',assigns)
+    assert_template_result(' 0  1  2 ','{%for item in array%} {{forloop.index0}} {%endfor%}',assigns)
+    assert_template_result(' 2  1  0 ','{%for item in array%} {{forloop.rindex0}} {%endfor%}',assigns)
+    assert_template_result(' 3  2  1 ','{%for item in array%} {{forloop.rindex}} {%endfor%}',assigns)
+    assert_template_result(' true  false  false ','{%for item in array%} {{forloop.first}} {%endfor%}',assigns)
+    assert_template_result(' false  false  true ','{%for item in array%} {{forloop.last}} {%endfor%}',assigns)
+  end
+  
+  def test_for_and_if
+    assigns = {'array' => [1,2,3] }
+    assert_template_result('+--', '{%for item in array%}{% if forloop.first %}+{% else %}-{% endif %}{%endfor%}', assigns)
+  end
+  
+  def test_limiting
+    assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]}
+    assert_template_result('12','{%for i in array limit:2 %}{{ i }}{%endfor%}',assigns)
+    assert_template_result('1234','{%for i in array limit:4 %}{{ i }}{%endfor%}',assigns)
+    assert_template_result('3456','{%for i in array limit:4 offset:2 %}{{ i }}{%endfor%}',assigns)
+    assert_template_result('3456','{%for i in array limit: 4 offset: 2 %}{{ i }}{%endfor%}',assigns)    
+    
+    assigns['limit'] = 2
+    assigns['offset'] = 2
+    assert_template_result('34','{%for i in array limit: limit offset: offset %}{{ i }}{%endfor%}',assigns)    
+  end
+  
+  def test_nested_for
+    assigns = {'array' => [[1,2],[3,4],[5,6]] }
+    assert_template_result('123456','{%for item in array%}{%for i in item%}{{ i }}{%endfor%}{%endfor%}',assigns)
+  end
+  
+  def test_offset_only
+    assigns = {'array' => [1,2,3,4,5,6,7,8,9,0]}
+    assert_template_result('890','{%for i in array offset:7 %}{{ i }}{%endfor%}',assigns)
+  end
+  
+  def test_pause_resume
+    assigns = {'array' => {'items' => [1,2,3,4,5,6,7,8,9,0]}}
+    markup = <<-MKUP
+      {%for i in array.items limit: 3 %}{{i}}{%endfor%}
+      next
+      {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
+      next
+      {%for i in array.items offset:continue limit: 3 %}{{i}}{%endfor%}
+      MKUP
+    expected = <<-XPCTD
+      123
+      next
+      456
+      next
+      789
+      XPCTD
+    assert_template_result(expected,markup,assigns)
+  end
+  
+  def test_pause_resume_limit
+    assigns = {'array' => {'items' => [1,2,3,4,5,6,7,8,9,0]}}
+    markup = <<-MKUP
+      {%for i in array.items limit:3 %}{{i}}{%endfor%}
+      next
+      {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
+      next
+      {%for i in array.items offset:continue limit:1 %}{{i}}{%endfor%}
+      MKUP
+    expected = <<-XPCTD
+      123
+      next
+      456
+      next
+      7
+      XPCTD
+    assert_template_result(expected,markup,assigns)
+  end
+  
+  def test_pause_resume_BIG_limit
+    assigns = {'array' => {'items' => [1,2,3,4,5,6,7,8,9,0]}}
+    markup = <<-MKUP
+      {%for i in array.items limit:3 %}{{i}}{%endfor%}
+      next
+      {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
+      next
+      {%for i in array.items offset:continue limit:1000 %}{{i}}{%endfor%}
+      MKUP
+    expected = <<-XPCTD
+      123
+      next
+      456
+      next
+      7890
+      XPCTD
+      assert_template_result(expected,markup,assigns)
+  end
+  
+  
+  def test_pause_resume_BIG_offset
+    assigns = {'array' => {'items' => [1,2,3,4,5,6,7,8,9,0]}}
+    markup = %q({%for i in array.items limit:3 %}{{i}}{%endfor%}
+      next
+      {%for i in array.items offset:continue limit:3 %}{{i}}{%endfor%}
+      next
+      {%for i in array.items offset:continue limit:3 offset:1000 %}{{i}}{%endfor%})
+    expected = %q(123
+      next
+      456
+      next
+      )
+      assert_template_result(expected,markup,assigns)
+  end
+  
+  def test_assign
+    assigns = {'var' => 'content' }
+    assert_template_result('var2:  var2:content','var2:{{var2}} {%assign var2 = var%} var2:{{var2}}',assigns)
+    
+  end
+
+  def test_hyphenated_assign
+    assigns = {'a-b' => '1' }
+    assert_template_result('a-b:1 a-b:2','a-b:{{a-b}} {%assign a-b = 2 %}a-b:{{a-b}}',assigns)
+    
+  end
+
+  def test_capture
+    assigns = {'var' => 'content' }
+    assert_template_result('content foo content foo ','{{ var2 }}{% capture var2 %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}', assigns)
+  end
+
+  def test_capture_detects_bad_syntax
+    assert_raise(SyntaxError) do
+      assert_template_result('content foo content foo ','{{ var2 }}{% capture %}{{ var }} foo {% endcapture %}{{ var2 }}{{ var2 }}', {'var' => 'content' })
+    end
+  end
+
+  def test_case
+    assigns = {'condition' => 2 }    
+    assert_template_result(' its 2 ','{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', assigns)
+
+    assigns = {'condition' => 1 }
+    assert_template_result(' its 1 ','{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', assigns)
+
+    assigns = {'condition' => 3 }
+    assert_template_result('','{% case condition %}{% when 1 %} its 1 {% when 2 %} its 2 {% endcase %}', assigns)  
+
+    assigns = {'condition' => "string here" }
+    assert_template_result(' hit ','{% case condition %}{% when "string here" %} hit {% endcase %}', assigns)  
+
+    assigns = {'condition' => "bad string here" }
+    assert_template_result('','{% case condition %}{% when "string here" %} hit {% endcase %}', assigns)  
+  end
+  
+  def test_case_with_else
+
+    assigns = {'condition' => 5 }
+    assert_template_result(' hit ','{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}', assigns)  
+
+    assigns = {'condition' => 6 }
+    assert_template_result(' else ','{% case condition %}{% when 5 %} hit {% else %} else {% endcase %}', assigns)  
+    
+    assigns = {'condition' => 6 }
+    assert_template_result(' else ','{% case condition %} {% when 5 %} hit {% else %} else {% endcase %}', assigns)  
+    
+
+  end
+  
+  def test_case_on_size
+    assert_template_result('',     '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [])     
+    assert_template_result('1' ,   '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1])     
+    assert_template_result('2' ,   '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1])     
+    assert_template_result('',     '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1])     
+    assert_template_result('',     '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1, 1])     
+    assert_template_result('',     '{% case a.size %}{% when 1 %}1{% when 2 %}2{% endcase %}', 'a' => [1, 1, 1, 1, 1])     
+  end  
+  
+  def test_case_on_size_with_else
+    assert_template_result('else', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', 'a' => [])     
+    assert_template_result('1',    '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', 'a' => [1])     
+    assert_template_result('2',    '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', 'a' => [1, 1])     
+    assert_template_result('else', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', 'a' => [1, 1, 1])     
+    assert_template_result('else', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', 'a' => [1, 1, 1, 1])     
+    assert_template_result('else', '{% case a.size %}{% when 1 %}1{% when 2 %}2{% else %}else{% endcase %}', 'a' => [1, 1, 1, 1, 1])     
+  end
+  
+  def test_case_on_length_with_else
+    assert_template_result('else',  '{% case a.empty? %}{% when true %}true{% when false %}false{% else %}else{% endcase %}', {})     
+    assert_template_result('false', '{% case false %}{% when true %}true{% when false %}false{% else %}else{% endcase %}', {})     
+    assert_template_result('true',  '{% case true %}{% when true %}true{% when false %}false{% else %}else{% endcase %}', {})     
+    assert_template_result('else',  '{% case NULL %}{% when true %}true{% when false %}false{% else %}else{% endcase %}', {})     
+  end
+  
+  def test_assign_from_case    
+    # Example from the shopify forums
+    code = %q({% case collection.handle %}{% when 'menswear-jackets' %}{% assign ptitle = 'menswear' %}{% when 'menswear-t-shirts' %}{% assign ptitle = 'menswear' %}{% else %}{% assign ptitle = 'womenswear' %}{% endcase %}{{ ptitle }})
+    template = Liquid::Template.parse(code)
+    assert_equal "menswear",   template.render("collection" => {'handle' => 'menswear-jackets'})
+    assert_equal "menswear",   template.render("collection" => {'handle' => 'menswear-t-shirts'})
+    assert_equal "womenswear", template.render("collection" => {'handle' => 'x'})
+    assert_equal "womenswear", template.render("collection" => {'handle' => 'y'})
+    assert_equal "womenswear", template.render("collection" => {'handle' => 'z'})
+  end
+
+  def test_case_when_or
+    code = '{% case condition %}{% when 1 or 2 or 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
+    assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 1 })
+    assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 2 })
+    assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 3 })
+    assert_template_result(' its 4 ', code, {'condition' => 4 })
+    assert_template_result('', code, {'condition' => 5 })
+    
+    code = '{% case condition %}{% when 1 or "string" or null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
+    assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 1 })
+    assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 'string' })
+    assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => nil })
+    assert_template_result('', code, {'condition' => 'something else' })    
+  end
+
+  def test_case_when_comma
+    code = '{% case condition %}{% when 1, 2, 3 %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
+    assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 1 })
+    assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 2 })
+    assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 3 })
+    assert_template_result(' its 4 ', code, {'condition' => 4 })
+    assert_template_result('', code, {'condition' => 5 })
+    
+    code = '{% case condition %}{% when 1, "string", null %} its 1 or 2 or 3 {% when 4 %} its 4 {% endcase %}'
+    assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 1 })
+    assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => 'string' })
+    assert_template_result(' its 1 or 2 or 3 ', code, {'condition' => nil })
+    assert_template_result('', code, {'condition' => 'something else' })    
+  end
+  
+  def test_assign
+    assert_equal 'variable', Liquid::Template.parse( '{% assign a = "variable"%}{{a}}'  ).render            
+  end
+  
+  def test_assign_is_global
+    assert_equal 'variable', Liquid::Template.parse( '{%for i in (1..2) %}{% assign a = "variable"%}{% endfor %}{{a}}'  ).render        
+  end  
+  
+  def test_case_detects_bad_syntax
+    assert_raise(SyntaxError) do
+      assert_template_result('',  '{% case false %}{% when %}true{% endcase %}', {})     
+    end
+
+    assert_raise(SyntaxError) do
+      assert_template_result('',  '{% case false %}{% huh %}true{% endcase %}', {})     
+    end
+    
+  end
+  
+  
+  
+  def test_cycle
+
+    assert_template_result('one','{%cycle "one", "two"%}')  
+    assert_template_result('one two','{%cycle "one", "two"%} {%cycle "one", "two"%}') 
+    
+    assert_template_result('one two one','{%cycle "one", "two"%} {%cycle "one", "two"%} {%cycle "one", "two"%}') 
+  end
+  
+  def test_multiple_cycles
+    assert_template_result('1 2 1 1 2 3 1','{%cycle 1,2%} {%cycle 1,2%} {%cycle 1,2%} {%cycle 1,2,3%} {%cycle 1,2,3%} {%cycle 1,2,3%} {%cycle 1,2,3%}') 
+  end
+  
+  def test_multiple_named_cycles
+    assert_template_result('one one two two one one','{%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %} {%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %} {%cycle 1: "one", "two" %} {%cycle 2: "one", "two" %}') 
+  end
+  
+  def test_multiple_named_cycles_with_names_from_context
+    assigns = {"var1" => 1, "var2" => 2 }
+    assert_template_result('one one two two one one','{%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %} {%cycle var1: "one", "two" %} {%cycle var2: "one", "two" %}', assigns) 
+  end
+  
+  def test_size_of_array
+    assigns = {"array" => [1,2,3,4]}
+    assert_template_result('array has 4 elements', "array has {{ array.size }} elements", assigns) 
+  end
+
+  def test_size_of_hash
+    assigns = {"hash" => {:a => 1, :b => 2, :c=> 3, :d => 4}}
+    assert_template_result('hash has 4 elements', "hash has {{ hash.size }} elements", assigns) 
+  end
+  
+  def test_illegal_symbols
+    assert_template_result('',     '{% if true == empty %}?{% endif %}', {})         
+    assert_template_result('',     '{% if true == null %}?{% endif %}', {})         
+    assert_template_result('',     '{% if empty == true %}?{% endif %}', {})         
+    assert_template_result('',     '{% if null == true %}?{% endif %}', {})         
+  end
+  
+  def test_ifchanged
+    assigns = {'array' => [ 1, 1, 2, 2, 3, 3] }
+    assert_template_result('123','{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}',assigns)
+
+    assigns = {'array' => [ 1, 1, 1, 1] }
+    assert_template_result('1','{%for item in array%}{%ifchanged%}{{item}}{% endifchanged %}{%endfor%}',assigns)
+  end
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/statements_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/statements_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/statements_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,137 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/helper'
+
+class StatementsTest < Test::Unit::TestCase
+  include Liquid
+
+
+  def test_true_eql_true
+    text = %| {% if true == true %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render
+  end
+
+  def test_true_not_eql_true
+    text = %| {% if true != true %} true {% else %} false {% endif %} |
+    expected = %|  false  |
+    assert_equal expected, Template.parse(text).render
+  end
+
+  def test_true_lq_true
+    text = %| {% if 0 > 0 %} true {% else %} false {% endif %} |
+    expected = %|  false  |
+    assert_equal expected, Template.parse(text).render
+  end
+
+  def test_one_lq_zero
+    text = %| {% if 1 > 0 %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render
+  end
+
+  def test_zero_lq_one
+    text = %| {% if 0 < 1 %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render
+  end
+
+  def test_zero_lq_or_equal_one
+    text = %| {% if 0 <= 0 %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render
+  end
+
+  def test_zero_lq_or_equal_one_involving_nil
+    text = %| {% if null <= 0 %} true {% else %} false {% endif %} |
+    expected = %|  false  |
+    assert_equal expected, Template.parse(text).render
+
+
+    text = %| {% if 0 <= null %} true {% else %} false {% endif %} |
+    expected = %|  false  |
+    assert_equal expected, Template.parse(text).render
+  end
+
+  def test_zero_lqq_or_equal_one
+    text = %| {% if 0 >= 0 %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render
+  end
+
+  def test_strings
+    text = %| {% if 'test' == 'test' %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render
+  end
+
+  def test_strings_not_equal
+    text = %| {% if 'test' != 'test' %} true {% else %} false {% endif %} |
+    expected = %|  false  |
+    assert_equal expected, Template.parse(text).render
+  end
+  
+  def test_var_strings_equal
+    text = %| {% if var == "hello there!" %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render('var' => 'hello there!')
+  end
+  
+  def test_var_strings_are_not_equal
+    text = %| {% if "hello there!" == var %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render('var' => 'hello there!')
+  end
+  
+  def test_var_and_long_string_are_equal
+    text = %| {% if var == 'hello there!' %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render('var' => 'hello there!')
+  end
+  
+
+  def test_var_and_long_string_are_equal_backwards
+    text = %| {% if 'hello there!' == var %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render('var' => 'hello there!')
+  end
+  
+  #def test_is_nil    
+  #  text = %| {% if var != nil %} true {% else %} false {% end %} |
+  #  @template.assigns = { 'var' => 'hello there!'}
+  #  expected = %|  true  |
+  #  assert_equal expected, @template.parse(text)
+  #end
+    
+  def test_is_collection_empty    
+    text = %| {% if array == empty %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render('array' => [])
+  end
+
+  def test_is_not_collection_empty    
+    text = %| {% if array == empty %} true {% else %} false {% endif %} |
+    expected = %|  false  |
+    assert_equal expected, Template.parse(text).render('array' => [1,2,3])
+  end
+
+  def test_nil
+    text = %| {% if var == nil %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render('var' => nil)
+
+    text = %| {% if var == null %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render('var' => nil)
+  end
+
+  def test_not_nil
+    text = %| {% if var != nil %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render('var' => 1 )
+
+    text = %| {% if var != null %} true {% else %} false {% endif %} |
+    expected = %|  true  |
+    assert_equal expected, Template.parse(text).render('var' => 1 )
+  end
+
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/strainer_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/strainer_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/strainer_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,16 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/helper'
+
+class StrainerTest < Test::Unit::TestCase
+  include Liquid
+
+  def test_strainer
+    strainer = Strainer.create(nil)
+    assert_equal false, strainer.respond_to?('__test__')
+    assert_equal false, strainer.respond_to?('test')
+    assert_equal false, strainer.respond_to?('instance_eval')
+    assert_equal false, strainer.respond_to?('__send__')
+    assert_equal true, strainer.respond_to?('size') # from the standard lib
+  end
+  
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/template_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/template_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/template_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,26 @@
+require File.dirname(__FILE__) + '/helper'
+
+class TemplateTest < Test::Unit::TestCase
+  include Liquid
+  
+  def test_tokenize_strings
+    assert_equal [' '], Template.new.send(:tokenize, ' ')
+    assert_equal ['hello world'], Template.new.send(:tokenize, 'hello world')
+  end                         
+  
+  def test_tokenize_variables
+    assert_equal ['{{funk}}'], Template.new.send(:tokenize, '{{funk}}')
+    assert_equal [' ', '{{funk}}', ' '], Template.new.send(:tokenize, ' {{funk}} ')
+    assert_equal [' ', '{{funk}}', ' ', '{{so}}', ' ', '{{brother}}', ' '], Template.new.send(:tokenize, ' {{funk}} {{so}} {{brother}} ')
+    assert_equal [' ', '{{  funk  }}', ' '], Template.new.send(:tokenize, ' {{  funk  }} ')
+  end                             
+  
+  def test_tokenize_blocks    
+    assert_equal ['{%comment%}'], Template.new.send(:tokenize, '{%comment%}')
+    assert_equal [' ', '{%comment%}', ' '], Template.new.send(:tokenize, ' {%comment%} ')
+    
+    assert_equal [' ', '{%comment%}', ' ', '{%endcomment%}', ' '], Template.new.send(:tokenize, ' {%comment%} {%endcomment%} ')
+    assert_equal ['  ', '{% comment %}', ' ', '{% endcomment %}', ' '], Template.new.send(:tokenize, "  {% comment %} {% endcomment %} ")    
+  end                                                          
+  
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/test_helper.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/test_helper.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/test_helper.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+$LOAD_PATH.unshift(File.dirname(__FILE__)+ '/extra')
+
+require 'test/unit'
+require 'test/unit/assertions'
+require 'caller'
+require 'breakpoint'
+require File.dirname(__FILE__) + '/../lib/liquid'
+
+
+module Test
+  module Unit
+    module Assertions
+        include Liquid
+        def assert_template_result(expected, template, assigns={}, message=nil)
+          assert_equal expected, Template.parse(template).render(assigns)
+        end 
+    end
+  end
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/unless_else_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/unless_else_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/unless_else_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,27 @@
+require File.dirname(__FILE__) + '/helper'
+
+class UnlessElseTest < Test::Unit::TestCase
+  include Liquid
+
+  def test_unless
+    assert_template_result('  ',' {% unless true %} this text should not go into the output {% endunless %} ')
+    assert_template_result('  this text should go into the output  ',
+              ' {% unless false %} this text should go into the output {% endunless %} ')
+    assert_template_result('  you rock ?','{% unless true %} you suck {% endunless %} {% unless false %} you rock {% endunless %}?')
+  end
+
+  def test_unless_else
+    assert_template_result(' YES ','{% unless true %} NO {% else %} YES {% endunless %}')
+    assert_template_result(' YES ','{% unless false %} YES {% else %} NO {% endunless %}')
+    assert_template_result(' YES ','{% unless "foo" %} NO {% else %} YES {% endunless %}')
+  end
+
+  def test_unless_in_loop
+    assert_template_result '23', '{% for i in choices %}{% unless i %}{{ forloop.index }}{% endunless %}{% endfor %}', 'choices' => [1, nil, false]
+  end
+
+  def test_unless_else_in_loop
+    assert_template_result ' TRUE  2  3 ', '{% for i in choices %}{% unless i %} {{ forloop.index }} {% else %} TRUE {% endunless %}{% endfor %}', 'choices' => [1, nil, false]
+  end
+
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/variable_test.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/variable_test.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/liquid-1.9.0/test/variable_test.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,135 @@
+#!/usr/bin/env ruby
+require File.dirname(__FILE__) + '/helper'
+
+class VariableTest < Test::Unit::TestCase
+  include Liquid
+
+  def test_variable
+    var = Variable.new('hello')
+    assert_equal 'hello', var.name
+  end
+  
+  def test_filters
+    var = Variable.new('hello | textileze')
+    assert_equal 'hello', var.name
+    assert_equal [[:textileze,[]]], var.filters
+
+    var = Variable.new('hello | textileze | paragraph')
+    assert_equal 'hello', var.name
+    assert_equal [[:textileze,[]], [:paragraph,[]]], var.filters
+
+    var = Variable.new(%! hello | strftime: '%Y'!)
+    assert_equal 'hello', var.name
+    assert_equal [[:strftime,["'%Y'"]]], var.filters
+
+    var = Variable.new(%! 'typo' | link_to: 'Typo', true !)
+    assert_equal %!'typo'!, var.name
+    assert_equal [[:link_to,["'Typo'", "true"]]], var.filters
+    
+    var = Variable.new(%! 'typo' | link_to: 'Typo', false !)
+    assert_equal %!'typo'!, var.name
+    assert_equal [[:link_to,["'Typo'", "false"]]], var.filters
+    
+    var = Variable.new(%! 'foo' | repeat: 3 !)
+    assert_equal %!'foo'!, var.name
+    assert_equal [[:repeat,["3"]]], var.filters
+    
+    var = Variable.new(%! 'foo' | repeat: 3, 3 !)
+    assert_equal %!'foo'!, var.name
+    assert_equal [[:repeat,["3","3"]]], var.filters
+
+    var = Variable.new(%! 'foo' | repeat: 3, 3, 3 !)
+    assert_equal %!'foo'!, var.name
+    assert_equal [[:repeat,["3","3","3"]]], var.filters
+
+    var = Variable.new(%! hello | strftime: '%Y, okay?'!)
+    assert_equal 'hello', var.name
+    assert_equal [[:strftime,["'%Y, okay?'"]]], var.filters
+  
+    var = Variable.new(%! hello | things: "%Y, okay?", 'the other one'!)
+    assert_equal 'hello', var.name
+    assert_equal [[:things,["\"%Y, okay?\"","'the other one'"]]], var.filters
+  end
+  
+  def test_filter_with_date_parameter
+
+    var = Variable.new(%! '2006-06-06' | date: "%m/%d/%Y"!)
+    assert_equal "'2006-06-06'", var.name
+    assert_equal [[:date,["\"%m/%d/%Y\""]]], var.filters
+    
+  end
+  
+  def test_filters_without_whitespace
+    var = Variable.new('hello | textileze | paragraph')
+    assert_equal 'hello', var.name
+    assert_equal [[:textileze,[]], [:paragraph,[]]], var.filters
+
+    var = Variable.new('hello|textileze|paragraph')
+    assert_equal 'hello', var.name
+    assert_equal [[:textileze,[]], [:paragraph,[]]], var.filters
+  end
+  
+  def test_symbol
+    var = Variable.new("http://disney.com/logo.gif | image: 'med' ")
+    assert_equal 'http://disney.com/logo.gif', var.name
+    assert_equal [[:image,["'med'"]]], var.filters    
+  end
+
+  def test_string_single_quoted
+    var = Variable.new(%| "hello" |)
+    assert_equal '"hello"', var.name
+  end
+
+  def test_string_double_quoted
+    var = Variable.new(%| 'hello' |)
+    assert_equal "'hello'", var.name
+  end
+  
+  def test_integer
+    var = Variable.new(%| 1000 |)
+    assert_equal "1000", var.name
+  end
+
+  def test_float
+    var = Variable.new(%| 1000.01 |)
+    assert_equal "1000.01", var.name
+  end
+  
+  def test_string_with_special_chars
+    var = Variable.new(%| 'hello! $!@.;"ddasd" ' |)
+    assert_equal %|'hello! $!@.;"ddasd" '|, var.name
+  end
+
+  def test_string_dot
+    var = Variable.new(%| test.test |)
+    assert_equal 'test.test', var.name
+  end
+end
+
+
+class VariableResolutionTest < Test::Unit::TestCase
+  include Liquid
+  
+  def test_simple_variable    
+    template = Template.parse(%|{{test}}|)
+    assert_equal 'worked', template.render('test' => 'worked')
+    assert_equal 'worked wonderfully', template.render('test' => 'worked wonderfully')
+  end
+
+  def test_simple_with_whitespaces    
+    template = Template.parse(%|  {{ test }}  |)
+    assert_equal '  worked  ', template.render('test' => 'worked')
+    assert_equal '  worked wonderfully  ', template.render('test' => 'worked wonderfully')
+  end
+
+  def test_ignore_unknown
+    template = Template.parse(%|{{ test }}|)
+    assert_equal '', template.render
+  end
+
+  def test_hash_scoping
+    template = Template.parse(%|{{ test.test }}|)
+    assert_equal 'worked', template.render('test' => {'test' => 'worked'})
+  end
+
+end
\ No newline at end of file

Added: trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/History.txt
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/History.txt	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/History.txt	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,82 @@
+== Version History:
+
+=== 1.0.1 / 2008-10-22:
+
+* Fixed multipart form upload so it isn't url escaping the data. DOH.
+  * Affects release_notes and release_changes, but never reported for 5 months.
+
+=== 1.0.0 / 2008-05-20:
+
+* Removed HTTPAccess2, thanks to Aaron Patterson. Even tho he's whiny.
+* Changed initialize/configure to make testing scream. 100x faster.
+
+=== 0.4.5 / 2008-03-11:
+
+* Update for Ruby 1.9.0.
+* Updated History, Rakefile, and Readme for new hoe abilities.
+* Added config backup/restore rake tasks (for testing).
+
+=== 0.4.4 / 2007-08-13:
+
+* New type_id values will merge with extant data. (self-repairing data is Good)
+* Scrape processor_ids, merging in with extant data.
+* Default to "Other" if a file's type is unrecognized.
+
+=== 0.4.3 / 2007-07-23:
+
+* Set mode on .rubyforge directory to 700.
+* Fix fetching of user id when user has no releases.
+
+=== 0.4.2 / 2007-05-21:
+
+* Fix for windoze users (spaces in path).
+* Added check for extant release.
+* Added default hash for first-time releases.
+
+=== 0.4.1 / 2007-03-08:
+
+* Verify that login succeeded and warn against if not (prolly should raise).
+* Print a friendly error if you have the wrong package id.
+* Handle upload error in add_release a bit better.
+
+=== 0.4.0 / 2007-01-09:
+
+* config.yml split and moved to user-config.yml (up to the user to do).
+* auto-config.yml now generated via config command.
+* @config renamed to @userconfig.
+* @config["rubyforge"] moved to @autoconfig.
+* Added save_autoconfig.
+* Pulled scrape_project from scrape_config.
+* scrape_config no longer takes a user param. Use opts to specify.
+* scrape_project, add_project, add/remove_release now save automatically.
+
+=== 0.3.2 / 2006-11-29:
+
+* Fixed file uploads for windows.
+* Correctly scrape releases with funky characters.
+
+=== 0.3.1 / 2006-10-24:
+
+* Added SSL login.
+* Added yet more debugging output if $DEBUG.
+
+=== 0.3.0 / 2006-09-30:
+
+* Added more debugging output if $DEBUG
+* Added news posting.
+* Added multiple file release to add_release (uses add_file for extras).
+* add_release now returns release_id
+* Fixed config scraper to include '-' in names.
+
+=== 0.2.1 / 2006-09-14:
+
+* Gemspec was too loose about packaging. Now using manifest.
+
+=== 0.2.0 / 2006-09-13:
+
+* Split original script into script and library.
+* Added tests for library.
+* Refactored heavily.
+* Added "config" command to scrape group/project/release ids from rubyforge.
+* Added "names" command to help pick groups and projects.
+* Added "add_file" command to add a file to an existing release.

Added: trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/Manifest.txt
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/Manifest.txt	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/Manifest.txt	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,11 @@
+History.txt
+Manifest.txt
+README.txt
+Rakefile
+bin/rubyforge
+lib/rubyforge.rb
+lib/rubyforge/client.rb
+lib/rubyforge/cookie_manager.rb
+test/test_rubyforge.rb
+test/test_rubyforge_client.rb
+test/test_rubyforge_cookie_manager.rb

Added: trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/README.txt
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/README.txt	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/README.txt	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,24 @@
+= Rubyforge
+
+* http://codeforpeople.rubyforge.org/rubyforge/
+* http://rubyforge.org/projects/codeforpeople/
+
+== Description
+
+A script which automates a limited set of rubyforge operations.
+
+* Run 'rubyforge help' for complete usage.
+* Setup: For first time users AND upgrades to 0.4.0:
+  * rubyforge setup (deletes your username and password, so run sparingly!)
+  * edit ~/.rubyforge/user-config.yml
+  * rubyforge config
+* For all rubyforge upgrades, run 'rubyforge config' to ensure you have latest.
+* Don't forget to login!  logging in will store a cookie in your
+  .rubyforge directory which expires after a time.  always run the
+  login command before any operation that requires authentication,
+  such as uploading a package.
+
+== Synopsis
+
+  rubyforge [options]* mode [mode_args]*
+

Added: trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/Rakefile
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/Rakefile	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/Rakefile	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,39 @@
+# -*- ruby -*-
+
+begin
+  require 'hoe'
+rescue LoadError
+  abort "ERROR: This Rakefile is only useful with hoe installed.
+       If you're trying to install the rubyforge library,
+       please install it via rubygems."
+end
+
+abort "you _must_ install this gem to release it" if
+  ENV['VERSION'] && ENV['VERSION'] != RubyForge::VERSION
+
+Hoe.new("rubyforge", RubyForge::VERSION) do |rubyforge|
+  rubyforge.rubyforge_name = "codeforpeople"
+  rubyforge.need_tar = false
+
+  rubyforge.developer('Ryan Davis', 'ryand-ruby at zenspider.com')
+  rubyforge.developer('Eric Hodel', 'drbrain at segment7.net')
+  rubyforge.developer('Ara T Howard', 'ara.t.howard at gmail.com')
+
+  rubyforge.multiruby_skip << "rubinius"
+end
+
+task :backup do
+  Dir.chdir File.expand_path("~/.rubyforge") do
+    cp "user-config.yml",  "user-config.yml.bak"
+    cp "auto-config.yml",  "auto-config.yml.bak"
+  end
+end
+
+task :restore do
+  Dir.chdir File.expand_path("~/.rubyforge") do
+    cp "user-config.yml.bak",  "user-config.yml"
+    cp "auto-config.yml.bak",  "auto-config.yml"
+  end
+end
+
+# vim:syntax=ruby

Added: trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/bin/rubyforge
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/bin/rubyforge	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/bin/rubyforge	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,223 @@
+#! /usr/bin/env ruby
+
+$VERBOSE = true
+
+$:.unshift(File::join(File::dirname(File::dirname(__FILE__)), "lib"))
+
+require 'getoptlong'
+require 'rubyforge'
+
+PROGRAM     = File::basename $0
+
+USAGE = <<-EOL
+SYNOPSIS
+
+  #{ PROGRAM } [options]* mode [mode_args]*
+
+DESCRIPTION
+
+  simplistic script which automates a limited set of rubyforge operations
+
+MODES
+
+  setup()
+    initializes your .rubyforge directory.  you need to run this first before
+    doing anything else.
+
+    example :
+      #{ PROGRAM } setup
+
+  config([project])
+    Helps you populate your auto-config.yml file by scraping rubyforge and
+    getting your groups, projects, and releases.
+
+    example :
+      #{ PROGRAM } config
+      #{ PROGRAM } config myproject
+
+  names()
+    Prints out the names of your configured groups and projects.
+
+    example :
+      #{ PROGRAM } names
+
+  login()
+    sends username and password from config.yml (or --username/--password
+    options) and stores login cookie in cookie.dat.  this is required for
+    subsquent operations work.
+
+    example :
+      #{ PROGRAM } login
+      #{ PROGRAM } login --username zaphod --password 42
+
+  create_package(group_id, package_name)
+    creates the named package under the specified group.
+
+    example :
+      #{ PROGRAM } create_package 1024 traits
+      #{ PROGRAM } login && #{ PROGRAM } create_package codeforpeople.com traits
+
+  add_release(group_id, package_id, release_name, userfile)
+    release a file as release_name under the specified group_id and
+    package_id.
+
+    example :
+      #{ PROGRAM } add_release codeforpeople.com traits 0.8.0 traits-0.8.0.gem
+      #{ PROGRAM } add_release codeforpeople.com traits 0.8.0 traits-0.8.0.tgz
+      #{ PROGRAM } add_release 1024 1242 0.8.0 traits-0.8.0.gem
+      #{ PROGRAM } login && #{ PROGRAM } add_release 1024 1242 0.8.0 traits-0.8.0.gem
+
+  add_file(group_id, package_id, release_id, userfile)
+    add a file to an existing release under the specified group_id,
+    package_id, and release_id
+
+    example :
+      #{ PROGRAM } add_file codeforpeople.com traits 0.8.0 traits-0.8.0.gem
+      #{ PROGRAM } add_file codeforpeople.com traits 0.8.0 traits-0.8.0.tgz
+      #{ PROGRAM } add_file 1024 1242 0.8.0 traits-0.8.0.gem
+
+  delete_package(group_id, package_name)
+    deletes a package and all its files.
+
+    example :
+      #{ PROGRAM } delete_package codeforpeople.com traits
+      #{ PROGRAM } delete_package 1024 traits
+
+NOTES
+
+  - In order to use group_id, package_id, or release_id by name,
+    rather than number, you must edit the rubyforge[group_ids] and
+    rubyforge[package_ids] translation tables in your config.yml. See
+    the config command for more information and help.
+
+  - don\'t forget to login!  logging in will store a cookie in your
+    .rubyforge directory which expires after a time.  always run the login
+    command before any operation that requires authentication, such as
+    uploading a package.
+
+TODO
+
+  - add error checking.  this requires screen scraping to see of an operation
+    succeeded since 200 is returned from rubyforge even for failed operations
+    and only the html text reveals the status.
+
+OPTIONS
+
+  global :
+    --help            , -h
+      this message
+    --config          , -c
+      specify a config file (default #{ RubyForge::CONFIG_F })
+    --username        , -u
+      specify username, taken from config otherwise
+    --password        , -p
+      specify password, taken from config otherwise
+    --cookie_jar      , -C
+      specify cookie storage file (default #{ RubyForge::COOKIE_F })
+
+  add_release :
+    --is_private      , -P
+      if true, release is not public
+    --release_date    , -r
+      specify time of release (default 'now')
+    --type_id         , -t
+      specify filetype code (default determined by ext)
+    --processor_id    , -o
+      specify processor (default 'Any')
+    --release_notes   , -n
+      specify release notes as string or file
+    --release_changes , -a
+      specify release changes as string or file
+    --preformatted    , -f
+      specify whether release_notes/changes are preformatted
+
+EOL
+
+mode = ARGV.shift
+
+opts = GetoptLong::new(
+         [ "--help"            , "-h" , GetoptLong::REQUIRED_ARGUMENT ],
+         [ "--username"        , "-u" , GetoptLong::REQUIRED_ARGUMENT ],
+         [ "--password"        , "-p" , GetoptLong::REQUIRED_ARGUMENT ],
+         [ "--cookie_jar"      , "-C" , GetoptLong::REQUIRED_ARGUMENT ],
+         [ "--is_private"      , "-P" , GetoptLong::REQUIRED_ARGUMENT ],
+         [ "--release_date"    , "-r" , GetoptLong::REQUIRED_ARGUMENT ],
+         [ "--type_id"         , "-t" , GetoptLong::REQUIRED_ARGUMENT ],
+         [ "--processor_id"    , "-o" , GetoptLong::REQUIRED_ARGUMENT ],
+         [ "--release_notes"   , "-n" , GetoptLong::REQUIRED_ARGUMENT ],
+         [ "--release_changes" , "-a" , GetoptLong::REQUIRED_ARGUMENT ],
+         [ "--preformatted"    , "-f" , GetoptLong::NO_ARGUMENT ]
+       ).enum_for.inject({}) { |h, (k, v)| h.update k.delete('-') => v }
+
+rubyforge = RubyForge.new
+rubyforge.configure opts
+
+mode = "help" if opts["help"]
+
+case mode
+when %r/help/
+  USAGE.display
+when %r/setup/
+  rubyforge.setup
+when %r/config/
+  project = ARGV.shift
+  if project then
+    rubyforge.scrape_project(project)
+  else
+    rubyforge.scrape_config
+  end
+when %r/names/
+  rf = rubyforge.autoconfig
+  puts "groups  : #{rf["group_ids"].keys.sort.join(", ")}"
+  puts "packages: #{rf["package_ids"].keys.sort.join(", ")}"
+when %r/login/
+  rubyforge.login
+when %r/create_package/
+  page, msg = "/frs/admin/index.php", "post_content"
+
+  group_id, package_name = ARGV
+
+  abort "no <group_id>" unless group_id
+  abort "no <package_name>" unless package_name
+
+  group_id = Integer(group_id) rescue group_id
+
+  rubyforge.create_package group_id, package_name
+when %r/delete_package/
+  group_id, package_id = ARGV
+
+  abort "no <group_id>" unless group_id
+  abort "no <package_id>" unless package_id
+
+  group_id = Integer(group_id) rescue group_id
+  package_id = Integer(package_id) rescue package_id
+
+  rubyforge.delete_package group_id, package_id
+when %r/add_release/
+  group_id, package_id, release_name, userfile = ARGV
+
+  abort "no <group_id>" unless group_id
+  abort "no <package_id>" unless package_id
+  abort "no <release_name>" unless release_name
+  abort "no <userfile>" unless userfile
+
+  group_id = Integer(group_id) rescue group_id
+  package_id = Integer(package_id) rescue package_id
+
+  rubyforge.add_release group_id, package_id, release_name, userfile
+when %r/add_file/
+  group_id, package_id, release_id, userfile = ARGV
+
+  abort "no <group_id>" unless group_id
+  abort "no <package_id>" unless package_id
+  abort "no <release_id>" unless release_id
+  abort "no <userfile>" unless userfile
+
+  group_id = Integer(group_id) rescue group_id
+  package_id = Integer(package_id) rescue package_id
+  release_id = Integer(release_id) rescue release_id
+
+  rubyforge.add_file group_id, package_id, release_id, userfile
+else
+  abort USAGE
+end


Property changes on: trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/bin/rubyforge
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge/client.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge/client.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge/client.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,134 @@
+require 'webrick/cookie'
+require 'net/http'
+require 'net/https'
+require 'rubyforge/cookie_manager'
+
+# clean up warnings caused by web servers that send down 2 digit years
+class Time
+  class << self
+    alias :old_utc :utc
+
+    def utc(*args)
+      century = Time.now.year / 100 * 100
+      args[0] += century if args[0] < 100
+      old_utc(*args)
+    end
+  end
+end unless Time.respond_to? :old_utc
+
+# clean up "using default DH parameters" warning for https
+class Net::HTTP
+  alias :old_use_ssl= :use_ssl=
+  def use_ssl= flag
+    self.old_use_ssl = flag
+    @ssl_context.tmp_dh_callback = proc {}
+  end
+end unless Net::HTTP.public_instance_methods.include? "old_use_ssl="
+
+class RubyForge
+  class Client
+    attr_accessor :debug_dev, :ssl_verify_mode, :agent_class
+
+    def initialize(proxy = nil)
+      @debug_dev       = nil
+      @ssl_verify_mode = OpenSSL::SSL::VERIFY_NONE
+      @cookie_manager  = CookieManager.new
+      @agent_class     = Net::HTTP
+    end
+
+    def cookie_store=(path)
+      @cookie_manager = CookieManager.load(path)
+    end
+
+    def post_content(uri, form = {}, headers = {})
+      uri = URI.parse(uri) unless uri.is_a?(URI)
+      request = agent_class::Post.new(uri.request_uri)
+      execute(request, uri, form, headers)
+    end
+
+    def get_content(uri, query = {}, headers = {})
+      uri = URI.parse(uri) unless uri.is_a?(URI)
+      request = agent_class::Get.new(uri.request_uri)
+      execute(request, uri, query, headers)
+    end
+
+    def execute(request, uri, parameters = {}, headers = {})
+      {
+        'content-type' => 'application/x-www-form-urlencoded'
+      }.merge(headers).each { |k,v| request[k] = v }
+
+      @cookie_manager[uri].each { |k,v|
+        request['Cookie'] = v.to_s
+      }
+
+      http = agent_class.new( uri.host, uri.port )
+
+      if uri.scheme == 'https'
+        http.use_ssl      = true
+        http.verify_mode  = OpenSSL::SSL::VERIFY_NONE
+      end
+
+      request_data = case request['Content-Type']
+                     when /boundary=(.*)$/
+                       boundary_data_for($1, parameters)
+                     else
+                       query_string_for(parameters)
+                     end
+      request['Content-Length'] = request_data.length.to_s
+
+      response = http.request(request, request_data)
+      (response.get_fields('Set-Cookie') || []).each do |raw_cookie|
+        WEBrick::Cookie.parse_set_cookies(raw_cookie).each { |baked_cookie|
+          baked_cookie.domain ||= url.host
+          baked_cookie.path   ||= url.path
+          @cookie_manager.add(uri, baked_cookie)
+        }
+      end
+
+      return response.body if response.class <= Net::HTTPSuccess
+
+      if response.class <= Net::HTTPRedirection
+        location = response['Location']
+        unless location =~ /^http/
+          location = "#{uri.scheme}://#{uri.host}#{location}"
+        end
+        uri = URI.parse(location)
+
+        execute(agent_class::Get.new(uri.request_uri), uri)
+      end
+    end
+
+    def boundary_data_for(boundary, parameters)
+      parameters.sort_by {|k,v| k.to_s }.map { |k,v|
+        parameter = "--#{boundary}\r\nContent-Disposition: form-data; name=\"" +
+            WEBrick::HTTPUtils.escape_form(k.to_s) + "\""
+
+        if v.respond_to? :path
+          parameter += "; filename=\"#{File.basename(v.path)}\"\r\n"
+          parameter += "Content-Transfer-Encoding: binary\r\n"
+          parameter += "Content-Type: text/plain"
+        end
+        parameter += "\r\n\r\n"
+
+        if v.respond_to? :path
+          parameter += v.read
+        else
+          parameter += v.to_s
+        end
+
+        parameter
+      }.join("\r\n") + "\r\n--#{boundary}--\r\n"
+    end
+
+    def query_string_for(parameters)
+      parameters.sort_by {|k,v| k.to_s }.map { |k,v|
+        k && [  WEBrick::HTTPUtils.escape_form(k.to_s),
+                WEBrick::HTTPUtils.escape_form(v.to_s) ].join('=')
+      }.compact.join('&')
+    end
+
+    def save_cookie_store
+      @cookie_manager.save!
+    end
+  end
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge/cookie_manager.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge/cookie_manager.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge/cookie_manager.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,51 @@
+class RubyForge
+  class CookieManager
+    class << self
+      def load(path)
+        cm = YAML.load_file(path) rescue CookieManager.new(path)
+        cm = CookieManager.new(path) unless cm.is_a?(CookieManager)
+        cm.clean_stale_cookies
+      end
+    end
+
+    attr_accessor :cookies_file
+    def initialize(cookies_file = nil)
+      @jar = Hash.new { |hash,domain_name|
+        hash[domain_name.downcase] = {}
+      }
+      @cookies_file = cookies_file
+    end
+
+    def [](uri)
+      # FIXME we need to do more matching on hostname....  This is not
+      # bulletproof
+      @jar[uri.host.downcase]
+    end
+
+    def empty?
+      @jar.empty? || @jar.all? { |k,v| v.empty? }
+    end
+
+    def save!
+      File.open(@cookies_file, 'wb') { |f|
+        f.write(YAML.dump(self))
+      }
+    end
+
+    def add(uri, cookie)
+      no_dot_domain = cookie.domain.gsub(/^\./, '')
+      return unless uri.host =~ /#{no_dot_domain}$/i
+      @jar[no_dot_domain][cookie.name] = cookie
+      clean_stale_cookies
+    end
+
+    def clean_stale_cookies
+      @jar.each do |domain, cookies|
+        cookies.each do |name, cookie|
+          cookies.delete(name) if cookie.expires < Time.now
+        end
+      end
+      self
+    end
+  end
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,475 @@
+#! /usr/bin/env ruby -w
+
+require 'enumerator'
+require 'fileutils'
+require 'yaml'
+require 'open-uri'
+require 'rubyforge/client'
+
+$TESTING = false unless defined? $TESTING
+
+class RubyForge
+
+  # :stopdoc:
+  VERSION     = '1.0.1'
+  HOME        = ENV["HOME"] || ENV["HOMEPATH"] || File::expand_path("~")
+  RUBYFORGE_D = File::join HOME, ".rubyforge"
+  CONFIG_F    = File::join RUBYFORGE_D, "user-config.yml"
+  COOKIE_F    = File::join RUBYFORGE_D, "cookie.dat"
+
+  # We must use __FILE__ instead of DATA because this is now a library
+  # and DATA is relative to $0, not __FILE__.
+  config = File.read(__FILE__).split(/__END__/).last.gsub(/#\{(.*)\}/) {eval $1}
+  CONFIG = YAML.load(config)
+  # :startdoc:
+
+  attr_reader :userconfig, :autoconfig
+
+  def initialize(userconfig=nil, autoconfig=nil, opts=nil)
+    # def initialize(userconfig=CONFIG_F, opts={})
+    @userconfig, @autoconfig = userconfig, autoconfig
+
+    @autoconfig ||= CONFIG["rubyforge"].dup
+    @userconfig.merge! opts if opts
+
+    @client = nil
+    @uri = nil
+  end
+
+  def configure opts = {}
+    user_path        = CONFIG_F
+    dir, file        = File.split(user_path)
+
+    @userconfig      = if test(?e, user_path) then
+                         YAML.load_file(user_path)
+                       else
+                         CONFIG
+                       end.merge(opts)
+    @autoconfig_path = File.join(dir, file.sub(/^user/, 'auto'))
+    @autoconfig      = if test(?e, @autoconfig_path) then
+                         YAML.load_file(@autoconfig_path)
+                       else
+                         CONFIG["rubyforge"].dup
+                       end
+    @autoconfig["type_ids"] = CONFIG['rubyforge']['type_ids'].dup
+
+    raise "no <username>"   unless @userconfig["username"]
+    raise "no <password>"   unless @userconfig["password"]
+    raise "no <cookie_jar>" unless @userconfig["cookie_jar"]
+
+    self
+  end
+
+  def uri
+    @uri ||= URI.parse @userconfig['uri']
+  end
+
+  def setup
+    FileUtils::mkdir_p RUBYFORGE_D, :mode => 0700 unless test ?d, RUBYFORGE_D
+    test ?e, CONFIG_F and FileUtils::mv CONFIG_F, "#{CONFIG_F}.bak"
+    config = CONFIG.dup
+    config.delete "rubyforge"
+
+    open(CONFIG_F, "w") { |f|
+      f.write YAML.dump(config)
+    }
+    FileUtils::touch COOKIE_F
+    edit = (ENV["EDITOR"] || ENV["EDIT"] || "vi") + " '#{CONFIG_F}'"
+    system edit or puts "edit '#{CONFIG_F}'"
+  end
+
+  def save_autoconfig
+    File.open(@autoconfig_path, "w") do |file|
+      YAML.dump @autoconfig, file
+    end
+  end
+
+  def scrape_config
+    username = @userconfig['username']
+
+    %w(group package processor release).each do |type|
+      @autoconfig["#{type}_ids"].clear
+    end
+
+    puts "Getting #{username}"
+    html = URI.parse("http://rubyforge.org/users/#{username}/index.html").read
+
+    projects = html.scan(%r%/projects/([^/]+)/%).flatten
+
+    puts "Fetching #{projects.size} projects"
+    projects.each do |project|
+      next if project == "support"
+      scrape_project(project)
+    end
+  end
+
+  def scrape_project(project)
+    data = {
+      "group_ids" => {},
+      "package_ids" => {},
+      "processor_ids" => Hash.new { |h,k| h[k] = {} },
+      "release_ids" => Hash.new { |h,k| h[k] = {} },
+    }
+
+    puts "Updating #{project}"
+
+    unless data["group_ids"].has_key? project then
+      html = URI.parse("http://rubyforge.org/projects/#{project}/index.html").read
+      group_id = html[/(frs|tracker|mail)\/\?group_id=\d+/][/\d+/].to_i
+      data["group_ids"][project] = group_id
+    end
+
+    group_id = data["group_ids"][project]
+
+    html = URI.parse("http://rubyforge.org/frs/?group_id=#{group_id}").read
+
+    package = nil
+    html.scan(/<h3>[^<]+|release_id=\d+">[^>]+|filemodule_id=\d+/).each do |s|
+      case s
+      when /<h3>([^<]+)/ then
+        package = $1.strip
+      when /release_id=(\d+)">([^<]+)/ then
+        data["release_ids"][package][$2] = $1.to_i
+      when /filemodule_id=(\d+)/ then
+        data["package_ids"][package] = $1.to_i
+      end
+    end
+
+    if not data['release_ids'][package].empty? and
+       @autoconfig['processor_ids'].empty? then
+      puts "Fetching processor ids"
+
+      login
+
+      html = client.get_content "http://rubyforge.org/frs/admin/qrs.php?package=&group_id=#{group_id}"
+
+      html =~ /<select name="processor_id">(.*?)<\/select>/m
+      processors = $1
+      processors.scan(/<option value="(\d{4})">([^<]+)/) do
+        data["processor_ids"][$2] = $1.to_i
+      end if processors
+    end
+
+    data.each do |key, val|
+      @autoconfig[key].merge! val
+    end
+
+    save_autoconfig
+  end
+
+  def login
+    page = self.uri + "/account/login.php"
+    page.scheme = 'https'
+    page = URI.parse page.to_s # set SSL port correctly
+
+    username = @userconfig["username"]
+    password = @userconfig["password"]
+
+    form = {
+      "return_to"      => "",
+      "form_loginname" => username,
+      "form_pw"        => password,
+      "login"          => "Login"
+    }
+
+    response = run page, form
+
+    re = %r/personal\s+page\s+for:\s+#{ Regexp.escape username }/iom
+    unless response =~ re
+      warn("%s:%d: warning: potentially failed login using %s:%s" %
+        [__FILE__,__LINE__,username,password]) unless $TESTING
+    end
+
+    response
+  end
+
+  def create_package(group_id, package_name)
+    page = "/frs/admin/index.php"
+
+    group_id = lookup "group", group_id
+    is_private = @userconfig["is_private"]
+    is_public = is_private ? 0 : 1
+
+    form = {
+      "func"         => "add_package",
+      "group_id"     => group_id,
+      "package_name" => package_name,
+      "is_public"    => is_public,
+      "submit"       => "Create This Package",
+    }
+
+    run page, form
+
+    group_name = @autoconfig["group_ids"].invert[group_id]
+    scrape_project(group_name)
+  end
+
+  ##
+  # Posts news item to +group_id+ (can be name) with +subject+ and +body+
+
+  def post_news(group_id, subject, body)
+    page = "/news/submit.php"
+    group_id = lookup "group", group_id
+
+    form = {
+      "group_id"     => group_id,
+      "post_changes" => "y",
+      "summary"      => subject,
+      "details"      => body,
+      "submit"       => "Submit",
+    }
+
+    run page, form
+  end
+
+  def delete_package(group_id, package_id)
+    page = "/frs/admin/index.php"
+
+    group_id = lookup "group", group_id
+    package_id = lookup "package", package_id
+
+    form = {
+      "func"        => "delete_package",
+      "group_id"    => group_id,
+      "package_id"  => package_id,
+      "sure"        => "1",
+      "really_sure" => "1",
+      "submit"      => "Delete",
+    }
+
+    package_name = @autoconfig["package_ids"].invert[package_id]
+    @autoconfig["package_ids"].delete package_name
+    @autoconfig["release_ids"].delete package_name
+    save_autoconfig
+
+    run page, form
+  end
+
+  def add_release(group_id, package_id, release_name, *files)
+    userfile = files.shift
+    page = "/frs/admin/qrs.php"
+
+    group_id        = lookup "group", group_id
+    package_id      = lookup "package", package_id
+    userfile        = open userfile, 'rb'
+    release_date    = @userconfig["release_date"]
+    type_id         = @userconfig["type_id"]
+    processor_id    = @userconfig["processor_id"]
+    release_notes   = @userconfig["release_notes"]
+    release_changes = @userconfig["release_changes"]
+    preformatted    = @userconfig["preformatted"]
+
+    release_date ||= Time.now.strftime("%Y-%m-%d %H:%M")
+
+    type_id ||= userfile.path[%r|\.[^\./]+$|]
+    type_id = (lookup "type", type_id rescue lookup "type", ".oth")
+
+    processor_id ||= "Any"
+    processor_id = lookup "processor", processor_id
+
+    release_notes = IO::read(release_notes) if
+      test(?e, release_notes) if release_notes
+
+    release_changes = IO::read(release_changes) if
+      test(?e, release_changes) if release_changes
+
+    preformatted = preformatted ? 1 : 0
+
+    form = {
+      "group_id"        => group_id,
+      "package_id"      => package_id,
+      "release_name"    => release_name,
+      "release_date"    => release_date,
+      "type_id"         => type_id,
+      "processor_id"    => processor_id,
+      "release_notes"   => release_notes,
+      "release_changes" => release_changes,
+      "preformatted"    => preformatted,
+      "userfile"        => userfile,
+      "submit"          => "Release File"
+    }
+
+    boundary = Array::new(8){ "%2.2d" % rand(42) }.join('__')
+    boundary = "multipart/form-data; boundary=___#{ boundary }___"
+
+    html = run(page, form, 'content-type' => boundary)
+    raise "Invalid package_id #{package_id}" if html[/Invalid package_id/]
+    raise "You have already released this version." if html[/That filename already exists in this project/]
+
+    release_id = html[/release_id=\d+/][/\d+/].to_i rescue nil
+
+    unless release_id then
+      puts html if $DEBUG
+      raise "Couldn't get release_id, upload failed\?"
+    end
+
+    puts "RELEASE ID = #{release_id}" if $DEBUG
+
+    files.each do |file|
+      add_file(group_id, package_id, release_id, file)
+    end
+
+    package_name = @autoconfig["package_ids"].invert[package_id]
+    raise "unknown package name for #{package_id}" if package_name.nil?
+    @autoconfig["release_ids"][package_name] ||= {}
+    @autoconfig["release_ids"][package_name][release_name] = release_id
+    save_autoconfig
+
+    release_id
+  end
+
+  ##
+  # add a file to an existing release under the specified group_id,
+  # package_id, and release_id
+  #
+  # example :
+  #   add_file("codeforpeople.com", "traits", "0.8.0", "traits-0.8.0.gem")
+  #   add_file("codeforpeople.com", "traits", "0.8.0", "traits-0.8.0.tgz")
+  #   add_file(1024, 1242, "0.8.0", "traits-0.8.0.gem")
+
+  def add_file(group_name, package_name, release_name, userfile)
+    page         = '/frs/admin/editrelease.php'
+    type_id      = @userconfig["type_id"]
+    group_id     = lookup "group", group_name
+    package_id   = lookup "package", package_name
+    release_id   = (Integer === release_name) ? release_name : lookup("release", package_name)[release_name]
+    processor_id = @userconfig["processor_id"]
+
+    page = "/frs/admin/editrelease.php?group_id=#{group_id}&release_id=#{release_id}&package_id=#{package_id}"
+
+    userfile = open userfile, 'rb'
+
+    type_id ||= userfile.path[%r|\.[^\./]+$|]
+    type_id = (lookup "type", type_id rescue lookup "type", ".oth")
+
+    processor_id ||= "Any"
+    processor_id = lookup "processor", processor_id
+
+    form = {
+      "step2"        => 1,
+      "type_id"      => type_id,
+      "processor_id" => processor_id,
+      "userfile"     => userfile,
+      "submit"       => "Add This File"
+      }
+
+    boundary = Array::new(8){ "%2.2d" % rand(42) }.join('__')
+    boundary = "multipart/form-data; boundary=___#{ boundary }___"
+
+    run page, form, 'content-type' => boundary
+  end
+
+  def client
+    return @client if @client
+
+    @client = RubyForge::Client::new ENV["HTTP_PROXY"]
+    @client.debug_dev = STDERR if ENV["RUBYFORGE_DEBUG"] || ENV["DEBUG"] || $DEBUG
+    @client.cookie_store = @userconfig["cookie_jar"]
+
+    @client
+  end
+
+  def run(page, form, extheader={}) # :nodoc:
+    uri = self.uri + page
+    if $DEBUG then
+      puts "client.post_content #{uri.inspect}, #{form.inspect}, #{extheader.inspect}"
+    end
+
+    response = client.post_content uri, form, extheader
+
+    client.save_cookie_store
+
+    if $DEBUG then
+      response.sub!(/\A.*end tabGenerator -->/m, '')
+      response.gsub!(/\t/, '  ')
+      response.gsub!(/\n{3,}/, "\n\n")
+      puts response
+    end
+
+    return response
+  end
+
+  def lookup(type, val) # :nodoc:
+    unless Fixnum === val then
+      key = val.to_s
+      val = @autoconfig["#{type}_ids"][key]
+      raise "no <#{type}_id> configured for <#{ key }>" unless val
+    end
+    val
+  end
+end
+
+__END__
+#
+# base rubyforge uri - store in #{ CONFIG_F }
+#
+  uri        : http://rubyforge.org
+#
+# this must be your username
+#
+  username   : username
+#
+# this must be your password
+#
+  password   : password
+#
+# defaults for some values
+#
+  cookie_jar : #{ COOKIE_F }
+  is_private : false
+# AUTOCONFIG:
+  rubyforge :
+  #
+  # map your group names to their rubyforge ids
+  #
+    group_ids :
+      codeforpeople.com : 1024
+  #
+  # map your package names to their rubyforge ids
+  #
+    package_ids :
+      traits : 1241
+  #
+  # map your package names to their rubyforge ids
+  #
+    release_ids :
+      traits :
+        1.2.3 : 666
+  #
+  # mapping file exts to rubyforge ids
+  #
+    type_ids :
+      .deb         : 1000
+      .rpm         : 2000
+      .zip         : 3000
+      .bz2         : 3100
+      .gz          : 3110
+      .src.zip     : 5000
+      .src.bz2     : 5010
+      .src.tar.bz2 : 5010
+      .src.gz      : 5020
+      .src.tar.gz  : 5020
+      .src.rpm     : 5100
+      .src         : 5900
+      .jpg         : 8000
+      .txt         : 8100
+      .text        : 8100
+      .htm         : 8200
+      .html        : 8200
+      .pdf         : 8300
+      .oth         : 9999
+      .ebuild      : 1300
+      .exe         : 1100
+      .dmg         : 1200
+      .tar.gz      : 5000
+      .tgz         : 5000
+      .gem         : 1400
+      .pgp         : 8150
+      .sig         : 8150
+      .pem         : 1500
+
+  #
+  # map processor names to rubyforge ids
+  #
+    processor_ids :
+      Other      : 9999


Property changes on: trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/lib/rubyforge.rb
___________________________________________________________________
Name: svn:executable
   + *

Added: trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test/test_rubyforge.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test/test_rubyforge.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test/test_rubyforge.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,390 @@
+require 'test/unit' unless defined? $ZENTEST and $ZENTEST
+
+$TESTING = true
+require 'rubyforge'
+require 'tmpdir'
+
+class RubyForge
+  attr_writer :client
+
+  alias :old_save_autoconfig :save_autoconfig
+  def save_autoconfig
+    # raise "not during test"
+  end
+end
+
+class RubyForge::FakeClient
+  def form; end
+  def save_cookie_store(*args) end
+
+  def post_content(*args)
+    FakeRubyForge::HTML
+  end
+
+  def get_content(*args)
+    URI::HTTP.data.join("\n")
+  end
+end
+
+class FakeRubyForge < RubyForge
+  HTML = "blah blah <form action=\"/frs/admin/editrelease.php?group_id=440&release_id=6948&package_id=491\" method=\"post\"> blah blah"
+
+  attr_accessor :page, :form, :extheader, :requests, :scrape
+  def run(page, form, extheader={})
+    @page, @form, @extheader = page, form, extheader
+    @requests ||= []
+    @requests << { :url => page, :form => form, :headers => extheader }
+    HTML
+  end
+
+  def scrape_project(proj)
+    @scrape ||= []
+    @scrape << proj
+  end
+end
+
+# TODO: remove this and make rubyforge use Client exclusively
+class URI::HTTP
+  def self.data
+    @data ||= []
+  end
+
+  def read
+    self.class.data.shift or raise "no more data"
+  end
+end
+
+class TestRubyForge < Test::Unit::TestCase
+  def setup
+    srand(0)
+    util_new FakeRubyForge
+  end
+
+  def teardown
+    File.unlink @cookie_path if defined? @cookie_path
+    #     if defined? @old_autoconfig then
+    #       @rubyforge.autoconfig.replace @old_autoconfig
+    #       @rubyforge.save_autoconfig
+    #     end
+  end
+
+  def test_initialize_bad
+    @cookie_path = File.join(Dir.tmpdir, "cookie.#{$$}.dat")
+    File.open(@cookie_path, 'w') {} # touch
+
+    user_data = {
+      "uri"        => "http://rubyforge.org",
+      "is_private" => false,
+      "cookie_jar" => @cookie_path,
+      "username"   => "username",
+      "password"   => "password"
+    }
+
+    assert_raise RuntimeError do
+      rf = RubyForge.new user_data
+      rf.configure "username" => nil
+    end
+    assert_raise RuntimeError do
+      rf = RubyForge.new user_data
+      rf.configure "password" => nil
+    end
+    assert_raise RuntimeError do
+      rf = RubyForge.new user_data
+      rf.configure "cookie_jar" => nil
+    end
+  end
+
+  def test_setup
+    # TODO raise NotImplementedError, 'Need to write test_setup'
+  end
+
+  def test_login
+    u, p = 'fooby', 's3kr3t'
+    @rubyforge.userconfig['username'] = u
+    @rubyforge.userconfig['password'] = p
+    @rubyforge.login
+
+    util_run('https://rubyforge.org/account/login.php',
+             'form_pw' => p,
+             'form_loginname' => u,
+             'return_to' => '',
+             'login' => 'Login')
+  end
+
+  def test_create_package
+    @rubyforge.create_package(42, 'woot_pkg')
+
+    util_run('/frs/admin/index.php',
+             "submit" => "Create This Package",
+             "group_id" => 42,
+             "is_public" => 1,
+             "package_name" => "woot_pkg",
+             "func" => "add_package")
+  end
+
+  def test_delete_package
+    @rubyforge.delete_package(42, 666)
+    util_delete_package
+  end
+
+  def test_delete_package_package_name
+    @rubyforge.delete_package(42, "woot_pkg")
+    util_delete_package
+  end
+
+  def test_delete_package_undefined_package_name
+    assert_raise RuntimeError do
+      @rubyforge.delete_package(42, "blah")
+    end
+  end
+
+  def test_delete_package_group_name
+    @rubyforge.delete_package("seattlerb", 666)
+    util_delete_package
+  end
+
+  def test_delete_package_undefined_group_name
+    assert_raise RuntimeError do
+      @rubyforge.delete_package("blah", 666)
+    end
+  end
+
+  def test_add_file
+    @rubyforge.autoconfig["package_ids"]["ringy_dingy"] = 314
+    @rubyforge.autoconfig["release_ids"]["ringy_dingy"] ||= {}
+    @rubyforge.autoconfig["release_ids"]["ringy_dingy"]["1.2.3"] = 43
+
+    @rubyforge.add_file('seattlerb', 'ringy_dingy', '1.2.3', __FILE__)
+
+    util_run('/frs/admin/editrelease.php?group_id=42&release_id=43&package_id=314',
+             { "step2" => 1,
+               "type_id" => 9999,
+               "processor_id" => 8000,
+               "submit" => "Add This File"},
+             {"content-type"=> "multipart/form-data; boundary=___00__03__03__39__09__19__21__36___"})
+  end
+
+  def test_add_release
+    @rubyforge.add_release(42, 666, '1.2.3', __FILE__)
+    util_add_release
+  end
+
+  def test_add_release_multiple
+    @rubyforge.add_release(42, 666, '1.2.3', __FILE__, __FILE__) # dunno if that'll work
+    add_release = ({ :url=>"/frs/admin/qrs.php",
+                     :form=>{"processor_id"=>8000,
+                       "submit"=>"Release File",
+                       "preformatted"=>0,
+                       "release_changes"=>nil,
+                       "type_id"=>9999,
+                       "group_id"=>42,
+                       "release_name"=>"1.2.3",
+                       "release_notes"=>nil,
+                       "package_id"=>666,
+                       "release_date"=>"today"},
+                     :headers=> {"content-type" => "multipart/form-data; boundary=___00__03__03__39__09__19__21__36___"}})
+    add_file = ({ :url => '/frs/admin/editrelease.php?group_id=42&release_id=6948&package_id=666',
+                  :form => { "step2" => 1,
+                    "type_id" => 9999,
+                    "processor_id" => 8000,
+                    "submit" => "Add This File"},
+                  :headers => {"content-type"=> "multipart/form-data; boundary=___23__06__24__24__12__01__38__39___"}})
+    expected = [add_release, add_file]
+
+    result = @rubyforge.requests
+    result.each do |r|
+      r[:form].delete "userfile"
+    end
+
+    assert_equal expected, result
+  end
+
+  def test_post_news
+    @rubyforge.post_news("seattlerb", "my summary", "my news")
+
+    util_run("/news/submit.php",
+             "group_id"     => 42,
+             "post_changes" => "y",
+             "details"      => "my news",
+             "summary"      => "my summary",
+             "submit"       => "Submit")
+  end
+
+  def test_add_release_package_name
+    @rubyforge.add_release(42, "woot_pkg", '1.2.3', __FILE__)
+    util_add_release
+  end
+
+  def test_add_release_undefined_package_name
+    assert_raise RuntimeError do
+      @rubyforge.add_release(42, "blah", '1.2.3', __FILE__)
+    end
+  end
+
+  def test_add_release_group_name
+    @rubyforge.add_release("seattlerb", 666, '1.2.3', __FILE__)
+    util_add_release
+  end
+
+  def test_add_release_undefined_group_name
+    assert_raise RuntimeError do
+      @rubyforge.add_release("blah", 666, '1.2.3', __FILE__)
+    end
+  end
+
+  def test_lookup_id
+    assert_equal 43, @rubyforge.lookup("package", 43)
+  end
+
+  def test_lookup_string_number
+    assert_raise RuntimeError do
+      @rubyforge.lookup("package", "43")
+    end
+  end
+
+  def test_lookup_name
+    @rubyforge.autoconfig["package_ids"]["ringy_dingy"] = 314
+    assert_equal 314, @rubyforge.lookup("package", "ringy_dingy")
+  end
+
+  def test_lookup_undefined
+    assert_raise RuntimeError do
+      @rubyforge.lookup("package", "blah")
+    end
+  end
+
+  def test_run
+    util_new FakeRubyForge
+    result = @rubyforge.add_release(42, 666, '1.2.3', __FILE__)
+
+    assert_equal 6948, result
+    extheader = {"content-type"=> "multipart/form-data; boundary=___00__03__03__39__09__19__21__36___"}
+
+    form = {
+      "processor_id" => 8000,
+      "submit" => "Release File",
+      "preformatted" => 0,
+      "release_changes" => nil,
+      "type_id" => 9999,
+      "group_id" => 42,
+      "release_name" => "1.2.3",
+      "release_notes" => nil,
+      "package_id" => 666,
+      "release_date" => "today"
+    }
+
+    client = @rubyforge.client
+#    assert client.form.delete("userfile")
+
+#     assert_equal 'http://rubyforge.org/frs/admin/qrs.php', client.url.to_s
+#     assert_equal form, client.form
+#     assert_equal extheader, client.headers
+  end
+
+  def test_scrape_project
+    orig_stdout = $stdout
+    orig_stderr = $stderr
+    $stdout = StringIO.new
+    $stderr = StringIO.new
+    util_new RubyForge # TODO: switch to Fake
+    @rubyforge.autoconfig.each { |k,v| v.clear }
+
+    URI::HTTP.data << "<a href='/tracker/?group_id=1513'>Tracker</a>"
+    URI::HTTP.data << <<-EOF
+<h3>ar_mailer
+<a href="/frs/monitor.php?filemodule_id=4566&group_id=1513&start=1">
+<a href="shownotes.php?release_id=13368">1.3.1</a>
+<a href="shownotes.php?release_id=12185">1.2.0</a></strong>
+    EOF
+
+    #    @rubyforge.scrape << < <-EOF
+    URI::HTTP.data << <<-EOF
+<select name="processor_id">
+<option value="100">Must Choose One</option>
+<option value="1000">i386</option>
+<option value="1001">i387</option>
+</select>
+    EOF
+
+    @rubyforge.scrape_project('my_project')
+
+    expected = {
+      "group_ids" => { "my_project" => 1513 },
+      "package_ids" => { "ar_mailer" => 4566 },
+      "processor_ids" => { "i386" => 1000, "i387" => 1001 },
+      "release_ids" => {
+        "ar_mailer" => { "1.2.0" => 12185, "1.3.1" => 13368 }
+      },
+      "type_ids" => {},
+    }
+
+    assert_equal expected, @rubyforge.autoconfig
+  ensure
+    $stdout = orig_stdout
+    $stderr = orig_stderr
+  end
+
+  def util_new(klass)
+    @cookie_path = File.join(Dir.tmpdir, "cookie.#{$$}.dat")
+    File.open(@cookie_path, 'w') {} # touch
+
+    user_data = {
+      "uri"        => "http://rubyforge.org",
+      "is_private" => false,
+      "cookie_jar" => @cookie_path,
+      "username"   => "username",
+      "password"   => "password"
+    }
+
+    auto_data = {
+      "group_ids" => {},
+      "package_ids" => {},
+      "release_ids" => Hash.new { |h,k| h[k] = {} },
+      "type_ids" => {},
+      "processor_ids" => {"Any"=>8000},
+    }
+
+    @rubyforge = klass.new user_data, auto_data
+
+    @rubyforge.client = RubyForge::FakeClient.new
+
+    @rubyforge.userconfig["release_date"]            = "today"
+    @rubyforge.autoconfig["type_ids"][".rb"]         = 9999
+    @rubyforge.autoconfig["group_ids"]["seattlerb"]  = 42
+    @rubyforge.autoconfig["package_ids"]["woot_pkg"] = 666
+  end
+
+  def util_run(page, form={}, extheader={})
+    form_result = @rubyforge.form
+    assert form_result.delete("userfile") unless extheader.empty?
+
+    assert_equal page, @rubyforge.page.to_s
+    assert_equal form, form_result
+    assert_equal extheader, @rubyforge.extheader
+  end
+
+  def util_add_release
+    util_run('/frs/admin/qrs.php',
+             {"processor_id" => 8000,
+               "submit" => "Release File",
+               "preformatted" => 0,
+               "release_changes" => nil,
+               "type_id" => 9999,
+               "group_id" => 42,
+               "release_name" => "1.2.3",
+               "release_notes" => nil,
+               "package_id" => 666,
+               "release_date" => "today"},
+             {"content-type"=> "multipart/form-data; boundary=___00__03__03__39__09__19__21__36___"})
+  end
+
+  def util_delete_package
+    util_run('/frs/admin/index.php',
+             "submit" => "Delete",
+             "really_sure" => "1",
+             "group_id" => 42,
+             "func" => "delete_package",
+             "package_id" => 666,
+             "sure" => "1")
+  end
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test/test_rubyforge_client.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test/test_rubyforge_client.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test/test_rubyforge_client.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,122 @@
+require 'test/unit' unless defined? $ZENTEST and $ZENTEST
+require 'rubyforge'
+
+class RubyForge::FakeAgent
+  class << self
+    attr_accessor :t_data, :t_request
+  end
+
+  def initialize(*args)
+  end
+
+  def request(request, data)
+    self.class.t_request = request
+    self.class.t_data = data
+    response = Net::HTTPOK.new('1.1', 200, '')
+    def response.read_body; ''; end
+    return response
+  end
+
+  class Post
+    def initialize(*args)
+      @args = args
+      @stuff = {}
+    end
+
+    def [] key
+      @stuff[key.downcase]
+    end
+
+    def []= key, val
+      @stuff[key.downcase] = val
+    end
+
+    def method_missing(*stuff)
+      # warn stuff.inspect
+    end
+  end
+end
+
+class TestRubyForgeClient < Test::Unit::TestCase
+  def setup
+    @client                        = RubyForge::Client.new
+    @client.agent_class            = RubyForge::FakeAgent
+    RubyForge::FakeAgent.t_data    = :unassigned
+    RubyForge::FakeAgent.t_request = :unassigned
+  end
+
+  def test_post_with_params
+    @client.post_content('http://example.com', { :f => 'adsf aoeu'})
+    assert_equal('f=adsf+aoeu', RubyForge::FakeAgent.t_data)
+
+    @client.post_content('http://example.com', { :a => 'b', :c => 'd' })
+    assert_equal('a=b&c=d', RubyForge::FakeAgent.t_data)
+  end
+
+  def test_multipart_post_one_param
+    random = Array::new(8){ "%2.2d" % rand(42) }.join('__')
+    boundary = "multipart/form-data; boundary=___#{ random }___"
+
+    expected = <<-END
+--___#{random}___\r
+Content-Disposition: form-data; name="a"\r\n\r
+a b c\r
+--___#{random}___--\r
+END
+
+    @client.post_content( 'http://example.com',
+                          { :a => 'a b c' },
+                          { 'content-type' => boundary }
+                        )
+    assert_equal(expected, RubyForge::FakeAgent.t_data)
+  end
+
+  def test_multipart_post_two_params
+    random = Array::new(8){ "%2.2d" % rand(42) }.join('__')
+    boundary = "multipart/form-data; boundary=___#{ random }___"
+
+    request = <<-END
+--___#{random}___\r
+Content-Disposition: form-data; name="a"\r\n\r
+b\r
+--___#{random}___\r
+Content-Disposition: form-data; name="c"\r\n\r
+d\r
+--___#{random}___--\r
+END
+
+    @client.post_content( 'http://example.com',
+                          { :a => 'b', :c => 'd' },
+                          { 'content-type' => boundary }
+                        )
+    assert_equal(request, RubyForge::FakeAgent.t_data)
+  end
+
+  def test_multipart_io
+    random = Array::new(8){ "%2.2d" % rand(42) }.join('__')
+    boundary = "multipart/form-data; boundary=___#{ random }___"
+
+    file_contents = 'blah blah blah'
+    file = StringIO.new(file_contents)
+    class << file
+      def path
+        '/one/two/three.rb'
+      end
+    end
+
+    request = <<-END
+--___#{random}___\r
+Content-Disposition: form-data; name="userfile"; filename="three.rb"\r
+Content-Transfer-Encoding: binary\r
+Content-Type: text/plain\r\n\r
+#{file_contents}\r
+--___#{random}___--\r
+END
+
+    @client.post_content( 'http://example.com',
+                          { :userfile => file },
+                          { 'content-type' => boundary }
+                        )
+    assert_equal(request, RubyForge::FakeAgent.t_data)
+  end
+end

Added: trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test/test_rubyforge_cookie_manager.rb
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test/test_rubyforge_cookie_manager.rb	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/gems/rubyforge-1.0.1/test/test_rubyforge_cookie_manager.rb	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,97 @@
+require 'test/unit' unless defined? $ZENTEST and $ZENTEST
+require 'rubyforge'
+require 'time'
+require 'yaml'
+require 'tempfile'
+
+class TestRubyForgeCookieManager < Test::Unit::TestCase
+  def setup
+    cookie = cookie_string('session_ser', 'zzzzzzzzzzzzzzzzzz')
+    @url      = URI.parse('http://rubyforge.org/account/login.php')
+    @cookie   = WEBrick::Cookie.parse_set_cookie(cookie)
+    @manager  = RubyForge::CookieManager.new
+  end
+
+  def test_empty?
+    manager = RubyForge::CookieManager.new
+    assert(manager.empty?)
+
+    assert_equal(0, manager[URI.parse('http://rubyforge.org/')].length)
+    assert(manager.empty?)
+  end
+
+  def test_add
+    manager = RubyForge::CookieManager.new
+    assert(manager.empty?)
+    manager.add(@url, @cookie)
+    assert(!manager.empty?)
+
+    cookie = manager[@url][@cookie.name]
+    assert cookie
+    assert_equal(@cookie.object_id, cookie.object_id)
+  end
+
+  def test_add_expired_cookie
+    cookie = cookie_string('session_ser', 'zzzz',
+              :expires => (Time.now - 10).strftime('%A, %d-%b-%Y %H:%M:%S %Z'))
+    cookie   = WEBrick::Cookie.parse_set_cookie(cookie)
+
+    manager = RubyForge::CookieManager.new
+    assert(manager.empty?)
+    manager.add(@url, cookie)
+    assert(manager.empty?)
+  end
+
+  def test_marshal
+    @manager.add(@url, @cookie)
+    assert([email protected]?)
+    m = YAML.load(YAML.dump(@manager))
+    assert(!m.empty?)
+  end
+
+  def test_save!
+    tmp = Tempfile.new('cookie_jar')
+    @manager.cookies_file = tmp.path
+    @manager.add(@url, @cookie)
+    @manager.save!
+
+    @manager = RubyForge::CookieManager.load(tmp.path)
+    assert(! @manager.empty?)
+  end
+
+  def test_load_empty_file
+    tmp = Tempfile.new('cookie_jar')
+    manager = RubyForge::CookieManager.load(tmp.path)
+    assert(manager.empty?)
+  end
+
+  def test_load_legacy_file
+    tmp = Tempfile.new('cookie_jar')
+    tmp.write([
+      'https://rubyforge.org/account/login.php',
+      'session_ser',
+      'zzzzzz',
+      '123456',
+      '.rubyforge.org',
+      '/',
+      '13'
+    ].join("\t"))
+    manager = RubyForge::CookieManager.load(tmp.path)
+    assert(manager.empty?)
+  end
+
+  def test_cookies_file=
+    tmp = Tempfile.new('cookie_jar')
+    @manager.cookies_file = tmp.path
+    assert(@manager.empty?)
+  end
+
+  def cookie_string(name, value, options = {})
+    options = {
+      :expires  => (Time.now + 86400).strftime('%A, %d-%b-%Y %H:%M:%S %Z'),
+      :path     => '/',
+      :domain   => '.rubyforge.org',
+    }.merge(options)
+    "#{name}=#{value}; #{options.map { |o| o.join('=') }.join('; ')}"
+  end
+end

Added: trunk/src/main/webapp/WEB-INF/gems/specifications/hoe-1.8.2.gemspec
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/specifications/hoe-1.8.2.gemspec	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/specifications/hoe-1.8.2.gemspec	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,40 @@
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+  s.name = %q{hoe}
+  s.version = "1.8.2"
+
+  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+  s.authors = ["Ryan Davis"]
+  s.date = %q{2008-10-24}
+  s.default_executable = %q{sow}
+  s.description = %q{Hoe is a simple rake/rubygems helper for project Rakefiles. It generates all the usual tasks for projects including rdoc generation, testing, packaging, and deployment.  Tasks Provided:  * announce         - Create news email file and post to rubyforge. * audit            - Run ZenTest against the package. * check_manifest   - Verify the manifest. * clean            - Clean up all the extras. * config_hoe       - Create a fresh ~/.hoerc file. * debug_gem        - Show information about the gem. * default          - Run the default tasks. * deps:email       - Print a contact list for gems dependent on this gem * deps:fetch       - Fetch all the dependent gems of this gem into tarballs * deps:list        - List all the dependent gems of this gem * docs             - Build the docs HTML Files * email            - Generate email announcement file. * gem              - Build the gem file hoe-1.8.0.gem * generate_key     - Generate a key for signing your gems. * install_gem      - Install the package as a gem. * multi            - Run the test suite using multiruby. * package          - Build all the packages * post_blog        - Post announcement to blog. * post_news        - Post announcement to rubyforge. * publish_docs     - Publish RDoc to RubyForge. * release          - Package and upload the release to rubyforge. * ridocs           - Generate ri locally for testing. * tasks            - Generate a list of tasks for doco. * test             - Run the test suite. * test_deps        - Show which test files fail when run alone.  See class rdoc for help. Hint: ri Hoe}
+  s.email = ["ryand-ruby at zenspider.com"]
+  s.executables = ["sow"]
+  s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
+  s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "bin/sow", "lib/hoe.rb", "test/test_hoe.rb"]
+  s.has_rdoc = true
+  s.homepage = %q{http://rubyforge.org/projects/seattlerb/}
+  s.rdoc_options = ["--main", "README.txt"]
+  s.require_paths = ["lib"]
+  s.rubyforge_project = %q{seattlerb}
+  s.rubygems_version = %q{1.3.1}
+  s.summary = %q{Hoe is a simple rake/rubygems helper for project Rakefiles}
+  s.test_files = ["test/test_hoe.rb"]
+
+  if s.respond_to? :specification_version then
+    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+    s.specification_version = 2
+
+    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
+      s.add_runtime_dependency(%q<rubyforge>, [">= 1.0.1"])
+      s.add_runtime_dependency(%q<rake>, [">= 0.8.3"])
+    else
+      s.add_dependency(%q<rubyforge>, [">= 1.0.1"])
+      s.add_dependency(%q<rake>, [">= 0.8.3"])
+    end
+  else
+    s.add_dependency(%q<rubyforge>, [">= 1.0.1"])
+    s.add_dependency(%q<rake>, [">= 0.8.3"])
+  end
+end

Added: trunk/src/main/webapp/WEB-INF/gems/specifications/liquid-1.9.0.gemspec
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/specifications/liquid-1.9.0.gemspec	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/specifications/liquid-1.9.0.gemspec	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,35 @@
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+  s.name = %q{liquid}
+  s.version = "1.9.0"
+
+  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+  s.authors = ["Tobias Luetke"]
+  s.date = %q{2008-05-04}
+  s.description = %q{A secure non evaling end user template engine with aesthetic markup.}
+  s.email = %q{tobi at leetsoft.com}
+  s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
+  s.files = ["CHANGELOG", "History.txt", "MIT-LICENSE", "Manifest.txt", "README.txt", "Rakefile", "example/server/example_servlet.rb", "example/server/liquid_servlet.rb", "example/server/server.rb", "example/server/templates/index.liquid", "example/server/templates/products.liquid", "init.rb", "lib/extras/liquid_view.rb", "lib/liquid.rb", "lib/liquid/block.rb", "lib/liquid/condition.rb", "lib/liquid/context.rb", "lib/liquid/document.rb", "lib/liquid/drop.rb", "lib/liquid/errors.rb", "lib/liquid/extensions.rb", "lib/liquid/file_system.rb", "lib/liquid/htmltags.rb", "lib/liquid/module_ex.rb", "lib/liquid/standardfilters.rb", "lib/liquid/strainer.rb", "lib/liquid/tag.rb", "lib/liquid/tags/assign.rb", "lib/liquid/tags/capture.rb", "lib/liquid/tags/case.rb", "lib/liquid/tags/comment.rb", "lib/liquid/tags/cycle.rb", "lib/liquid/tags/for.rb", "lib/liquid/tags/if.rb", "lib/liquid/tags/ifchanged.rb", "lib/liquid/tags/include.rb", "lib/liquid/tags/unless.rb", "lib/liquid/template.rb", "lib/liquid/variable.rb", "test/block_test.rb", "test/condition_test.rb", "test/context_test.rb", "test/drop_test.rb", "test/error_handling_test.rb", "test/extra/breakpoint.rb", "test/extra/caller.rb", "test/file_system_test.rb", "test/filter_test.rb", "test/helper.rb", "test/html_tag_test.rb", "test/if_else_test.rb", "test/include_tag_test.rb", "test/module_ex_test.rb", "test/output_test.rb", "test/parsing_quirks_test.rb", "test/regexp_test.rb", "test/security_test.rb", "test/standard_filter_test.rb", "test/standard_tag_test.rb", "test/statements_test.rb", "test/strainer_test.rb", "test/template_test.rb", "test/test_helper.rb", "test/unless_else_test.rb", "test/variable_test.rb"]
+  s.has_rdoc = true
+  s.homepage = %q{http://www.liquidmarkup.org}
+  s.rdoc_options = ["--main", "README.txt"]
+  s.require_paths = ["lib"]
+  s.rubyforge_project = %q{liquid}
+  s.rubygems_version = %q{1.3.1}
+  s.summary = %q{A secure non evaling end user template engine with aesthetic markup.}
+  s.test_files = ["test/test_helper.rb"]
+
+  if s.respond_to? :specification_version then
+    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+    s.specification_version = 2
+
+    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
+      s.add_runtime_dependency(%q<hoe>, [">= 1.5.1"])
+    else
+      s.add_dependency(%q<hoe>, [">= 1.5.1"])
+    end
+  else
+    s.add_dependency(%q<hoe>, [">= 1.5.1"])
+  end
+end

Added: trunk/src/main/webapp/WEB-INF/gems/specifications/rubyforge-1.0.1.gemspec
===================================================================
--- trunk/src/main/webapp/WEB-INF/gems/specifications/rubyforge-1.0.1.gemspec	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/WEB-INF/gems/specifications/rubyforge-1.0.1.gemspec	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1,34 @@
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+  s.name = %q{rubyforge}
+  s.version = "1.0.1"
+
+  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+  s.authors = ["Ryan Davis", "Eric Hodel", "Ara T Howard"]
+  s.date = %q{2008-10-22}
+  s.default_executable = %q{rubyforge}
+  s.description = %q{A script which automates a limited set of rubyforge operations.  * Run 'rubyforge help' for complete usage. * Setup: For first time users AND upgrades to 0.4.0: * rubyforge setup (deletes your username and password, so run sparingly!) * edit ~/.rubyforge/user-config.yml * rubyforge config * For all rubyforge upgrades, run 'rubyforge config' to ensure you have latest. * Don't forget to login!  logging in will store a cookie in your .rubyforge directory which expires after a time.  always run the login command before any operation that requires authentication, such as uploading a package.}
+  s.email = ["ryand-ruby at zenspider.com", "drbrain at segment7.net", "ara.t.howard at gmail.com"]
+  s.executables = ["rubyforge"]
+  s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
+  s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "bin/rubyforge", "lib/rubyforge.rb", "lib/rubyforge/client.rb", "lib/rubyforge/cookie_manager.rb", "test/test_rubyforge.rb", "test/test_rubyforge_client.rb", "test/test_rubyforge_cookie_manager.rb"]
+  s.has_rdoc = true
+  s.homepage = %q{http://codeforpeople.rubyforge.org/rubyforge/}
+  s.rdoc_options = ["--main", "README.txt"]
+  s.require_paths = ["lib"]
+  s.rubyforge_project = %q{codeforpeople}
+  s.rubygems_version = %q{1.3.1}
+  s.summary = %q{A script which automates a limited set of rubyforge operations}
+  s.test_files = ["test/test_rubyforge.rb", "test/test_rubyforge_client.rb", "test/test_rubyforge_cookie_manager.rb"]
+
+  if s.respond_to? :specification_version then
+    current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
+    s.specification_version = 2
+
+    if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
+    else
+    end
+  else
+  end
+end

Added: trunk/src/main/webapp/templates
===================================================================
--- trunk/src/main/webapp/templates	2008-12-21 03:55:25 UTC (rev 1009)
+++ trunk/src/main/webapp/templates	2008-12-21 16:12:07 UTC (rev 1010)
@@ -0,0 +1 @@
+link ../rails/publicspace/public/templates/
\ No newline at end of file


Property changes on: trunk/src/main/webapp/templates
___________________________________________________________________
Name: svn:special
   + *




More information about the kune-commits mailing list