<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>vendor/rails/Rakefile</filename>
    </added>
    <added>
      <filename>vendor/rails/pushgems.rb</filename>
    </added>
    <added>
      <filename>vendor/rails/release.rb</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -984,7 +984,6 @@ module ActionController #:nodoc:
       # of sending it as the response body to the browser.
       def render_to_string(options = nil, &amp;block) #:doc:
         render(options, &amp;block)
-        response.body
       ensure
         response.content_type = nil
         erase_render_results
@@ -1021,7 +1020,7 @@ module ActionController #:nodoc:
 
       # Clears the rendered results, allowing for another render to be performed.
       def erase_render_results #:nodoc:
-        response.body = []
+        response.body = nil
         @performed_render = false
       end
 
@@ -1248,12 +1247,13 @@ module ActionController #:nodoc:
         response.status = interpret_status(status || DEFAULT_RENDER_STATUS_CODE)
 
         if append_response
-          response.body_parts &lt;&lt; text.to_s
+          response.body ||= ''
+          response.body &lt;&lt; text.to_s
         else
           response.body = case text
-            when Proc then  text
-            when nil  then  [&quot; &quot;] # Safari doesn't pass the headers of the return if the response is zero length
-            else            [text.to_s]
+            when Proc then text
+            when nil  then &quot; &quot; # Safari doesn't pass the headers of the return if the response is zero length
+            else           text.to_s
           end
         end
       end</diff>
      <filename>vendor/rails/actionpack/lib/action_controller/base.rb</filename>
    </modified>
    <modified>
      <diff>@@ -332,13 +332,11 @@ module ActionController
             @cookies[name] = value
           end
 
+          @body = &quot;&quot;
           if body.is_a?(String)
-            @body_parts = [body]
-            @body = body
+            @body &lt;&lt; body
           else
-            @body_parts = []
-            body.each { |part| @body_parts &lt;&lt; part.to_s }
-            @body = @body_parts.join
+            body.each { |part| @body &lt;&lt; part }
           end
 
           if @controller = ActionController::Base.last_instantiation
@@ -351,7 +349,7 @@ module ActionController
             @response = Response.new
             @response.status = status.to_s
             @response.headers.replace(@headers)
-            @response.body = @body_parts
+            @response.body = @body
           end
 
           # Decorate the response with the standard behavior of the</diff>
      <filename>vendor/rails/actionpack/lib/action_controller/integration.rb</filename>
    </modified>
    <modified>
      <diff>@@ -40,28 +40,14 @@ module ActionController # :nodoc:
     delegate :default_charset, :to =&gt; 'ActionController::Base'
 
     def initialize
-      super
+      @status = 200
       @header = Rack::Utils::HeaderHash.new(DEFAULT_HEADERS)
-      @session, @assigns = [], []
-    end
 
-    def body
-      str = ''
-      each { |part| str &lt;&lt; part.to_s }
-      str
-    end
+      @writer = lambda { |x| @body &lt;&lt; x }
+      @block = nil
 
-    def body=(body)
-      @body =
-        if body.is_a?(String)
-          [body]
-        else
-          body
-        end
-    end
-
-    def body_parts
-      @body
+      @body = &quot;&quot;,
+      @session, @assigns = [], []
     end
 
     def location; headers['Location'] end
@@ -166,7 +152,7 @@ module ActionController # :nodoc:
         @writer = lambda { |x| callback.call(x) }
         @body.call(self, self)
       elsif @body.is_a?(String)
-        callback.call(@body)
+        @body.each_line(&amp;callback)
       else
         @body.each(&amp;callback)
       end
@@ -176,8 +162,7 @@ module ActionController # :nodoc:
     end
 
     def write(str)
-      str = str.to_s
-      @writer.call str
+      @writer.call str.to_s
       str
     end
 
@@ -201,7 +186,7 @@ module ActionController # :nodoc:
 
           if request &amp;&amp; request.etag_matches?(etag)
             self.status = '304 Not Modified'
-            self.body = []
+            self.body = ''
           end
 
           set_conditional_cache_control!
@@ -210,11 +195,7 @@ module ActionController # :nodoc:
 
       def nonempty_ok_response?
         ok = !status || status.to_s[0..2] == '200'
-        ok &amp;&amp; string_body?
-      end
-
-      def string_body?
-        !body_parts.respond_to?(:call) &amp;&amp; body_parts.any? &amp;&amp; body_parts.all? { |part| part.is_a?(String) }
+        ok &amp;&amp; body.is_a?(String) &amp;&amp; !body.empty?
       end
 
       def set_conditional_cache_control!
@@ -235,8 +216,8 @@ module ActionController # :nodoc:
           headers.delete('Content-Length')
         elsif length = headers['Content-Length']
           headers['Content-Length'] = length.to_s
-        elsif string_body? &amp;&amp; (!status || status.to_s[0..2] != '304')
-          headers[&quot;Content-Length&quot;] = Rack::Utils.bytesize(body).to_s
+        elsif !body.respond_to?(:call) &amp;&amp; (!status || status.to_s[0..2] != '304')
+          headers[&quot;Content-Length&quot;] = (body.respond_to?(:bytesize) ? body.bytesize : body.size).to_s
         end
       end
 </diff>
      <filename>vendor/rails/actionpack/lib/action_controller/response.rb</filename>
    </modified>
    <modified>
      <diff>@@ -13,7 +13,6 @@ module ActionController #:nodoc:
 
       @query_parameters   = {}
       @session            = TestSession.new
-      @session_options    ||= {}
 
       initialize_default_values
       initialize_containers
@@ -111,7 +110,6 @@ module ActionController #:nodoc:
     end
 
     def recycle!
-      @env[&quot;action_controller.request.request_parameters&quot;] = {}
       self.query_parameters   = {}
       self.path_parameters    = {}
       @headers, @request_method, @accepts, @content_type = nil, nil, nil, nil
@@ -260,11 +258,11 @@ module ActionController #:nodoc:
 
     # Returns binary content (downloadable file), converted to a String
     def binary_content
-      raise &quot;Response body is not a Proc: #{body_parts.inspect}&quot; unless body_parts.kind_of?(Proc)
+      raise &quot;Response body is not a Proc: #{body.inspect}&quot; unless body.kind_of?(Proc)
       require 'stringio'
 
       sio = StringIO.new
-      body_parts.call(self, sio)
+      body.call(self, sio)
 
       sio.rewind
       sio.read</diff>
      <filename>vendor/rails/actionpack/lib/action_controller/test_process.rb</filename>
    </modified>
    <modified>
      <diff>@@ -303,12 +303,6 @@ module ActionView #:nodoc:
       self.template = last_template
     end
 
-    def punctuate_body!(part)
-      flush_output_buffer
-      response.body_parts &lt;&lt; part
-      nil
-    end
-
     private
       # Evaluates the local assigns and controller ivars, pushes them to the view.
       def _evaluate_assigns_and_ivars #:nodoc:</diff>
      <filename>vendor/rails/actionpack/lib/action_view/base.rb</filename>
    </modified>
    <modified>
      <diff>@@ -131,14 +131,6 @@ module ActionView
       ensure
         self.output_buffer = old_buffer
       end
-
-      # Add the output buffer to the response body and start a new one.
-      def flush_output_buffer #:nodoc:
-        if output_buffer &amp;&amp; output_buffer != ''
-          response.body_parts &lt;&lt; output_buffer
-          self.output_buffer = ''
-        end
-      end
     end
   end
 end</diff>
      <filename>vendor/rails/actionpack/lib/action_view/helpers/capture_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -628,7 +628,7 @@ module ActionView
       #
       # The HTML specification says unchecked check boxes are not successful, and
       # thus web browsers do not send them. Unfortunately this introduces a gotcha:
-      # if an +Invoice+ model has a +paid+ flag, and in the form that edits a paid
+      # if an Invoice model has a +paid+ flag, and in the form that edits a paid
       # invoice the user unchecks its check box, no +paid+ parameter is sent. So,
       # any mass-assignment idiom like
       #
@@ -636,15 +636,12 @@ module ActionView
       #
       # wouldn't update the flag.
       #
-      # To prevent this the helper generates an auxiliary hidden field before
-      # the very check box. The hidden field has the same name and its
-      # attributes mimick an unchecked check box.
-      #
-      # This way, the client either sends only the hidden field (representing
-      # the check box is unchecked), or both fields. Since the HTML specification
-      # says key/value pairs have to be sent in the same order they appear in the
-      # form, and parameters extraction gets the last occurrence of any repeated
-      # key in the query string, that works for ordinary forms.
+      # To prevent this the helper generates a hidden field with the same name as
+      # the checkbox after the very check box. So, the client either sends only the
+      # hidden field (representing the check box is unchecked), or both fields.
+      # Since the HTML specification says key/value pairs have to be sent in the
+      # same order they appear in the form and Rails parameters extraction always
+      # gets the first occurrence of any given key, that works in ordinary forms.
       #
       # Unfortunately that workaround does not work when the check box goes
       # within an array-like parameter, as in
@@ -655,26 +652,22 @@ module ActionView
       #   &lt;% end %&gt;
       #
       # because parameter name repetition is precisely what Rails seeks to distinguish
-      # the elements of the array. For each item with a checked check box you
-      # get an extra ghost item with only that attribute, assigned to &quot;0&quot;.
-      #
-      # In that case it is preferable to either use +check_box_tag+ or to use
-      # hashes instead of arrays.
+      # the elements of the array.
       #
       # ==== Examples
       #   # Let's say that @post.validated? is 1:
       #   check_box(&quot;post&quot;, &quot;validated&quot;)
-      #   # =&gt; &lt;input name=&quot;post[validated]&quot; type=&quot;hidden&quot; value=&quot;0&quot; /&gt;
-      #   #    &lt;input type=&quot;checkbox&quot; id=&quot;post_validated&quot; name=&quot;post[validated]&quot; value=&quot;1&quot; /&gt;
+      #   # =&gt; &lt;input type=&quot;checkbox&quot; id=&quot;post_validated&quot; name=&quot;post[validated]&quot; value=&quot;1&quot; /&gt;
+      #   #    &lt;input name=&quot;post[validated]&quot; type=&quot;hidden&quot; value=&quot;0&quot; /&gt;
       #
       #   # Let's say that @puppy.gooddog is &quot;no&quot;:
       #   check_box(&quot;puppy&quot;, &quot;gooddog&quot;, {}, &quot;yes&quot;, &quot;no&quot;)
-      #   # =&gt; &lt;input name=&quot;puppy[gooddog]&quot; type=&quot;hidden&quot; value=&quot;no&quot; /&gt;
-      #   #    &lt;input type=&quot;checkbox&quot; id=&quot;puppy_gooddog&quot; name=&quot;puppy[gooddog]&quot; value=&quot;yes&quot; /&gt;
+      #   # =&gt; &lt;input type=&quot;checkbox&quot; id=&quot;puppy_gooddog&quot; name=&quot;puppy[gooddog]&quot; value=&quot;yes&quot; /&gt;
+      #   #    &lt;input name=&quot;puppy[gooddog]&quot; type=&quot;hidden&quot; value=&quot;no&quot; /&gt;
       #
       #   check_box(&quot;eula&quot;, &quot;accepted&quot;, { :class =&gt; 'eula_check' }, &quot;yes&quot;, &quot;no&quot;)
-      #   # =&gt; &lt;input name=&quot;eula[accepted]&quot; type=&quot;hidden&quot; value=&quot;no&quot; /&gt;
-      #   #    &lt;input type=&quot;checkbox&quot; class=&quot;eula_check&quot; id=&quot;eula_accepted&quot; name=&quot;eula[accepted]&quot; value=&quot;yes&quot; /&gt;
+      #   # =&gt; &lt;input type=&quot;checkbox&quot; class=&quot;eula_check&quot; id=&quot;eula_accepted&quot; name=&quot;eula[accepted]&quot; value=&quot;yes&quot; /&gt;
+      #   #    &lt;input name=&quot;eula[accepted]&quot; type=&quot;hidden&quot; value=&quot;no&quot; /&gt;
       #
       def check_box(object_name, method, options = {}, checked_value = &quot;1&quot;, unchecked_value = &quot;0&quot;)
         InstanceTag.new(object_name, method, self, options.delete(:object)).to_check_box_tag(options, checked_value, unchecked_value)</diff>
      <filename>vendor/rails/actionpack/lib/action_view/helpers/form_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -324,7 +324,7 @@ module ActionView
 
       # Turns all URLs and e-mail addresses into clickable links. The &lt;tt&gt;:link&lt;/tt&gt; option
       # will limit what should be linked. You can add HTML attributes to the links using
-      # &lt;tt&gt;:html&lt;/tt&gt;. Possible values for &lt;tt&gt;:link&lt;/tt&gt; are &lt;tt&gt;:all&lt;/tt&gt; (default),
+      # &lt;tt&gt;:href_options&lt;/tt&gt;. Possible values for &lt;tt&gt;:link&lt;/tt&gt; are &lt;tt&gt;:all&lt;/tt&gt; (default),
       # &lt;tt&gt;:email_addresses&lt;/tt&gt;, and &lt;tt&gt;:urls&lt;/tt&gt;. If a block is given, each URL and
       # e-mail address is yielded and the result is used as the link text.
       #
