<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,4 +1,4 @@
-=== 0.1.0 / 2008-10-15
+=== 0.1.0 / 2008-10-23
 
 * Initial Release
 </diff>
      <filename>History.txt</filename>
    </modified>
    <modified>
      <diff>@@ -58,6 +58,10 @@ no new request is needed.
 Just want to let you know all this. Neoneo is usable but it's more like a
 No Kahuna Information Delivery Bus than a No Kahuna Dragster!
 
+== Etymology
+Neoneo as the hawaiian word for chaos is just what is logical caused by 
+No Kahuna ;)
+
 == LICENSE:
 
 (The MIT License)</diff>
      <filename>README.txt</filename>
    </modified>
    <modified>
      <diff>@@ -6,7 +6,6 @@ module Neoneo
   
   require 'hpricot_extensions'
   require 'utils'
-  require 'conf'
   
   
   BASE_URL    = 'http://nokahuna.com/'
@@ -64,8 +63,8 @@ module Neoneo
       handle_errors(page)
     end
     
-    def post(url)
-      page = super(url)
+    def post(url, options = {})
+      page = super(url, options)
       handle_errors(page)
     end
     
@@ -81,6 +80,8 @@ module Neoneo
     # If the error message does not match any of the specific messages Neoneo
     # tries to catch, a default Neoneo::Error is thrown.
     def handle_errors(page)
+      return page if page.instance_of? WWW::Mechanize::File
+      
       errors = page.search('div#flash.error p').map {|e| e.innerText}
       errors.each do |error|
         case error
@@ -115,7 +116,7 @@ module Neoneo
   # Also there is no way to check the stay logged in option of No Kahuna yet.
   # This is planned for a future version. 
   class User
-    attr_reader :projects
+    attr_reader :projects, :authenticity_token, :agent
   
     def initialize(user, pass)
       @agent = Agent.new
