class Array

  ##
  # call-seq:
  #   (...)
  #
  # Returns a new array populated with the given objects.
  #
  #   Array.[]( 1, 'a', /^A/ )
  #   Array[ 1, 'a', /^A/ ]
  #   [ 1, 'a', /^A/ ]


  def self.[](*args)
    Array.new args
  end


  ##
  # call-seq:
  #   Array.new(size=0, obj=nil)
  #   Array.new(array)
  #   Array.new(size) {|index| block }
  #
  # Returns a new array. In the first form, the new array is empty. In
  # the second it is created with <em>size</em> copies of <em>obj</em>
  # (that is, <em>size</em> references to the same <em>obj</em>). The
  # third form creates a copy of the array passed as a parameter (the
  # array is generated by calling to_ary on the parameter). In the last
  # form, an array of the given size is created. Each element in this
  # array is calculated by passing the element's index to the given
  # block and storing the return value.
  #
  #    Array.new
  #    Array.new(2)
  #    Array.new(5, "A")
  #    # only one copy of the object is created
  #    a = Array.new(2, Hash.new)
  #    a[0]['cat'] = 'feline'
  #    a
  #    a[1]['cat'] = 'Felix'
  #    a
  #    # here multiple copies are created
  #    a = Array.new(2) { Hash.new }
  #    a[0]['cat'] = 'feline'
  #    a
  #    squares = Array.new(5) {|i| i*i}
  #    squares
  #    copy = Array.new(squares)

  # def initialize(*args); end

  ##
  # call-seq:
  #   array & other_array
  #
  # Set Intersection---Returns a new array containing elements common to
  # the two arrays, with no duplicates.
  #
  #    [ 1, 1, 3, 5 ] & [ 1, 2, 3 ]   #=> [ 1, 3 ]

  def &(other)
    other = convert other
    new = Array.new
    hash = make_hash other

    self.each do |key|
      value = hash.delete key
      new << key if value == true
    end

    return new
  end

  ##
  # call-seq:
  #   array * int     ->    an_array
  #   array * str     ->    a_string
  #
  # Repetition---With a String argument, equivalent to self.join(str).
  # Otherwise, returns a new array built by concatenating the
  # <em>int</em> copies of <em>self</em>.
  #
  #    [ 1, 2, 3 ] * 3    #=> [ 1, 2, 3, 1, 2, 3, 1, 2, 3 ]
  #    [ 1, 2, 3 ] * ","  #=> "1,2,3"

  def *(times)
    if times.respond_to? :to_str then
      tmp = times.to_str
      return self.join(tmp) unless tmp.nil?
    elsif times.respond_to? :to_int then
      times = times.to_int
    else
      raise TypeError, "cannot convert " + times.class.name + " into Integer"
    end
    
    return Array.new if times == 0 # HACK ary_new(rb_obj_class(ary), 0)
    raise ArgumentError, "negative argument" if times < 0
    # raise "argument to big" if LONG_MAX/times < self.length # HACK Bignums are already too big
    
    new = Array.new
    length = self.length * times

    1.upto times do
      new += self
    end
    
    return new
  end

  ##
  # call-seq:
  #   array + other_array   -> an_array
  #
  # Concatenation---Returns a new array built by concatenating the two
  # arrays together to produce a third array.
  #
  #    [ 1, 2, 3 ] + [ 4, 5 ]    #=> [ 1, 2, 3, 4, 5 ]

  def +(other)
    new = self.dup
    mem_copy new, 0, self, 0, self.length
    mem_copy new, new.length, other, 0, other.length
    #other.each do |item|
    #  new << item
    #end

    return new
  end

  ##
  # call-seq:
  #   array - other_array    -> an_array
  #
  # Array Difference---Returns a new array that is a copy of the
  # original array, removing any items that also appear in other_array.
  # (If you need set-like behavior, see the library class Set.)
  #
  #    [ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ]  #=>  [ 3, 3, 5 ]

  def -(other)
    hash = make_hash other
    new = Array.new

    self.each do |key|
      value = hash.include? key
      next if value == true
      new << key
    end

    return new
  end

  ##
  # call-seq:
  #   array | other_array     ->  an_array
  #
  # Set Union---Returns a new array by joining this array with
  # other_array, removing duplicates.
  #
  #    [ "a", "b", "c" ] | [ "c", "d", "a" ]
  #           #=> [ "a", "b", "c", "d" ]

  def |(other)
    other = convert other
    new = Array.new
    hash = make_hash self, other

    self.each do |key|
      value = hash.delete key
      new << key if value == true
    end

    other.each do |key|
      value = hash.delete key
      new << key if value == true
    end

    return new
  end

  alias_method :old_append, :<<

  ##
  # call-seq:
  #   array << obj            -> array
  #
  # Append---Pushes the given object on to the end of this array. This
  # expression returns the array itself, so several appends may be
  # chained together.
  #
  #    [ 1, 2 ] << "c" << "d" << [ 3, 4 ]
  #            #=>  [ 1, 2, "c", "d", [ 3, 4 ] ]

  def <<(arg1)
    return old_append(arg1)
  end

  ##
  # call-seq:
  #   array <=> other_array   ->  -1, 0, +1
  #
  # Comparison---Returns an integer (-1, 0, or +1) if this array is less
  # than, equal to, or greater than other_array. Each object in each
  # array is compared (using <=>). If any value isn't equal, then that
  # inequality is the return value. If all the values found are equal,
  # then the return is based on a comparison of the array lengths. Thus,
  # two arrays are ``equal'' according to <tt>Array#<=></tt> if and only
  # if they have the same length and the value of each element is equal
  # to the value of the corresponding element in the other array.
  #
  #    [ "a", "a", "c" ]    <=> [ "a", "b", "c" ]   #=> -1
  #    [ 1, 2, 3, 4, 5, 6 ] <=> [ 1, 2 ]            #=> +1

  def <=>(other)
    other = convert other
    length = self.length
    length = other.length if length > other.length

    length = length - 1

      0.upto length do |i|
        value = self.at(i) <=> other.at(i)
        return value if value != 0
      end

    length = self.length - other.length
    return 0 if length == 0
    return 1 if length > 0
    return -1
  end

  ##
  # call-seq:
  #   array == other_array   ->   bool
  #
  # Equality---Two arrays are equal if they contain the same number of
  # elements and if each element is equal to (according to Object.==)
  # the corresponding element in the other array.
  #
  #    [ "a", "c" ]    == [ "a", "c", 7 ]     #=> false
  #    [ "a", "c", 7 ] == [ "a", "c", 7 ]     #=> true
  #    [ "a", "c", 7 ] == [ "a", "d", "f" ]   #=> false

  def ==(other)
    return true if self.object_id == other.object_id

    unless other.kind_of? Array then
      return false unless other.respond_to? :to_ary
      return other == self
    end

    return false unless other.length == self.length

    self.each_with_index do |item, i|
      return false unless item == other.at(i)
    end
    
    return true
  end

  alias_method :old_index, :[]

  ##
  # call-seq:
  #   array[index]                -> obj      or nil
  #   array[start, length]        -> an_array or nil
  #   array[range]                -> an_array or nil
  #   array.slice(index)          -> obj      or nil
  #   array.slice(start, length)  -> an_array or nil
  #   array.slice(range)          -> an_array or nil
  #
  # Element Reference---Returns the element at <em>index</em>, or
  # returns a subarray starting at <em>start</em> and continuing for
  # <em>length</em> elements, or returns a subarray specified by
  # <em>range</em>. Negative indices count backward from the end of the
  # array (-1 is the last element). Returns nil if the index (or
  # starting index) are out of range.
  #
  #    a = [ "a", "b", "c", "d", "e" ]
  #    a[2] +  a[0] + a[1]    #=> "cab"
  #    a[6]                   #=> nil
  #    a[1, 2]                #=> [ "b", "c" ]
  #    a[1..3]                #=> [ "b", "c", "d" ]
  #    a[4..7]                #=> [ "e" ]
  #    a[6..10]               #=> nil
  #    a[-3, 3]               #=> [ "c", "d", "e" ]
  #    # special cases
  #    a[5]                   #=> nil
  #    a[5, 1]                #=> []
  #    a[5..10]               #=> []

  def [](*args)
    return old_index(*args)
  end

  ##
  # call-seq:
  #   array[index]         = obj                     ->  obj
  #   array[start, length] = obj or an_array or nil  ->  obj or an_array or nil
  #   array[range]         = obj or an_array or nil  ->  obj or an_array or nil
  #
  # Element Assignment---Sets the element at <em>index</em>, or replaces
  # a subarray starting at <em>start</em> and continuing for
  # <em>length</em> elements, or replaces a subarray specified by
  # <em>range</em>. If indices are greater than the current capacity of
  # the array, the array grows automatically. A negative indices will
  # count backward from the end of the array. Inserts elements if
  # <em>length</em> is zero. If <tt>nil</tt> is used in the second and
  # third form, deletes elements from <em>self</em>. An
  # <tt>IndexError</tt> is raised if a negative index points past the
  # beginning of the array. See also <tt>Array#push</tt>, and
  # <tt>Array#unshift</tt>.
  #
  #    a = Array.new
  #    a[4] = "4";                 #=> [nil, nil, nil, nil, "4"]
  #    a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"]
  #    a[1..2] = [ 1, 2 ]          #=> ["a", 1, 2, nil, "4"]
  #    a[0, 2] = "?"               #=> ["?", 2, nil, "4"]
  #    a[0..2] = "A"               #=> ["A", "4"]
  #    a[-1]   = "Z"               #=> ["A", "Z"]
  #    a[1..-1] = nil              #=> ["A"]

  #def []=(*args); end # CORE

  ##
  # call-seq:
  #   array.assoc(obj)   ->  an_array  or  nil
  #
  # Searches through an array whose elements are also arrays comparing
  # <em>obj</em> with the first element of each contained array using
  # obj.==. Returns the first contained array that matches (that is, the
  # first associated array), or <tt>nil</tt> if no match is found. See
  # also <tt>Array#rassoc</tt>.
  #
  #    s1 = [ "colors", "red", "blue", "green" ]
  #    s2 = [ "letters", "a", "b", "c" ]
  #    s3 = "foo"
  #    a  = [ s1, s2, s3 ]
  #    a.assoc("letters")  #=> [ "letters", "a", "b", "c" ]
  #    a.assoc("foo")      #=> nil

  def assoc(key)
    self.each do |item|
      if item.kind_of? Array and # is an array
         item.length > 1 and # of two or more items
         item.at(0) == key then # where the second matches
        return item
      end
    end

    return nil
  end

  ##
  # call-seq:
  #   array.at(index)   ->   obj  or nil
  #
  # Returns the element at <em>index</em>. A negative index counts from
  # the end of <em>self</em>. Returns <tt>nil</tt> if the index is out
  # of range. See also <tt>Array#[]</tt>. (<tt>Array#at</tt> is slightly
  # faster than <tt>Array#[]</tt>, as it does not accept ranges and so
  # on.)
  #
  #    a = [ "a", "b", "c", "d", "e" ]
  #    a.at(0)     #=> "a"
  #    a.at(-1)    #=> "e"

  #def at(arg1); end # CORE

  ##
  # call-seq:
  #   array.clear    ->  array
  #
  # Removes all elements from <em>self</em>.
  #
  #    a = [ "a", "b", "c", "d", "e" ]
  #    a.clear    #=> [ ]

  def clear
    self.replace Array.new
    return self
  end
  
  ##
  # call-seq:
  #   array.collect {|item| block }  -> an_array
  #   array.map     {|item| block }  -> an_array
  #
  # Invokes <em>block</em> once for each element of <em>self</em>.
  # Creates a new array containing the values returned by the block. See
  # also <tt>Enumerable#collect</tt>.
  #
  #    a = [ "a", "b", "c", "d" ]
  #    a.collect {|x| x + "!" }   #=> ["a!", "b!", "c!", "d!"]
  #    a                          #=> ["a", "b", "c", "d"]

  def collect
    if block_given? then
      array = Array.new

      self.each do |item|
        array << yield(item)
      end

      return array
    else
      return self.dup
    end
  end

  ##
  # call-seq:
  #   array.collect! {|item| block }   ->   array
  #   array.map!     {|item| block }   ->   array
  #
  # Invokes the block once for each element of <em>self</em>, replacing
  # the element with the value returned by <em>block</em>. See also
  # <tt>Enumerable#collect</tt>.
  #
  #    a = [ "a", "b", "c", "d" ]
  #    a.collect! {|x| x + "!" }
  #    a             #=>  [ "a!", "b!", "c!", "d!" ]

  def collect!
    self.each_with_index do |item, i|
      new_value = yield item
      self[i] = new_value
    end

    return self
  end

  ##
  # call-seq:
  #   array.compact     ->  an_array
  #
  # Returns a copy of <em>self</em> with all <tt>nil</tt> elements
  # removed.
  #
  #    [ "a", nil, "b", nil, "c", nil ].compact
  #                      #=> [ "a", "b", "c" ]

  def compact
    new = self.dup
    new.compact!
    return new
  end

  ##
  # call-seq:
  #   array.compact!    ->   array  or  nil
  #
  # Removes <tt>nil</tt> elements from array. Returns <tt>nil</tt> if no
  # changes were made.
  #
  #    [ "a", nil, "b", nil, "c" ].compact! #=> [ "a", "b", "c" ]
  #    [ "a", "b", "c" ].compact!           #=> nil

  def compact!
    original_length = self.length

    j = 0
    
    0.upto(self.length - 1) do |i|
      item = self.at i
      unless item.nil? then
        self[j] = item
        j += 1
      end
    end

    return nil if j == original_length

    self.slice!(j..-1)

    return self
  end

  ##
  # call-seq:
  #   array.concat(other_array)   ->  array
  #
  # Appends the elements in other_array to <em>self</em>.
  #
  #    [ "a", "b" ].concat( ["c", "d"] ) #=> [ "a", "b", "c", "d" ]

  def concat(other)
    other = other.to_ary
    if other.length > 0 then
      splice self.length, 0, other
    end

    return self
  end

  ##
  # call-seq:
  #   array.delete(obj)            -> obj or nil 
  #   array.delete(obj) { block }  -> obj or nil
  #
  # Deletes items from <em>self</em> that are equal to <em>obj</em>. If
  # the item is not found, returns <tt>nil</tt>. If the optional code
  # block is given, returns the result of <em>block</em> if the item is
  # not found.
  #
  #    a = [ "a", "b", "b", "b", "c" ]
  #    a.delete("b")                   #=> "b"
  #    a                               #=> ["a", "c"]
  #    a.delete("z")                   #=> nil
  #    a.delete("z") { "not found" }   #=> "not found"

  def delete(object) # HACK lots like compact!
    original_length = self.length

    j = 0
    
    0.upto(self.length - 1) do |i|
      item = self.at i
      unless item == object then
        self[j] = item
        j += 1
      end
    end

    if j == original_length then
      return yield if block_given?
      return nil
    end

    self.slice!(j..-1)

    return object
  end

  ##
  # call-seq:
  #   array.delete_at(index)  -> obj or nil
  #
  # Deletes the element at the specified index, returning that element,
  # or <tt>nil</tt> if the index is out of range. See also
  # <tt>Array#slice!</tt>.
  #
  #    a = %w( ant bat cat dog )
  #    a.delete_at(2)    #=> "cat"
  #    a                 #=> ["ant", "bat", "dog"]
  #    a.delete_at(99)   #=> nil

  def delete_at(position)
    length = self.length

    return nil if position >= length

    if position < 0 then
      position += length
      return nil if position < 0
    end

    deleted = self.at position
    (position + 1).upto length do |i|
      self[i - 1] = self.at i
    end

    self.slice!(-1)

    return deleted
  end

  ##
  # call-seq:
  #   array.delete_if {|item| block }  -> array
  #
  # Deletes every element of <em>self</em> for which <em>block</em>
  # evaluates to <tt>true</tt>.
  #
  #    a = [ "a", "b", "c" ]
  #    a.delete_if {|x| x >= "b" }   #=> ["a"]

  alias_method :reject!, :delete_if # HACK

  ##
  # call-seq:
  #   array.each {|item| block }   ->   array
  #
  # Calls <em>block</em> once for each element in <em>self</em>, passing
  # that element as a parameter.
  #
  #    a = [ "a", "b", "c" ]
  #    a.each {|x| print x, " -- " }
  #
  # produces:
  #
  #    a -- b -- c --

  def each(&block)
    0.upto(self.length - 1) do |i|
      yield self.at(i)
    end

    return self
  end

  ##
  # call-seq:
  #   array.each_index {|index| block }  ->  array
  #
  # Same as <tt>Array#each</tt>, but passes the index of the element
  # instead of the element itself.
  #
  #    a = [ "a", "b", "c" ]
  #    a.each_index {|x| print x, " -- " }
  #
  # produces:
  #
  #    0 -- 1 -- 2 --

  def each_index
    0.upto(self.length - 1) do |i|
      yield i
    end

    return self
  end

  ##
  # call-seq:
  #   array.empty?   -> true or false
  #
  # Returns <tt>true</tt> if <em>self</em> array contains no elements.
  #
  #    [].empty?   #=> true

  def empty?
    return self.length == 0
  end

  ##
  # call-seq:
  #   array.eql?(other)  -> true or false
  #
  # Returns <tt>true</tt> if <em>array</em> and <em>other</em> are the
  # same object, or are both arrays with the same content.

  def eql?(other)
    return true if self.object_id == other.object_id
    return false unless other.kind_of? Array
    return false unless self.length == other.length
    self.each_with_index do |item, i|
      return false unless item.eql? other.at(i)
    end
    return true
  end

  ##
  # call-seq:
  #   array.fetch(index)                    -> obj
  #   array.fetch(index, default )          -> obj
  #   array.fetch(index) {|index| block }   -> obj
  #
  # Tries to return the element at position <em>index</em>. If the index
  # lies outside the array, the first form throws an <tt>IndexError</tt>
  # exception, the second form returns <em>default</em>, and the third
  # form returns the value of invoking the block, passing in the index.
  # Negative values of <em>index</em> count from the end of the array.
  #
  #    a = [ 11, 22, 33, 44 ]
  #    a.fetch(1)               #=> 22
  #    a.fetch(-1)              #=> 44
  #    a.fetch(4, 'cat')        #=> "cat"
  #    a.fetch(4) { |i| i*i }   #=> 16

  def fetch(position, default = :_unset) # HACK, may be nil
    index = position
    if block_given? and default != :_unset then
      warn "block supersedes default value argument"
    end

    index += self.length if index < 0

    if index < 0  or self.length <= index then
      return yield(position) if block_given?
      return default unless default == :_unset
      raise IndexError, "index " + index.to_s + " out of array"
    end

    return self.at(index)
  end

  # HACK WORST METHOD EVAR!

  ##
  # call-seq:
  #   array.fill(obj)                                -> array
  #   array.fill(obj, start [, length])              -> array
  #   array.fill(obj, range )                        -> array
  #   array.fill {|index| block }                    -> array
  #   array.fill(start [, length] ) {|index| block } -> array
  #   array.fill(range) {|index| block }             -> array
  #
  # The first three forms set the selected elements of <em>self</em>
  # (which may be the entire array) to <em>obj</em>. A <em>start</em> of
  # <tt>nil</tt> is equivalent to zero. A <em>length</em> of
  # <tt>nil</tt> is equivalent to <em>self.length</em>. The last three
  # forms fill the array with the value of the block. The block is
  # passed the absolute index of each element to be filled.
  #
  #    a = [ "a", "b", "c", "d" ]
  #    a.fill("x")              #=> ["x", "x", "x", "x"]
  #    a.fill("z", 2, 2)        #=> ["x", "x", "z", "z"]
  #    a.fill("y", 0..1)        #=> ["y", "y", "z", "z"]
  #    a.fill {|i| i*i}         #=> [0, 1, 4, 9]
  #    a.fill(-2) {|i| i*i*i}   #=> [0, 1, 8, 27]

  def fill(*args) # HACK tests missing
    object, range, start, count = :_unset

    object = args.shift unless block_given?

    case args.length
    when 0 then # ok
    when 1 then
      Range === args.first ? (range = *args) : (start = *args)
    when 2 then
      raise TypeError, "Can't convert Range into Integer" if Range === args.first
      start, count = *args
    when 3 then
      msg = block_given? ?
            "wrong number of arguments (3 for 2)" :
            "wrong number of arguments (4 for 3)"
      raise ArgumentError, msg
    end

    if range then
      if block_given? then
        range.each { |i| self[i] = yield i }
      else
        range.each { |i| self[i] = object }
      end
      return self
    end

    start = 0 if start.nil? or start == :_unset
    start = length + start if start < 0
    start = 0 if start < 0

    count = length if count == :_unset
    count = length - start if count.nil?

    if block_given? then
      count.times { |i| offset = start + i; self[offset] = yield offset }
    else
      count.times { |i| self[start + i] = object }
    end

    return self
  end

  ##
  # call-seq:
  #   array.first   ->   obj or nil
  #
  # Returns the first element of the array. If the array is empty,
  # returns <tt>nil</tt>.
  #
  #    a = [ "q", "r", "s", "t" ]
  #    a.first   #=> "q"

  def first(count = nil)
    return self.at(0) if count.nil?

    if not count.respond_to? :to_int then
      raise TypeError, "cannot convert Object into Integer"
    elsif count < 0 then
      raise ArgumentError, "negative array size (or size too big)"
    end

    count = count.to_int

    count = self.length if count > self.length

    return self[0...count]
  end

  ##
  # call-seq:
  #   array.flatten -> an_array
  #
  # Returns a new array that is a one-dimensional flattening of this
  # array (recursively). That is, for every element that is an array,
  # extract its elements into the new array.
  #
  #    s = [ 1, 2, 3 ]           #=> [1, 2, 3]
  #    t = [ 4, 5, 6, [7, 8] ]   #=> [4, 5, 6, [7, 8]]
  #    a = [ s, t, 9, 10 ]       #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9,
  # 10]
  #    a.flatten                 #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10

  def flatten
    new = self.dup
    new.flatten!
    return new
  end

  ##
  # call-seq:
  #   array.flatten! -> array or nil
  #
  # Flattens <em>self</em> in place. Returns <tt>nil</tt> if no
  # modifications were made (i.e., <em>array</em> contains no
  # subarrays.)
  #
  #    a = [ 1, 2, [3, [4, 5] ] ]
  #    a.flatten!   #=> [1, 2, 3, 4, 5]
  #    a.flatten!   #=> nil
  #    a            #=> [1, 2, 3, 4, 5]

  def flatten!
    modified = false
    memo = nil
    i = 0

    while i < self.length do
      sub_array = self.at i
      if sub_array.respond_to? :to_ary then
        sub_array = sub_array.to_ary
        memo = Array.new if memo.nil?
        i += help_flatten i, sub_array, memo
        modified = true
      end
      i += 1
    end

    return nil unless modified
    return self
  end

  ##
  # call-seq:
  #   array.frozen?  -> true or false
  #
  # Return <tt>true</tt> if this array is frozen (or temporarily frozen
  # while being sorted).

  #def frozen?; end # FIX

  # HACK needs a better test

  ##
  # call-seq:
  #   array.hash   -> fixnum
  #
  # Compute a hash-code for this array. Two arrays with the same content
  # will have the same hash code (and will compare using <tt>eql?</tt>).

  def hash
    value = self.length
    self.each do |item|
      value = (value << 1) | (value < 0 ? 1 : 0)
      value ^= item.hash
    end

    return value
  end

  ##
  # call-seq:
  #   array.include?(obj)   -> true or false
  #
  # Returns <tt>true</tt> if the given object is present in
  # <em>self</em> (that is, if any object <tt>==</tt>
  # <em>anObject</em>), <tt>false</tt> otherwise.
  #
  #    a = [ "a", "b", "c" ]
  #    a.include?("b")   #=> true
  #    a.include?("z")   #=> false

  def include?(target)
    return false if self.index(target).nil?
    return true
  end

  ##
  # call-seq:
  #   array.index(obj)   ->  int or nil
  #
  # Returns the index of the first object in <em>self</em> such that is
  # <tt>==</tt> to <em>obj</em>. Returns <tt>nil</tt> if no match is
  # found.
  #
  #    a = [ "a", "b", "c" ]
  #    a.index("b")   #=> 1
  #    a.index("z")   #=> nil

  def index(target)
    self.each_with_index do |item, i|
      return i if target == item
    end

    return nil
  end

  ##
  # call-seq:
  #   array.indexes( i1, i2, ... iN )   -> an_array
  #   array.indices( i1, i2, ... iN )   -> an_array
  #
  # Deprecated; use <tt>Array#select</tt>.

  def indexes(*args) # UNTESTED deprecated
    warn "Array#indexes is deprecated, use Array#values_at"
    new = Array.new

    args.each do |i|
      new << self.at(i)
    end

    return new
  end

  ##
  # call-seq:
  #   array.indexes( i1, i2, ... iN )   -> an_array
  #   array.indices( i1, i2, ... iN )   -> an_array
  #
  # Deprecated; use <tt>Array#select</tt>.

  alias_method :indices, :indexes # UNTESTED deprecated - HACK move doco?

  ##
  # call-seq:
  #   array.insert(index, obj...)  -> array
  #
  # Inserts the given values before the element with the given index
  # (which may be negative).
  #
  #    a = %w{ a b c d }
  #    a.insert(2, 99)         #=> ["a", "b", 99, "c", "d"]
  #    a.insert(-2, 1, 2, 3)   #=> ["a", "b", 99, "c", 1, 2, 3, "d"]

  def insert(position, *objects)
    if position == -1 then
      position = self.length
    elsif position < 0 then
      position += 1
    end

    return self if objects.empty?

    splice position, 0, objects

    return self
  end

  ##
  # call-seq:
  #   array.inspect  -> string
  #
  # Create a printable version of <em>array</em>.

  def inspect # HACK finish
    return "[]" if self.length == 0
    str = "[" + self.join(", ") + "]"
    return str
  end

  alias_method :old_join, :join

  ##
  # call-seq:
  #   array.join(sep=$,)    -> str
  #
  # Returns a string created by converting each element of the array to
  # a string, separated by <em>sep</em>.
  #
  #    [ "a", "b", "c" ].join        #=> "abc"
  #    [ "a", "b", "c" ].join("-")   #=> "a-b-c"

  def join(*args)
    return old_join(*args) # HACK
  end

  ##
  # call-seq:
  #   array.last     ->  obj or nil
  #   array.last(n)  ->  an_array
  #
  # Returns the last element(s) of <em>self</em>. If the array is empty,
  # the first form returns <tt>nil</tt>.
  #
  #    [ "w", "x", "y", "z" ].last   #=> "z"

  def last(count = nil)
    return self[-1] if count.nil?

    if not count.respond_to? :to_int then
      raise TypeError, "cannot convert Object into Integer"
    elsif count < 0 then
      raise ArgumentError, "negative array size (or size too big)"
    elsif count == 0 then
      return Array.new
    elsif count > self.length then
      count = 0
    end

    count = count.to_int

    return self[-count..-1]
  end

  ##
  # call-seq:
  #   array.length -> int
  #
  # Returns the number of elements in <em>self</em>. May be zero.
  #
  #    [ 1, 2, 3, 4, 5 ].length   #=> 5

  def length
    return self.size
  end

  ##
  # call-seq:
  #   array.collect {|item| block }  -> an_array
  #   array.map     {|item| block }  -> an_array
  #
  # Invokes <em>block</em> once for each element of <em>self</em>.
  # Creates a new array containing the values returned by the block. See
  # also <tt>Enumerable#collect</tt>.
  #
  #    a = [ "a", "b", "c", "d" ]
  #    a.collect {|x| x + "!" }   #=> ["a!", "b!", "c!", "d!"]
  #    a                          #=> ["a", "b", "c", "d"]

  alias_method :map, :collect # HACK

  ##
  # call-seq:
  #   array.collect! {|item| block }   ->   array
  #   array.map!     {|item| block }   ->   array
  #
  # Invokes the block once for each element of <em>self</em>, replacing
  # the element with the value returned by <em>block</em>. See also
  # <tt>Enumerable#collect</tt>.
  #
  #    a = [ "a", "b", "c", "d" ]
  #    a.collect! {|x| x + "!" }
  #    a             #=>  [ "a!", "b!", "c!", "d!" ]

  alias_method :map!, :collect! # HACK

  ##
  # call-seq:
  #   array.nitems -> int
  #
  # Returns the number of non-<tt>nil</tt> elements in <em>self</em>.
  # May be zero.
  #
  #    [ 1, nil, 3, nil, 5 ].nitems   #=> 3

  def nitems
    count = 0
    self.each do |item|
      count += 1 unless item.nil?
    end

    return count
  end

  ##
  # call-seq:
  #   arr.pack ( aTemplateString ) -> aBinaryString
  #
  # Packs the contents of <em>arr</em> into a binary sequence according
  # to the directives in <em>aTemplateString</em> (see the table below)
  # Directives ``A,'' ``a,'' and ``Z'' may be followed by a count, which
  # gives the width of the resulting field. The remaining directives
  # also may take a count, indicating the number of array elements to
  # convert. If the count is an asterisk (``<tt>*</tt>''), all remaining
  # array elements will be converted. Any of the directives
  # ``<tt>sSiIlL</tt>'' may be followed by an underscore
  # (``<tt>_</tt>'') to use the underlying platform's native size for
  # the specified type; otherwise, they use a platform-independent size.
  # Spaces are ignored in the template string. See also
  # <tt>String#unpack</tt>.
  #
  #    a = [ "a", "b", "c" ]
  #    n = [ 65, 66, 67 ]
  #    a.pack("A3A3A3")   #=> "a  b  c  "
  #    a.pack("a3a3a3")   #=> "a\000\000b\000\000c\000\000"
  #    n.pack("ccc")      #=> "ABC"
  #
  # Directives for <tt>pack</tt>.
  #
  #  Directive    Meaning
  #  ---------------------------------------------------------------
  #      @     |  Moves to absolute position
  #      A     |  ASCII string (space padded, count is width)
  #      a     |  ASCII string (null padded, count is width)
  #      B     |  Bit string (descending bit order)
  #      b     |  Bit string (ascending bit order)
  #      C     |  Unsigned char
  #      c     |  Char
  #      D, d  |  Double-precision float, native format
  #      E     |  Double-precision float, little-endian byte order
  #      e     |  Single-precision float, little-endian byte order
  #      F, f  |  Single-precision float, native format
  #      G     |  Double-precision float, network (big-endian) byte
  # order
  #      g     |  Single-precision float, network (big-endian) byte
  # order
  #      H     |  Hex string (high nibble first)
  #      h     |  Hex string (low nibble first)
  #      I     |  Unsigned integer
  #      i     |  Integer
  #      L     |  Unsigned long
  #      l     |  Long
  #      M     |  Quoted printable, MIME encoding (see RFC2045)
  #      m     |  Base64 encoded string
  #      N     |  Long, network (big-endian) byte order
  #      n     |  Short, network (big-endian) byte-order
  #      P     |  Pointer to a structure (fixed-length string)
  #      p     |  Pointer to a null-terminated string
  #      Q, q  |  64-bit number
  #      S     |  Unsigned short
  #      s     |  Short
  #      U     |  UTF-8
  #      u     |  UU-encoded string
  #      V     |  Long, little-endian byte order
  #      v     |  Short, little-endian byte order
  #      w     |  BER-compressed integer\fnm
  #      X     |  Back up a byte
  #      x     |  Null byte
  #      Z     |  Same as ``a'', except that null is added with *
  #--
  # C->Ruby Conversion guide:
  #
  # NEXTFROM -> self.at idx; idx += 1

  def pack(format)
    spc10 = " " * 10
    nul10 = "\0" * 10
    items = self.length
    res = ''
    len = 0
    idx = 0
    skip = 0

    format.split('').each_with_index do |type, i|