@@ -341,7 +341,7 @@ module ActionView
       #   # =&gt; &quot;Visit http://www.loudthinking.com/ or e-mail &lt;a href=\&quot;mailto:david@loudthinking.com\&quot;&gt;david@loudthinking.com&lt;/a&gt;&quot;
       #
       #   post_body = &quot;Welcome to my new blog at http://www.myblog.com/.  Please e-mail me at me@email.com.&quot;
-      #   auto_link(post_body, :html =&gt; { :target =&gt; '_blank' }) do |text|
+      #   auto_link(post_body, :href_options =&gt; { :target =&gt; '_blank' }) do |text|
       #     truncate(text, 15)
       #   end
       #   # =&gt; &quot;Welcome to my new blog at &lt;a href=\&quot;http://www.myblog.com/\&quot; target=\&quot;_blank\&quot;&gt;http://www.m...&lt;/a&gt;.
@@ -359,7 +359,7 @@ module ActionView
       #   auto_link(post_body, :all, :target =&gt; &quot;_blank&quot;)     # =&gt; Once upon\na time
       #   # =&gt; &quot;Welcome to my new blog at &lt;a href=\&quot;http://www.myblog.com/\&quot; target=\&quot;_blank\&quot;&gt;http://www.myblog.com&lt;/a&gt;.
       #         Please e-mail me at &lt;a href=\&quot;mailto:me@email.com\&quot;&gt;me@email.com&lt;/a&gt;.&quot;
-      def auto_link(text, *args, &amp;block)#link = :all, html = {}, &amp;block)
+      def auto_link(text, *args, &amp;block)#link = :all, href_options = {}, &amp;block)
         return '' if text.blank?
 
         options = args.size == 2 ? {} : args.extract_options! # this is necessary because the old auto_link API has a Hash as its last parameter</diff>
      <filename>vendor/rails/actionpack/lib/action_view/helpers/text_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -61,7 +61,7 @@ module ActionView #:nodoc:
         end
       end
 
-      return Template.new(original_template_path) if File.file?(original_template_path)
+      return Template.new(original_template_path, original_template_path.to_s =~ /\A\// ? &quot;&quot; : &quot;.&quot;) if File.file?(original_template_path)
 
       raise MissingTemplate.new(self, original_template_path, format)
     end</diff>
      <filename>vendor/rails/actionpack/lib/action_view/paths.rb</filename>
    </modified>
    <modified>
      <diff>@@ -107,8 +107,9 @@ module ActionView #:nodoc:
     attr_accessor :locale, :name, :format, :extension
     delegate :to_s, :to =&gt; :path
 
-    def initialize(template_path, load_path = nil)
-      @template_path, @load_path = template_path.dup, load_path
+    def initialize(template_path, load_path)
+      @template_path = template_path.dup
+      @load_path, @filename = load_path, File.join(load_path, template_path)
       @base_path, @name, @locale, @format, @extension = split(template_path)
       @base_path.to_s.gsub!(/\/$/, '') # Push to split method
 
@@ -179,12 +180,6 @@ module ActionView #:nodoc:
       @@exempt_from_layout.any? { |exempted| path =~ exempted }
     end
 
-    def filename
-      # no load_path means this is an &quot;absolute pathed&quot; template
-      load_path ? File.join(load_path, template_path) : template_path
-    end
-    memoize :filename
-
     def source
       File.read(filename)
     end
@@ -217,30 +212,46 @@ module ActionView #:nodoc:
       end
 
       def valid_locale?(locale)
-        locale &amp;&amp; I18n.available_locales.include?(locale.to_sym)
+        I18n.available_locales.include?(locale.to_sym)
       end
 
       # Returns file split into an array
       #   [base_path, name, locale, format, extension]
       def split(file)
         if m = file.to_s.match(/^(.*\/)?([^\.]+)\.(.*)$/)
-          [m[1], m[2], *parse_extensions(m[3])]
+          base_path = m[1]
+          name = m[2]
+          extensions = m[3]
+        else
+          return
         end
-      end
-
-      # returns parsed extensions as an array
-      #   [locale, format, extension]
-      def parse_extensions(extensions)
-        exts = extensions.split(&quot;.&quot;)
 
-        if extension = valid_extension?(exts.last) &amp;&amp; exts.pop || nil
-          locale = valid_locale?(exts.first) &amp;&amp; exts.shift || nil
-          format = exts.join('.') if exts.any? # join('.') is needed for multipart templates
-        else # no extension, just format
-          format = exts.last
+        locale = nil
+        format = nil
+        extension = nil
+
+        if m = extensions.split(&quot;.&quot;)
+          if valid_locale?(m[0]) &amp;&amp; m[1] &amp;&amp; valid_extension?(m[2]) # All three
+            locale = m[0]
+            format = m[1]
+            extension = m[2]
+          elsif m[0] &amp;&amp; m[1] &amp;&amp; valid_extension?(m[2]) # Multipart formats
+            format = &quot;#{m[0]}.#{m[1]}&quot;
+            extension = m[2]
+          elsif valid_locale?(m[0]) &amp;&amp; valid_extension?(m[1]) # locale and extension
+            locale = m[0]
+            extension = m[1]
+          elsif valid_extension?(m[1]) # format and extension
+            format = m[0]
+            extension = m[1]
+          elsif valid_extension?(m[0]) # Just extension
+            extension = m[0]
+          else # No extension
+            format = m[0]
+          end
         end
 
-        [locale, format, extension]
+        [base_path, name, locale, format, extension]
       end
   end
 end</diff>
      <filename>vendor/rails/actionpack/lib/action_view/template.rb</filename>
    </modified>
    <modified>
      <diff>@@ -258,7 +258,7 @@ class RackResponseTest &lt; BaseRackTest
     }, headers)
 
     parts = []
-    body.each { |part| parts &lt;&lt; part.to_s }
+    body.each { |part| parts &lt;&lt; part }
     assert_equal [&quot;0&quot;, &quot;1&quot;, &quot;2&quot;, &quot;3&quot;, &quot;4&quot;], parts
   end
 end</diff>
      <filename>vendor/rails/actionpack/test/controller/rack_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -3,6 +3,7 @@ require 'abstract_unit'
 class RequestTest &lt; ActiveSupport::TestCase
   def setup
     ActionController::Base.relative_url_root = nil
+    @request = ActionController::TestRequest.new
   end
 
   def teardown
@@ -10,52 +11,60 @@ class RequestTest &lt; ActiveSupport::TestCase
   end
 
   def test_remote_ip
-    request = stub_request 'REMOTE_ADDR' =&gt; '1.2.3.4'
-    assert_equal '1.2.3.4', request.remote_ip
+    assert_equal '0.0.0.0', @request.remote_ip
 
-    request = stub_request 'REMOTE_ADDR' =&gt; '1.2.3.4,3.4.5.6'
-    assert_equal '1.2.3.4', request.remote_ip
+    @request.remote_addr = '1.2.3.4'
+    assert_equal '1.2.3.4', @request.remote_ip
 
-    request = stub_request 'REMOTE_ADDR' =&gt; '1.2.3.4',
-      'HTTP_X_FORWARDED_FOR' =&gt; '3.4.5.6'
-    assert_equal '1.2.3.4', request.remote_ip
+    @request.remote_addr = '1.2.3.4,3.4.5.6'
+    assert_equal '1.2.3.4', @request.remote_ip
 
-    request = stub_request 'REMOTE_ADDR' =&gt; '127.0.0.1',
-      'HTTP_X_FORWARDED_FOR' =&gt; '3.4.5.6'
-    assert_equal '3.4.5.6', request.remote_ip
+    @request.env['HTTP_CLIENT_IP'] = '2.3.4.5'
+    assert_equal '1.2.3.4', @request.remote_ip
 
-    request = stub_request 'HTTP_X_FORWARDED_FOR' =&gt; 'unknown,3.4.5.6'
-    assert_equal '3.4.5.6', request.remote_ip
+    @request.remote_addr = '192.168.0.1'
+    assert_equal '2.3.4.5', @request.remote_ip
+    @request.env.delete 'HTTP_CLIENT_IP'
 
-    request = stub_request 'HTTP_X_FORWARDED_FOR' =&gt; '172.16.0.1,3.4.5.6'
-    assert_equal '3.4.5.6', request.remote_ip
+    @request.remote_addr = '1.2.3.4'
+    @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6'
+    assert_equal '1.2.3.4', @request.remote_ip
 
-    request = stub_request 'HTTP_X_FORWARDED_FOR' =&gt; '192.168.0.1,3.4.5.6'
-    assert_equal '3.4.5.6', request.remote_ip
+    @request.remote_addr = '127.0.0.1'
+    @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6'
+    assert_equal '3.4.5.6', @request.remote_ip
 
-    request = stub_request 'HTTP_X_FORWARDED_FOR' =&gt; '10.0.0.1,3.4.5.6'
-    assert_equal '3.4.5.6', request.remote_ip
+    @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,3.4.5.6'
+    assert_equal '3.4.5.6', @request.remote_ip
 
-    request = stub_request 'HTTP_X_FORWARDED_FOR' =&gt; '10.0.0.1, 10.0.0.1, 3.4.5.6'
-    assert_equal '3.4.5.6', request.remote_ip
+    @request.env['HTTP_X_FORWARDED_FOR'] = '172.16.0.1,3.4.5.6'
+    assert_equal '3.4.5.6', @request.remote_ip
 
-    request = stub_request 'HTTP_X_FORWARDED_FOR' =&gt; '127.0.0.1,3.4.5.6'
-    assert_equal '3.4.5.6', request.remote_ip
+    @request.env['HTTP_X_FORWARDED_FOR'] = '192.168.0.1,3.4.5.6'
+    assert_equal '3.4.5.6', @request.remote_ip
 
-    request = stub_request 'HTTP_X_FORWARDED_FOR' =&gt; 'unknown,192.168.0.1'
-    assert_equal 'unknown', request.remote_ip
+    @request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1,3.4.5.6'
+    assert_equal '3.4.5.6', @request.remote_ip
 
-    request = stub_request 'HTTP_X_FORWARDED_FOR' =&gt; '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4'
-    assert_equal '3.4.5.6', request.remote_ip
+    @request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1, 10.0.0.1, 3.4.5.6'
+    assert_equal '3.4.5.6', @request.remote_ip
 
-    request = stub_request 'HTTP_X_FORWARDED_FOR' =&gt; '1.1.1.1',
-                           'HTTP_CLIENT_IP'       =&gt; '2.2.2.2'
+    @request.env['HTTP_X_FORWARDED_FOR'] = '127.0.0.1,3.4.5.6'
+    assert_equal '3.4.5.6', @request.remote_ip
+
+    @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,192.168.0.1'
+    assert_equal 'unknown', @request.remote_ip
+
+    @request.env['HTTP_X_FORWARDED_FOR'] = '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4'
+    assert_equal '3.4.5.6', @request.remote_ip
+
+    @request.env['HTTP_CLIENT_IP'] = '8.8.8.8'
     e = assert_raise(ActionController::ActionControllerError) {
-      request.remote_ip
+      @request.remote_ip
     }
     assert_match /IP spoofing attack/, e.message
-    assert_match /HTTP_X_FORWARDED_FOR=&quot;1.1.1.1&quot;/, e.message
-    assert_match /HTTP_CLIENT_IP=&quot;2.2.2.2&quot;/, e.message
+    assert_match /HTTP_X_FORWARDED_FOR=&quot;9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4&quot;/, e.message
+    assert_match /HTTP_CLIENT_IP=&quot;8.8.8.8&quot;/, e.message
 
     # turn IP Spoofing detection off.
     # This is useful for sites that are aimed at non-IP clients.  The typical
@@ -63,333 +72,336 @@ class RequestTest &lt; ActiveSupport::TestCase
     # leap of faith to assume that their proxies are ever going to set the
     # HTTP_CLIENT_IP/HTTP_X_FORWARDED_FOR headers properly.
     ActionController::Base.ip_spoofing_check = false
-    request = stub_request 'HTTP_X_FORWARDED_FOR' =&gt; '1.1.1.1',
-                           'HTTP_CLIENT_IP'       =&gt; '2.2.2.2'
-    assert_equal '2.2.2.2', request.remote_ip
+    assert_equal('8.8.8.8', @request.remote_ip)
     ActionController::Base.ip_spoofing_check = true
 
-    request = stub_request 'HTTP_X_FORWARDED_FOR' =&gt; '8.8.8.8, 9.9.9.9'
-    assert_equal '9.9.9.9', request.remote_ip
+    @request.env['HTTP_X_FORWARDED_FOR'] = '8.8.8.8, 9.9.9.9'
+    assert_equal '8.8.8.8', @request.remote_ip
+
+    @request.env.delete 'HTTP_CLIENT_IP'
+    @request.env.delete 'HTTP_X_FORWARDED_FOR'
   end
 
   def test_domains
-    request = stub_request 'HTTP_HOST' =&gt; 'www.rubyonrails.org'
-    assert_equal &quot;rubyonrails.org&quot;, request.domain
+    @request.host = &quot;www.rubyonrails.org&quot;
+    assert_equal &quot;rubyonrails.org&quot;, @request.domain
+
+    @request.host = &quot;www.rubyonrails.co.uk&quot;
+    assert_equal &quot;rubyonrails.co.uk&quot;, @request.domain(2)
 
