[前][次][番号順一覧][スレッド一覧][生データ]

yarv-diff:129

From: ko1 atdot.net
Date: 31 Oct 2005 23:28:35 -0000
Subject: [yarv-diff:129] r286 - in trunk: . benchmark/other-lang lib

Author: ko1
Date: 2005-11-01 08:28:34 +0900 (Tue, 01 Nov 2005)
New Revision: 286

Added:
   trunk/lib/English.rb
   trunk/lib/cgi.rb
   trunk/lib/complex.rb
   trunk/lib/delegate.rb
Modified:
   trunk/ChangeLog
   trunk/benchmark/other-lang/eval.rb
Log:
	* benchmark/other-lang/eval.rb : fix path

	* lib/English.rb, lib/cgi.rb, lib/complex.rb, lib/delegate.rb : 
	added



Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2005-10-31 23:20:44 UTC (rev 285)
+++ trunk/ChangeLog	2005-10-31 23:28:34 UTC (rev 286)
@@ -5,6 +5,14 @@
 #
 
 
+2005-11-01(Tue) 08:28:19 +0900  Koichi Sasada  <ko1 atdot.net>
+
+	* benchmark/other-lang/eval.rb : fix path
+
+	* lib/English.rb, lib/cgi.rb, lib/complex.rb, lib/delegate.rb : 
+	added
+
+
 2005-11-01(Tue) 08:18:33 +0900  Koichi Sasada  <ko1 atdot.net>
 
 	* compile.c : push and pop values after checkincludearray for

Modified: trunk/benchmark/other-lang/eval.rb
===================================================================
--- trunk/benchmark/other-lang/eval.rb	2005-10-31 23:20:44 UTC (rev 285)
+++ trunk/benchmark/other-lang/eval.rb	2005-10-31 23:28:34 UTC (rev 286)
@@ -1,6 +1,6 @@
 
 Bench = %w(
-  loop2); %w(
+  loop
   ack
   fib
   tak
@@ -8,10 +8,8 @@
 )
 
 Lang = <<EOP.map{|l| l.strip}
-  yruby
-  yruby -I../rubyext/yarv/cygwin -I../rubyext/yarv -rite
-EOP
-<<EOP
+  ruby-cyg
+  ../../../build/miniruby
   perl
   python
   gosh
@@ -28,14 +26,11 @@
 p Bench
 p Lang
 
-
 require 'benchmark'
 
 def bench cmd
   m = Benchmark.measure{
-    # cmd
     #p cmd
-#    p cmd
     system(cmd)
   }
   [m.utime, m.real]