#puts "#{i}: #{type}"
      if skip > 0 then # skip over consumed characters
        skip -= 1
        next
      end
      next if type == ' '

      if format[i + skip + 1] == ?* then # set data length
        len = type =~ /[@Xxu]/ ? 0 : items
        skip += 1
      elsif format[i + skip + 1].chr =~ /\d/ then
        format[i + skip + 1..-1] =~ /^(\d+)/
        skip += $1.length
        len = $1.to_i
      else
        len = 1
      end

      case type
      when 'A', 'a', 'Z', 'B', 'b', 'H', 'h' then
        raise ArgumentError if idx >= self.length
        from = self.at idx
        idx += 1
        if from.nil? then
          ptr = ""
        else
          ptr = from = from.to_str
        end

        plen = ptr.length

        len = plen if format[i + skip] == ?*

        case type
        when 'a', 'A', 'Z' then
          if plen >= len then
            res << ptr[0...len]
            if format[i + skip] == ?* and type == 'Z' then
              res << "\0"
            end
          else
            res << ptr[0...plen]
            len -= plen
            while len >= 10 do
              res << (type == 'A' ? spc10 : nul10)
              len -= 10
            end
            res << (type == 'A' ? spc10 : nul10)[0...len]
          end

        when 'b' then # bit string ascending
          i = j = byte = 0

          if len > plen then
            j = (len - plen + 1) / 2
            len = plen
          end

          0.upto(len - 1) do |i|
            if ptr[i] & 1 != 0 then
              byte |= 128
            end

            if i + 1 & 7 != 0 then
              byte = byte >> 1
            else
              res << byte.chr