-    request = stub_request 'HTTP_HOST' =&gt; &quot;www.rubyonrails.co.uk&quot;
-    assert_equal &quot;rubyonrails.co.uk&quot;, request.domain(2)
+    @request.host = &quot;192.168.1.200&quot;
+    assert_nil @request.domain
 
-    request = stub_request 'HTTP_HOST' =&gt; &quot;192.168.1.200&quot;
-    assert_nil request.domain
+    @request.host = &quot;foo.192.168.1.200&quot;
+    assert_nil @request.domain
 
-    request = stub_request 'HTTP_HOST' =&gt; &quot;foo.192.168.1.200&quot;
-    assert_nil request.domain
+    @request.host = &quot;192.168.1.200.com&quot;
+    assert_equal &quot;200.com&quot;, @request.domain
 
-    request = stub_request 'HTTP_HOST' =&gt; &quot;192.168.1.200.com&quot;
-    assert_equal &quot;200.com&quot;, request.domain
+    @request.host = nil
+    assert_nil @request.domain
   end
 
   def test_subdomains
-    request = stub_request 'HTTP_HOST' =&gt; &quot;www.rubyonrails.org&quot;
-    assert_equal %w( www ), request.subdomains
+    @request.host = &quot;www.rubyonrails.org&quot;
+    assert_equal %w( www ), @request.subdomains
 
-    request = stub_request 'HTTP_HOST' =&gt; &quot;www.rubyonrails.co.uk&quot;
-    assert_equal %w( www ), request.subdomains(2)
+    @request.host = &quot;www.rubyonrails.co.uk&quot;
+    assert_equal %w( www ), @request.subdomains(2)
 
-    request = stub_request 'HTTP_HOST' =&gt; &quot;dev.www.rubyonrails.co.uk&quot;
-    assert_equal %w( dev www ), request.subdomains(2)
+    @request.host = &quot;dev.www.rubyonrails.co.uk&quot;
+    assert_equal %w( dev www ), @request.subdomains(2)
 
-    request = stub_request 'HTTP_HOST' =&gt; &quot;foobar.foobar.com&quot;
-    assert_equal %w( foobar ), request.subdomains
+    @request.host = &quot;foobar.foobar.com&quot;
+    assert_equal %w( foobar ), @request.subdomains
 
-    request = stub_request 'HTTP_HOST' =&gt; &quot;192.168.1.200&quot;
-    assert_equal [], request.subdomains
+    @request.host = &quot;192.168.1.200&quot;
+    assert_equal [], @request.subdomains
 
-    request = stub_request 'HTTP_HOST' =&gt; &quot;foo.192.168.1.200&quot;
-    assert_equal [], request.subdomains
+    @request.host = &quot;foo.192.168.1.200&quot;
+    assert_equal [], @request.subdomains
 
-    request = stub_request 'HTTP_HOST' =&gt; &quot;192.168.1.200.com&quot;
-    assert_equal %w( 192 168 1 ), request.subdomains
+    @request.host = &quot;192.168.1.200.com&quot;
+    assert_equal %w( 192 168 1 ), @request.subdomains
 
-    request = stub_request 'HTTP_HOST' =&gt; nil
-    assert_equal [], request.subdomains
+    @request.host = nil
+    assert_equal [], @request.subdomains
   end
 
   def test_port_string
-    request = stub_request 'HTTP_HOST' =&gt; 'www.example.org:80'
-    assert_equal &quot;&quot;, request.port_string
+    @request.port = 80
+    assert_equal &quot;&quot;, @request.port_string
 
-    request = stub_request 'HTTP_HOST' =&gt; 'www.example.org:8080'
-    assert_equal &quot;:8080&quot;, request.port_string
+    @request.port = 8080
+    assert_equal &quot;:8080&quot;, @request.port_string
   end
 
   def test_request_uri
-    request = stub_request 'REQUEST_URI' =&gt; &quot;http://www.rubyonrails.org/path/of/some/uri?mapped=1&quot;
-    assert_equal &quot;/path/of/some/uri?mapped=1&quot;, request.request_uri
-    assert_equal &quot;/path/of/some/uri&quot;,          request.path
+    @request.env['SERVER_SOFTWARE'] = 'Apache 42.342.3432'
 
-    request = stub_request 'REQUEST_URI' =&gt; &quot;http://www.rubyonrails.org/path/of/some/uri&quot;
-    assert_equal &quot;/path/of/some/uri&quot;, request.request_uri
-    assert_equal &quot;/path/of/some/uri&quot;, request.path
+    @request.set_REQUEST_URI &quot;http://www.rubyonrails.org/path/of/some/uri?mapped=1&quot;
+    assert_equal &quot;/path/of/some/uri?mapped=1&quot;, @request.request_uri
+    assert_equal &quot;/path/of/some/uri&quot;, @request.path
 
-    request = stub_request 'REQUEST_URI' =&gt; &quot;/path/of/some/uri&quot;
-    assert_equal &quot;/path/of/some/uri&quot;, request.request_uri
-    assert_equal &quot;/path/of/some/uri&quot;, request.path
+    @request.set_REQUEST_URI &quot;http://www.rubyonrails.org/path/of/some/uri&quot;
+    assert_equal &quot;/path/of/some/uri&quot;, @request.request_uri
+    assert_equal &quot;/path/of/some/uri&quot;, @request.path
 
-    request = stub_request 'REQUEST_URI' =&gt; &quot;/&quot;
-    assert_equal &quot;/&quot;, request.request_uri
-    assert_equal &quot;/&quot;, request.path
+    @request.set_REQUEST_URI &quot;/path/of/some/uri&quot;
+    assert_equal &quot;/path/of/some/uri&quot;, @request.request_uri
+    assert_equal &quot;/path/of/some/uri&quot;, @request.path
 
-    request = stub_request 'REQUEST_URI' =&gt; &quot;/?m=b&quot;
-    assert_equal &quot;/?m=b&quot;, request.request_uri
-    assert_equal &quot;/&quot;,     request.path
+    @request.set_REQUEST_URI &quot;/&quot;
+    assert_equal &quot;/&quot;, @request.request_uri
+    assert_equal &quot;/&quot;, @request.path
 
-    request = stub_request 'REQUEST_URI' =&gt; &quot;/&quot;, 'SCRIPT_NAME' =&gt; '/dispatch.cgi'
-    assert_equal &quot;/&quot;, request.request_uri
-    assert_equal &quot;/&quot;, request.path
+    @request.set_REQUEST_URI &quot;/?m=b&quot;
+    assert_equal &quot;/?m=b&quot;, @request.request_uri
+    assert_equal &quot;/&quot;, @request.path
+
+    @request.set_REQUEST_URI &quot;/&quot;
+    @request.env['SCRIPT_NAME'] = &quot;/dispatch.cgi&quot;
+    assert_equal &quot;/&quot;, @request.request_uri
+    assert_equal &quot;/&quot;, @request.path
 
     ActionController::Base.relative_url_root = &quot;/hieraki&quot;
-    request = stub_request 'REQUEST_URI' =&gt; &quot;/hieraki/&quot;, 'SCRIPT_NAME' =&gt; &quot;/hieraki/dispatch.cgi&quot;
-    assert_equal &quot;/hieraki/&quot;, request.request_uri
-    assert_equal &quot;/&quot;,         request.path
+    @request.set_REQUEST_URI &quot;/hieraki/&quot;
+    @request.env['SCRIPT_NAME'] = &quot;/hieraki/dispatch.cgi&quot;
+    assert_equal &quot;/hieraki/&quot;, @request.request_uri
+    assert_equal &quot;/&quot;, @request.path
     ActionController::Base.relative_url_root = nil
 
     ActionController::Base.relative_url_root = &quot;/collaboration/hieraki&quot;
-    request = stub_request 'REQUEST_URI' =&gt; &quot;/collaboration/hieraki/books/edit/2&quot;,
-      'SCRIPT_NAME' =&gt; &quot;/collaboration/hieraki/dispatch.cgi&quot;
-    assert_equal &quot;/collaboration/hieraki/books/edit/2&quot;, request.request_uri
-    assert_equal &quot;/books/edit/2&quot;,                       request.path
+    @request.set_REQUEST_URI &quot;/collaboration/hieraki/books/edit/2&quot;
+    @request.env['SCRIPT_NAME'] = &quot;/collaboration/hieraki/dispatch.cgi&quot;
+    assert_equal &quot;/collaboration/hieraki/books/edit/2&quot;, @request.request_uri
+    assert_equal &quot;/books/edit/2&quot;, @request.path
     ActionController::Base.relative_url_root = nil
 
     # The following tests are for when REQUEST_URI is not supplied (as in IIS)
-    request = stub_request 'PATH_INFO'   =&gt; &quot;/path/of/some/uri?mapped=1&quot;,
-                           'SCRIPT_NAME' =&gt; nil,
-                           'REQUEST_URI' =&gt; nil
-    assert_equal &quot;/path/of/some/uri?mapped=1&quot;, request.request_uri
-    assert_equal &quot;/path/of/some/uri&quot;,          request.path
+    @request.env['PATH_INFO'] = &quot;/path/of/some/uri?mapped=1&quot;
+    @request.env['SCRIPT_NAME'] = nil #&quot;/path/dispatch.rb&quot;
+    @request.set_REQUEST_URI nil
+    assert_equal &quot;/path/of/some/uri?mapped=1&quot;, @request.request_uri
+    assert_equal &quot;/path/of/some/uri&quot;, @request.path
 
     ActionController::Base.relative_url_root = '/path'
-    request = stub_request 'PATH_INFO'   =&gt; &quot;/path/of/some/uri?mapped=1&quot;,
-                           'SCRIPT_NAME' =&gt; &quot;/path/dispatch.rb&quot;,
-                           'REQUEST_URI' =&gt; nil
-    assert_equal &quot;/path/of/some/uri?mapped=1&quot;, request.request_uri
-    assert_equal &quot;/of/some/uri&quot;,               request.path
+    @request.env['PATH_INFO'] = &quot;/path/of/some/uri?mapped=1&quot;
+    @request.env['SCRIPT_NAME'] = &quot;/path/dispatch.rb&quot;
+    @request.set_REQUEST_URI nil
+    assert_equal &quot;/path/of/some/uri?mapped=1&quot;, @request.request_uri
+    assert_equal &quot;/of/some/uri&quot;, @request.path
     ActionController::Base.relative_url_root = nil
 
-    request = stub_request 'PATH_INFO'   =&gt; &quot;/path/of/some/uri&quot;,
-                           'SCRIPT_NAME' =&gt; nil,
-                           'REQUEST_URI' =&gt; nil
-    assert_equal &quot;/path/of/some/uri&quot;, request.request_uri
-    assert_equal &quot;/path/of/some/uri&quot;, request.path
+    @request.env['PATH_INFO'] = &quot;/path/of/some/uri&quot;
+    @request.env['SCRIPT_NAME'] = nil
+    @request.set_REQUEST_URI nil
+    assert_equal &quot;/path/of/some/uri&quot;, @request.request_uri
+    assert_equal &quot;/path/of/some/uri&quot;, @request.path
 
-    request = stub_request 'PATH_INFO' =&gt; '/', 'REQUEST_URI' =&gt; nil
-    assert_equal &quot;/&quot;, request.request_uri
-    assert_equal &quot;/&quot;, request.path
+    @request.env['PATH_INFO'] = &quot;/&quot;
+    @request.set_REQUEST_URI nil
+    assert_equal &quot;/&quot;, @request.request_uri
+    assert_equal &quot;/&quot;, @request.path
 
-    request = stub_request 'PATH_INFO' =&gt; '/?m=b', 'REQUEST_URI' =&gt; nil
-    assert_equal &quot;/?m=b&quot;, request.request_uri
-    assert_equal &quot;/&quot;,     request.path
+    @request.env['PATH_INFO'] = &quot;/?m=b&quot;
+    @request.set_REQUEST_URI nil
+    assert_equal &quot;/?m=b&quot;, @request.request_uri
+    assert_equal &quot;/&quot;, @request.path
 
-    request = stub_request 'PATH_INFO'   =&gt; &quot;/&quot;,
-                           'SCRIPT_NAME' =&gt; &quot;/dispatch.cgi&quot;,
-                           'REQUEST_URI' =&gt; nil
-    assert_equal &quot;/&quot;, request.request_uri
-    assert_equal &quot;/&quot;, request.path
+    @request.env['PATH_INFO'] = &quot;/&quot;
+    @request.env['SCRIPT_NAME'] = &quot;/dispatch.cgi&quot;
+    @request.set_REQUEST_URI nil
+    assert_equal &quot;/&quot;, @request.request_uri
+    assert_equal &quot;/&quot;, @request.path
 
     ActionController::Base.relative_url_root = '/hieraki'