@@ -125,6 +126,7 @@ module Neoneo
       page = @agent.get(&quot;#{BASE_URL}login&quot;)
 
       form = page.forms.first
+      @authenticity_token = form.authenticity_token
       form.login = user
       form.password = pass
 
@@ -138,7 +140,7 @@ module Neoneo
         own_tasks  = project_link.search('span.taskCount').first.children.first.clean.gsub(/^(\d+)\s\//, '\1').to_i
         id         = project_link.attributes['href'].gsub(/^#{PROJECT_URL}(\d+)\/.*$/, '\1')
 
-        @projects &lt;&lt; Project.new(id, name, total_taks, own_tasks, @agent)
+        @projects &lt;&lt; Project.new(id, name, total_taks, own_tasks, self)
       end
     
     end
@@ -152,21 +154,21 @@ module Neoneo
   # a project and can also be used to change the name and description of the
   # project.
   class Project
-    attr_reader   :id, :agent
+    attr_reader   :id, :agent, :user
     attr_accessor :name, :total_tasks, :own_tasks, :description
     
-    def initialize(id, name, total_tasks, own_tasks, agent)
+    def initialize(id, name, total_tasks, own_tasks, user)
       @id                = id
       @name              = name
       @total_tasks_count = total_tasks
       @own_tasks_count   = own_tasks
       
-      @agent             = agent
+      @user              = user
     end
     
     def description
       unless @description
-        page = @agent.get(url)
+        page = user.agent.get(url)
         @description = page.search('div.projectDescription p').last.clean
       end
       @description
@@ -177,23 +179,52 @@ module Neoneo
     end
     
     def categories
-      build_categories!(@agent.get(url('tasks/new'))) unless @categories
+      build_categories!(user.agent.get(url('tasks/new'))) unless @categories
       
       @categories
     end
     
     def members
-      build_members!(@agent.get(url('tasks/new'))) unless @members
+      build_members!(user.agent.get(url('tasks/new'))) unless @members
       
       @members
     end
     
+    # The open tasks of the project
     def tasks
-      build_tasks!(@agent.get(url('tasks?group_by=category'))) unless @tasks
+      build_tasks!(user.agent.get(url('tasks?group_by=category'))) unless @tasks
       
       @tasks
     end
     
+    # The closed tasks of the project
+    #
+    # For technical reasons I decided to devide the tasks into closed and open
+    # ones hoping that nobody really needs the closed ones ;)
+    # The problem is: At the moment the only chance to get an overview of closed
+    # tasks in the No Kahuna interface is to search for 'task'. But then
+    # you get no category information with the tasks. So I decided that it is
+    # more important to have the category information for any task available 
+    # without the need to load a single page for any task which is possible
+    # with the normal task overview and which the tasks method does.
+    # If you really would like to see the closed tasks use this method by be 
+    # aware, that if you access the category of a closed task a new HTTP request
+    # has to made!
+    #
+    # Also watch out for an other pitfall: If you close or reopen a task they
+    # stay in their original array! So if you do
+    #  project.tasks.first.close!
+    # a call to
+    #  project.tasks
+    # just after that would INCLUDE the closed task and if you already had 
+    # called closed_tasks another call to that would NOT INCLUDE the closed 
+    # task! 
+    def closed_tasks
+      build_closed_tasks!(user.agent.get(url('tasks/search?s=task'))) unless @closed_tasks
+      
+      @closed_tasks
+    end
+    
     # Adds a task to a project.
     # The options hash can consist of the following keys:
     #  - :category  =&gt; 'Some Category Name' OR some_category_object
@@ -206,7 +237,7 @@ module Neoneo
     #                  :category =&gt; project.categories.first,
     #                  :notify   =&gt; ['John Doe', project.members.last])
     def add_task(description, options = {})
-      page = @agent.get(url('tasks/new'))
+      page = user.agent.get(url('tasks/new'))
       
       build_categories!(page) unless @categories
       build_members!(page)    unless @members
@@ -225,9 +256,9 @@ module Neoneo
       end
       notifications.compact!
       
-      page = @agent.get(url('tasks/new'))
+      page = user.agent.get(url('tasks/new'))
       form = page.forms.last
-      
+
       form.send('task[body]'.to_sym, description)
       form.send('task[assigned_to_id]'.to_sym, assign_to.id) if assign_to
       form.send('task[category_id]'.to_sym,    category.id) if category
@@ -236,7 +267,7 @@ module Neoneo
         form.add_field!('subscriber_ids[]', notification.id)
       end
       
-      @agent.submit form
+      user.agent.submit form
     end
     
     # Saves the project name and descriptions which you can set simply with
@@ -247,11 +278,11 @@ module Neoneo
     # project.description = 'New description'
     # project.save
     def save
-      page = @agent.get(url('edit'))
+      page = user.agent.get(url('edit'))
       form = page.forms.last
       form.send('project[name]='.to_sym, @name)
       form.send('project[description]='.to_sym, @description) if @description
-      page = @agent.submit form
+      page = user.agent.submit form
 
       raise Error unless page.search('div#flash.notice p').first.clean == 
                         'Successfully saved project'
@@ -302,6 +333,20 @@ module Neoneo
         end
       end
     end
+    
+    def build_closed_tasks!(page)
+      @closed_tasks = SingleSelectArray.new
+      
+      tasks = page.search('div#tasks_for_me ul.search li.done')
+      
+      tasks.each do |task_item|
+        user = Utils::URL.url_unescape(task_item.search('span.avatar a').first.attributes['href'].gsub(/^\/users\//, ''))
+        task_link = task_item.search('a.taskLink')
+        id          = task_link.search('span.taskId').first.clean
+        description = task_link.search('span.taskShortBody').first.clean
+        @closed_tasks &lt;&lt; Task.new(id, description, nil, members.find(user), self, true)
+      end
+    end
   end
   
   # Representation of No Kahuna's categories for tasks
@@ -353,18 +398,19 @@ module Neoneo
   
   # Represents a No Kahuna task
   #
-  # At the moment this class is read-only. So you can't change, close or re-open
-  # a task with Neoneo.
+  # At the moment this class is read-only in regards of it's description.
+  # But you can close or reopen a task.
   # This will be improved as soon as possible!
   class Task
-    attr_reader   :id, :user, :project, :category
+    attr_reader   :id, :user, :project
     
-    def initialize(id, description, category, user, project)
+    def initialize(id, description, category, user, project, done = false)
       @id = id
       @description = description
       @category = category
       @user = user
       @project = project
+      @done = done
       
       @uncertain = @description =~ /\.{3}$/
     end
@@ -374,25 +420,53 @@ module Neoneo
       @description
     end
     
+    def category
+      build_category! unless @category
+      
+      @category
+    end
+    
     def url(appendix = '')
       @project.url(&quot;tasks/#{@id}/#{appendix}&quot;)
     end
     
+    def close!
+      page = @project.user.agent.get(url)
+      form = page.forms.last
+      authenticity_token = form.authenticity_token
+      
+      @project.user.agent.post(url('done'), :authenticity_token =&gt; authenticity_token, '_method'.to_sym =&gt; 'put')
+      @done = true
+    end
+    
+    def reopen!
+      return unless @done
+
+      page = @project.user.agent.get(url)
+      form = page.forms.last
+      authenticity_token = form.authenticity_token
+      
+      @project.user.agent.post(url('not_done'), :authenticity_token =&gt; authenticity_token, '_method'.to_sym =&gt; 'put')
+      @done = false
+    end
+    
+    def closed?
+      @done
+    end
+    
     private
-    def build_description!
-      page = project.agent.get(url('edit'))
+    def build_description!(page = nil)
+      page ||= project.user.agent.get(url('edit'))
       form = page.forms.last
       @description = form.send('task[body]'.to_sym)
       @uncertain = false
     end
+    
+    def build_category!(page = nil)
+      page ||= project.user.agent.get(url('edit'))
+      
+      @category = project.categories.find(page.search('span.category').clear)
+    end
   end
   
 end
-
-# user = Neoneo::User.new('NeoNeo_Test', Pass.pass)
-# project = user.projects.find('NeoNeo')
-# p project.tasks.map {|t| a = []; a &lt;&lt; (t.user ? t.user.name : ''); a &lt;&lt; (t.category ? t.category.name : ''); a}
-# # 
-# # 20.times do 
-# #   project.add_task(&quot;NEONEO Test #{Time.now}&quot;, :assign_to =&gt; project.members[rand(project.members.size)], :category =&gt; 'Trash')
-# # end</diff>
      <filename>lib/neoneo.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,45 +1,4 @@
 require File.join(File.dirname(__FILE__), 'spec_helper')
 
-describe Babylon do
-  it &quot;should raise an Babylon::Error on erroneous Google response&quot; do
-    Babylon.should_receive(:get).and_return({&quot;responseStatus&quot;=&gt;400, &quot;responseDetails&quot;=&gt;nil})
-
-    begin
-      Babylon.language_of(&quot;Text that causes an error&quot;)
-    rescue Babylon::Error
-    else
-      flunk 'Should raise an Babylon::Error'
-    end
-  end
-  
-  it &quot;should raise an Babylon::UncertaintyError if the text can not be clearly determined an reliability is demanded&quot; do
-    Babylon.should_receive(:get).and_return({&quot;responseData&quot;=&gt;{&quot;language&quot;=&gt;&quot;en&quot;, &quot;confidence&quot;=&gt;0.1771214, &quot;isReliable&quot;=&gt;false}, &quot;responseStatus&quot;=&gt;200, &quot;responseDetails&quot;=&gt;nil})
-
-    begin
-      Babylon.language_of(&quot;Undeterminable text&quot;, :ensure_reliability =&gt; true)
-    rescue Babylon::UncertaintyError
-    else
-      flunk 'Should raise an Babylon::UncertaintyError'
-    end
-  end
-  
-  it &quot;should raise no Babylon::UncertaintyError if the certainty equals the demanded one&quot; do
-    Babylon.should_receive(:get).and_return({&quot;responseData&quot;=&gt;{&quot;language&quot;=&gt;&quot;en&quot;, &quot;confidence&quot;=&gt;0.20, &quot;isReliable&quot;=&gt;true}, &quot;responseStatus&quot;=&gt;200, &quot;responseDetails&quot;=&gt;nil})
-    Babylon.language_of(&quot;Undeterminable text&quot;, :min_certainty =&gt; 0.20)
-  end
-  
-  it &quot;should raise no Babylon::UncertaintyError if the certainty is above the demanded one&quot; do
-    Babylon.should_receive(:get).and_return({&quot;responseData&quot;=&gt;{&quot;language&quot;=&gt;&quot;en&quot;, &quot;confidence&quot;=&gt;0.201, &quot;isReliable&quot;=&gt;true}, &quot;responseStatus&quot;=&gt;200, &quot;responseDetails&quot;=&gt;nil})
-    Babylon.language_of(&quot;Undeterminable text&quot;, :min_certainty =&gt; 0.20)
-  end
-
-  it &quot;should raise Babylon::UncertaintyError if the certainty is below the demanded one&quot; do
-    Babylon.should_receive(:get).and_return({&quot;responseData&quot;=&gt;{&quot;language&quot;=&gt;&quot;en&quot;, &quot;confidence&quot;=&gt;0.209, &quot;isReliable&quot;=&gt;true}, &quot;responseStatus&quot;=&gt;200, &quot;responseDetails&quot;=&gt;nil})
-    begin
-      Babylon.language_of(&quot;Undeterminable text&quot;, :min_certainty =&gt; 0.21)
-    rescue Babylon::UncertaintyError
-    else
-      flunk 'Should raise an Babylon::UncertaintyError'
-    end
-  end
+describe Neoneo do
 end</diff>
      <filename>spec/neoneo_spec.rb</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>lib/conf.rb</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>41aa3d7bd85f95458a93e0aa1b9e63bcc1985115</id>
    </parent>
  </parents>
  <author>
    <name>Thorben Schr&#246;der</name>
    <email>thorben.schroeder@gmail.com</email>
  </author>
  <url>http://github.com/walski/neoneo/commit/e8e8494ab0238dd40c974cda8ea827c97d581888</url>
  <id>e8e8494ab0238dd40c974cda8ea827c97d581888</id>
  <committed-date>2008-10-23T03:24:24-07:00</committed-date>
  <authored-date>2008-10-23T03:24:24-07:00</authored-date>
  <message>Closing and reopening tasks is now possible.</message>
  <tree>ff0d1bee722d3754193166335dd95d24682e209a</tree>
  <committer>
    <name>Thorben Schr&#246;der</name>
    <email>thorben.schroeder@gmail.com</email>
  </committer>
</commit>