#puts "adding #{byte.chr.inspect}"
              byte = 0
            end
          end

          if len & 7 != 0 then
            byte = byte >> 7 - (len & 7)
            res << byte.chr
            len = j

            while len >= 10 do # shrink
              res << nul10
              len -= 10
            end
            res << nul10[0...len]
          end

        when 'B' then
          i = j = byte = 0

          if len > plen then
            j = (len - plen + 1) / 2
            len = plen
          end

          0.upto(len - 1) do |i|
            byte |= ptr[i] & 1
#p "#{i}: #{byte.inspect}, #{i & 7}"
            if i + 1 & 7 != 0 then
              byte = byte << 1
            else
              res << byte.chr
#puts "adding #{byte.chr.inspect}"
              byte = 0
            end
          end

          if len & 7 != 0 then
            byte = byte << 7 - (len & 7)
            res << byte.chr
            len = j

            while len >= 10 do # shrink
              res << nul10
              len -= 10
            end
            res << nul10[0...len]
          end

        when 'H' then
          i = j = byte = 0

          if len > plen then
            j = (len - plen + 1) / 2
            len = plen
          end

          0.upto(len - 1) do |i|
            if ptr[i] =~ /A-Za-z/ then
              byte |= ((ptr[i] & 15) + 9) & 15
            else
              byte |= ptr[i] & 15
            end

            if i + 1 & 1 != 0 then # i & 1
              byte = byte << 4
            else
              c = byte & 0xff