-    request = stub_request 'PATH_INFO'   =&gt; &quot;/hieraki/&quot;,
-                           'SCRIPT_NAME' =&gt; &quot;/hieraki/dispatch.cgi&quot;,
-                           'REQUEST_URI' =&gt; nil
-    assert_equal &quot;/hieraki/&quot;, request.request_uri
-    assert_equal &quot;/&quot;,         request.path
+    @request.env['PATH_INFO'] = &quot;/hieraki/&quot;
+    @request.env['SCRIPT_NAME'] = &quot;/hieraki/dispatch.cgi&quot;
+    @request.set_REQUEST_URI nil
+    assert_equal &quot;/hieraki/&quot;, @request.request_uri
+    assert_equal &quot;/&quot;, @request.path
     ActionController::Base.relative_url_root = nil
 
-    request = stub_request 'REQUEST_URI' =&gt; '/hieraki/dispatch.cgi'
+    @request.set_REQUEST_URI '/hieraki/dispatch.cgi'
     ActionController::Base.relative_url_root = '/hieraki'
-    assert_equal &quot;/dispatch.cgi&quot;, request.path
+    assert_equal &quot;/dispatch.cgi&quot;, @request.path
     ActionController::Base.relative_url_root = nil
 
-    request = stub_request 'REQUEST_URI' =&gt; '/hieraki/dispatch.cgi'
+    @request.set_REQUEST_URI '/hieraki/dispatch.cgi'
     ActionController::Base.relative_url_root = '/foo'
-    assert_equal &quot;/hieraki/dispatch.cgi&quot;, request.path
+    assert_equal &quot;/hieraki/dispatch.cgi&quot;, @request.path
     ActionController::Base.relative_url_root = nil
 
     # This test ensures that Rails uses REQUEST_URI over PATH_INFO
     ActionController::Base.relative_url_root = nil
-    request = stub_request 'REQUEST_URI' =&gt; &quot;/some/path&quot;,
-                           'PATH_INFO'   =&gt; &quot;/another/path&quot;,
-                           'SCRIPT_NAME' =&gt; &quot;/dispatch.cgi&quot;
-    assert_equal &quot;/some/path&quot;, request.request_uri
-    assert_equal &quot;/some/path&quot;, request.path
+    @request.env['REQUEST_URI'] = &quot;/some/path&quot;
+    @request.env['PATH_INFO'] = &quot;/another/path&quot;
+    @request.env['SCRIPT_NAME'] = &quot;/dispatch.cgi&quot;
+    assert_equal &quot;/some/path&quot;, @request.request_uri
+    assert_equal &quot;/some/path&quot;, @request.path
   end
 
   def test_host_with_default_port
-    request = stub_request 'HTTP_HOST' =&gt; 'rubyonrails.org:80'
-    assert_equal &quot;rubyonrails.org&quot;, request.host_with_port
+    @request.host = &quot;rubyonrails.org&quot;
+    @request.port = 80
+    assert_equal &quot;rubyonrails.org&quot;, @request.host_with_port
   end
 
   def test_host_with_non_default_port
-    request = stub_request 'HTTP_HOST' =&gt; 'rubyonrails.org:81'
-    assert_equal &quot;rubyonrails.org:81&quot;, request.host_with_port
+    @request.host = &quot;rubyonrails.org&quot;
+    @request.port = 81
+    assert_equal &quot;rubyonrails.org:81&quot;, @request.host_with_port
   end
 
   def test_server_software
-    request = stub_request
-    assert_equal nil, request.server_software
+    assert_equal nil, @request.server_software
 
-    request = stub_request 'SERVER_SOFTWARE' =&gt; 'Apache3.422'
-    assert_equal 'apache', request.server_software
+    @request.env['SERVER_SOFTWARE'] = 'Apache3.422'
+    assert_equal 'apache', @request.server_software
 
-    request = stub_request 'SERVER_SOFTWARE' =&gt; 'lighttpd(1.1.4)'
-    assert_equal 'lighttpd', request.server_software
+    @request.env['SERVER_SOFTWARE'] = 'lighttpd(1.1.4)'
+    assert_equal 'lighttpd', @request.server_software
   end
 
   def test_xml_http_request
-    request = stub_request
-
-    assert !request.xml_http_request?
-    assert !request.xhr?
+    assert !@request.xml_http_request?
+    assert !@request.xhr?
 
-    request = stub_request 'HTTP_X_REQUESTED_WITH' =&gt; 'DefinitelyNotAjax1.0'
-    assert !request.xml_http_request?
-    assert !request.xhr?
+    @request.env['HTTP_X_REQUESTED_WITH'] = &quot;DefinitelyNotAjax1.0&quot;
+    assert !@request.xml_http_request?
+    assert !@request.xhr?
 
-    request = stub_request 'HTTP_X_REQUESTED_WITH' =&gt; 'XMLHttpRequest'
-    assert request.xml_http_request?
-    assert request.xhr?
+    @request.env['HTTP_X_REQUESTED_WITH'] = &quot;XMLHttpRequest&quot;
+    assert @request.xml_http_request?
+    assert @request.xhr?
   end
 
   def test_reports_ssl
-    request = stub_request
-    assert !request.ssl?
-
-    request = stub_request 'HTTPS' =&gt; 'on'
-    assert request.ssl?
+    assert !@request.ssl?
+    @request.env['HTTPS'] = 'on'
+    assert @request.ssl?
   end
 
   def test_reports_ssl_when_proxied_via_lighttpd
-    request = stub_request
-    assert !request.ssl?
-
-    request = stub_request 'HTTP_X_FORWARDED_PROTO' =&gt; 'https'
-    assert request.ssl?
+    assert !@request.ssl?
+    @request.env['HTTP_X_FORWARDED_PROTO'] = 'https'
+    assert @request.ssl?
   end
 
   def test_symbolized_request_methods
     [:get, :post, :put, :delete].each do |method|
-      request = stub_request 'REQUEST_METHOD' =&gt; method.to_s.upcase
-      assert_equal method, request.method
+      self.request_method = method
+      assert_equal method, @request.method
     end
   end
 
   def test_invalid_http_method_raises_exception
     assert_raise(ActionController::UnknownHttpMethod) do
-      request = stub_request 'REQUEST_METHOD' =&gt; 'RANDOM_METHOD'
-      request.request_method
+      self.request_method = :random_method
+      @request.request_method
     end
   end
 
   def test_allow_method_hacking_on_post
     [:get, :head, :options, :put, :post, :delete].each do |method|
-      request = stub_request 'REQUEST_METHOD' =&gt; method.to_s.upcase
-      assert_equal(method == :head ? :get : method, request.method)
+      self.request_method = method
+      assert_equal(method == :head ? :get : method, @request.method)
+    end
+  end
+
+  def test_invalid_method_hacking_on_post_raises_exception
+    assert_raise(ActionController::UnknownHttpMethod) do
+      self.request_method = :_random_method
+      @request.request_method
     end
   end
 
   def test_restrict_method_hacking
+    @request.instance_eval { @parameters = { :_method =&gt; 'put' } }
     [:get, :put, :delete].each do |method|
-      request = stub_request 'REQUEST_METHOD' =&gt; method.to_s.upcase,
-        'action_controller.request.request_parameters' =&gt; { :_method =&gt; 'put' }
-      assert_equal method, request.method
+      self.request_method = method
+      assert_equal method, @request.method
     end
   end
 
   def test_head_masquerading_as_get
-    request = stub_request 'REQUEST_METHOD' =&gt; 'HEAD'
-    assert_equal :get, request.method
-    assert request.get?
-    assert request.head?
+    self.request_method = :head
+    assert_equal :get, @request.method
+    assert @request.get?
+    assert @request.head?
   end
 
   def test_xml_format
-    request = stub_request
-    request.expects(:parameters).at_least_once.returns({ :format =&gt; 'xml' })
-    assert_equal Mime::XML, request.format
+    @request.instance_eval { @parameters = { :format =&gt; 'xml' } }
+    assert_equal Mime::XML, @request.format
   end
 
   def test_xhtml_format
-    request = stub_request
-    request.expects(:parameters).at_least_once.returns({ :format =&gt; 'xhtml' })
-    assert_equal Mime::HTML, request.format
+    @request.instance_eval { @parameters = { :format =&gt; 'xhtml' } }
+    assert_equal Mime::HTML, @request.format
   end
 
   def test_txt_format
-    request = stub_request
-    request.expects(:parameters).at_least_once.returns({ :format =&gt; 'txt' })
-    assert_equal Mime::TEXT, request.format
+    @request.instance_eval { @parameters = { :format =&gt; 'txt' } }
+    assert_equal Mime::TEXT, @request.format
   end
 
-  def test_xml_http_request
+  def test_nil_format
     ActionController::Base.use_accept_header, old =
       false, ActionController::Base.use_accept_header
 
-    request = stub_request 'HTTP_X_REQUESTED_WITH' =&gt; 'XMLHttpRequest'
-    request.expects(:parameters).at_least_once.returns({})
-    assert request.xhr?
-    assert_equal Mime::JS, request.format
+    @request.instance_eval { @parameters = {} }
+    @request.env[&quot;HTTP_X_REQUESTED_WITH&quot;] = &quot;XMLHttpRequest&quot;
+    assert @request.xhr?
+    assert_equal Mime::JS, @request.format
+
   ensure
     ActionController::Base.use_accept_header = old
   end
 
   def test_content_type
-    request = stub_request 'CONTENT_TYPE' =&gt; 'text/html'
-    assert_equal Mime::HTML, request.content_type
+    @request.env[&quot;CONTENT_TYPE&quot;] = &quot;text/html&quot;
+    assert_equal Mime::HTML, @request.content_type
   end
 
-  def test_can_override_format_with_parameter
-    request = stub_request
-    request.expects(:parameters).at_least_once.returns({ :format =&gt; :txt })
-    assert !request.format.xml?
-
-    request = stub_request
-    request.expects(:parameters).at_least_once.returns({ :format =&gt; :xml })
-    assert request.format.xml?
+  def test_format_assignment_should_set_format
+    @request.instance_eval { self.format = :txt }
+    assert !@request.format.xml?
+    @request.instance_eval { self.format = :xml }
+    assert @request.format.xml?
   end
 
   def test_content_no_type
-    request = stub_request
-    assert_equal nil, request.content_type
+    assert_equal nil, @request.content_type
   end
 
   def test_content_type_xml
-    request = stub_request 'CONTENT_TYPE' =&gt; 'application/xml'
-    assert_equal Mime::XML, request.content_type
+    @request.env[&quot;CONTENT_TYPE&quot;] = &quot;application/xml&quot;
+    assert_equal Mime::XML, @request.content_type
   end
 
   def test_content_type_with_charset
-    request = stub_request 'CONTENT_TYPE' =&gt; 'application/xml; charset=UTF-8'
-    assert_equal Mime::XML, request.content_type
+    @request.env[&quot;CONTENT_TYPE&quot;] = &quot;application/xml; charset=UTF-8&quot;
+    assert_equal Mime::XML, @request.content_type
   end
 
   def test_user_agent
-    request = stub_request 'HTTP_USER_AGENT' =&gt; 'TestAgent'
-    assert_equal 'TestAgent', request.user_agent
+    assert_not_nil @request.user_agent
   end
 
   def test_parameters
-    request = stub_request
-    request.stubs(:request_parameters).returns({ &quot;foo&quot; =&gt; 1 })
-    request.stubs(:query_parameters).returns({ &quot;bar&quot; =&gt; 2 })
+    @request.stubs(:request_parameters).returns({ &quot;foo&quot; =&gt; 1 })
+    @request.stubs(:query_parameters).returns({ &quot;bar&quot; =&gt; 2 })
 
-    assert_equal({&quot;foo&quot; =&gt; 1, &quot;bar&quot; =&gt; 2}, request.parameters)
-    assert_equal({&quot;foo&quot; =&gt; 1}, request.request_parameters)
-    assert_equal({&quot;bar&quot; =&gt; 2}, request.query_parameters)
-  end
-
-protected
-
-  def stub_request(env={})
-    ActionController::Request.new(env)
+    assert_equal({&quot;foo&quot; =&gt; 1, &quot;bar&quot; =&gt; 2}, @request.parameters)
+    assert_equal({&quot;foo&quot; =&gt; 1}, @request.request_parameters)
+    assert_equal({&quot;bar&quot; =&gt; 2}, @request.query_parameters)
   end
 
+  protected
+    def request_method=(method)
+      @request.env['REQUEST_METHOD'] = method.to_s.upcase
+      @request.request_method = nil # Reset the ivar cache
+    end
 end</diff>
      <filename>vendor/rails/actionpack/test/controller/request_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -44,12 +44,12 @@ class SendFileTest &lt; ActionController::TestCase
     response = nil
     assert_nothing_raised { response = process('file') }
     assert_not_nil response
-    assert_kind_of Proc, response.body_parts
+    assert_kind_of Proc, response.body
 
     require 'stringio'
     output = StringIO.new
     output.binmode
-    assert_nothing_raised { response.body_parts.call(response, output) }
+    assert_nothing_raised { response.body.call(response, output) }
     assert_equal file_data, output.string
   end
 </diff>
      <filename>vendor/rails/actionpack/test/controller/send_file_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -193,6 +193,27 @@ class CookieStoreTest &lt; ActionController::IntegrationTest
     end
   end
 