Added: trunk/lib/English.rb
===================================================================
--- trunk/lib/English.rb	2005-10-31 23:20:44 UTC (rev 285)
+++ trunk/lib/English.rb	2005-10-31 23:28:34 UTC (rev 286)
@@ -0,0 +1,155 @@
+#  Include the English library file in a Ruby script, and you can
+#  reference the global variables such as \VAR{\$\_} using less
+#  cryptic names, listed in the following table.% \vref{tab:english}.
+#
+#  Without 'English':
+#
+#      $\ = ' -- '
+#      "waterbuffalo" =~ /buff/
+#      print $", $', $$, "\n"
+#
+#  With English:
+#
+#      require "English"
+#      
+#      $OUTPUT_FIELD_SEPARATOR = ' -- '
+#      "waterbuffalo" =~ /buff/
+#      print $LOADED_FEATURES, $POSTMATCH, $PID, "\n"
+
+
+# The exception object passed to +raise+.
+alias $ERROR_INFO              $!
+
+# The stack backtrace generated by the last
+# exception. <tt>See Kernel.caller</tt> for details. Thread local.
+alias $ERROR_POSITION          $@
+
+# The default separator pattern used by <tt>String.split</tt>.  May be
+# set from the command line using the <tt>-F</tt> flag.
+alias $FS                      $;
+
+# The default separator pattern used by <tt>String.split</tt>.  May be
+# set from the command line using the <tt>-F</tt> flag.
+alias $FIELD_SEPARATOR         $;
+
+# The separator string output between the parameters to methods such
+# as <tt>Kernel.print</tt> and <tt>Array.join</tt>. Defaults to +nil+,
+# which adds no text.
+alias $OFS                     $,
+
+# The separator string output between the parameters to methods such
+# as <tt>Kernel.print</tt> and <tt>Array.join</tt>. Defaults to +nil+,
+# which adds no text.
+alias $OUTPUT_FIELD_SEPARATOR  $,
+
+# The input record separator (newline by default). This is the value
+# that routines such as <tt>Kernel.gets</tt> use to determine record
+# boundaries. If set to +nil+, +gets+ will read the entire file.
+alias $RS                      $/
+
+# The input record separator (newline by default). This is the value
+# that routines such as <tt>Kernel.gets</tt> use to determine record
+# boundaries. If set to +nil+, +gets+ will read the entire file.
+alias $INPUT_RECORD_SEPARATOR  $/
+
+# The string appended to the output of every call to methods such as
+# <tt>Kernel.print</tt> and <tt>IO.write</tt>. The default value is
+# +nil+.
+alias $ORS                     $\
+
+# The string appended to the output of every call to methods such as
+# <tt>Kernel.print</tt> and <tt>IO.write</tt>. The default value is
+# +nil+.
+alias $OUTPUT_RECORD_SEPARATOR $\
+
+# The number of the last line read from the current input file.
+alias $INPUT_LINE_NUMBER       $.
+
+# The number of the last line read from the current input file.
+alias $NR                      $.
+
+# The last line read by <tt>Kernel.gets</tt> or
+# <tt>Kernel.readline</tt>. Many string-related functions in the
+# +Kernel+ module operate on <tt>$_</tt> by default. The variable is
+# local to the current scope. Thread local.
+alias $LAST_READ_LINE          $_
+
+# The destination of output for <tt>Kernel.print</tt>
+# and <tt>Kernel.printf</tt>. The default value is
+# <tt>$stdout</tt>.
+alias $DEFAULT_OUTPUT          $>
+
+# An object that provides access to the concatenation
+# of the contents of all the files
+# given as command-line arguments, or <tt>$stdin</tt>
+# (in the case where there are no
+# arguments). <tt>$<</tt> supports methods similar to a 
+# +File+ object:
+# +inmode+, +close+,
+# <tt>closed?</tt>, +each+,
+# <tt>each_byte</tt>, <tt>each_line</tt>,
+# +eof+, <tt>eof?</tt>, +file+,
+# +filename+, +fileno+,
+# +getc+, +gets+, +lineno+,
+# <tt>lineno=</tt>, +path+, 
+# +pos+, <tt>pos=</tt>,
+# +read+, +readchar+,
+# +readline+, +readlines+,
+# +rewind+, +seek+, +skip+,
+# +tell+, <tt>to_a</tt>, <tt>to_i</tt>,
+# <tt>to_io</tt>, <tt>to_s</tt>, along with the
+# methods in +Enumerable+. The method +file+
+# returns a +File+ object for the file currently
+# being read. This may change as <tt>$<</tt> reads
+# through the files on the command line. Read only.
+alias $DEFAULT_INPUT           $<
+
+# The process number of the program being executed. Read only.
+alias $PID                     $$
+
+# The process number of the program being executed. Read only.
+alias $PROCESS_ID              $$
+
+# The exit status of the last child process to terminate. Read
+# only. Thread local.
+alias $CHILD_STATUS            $?
+
+# A +MatchData+ object that encapsulates the results of a successful
+# pattern match. The variables <tt>$&</tt>, <tt>$`</tt>, <tt>$'</tt>,
+# and <tt>$1</tt> to <tt>$9</tt> are all derived from
+# <tt>$~</tt>. Assigning to <tt>$~</tt> changes the values of these
+# derived variables.  This variable is local to the current
+# scope. Thread local.
+alias $LAST_MATCH_INFO         $~
+
+# If set to any value apart from +nil+ or +false+, all pattern matches
+# will be case insensitive, string comparisons will ignore case, and
+# string hash values will be case insensitive. Deprecated
+alias $IGNORECASE              $=
+
+# An array of strings containing the command-line
+# options from the invocation of the program. Options
+# used by the Ruby interpreter will have been
+# removed. Read only. Also known simply as +ARGV+.
+alias $ARGV                    $*
+
+# The string matched by the last successful pattern
+# match. This variable is local to the current
+# scope. Read only. Thread local.
+alias $MATCH                   $&
+
+# The string preceding the match in the last
+# successful pattern match. This variable is local to 
+# the current scope. Read only. Thread local.
+alias $PREMATCH                $`
+
+# The string following the match in the last
+# successful pattern match. This variable is local to 
+# the current scope. Read only. Thread local.
+alias $POSTMATCH               $'
+
+# The contents of the highest-numbered group matched in the last
+# successful pattern match. Thus, in <tt>"cat" =~ /(c|a)(t|z)/</tt>,
+# <tt>$+</tt> will be set to "t".  This variable is local to the
+# current scope. Read only. Thread local.
+alias $LAST_PAREN_MATCH        $+

Added: trunk/lib/cgi.rb
===================================================================
--- trunk/lib/cgi.rb	2005-10-31 23:20:44 UTC (rev 285)
+++ trunk/lib/cgi.rb	2005-10-31 23:28:34 UTC (rev 286)
@@ -0,0 +1,2312 @@
+# 
+# cgi.rb - cgi support library
+# 
+# Copyright (C) 2000  Network Applied Communication Laboratory, Inc.
+# 
+# Copyright (C) 2000  Information-technology Promotion Agency, Japan
+#
+# Author: Wakou Aoyama <wakou ruby-lang.org>
+#
+# Documentation: Wakou Aoyama (RDoc'd and embellished by William Webber) 
+# 
+# == Overview
+#
+# The Common Gateway Interface (CGI) is a simple protocol
+# for passing an HTTP request from a web server to a
+# standalone program, and returning the output to the web
+# browser.  Basically, a CGI program is called with the
+# parameters of the request passed in either in the
+# environment (GET) or via $stdin (POST), and everything
+# it prints to $stdout is returned to the client.
+# 
+# This file holds the +CGI+ class.  This class provides
+# functionality for retrieving HTTP request parameters,
+# managing cookies, and generating HTML output.  See the
+# class documentation for more details and examples of use.
+#
+# The file cgi/session.rb provides session management
+# functionality; see that file for more details.
+#
+# See http://www.w3.org/CGI/ for more information on the CGI
+# protocol.
+
+raise "Please, use ruby 1.5.4 or later." if RUBY_VERSION < "1.5.4"
+
+require 'English'
+
+# CGI class.  See documentation for the file cgi.rb for an overview
+# of the CGI protocol.
+#
+# == Introduction
+#
+# CGI is a large class, providing several categories of methods, many of which
+# are mixed in from other modules.  Some of the documentation is in this class,
+# some in the modules CGI::QueryExtension and CGI::HtmlExtension.  See
+# CGI::Cookie for specific information on handling cookies, and cgi/session.rb
+# (CGI::Session) for information on sessions.
+#
+# For queries, CGI provides methods to get at environmental variables,
+# parameters, cookies, and multipart request data.  For responses, CGI provides
+# methods for writing output and generating HTML.
+#
+# Read on for more details.  Examples are provided at the bottom.
+#
+# == Queries
+#
+# The CGI class dynamically mixes in parameter and cookie-parsing
+# functionality,  environmental variable access, and support for
+# parsing multipart requests (including uploaded files) from the
+# CGI::QueryExtension module.
+#
+# === Environmental Variables
+#
+# The standard CGI environmental variables are available as read-only
+# attributes of a CGI object.  The following is a list of these variables:
+#
+#
+#   AUTH_TYPE               HTTP_HOST          REMOTE_IDENT
+#   CONTENT_LENGTH          HTTP_NEGOTIATE     REMOTE_USER
+#   CONTENT_TYPE            HTTP_PRAGMA        REQUEST_METHOD
+#   GATEWAY_INTERFACE       HTTP_REFERER       SCRIPT_NAME
+#   HTTP_ACCEPT             HTTP_USER_AGENT    SERVER_NAME
+#   HTTP_ACCEPT_CHARSET     PATH_INFO          SERVER_PORT
+#   HTTP_ACCEPT_ENCODING    PATH_TRANSLATED    SERVER_PROTOCOL
+#   HTTP_ACCEPT_LANGUAGE    QUERY_STRING       SERVER_SOFTWARE
+#   HTTP_CACHE_CONTROL      REMOTE_ADDR
+#   HTTP_FROM               REMOTE_HOST
+#
+#
+# For each of these variables, there is a corresponding attribute with the
+# same name, except all lower case and without a preceding HTTP_.  
+# +content_length+ and +server_port+ are integers; the rest are strings.
+#
+# === Parameters
+#
+# The method #params() returns a hash of all parameters in the request as
+# name/value-list pairs, where the value-list is an Array of one or more
+# values.  The CGI object itself also behaves as a hash of parameter names 
+# to values, but only returns a single value (as a String) for each 
+# parameter name.
+#
+# For instance, suppose the request contains the parameter 
+# "favourite_colours" with the multiple values "blue" and "green".  The
+# following behaviour would occur:
+#
+#   cgi.params["favourite_colours"]  # => ["blue", "green"]
+#   cgi["favourite_colours"]         # => "blue"
+#
+# If a parameter does not exist, the former method will return an empty
+# array, the latter an empty string.  The simplest way to test for existence
+# of a parameter is by the #has_key? method.
+#
+# === Cookies
+#
+# HTTP Cookies are automatically parsed from the request.  They are available
+# from the #cookies() accessor, which returns a hash from cookie name to
+# CGI::Cookie object.
+#
+# === Multipart requests
+#
+# If a request's method is POST and its content type is multipart/form-data, 
+# then it may contain uploaded files.  These are stored by the QueryExtension
+# module in the parameters of the request.  The parameter name is the name
+# attribute of the file input field, as usual.  However, the value is not
+# a string, but an IO object, either an IOString for small files, or a
+# Tempfile for larger ones.  This object also has the additional singleton
+# methods:
+#
+# #local_path():: the path of the uploaded file on the local filesystem
+# #original_filename():: the name of the file on the client computer
+# #content_type():: the content type of the file
+#
+# == Responses
+#
+# The CGI class provides methods for sending header and content output to
+# the HTTP client, and mixes in methods for programmatic HTML generation
+# from CGI::HtmlExtension and CGI::TagMaker modules.  The precise version of HTML
+# to use for HTML generation is specified at object creation time.
+#
+# === Writing output
+#
+# The simplest way to send output to the HTTP client is using the #out() method.
+# This takes the HTTP headers as a hash parameter, and the body content
+# via a block.  The headers can be generated as a string using the #header()
+# method.  The output stream can be written directly to using the #print()
+# method.
+#
+# === Generating HTML
+#
+# Each HTML element has a corresponding method for generating that
+# element as a String.  The name of this method is the same as that
+# of the element, all lowercase.  The attributes of the element are 
+# passed in as a hash, and the body as a no-argument block that evaluates
+# to a String.  The HTML generation module knows which elements are
+# always empty, and silently drops any passed-in body.  It also knows
+# which elements require matching closing tags and which don't.  However,
+# it does not know what attributes are legal for which elements.
+#
+# There are also some additional HTML generation methods mixed in from
+# the CGI::HtmlExtension module.  These include individual methods for the
+# different types of form inputs, and methods for elements that commonly
+# take particular attributes where the attributes can be directly specified
+# as arguments, rather than via a hash.
+#
+# == Examples of use
+# 
+# === Get form values
+# 
+#   require "cgi"
+#   cgi = CGI.new
+#   value = cgi['field_name']   # <== value string for 'field_name'
+#     # if not 'field_name' included, then return "".
+#   fields = cgi.keys            # <== array of field names
+# 
+#   # returns true if form has 'field_name'
+#   cgi.has_key?('field_name')
+#   cgi.has_key?('field_name')
+#   cgi.include?('field_name')
+# 
+# CAUTION! cgi['field_name'] returned an Array with the old 
+# cgi.rb(included in ruby 1.6)
+# 
+# === Get form values as hash
+# 
+#   require "cgi"
+#   cgi = CGI.new
+#   params = cgi.params
+# 
+# cgi.params is a hash.
+# 
+#   cgi.params['new_field_name'] = ["value"]  # add new param
+#   cgi.params['field_name'] = ["new_value"]  # change value
+#   cgi.params.delete('field_name')           # delete param
+#   cgi.params.clear                          # delete all params
+# 
+# 
+# === Save form values to file
+# 
+#   require "pstore"
+#   db = PStore.new("query.db")
+#   db.transaction do
+#     db["params"] = cgi.params
+#   end
+# 
+# 
+# === Restore form values from file
+# 
+#   require "pstore"
+#   db = PStore.new("query.db")
+#   db.transaction do
+#     cgi.params = db["params"]
+#   end
+# 
+# 
+# === Get multipart form values
+# 
+#   require "cgi"
+#   cgi = CGI.new
+#   value = cgi['field_name']   # <== value string for 'field_name'
+#   value.read                  # <== body of value
+#   value.local_path            # <== path to local file of value
+#   value.original_filename     # <== original filename of value
+#   value.content_type          # <== content_type of value
+# 
+# and value has StringIO or Tempfile class methods.
+# 
+# === Get cookie values
+# 
+#   require "cgi"
+#   cgi = CGI.new
+#   values = cgi.cookies['name']  # <== array of 'name'
+#     # if not 'name' included, then return [].
+#   names = cgi.cookies.keys      # <== array of cookie names
+# 
+# and cgi.cookies is a hash.
+# 
+# === Get cookie objects
+# 
+#   require "cgi"
+#   cgi = CGI.new
+#   for name, cookie in cgi.cookies
+#     cookie.expires = Time.now + 30
+#   end
+#   cgi.out("cookie" => cgi.cookies) {"string"}
+# 
+#   cgi.cookies # { "name1" => cookie1, "name2" => cookie2, ... }
+# 
+#   require "cgi"
+#   cgi = CGI.new
+#   cgi.cookies['name'].expires = Time.now + 30
+#   cgi.out("cookie" => cgi.cookies['name']) {"string"}
+# 
+# === Print http header and html string to $DEFAULT_OUTPUT ($>)
+# 
+#   require "cgi"
+#   cgi = CGI.new("html3")  # add HTML generation methods
+#   cgi.out() do
+#     cgi.html() do
+#       cgi.head{ cgi.title{"TITLE"} } +
+#       cgi.body() do
+#         cgi.form() do
+#           cgi.textarea("get_text") +
+#           cgi.br +
+#           cgi.submit
+#         end +
+#         cgi.pre() do
+#           CGI::escapeHTML(
+#             "params: " + cgi.params.inspect + "\n" +
+#             "cookies: " + cgi.cookies.inspect + "\n" +
+#             ENV.collect() do |key, value|
+#               key + " --> " + value + "\n"
+#             end.join("")
+#           )
+#         end
+#       end
+#     end
+#   end
+# 
+#   # add HTML generation methods
+#   CGI.new("html3")    # html3.2
+#   CGI.new("html4")    # html4.01 (Strict)
+#   CGI.new("html4Tr")  # html4.01 Transitional
+#   CGI.new("html4Fr")  # html4.01 Frameset
+#
+class CGI
+
+  # :stopdoc:
+
+  # String for carriage return
+  CR  = "\015"
+
+  # String for linefeed
+  LF  = "\012"
+
+  # Standard internet newline sequence
+  EOL = CR + LF
+
+  REVISION = '$Id: cgi.rb,v 1.82 2005/09/17 15:59:46 matz Exp $' #:nodoc:
+
+  NEEDS_BINMODE = true if /WIN/ni.match(RUBY_PLATFORM) 
+
+  # Path separators in different environments.
+  PATH_SEPARATOR = {'UNIX'=>'/', 'WINDOWS'=>'\\', 'MACINTOSH'=>':'}
+
+  # HTTP status codes.
+  HTTP_STATUS = {
+    "OK"                  => "200 OK",
+    "PARTIAL_CONTENT"     => "206 Partial Content",
+    "MULTIPLE_CHOICES"    => "300 Multiple Choices",
+    "MOVED"               => "301 Moved Permanently",
+    "REDIRECT"            => "302 Found",
+    "NOT_MODIFIED"        => "304 Not Modified",
+    "BAD_REQUEST"         => "400 Bad Request",
+    "AUTH_REQUIRED"       => "401 Authorization Required",
+    "FORBIDDEN"           => "403 Forbidden",
+    "NOT_FOUND"           => "404 Not Found",
+    "METHOD_NOT_ALLOWED"  => "405 Method Not Allowed",
+    "NOT_ACCEPTABLE"      => "406 Not Acceptable",
+    "LENGTH_REQUIRED"     => "411 Length Required",
+    "PRECONDITION_FAILED" => "412 Rrecondition Failed",
+    "SERVER_ERROR"        => "500 Internal Server Error",
+    "NOT_IMPLEMENTED"     => "501 Method Not Implemented",
+    "BAD_GATEWAY"         => "502 Bad Gateway",
+    "VARIANT_ALSO_VARIES" => "506 Variant Also Negotiates"
+  }
+
+  # Abbreviated day-of-week names specified by RFC 822
+  RFC822_DAYS = %w[ Sun Mon Tue Wed Thu Fri Sat ]
+
+  # Abbreviated month names specified by RFC 822
+  RFC822_MONTHS = %w[ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec ]
+
+  # :startdoc:
+
+  def env_table 
+    ENV
+  end
+
+  def stdinput
+    $stdin
+  end
+
+  def stdoutput
+    $DEFAULT_OUTPUT
+  end
+
+  private :env_table, :stdinput, :stdoutput
+
+  # URL-encode a string.
+  #   url_encoded_string = CGI::escape("'Stop!' said Fred")
+  #      # => "%27Stop%21%27+said+Fred"
+  def CGI::escape(string)
+    string.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
+      '%' + $1.unpack('H2' * $1.size).join('%').upcase
+    end.tr(' ', '+')
+  end
+
+
+  # URL-decode a string.
+  #   string = CGI::unescape("%27Stop%21%27+said+Fred")
+  #      # => "'Stop!' said Fred"
+  def CGI::unescape(string)
+    string.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n) do
+      [$1.delete('%')].pack('H*')
+    end
+  end
+
+
+  # Escape special characters in HTML, namely &\"<>
+  #   CGI::escapeHTML('Usage: foo "bar" <baz>')
+  #      # => "Usage: foo &quot;bar&quot; &lt;baz&gt;"
+  def CGI::escapeHTML(string)
+    string.gsub(/&/n, '&amp;').gsub(/\"/n, '&quot;').gsub(/>/n, '&gt;').gsub(/</n, '&lt;')
+  end
+
+
+  # Unescape a string that has been HTML-escaped
+  #   CGI::unescapeHTML("Usage: foo &quot;bar&quot; &lt;baz&gt;")
+  #      # => "Usage: foo \"bar\" <baz>"
+  def CGI::unescapeHTML(string)
+    string.gsub(/&(.*?);/n) do
+      match = $1.dup
+      case match
+      when /\Aamp\z/ni           then '&'
+      when /\Aquot\z/ni          then '"'
+      when /\Agt\z/ni            then '>'
+      when /\Alt\z/ni            then '<'
+      when /\A#0*(\d+)\z/n       then
+        if Integer($1) < 256
+          Integer($1).chr
+        else
+          if Integer($1) < 65536 and ($KCODE[0] == ?u or $KCODE[0] == ?U)
+            [Integer($1)].pack("U")
+          else
+            "&##{$1};"
+          end
+        end
+      when /\A#x([0-9a-f]+)\z/ni then
+        if $1.hex < 256
+          $1.hex.chr
+        else
+          if $1.hex < 65536 and ($KCODE[0] == ?u or $KCODE[0] == ?U)
+            [$1.hex].pack("U")
+          else
+            "&#x#{$1};"
+          end
+        end
+      else
+        "&#{match};"
+      end
+    end
+  end
+  def CGI::escape_html(str)
+    escapeHTML(str)
+  end
+  def CGI::unescape_html(str)
+    unescapeHTML(str)
+  end
+
+  # Escape only the tags of certain HTML elements in +string+.
+  #
+  # Takes an element or elements or array of elements.  Each element
+  # is specified by the name of the element, without angle brackets.
+  # This matches both the start and the end tag of that element.
+  # The attribute list of the open tag will also be escaped (for
+  # instance, the double-quotes surrounding attribute values).
+  #
+  #   print CGI::escapeElement('<BR><A HREF="url"></A>', "A", "IMG")
+  #     # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"
+  #
+  #   print CGI::escapeElement('<BR><A HREF="url"></A>', ["A", "IMG"])
+  #     # "<BR>&lt;A HREF=&quot;url&quot;&gt;&lt;/A&gt"
+  def CGI::escapeElement(string, *elements)
+    elements = elements[0] if elements[0].kind_of?(Array)
+    unless elements.empty?
+      string.gsub(/<\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?>/ni) do
+        CGI::escapeHTML($&)
+      end
+    else
+      string
+    end
+  end
+
+
+  # Undo escaping such as that done by CGI::escapeElement()
+  #
+  #   print CGI::unescapeElement(
+  #           CGI::escapeHTML('<BR><A HREF="url"></A>'), "A", "IMG")
+  #     # "&lt;BR&gt;<A HREF="url"></A>"
+  # 
+  #   print CGI::unescapeElement(
+  #           CGI::escapeHTML('<BR><A HREF="url"></A>'), ["A", "IMG"])
+  #     # "&lt;BR&gt;<A HREF="url"></A>"
+  def CGI::unescapeElement(string, *elements)
+    elements = elements[0] if elements[0].kind_of?(Array)
+    unless elements.empty?
+      string.gsub(/&lt;\/?(?:#{elements.join("|")})(?!\w)(?:.|\n)*?&gt;/ni) do
+        CGI::unescapeHTML($&)
+      end
+    else
+      string
+    end
+  end
+  def CGI::escape_element(str)
+    escapeElement(str)
+  end
+  def CGI::unescape_element(str)
+    unescapeElement(str)
+  end
+
+  # Format a +Time+ object as a String using the format specified by RFC 1123.
+  #
+  #   CGI::rfc1123_date(Time.now)
+  #     # Sat, 01 Jan 2000 00:00:00 GMT
+  def CGI::rfc1123_date(time)
+    t = time.clone.gmtime
+    return format("%s, %.2d %s %.4d %.2d:%.2d:%.2d GMT",
+                RFC822_DAYS[t.wday], t.day, RFC822_MONTHS[t.month-1], t.year,
+                t.hour, t.min, t.sec)
+  end
+
+
+  # Create an HTTP header block as a string.
+  #
+  # Includes the empty line that ends the header block.
+  #
+  # +options+ can be a string specifying the Content-Type (defaults
+  # to text/html), or a hash of header key/value pairs.  The following
+  # header keys are recognized:
+  #
+  # type:: the Content-Type header.  Defaults to "text/html"
+  # charset:: the charset of the body, appended to the Content-Type header.
+  # nph:: a boolean value.  If true, prepend protocol string and status code, and
+  #       date; and sets default values for "server" and "connection" if not
+  #       explicitly set.
+  # status:: the HTTP status code, returned as the Status header.  See the
+  #          list of available status codes below.
+  # server:: the server software, returned as the Server header.
+  # connection:: the connection type, returned as the Connection header (for 
+  #              instance, "close".
+  # length:: the length of the content that will be sent, returned as the
+  #          Content-Length header.
+  # language:: the language of the content, returned as the Content-Language
+  #            header.
+  # expires:: the time on which the current content expires, as a +Time+
+  #           object, returned as the Expires header.
+  # cookie:: a cookie or cookies, returned as one or more Set-Cookie headers.
+  #          The value can be the literal string of the cookie; a CGI::Cookie
+  #          object; an Array of literal cookie strings or Cookie objects; or a 
+  #          hash all of whose values are literal cookie strings or Cookie objects.
+  #          These cookies are in addition to the cookies held in the
+  #          @output_cookies field.
+  #
+  # Other header lines can also be set; they are appended as key: value.
+  # 
+  #   header
+  #     # Content-Type: text/html
+  # 
+  #   header("text/plain")
+  #     # Content-Type: text/plain
+  # 
+  #   header("nph"        => true,
+  #          "status"     => "OK",  # == "200 OK"
+  #            # "status"     => "200 GOOD",
+  #          "server"     => ENV['SERVER_SOFTWARE'],
+  #          "connection" => "close",
+  #          "type"       => "text/html",
+  #          "charset"    => "iso-2022-jp",
+  #            # Content-Type: text/html; charset=iso-2022-jp
+  #          "length"     => 103,
+  #          "language"   => "ja",
+  #          "expires"    => Time.now + 30,
+  #          "cookie"     => [cookie1, cookie2],
+  #          "my_header1" => "my_value"
+  #          "my_header2" => "my_value")
+  # 
+  # The status codes are:
+  # 
+  #   "OK"                  --> "200 OK"
+  #   "PARTIAL_CONTENT"     --> "206 Partial Content"
+  #   "MULTIPLE_CHOICES"    --> "300 Multiple Choices"
+  #   "MOVED"               --> "301 Moved Permanently"
+  #   "REDIRECT"            --> "302 Found"
+  #   "NOT_MODIFIED"        --> "304 Not Modified"
+  #   "BAD_REQUEST"         --> "400 Bad Request"
+  #   "AUTH_REQUIRED"       --> "401 Authorization Required"
+  #   "FORBIDDEN"           --> "403 Forbidden"
+  #   "NOT_FOUND"           --> "404 Not Found"
+  #   "METHOD_NOT_ALLOWED"  --> "405 Method Not Allowed"
+  #   "NOT_ACCEPTABLE"      --> "406 Not Acceptable"
+  #   "LENGTH_REQUIRED"     --> "411 Length Required"
+  #   "PRECONDITION_FAILED" --> "412 Precondition Failed"
+  #   "SERVER_ERROR"        --> "500 Internal Server Error"
+  #   "NOT_IMPLEMENTED"     --> "501 Method Not Implemented"
+  #   "BAD_GATEWAY"         --> "502 Bad Gateway"
+  #   "VARIANT_ALSO_VARIES" --> "506 Variant Also Negotiates"
+  # 
+  # This method does not perform charset conversion. 
+  #
+  def header(options = "text/html")
+
+    buf = ""
+
+    case options
+    when String
+      options = { "type" => options }
+    when Hash
+      options = options.dup
+    end
+
+    unless options.has_key?("type")
+      options["type"] = "text/html"
+    end
+
+    if options.has_key?("charset")
+      options["type"] += "; charset=" + options.delete("charset")
+    end
+
+    options.delete("nph") if defined?(MOD_RUBY)
+    if options.delete("nph") or /IIS/n.match(env_table['SERVER_SOFTWARE'])
+      buf += (env_table["SERVER_PROTOCOL"] or "HTTP/1.0")  + " " +
+             (HTTP_STATUS[options["status"]] or options["status"] or "200 OK") +
+             EOL +
+             "Date: " + CGI::rfc1123_date(Time.now) + EOL
+
+      unless options.has_key?("server")
+        options["server"] = (env_table['SERVER_SOFTWARE'] or "")
+      end
+
+      unless options.has_key?("connection")
+        options["connection"] = "close"
+      end
+
+      options.delete("status")
+    end
+
+    if options.has_key?("status")
+      buf += "Status: " +
+             (HTTP_STATUS[options["status"]] or options["status"]) + EOL
+      options.delete("status")
+    end
+
+    if options.has_key?("server")
+      buf += "Server: " + options.delete("server") + EOL
+    end
+
+    if options.has_key?("connection")
+      buf += "Connection: " + options.delete("connection") + EOL
+    end
+
+    buf += "Content-Type: " + options.delete("type") + EOL
+
+    if options.has_key?("length")
+      buf += "Content-Length: " + options.delete("length").to_s + EOL
+    end
+
+    if options.has_key?("language")
+      buf += "Content-Language: " + options.delete("language") + EOL
+    end
+
+    if options.has_key?("expires")
+      buf += "Expires: " + CGI::rfc1123_date( options.delete("expires") ) + EOL
+    end
+
+    if options.has_key?("cookie")
+      if options["cookie"].kind_of?(String) or
+           options["cookie"].kind_of?(Cookie)
+        buf += "Set-Cookie: " + options.delete("cookie").to_s + EOL
+      elsif options["cookie"].kind_of?(Array)
+        options.delete("cookie").each{|cookie|
+          buf += "Set-Cookie: " + cookie.to_s + EOL
+        }
+      elsif options["cookie"].kind_of?(Hash)
+        options.delete("cookie").each_value{|cookie|
+          buf += "Set-Cookie: " + cookie.to_s + EOL
+        }
+      end
+    end
+    if @output_cookies
+      for cookie in @output_cookies
+        buf += "Set-Cookie: " + cookie.to_s + EOL
+      end
+    end
+
+    options.each{|key, value|
+      buf += key + ": " + value.to_s + EOL
+    }
+
+    if defined?(MOD_RUBY)
+      table = Apache::request.headers_out
+      buf.scan(/([^:]+): (.+)#{EOL}/n){ |name, value|
+        warn sprintf("name:%s value:%s\n", name, value) if $DEBUG
+        case name
+        when 'Set-Cookie'
+          table.add(name, value)
+        when /^status$/ni
+          Apache::request.status_line = value
+          Apache::request.status = value.to_i
+        when /^content-type$/ni
+          Apache::request.content_type = value
+        when /^content-encoding$/ni
+          Apache::request.content_encoding = value
+        when /^location$/ni
+	  if Apache::request.status == 200
+	    Apache::request.status = 302
+	  end
+          Apache::request.headers_out[name] = value
+        else
+          Apache::request.headers_out[name] = value
+        end
+      }
+      Apache::request.send_http_header
+      ''
+    else
+      buf + EOL
+    end
+
+  end # header()
+
+
+  # Print an HTTP header and body to $DEFAULT_OUTPUT ($>)
+  #
+  # The header is provided by +options+, as for #header().
+  # The body of the document is that returned by the passed-
+  # in block.  This block takes no arguments.  It is required.
+  #
+  #   cgi = CGI.new
+  #   cgi.out{ "string" }
+  #     # Content-Type: text/html
+  #     # Content-Length: 6
+  #     #
+  #     # string
+  # 
+  #   cgi.out("text/plain") { "string" }
+  #     # Content-Type: text/plain
+  #     # Content-Length: 6
+  #     #
+  #     # string
+  # 
+  #   cgi.out("nph"        => true,
+  #           "status"     => "OK",  # == "200 OK"
+  #           "server"     => ENV['SERVER_SOFTWARE'],
+  #           "connection" => "close",
+  #           "type"       => "text/html",
+  #           "charset"    => "iso-2022-jp",
+  #             # Content-Type: text/html; charset=iso-2022-jp
+  #           "language"   => "ja",
+  #           "expires"    => Time.now + (3600 * 24 * 30),
+  #           "cookie"     => [cookie1, cookie2],
+  #           "my_header1" => "my_value",
+  #           "my_header2" => "my_value") { "string" }
+  # 
+  # Content-Length is automatically calculated from the size of
+  # the String returned by the content block.
+  #
+  # If ENV['REQUEST_METHOD'] == "HEAD", then only the header
+  # is outputted (the content block is still required, but it
+  # is ignored).
+  # 
+  # If the charset is "iso-2022-jp" or "euc-jp" or "shift_jis" then
+  # the content is converted to this charset, and the language is set 
+  # to "ja".
+  def out(options = "text/html") # :yield:
+
+    options = { "type" => options } if options.kind_of?(String)
+    content = yield
+
+    if options.has_key?("charset")
+      # require "nkf"
+      case options["charset"]
+      when /iso-2022-jp/ni
+        #content = NKF::nkf('-j', content)
+        options["language"] = "ja" unless options.has_key?("language")
+      when /euc-jp/ni
+        #content = NKF::nkf('-e', content)
+        options["language"] = "ja" unless options.has_key?("language")
+      when /shift_jis/ni
+        #content = NKF::nkf('-s', content)
+        options["language"] = "ja" unless options.has_key?("language")
+      end
+    end
+
+    options["length"] = content.length.to_s
+    output = stdoutput
+    output.binmode if defined? output.binmode
+    output.print header(options)
+    output.print content unless "HEAD" == env_table['REQUEST_METHOD']
+  end
+
+
+  # Print an argument or list of arguments to the default output stream
+  #
+  #   cgi = CGI.new
+  #   cgi.print    # default:  cgi.print == $DEFAULT_OUTPUT.print
+  def print(*options)
+    stdoutput.print(*options)
+  end
+
+  require "delegate"
+
+  # Class representing an HTTP cookie.
+  #
+  # In addition to its specific fields and methods, a Cookie instance
+  # is a delegator to the array of its values.
+  #
+  # See RFC 2965.
+  #
+  # == Examples of use
+  #   cookie1 = CGI::Cookie::new("name", "value1", "value2", ...)
+  #   cookie1 = CGI::Cookie::new("name" => "name", "value" => "value")
+  #   cookie1 = CGI::Cookie::new('name'    => 'name',
+  #                              'value'   => ['value1', 'value2', ...],
+  #                              'path'    => 'path',   # optional
+  #                              'domain'  => 'domain', # optional
+  #                              'expires' => Time.now, # optional
+  #                              'secure'  => true      # optional
+  #                             )
+  # 
+  #   cgi.out("cookie" => [cookie1, cookie2]) { "string" }
+  # 
+  #   name    = cookie1.name
+  #   values  = cookie1.value
+  #   path    = cookie1.path
+  #   domain  = cookie1.domain
+  #   expires = cookie1.expires
+  #   secure  = cookie1.secure
+  # 
+  #   cookie1.name    = 'name'
+  #   cookie1.value   = ['value1', 'value2', ...]
+  #   cookie1.path    = 'path'
+  #   cookie1.domain  = 'domain'
+  #   cookie1.expires = Time.now + 30
+  #   cookie1.secure  = true
+  class Cookie < DelegateClass(Array)
+
+    # Create a new CGI::Cookie object.
+    #
+    # The contents of the cookie can be specified as a +name+ and one
+    # or more +value+ arguments.  Alternatively, the contents can
+    # be specified as a single hash argument.  The possible keywords of
+    # this hash are as follows:
+    #
+    # name:: the name of the cookie.  Required.
+    # value:: the cookie's value or list of values.
+    # path:: the path for which this cookie applies.  Defaults to the
+    #        base directory of the CGI script.
+    # domain:: the domain for which this cookie applies.
+    # expires:: the time at which this cookie expires, as a +Time+ object.
+    # secure:: whether this cookie is a secure cookie or not (default to
+    #          false).  Secure cookies are only transmitted to HTTPS 
+    #          servers.
+    #
+    # These keywords correspond to attributes of the cookie object.
+    def initialize(name = "", *value)
+      options = if name.kind_of?(String)
+                  { "name" => name, "value" => value }
+                else
+                  name
+                end
+      unless options.has_key?("name")
+        raise ArgumentError, "`name' required"
+      end
+
+      @name = options["name"]
+      @value = Array(options["value"])
+      # simple support for IE
+      if options["path"]
+        @path = options["path"]
+      else
+        %r|^(.*/)|.match(ENV["SCRIPT_NAME"])
+        @path = ($1 or "")
+      end
+      @domain = options["domain"]
+      @expires = options["expires"]
+      @secure = options["secure"] == true ? true : false
+
+      super(@value)
+    end
+
+    attr_accessor("name", "value", "path", "domain", "expires")
+    attr_reader("secure")
+
+    # Set whether the Cookie is a secure cookie or not.
+    #
+    # +val+ must be a boolean.
+    def secure=(val)
+      @secure = val if val == true or val == false
+      @secure
+    end
+
+    # Convert the Cookie to its string representation.
+    def to_s
+      buf = ""
+      buf += @name + '='
+
+      if @value.kind_of?(String)
+        buf += CGI::escape(@value)
+      else
+        buf += @value.collect{|v| CGI::escape(v) }.join("&")
+      end
+
+      if @domain
+        buf += '; domain=' + @domain
+      end
+
+      if @path
+        buf += '; path=' + @path
+      end
+
+      if @expires
+        buf += '; expires=' + CGI::rfc1123_date(@expires)
+      end
+
+      if @secure == true
+        buf += '; secure'
+      end
+
+      buf
+    end
+
+  end # class Cookie
+
+
+  # Parse a raw cookie string into a hash of cookie-name=>Cookie
+  # pairs.
+  #
+  #   cookies = CGI::Cookie::parse("raw_cookie_string")
+  #     # { "name1" => cookie1, "name2" => cookie2, ... }
+  #
+  def Cookie::parse(raw_cookie)
+    cookies = Hash.new([])
+    return cookies unless raw_cookie
+
+    raw_cookie.split(/[;,] /).each do |pairs|
+      name, values = pairs.split('=',2)
+      next unless name and values
+      name = CGI::unescape(name)
+      values ||= ""
+      values = values.split('&').collect{|v| CGI::unescape(v) }
+      if cookies.has_key?(name)
+        values = cookies[name].value + values
+      end
+      cookies[name] = Cookie::new({ "name" => name, "value" => values })
+    end
+
+    cookies
+  end
+
+  # Parse an HTTP query string into a hash of key=>value pairs.
+  #
+  #   params = CGI::parse("query_string")
+  #     # {"name1" => ["value1", "value2", ...],
+  #     #  "name2" => ["value1", "value2", ...], ... }
+  #
+  def CGI::parse(query)
+    params = Hash.new([].freeze)
+
+    query.split(/[&;]/n).each do |pairs|
+      key, value = pairs.split('=',2).collect{|v| CGI::unescape(v) }
+      if params.has_key?(key)
+        params[key].push(value)
+      else
+        params[key] = [value]
+      end
+    end
+
+    params
+  end
+
+  # Mixin module. It provides the follow functionality groups:
+  #
+  # 1. Access to CGI environment variables as methods.  See 
+  #    documentation to the CGI class for a list of these variables.
+  #
+  # 2. Access to cookies, including the cookies attribute.
+  #
+  # 3. Access to parameters, including the params attribute, and overloading
+  #    [] to perform parameter value lookup by key.
+  #
+  # 4. The initialize_query method, for initialising the above
+  #    mechanisms, handling multipart forms, and allowing the
+  #    class to be used in "offline" mode.
+  #
+  module QueryExtension
+
+    %w[ CONTENT_LENGTH SERVER_PORT ].each do |env|
+      eval %Q{
+        def #{env.sub(/^HTTP_/n, '').downcase}
+          (val = env_table[env]) && Integer(val)
+        end
+      }
+    end
+
+    %w[ AUTH_TYPE CONTENT_TYPE GATEWAY_INTERFACE PATH_INFO
+        PATH_TRANSLATED QUERY_STRING REMOTE_ADDR REMOTE_HOST
+        REMOTE_IDENT REMOTE_USER REQUEST_METHOD SCRIPT_NAME
+        SERVER_NAME SERVER_PROTOCOL SERVER_SOFTWARE
+
+        HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
+        HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM HTTP_HOST
+        HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env|
+          eval %Q{
+            def #{env.sub(/^HTTP_/n, '').downcase}
+              env_table['#{env}']
+            end
+          }
+        end
+
+    # Get the raw cookies as a string.
+    def raw_cookie
+      env_table["HTTP_COOKIE"]
+    end
+
+    # Get the raw RFC2965 cookies as a string.
+    def raw_cookie2
+      env_table["HTTP_COOKIE2"]
+    end
+
+    # Get the cookies as a hash of cookie-name=>Cookie pairs.
+    attr_accessor("cookies")
+
+    # Get the parameters as a hash of name=>values pairs, where
+    # values is an Array.
+    attr("params")
+
+    # Set all the parameters.
+    def params=(hash)
+      @params.clear
+      @params.update(hash)
+    end
+
+    def read_multipart(boundary, content_length)
+      params = Hash.new([])
+      boundary = "--" + boundary
+      buf = ""
+      bufsize = 10 * 1024
+
+      # start multipart/form-data
+      stdinput.binmode if defined? stdinput.binmode
+      boundary_size = boundary.size + EOL.size
+      content_length -= boundary_size
+      status = stdinput.read(boundary_size)
+      if nil == status
+        raise EOFError, "no content body"
+      elsif boundary + EOL != status
+        raise EOFError, "bad content body"
+      end
+
+      loop do
+        head = nil
+        if 10240 < content_length
+          require "tempfile"
+          body = Tempfile.new("CGI")
+        else
+          begin
+            require "stringio"
+            body = StringIO.new
+          rescue LoadError
+            require "tempfile"
+            body = Tempfile.new("CGI")
+          end
+        end
+        body.binmode if defined? body.binmode
+
+        until head and /#{boundary}(?:#{EOL}|--)/n.match(buf)
+
+          if (not head) and /#{EOL}#{EOL}/n.match(buf)
+            buf = buf.sub(/\A((?:.|\n)*?#{EOL})#{EOL}/n) do
+              head = $1.dup
+              ""
+            end
+            next
+          end
+
+          if head and ( (EOL + boundary + EOL).size < buf.size )
+            body.print buf[0 ... (buf.size - (EOL + boundary + EOL).size)]
+            buf[0 ... (buf.size - (EOL + boundary + EOL).size)] = ""
+          end
+
+          c = if bufsize < content_length
+                stdinput.read(bufsize)
+              else
+                stdinput.read(content_length)
+              end
+          if c.nil?
+            raise EOFError, "bad content body"
+          end
+          buf.concat(c)
+          content_length -= c.size
+        end
+
+        buf = buf.sub(/\A((?:.|\n)*?)(?:[\r\n]{1,2})?#{boundary}([\r\n]{1,2}|--)/n) do
+          body.print $1
+          if "--" == $2
+            content_length = -1
+          end
+          ""
+        end
+
+        body.rewind
+
+        /Content-Disposition:.* filename="?([^\";]*)"?/ni.match(head)
+	filename = ($1 or "")
+	if /Mac/ni.match(env_table['HTTP_USER_AGENT']) and
+	    /Mozilla/ni.match(env_table['HTTP_USER_AGENT']) and
+	    (not /MSIE/ni.match(env_table['HTTP_USER_AGENT']))
+	  filename = CGI::unescape(filename)
+	end
+        
+        /Content-Type: (.*)/ni.match(head)
+        content_type = ($1 or "")
+
+        (class << body; self; end).class_eval do
+          alias local_path path
+          define_method(:original_filename) {filename.dup.taint}
+          define_method(:content_type) {content_type.dup.taint}
+        end
+
+        /Content-Disposition:.* name="?([^\";]*)"?/ni.match(head)
+        name = $1.dup
+
+        if params.has_key?(name)
+          params[name].push(body)
+        else
+          params[name] = [body]
+        end
+        break if buf.size == 0
+        break if content_length === -1
+      end
+
+      params
+    end # read_multipart
+    private :read_multipart
+
+    # offline mode. read name=value pairs on standard input.
+    def read_from_cmdline
+      require "shellwords"
+
+      string =
+      if !ARGV.empty? || $no_offline
+        ARGV.join(' ')
+      else
+        if STDIN.tty?
+          STDERR.print(
+            %|(offline mode: enter name=value pairs on standard input)\n|
+          )
+        end
+        readlines.join(' ').gsub(/\n/n, '')
+      end.gsub(/\\=/n, '%3D').gsub(/\\&/n, '%26')
+
+      words = Shellwords.shellwords(string)
+
+      if words.find{|x| /=/n.match(x) }
+        words.join('&')
+      else
+        words.join('+')
+      end
+    end
+    private :read_from_cmdline
+
+    # Initialize the data from the query.
+    #
+    # Handles multipart forms (in particular, forms that involve file uploads).
+    # Reads query parameters in the @params field, and cookies into @cookies.
+    def initialize_query()
+      if ("POST" == env_table['REQUEST_METHOD']) and
+         %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?|n.match(env_table['CONTENT_TYPE'])
+        boundary = $1.dup
+        @multipart = true
+        @params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
+      else
+        @multipart = false
+        @params = CGI::parse(
+                    case env_table['REQUEST_METHOD']
+                    when "GET", "HEAD"
+                      if defined?(MOD_RUBY)
+                        Apache::request.args or ""
+                      else
+                        env_table['QUERY_STRING'] or ""
+                      end
+                    when "POST"
+                      stdinput.binmode if defined? stdinput.binmode
+                      stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or ''
+                    else
+                      read_from_cmdline
+                    end
+                  )
+      end
+
+      @cookies = CGI::Cookie::parse((env_table['HTTP_COOKIE'] or env_table['COOKIE']))
+    end
+    private :initialize_query
+
+    def multipart?
+      @multipart
+    end
+
+    module Value    # :nodoc:
+      def set_params(params)
+        @params = params
+      end
+      def [](idx, *args)
+        if args.size == 0
+          warn "#{caller(1)[0]}:CAUTION! cgi['key'] == cgi.params['key'][0]; if want Array, use cgi.params['key']"
+          @params[idx]
+        else
+          super[idx,*args]
+        end
+      end
+      def first
+        warn "#{caller(1)[0]}:CAUTION! cgi['key'] == cgi.params['key'][0]; if want Array, use cgi.params['key']"
+        self
+      end
+      alias last first
+      def to_a
+        @params || [self]
+      end
+      alias to_ary to_a   	# to be rhs of multiple assignment
+    end
+
+    # Get the value for the parameter with a given key.
+    #
+    # If the parameter has multiple values, only the first will be 
+    # retrieved; use #params() to get the array of values.
+    def [](key)
+      params = @params[key]
+      value = params[0]
+      if @multipart
+        if value
+          return value
+        elsif defined? StringIO
+          StringIO.new("")
+        else
+          Tempfile.new("CGI")
+        end
+      else
+        str = if value then value.dup else "" end
+        str.extend(Value)
+        str.set_params(params)
+        str
+      end
+    end
+
+    # Return all parameter keys as an array.
+    def keys(*args)
+      @params.keys(*args)
+    end
+
+    # Returns true if a given parameter key exists in the query.
+    def has_key?(*args)
+      @params.has_key?(*args)
+    end
+    alias key? has_key?
+    alias include? has_key?
+
+  end # QueryExtension
+
+
+  # Prettify (indent) an HTML string.
+  #
+  # +string+ is the HTML string to indent.  +shift+ is the indentation
+  # unit to use; it defaults to two spaces.
+  #
+  #   print CGI::pretty("<HTML><BODY></BODY></HTML>")
+  #     # <HTML>
+  #     #   <BODY>
+  #     #   </BODY>
+  #     # </HTML>
+  # 
+  #   print CGI::pretty("<HTML><BODY></BODY></HTML>", "\t")
+  #     # <HTML>
+  #     #         <BODY>
+  #     #         </BODY>
+  #     # </HTML>
+  #
+  def CGI::pretty(string, shift = "  ")
+    lines = string.gsub(/(?!\A)<(?:.|\n)*?>/n, "\n\\0").gsub(/<(?:.|\n)*?>(?!\n)/n, "\\0\n")
+    end_pos = 0
+    while end_pos = lines.index(/^<\/(\w+)/n, end_pos)
+      element = $1.dup
+      start_pos = lines.rindex(/^\s*<#{element}/ni, end_pos)
+      lines[start_pos ... end_pos] = "__" + lines[start_pos ... end_pos].gsub(/\n(?!\z)/n, "\n" + shift) + "__"
+    end
+    lines.gsub(/^((?:#{Regexp::quote(shift)})*)__(?=<\/?\w)/n, '\1')
+  end
+
+
+  # Base module for HTML-generation mixins.
+  #
+  # Provides methods for code generation for tags following
+  # the various DTD element types.
+  module TagMaker # :nodoc:
+
+    # Generate code for an element with required start and end tags.
+    #
+    #   - -
+    def nn_element_def(element)
+      nOE_element_def(element, <<-END)
+          if block_given?
+            yield.to_s
+          else
+            ""
+          end +
+          "</#{element.upcase}>"
+      END
+    end
+
+    # Generate code for an empty element.
+    #
+    #   - O EMPTY
+    def nOE_element_def(element, append = nil)
+      s = <<-END
+          "<#{element.upcase}" + attributes.collect{|name, value|
+            next unless value
+            " " + CGI::escapeHTML(name) +
+            if true == value
+              ""
+            else
+              '="' + CGI::escapeHTML(value) + '"'
+            end
+          }.to_s + ">"
+      END
+      s.sub!(/\Z/, " +") << append if append
+      s
+    end
+
+    # Generate code for an element for which the end (and possibly the
+    # start) tag is optional.
+    #
+    #   O O or - O
+    def nO_element_def(element)
+      nOE_element_def(element, <<-END)
+          if block_given?
+            yield.to_s + "</#{element.upcase}>"
+          else
+            ""
+          end
+      END
+    end
+
+  end # TagMaker
+
+
+  #
+  # Mixin module providing HTML generation methods.
+  #
+  # For example,
+  #   cgi.a("http://www.example.com") { "Example" }
+  #     # => "<A HREF=\"http://www.example.com\">Example</A>"
+  #
+  # Modules Http3, Http4, etc., contain more basic HTML-generation methods
+  # (:title, :center, etc.).
+  #
+  # See class CGI for a detailed example. 
+  #
+  module HtmlExtension
+
+
+    # Generate an Anchor element as a string.
+    #
+    # +href+ can either be a string, giving the URL
+    # for the HREF attribute, or it can be a hash of
+    # the element's attributes.
+    #
+    # The body of the element is the string returned by the no-argument
+    # block passed in.
+    #
+    #   a("http://www.example.com") { "Example" }
+    #     # => "<A HREF=\"http://www.example.com\">Example</A>"
+    #
+    #   a("HREF" => "http://www.example.com", "TARGET" => "_top") { "Example" }
+    #     # => "<A HREF=\"http://www.example.com\" TARGET=\"_top\">Example</A>"
+    #
+    def a(href = "") # :yield:
+      attributes = if href.kind_of?(String)
+                     { "HREF" => href }
+                   else
+                     href
+                   end
+      if block_given?
+        super(attributes){ yield }
+      else
+        super(attributes)
+      end
+    end
+
+    # Generate a Document Base URI element as a String. 
+    #
+    # +href+ can either by a string, giving the base URL for the HREF
+    # attribute, or it can be a has of the element's attributes.
+    #
+    # The passed-in no-argument block is ignored.
+    #
+    #   base("http://www.example.com/cgi")
+    #     # => "<BASE HREF=\"http://www.example.com/cgi\">"
+    def base(href = "") # :yield:
+      attributes = if href.kind_of?(String)
+                     { "HREF" => href }
+                   else
+                     href
+                   end
+      if block_given?
+        super(attributes){ yield }
+      else
+        super(attributes)
+      end
+    end
+
+    # Generate a BlockQuote element as a string.
+    #
+    # +cite+ can either be a string, give the URI for the source of
+    # the quoted text, or a hash, giving all attributes of the element,
+    # or it can be omitted, in which case the element has no attributes.
+    #
+    # The body is provided by the passed-in no-argument block
+    #
+    #   blockquote("http://www.example.com/quotes/foo.html") { "Foo!" }
+    #     #=> "<BLOCKQUOTE CITE=\"http://www.example.com/quotes/foo.html\">Foo!</BLOCKQUOTE>
+    def blockquote(cite = nil)  # :yield:
+      attributes = if cite.kind_of?(String)
+                     { "CITE" => cite }
+                   else
+                     cite or ""
+                   end
+      if block_given?
+        super(attributes){ yield }
+      else
+        super(attributes)
+      end
+    end
+
+
+    # Generate a Table Caption element as a string.
+    #
+    # +align+ can be a string, giving the alignment of the caption
+    # (one of top, bottom, left, or right).  It can be a hash of
+    # all the attributes of the element.  Or it can be omitted.
+    #
+    # The body of the element is provided by the passed-in no-argument block.
+    #
+    #   caption("left") { "Capital Cities" }
+    #     # => <CAPTION ALIGN=\"left\">Capital Cities</CAPTION>
+    def caption(align = nil) # :yield:
+      attributes = if align.kind_of?(String)
+                     { "ALIGN" => align }
+                   else
+                     align or ""
+                   end
+      if block_given?
+        super(attributes){ yield }
+      else
+        super(attributes)
+      end
+    end
+
+
+    # Generate a Checkbox Input element as a string.
+    #
+    # The attributes of the element can be specified as three arguments,
+    # +name+, +value+, and +checked+.  +checked+ is a boolean value;
+    # if true, the CHECKED attribute will be included in the element.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   checkbox("name")
+    #     # = checkbox("NAME" => "name")
+    # 
+    #   checkbox("name", "value")
+    #     # = checkbox("NAME" => "name", "VALUE" => "value")
+    # 
+    #   checkbox("name", "value", true)
+    #     # = checkbox("NAME" => "name", "VALUE" => "value", "CHECKED" => true)
+    def checkbox(name = "", value = nil, checked = nil)
+      attributes = if name.kind_of?(String)
+                     { "TYPE" => "checkbox", "NAME" => name,
+                       "VALUE" => value, "CHECKED" => checked }
+                   else
+                     name["TYPE"] = "checkbox"
+                     name
+                   end
+      input(attributes)
+    end
+
+    # Generate a sequence of checkbox elements, as a String.
+    #
+    # The checkboxes will all have the same +name+ attribute.
+    # Each checkbox is followed by a label.
+    # There will be one checkbox for each value.  Each value
+    # can be specified as a String, which will be used both
+    # as the value of the VALUE attribute and as the label
+    # for that checkbox.  A single-element array has the
+    # same effect.
+    #
+    # Each value can also be specified as a three-element array.
+    # The first element is the VALUE attribute; the second is the
+    # label; and the third is a boolean specifying whether this
+    # checkbox is CHECKED.
+    #
+    # Each value can also be specified as a two-element
+    # array, by omitting either the value element (defaults
+    # to the same as the label), or the boolean checked element
+    # (defaults to false).
+    #
+    #   checkbox_group("name", "foo", "bar", "baz")
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="bar">bar
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
+    # 
+    #   checkbox_group("name", ["foo"], ["bar", true], "baz")
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="foo">foo
+    #     # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="bar">bar
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="baz">baz
+    # 
+    #   checkbox_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="1">Foo
+    #     # <INPUT TYPE="checkbox" CHECKED NAME="name" VALUE="2">Bar
+    #     # <INPUT TYPE="checkbox" NAME="name" VALUE="Baz">Baz
+    # 
+    #   checkbox_group("NAME" => "name",
+    #                    "VALUES" => ["foo", "bar", "baz"])
+    # 
+    #   checkbox_group("NAME" => "name",
+    #                    "VALUES" => [["foo"], ["bar", true], "baz"])
+    # 
+    #   checkbox_group("NAME" => "name",
+    #                    "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
+    def checkbox_group(name = "", *values)
+      if name.kind_of?(Hash)
+        values = name["VALUES"]
+        name = name["NAME"]
+      end
+      values.collect{|value|
+        if value.kind_of?(String)
+          checkbox(name, value) + value
+        else
+          if value[value.size - 1] == true
+            checkbox(name, value[0], true) +
+            value[value.size - 2]
+          else
+            checkbox(name, value[0]) +
+            value[value.size - 1]
+          end
+        end
+      }.to_s
+    end
+
+
+    # Generate an File Upload Input element as a string.
+    #
+    # The attributes of the element can be specified as three arguments,
+    # +name+, +size+, and +maxlength+.  +maxlength+ is the maximum length
+    # of the file's _name_, not of the file's _contents_.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    # See #multipart_form() for forms that include file uploads.
+    #
+    #   file_field("name")
+    #     # <INPUT TYPE="file" NAME="name" SIZE="20">
+    # 
+    #   file_field("name", 40)
+    #     # <INPUT TYPE="file" NAME="name" SIZE="40">
+    # 
+    #   file_field("name", 40, 100)
+    #     # <INPUT TYPE="file" NAME="name" SIZE="40" MAXLENGTH="100">
+    # 
+    #   file_field("NAME" => "name", "SIZE" => 40)
+    #     # <INPUT TYPE="file" NAME="name" SIZE="40">
+    def file_field(name = "", size = 20, maxlength = nil)
+      attributes = if name.kind_of?(String)
+                     { "TYPE" => "file", "NAME" => name,
+                       "SIZE" => size.to_s }
+                   else
+                     name["TYPE"] = "file"
+                     name
+                   end
+      attributes["MAXLENGTH"] = maxlength.to_s if maxlength
+      input(attributes)
+    end
+
+
+    # Generate a Form element as a string.
+    #
+    # +method+ should be either "get" or "post", and defaults to the latter.
+    # +action+ defaults to the current CGI script name.  +enctype+
+    # defaults to "application/x-www-form-urlencoded".  
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    # See also #multipart_form() for forms that include file uploads.
+    #
+    #   form{ "string" }
+    #     # <FORM METHOD="post" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
+    # 
+    #   form("get") { "string" }
+    #     # <FORM METHOD="get" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
+    # 
+    #   form("get", "url") { "string" }
+    #     # <FORM METHOD="get" ACTION="url" ENCTYPE="application/x-www-form-urlencoded">string</FORM>
+    # 
+    #   form("METHOD" => "post", "ENCTYPE" => "enctype") { "string" }
+    #     # <FORM METHOD="post" ENCTYPE="enctype">string</FORM>
+    def form(method = "post", action = script_name, enctype = "application/x-www-form-urlencoded")
+      attributes = if method.kind_of?(String)
+                     { "METHOD" => method, "ACTION" => action,
+                       "ENCTYPE" => enctype } 
+                   else
+                     unless method.has_key?("METHOD")
+                       method["METHOD"] = "post"
+                     end
+                     unless method.has_key?("ENCTYPE")
+                       method["ENCTYPE"] = enctype
+                     end
+                     method
+                   end
+      if block_given?
+        body = yield
+      else
+        body = ""
+      end
+      if @output_hidden
+        body += @output_hidden.collect{|k,v|
+          "<INPUT TYPE=\"HIDDEN\" NAME=\"#{k}\" VALUE=\"#{v}\">"
+        }.to_s
+      end
+      super(attributes){body}
+    end
+
+    # Generate a Hidden Input element as a string.
+    #
+    # The attributes of the element can be specified as two arguments,
+    # +name+ and +value+.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   hidden("name")
+    #     # <INPUT TYPE="hidden" NAME="name">
+    # 
+    #   hidden("name", "value")
+    #     # <INPUT TYPE="hidden" NAME="name" VALUE="value">
+    # 
+    #   hidden("NAME" => "name", "VALUE" => "reset", "ID" => "foo")
+    #     # <INPUT TYPE="hidden" NAME="name" VALUE="value" ID="foo">
+    def hidden(name = "", value = nil)
+      attributes = if name.kind_of?(String)
+                     { "TYPE" => "hidden", "NAME" => name, "VALUE" => value }
+                   else
+                     name["TYPE"] = "hidden"
+                     name
+                   end
+      input(attributes)
+    end
+
+    # Generate a top-level HTML element as a string.
+    #
+    # The attributes of the element are specified as a hash.  The
+    # pseudo-attribute "PRETTY" can be used to specify that the generated
+    # HTML string should be indented.  "PRETTY" can also be specified as
+    # a string as the sole argument to this method.  The pseudo-attribute
+    # "DOCTYPE", if given, is used as the leading DOCTYPE SGML tag; it
+    # should include the entire text of this tag, including angle brackets.
+    #
+    # The body of the html element is supplied as a block.
+    # 
+    #   html{ "string" }
+    #     # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML>string</HTML>
+    # 
+    #   html("LANG" => "ja") { "string" }
+    #     # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><HTML LANG="ja">string</HTML>
+    # 
+    #   html("DOCTYPE" => false) { "string" }
+    #     # <HTML>string</HTML>
+    # 
+    #   html("DOCTYPE" => '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">') { "string" }
+    #     # <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"><HTML>string</HTML>
+    # 
+    #   html("PRETTY" => "  ") { "<BODY></BODY>" }
+    #     # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+    #     # <HTML>
+    #     #   <BODY>
+    #     #   </BODY>
+    #     # </HTML>
+    # 
+    #   html("PRETTY" => "\t") { "<BODY></BODY>" }
+    #     # <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+    #     # <HTML>
+    #     #         <BODY>
+    #     #         </BODY>
+    #     # </HTML>
+    # 
+    #   html("PRETTY") { "<BODY></BODY>" }
+    #     # = html("PRETTY" => "  ") { "<BODY></BODY>" }
+    # 
+    #   html(if $VERBOSE then "PRETTY" end) { "HTML string" }
+    #
+    def html(attributes = {}) # :yield:
+      if nil == attributes
+        attributes = {}
+      elsif "PRETTY" == attributes
+        attributes = { "PRETTY" => true }
+      end
+      pretty = attributes.delete("PRETTY")
+      pretty = "  " if true == pretty
+      buf = ""
+
+      if attributes.has_key?("DOCTYPE")
+        if attributes["DOCTYPE"]
+          buf += attributes.delete("DOCTYPE")
+        else
+          attributes.delete("DOCTYPE")
+        end
+      else
+        buf += doctype
+      end
+
+      if block_given?
+        buf += super(attributes){ yield }
+      else
+        buf += super(attributes)
+      end
+
+      if pretty
+        CGI::pretty(buf, pretty)
+      else
+        buf
+      end
+
+    end
+
+    # Generate an Image Button Input element as a string.
+    #
+    # +src+ is the URL of the image to use for the button.  +name+ 
+    # is the input name.  +alt+ is the alternative text for the image.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    # 
+    #   image_button("url")
+    #     # <INPUT TYPE="image" SRC="url">
+    # 
+    #   image_button("url", "name", "string")
+    #     # <INPUT TYPE="image" SRC="url" NAME="name" ALT="string">
+    # 
+    #   image_button("SRC" => "url", "ATL" => "strng")
+    #     # <INPUT TYPE="image" SRC="url" ALT="string">
+    def image_button(src = "", name = nil, alt = nil)
+      attributes = if src.kind_of?(String)
+                     { "TYPE" => "image", "SRC" => src, "NAME" => name,
+                       "ALT" => alt }
+                   else
+                     src["TYPE"] = "image"
+                     src["SRC"] ||= ""
+                     src
+                   end
+      input(attributes)
+    end
+
+
+    # Generate an Image element as a string.
+    #
+    # +src+ is the URL of the image.  +alt+ is the alternative text for
+    # the image.  +width+ is the width of the image, and +height+ is
+    # its height.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   img("src", "alt", 100, 50)
+    #     # <IMG SRC="src" ALT="alt" WIDTH="100" HEIGHT="50">
+    # 
+    #   img("SRC" => "src", "ALT" => "alt", "WIDTH" => 100, "HEIGHT" => 50)
+    #     # <IMG SRC="src" ALT="alt" WIDTH="100" HEIGHT="50">
+    def img(src = "", alt = "", width = nil, height = nil)
+      attributes = if src.kind_of?(String)
+                     { "SRC" => src, "ALT" => alt }
+                   else
+                     src
+                   end
+      attributes["WIDTH"] = width.to_s if width
+      attributes["HEIGHT"] = height.to_s if height
+      super(attributes)
+    end
+
+
+    # Generate a Form element with multipart encoding as a String.
+    #
+    # Multipart encoding is used for forms that include file uploads.
+    #
+    # +action+ is the action to perform.  +enctype+ is the encoding
+    # type, which defaults to "multipart/form-data".
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   multipart_form{ "string" }
+    #     # <FORM METHOD="post" ENCTYPE="multipart/form-data">string</FORM>
+    # 
+    #   multipart_form("url") { "string" }
+    #     # <FORM METHOD="post" ACTION="url" ENCTYPE="multipart/form-data">string</FORM>
+    def multipart_form(action = nil, enctype = "multipart/form-data")
+      attributes = if action == nil
+                     { "METHOD" => "post", "ENCTYPE" => enctype } 
+                   elsif action.kind_of?(String)
+                     { "METHOD" => "post", "ACTION" => action,
+                       "ENCTYPE" => enctype } 
+                   else
+                     unless action.has_key?("METHOD")
+                       action["METHOD"] = "post"
+                     end
+                     unless action.has_key?("ENCTYPE")
+                       action["ENCTYPE"] = enctype
+                     end
+                     action
+                   end
+      if block_given?
+        form(attributes){ yield }
+      else
+        form(attributes)
+      end
+    end
+
+
+    # Generate a Password Input element as a string.
+    #
+    # +name+ is the name of the input field.  +value+ is its default
+    # value.  +size+ is the size of the input field display.  +maxlength+
+    # is the maximum length of the inputted password.
+    #
+    # Alternatively, attributes can be specified as a hash.
+    #
+    #   password_field("name")
+    #     # <INPUT TYPE="password" NAME="name" SIZE="40">
+    # 
+    #   password_field("name", "value")
+    #     # <INPUT TYPE="password" NAME="name" VALUE="value" SIZE="40">
+    # 
+    #   password_field("password", "value", 80, 200)
+    #     # <INPUT TYPE="password" NAME="name" VALUE="value" SIZE="80" MAXLENGTH="200">
+    # 
+    #   password_field("NAME" => "name", "VALUE" => "value")
+    #     # <INPUT TYPE="password" NAME="name" VALUE="value">
+    def password_field(name = "", value = nil, size = 40, maxlength = nil)
+      attributes = if name.kind_of?(String)
+                     { "TYPE" => "password", "NAME" => name,
+                       "VALUE" => value, "SIZE" => size.to_s }
+                   else
+                     name["TYPE"] = "password"
+                     name
+                   end
+      attributes["MAXLENGTH"] = maxlength.to_s if maxlength
+      input(attributes)
+    end
+
+    # Generate a Select element as a string.
+    #
+    # +name+ is the name of the element.  The +values+ are the options that
+    # can be selected from the Select menu.  Each value can be a String or
+    # a one, two, or three-element Array.  If a String or a one-element
+    # Array, this is both the value of that option and the text displayed for
+    # it.  If a three-element Array, the elements are the option value, displayed
+    # text, and a boolean value specifying whether this option starts as selected.
+    # The two-element version omits either the option value (defaults to the same
+    # as the display text) or the boolean selected specifier (defaults to false).
+    #
+    # The attributes and options can also be specified as a hash.  In this
+    # case, options are specified as an array of values as described above,
+    # with the hash key of "VALUES".
+    #
+    #   popup_menu("name", "foo", "bar", "baz")
+    #     # <SELECT NAME="name">
+    #     #   <OPTION VALUE="foo">foo</OPTION>
+    #     #   <OPTION VALUE="bar">bar</OPTION>
+    #     #   <OPTION VALUE="baz">baz</OPTION>
+    #     # </SELECT>
+    # 
+    #   popup_menu("name", ["foo"], ["bar", true], "baz")
+    #     # <SELECT NAME="name">
+    #     #   <OPTION VALUE="foo">foo</OPTION>
+    #     #   <OPTION VALUE="bar" SELECTED>bar</OPTION>
+    #     #   <OPTION VALUE="baz">baz</OPTION>
+    #     # </SELECT>
+    # 
+    #   popup_menu("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
+    #     # <SELECT NAME="name">
+    #     #   <OPTION VALUE="1">Foo</OPTION>
+    #     #   <OPTION SELECTED VALUE="2">Bar</OPTION>
+    #     #   <OPTION VALUE="Baz">Baz</OPTION>
+    #     # </SELECT>
+    # 
+    #   popup_menu("NAME" => "name", "SIZE" => 2, "MULTIPLE" => true,
+    #               "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
+    #     # <SELECT NAME="name" MULTIPLE SIZE="2">
+    #     #   <OPTION VALUE="1">Foo</OPTION>
+    #     #   <OPTION SELECTED VALUE="2">Bar</OPTION>
+    #     #   <OPTION VALUE="Baz">Baz</OPTION>
+    #     # </SELECT>
+    def popup_menu(name = "", *values)
+
+      if name.kind_of?(Hash)
+        values   = name["VALUES"]
+        size     = name["SIZE"].to_s if name["SIZE"]
+        multiple = name["MULTIPLE"]
+        name     = name["NAME"]
+      else
+        size = nil
+        multiple = nil
+      end
+
+      select({ "NAME" => name, "SIZE" => size,
+               "MULTIPLE" => multiple }){
+        values.collect{|value|
+          if value.kind_of?(String)
+            option({ "VALUE" => value }){ value }
+          else
+            if value[value.size - 1] == true
+              option({ "VALUE" => value[0], "SELECTED" => true }){
+                value[value.size - 2]
+              }
+            else
+              option({ "VALUE" => value[0] }){
+                value[value.size - 1]
+              }
+            end
+          end
+        }.to_s
+      }
+
+    end
+
+    # Generates a radio-button Input element.
+    #
+    # +name+ is the name of the input field.  +value+ is the value of
+    # the field if checked.  +checked+ specifies whether the field
+    # starts off checked.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   radio_button("name", "value")
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="value">
+    # 
+    #   radio_button("name", "value", true)
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="value" CHECKED>
+    # 
+    #   radio_button("NAME" => "name", "VALUE" => "value", "ID" => "foo")
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="value" ID="foo">
+    def radio_button(name = "", value = nil, checked = nil)
+      attributes = if name.kind_of?(String)
+                     { "TYPE" => "radio", "NAME" => name,
+                       "VALUE" => value, "CHECKED" => checked }
+                   else
+                     name["TYPE"] = "radio"
+                     name
+                   end
+      input(attributes)
+    end
+
+    # Generate a sequence of radio button Input elements, as a String.
+    #
+    # This works the same as #checkbox_group().  However, it is not valid
+    # to have more than one radiobutton in a group checked.
+    # 
+    #   radio_group("name", "foo", "bar", "baz")
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="bar">bar
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
+    # 
+    #   radio_group("name", ["foo"], ["bar", true], "baz")
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="foo">foo
+    #     # <INPUT TYPE="radio" CHECKED NAME="name" VALUE="bar">bar
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="baz">baz
+    # 
+    #   radio_group("name", ["1", "Foo"], ["2", "Bar", true], "Baz")
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="1">Foo
+    #     # <INPUT TYPE="radio" CHECKED NAME="name" VALUE="2">Bar
+    #     # <INPUT TYPE="radio" NAME="name" VALUE="Baz">Baz
+    # 
+    #   radio_group("NAME" => "name",
+    #                 "VALUES" => ["foo", "bar", "baz"])
+    # 
+    #   radio_group("NAME" => "name",
+    #                 "VALUES" => [["foo"], ["bar", true], "baz"])
+    # 
+    #   radio_group("NAME" => "name",
+    #                 "VALUES" => [["1", "Foo"], ["2", "Bar", true], "Baz"])
+    def radio_group(name = "", *values)
+      if name.kind_of?(Hash)
+        values = name["VALUES"]
+        name = name["NAME"]
+      end
+      values.collect{|value|
+        if value.kind_of?(String)
+          radio_button(name, value) + value
+        else
+          if value[value.size - 1] == true
+            radio_button(name, value[0], true) +
+            value[value.size - 2]
+          else
+            radio_button(name, value[0]) +
+            value[value.size - 1]
+          end
+        end
+      }.to_s
+    end
+
+    # Generate a reset button Input element, as a String.
+    #
+    # This resets the values on a form to their initial values.  +value+
+    # is the text displayed on the button. +name+ is the name of this button.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   reset
+    #     # <INPUT TYPE="reset">
+    # 
+    #   reset("reset")
+    #     # <INPUT TYPE="reset" VALUE="reset">
+    # 
+    #   reset("VALUE" => "reset", "ID" => "foo")
+    #     # <INPUT TYPE="reset" VALUE="reset" ID="foo">
+    def reset(value = nil, name = nil)
+      attributes = if (not value) or value.kind_of?(String)
+                     { "TYPE" => "reset", "VALUE" => value, "NAME" => name }
+                   else
+                     value["TYPE"] = "reset"
+                     value
+                   end
+      input(attributes)
+    end
+
+    alias scrolling_list popup_menu
+
+    # Generate a submit button Input element, as a String.
+    #
+    # +value+ is the text to display on the button.  +name+ is the name
+    # of the input.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   submit
+    #     # <INPUT TYPE="submit">
+    # 
+    #   submit("ok")
+    #     # <INPUT TYPE="submit" VALUE="ok">
+    # 
+    #   submit("ok", "button1")
+    #     # <INPUT TYPE="submit" VALUE="ok" NAME="button1">
+    # 
+    #   submit("VALUE" => "ok", "NAME" => "button1", "ID" => "foo")
+    #     # <INPUT TYPE="submit" VALUE="ok" NAME="button1" ID="foo">
+    def submit(value = nil, name = nil)
+      attributes = if (not value) or value.kind_of?(String)
+                     { "TYPE" => "submit", "VALUE" => value, "NAME" => name }
+                   else
+                     value["TYPE"] = "submit"
+                     value
+                   end
+      input(attributes)
+    end
+
+    # Generate a text field Input element, as a String.
+    #
+    # +name+ is the name of the input field.  +value+ is its initial
+    # value.  +size+ is the size of the input area.  +maxlength+
+    # is the maximum length of input accepted.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    #   text_field("name")
+    #     # <INPUT TYPE="text" NAME="name" SIZE="40">
+    # 
+    #   text_field("name", "value")
+    #     # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="40">
+    # 
+    #   text_field("name", "value", 80)
+    #     # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="80">
+    # 
+    #   text_field("name", "value", 80, 200)
+    #     # <INPUT TYPE="text" NAME="name" VALUE="value" SIZE="80" MAXLENGTH="200">
+    # 
+    #   text_field("NAME" => "name", "VALUE" => "value")
+    #     # <INPUT TYPE="text" NAME="name" VALUE="value">
+    def text_field(name = "", value = nil, size = 40, maxlength = nil)
+      attributes = if name.kind_of?(String)
+                     { "TYPE" => "text", "NAME" => name, "VALUE" => value,
+                       "SIZE" => size.to_s }
+                   else
+                     name["TYPE"] = "text"
+                     name
+                   end
+      attributes["MAXLENGTH"] = maxlength.to_s if maxlength
+      input(attributes)
+    end
+
+    # Generate a TextArea element, as a String.
+    #
+    # +name+ is the name of the textarea.  +cols+ is the number of
+    # columns and +rows+ is the number of rows in the display.
+    #
+    # Alternatively, the attributes can be specified as a hash.
+    #
+    # The body is provided by the passed-in no-argument block
+    #
+    #   textarea("name")
+    #      # = textarea("NAME" => "name", "COLS" => 70, "ROWS" => 10)
+    #
+    #   textarea("name", 40, 5)
+    #      # = textarea("NAME" => "name", "COLS" => 40, "ROWS" => 5)
+    def textarea(name = "", cols = 70, rows = 10)  # :yield:
+      attributes = if name.kind_of?(String)
+                     { "NAME" => name, "COLS" => cols.to_s,
+                       "ROWS" => rows.to_s }
+                   else
+                     name
+                   end
+      if block_given?
+        super(attributes){ yield }
+      else
+        super(attributes)
+      end
+    end
+
+  end # HtmlExtension
+
+
+  # Mixin module for HTML version 3 generation methods.
+  module Html3 # :nodoc:
+
+    # The DOCTYPE declaration for this version of HTML
+    def doctype
+      %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">|
+    end
+
+    # Initialise the HTML generation methods for this version.
+    def element_init
+      extend TagMaker
+      methods = ""
+      # - -
+      for element in %w[ A TT I B U STRIKE BIG SMALL SUB SUP EM STRONG
+          DFN CODE SAMP KBD VAR CITE FONT ADDRESS DIV center MAP
+          APPLET PRE XMP LISTING DL OL UL DIR MENU SELECT table TITLE
+          STYLE SCRIPT H1 H2 H3 H4 H5 H6 TEXTAREA FORM BLOCKQUOTE
+          CAPTION ]
+        methods += <<-BEGIN + nn_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # - O EMPTY
+      for element in %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT
+          ISINDEX META ]
+        methods += <<-BEGIN + nOE_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # O O or - O
+      for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD LI OPTION tr
+          th td ]
+        methods += <<-BEGIN + nO_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+      eval(methods)
+    end
+
+  end # Html3
+
+
+  # Mixin module for HTML version 4 generation methods.
+  module Html4 # :nodoc:
+
+    # The DOCTYPE declaration for this version of HTML
+    def doctype
+      %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">|
+    end
+
+    # Initialise the HTML generation methods for this version.
+    def element_init
+      extend TagMaker
+      methods = ""
+      # - -
+      for element in %w[ TT I B BIG SMALL EM STRONG DFN CODE SAMP KBD
+        VAR CITE ABBR ACRONYM SUB SUP SPAN BDO ADDRESS DIV MAP OBJECT
+        H1 H2 H3 H4 H5 H6 PRE Q INS DEL DL OL UL LABEL SELECT OPTGROUP
+        FIELDSET LEGEND BUTTON TABLE TITLE STYLE SCRIPT NOSCRIPT
+        TEXTAREA FORM A BLOCKQUOTE CAPTION ]
+        methods += <<-BEGIN + nn_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # - O EMPTY
+      for element in %w[ IMG BASE BR AREA LINK PARAM HR INPUT COL META ]
+        methods += <<-BEGIN + nOE_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # O O or - O
+      for element in %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY
+          COLGROUP TR TH TD HEAD]
+        methods += <<-BEGIN + nO_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+      eval(methods)
+    end
+
+  end # Html4
+
+
+  # Mixin module for HTML version 4 transitional generation methods.
+  module Html4Tr # :nodoc:
+
+    # The DOCTYPE declaration for this version of HTML
+    def doctype
+      %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">|
+    end
+
+    # Initialise the HTML generation methods for this version.
+    def element_init
+      extend TagMaker
+      methods = ""
+      # - -
+      for element in %w[ TT I B U S STRIKE BIG SMALL EM STRONG DFN
+          CODE SAMP KBD VAR CITE ABBR ACRONYM FONT SUB SUP SPAN BDO
+          ADDRESS DIV CENTER MAP OBJECT APPLET H1 H2 H3 H4 H5 H6 PRE Q
+          INS DEL DL OL UL DIR MENU LABEL SELECT OPTGROUP FIELDSET
+          LEGEND BUTTON TABLE IFRAME NOFRAMES TITLE STYLE SCRIPT
+          NOSCRIPT TEXTAREA FORM A BLOCKQUOTE CAPTION ]
+        methods += <<-BEGIN + nn_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # - O EMPTY
+      for element in %w[ IMG BASE BASEFONT BR AREA LINK PARAM HR INPUT
+          COL ISINDEX META ]
+        methods += <<-BEGIN + nOE_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # O O or - O
+      for element in %w[ HTML BODY P DT DD LI OPTION THEAD TFOOT TBODY
+          COLGROUP TR TH TD HEAD ]
+        methods += <<-BEGIN + nO_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+      eval(methods)
+    end
+
+  end # Html4Tr
+
+
+  # Mixin module for generating HTML version 4 with framesets.
+  module Html4Fr # :nodoc:
+
+    # The DOCTYPE declaration for this version of HTML
+    def doctype
+      %|<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">|
+    end
+
+    # Initialise the HTML generation methods for this version.
+    def element_init
+      methods = ""
+      # - -
+      for element in %w[ FRAMESET ]
+        methods += <<-BEGIN + nn_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+
+      # - O EMPTY
+      for element in %w[ FRAME ]
+        methods += <<-BEGIN + nOE_element_def(element) + <<-END
+          def #{element.downcase}(attributes = {})
+        BEGIN
+          end
+        END
+      end
+      eval(methods)
+    end
+
+  end # Html4Fr
+
+
+  # Creates a new CGI instance.
+  #
+  # +type+ specifies which version of HTML to load the HTML generation
+  # methods for.  The following versions of HTML are supported:
+  #
+  # html3:: HTML 3.x
+  # html4:: HTML 4.0
+  # html4Tr:: HTML 4.0 Transitional
+  # html4Fr:: HTML 4.0 with Framesets
+  #
+  # If not specified, no HTML generation methods will be loaded.
+  #
+  # If the CGI object is not created in a standard CGI call environment
+  # (that is, it can't locate REQUEST_METHOD in its environment), then
+  # it will run in "offline" mode.  In this mode, it reads its parameters
+  # from the command line or (failing that) from standard input.  Otherwise,
+  # cookies and other parameters are parsed automatically from the standard
+  # CGI locations, which varies according to the REQUEST_METHOD.
+  def initialize(type = "query")
+    if defined?(MOD_RUBY) && !ENV.key?("GATEWAY_INTERFACE")
+      Apache.request.setup_cgi_env
+    end
+
+      (class << self; self; end).class_eval do
+        const_set(:CGI_PARAMS,  [1])
+        const_set(:CGI_COOKIES, [2])
+      end
+
+    extend QueryExtension
+    @multipart = false
+
+    initialize_query()  # set @params, @cookies
+    @output_cookies = nil
+    @output_hidden = nil
+
+    case type
+    when "html3"
+      extend Html3
+      element_init()
+      extend HtmlExtension
+    when "html4"
+      extend Html4
+      element_init()
+      extend HtmlExtension
+    when "html4Tr"
+      extend Html4Tr
+      element_init()
+      extend HtmlExtension
+    when "html4Fr"
+      extend Html4Tr
+      element_init()
+      extend Html4Fr
+      element_init()
+      extend HtmlExtension
+    end
+  end
+
+end   # class CGI

Added: trunk/lib/complex.rb
===================================================================
--- trunk/lib/complex.rb	2005-10-31 23:20:44 UTC (rev 285)
+++ trunk/lib/complex.rb	2005-10-31 23:28:34 UTC (rev 286)
@@ -0,0 +1,631 @@
+#
+#   complex.rb - 
+#   	$Release Version: 0.5 $
+#   	$Revision: 1.3 $
+#   	$Date: 1998/07/08 10:05:28 $
+#   	by Keiju ISHITSUKA(SHL Japan Inc.)
+#
+# ----
+#
+# complex.rb implements the Complex class for complex numbers.  Additionally,
+# some methods in other Numeric classes are redefined or added to allow greater
+# interoperability with Complex numbers.
+#
+# Complex numbers can be created in the following manner:
+# - <tt>Complex(a, b)</tt>
+# - <tt>Complex.polar(radius, theta)</tt>
+#   
+# Additionally, note the following:
+# - <tt>Complex::I</tt> (the mathematical constant <i>i</i>)
+# - <tt>Numeric#im</tt> (e.g. <tt>5.im -> 0+5i</tt>)
+#
+# The following +Math+ module methods are redefined to handle Complex arguments.
+# They will work as normal with non-Complex arguments.
+#    sqrt exp cos sin tan log log10
+#    cosh sinh tanh acos asin atan atan2 acosh asinh atanh
+#
+
+
+#
+# Numeric is a built-in class on which Fixnum, Bignum, etc., are based.  Here
+# some methods are added so that all number types can be treated to some extent
+# as Complex numbers.
+#
+class Numeric
+  #
+  # Returns a Complex number <tt>(0,<i>self</i>)</tt>.
+  #
+  def im
+    Complex(0, self)
+  end
+  
+  #
+  # The real part of a complex number, i.e. <i>self</i>.
+  #
+  def real
+    self
+  end
+  
+  #
+  # The imaginary part of a complex number, i.e. 0.
+  #
+  def image
+    0
+  end
+  alias imag image
+  
+  #
+  # See Complex#arg.
+  #
+  def arg
+    if self >= 0
+      return 0
+    else
+      return Math::PI
+    end
+  end
+  alias angle arg
+  
+  #
+  # See Complex#polar.
+  #
+  def polar
+    return abs, arg
+  end
+  
+  #
+  # See Complex#conjugate (short answer: returns <i>self</i>).
+  #
+  def conjugate
+    self
+  end
+  alias conj conjugate
+end
+
+
+#
+# Creates a Complex number.  +a+ and +b+ should be Numeric.  The result will be
+# <tt>a+bi</tt>.
+#
+def Complex(a, b = 0)
+  if b == 0 and (a.kind_of?(Complex) or defined? Complex::Unify)
+    a
+  else
+    Complex.new( a.real-b.imag, a.imag+b.real )
+  end
+end
+
+#
+# The complex number class.  See complex.rb for an overview.
+#
+class Complex < Numeric
+  @RCS_ID='-$Id: complex.rb,v 1.3 1998/07/08 10:05:28 keiju Exp keiju $-'
+
+  undef step
+
+  def Complex.generic?(other) # :nodoc:
+    other.kind_of?(Integer) or
+    other.kind_of?(Float) or
+    (defined?(Rational) and other.kind_of?(Rational))
+  end
+
+  #
+  # Creates a +Complex+ number in terms of +r+ (radius) and +theta+ (angle).
+  #
+  def Complex.polar(r, theta)
+    Complex(r*Math.cos(theta), r*Math.sin(theta))
+  end
+
+  #
+  # Creates a +Complex+ number <tt>a</tt>+<tt>b</tt><i>i</i>.
+  #
+  def Complex.new!(a, b=0)
+    new(a,b)
+  end
+
+  def initialize(a, b)
+    raise TypeError, "non numeric 1st arg `#{a.inspect}'" if !a.kind_of? Numeric
+    raise TypeError, "`#{a.inspect}' for 1st arg" if a.kind_of? Complex
+    raise TypeError, "non numeric 2nd arg `#{b.inspect}'" if !b.kind_of? Numeric
+    raise TypeError, "`#{b.inspect}' for 2nd arg" if b.kind_of? Complex
+    @real = a
+    @image = b
+  end
+
+  #
+  # Addition with real or complex number.
+  #
+  def + (other)
+    if other.kind_of?(Complex)
+      re = @real + other.real
+      im = @image + other.image
+      Complex(re, im)
+    elsif Complex.generic?(other)
+      Complex(@real + other, @image)
+    else
+      x , y = other.coerce(self)
+      x + y
+    end
+  end
+  
+  #
+  # Subtraction with real or complex number.
+  #
+  def - (other)
+    if other.kind_of?(Complex)
+      re = @real - other.real
+      im = @image - other.image
+      Complex(re, im)
+    elsif Complex.generic?(other)
+      Complex(@real - other, @image)
+    else
+      x , y = other.coerce(self)
+      x - y
+    end
+  end
+  
+  #
+  # Multiplication with real or complex number.
+  #
+  def * (other)
+    if other.kind_of?(Complex)
+      re = @real*other.real - @image*other.image
+      im = @real*other.image + @image*other.real
+      Complex(re, im)
+    elsif Complex.generic?(other)
+      Complex(@real * other, @image * other)
+    else
+      x , y = other.coerce(self)
+      x * y
+    end
+  end
+  
+  #
+  # Division by real or complex number.
+  #
+  def / (other)
+    if other.kind_of?(Complex)
+      self*other.conjugate/other.abs2
+    elsif Complex.generic?(other)
+      Complex(@real/other, @image/other)
+    else
+      x, y = other.coerce(self)
+      x/y
+    end
+  end
+  
+  #
+  # Raise this complex number to the given (real or complex) power.
+  #
+  def ** (other)
+    if other == 0
+      return Complex(1)
+    end
+    if other.kind_of?(Complex)
+      r, theta = polar
+      ore = other.real
+      oim = other.image
+      nr = Math.exp!(ore*Math.log!(r) - oim * theta)
+      ntheta = theta*ore + oim*Math.log!(r)
+      Complex.polar(nr, ntheta)
+    elsif other.kind_of?(Integer)
+      if other > 0
+	x = self
+	z = x
+	n = other - 1
+	while n != 0
+	  while (div, mod = n.divmod(2)
+		 mod == 0)
+	    x = Complex(x.real*x.real - x.image*x.image, 2*x.real*x.image)
+	    n = div
+	  end
+	  z *= x
+	  n -= 1
+	end
+	z
+      else
+	if defined? Rational
+	  (Rational(1) / self) ** -other
+	else
+	  self ** Float(other)
+	end
+      end
+    elsif Complex.generic?(other)
+      r, theta = polar
+      Complex.polar(r**other, theta*other)
+    else
+      x, y = other.coerce(self)
+      x**y
+    end
+  end
+  
+  #
+  # Remainder after division by a real or complex number.
+  #
+  def % (other)
+    if other.kind_of?(Complex)
+      Complex(@real % other.real, @image % other.image)
+    elsif Complex.generic?(other)
+      Complex(@real % other, @image % other)
+    else
+      x , y = other.coerce(self)
+      x % y
+    end
+  end
+  
+#--
+#    def divmod(other)
+#      if other.kind_of?(Complex)
+#        rdiv, rmod = @real.divmod(other.real)
+#        idiv, imod = @image.divmod(other.image)
+#        return Complex(rdiv, idiv), Complex(rmod, rmod)
+#      elsif Complex.generic?(other)
+#        Complex( real.divmod(other), @image.divmod(other))
+#      else
+#        x , y = other.coerce(self)
+#        x.divmod(y)
+#      end
+#    end
+#++
+  
+  #
+  # Absolute value (aka modulus): distance from the zero point on the complex
+  # plane.
+  #
+  def abs
+    Math.hypot(@real, @image)
+  end
+  
+  #
+  # Square of the absolute value.
+  #
+  def abs2
+    @real*@real + @image*@image
+  end
+  
+  #
+  # Argument (angle from (1,0) on the complex plane).
+  #
+  def arg
+    Math.atan2!(@image, @real)
+  end
+  alias angle arg
+  
+  #
+  # Returns the absolute value _and_ the argument.
+  #
+  def polar
+    return abs, arg
+  end
+  
+  #
+  # Complex conjugate (<tt>z + z.conjugate = 2 * z.real</tt>).
+  #
+  def conjugate
+    Complex(@real, -@image)
+  end
+  alias conj conjugate
+  
+  #
+  # Compares the absolute values of the two numbers.
+  #
+  def <=> (other)
+    self.abs <=> other.abs
+  end
+  
+  #
+  # Test for numerical equality (<tt>a == a + 0<i>i</i></tt>).
+  #
+  def == (other)
+    if other.kind_of?(Complex)
+      @real == other.real and @image == other.image
+    elsif Complex.generic?(other)
+      @real == other and @image == 0
+    else
+      other == self
+    end
+  end
+
+  #
+  # Attempts to coerce +other+ to a Complex number.
+  #
+  def coerce(other)
+    if Complex.generic?(other)
+      return Complex.new!(other), self
+    else
+      super
+    end
+  end
+
+  #
+  # FIXME
+  #
+  def denominator
+    @real.denominator.lcm( image.denominator)
+  end
+  
+  #
+  # FIXME
+  #
+  def numerator
+    cd = denominator
+    Complex( real.numerator*(cd/ real.denominator),
+	    @image.numerator*(cd/ image.denominator))
+  end
+  
+  #
+  # Standard string representation of the complex number.
+  #
+  def to_s
+    if @real != 0
+      if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1
+	if @image >= 0
+	  @real.to_s+"+("+ image.to_s+")i"
+	else
+	  @real.to_s+"-("+(- image).to_s+")i"
+	end
+      else
+	if @image >= 0
+	  @real.to_s+"+"+ image.to_s+"i"
+	else
+	  @real.to_s+"-"+(- image).to_s+"i"
+	end
+      end
+    else
+      if defined?(Rational) and @image.kind_of?(Rational) and @image.denominator != 1
+	"("+ image.to_s+")i"
+      else
+	@image.to_s+"i"
+      end
+    end
+  end
+  
+  #
+  # Returns a hash code for the complex number.
+  #
+  def hash
+    @real.hash ^ @image.hash
+  end
+  
+  #
+  # Returns "<tt>Complex(<i>real</i>, <i>image</i>)</tt>".
+  #
+  def inspect
+    sprintf("Complex(%s, %s)", @real.inspect, @image.inspect)
+  end
+
+  
+  #
+  # +I+ is the imaginary number.  It exists at point (0,1) on the complex plane.
+  #
+  I = Complex(0,1)
+  
+  # The real part of a complex number.
+  attr :real
+
+  # The imaginary part of a complex number.
+  attr :image
+  alias imag image
+  
+end
+
+
+
+
+module Math
+  alias sqrt! sqrt
+  alias exp! exp
+  alias log! log
+  alias log10! log10
+  alias cos! cos
+  alias sin! sin
+  alias tan! tan
+  alias cosh! cosh
+  alias sinh! sinh
+  alias tanh! tanh
+  alias acos! acos
+  alias asin! asin
+  alias atan! atan
+  alias atan2! atan2
+  alias acosh! acosh
+  alias asinh! asinh
+  alias atanh! atanh  
+
+  # Redefined to handle a Complex argument.
+  def sqrt(z)
+    if Complex.generic?(z)
+      if z >= 0
+	sqrt!(z)
+      else
+	Complex(0,sqrt!(-z))
+      end
+    else
+      if z.image < 0
+	sqrt(z.conjugate).conjugate
+      else
+	r = z.abs
+	x = z.real
+	Complex( sqrt!((r+x)/2), sqrt!((r-x)/2) )
+      end
+    end
+  end
+  
+  # Redefined to handle a Complex argument.
+  def exp(z)
+    if Complex.generic?(z)
+      exp!(z)
+    else
+      Complex(exp!(z.real) * cos!(z.image), exp!(z.real) * sin!(z.image))
+    end
+  end
+  
+  # Redefined to handle a Complex argument.
+  def cos(z)
+    if Complex.generic?(z)
+      cos!(z)
+    else
+      Complex(cos!(z.real)*cosh!(z.image),
+	      -sin!(z.real)*sinh!(z.image))
+    end
+  end
+    
+  # Redefined to handle a Complex argument.
+  def sin(z)
+    if Complex.generic?(z)
+      sin!(z)
+    else
+      Complex(sin!(z.real)*cosh!(z.image),
+	      cos!(z.real)*sinh!(z.image))
+    end
+  end
+  
+  # Redefined to handle a Complex argument.
+  def tan(z)
+    if Complex.generic?(z)
+      tan!(z)
+    else
+      sin(z)/cos(z)
+    end
+  end
+
+  def sinh(z)
+    if Complex.generic?(z)
+      sinh!(z)
+    else
+      Complex( sinh!(z.real)*cos!(z.image), cosh!(z.real)*sin!(z.image) )
+    end
+  end
+
+  def cosh(z)
+    if Complex.generic?(z)
+      cosh!(z)
+    else
+      Complex( cosh!(z.real)*cos!(z.image), sinh!(z.real)*sin!(z.image) )
+    end
+  end
+
+  def tanh(z)
+    if Complex.generic?(z)
+      tanh!(z)
+    else
+      sinh(z)/cosh(z)
+    end
+  end
+  
+  # Redefined to handle a Complex argument.
+  def log(z)
+    if Complex.generic?(z) and z >= 0
+      log!(z)
+    else
+      r, theta = z.polar
+      Complex(log!(r.abs), theta)
+    end
+  end
+  
+  # Redefined to handle a Complex argument.
+  def log10(z)
+    if Complex.generic?(z)
+      log10!(z)
+    else
+      log(z)/log!(10)
+    end
+  end
+
+  def acos(z)
+    if Complex.generic?(z) and z >= -1 and z <= 1
+      acos!(z)
+    else
+      -1.0.im * log( z + 1.0.im * sqrt(1.0-z*z) )
+    end
+  end
+
+  def asin(z)
+    if Complex.generic?(z) and z >= -1 and z <= 1
+      asin!(z)
+    else
+      -1.0.im * log( 1.0.im * z + sqrt(1.0-z*z) )
+    end
+  end
+
+  def atan(z)
+    if Complex.generic?(z)
+      atan!(z)
+    else
+      1.0.im * log( (1.0.im+z) / (1.0.im-z) ) / 2.0
+    end
+  end
+
+  def atan2(y,x)
+    if Complex.generic?(y) and Complex.generic?(x)
+      atan2!(y,x)
+    else
+      -1.0.im * log( (x+1.0.im*y) / sqrt(x*x+y*y) )
+    end
+  end
+
+  def acosh(z)
+    if Complex.generic?(z) and z >= 1
+      acosh!(z)
+    else
+      log( z + sqrt(z*z-1.0) )
+    end
+  end
+
+  def asinh(z)
+    if Complex.generic?(z)
+      asinh!(z)
+    else
+      log( z + sqrt(1.0+z*z) )
+    end
+  end
+
+  def atanh(z)
+    if Complex.generic?(z) and z >= -1 and z <= 1
+      atanh!(z)
+    else
+      log( (1.0+z) / (1.0-z) ) / 2.0
+    end
+  end
+
+  module_function :sqrt!
+  module_function :sqrt
+  module_function :exp!
+  module_function :exp
+  module_function :log!
+  module_function :log
+  module_function :log10!
+  module_function :log10
+  module_function :cosh!
+  module_function :cosh
+  module_function :cos!
+  module_function :cos
+  module_function :sinh!
+  module_function :sinh
+  module_function :sin!
+  module_function :sin
+  module_function :tan!
+  module_function :tan
+  module_function :tanh!
+  module_function :tanh
+  module_function :acos!
+  module_function :acos
+  module_function :asin!
+  module_function :asin
+  module_function :atan!
+  module_function :atan
+  module_function :atan2!
+  module_function :atan2
+  module_function :acosh!
+  module_function :acosh
+  module_function :asinh!
+  module_function :asinh
+  module_function :atanh!
+  module_function :atanh
+  
+end
+
+# Documentation comments:
+#  - source: original (researched from pickaxe)
+#  - a couple of fixme's
+#  - RDoc output for Bignum etc. is a bit short, with nothing but an
+#    (undocumented) alias.  No big deal.

Added: trunk/lib/delegate.rb
===================================================================
--- trunk/lib/delegate.rb	2005-10-31 23:20:44 UTC (rev 285)
+++ trunk/lib/delegate.rb	2005-10-31 23:28:34 UTC (rev 286)
@@ -0,0 +1,323 @@
+# = delegate -- Support for the Delegation Pattern
+#
+# Documentation by James Edward Gray II and Gavin Sinclair
+#
+# == Introduction
+#
+# This library provides three different ways to delegate method calls to an
+# object.  The easiest to use is SimpleDelegator.  Pass an object to the
+# constructor and all methods supported by the object will be delegated.  This
+# object can be changed later.
+#
+# Going a step further, the top level DelegateClass method allows you to easily
+# setup delegation through class inheritance.  This is considerably more
+# flexible and thus probably the most common use for this library.
+#
+# Finally, if you need full control over the delegation scheme, you can inherit
+# from the abstract class Delegator and customize as needed.  (If you find
+# yourself needing this control, have a look at _forwardable_, also in the
+# standard library.  It may suit your needs better.)
+#
+# == Notes
+#
+# Be advised, RDoc will not detect delegated methods.
+#
+# <b>delegate.rb provides full-class delegation via the
+# DelegateClass() method.  For single-method delegation via
+# def_delegator(), see forwardable.rb.</b>
+#
+# == Examples
+#
+# === SimpleDelegator
+#
+# Here's a simple example that takes advantage of the fact that
+# SimpleDelegator's delegation object can be changed at any time.
+#
+#   class Stats
+#     def initialize
+#       @source = SimpleDelegator.new([])
+#     end
+#     
+#     def stats( records )
+#       @source.__setobj__(records)
+#       	
+#       "Elements:  #{ source.size}\n" +
+#       " Non-Nil:  #{ source.compact.size}\n" +
+#       "  Unique:  #{ source.uniq.size}\n"
+#     end
+#   end
+#   
+#   s = Stats.new
+#   puts s.stats(%w{James Edward Gray II})
+#   puts
+#   puts s.stats([1, 2, 3, nil, 4, 5, 1, 2])
+#
+# <i>Prints:</i>
+#
+#   Elements:  4
+#    Non-Nil:  4
+#     Unique:  4
+# 
+#   Elements:  8
+#    Non-Nil:  7
+#     Unique:  6
+#
+# === DelegateClass()
+#
+# Here's a sample of use from <i>tempfile.rb</i>.
+#
+# A _Tempfile_ object is really just a _File_ object with a few special rules
+# about storage location and/or when the File should be deleted.  That makes for
+# an almost textbook perfect example of how to use delegation.
+#
+#   class Tempfile < DelegateClass(File)
+#     # constant and class member data initialization...
+#   
+#     def initialize(basename, tmpdir=Dir::tmpdir)
+#       # build up file path/name in var tmpname...
+#     
+#       @tmpfile = File.open(tmpname, File::RDWR|File::CREAT|File::EXCL, 0600)
+#     
+#       # ...
+#     
+#       super(@tmpfile)
+#     
+#       # below this point, all methods of File are supported...
+#     end
+#   
+#     # ...
+#   end
+#
+# === Delegator
+#
+# SimpleDelegator's implementation serves as a nice example here.
+#
+#    class SimpleDelegator < Delegator
+#      def initialize(obj)
+#        super             # pass obj to Delegator constructor, required
+#        @_sd_obj = obj    # store obj for future use
+#      end
+# 
+#      def __getobj__
+#        @_sd_obj          # return object we are delegating to, required
+#      end
+# 
+#      def __setobj__(obj)
+#        @_sd_obj = obj    # change delegation object, a feature we're providing
+#      end
+# 
+#      # ...
+#    end
+
+#
+# Delegator is an abstract class used to build delegator pattern objects from
+# subclasses.  Subclasses should redefine \_\_getobj\_\_.  For a concrete
+# implementation, see SimpleDelegator.
+#
+class Delegator
+  preserved = ["__id__", "object_id", "__send__", "respond_to?"]
+  instance_methods.each do |m|
+    next if preserved.include?(m)
+    undef_method m
+  end
+
+  #
+  # Pass in the _obj_ to delegate method calls to.  All methods supported by
+  # _obj_ will be delegated to.
+  #
+  def initialize(obj)
+    __setobj__(obj)
+  end
+
+  # Handles the magic of delegation through \_\_getobj\_\_.
+  def method_missing(m, *args)
+    begin
+      target = self.__getobj__
+      unless target.respond_to?(m)
+        super(m, *args)
+      end
+      target.__send__(m, *args)
+    rescue Exception
+      $@.delete_if{|s| /^#{__FILE__}:\d+:in `method_missing'$/ =~ s} #`
+      ::Kernel::raise
+    end
+  end
+
+  # 
+  # Checks for a method provided by this the delegate object by fowarding the 
+  # call through \_\_getobj\_\_.
+  # 
+  def respond_to?(m)
+    return true if super
+    return self.__getobj__.respond_to?(m)
+  end
+
+  #
+  # This method must be overridden by subclasses and should return the object
+  # method calls are being delegated to.
+  #
+  def __getobj__
+    raise NotImplementedError, "need to define `__getobj__'"
+  end
+
+  #
+  # This method must be overridden by subclasses and change the object delegate
+  # to _obj_.
+  #
+  def __setobj__(obj)
+    raise NotImplementedError, "need to define `__setobj__'"
+  end
+
+  # Serialization support for the object returned by \_\_getobj\_\_.
+  def marshal_dump
+    __getobj__
+  end
+  # Reinitializes delegation from a serialized object.
+  def marshal_load(obj)
+    __setobj__(obj)
+  end
+end
+
+#
+# A concrete implementation of Delegator, this class provides the means to
+# delegate all supported method calls to the object passed into the constructor
+# and even to change the object being delegated to at a later time with
+# \_\_setobj\_\_ .
+#
+class SimpleDelegator<Delegator
+  # Returns the current object method calls are being delegated to.
+  def __getobj__
+    @_sd_obj
+  end
+
+  #
+  # Changes the delegate object to _obj_.
+  #
+  # It's important to note that this does *not* cause SimpleDelegator's methods
+  # to change.  Because of this, you probably only want to change delegation
+  # to objects of the same type as the original delegate.
+  #
+  # Here's an example of changing the delegation object.
+  #
+  #   names = SimpleDelegator.new(%w{James Edward Gray II})
+  #   puts names[1]    # => Edward
+  #   names.__setobj__(%w{Gavin Sinclair})
+  #   puts names[1]    # => Sinclair
+  #
+  def __setobj__(obj)
+    raise ArgumentError, "cannot delegate to self" if self.equal?(obj)
+    @_sd_obj = obj
+  end
+
+  # Clone support for the object returned by \_\_getobj\_\_.
+  def clone
+    copy = super
+    copy.__setobj__(__getobj__.clone)
+    copy
+  end
+  # Duplication support for the object returned by \_\_getobj\_\_.
+  def dup
+    copy = super
+    copy.__setobj__(__getobj__.dup)
+    copy
+  end
+end
+
+# :stopdoc:
+# backward compatibility ^_^;;;
+Delegater = Delegator
+SimpleDelegater = SimpleDelegator
+# :startdoc:
+
+#
+# The primary interface to this library.  Use to setup delegation when defining
+# your class.
+#
+#   class MyClass < DelegateClass( ClassToDelegateTo )    # Step 1
+#     def initiaize
+#       super(obj_of_ClassToDelegateTo)                   # Step 2
+#     end
+#   end
+#
+def DelegateClass(superclass)
+  klass = Class.new
+  methods = superclass.public_instance_methods(true)
+  methods -= [
+    "__id__", "object_id", "__send__", "respond_to?",
+    "initialize", "method_missing", "__getobj__", "__setobj__",
+    "clone", "dup", "marshal_dump", "marshal_load",
+  ]
+  klass.module_eval {
+    def initialize(obj)  # :nodoc:
+      @_dc_obj = obj
+    end
+    def method_missing(m, *args)  # :nodoc:
+      unless @_dc_obj.respond_to?(m)
+        super(m, *args)
+      end
+      @_dc_obj.__send__(m, *args)
+    end
+    def respond_to?(m)  # :nodoc:
+      return true if super
+      return @_dc_obj.respond_to?(m)
+    end
+    def __getobj__  # :nodoc:
+      @_dc_obj
+    end
+    def __setobj__(obj)  # :nodoc:
+      raise ArgumentError, "cannot delegate to self" if self.equal?(obj)
+      @_dc_obj = obj
+    end
+    def clone  # :nodoc:
+      super
+      __setobj__(__getobj__.clone)
+    end
+    def dup  # :nodoc:
+      super
+      __setobj__(__getobj__.dup)
+    end
+  }
+  for method in methods
+    begin
+      klass.module_eval <<-EOS, __FILE__, __LINE__+1
+        def #{method}(*args, &block)
+	  begin
+	    @_dc_obj.__send__(:#{method}, *args, &block)
+	  rescue
+	    $@[0,2] = nil
+	    raise
+	  end
+	end
+      EOS
+    rescue SyntaxError
+      raise NameError, "invalid identifier %s" % method, caller(3)
+    end
+  end
+  return klass
+end
+
+# :enddoc:
+
+if __FILE__ == $0
+  class ExtArray<DelegateClass(Array)
+    def initialize()
+      super([])
+    end
+  end
+
+  ary = ExtArray.new
+  p ary.class
+  ary.push 25
+  p ary
+
+  foo = Object.new
+  def foo.test
+    25
+  end
+  def foo.error
+    raise 'this is OK'
+  end
+  foo2 = SimpleDelegator.new(foo)
+  p foo.test == foo2.test	# => true
+  foo2.error			# raise error!
+end


--
ML: yarv-diff quickml.atdot.net
Info: http://www.atdot.net/~ko1/quickml

[前][次][番号順一覧][スレッド一覧][生データ]