puts "loop, adding #{c}, byte: #{byte}"
              res << c
              byte = 0
            end
          end

          if len & 1 != 0 then
            c = byte & 0xff
puts "done, adding #{c}, byte: #{byte}"
            res << c
          end

          len = j

          while len >= 10 do # grow
            res << nul10
            len -= 10
          end
          res << nul10[0...len]
        end

      when '@' then
        len -= res.length

        if len > 0 then
          while len >= 10 do # grow
            res << nul10
            len -= 10
          end
          res << nul10[0...len]
        end

        len = -len

        if len > 0 then
          plen = res.length # shrink
          raise ArgumentError, "X outside of string" if plen < len
          res.slice!(plen - len..-1)
        end

      when 'c', 'C' then # signed/unsigned char
        while len > 0 do
          len -= 1
          from = self.at idx
          idx += 1
          c = num2i32 from
          c = 0x100 + c if c < 0
          res << c.chr
        end
      end

p res
    end

    return res
  end

  ##
  # call-seq:
  #   array.pop  -> obj or nil
  #
  # Removes the last element from <em>self</em> and returns it, or
  # <tt>nil</tt> if the array is empty.
  #
  #    a = [ "a", "m", "z" ]
  #    a.pop   #=> "z"
  #    a       #=> ["a", "m"]

  def pop
    return nil if self.empty?
    return self.slice!(-1)
  end

  ##
  # call-seq:
  #   array.push(obj, ... )   -> array
  #
  # Append---Pushes the given object(s) on to the end of this array.
  # This expression returns the array itself, so several appends may be
  # chained together.
  #
  #    a = [ "a", "b", "c" ]
  #    a.push("d", "e", "f")
  #            #=> ["a", "b", "c", "d", "e", "f"]

  def push(*args)
    args.each do |arg|
      self << arg
    end

    return self
  end

  ##
  # call-seq:
  #   array.rassoc(key) -> an_array or nil
  #
  # Searches through the array whose elements are also arrays. Compares
  # <em>key</em> with the second element of each contained array using
  # <tt>==</tt>. Returns the first contained array that matches. See
  # also <tt>Array#assoc</tt>.
  #
  #    a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ]
  #    a.rassoc("two")    #=> [2, "two"]
  #    a.rassoc("four")   #=> nil

  def rassoc(value)
    self.each do |item|
      if item.kind_of? Array and # is an array
         item.length > 1 and # of two or more items
         item.at(1) == value then # where the second matches
        return item
      end
    end

    return nil
  end

  ##
  # call-seq:
  #   array.reject {|item| block }  -> an_array
  #
  # Returns a new array containing the items in <em>self</em> for which
  # the block is not true.

  def reject(&block)
    array = self.dup
    array.reject!(&block)
    return array
  end

  ##
  # call-seq:
  #   array.reject! {|item| block }  -> array or nil
  #
  # Equivalent to <tt>Array#delete_if</tt>, deleting elements from
  # <em>self</em> for which the block evaluates to true, but returns
  # <tt>nil</tt> if no changes were made. Also see
  # <tt>Enumerable#reject</tt>.

  def reject!
    j = 0

    self.each_with_index do |item, i|
      next if yield(item) == true
      if i != j then
        self[j] = item
      end
      j += 1
    end

    return nil if self.length == j
    
    if j < self.length then
      self.slice!(j..-1)
    end

    return self
  end

  ##
  # call-seq:
  #   array.replace(other_array)  -> array
  #
  # Replaces the contents of <em>self</em> with the contents of
  # <em>other_array</em>, truncating or expanding if necessary.
  #
  #    a = [ "a", "b", "c", "d", "e" ]
  #    a.replace([ "x", "y", "z" ])   #=> ["x", "y", "z"]
  #    a                              #=> ["x", "y", "z"]

  def replace(other)
    other.each_with_index do |item, i|
      self[i] = item
    end

    self.slice!(other.length..-1)

    return self
  end

  ##
  # call-seq:
  #   array.reverse -> an_array
  #
  # Returns a new array containing <em>self</em>'s elements in reverse
  # order.
  #
  #    [ "a", "b", "c" ].reverse   #=> ["c", "b", "a"]
  #    [ 1 ].reverse               #=> [1]

  def reverse
    array = self.dup
    array.reverse!
    return array
  end

  ##
  # call-seq:
  #   array.reverse!   -> array 
  #
  # Reverses <em>self</em> in place.
  #
  #    a = [ "a", "b", "c" ]
  #    a.reverse!       #=> ["c", "b", "a"]
  #    a                #=> ["c", "b", "a"]

  def reverse!
    return self if self.length < 1

    p1 = 0
    p2 = self.length - 1

    while p1 < p2 do
      tmp = self.at p1
      self[p1] = self.at p2
      self[p2] = tmp
      p1 += 1
      p2 -= 1
    end
    
    return self
  end

  ##
  # call-seq:
  #   array.reverse_each {|item| block } 
  #
  # Same as <tt>Array#each</tt>, but traverses <em>self</em> in reverse
  # order.
  #
  #    a = [ "a", "b", "c" ]
  #    a.reverse_each {|x| print x, " " }
  #
  # produces:
  #
  #    c b a

  def reverse_each
    last_index = self.length - 1
    last_index.downto 0 do |i|
      item = self.at i
      yield item
    end

    return self
  end

  ##
  # call-seq:
  #   array.rindex(obj)    ->  int or nil
  #
  # Returns the index of the last object in <em>array</em> <tt>==</tt>
  # to <em>obj</em>. Returns <tt>nil</tt> if no match is found.
  #
  #    a = [ "a", "b", "b", "b", "c" ]
  #    a.rindex("b")   #=> 3
  #    a.rindex("z")   #=> nil

  def rindex(target)
    i = self.length - 1
    self.reverse_each do |item|
      return i if item == target
      i -= 1
    end

    return nil
  end

  ##
  # call-seq:
  #   array.select {|item| block } -> an_array
  #
  # Invokes the block passing in successive elements from
  # <em>array</em>, returning an array containing those elements for
  # which the block returns a true value (equivalent to
  # <tt>Enumerable#select</tt>).
  #
  #    a = %w{ a b c d e f }
  #    a.select {|v| v =~ /[aeiou]/}   #=> ["a", "e"]

  def select(*args) # UNTESTED deprecated
    if args.length > 0 then
      raise ArgumentError, "wrong number of arguments (" + args.length.to_s + " for 0)"
    end

    selected = Array.new
    self.each do |item|
      selected << item if yield item
    end

    return selected
  end

  ##
  # call-seq:
  #   array.shift   ->   obj or nil
  #
  # Returns the first element of <em>self</em> and removes it (shifting
  # all other elements down by one). Returns <tt>nil</tt> if the array
  # is empty.
  #
  #    args = [ "-m", "-q", "filename" ]
  #    args.shift   #=> "-m"
  #    args         #=> ["-q", "filename"]

  def shift
    return nil if self.empty?
    return self.slice!(0)
  end


  ##
  # call-seq:
  #   ()
  #
  # Alias for #length

  #def size; end # CORE

  ##
  # call-seq:
  #   array[index]                -> obj      or nil
  #   array[start, length]        -> an_array or nil
  #   array[range]                -> an_array or nil
  #   array.slice(index)          -> obj      or nil
  #   array.slice(start, length)  -> an_array or nil
  #   array.slice(range)          -> an_array or nil
  #
  # Element Reference---Returns the element at <em>index</em>, or
  # returns a subarray starting at <em>start</em> and continuing for
  # <em>length</em> elements, or returns a subarray specified by
  # <em>range</em>. Negative indices count backward from the end of the
  # array (-1 is the last element). Returns nil if the index (or
  # starting index) are out of range.
  #
  #    a = [ "a", "b", "c", "d", "e" ]
  #    a[2] +  a[0] + a[1]    #=> "cab"
  #    a[6]                   #=> nil
  #    a[1, 2]                #=> [ "b", "c" ]
  #    a[1..3]                #=> [ "b", "c", "d" ]
  #    a[4..7]                #=> [ "e" ]
  #    a[6..10]               #=> nil
  #    a[-3, 3]               #=> [ "c", "d", "e" ]
  #    # special cases
  #    a[5]                   #=> nil
  #    a[5, 1]                #=> []
  #    a[5..10]               #=> []

  alias_method :[], :slice # HACK

  ##
  # call-seq:
  #   array.slice!(index)         -> obj or nil
  #   array.slice!(start, length) -> sub_array or nil
  #   array.slice!(range)         -> sub_array or nil 
  #
  # Deletes the element(s) given by an index (optionally with a length)
  # or by a range. Returns the deleted object, subarray, or <tt>nil</tt>
  # if the index is out of range. Equivalent to:
  #
  #    def slice!(*args)
  #      result = self[*args]
  #      self[*args] = nil
  #      result
  #    end
  #    a = [ "a", "b", "c" ]
  #    a.slice!(1)     #=> "b"
  #    a               #=> ["a", "c"]
  #    a.slice!(-1)    #=> "c"
  #    a               #=> ["a"]
  #    a.slice!(100)   #=> nil
  #    a               #=> ["a"]

  #def slice!(pos, len = nil); end

  ##
  # call-seq:
  #   array.sort                   -> an_array 
  #   array.sort {| a,b | block }  -> an_array 
  #
  # Returns a new array created by sorting <em>self</em>. Comparisons
  # for the sort will be done using the <tt><=></tt> operator or using
  # an optional code block. The block implements a comparison between
  # <em>a</em> and <em>b</em>, returning -1, 0, or +1. See also
  # <tt>Enumerable#sort_by</tt>.
  #
  #    a = [ "d", "a", "e", "c", "b" ]
  #    a.sort                    #=> ["a", "b", "c", "d", "e"]
  #    a.sort {|x,y| y <=> x }   #=> ["e", "d", "c", "b", "a"]

  def sort(&block)
    sorted = self.dup
    return sorted.sort!(&block)
  end

  ##
  # call-seq:
  #   array.sort!                   -> array
  #   array.sort! {| a,b | block }  -> array 
  #
  # Sorts <em>self</em>. Comparisons for the sort will be done using the
  # <tt><=></tt> operator or using an optional code block. The block
  # implements a comparison between <em>a</em> and <em>b</em>, returning
  # -1, 0, or +1. See also <tt>Enumerable#sort_by</tt>.
  #
  #    a = [ "d", "a", "e", "c", "b" ]
  #    a.sort                    #=> ["a", "b", "c", "d", "e"]
  #    a.sort {|x,y| y <=> x }   #=> ["e", "d", "c", "b", "a"]

  def sort!(&block)
    return self if self.empty?
    pivot = self.first
    left = nil
    right = nil

    unless block.nil? then
      left, right = self[1..-1].partition { |e| 0 >= block.call(e, pivot) }
    else
      left, right = self[1..-1].partition { |e| 0 >= (e <=> pivot) }
    end

    self.replace left.sort!(&block) + [ self.first ] + right.sort!(&block)

    return self
  end

  # HACK missing tests for non-Array subclasses

  ##
  # call-seq:
  #   array.to_a     -> array
  #
  # Returns <em>self</em>. If called on a subclass of Array, converts
  # the receiver to an Array object.

  def to_a
    return self
  end

  ##
  # call-seq:
  #   array.to_ary -> array
  #
  # Returns <em>self</em>.

  def to_ary
    return self
  end

  ##
  # call-seq:
  #   array.to_s -> string
  #
  # Returns <em>self</em><tt>.join</tt>.
  #
  #    [ "a", "e", "i", "o" ].to_s   #=> "aeio"

  def to_s
    return "" if self.length == 0
    return self.join($\)
  end

  ##
  # call-seq:
  #   array.transpose -> an_array
  #
  # Assumes that <em>self</em> is an array of arrays and transposes the
  # rows and columns.
  #
  #    a = [[1,2], [3,4], [5,6]]
  #    a.transpose   #=> [[1, 3, 5], [2, 4, 6]]

  def transpose
    return self.dup if self.empty?
    elen = -1
    alen = self.length
    result = nil

    self.each_with_index do |item, i|
      tmp = convert(item)

      if elen < 0 then # first element
        elen = tmp.length
        result = Array.new elen

        0.upto(result.length - 1) do |j|
          result[j] = Array.new alen
        end
      elsif elen != tmp.length then
        raise IndexError, "element size differs (" + tmp.length.to_s + " should be " + elen.to_s + ")"
      end

      0.upto(elen - 1) do |j|
        result[j][i] = tmp[j]
      end
    end

    return result
  end

  ##
  # call-seq:
  #   array.uniq   -> an_array
  #
  # Returns a new array by removing duplicate values in <em>self</em>.
  #
  #    a = [ "a", "a", "b", "b", "c" ]
  #    a.uniq   #=> ["a", "b", "c"]

  def uniq
    array = self.dup
    array.uniq!
    return array
  end

  ##
  # call-seq:
  #   array.uniq! -> array or nil
  #
  # Removes duplicate elements from <em>self</em>. Returns <tt>nil</tt>
  # if no changes are made (that is, no duplicates are found).
  #
  #    a = [ "a", "a", "b", "b", "c" ]
  #    a.uniq!   #=> ["a", "b", "c"]
  #    b = [ "a", "b", "c" ]
  #    b.uniq!   #=> nil

  def uniq!
    hash = make_hash self

    return nil if hash.length == self.length
    
    j = 0
    self.each do |key|
      value = hash.delete key
      if value == true then
        self[j] = key
        j += 1
      end
    end

    self.slice!(j..-1)

    return self
  end

  ##
  # call-seq:
  #   array.unshift(obj, ...)  -> array
  #
  # Prepends objects to the front of <em>array</em>. other elements up
  # one.
  #
  #    a = [ "b", "c", "d" ]
  #    a.unshift("a")   #=> ["a", "b", "c", "d"]
  #    a.unshift(1, 2)  #=> [ 1, 2, "a", "b", "c", "d"]

  def unshift(*args)
    return self if args.empty?
    count = args.length

    unless self.empty? then
      (self.length - 1).downto 0 do |i|
        self[i + count] = self[i]
      end
    end

    args.each_with_index do |item, i|
      self[i] = item
    end

    return self
  end

  ##
  # call-seq:
  #   array.values_at(selector,... )  -> an_array
  #
  # Returns an array containing the elements in <em>self</em>
  # corresponding to the given selector(s). The selectors may be either
  # integer indices or ranges. See also <tt>Array#select</tt>.
  #
  #    a = %w{ a b c d e f }
  #    a.values_at(1, 3, 5)
  #    a.values_at(1, 3, 5, 7)
  #    a.values_at(-1, -3, -5, -7)
  #    a.values_at(1..3, 2...5)

  def values_at(*args)
    result = Array.new

    args.each do |arg|
      case arg
      when Fixnum then
        result << self.at(arg)
        next
      when Numeric then  
        result << self.at(arg.to_int)
      when Range then
        # HACK rb_range_beg_len
        self.each_with_index do |item, i|
          result << item if arg.include? i
        end
      else
        raise TypeError, "Cannot convert " + arg.class.name + " into Integer"
      end
    end

    return result
  end

  ##
  # call-seq:
  #   array.zip(arg, ...)                   -> an_array
  #   array.zip(arg, ...) {| arr | block }  -> nil
  #
  # Converts any arguments to arrays, then merges elements of
  # <em>self</em> with corresponding elements from each argument. This
  # generates a sequence of <tt>self.size</tt> <em>n</em>-element
  # arrays, where <em>n</em> is one more that the count of arguments. If
  # the size of any argument is less than <tt>enumObj.size</tt>,
  # <tt>nil</tt> values are supplied. If a block given, it is invoked
  # for each output array, otherwise an array of arrays is returned.
  #
  #    a = [ 4, 5, 6 ]
  #    b = [ 7, 8, 9 ]
  #    [1,2,3].zip(a, b)      #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]
  #    [1,2].zip(a,b)         #=> [[1, 4, 7], [2, 5, 8]]
  #    a.zip([1,2],[8])       #=> [[4,1,8], [5,2,nil], [6,nil,nil]]
  #--
  # HACK no tests for #zip

  def zip(*args)
    raise "I don't do that yet" if block_given?

    args = args.map { |a| convert a }
    args_len = args.length

    len = self.length
    result = Array.new len

    0.upto(length - 1) do |i|
      tmp = Array.new args_len + 1
      tmp[0] = self.at(i)

      0.upto(args_len - 1) do |j|
        tmp[j + 1] = args[j][i]
      end

      result[i] = tmp
    end

    return result
  end

  private

  def convert(object)
    unless object.respond_to? :to_ary then
      raise TypeError, "cannot convert " + object.class.name + " into Array"
    end
    return object.to_ary
  end

  def help_flatten(index, sub_array, memo)
    i = index
    n = 0
    limit = index + sub_array.length

    id = sub_array.object_id

    if memo.include? id then
      raise ArgumentError, "tried to flatten recursive array"
    end

    memo.push id
    splice index, 1, sub_array

    while i < limit do
      temp = self.at i
      if temp.respond_to? :to_ary then
        n = help_flatten i, temp.to_ary, memo
        i += n
        limit += n
      end
      i += 1
    end

    memo.pop

    return limit - index - 1 # number of increased items
  end

  def make_hash(*arrays)
    hash = Hash.new

    arrays.each do |array|
      array.each_with_index do |key, i|
        hash[key] = true
      end
    end

    return hash
  end

  def mem_clear(start, count)
    start.upto(start + count) do |i|
      self[i] = nil
    end
  end

  def mem_copy(dest, start, source, offset, length)
    0.upto(length - 1) do |i|
      dest[i + start] = source.at(i + offset)
    end
  end

  def splice(beg, len, rpl)
    raise IndexError, "negative len (" + len.to_s + ")" if len < 0

    if beg < 0 then
      beg += self.length
      if beg < 0 then
        beg -= self.length
        raise IndexError, "index " + beg.to_s + " out of self"
      end
    end

    if beg + len > self.length then
      len = self.length - beg
    end

    rlen = 0

    unless rpl.nil? then
      rpl = rpl.to_ary
      rlen = rpl.length
    end

    if beg >= self.length then
      len = beg + rlen
      mem_clear self.length, beg - self.length
      if rlen > 0 then
        mem_copy self, beg, rpl, 0, rlen
      end
      self.slice!(len..-1)
    else
      if beg + len > self.length then
        len = self.length - beg
      end

      alen = self.length + rlen - len

      if len != rlen then
        mem_copy(self, beg + rlen,
                 self, beg + len,
                 self.length - (beg + len))
        self.slice!(alen..-1)
      end

      mem_copy(self, beg, rpl, 0, rlen) if rlen > 0
    end
  end

  # For pack

  def num2i32(x) # :nodoc:
    y = x.to_int
    return y if y.kind_of? Integer
    raise TypeError, "can't convert " + x.class + " to `integer'"
  end

end

puts 'DONE!'