+  def test_session_store_with_expire_after
+    app = ActionController::Session::CookieStore.new(DispatcherApp, :key =&gt; SessionKey, :secret =&gt; SessionSecret, :expire_after =&gt; 5.hours)
+    @integration_session = open_session(app)
+
+    with_test_route_set do
+      # First request accesses the session
+      cookies[SessionKey] = SignedBar
+
+      get '/set_session_value'
+      assert_response :success
+      cookie = headers['Set-Cookie']
+
+      # Second request does not access the session so the
+      # expires header should not be changed
+      get '/no_session_access'
+      assert_response :success
+      assert_equal cookie, headers['Set-Cookie'],
+        &quot;#{unmarshal_session(cookie).inspect} expected but was #{unmarshal_session(headers['Set-Cookie']).inspect}&quot;
+    end
+  end
+
   private
     def with_test_route_set
       with_routing do |set|</diff>
      <filename>vendor/rails/actionpack/test/controller/session/cookie_store_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -130,10 +130,6 @@ XML
     ActionController::Routing::Routes.reload
   end
 
-  def test_test_request_has_session_options_initialized
-    assert @request.session_options
-  end
-
   def test_raw_post_handling
     params = {:page =&gt; {:name =&gt; 'page name'}, 'some key' =&gt; 123}
     post :render_raw_post, params.dup
@@ -519,14 +515,6 @@ XML
     assert_nil @request.instance_variable_get(&quot;@request_method&quot;)
   end
 
-  def test_params_reset_after_post_request
-    post :no_op, :foo =&gt; &quot;bar&quot;
-    assert_equal &quot;bar&quot;, @request.params[:foo]
-    @request.recycle!
-    post :no_op
-    assert @request.params[:foo].blank?
-  end
-
   %w(controller response request).each do |variable|
     %w(get post put delete head process).each do |method|
       define_method(&quot;test_#{variable}_missing_for_#{method}_raises_error&quot;) do</diff>
      <filename>vendor/rails/actionpack/test/controller/test_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -810,28 +810,25 @@ module ActiveRecord #:nodoc:
 
       # Updates all records with details given if they match a set of conditions supplied, limits and order can
       # also be supplied. This method constructs a single SQL UPDATE statement and sends it straight to the
-      # database. It does not instantiate the involved models and it does not trigger Active Record callbacks
-      # or validations.
+      # database. It does not instantiate the involved models and it does not trigger Active Record callbacks.
       #
       # ==== Parameters
       #
-      # * +updates+ - A string, array, or hash representing the SET part of an SQL statement.
-      # * +conditions+ - A string, array, or hash representing the WHERE part of an SQL statement. See conditions in the intro.
+      # * +updates+ - A string of column and value pairs that will be set on any records that match conditions. This creates the SET clause of the generated SQL.
+      # * +conditions+ - An SQL fragment like &quot;administrator = 1&quot; or [ &quot;user_name = ?&quot;, username ]. See conditions in the intro for more info.
       # * +options+ - Additional options are &lt;tt&gt;:limit&lt;/tt&gt; and &lt;tt&gt;:order&lt;/tt&gt;, see the examples for usage.
       #
       # ==== Examples
       #
-      #   # Update all customers with the given attributes
-      #   Customer.update_all :wants_email =&gt; true
+      #   # Update all billing objects with the 3 different attributes given
+      #   Billing.update_all( &quot;category = 'authorized', approved = 1, author = 'David'&quot; )
       #
-      #   # Update all books with 'Rails' in their title
-      #   Book.update_all &quot;author = 'David'&quot;, &quot;title LIKE '%Rails%'&quot;
+      #   # Update records that match our conditions
+      #   Billing.update_all( &quot;author = 'David'&quot;, &quot;title LIKE '%Rails%'&quot; )
       #
-      #   # Update all avatars migrated more than a week ago
-      #   Avatar.update_all ['migrated_at = ?, Time.now.utc], ['migrated_at &gt; ?', 1.week.ago]
-      #
-      #   # Update all books that match our conditions, but limit it to 5 ordered by date
-      #   Book.update_all &quot;author = 'David'&quot;, &quot;title LIKE '%Rails%'&quot;, :order =&gt; 'created_at', :limit =&gt; 5
+      #   # Update records that match our conditions but limit it to 5 ordered by date
+      #   Billing.update_all( &quot;author = 'David'&quot;, &quot;title LIKE '%Rails%'&quot;,
+      #                         :order =&gt; 'created_at', :limit =&gt; 5 )
       def update_all(updates, conditions = nil, options = {})
         sql  = &quot;UPDATE #{quoted_table_name} SET #{sanitize_sql_for_assignment(updates)} &quot;
 </diff>
      <filename>vendor/rails/activerecord/lib/active_record/base.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,7 @@
 = Active Resource
 
 Active Resource (ARes) connects business objects and Representational State Transfer (REST)
-web services.  It implements object-relational mapping for REST web services to provide transparent
+web services.  It implements object-relational mapping for REST webservices to provide transparent 
 proxying capabilities between a client (ActiveResource) and a RESTful service (which is provided by Simply RESTful routing
 in ActionController::Resources).
 
@@ -22,14 +22,14 @@ received and serialized into a usable Ruby object.
 
 === Configuration and Usage
 
-Putting Active Resource to use is very similar to Active Record.  It's as simple as creating a model class
+Putting ActiveResource to use is very similar to ActiveRecord.  It's as simple as creating a model class
 that inherits from ActiveResource::Base and providing a &lt;tt&gt;site&lt;/tt&gt; class variable to it:
 
    class Person &lt; ActiveResource::Base
      self.site = &quot;http://api.people.com:3000/&quot;
    end
 
-Now the Person class is REST enabled and can invoke REST services very similarly to how Active Record invokes
+Now the Person class is REST enabled and can invoke REST services very similarly to how ActiveRecord invokes
 lifecycle methods that operate against a persistent store.
 
    # Find a person with id = 1
@@ -42,7 +42,7 @@ records.  But rather than dealing directly with a database record, you're dealin
 ==== Protocol
 
 Active Resource is built on a standard XML format for requesting and submitting resources over HTTP.  It mirrors the RESTful routing 
-built into Action Controller but will also work with any other REST service that properly implements the protocol.
+built into ActionController but will also work with any other REST service that properly implements the protocol. 
 REST uses HTTP, but unlike &quot;typical&quot; web applications, it makes use of all the verbs available in the HTTP specification:
 
 * GET requests are used for finding and retrieving resources.
@@ -55,8 +55,8 @@ for more general information on REST web services, see the article here[http://e
 
 ==== Find
 
-Find requests use the GET method and expect the XML form of whatever resource/resources is/are being requested.  So,
-for a request for a single element, the XML of that item is expected in response:
+GET Http requests expect the XML form of whatever resource/resources is/are being requested.  So,
+for a request for a single element - the XML of that item is expected in response:
 
    # Expects a response of
    #
@@ -101,7 +101,7 @@ Collections can also be requested in a similar fashion
 
 ==== Create
 
-Creating a new resource submits the XML form of the resource as the body of the request and expects
+Creating a new resource submits the xml form of the resource as the body of the request and expects
 a 'Location' header in the response with the RESTful URL location of the newly created resource.  The
 id of the newly created resource is parsed out of the Location response header and automatically set
 as the id of the ARes object.</diff>
      <filename>vendor/rails/activeresource/README</filename>
    </modified>
    <modified>
      <diff>@@ -19,7 +19,7 @@ module ActiveResource
   #   end
   #
   # Now the Person class is mapped to RESTful resources located at &lt;tt&gt;http://api.people.com:3000/people/&lt;/tt&gt;, and
-  # you can now use Active Resource's lifecycle methods to manipulate resources. In the case where you already have
+  # you can now use Active Resource's lifecycles methods to manipulate resources. In the case where you already have
   # an existing model with the same name as the desired RESTful resource you can set the +element_name+ value.
   #
   #   class PersonResource &lt; ActiveResource::Base
@@ -112,7 +112,6 @@ module ActiveResource
   #
   # Note: Some values cannot be provided in the URL passed to site.  e.g. email addresses
   # as usernames.  In those situations you should use the separate user and password option.
-  #
   # == Errors &amp; Validation
   #
   # Error handling and validation is handled in much the same manner as you're used to seeing in
@@ -157,7 +156,7 @@ module ActiveResource
   #
   # === Validation errors
   #
-  # Active Resource supports validations on resources and will return errors if any of these validations fail
+  # Active Resource supports validations on resources and will return errors if any these validations fail
   # (e.g., &quot;First name can not be blank&quot; and so on).  These types of errors are denoted in the response by
   # a response code of &lt;tt&gt;422&lt;/tt&gt; and an XML representation of the validation errors.  The save operation will
   # then fail (with a &lt;tt&gt;false&lt;/tt&gt; return value) and the validation errors can be accessed on the resource in question.
@@ -414,7 +413,7 @@ module ActiveResource
       # will split from the +prefix_options+.
       #
       # ==== Options
-      # * +prefix_options+ - A hash to add a prefix to the request for nested URLs (e.g., &lt;tt&gt;:account_id =&gt; 19&lt;/tt&gt;
+      # * +prefix_options+ - A hash to add a prefix to the request for nested URL's (e.g., &lt;tt&gt;:account_id =&gt; 19&lt;/tt&gt;
       #   would yield a URL like &lt;tt&gt;/accounts/19/purchases.xml&lt;/tt&gt;).
       # * +query_options+ - A hash to add items to the query string for the request.
       #
@@ -692,7 +691,7 @@ module ActiveResource
     end
 
 
-    # Returns +true+ if this object hasn't yet been saved, otherwise, returns +false+.
+    # A method to determine if the resource a \new object (i.e., it has not been POSTed to the remote service yet).
     #
     # ==== Examples
     #   not_new = Computer.create(:brand =&gt; 'Apple', :make =&gt; 'MacBook', :vendor =&gt; 'MacMall')
@@ -761,7 +760,7 @@ module ActiveResource
       id.hash
     end
 
-    # Duplicates the current resource without saving it.
+    # Duplicate the current resource without saving it.
     #
     # ==== Examples
     #   my_invoice = Invoice.create(:customer =&gt; 'That Company')
@@ -780,8 +779,8 @@ module ActiveResource
       end
     end
 
-    # Saves (+POST+) or \updates (+PUT+) a resource.  Delegates to +create+ if the object is \new,
-    # +update+ if it exists. If the response to the \save includes a body, it will be assumed that this body
+    # A method to \save (+POST+) or \update (+PUT+) a resource.  It delegates to +create+ if a \new object, 
+    # +update+ if it is existing. If the response to the \save includes a body, it will be assumed that this body
     # is XML for the final object as it looked after the \save (which would include attributes like +created_at+
     # that weren't part of the original submit).
     #
@@ -833,7 +832,7 @@ module ActiveResource
       !new? &amp;&amp; self.class.exists?(to_param, :params =&gt; prefix_options)
     end
 
-    # Converts the resource to an XML string representation.
+    # A method to convert the the resource to an XML string.
     #
     # ==== Options
     # The +options+ parameter is handed off to the +to_xml+ method on each
@@ -862,7 +861,8 @@ module ActiveResource
       attributes.to_xml({:root =&gt; self.class.element_name}.merge(options))
     end
 
-    # Converts the resource to a JSON string representation.
+    # Returns a JSON string representing the model. Some configuration is
+    # available through +options+.
     #
     # ==== Options
     # The +options+ are passed to the +to_json+ method on each</diff>
      <filename>vendor/rails/activeresource/lib/active_resource/base.rb</filename>
    </modified>
    <modified>
      <diff>@@ -95,46 +95,46 @@ module ActiveResource
       @password = URI.decode(@site.password) if @site.password
     end
 
-    # Sets the user for remote service.
+    # Set user for remote service.
     def user=(user)
       @user = user
     end
 
-    # Sets the password for remote service.
+    # Set password for remote service.
     def password=(password)
       @password = password
     end
 
-    # Sets the number of seconds after which HTTP requests to the remote service should time out.
+    # Set the number of seconds after which HTTP requests to the remote service should time out.
     def timeout=(timeout)
       @timeout = timeout
     end
 
-    # Executes a GET request.
+    # Execute a GET request.
     # Used to get (find) resources.
     def get(path, headers = {})
       format.decode(request(:get, path, build_request_headers(headers, :get)).body)
     end
 
-    # Executes a DELETE request (see HTTP protocol documentation if unfamiliar).
+    # Execute a DELETE request (see HTTP protocol documentation if unfamiliar).
     # Used to delete resources.
     def delete(path, headers = {})
       request(:delete, path, build_request_headers(headers, :delete))
     end
 
-    # Executes a PUT request (see HTTP protocol documentation if unfamiliar).
+    # Execute a PUT request (see HTTP protocol documentation if unfamiliar).
     # Used to update resources.
     def put(path, body = '', headers = {})
       request(:put, path, body.to_s, build_request_headers(headers, :put))
     end
 
-    # Executes a POST request.
+    # Execute a POST request.
     # Used to create new resources.
     def post(path, body = '', headers = {})
       request(:post, path, body.to_s, build_request_headers(headers, :post))
     end
 
-    # Executes a HEAD request.
+    # Execute a HEAD request.
     # Used to obtain meta-information about resources, such as whether they exist and their size (via response headers).
     def head(path, headers = {})
       request(:head, path, build_request_headers(headers))
@@ -142,7 +142,7 @@ module ActiveResource
 
 
     private
-      # Makes a request to the remote service.
+      # Makes request to remote service.
       def request(method, path, *arguments)
         logger.info &quot;#{method.to_s.upcase} #{site.scheme}://#{site.host}:#{site.port}#{path}&quot; if logger
         result = nil
@@ -153,7 +153,7 @@ module ActiveResource
         raise TimeoutError.new(e.message)
       end
 
-      # Handles response and error codes from the remote service.
+      # Handles response and error codes from remote service.
       def handle_response(response)
         case response.code.to_i
           when 301,302
@@ -183,7 +183,7 @@ module ActiveResource
         end
       end
 
-      # Creates new Net::HTTP instance for communication with the
+      # Creates new Net::HTTP instance for communication with
       # remote service and resources.
       def http
         http             = Net::HTTP.new(@site.host, @site.port)</diff>
      <filename>vendor/rails/activeresource/lib/active_resource/connection.rb</filename>
    </modified>
    <modified>
      <diff>@@ -3,7 +3,7 @@ module ActiveResource
   end
 
   # Active Resource validation is reported to and from this object, which is used by Base#save
-  # to determine whether the object is in a valid state to be saved. See usage example in Validations.
+  # to determine whether the object in a valid state to be saved. See usage example in Validations.  
   class Errors
     include Enumerable
     attr_reader :errors
@@ -14,10 +14,7 @@ module ActiveResource
       @base, @errors = base, {}
     end
 
-    # Adds an error to the base object instead of any particular attribute. This is used
-    # to report errors that don't tie to any specific attribute, but rather to the object
-    # as a whole. These error messages don't get prepended with any field name when iterating
-    # with +each_full+, so they should be complete sentences.
+    # Add an error to the base Active Resource object rather than an attribute.
     #
     # ==== Examples
     #   my_folder = Folder.find(1)
@@ -71,9 +68,9 @@ module ActiveResource
       !@errors[attribute.to_s].nil?
     end
 
-    # Returns +nil+ if no errors are associated with the specified +attribute+.
-    # Returns the error message if one error is associated with the specified +attribute+.
-    # Returns an array of error messages if more than one error is associated with the specified +attribute+.
+    # A method to return the errors associated with +attribute+, which returns nil, if no errors are 
+    # associated with the specified +attribute+, the error message if one error is associated with the specified +attribute+,
+    # or an array of error messages if more than one error is associated with the specified +attribute+.
     #
     # ==== Examples
     #   my_person = Person.new(params[:person])
@@ -95,7 +92,9 @@ module ActiveResource
     
     alias :[] :on
 
-    # Returns errors assigned to the base object through +add_to_base+ according to the normal rules of &lt;tt&gt;on(attribute)&lt;/tt&gt;.
+    # A method to return errors assigned to +base+ object through add_to_base, which returns nil, if no errors are 
+    # associated with the specified +attribute+, the error message if one error is associated with the specified +attribute+,
+    # or an array of error messages if more than one error is associated with the specified +attribute+.
     #
     # ==== Examples
     #   my_account = Account.find(1)</diff>
      <filename>vendor/rails/activeresource/lib/active_resource/validations.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,3 @@
-*Edge
-
-* Time.local instances: Adding 24.hours across the DST boundary adds 24 hours instead of one day #2066 [Michael Curtis]
-
-
 *2.3.2 [Final] (March 15, 2009)*
 
 * XmlMini supports LibXML and Nokogiri backends.  #2084, #2190 [Bart ten Brinke, Aaron Patterson]</diff>
      <filename>vendor/rails/activesupport/CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -116,14 +116,22 @@ module ActiveSupport #:nodoc:
           seconds_to_advance == 0 ? time_advanced_by_date : time_advanced_by_date.since(seconds_to_advance)
         end
 
-        # Returns a new Time representing the time a number of seconds ago
+        # Returns a new Time representing the time a number of seconds ago, this is basically a wrapper around the Numeric extension
         def ago(seconds)
           self.since(-seconds)
         end
 
-        # Returns a new Time representing the time a number of seconds since the instance time
+        # Returns a new Time representing the time a number of seconds since the instance time, this is basically a wrapper around
+        # the Numeric extension.
         def since(seconds)
-          self + seconds
+          f = seconds.since(self)
+          if ActiveSupport::Duration === seconds
+            f
+          else
+            initial_dst = self.dst? ? 1 : 0
+            final_dst   = f.dst? ? 1 : 0
+            (seconds.abs &gt;= 86400 &amp;&amp; initial_dst != final_dst) ? f + (initial_dst - final_dst).hours : f
+          end
         rescue
           self.to_datetime.since(seconds)
         end</diff>
      <filename>vendor/rails/activesupport/lib/active_support/core_ext/time/calculations.rb</filename>
    </modified>
    <modified>
      <diff>@@ -109,18 +109,6 @@ class DurationTest &lt; ActiveSupport::TestCase
   ensure
     Time.zone_default = nil
   end
-  
-  def test_adding_hours_across_dst_boundary
-    with_env_tz 'CET' do
-      assert_equal Time.local(2009,3,29,0,0,0) + 24.hours, Time.local(2009,3,30,1,0,0)
-    end
-  end
-  
-  def test_adding_day_across_dst_boundary
-    with_env_tz 'CET' do
-      assert_equal Time.local(2009,3,29,0,0,0) + 1.day, Time.local(2009,3,30,0,0,0)
-    end
-  end
 
   protected
     def with_env_tz(new_tz = 'US/Eastern')</diff>
      <filename>vendor/rails/activesupport/test/core_ext/duration_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -183,46 +183,26 @@ class TimeExtCalculationsTest &lt; Test::Unit::TestCase
   def test_daylight_savings_time_crossings_backward_start
     with_env_tz 'US/Eastern' do
       # dt: US: 2005 April 3rd 4:18am
-      assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(24.hours), 'dt-24.hours=&gt;st'
-      assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(86400), 'dt-86400=&gt;st'
-      assert_equal Time.local(2005,4,2,3,18,0), Time.local(2005,4,3,4,18,0).ago(86400.seconds), 'dt-86400.seconds=&gt;st'
-      
-      assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(24.hours), 'st-24.hours=&gt;st'
-      assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400), 'st-86400=&gt;st'
-      assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400.seconds), 'st-86400.seconds=&gt;st'
+      assert_equal Time.local(2005,4,2,4,18,0), Time.local(2005,4,3,4,18,0).ago(86400), 'dt-1.day=&gt;st'
+      assert_equal Time.local(2005,4,1,4,18,0), Time.local(2005,4,2,4,18,0).ago(86400), 'st-1.day=&gt;st'
     end
     with_env_tz 'NZ' do
       # dt: New Zealand: 2006 October 1st 4:18am
-      assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(24.hours), 'dt-24.hours=&gt;st'
-      assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(86400.seconds), 'dt-86400.seconds=&gt;st'
-      assert_equal Time.local(2006,9,30,3,18,0), Time.local(2006,10,1,4,18,0).ago(86400), 'dt-86400=&gt;st'
-      
-      assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400), 'st-86400=&gt;st'
-      assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(24.hours), 'st-24.hours=&gt;st'
-      assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400.seconds), 'st-86400.seconds=&gt;st'
+      assert_equal Time.local(2006,9,30,4,18,0), Time.local(2006,10,1,4,18,0).ago(86400), 'dt-1.day=&gt;st'
+      assert_equal Time.local(2006,9,29,4,18,0), Time.local(2006,9,30,4,18,0).ago(86400), 'st-1.day=&gt;st'
     end
   end
 
   def test_daylight_savings_time_crossings_backward_end
     with_env_tz 'US/Eastern' do
       # st: US: 2005 October 30th 4:03am
-      assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(24.hours), 'st-24.hours=&gt;dt'
-      assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(86400), 'st-86400=&gt;dt'
-      assert_equal Time.local(2005,10,29,5,3), Time.local(2005,10,30,4,3,0).ago(86400.seconds), 'st-86400.seconds=&gt;dt'
-      
-      assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(24.hours), 'dt-24.hours=&gt;dt'
-      assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400), 'dt-86400=&gt;dt'
-      assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400.seconds), 'dt-86400.seconds=&gt;dt'
+      assert_equal Time.local(2005,10,29,4,3), Time.local(2005,10,30,4,3,0).ago(86400), 'st-1.day=&gt;dt'
+      assert_equal Time.local(2005,10,28,4,3), Time.local(2005,10,29,4,3,0).ago(86400), 'dt-1.day=&gt;dt'
     end
     with_env_tz 'NZ' do
       # st: New Zealand: 2006 March 19th 4:03am
-      assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(24.hours), 'st-24.hours=&gt;dt'
-      assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(86400), 'st-86400=&gt;dt'
-      assert_equal Time.local(2006,3,18,5,3), Time.local(2006,3,19,4,3,0).ago(86400.seconds), 'st-86400.seconds=&gt;dt'
-      
-      assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(24.hours), 'dt-24.hours=&gt;dt'
-      assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400), 'dt-86400=&gt;dt'
-      assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400.seconds), 'dt-86400.seconds=&gt;dt'
+      assert_equal Time.local(2006,3,18,4,3), Time.local(2006,3,19,4,3,0).ago(86400), 'st-1.day=&gt;dt'
+      assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(86400), 'dt-1.day=&gt;dt'
     end
   end
 
@@ -251,7 +231,6 @@ class TimeExtCalculationsTest &lt; Test::Unit::TestCase
       assert_equal Time.local(2006,3,17,4,3), Time.local(2006,3,18,4,3,0).ago(1.day), 'dt-1.day=&gt;dt'
     end
   end
-  
   def test_since
     assert_equal Time.local(2005,2,22,10,10,11), Time.local(2005,2,22,10,10,10).since(1)
     assert_equal Time.local(2005,2,22,11,10,10), Time.local(2005,2,22,10,10,10).since(3600)
@@ -264,23 +243,13 @@ class TimeExtCalculationsTest &lt; Test::Unit::TestCase
   def test_daylight_savings_time_crossings_forward_start
     with_env_tz 'US/Eastern' do
       # st: US: 2005 April 2nd 7:27pm
-      assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(24.hours), 'st+24.hours=&gt;dt'
-      assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(86400), 'st+86400=&gt;dt'
-      assert_equal Time.local(2005,4,3,20,27,0), Time.local(2005,4,2,19,27,0).since(86400.seconds), 'st+86400.seconds=&gt;dt'
-      
-      assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(24.hours), 'dt+24.hoursy=&gt;dt'
-      assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400), 'dt+86400=&gt;dt'
-      assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400.seconds), 'dt+86400.seconds=&gt;dt'
+      assert_equal Time.local(2005,4,3,19,27,0), Time.local(2005,4,2,19,27,0).since(86400), 'st+1.day=&gt;dt'
+      assert_equal Time.local(2005,4,4,19,27,0), Time.local(2005,4,3,19,27,0).since(86400), 'dt+1.day=&gt;dt'
     end
     with_env_tz 'NZ' do
       # st: New Zealand: 2006 September 30th 7:27pm
-      assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(24.hours), 'st+24.hours=&gt;dt'
-      assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(86400), 'st+86400=&gt;dt'
-      assert_equal Time.local(2006,10,1,20,27,0), Time.local(2006,9,30,19,27,0).since(86400.seconds), 'st+86400.seconds=&gt;dt'
-      
-      assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(24.hours), 'dt+24.hours=&gt;dt'
-      assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400), 'dt+86400=&gt;dt'
-      assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400.seconds), 'dt+86400.seconds=&gt;dt'
+      assert_equal Time.local(2006,10,1,19,27,0), Time.local(2006,9,30,19,27,0).since(86400), 'st+1.day=&gt;dt'
+      assert_equal Time.local(2006,10,2,19,27,0), Time.local(2006,10,1,19,27,0).since(86400), 'dt+1.day=&gt;dt'
     end
   end
 
@@ -326,23 +295,13 @@ class TimeExtCalculationsTest &lt; Test::Unit::TestCase
   def test_daylight_savings_time_crossings_forward_end
     with_env_tz 'US/Eastern' do
       # dt: US: 2005 October 30th 12:45am
-      assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(24.hours), 'dt+24.hours=&gt;st'
-      assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(86400), 'dt+86400=&gt;st'
-      assert_equal Time.local(2005,10,30,23,45,0), Time.local(2005,10,30,0,45,0).since(86400.seconds), 'dt+86400.seconds=&gt;st'
-      
-      assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(24.hours), 'st+24.hours=&gt;st'
-      assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400), 'st+86400=&gt;st'
-      assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400.seconds), 'st+86400.seconds=&gt;st'
+      assert_equal Time.local(2005,10,31,0,45,0), Time.local(2005,10,30,0,45,0).since(86400), 'dt+1.day=&gt;st'
+      assert_equal Time.local(2005,11, 1,0,45,0), Time.local(2005,10,31,0,45,0).since(86400), 'st+1.day=&gt;st'
     end
     with_env_tz 'NZ' do
       # dt: New Zealand: 2006 March 19th 1:45am
-      assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(24.hours), 'dt+24.hours=&gt;st'
-      assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(86400), 'dt+86400=&gt;st'
-      assert_equal Time.local(2006,3,20,0,45,0), Time.local(2006,3,19,1,45,0).since(86400.seconds), 'dt+86400.seconds=&gt;st'
-      
-      assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(24.hours), 'st+24.hours=&gt;st'
-      assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400), 'st+86400=&gt;st'
-      assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400.seconds), 'st+86400.seconds=&gt;st'
+      assert_equal Time.local(2006,3,20,1,45,0), Time.local(2006,3,19,1,45,0).since(86400), 'dt+1.day=&gt;st'
+      assert_equal Time.local(2006,3,21,1,45,0), Time.local(2006,3,20,1,45,0).since(86400), 'st+1.day=&gt;st'
     end
   end
 </diff>
      <filename>vendor/rails/activesupport/test/core_ext/time_ext_test.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,7 +1,5 @@
 *2.3.2 [Final] (March 15, 2009)*
 
-* Remove outdated script/plugin options [Pratik Naik]
-
 * Allow metal to live in plugins #2045 [Matthew Rudy]
 
 * Added metal [Josh Peek]</diff>
      <filename>vendor/rails/railties/CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -247,7 +247,6 @@ end
 
 desc 'Generate guides (for authors), use ONLY=foo to process just &quot;foo.textile&quot;'
 task :guides do
-  ENV[&quot;WARN_BROKEN_LINKS&quot;] = &quot;1&quot; # authors can't disable this
   ruby &quot;guides/rails_guides.rb&quot;
 end
 </diff>
      <filename>vendor/rails/railties/Rakefile</filename>
    </modified>
    <modified>
      <diff></diff>
      <filename>vendor/rails/railties/guides/images/fxn.jpg</filename>
    </modified>
    <modified>
      <diff>@@ -33,7 +33,6 @@ module RailsGuides
   autoload :Indexer, &quot;rails_guides/indexer&quot;
   autoload :Helpers, &quot;rails_guides/helpers&quot;
   autoload :TextileExtensions, &quot;rails_guides/textile_extensions&quot;
-  autoload :Levenshtein, &quot;rails_guides/levenshtein&quot;
 end
 
 RedCloth.send(:include, RailsGuides::TextileExtensions)</diff>
      <filename>vendor/rails/railties/guides/rails_guides.rb</filename>
    </modified>
    <modified>
      <diff>@@ -57,7 +57,6 @@ module RailsGuides
 
           result = view.render(:layout =&gt; 'layout', :text =&gt; textile(body))
           f.write result
-          warn_about_broken_links(result) if ENV.key?(&quot;WARN_BROKEN_LINKS&quot;)
         end
       end
     end
@@ -135,38 +134,5 @@ module RailsGuides
         code_blocks[$1.to_i]
       end
     end
-
-    def warn_about_broken_links(html)
-      anchors = extract_anchors(html)
-      check_fragment_identifiers(html, anchors)
-    end
-    
-    def extract_anchors(html)
-      # Textile generates headers with IDs computed from titles.
-      anchors = Set.new
-      html.scan(/&lt;h\d\s+id=&quot;([^&quot;]+)/).flatten.each do |anchor|
-        if anchors.member?(anchor)
-          puts &quot;*** DUPLICATE HEADER ID: #{anchor}, please consider rewording&quot; if ENV.key?(&quot;WARN_DUPLICATE_HEADERS&quot;)
-        else
-          anchors &lt;&lt; anchor
-        end
-      end
-
-      # Also, footnotes are rendered as paragraphs this way.
-      anchors += Set.new(html.scan(/&lt;p\s+class=&quot;footnote&quot;\s+id=&quot;([^&quot;]+)/).flatten)
-      return anchors
-    end
-    
-    def check_fragment_identifiers(html, anchors)
-      html.scan(/&lt;a\s+href=&quot;#([^&quot;]+)/).flatten.each do |fragment_identifier|
-        next if fragment_identifier == 'mainCol' # in layout, jumps to some DIV
-        unless anchors.member?(fragment_identifier)
-          guess = anchors.min { |a, b|
-            Levenshtein.distance(fragment_identifier, a) &lt;=&gt; Levenshtein.distance(fragment_identifier, b)
-          }
-          puts &quot;*** BROKEN LINK: ##{fragment_identifier}, perhaps you meant ##{guess}.&quot;
-        end
-      end
-    end
   end
 end</diff>
      <filename>vendor/rails/railties/guides/rails_guides/generator.rb</filename>
    </modified>
    <modified>
      <diff>@@ -111,6 +111,7 @@ h5. +last+
 &lt;tt&gt;Model.last(options = nil)&lt;/tt&gt; finds the last record matched by the supplied options. If no +options+ are supplied, the last matching record is returned. For example:
 
 &lt;ruby&gt;
+# Find the client with primary key (id) 10.
 client = Client.last
 =&gt; #&lt;Client id: 221, name: =&gt; &quot;Russel&quot;&gt;
 &lt;/ruby&gt;</diff>
      <filename>vendor/rails/railties/guides/source/active_record_querying.textile</filename>
    </modified>
    <modified>
      <diff>@@ -683,7 +683,7 @@ This would result in +params[:addresses]+ being an array of hashes with keys +li
 
 There's a restriction, however, while hashes can be nested arbitrarily, only one level of &quot;arrayness&quot; is allowed. Arrays can be usually replaced by hashes, for example instead of having an array of model objects one can have a hash of model objects keyed by their id, an array index or some other parameter.
 
-WARNING: Array parameters do not play well with the +check_box+ helper. According to the HTML specification unchecked checkboxes submit no value. However it is often convenient for a checkbox to always submit a value. The +check_box+ helper fakes this by creating an auxiliary hidden input with the same name. If the checkbox is unchecked only the hidden input is submitted and if it is checked then both are submitted but the value submitted by the checkbox takes precedence. When working with array parameters this duplicate submission will confuse Rails since duplicate input names are how it decides when to start a new array element. It is preferable to either use +check_box_tag+ or to use hashes instead of arrays.
+WARNING: Array parameters do not play well with the +check_box+ helper. According to the HTML specification unchecked checkboxes submit no value. However it is often convenient for a checkbox to always submit a value. The +check_box+ helper fakes this by creating a second hidden input with the same name. If the checkbox is unchecked only the hidden input is submitted and if it is checked then both are submitted but the value submitted by the checkbox takes precedence. When working with array parameters this duplicate submission will confuse Rails since duplicate input names are how it decides when to start a new array element. It is preferable to either use +check_box_tag+ or to use hashes instead of arrays.
 
 h4. Using Form Helpers
 </diff>
      <filename>vendor/rails/railties/guides/source/form_helpers.textile</filename>
    </modified>
    <modified>
      <diff>@@ -959,7 +959,7 @@ On pages generated by +NewsController+, you want to hide the top menu and add a
   &lt;div id=&quot;right_menu&quot;&gt;Right menu items here&lt;/div&gt;
   &lt;%= yield(:news_content) or yield %&gt;
   &lt;% end -%&gt;
-&lt;%= render :file =&gt; 'layouts/application' %&gt;
+&lt;% render :file =&gt; 'layouts/application' %&gt;
 &lt;/erb&gt;
 
 That's it. The News views will use the new layout, hiding the top menu and adding a new right menu inside the &quot;content&quot; div.</diff>
      <filename>vendor/rails/railties/guides/source/layouts_and_rendering.textile</filename>
    </modified>
    <modified>
      <diff>@@ -1,8 +1,47 @@
 # Rails Plugin Manager.
+# 
+# Listing available plugins:
+#
+#   $ ./script/plugin list
+#   continuous_builder            http://dev.rubyonrails.com/svn/rails/plugins/continuous_builder
+#   asset_timestamping            http://svn.aviditybytes.com/rails/plugins/asset_timestamping
+#   enumerations_mixin            http://svn.protocool.com/rails/plugins/enumerations_mixin/trunk
+#   calculations                  http://techno-weenie.net/svn/projects/calculations/
+#   ...
 #
 # Installing plugins:
 #
 #   $ ./script/plugin install continuous_builder asset_timestamping
+#
+# Finding Repositories:
+#
+#   $ ./script/plugin discover
+# 
+# Adding Repositories:
+#
+#   $ ./script/plugin source http://svn.protocool.com/rails/plugins/
+#
+# How it works:
+# 
+#   * Maintains a list of subversion repositories that are assumed to have
+#     a plugin directory structure. Manage them with the (source, unsource,
+#     and sources commands)
+#     
+#   * The discover command scrapes the following page for things that
+#     look like subversion repositories with plugins:
+#     http://wiki.rubyonrails.org/rails/pages/Plugins
+# 
+#   * Unless you specify that you want to use svn, script/plugin uses plain old
+#     HTTP for downloads.  The following bullets are true if you specify
+#     that you want to use svn.
+#
+#   * If `vendor/plugins` is under subversion control, the script will
+#     modify the svn:externals property and perform an update. You can
+#     use normal subversion commands to keep the plugins up to date.
+# 
+#   * Or, if `vendor/plugins` is not under subversion control, the
+#     plugin is pulled via `svn checkout` or `svn export` but looks
+#     exactly the same.
 # 
 # Specifying revisions:
 #
@@ -117,13 +156,13 @@ end
 class Plugin
   attr_reader :name, :uri
   
-  def initialize(uri, name = nil)
+  def initialize(uri, name=nil)
     @uri = uri
     guess_name(uri)
   end
   
   def self.find(name)
-    new(name)
+    name =~ /\// ? new(name) : Repositories.instance.find_plugin(name)
   end
   
   def to_s
@@ -169,13 +208,10 @@ class Plugin
     else
       puts &quot;Plugin doesn't exist: #{path}&quot;
     end
-
-    if rails_env.use_externals?
-      # clean up svn:externals
-      externals = rails_env.externals
-      externals.reject!{|n,u| name == n or name == u}
-      rails_env.externals = externals
-    end
+    # clean up svn:externals
+    externals = rails_env.externals
+    externals.reject!{|n,u| name == n or name == u}
+    rails_env.externals = externals
   end
 
   def info
@@ -274,6 +310,129 @@ class Plugin
     end
 end
 
+class Repositories
+  include Enumerable
+  
+  def initialize(cache_file = File.join(find_home, &quot;.rails-plugin-sources&quot;))
+    @cache_file = File.expand_path(cache_file)
+    load!
+  end
+  
+  def each(&amp;block)
+    @repositories.each(&amp;block)
+  end
+  
+  def add(uri)
+    unless find{|repo| repo.uri == uri }
+      @repositories.push(Repository.new(uri)).last
+    end
+  end
+  
+  def remove(uri)
+    @repositories.reject!{|repo| repo.uri == uri}
+  end
+  
+  def exist?(uri)
+    @repositories.detect{|repo| repo.uri == uri }
+  end
+  
+  def all
+    @repositories
+  end
+  
+  def find_plugin(name)
+    @repositories.each do |repo|
+      repo.each do |plugin|
+        return plugin if plugin.name == name
+      end
+    end
+    return nil
+  end
+  
+  def load!
+    contents = File.exist?(@cache_file) ? File.read(@cache_file) : defaults
+    contents = defaults if contents.empty?
+    @repositories = contents.split(/\n/).reject do |line|
+      line =~ /^\s*#/ or line =~ /^\s*$/
+    end.map { |source| Repository.new(source.strip) }
+  end
+  
+  def save
+    File.open(@cache_file, 'w') do |f|
+      each do |repo|
+        f.write(repo.uri)
+        f.write(&quot;\n&quot;)
+      end
+    end
+  end
+  
+  def defaults
+    &lt;&lt;-DEFAULTS
+    http://dev.rubyonrails.com/svn/rails/plugins/
+    DEFAULTS
+  end
+ 
+  def find_home
+    ['HOME', 'USERPROFILE'].each do |homekey|
+      return ENV[homekey] if ENV[homekey]
+    end
+    if ENV['HOMEDRIVE'] &amp;&amp; ENV['HOMEPATH']
+      return &quot;#{ENV['HOMEDRIVE']}:#{ENV['HOMEPATH']}&quot;
+    end
+    begin
+      File.expand_path(&quot;~&quot;)
+    rescue StandardError =&gt; ex
+      if File::ALT_SEPARATOR
+        &quot;C:/&quot;
+      else
+        &quot;/&quot;
+      end
+    end
+  end
+
+  def self.instance
+    @instance ||= Repositories.new
+  end
+  
+  def self.each(&amp;block)
+    self.instance.each(&amp;block)
+  end
+end
+
+class Repository
+  include Enumerable
+  attr_reader :uri, :plugins
+  
+  def initialize(uri)
+    @uri = uri.chomp('/') &lt;&lt; &quot;/&quot;
+    @plugins = nil
+  end
+  
+  def plugins
+    unless @plugins
+      if $verbose
+        puts &quot;Discovering plugins in #{@uri}&quot; 
+        puts index
+      end
+
+      @plugins = index.reject{ |line| line !~ /\/$/ }
+      @plugins.map! { |name| Plugin.new(File.join(@uri, name), name) }
+    end
+
+    @plugins
+  end
+  
+  def each(&amp;block)
+    plugins.each(&amp;block)
+  end
+  
+  private
+    def index
+      @index ||= RecursiveHTTPFetcher.new(@uri).ls
+    end
+end
+
+
 # load default environment and parse arguments
 require 'optparse'
 module Commands
@@ -313,8 +472,14 @@ module Commands
         o.separator &quot;&quot;
         o.separator &quot;COMMANDS&quot;
         
+        o.separator &quot;  discover   Discover plugin repositories.&quot;
+        o.separator &quot;  list       List available plugins.&quot;
         o.separator &quot;  install    Install plugin(s) from known repositories or URLs.&quot;
+        o.separator &quot;  update     Update installed plugins.&quot;
         o.separator &quot;  remove     Uninstall plugins.&quot;
+        o.separator &quot;  source     Add a plugin source repository.&quot;
+        o.separator &quot;  unsource   Remove a plugin repository.&quot;
+        o.separator &quot;  sources    List currently configured plugin repositories.&quot;
         
         o.separator &quot;&quot;
         o.separator &quot;EXAMPLES&quot;
@@ -326,6 +491,20 @@ module Commands
         o.separator &quot;    #{@script_name} install git://github.com/SomeGuy/my_awesome_plugin.git\n&quot;
         o.separator &quot;  Install a plugin and add a svn:externals entry to vendor/plugins&quot;
         o.separator &quot;    #{@script_name} install -x continuous_builder\n&quot;
+        o.separator &quot;  List all available plugins:&quot;
+        o.separator &quot;    #{@script_name} list\n&quot;
+        o.separator &quot;  List plugins in the specified repository:&quot;
+        o.separator &quot;    #{@script_name} list --source=http://dev.rubyonrails.com/svn/rails/plugins/\n&quot;
+        o.separator &quot;  Discover and prompt to add new repositories:&quot;
+        o.separator &quot;    #{@script_name} discover\n&quot;
+        o.separator &quot;  Discover new repositories but just list them, don't add anything:&quot;
+        o.separator &quot;    #{@script_name} discover -l\n&quot;
+        o.separator &quot;  Add a new repository to the source list:&quot;
+        o.separator &quot;    #{@script_name} source http://dev.rubyonrails.com/svn/rails/plugins/\n&quot;
+        o.separator &quot;  Remove a repository from the source list:&quot;
+        o.separator &quot;    #{@script_name} unsource http://dev.rubyonrails.com/svn/rails/plugins/\n&quot;
+        o.separator &quot;  Show currently configured repositories:&quot;
+        o.separator &quot;    #{@script_name} sources\n&quot;        
       end
     end
     
@@ -334,7 +513,7 @@ module Commands
       options.parse!(general)
       
       command = general.shift
-      if command =~ /^(install|remove)$/
+      if command =~ /^(list|discover|install|source|unsource|sources|remove|update|info)$/
         command = Commands.const_get(command.capitalize).new(self)
         command.parse!(sub)
       else
@@ -356,6 +535,218 @@ module Commands
     end
   end
   
+  
+  class List
+    def initialize(base_command)
+      @base_command = base_command
+      @sources = []
+      @local = false
+      @remote = true
+    end
+    
+    def options
+      OptionParser.new do |o|
+        o.set_summary_indent('  ')
+        o.banner =    &quot;Usage: #{@base_command.script_name} list [OPTIONS] [PATTERN]&quot;
+        o.define_head &quot;List available plugins.&quot;
+        o.separator   &quot;&quot;        
+        o.separator   &quot;Options:&quot;
+        o.separator   &quot;&quot;
+        o.on(         &quot;-s&quot;, &quot;--source=URL1,URL2&quot;, Array,
+                      &quot;Use the specified plugin repositories.&quot;) {|sources| @sources = sources}
+        o.on(         &quot;--local&quot;, 
+                      &quot;List locally installed plugins.&quot;) {|local| @local, @remote = local, false}
+        o.on(         &quot;--remote&quot;,
+                      &quot;List remotely available plugins. This is the default behavior&quot;,
+                      &quot;unless --local is provided.&quot;) {|remote| @remote = remote}
+      end
+    end
+    
+    def parse!(args)
+      options.order!(args)
+      unless @sources.empty?
+        @sources.map!{ |uri| Repository.new(uri) }
+      else
+        @sources = Repositories.instance.all
+      end
+      if @remote
+        @sources.map{|r| r.plugins}.flatten.each do |plugin| 
+          if @local or !plugin.installed?
+            puts plugin.to_s
+          end
+        end
+      else
+        cd &quot;#{@base_command.environment.root}/vendor/plugins&quot;
+        Dir[&quot;*&quot;].select{|p| File.directory?(p)}.each do |name| 
+          puts name
+        end
+      end
+    end
+  end
+  
+  
+  class Sources
+    def initialize(base_command)
+      @base_command = base_command
+    end
+    
+    def options
+      OptionParser.new do |o|
+        o.set_summary_indent('  ')
+        o.banner =    &quot;Usage: #{@base_command.script_name} sources [OPTIONS] [PATTERN]&quot;
+        o.define_head &quot;List configured plugin repositories.&quot;
+        o.separator   &quot;&quot;        
+        o.separator   &quot;Options:&quot;
+        o.separator   &quot;&quot;
+        o.on(         &quot;-c&quot;, &quot;--check&quot;, 
+                      &quot;Report status of repository.&quot;) { |sources| @sources = sources}
+      end
+    end
+    
+    def parse!(args)
+      options.parse!(args)
+      Repositories.each do |repo|
+        puts repo.uri
+      end
+    end
+  end
+  
+  
+  class Source
+    def initialize(base_command)
+      @base_command = base_command
+    end
+    
+    def options
+      OptionParser.new do |o|
+        o.set_summary_indent('  ')
+        o.banner =    &quot;Usage: #{@base_command.script_name} source REPOSITORY [REPOSITORY [REPOSITORY]...]&quot;
+        o.define_head &quot;Add new repositories to the default search list.&quot;
+      end
+    end
+    
+    def parse!(args)
+      options.parse!(args)
+      count = 0
+      args.each do |uri|
+        if Repositories.instance.add(uri)
+          puts &quot;added: #{uri.ljust(50)}&quot; if $verbose
+          count += 1
+        else
+          puts &quot;failed: #{uri.ljust(50)}&quot;
+        end
+      end
+      Repositories.instance.save
+      puts &quot;Added #{count} repositories.&quot;
+    end
+  end
+  
+  
+  class Unsource
+    def initialize(base_command)
+      @base_command = base_command
+    end
+    
+    def options
+      OptionParser.new do |o|
+        o.set_summary_indent('  ')
+        o.banner =    &quot;Usage: #{@base_command.script_name} unsource URI [URI [URI]...]&quot;
+        o.define_head &quot;Remove repositories from the default search list.&quot;
+        o.separator &quot;&quot;
+        o.on_tail(&quot;-h&quot;, &quot;--help&quot;, &quot;Show this help message.&quot;) { puts o; exit }
+      end
+    end
+    
+    def parse!(args)
+      options.parse!(args)
+      count = 0
+      args.each do |uri|
+        if Repositories.instance.remove(uri)
+          count += 1
+          puts &quot;removed: #{uri.ljust(50)}&quot;
+        else
+          puts &quot;failed: #{uri.ljust(50)}&quot;
+        end
+      end
+      Repositories.instance.save
+      puts &quot;Removed #{count} repositories.&quot;
+    end
+  end
+
+  
+  class Discover
+    def initialize(base_command)
+      @base_command = base_command
+      @list = false
+      @prompt = true
+    end
+    
+    def options
+      OptionParser.new do |o|
+        o.set_summary_indent('  ')
+        o.banner =    &quot;Usage: #{@base_command.script_name} discover URI [URI [URI]...]&quot;
+        o.define_head &quot;Discover repositories referenced on a page.&quot;
+        o.separator   &quot;&quot;        
+        o.separator   &quot;Options:&quot;
+        o.separator   &quot;&quot;
+        o.on(         &quot;-l&quot;, &quot;--list&quot;, 
+                      &quot;List but don't prompt or add discovered repositories.&quot;) { |list| @list, @prompt = list, !@list }
+        o.on(         &quot;-n&quot;, &quot;--no-prompt&quot;, 
+                      &quot;Add all new repositories without prompting.&quot;) { |v| @prompt = !v }
+      end
+    end
+
+    def parse!(args)
+      options.parse!(args)
+      args = ['http://wiki.rubyonrails.org/rails/pages/Plugins'] if args.empty?
+      args.each do |uri|
+        scrape(uri) do |repo_uri|
+          catch(:next_uri) do
+            if @prompt
+              begin
+                $stdout.print &quot;Add #{repo_uri}? [Y/n] &quot;
+                throw :next_uri if $stdin.gets !~ /^y?$/i
+              rescue Interrupt
+                $stdout.puts
+                exit 1
+              end
+            elsif @list
+              puts repo_uri
+              throw :next_uri
+            end
+            Repositories.instance.add(repo_uri)
+            puts &quot;discovered: #{repo_uri}&quot; if $verbose or !@prompt
+          end
+        end
+      end
+      Repositories.instance.save
+    end
+    
+    def scrape(uri)
+      require 'open-uri'
+      puts &quot;Scraping #{uri}&quot; if $verbose
+      dupes = []
+      content = open(uri).each do |line|
+        begin
+          if line =~ /&lt;a[^&gt;]*href=['&quot;]([^'&quot;]*)['&quot;]/ || line =~ /(svn:\/\/[^&lt;|\n]*)/
+            uri = $1
+            if uri =~ /^\w+:\/\// &amp;&amp; uri =~ /\/plugins\// &amp;&amp; uri !~ /\/browser\// &amp;&amp; uri !~ /^http:\/\/wiki\.rubyonrails/ &amp;&amp; uri !~ /http:\/\/instiki/
+              uri = extract_repository_uri(uri)
+              yield uri unless dupes.include?(uri) || Repositories.instance.exist?(uri)
+              dupes &lt;&lt; uri
+            end
+          end
+        rescue
+          puts &quot;Problems scraping '#{uri}': #{$!.to_s}&quot;
+        end
+      end
+    end
+    
+    def extract_repository_uri(uri)
+      uri.match(/(svn|https?):.*\/plugins\//i)[0]
+    end 
+  end
+  
   class Install
     def initialize(base_command)
       @base_command = base_command
@@ -426,6 +817,41 @@ module Commands
     end
   end
 
+  class Update
+    def initialize(base_command)
+      @base_command = base_command
+    end
+   
+    def options
+      OptionParser.new do |o|
+        o.set_summary_indent('  ')
+        o.banner =    &quot;Usage: #{@base_command.script_name} update [name [name]...]&quot;
+        o.on(         &quot;-r REVISION&quot;, &quot;--revision REVISION&quot;,
+                      &quot;Checks out the given revision from subversion.&quot;,
+                      &quot;Ignored if subversion is not used.&quot;) { |v| @revision = v }
+        o.define_head &quot;Update plugins.&quot;
+      end
+    end
+   
+    def parse!(args)
+      options.parse!(args)
+      root = @base_command.environment.root
+      cd root
+      args = Dir[&quot;vendor/plugins/*&quot;].map do |f|
+        File.directory?(&quot;#{f}/.svn&quot;) ? File.basename(f) : nil
+      end.compact if args.empty?
+      cd &quot;vendor/plugins&quot;
+      args.each do |name|
+        if File.directory?(name)
+          puts &quot;Updating plugin: #{name}&quot;
+          system(&quot;svn #{$verbose ? '' : '-q'} up \&quot;#{name}\&quot; #{@revision ? &quot;-r #{@revision}&quot; : ''}&quot;)
+        else
+          puts &quot;Plugin doesn't exist: #{name}&quot;
+        end
+      end
+    end
+  end
+
   class Remove
     def initialize(base_command)
       @base_command = base_command</diff>
      <filename>vendor/rails/railties/lib/commands/plugin.rb</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>vendor/rails/REVISION_ea8077c6427d208188f9cd11f88ebdc8f60dec28</filename>
    </removed>
    <removed>
      <filename>vendor/rails/actionpack/test/template/body_parts_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/rails/actionpack/test/template/output_buffer_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/rails/actionpack/test/template/template_test.rb</filename>
    </removed>
    <removed>
      <filename>vendor/rails/railties/guides/rails_guides/levenshtein.rb</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>cb34329da118b74e8f4c78e87bb316474f167059</id>
    </parent>
  </parents>
  <author>
    <name>binarylogic</name>
    <email>bjohnson@binarylogic.com</email>
  </author>
  <url>http://github.com/binarylogic/authlogic_example/commit/1e18650d32d2196e6d8e328858e822fd23a2812e</url>
  <id>1e18650d32d2196e6d8e328858e822fd23a2812e</id>
  <committed-date>2009-06-20T01:36:32-07:00</committed-date>
  <authored-date>2009-06-20T01:36:32-07:00</authored-date>
  <message>Update rails</message>
  <tree>c2bfbd8aefa5a5b7e2c8f0f0485aaf7f686b537d</tree>
  <committer>
    <name>binarylogic</name>
    <email>bjohnson@binarylogic.com</email>
  </committer>
</commit>
