[前][次][番号順一覧][スレッド一覧]

ruby-changes:2609

From: ko1@a...
Date: 4 Dec 2007 17:10:07 +0900
Subject: [ruby-changes:2609] naruse - Ruby:r14100 (trunk): * lib/json.rb, lib/json/*: moved to ext/json/lib.

naruse	2007-12-04 17:09:44 +0900 (Tue, 04 Dec 2007)

  New Revision: 14100

  Added directories:
    trunk/ext/json/lib/
    trunk/ext/json/lib/json/
  Added files:
    trunk/ext/json/extconf.rb
    trunk/ext/json/lib/json.rb
  Removed directories:
    trunk/lib/json/
  Removed files:
    trunk/lib/json.rb
  Modified files:
    trunk/ChangeLog

  Log:
    * lib/json.rb, lib/json/*: moved to ext/json/lib.
    --
    
    M    trunk/ChangeLog
    D    trunk/lib/json
    D    trunk/lib/json.rb
    A    trunk/ext/json/lib
    A    trunk/ext/json/lib/json
    A    trunk/ext/json/lib/json.rb
    A    trunk/ext/json/extconf.rb

  Added: trunk/ext/json/lib/

  Added: trunk/ext/json/lib/json/

  Deleted: trunk/lib/json/
    % svn ls -r 14100 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/json/

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ext/json/lib/json
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ChangeLog?r1=14100&r2=14099
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ext/json/extconf.rb?revision=14100&view=markup
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/lib/json.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/trunk/ext/json/lib/json.rb

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 14099)
+++ ChangeLog	(revision 14100)
@@ -1,3 +1,7 @@
+Tue Dec  4 17:07:25 2007  NARUSE, Yui  <naruse@r...>
+
+	* lib/json.rb, lib/json/*: moved to ext/json/lib.
+
 Tue Dec  4 16:34:46 2007  Nobuyoshi Nakada  <nobu@r...>
 
 	* ext/iconv/iconv.c (iconv_create): achieve target encoding.
Index: lib/json.rb
===================================================================
--- lib/json.rb	(revision 14099)
+++ lib/json.rb	(revision 14100)
@@ -1,235 +0,0 @@
-require 'json/common'
-# = json - JSON for Ruby
-#
-# == Description
-#
-# This is a implementation of the JSON specification according to RFC 4627
-# (http://www.ietf.org/rfc/rfc4627.txt). Starting from version 1.0.0 on there
-# will be two variants available:
-#
-# * A pure ruby variant, that relies on the iconv and the stringscan
-#   extensions, which are both part of the ruby standard library.
-# * The quite a bit faster C extension variant, which is in parts implemented
-#   in C and comes with its own unicode conversion functions and a parser
-#   generated by the ragel state machine compiler
-#   (http://www.cs.queensu.ca/~thurston/ragel).
-#
-# Both variants of the JSON generator escape all non-ASCII an control
-# characters with \uXXXX escape sequences, and support UTF-16 surrogate pairs
-# in order to be able to generate the whole range of unicode code points. This
-# means that generated JSON text is encoded as UTF-8 (because ASCII is a subset
-# of UTF-8) and at the same time avoids decoding problems for receiving
-# endpoints, that don't expect UTF-8 encoded texts. On the negative side this
-# may lead to a bit longer strings than necessarry.
-#
-# All strings, that are to be encoded as JSON strings, should be UTF-8 byte
-# sequences on the Ruby side. To encode raw binary strings, that aren't UTF-8
-# encoded, please use the to_json_raw_object method of String (which produces
-# an object, that contains a byte array) and decode the result on the receiving
-# endpoint.
-#
-# == Author
-#
-# Florian Frank <mailto:flori@p...>
-#
-# == License
-#
-# This software is distributed under the same license as Ruby itself, see
-# http://www.ruby-lang.org/en/LICENSE.txt.
-#
-# == Download
-#
-# The latest version of this library can be downloaded at
-#
-# * http://rubyforge.org/frs?group_id=953
-#
-# Online Documentation should be located at
-#
-# * http://json.rubyforge.org
-#
-# == Usage
-# 
-# To use JSON you can
-#   require 'json'
-# to load the installed variant (either the extension 'json' or the pure
-# variant 'json_pure'). If you have installed the extension variant, you can
-# pick either the extension variant or the pure variant by typing
-#   require 'json/ext'
-# or
-#   require 'json/pure'
-#
-# You can choose to load a set of common additions to ruby core's objects if
-# you
-#   require 'json/add/core'
-#
-# After requiring this you can, e. g., serialise/deserialise Ruby ranges:
-#
-#   JSON JSON(1..10) # => 1..10
-#
-# To find out how to add JSON support to other or your own classes, read the
-# Examples section below.
-#
-# To get the best compatibility to rails' JSON implementation, you can
-#   require 'json/add/rails'
-#
-# Both of the additions attempt to require 'json' (like above) first, if it has
-# not been required yet.
-#
-# == Speed Comparisons
-#
-# I have created some benchmark results (see the benchmarks subdir of the
-# package) for the JSON-Parser to estimate the speed up in the C extension:
-#
-# JSON::Pure::Parser::  28.90  calls/second
-# JSON::Ext::Parser::  505.50 calls/second
-#
-# This is ca. <b>17.5</b> times the speed of the pure Ruby implementation.
-#
-# I have benchmarked the JSON-Generator as well. This generates a few more
-# values, because there are different modes, that also influence the achieved
-# speed:
-#
-# * JSON::Pure::Generator:
-#   generate::        35.06 calls/second
-#   pretty_generate:: 34.00 calls/second
-#   fast_generate::   41.06 calls/second
-#
-# * JSON::Ext::Generator:
-#   generate::        492.11 calls/second
-#   pretty_generate:: 348.85 calls/second
-#   fast_generate::   541.60 calls/second
-#
-# * Speedup Ext/Pure:
-#   generate safe::   14.0 times
-#   generate pretty:: 10.3 times
-#   generate fast::   13.2 times
-#
-# The rails framework includes a generator as well, also it seems to be rather
-# slow: I measured only 23.87 calls/second which is slower than any of my pure
-# generator results. Here a comparison of the different speedups with the Rails
-# measurement as the divisor:
-#
-# * Speedup Pure/Rails:
-#   generate safe::   1.5 times
-#   generate pretty:: 1.4 times
-#   generate fast::   1.7 times
-#
-# * Speedup Ext/Rails:
-#   generate safe::   20.6 times
-#   generate pretty:: 14.6 times
-#   generate fast::   22.7 times
-#
-# To achieve the fastest JSON text output, you can use the
-# fast_generate/fast_unparse methods. Beware, that this will disable the
-# checking for circular Ruby data structures, which may cause JSON to go into
-# an infinite loop.
-#
-# == Examples
-#
-# To create a JSON text from a ruby data structure, you
-# can call JSON.generate (or JSON.unparse) like that:
-#
-#  json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
-#  # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
-#
-# To create a valid JSON text you have to make sure, that the output is
-# embedded in either a JSON array [] or a JSON object {}. The easiest way to do
-# this, is by putting your values in a Ruby Array or Hash instance.
-#
-# To get back a ruby data structure from a JSON text, you have to call
-# JSON.parse on it:
-#
-#  JSON.parse json
-#  # => [1, 2, {"a"=>3.141}, false, true, nil, "4..10"]
-# 
-# Note, that the range from the original data structure is a simple
-# string now. The reason for this is, that JSON doesn't support ranges
-# or arbitrary classes. In this case the json library falls back to call
-# Object#to_json, which is the same as #to_s.to_json.
-#
-# It's possible to add JSON support serialization to arbitrary classes by
-# simply implementing a more specialized version of the #to_json method, that
-# should return a JSON object (a hash converted to JSON with #to_json) like
-# this (don't forget the *a for all the arguments):
-#
-#  class Range
-#    def to_json(*a)
-#      {
-#        'json_class'   => self.class.name, # = 'Range'
-#        'data'         => [ first, last, exclude_end? ]
-#      }.to_json(*a)
-#    end
-#  end
-#
-# The hash key 'json_class' is the class, that will be asked to deserialise the
-# JSON representation later. In this case it's 'Range', but any namespace of
-# the form 'A::B' or '::A::B' will do. All other keys are arbitrary and can be
-# used to store the necessary data to configure the object to be deserialised.
-#
-# If a the key 'json_class' is found in a JSON object, the JSON parser checks
-# if the given class responds to the json_create class method. If so, it is
-# called with the JSON object converted to a Ruby hash. So a range can
-# be deserialised by implementing Range.json_create like this:
-# 
-#  class Range
-#    def self.json_create(o)
-#      new(*o['data'])
-#    end
-#  end
-#
-# Now it possible to serialise/deserialise ranges as well:
-#
-#  json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
-#  # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
-#  JSON.parse json
-#  # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
-#
-# JSON.generate always creates the shortest possible string representation of a
-# ruby data structure in one line. This good for data storage or network
-# protocols, but not so good for humans to read. Fortunately there's also
-# JSON.pretty_generate (or JSON.pretty_generate) that creates a more
-# readable output:
-#
-#  puts JSON.pretty_generate([1, 2, {"a"=>3.141}, false, true, nil, 4..10])
-#  [
-#    1,
-#    2,
-#    {
-#      "a": 3.141
-#    },
-#    false,
-#    true,
-#    null,
-#    {
-#      "json_class": "Range",
-#      "data": [
-#        4,
-#        10,
-#        false
-#      ]
-#    }
-#  ]
-#
-# There are also the methods Kernel#j for unparse, and Kernel#jj for
-# pretty_unparse output to the console, that work analogous to Core Ruby's p
-# and the pp library's pp methods.
-#
-# The script tools/server.rb contains a small example if you want to test, how
-# receiving a JSON object from a webrick server in your browser with the
-# javasript prototype library (http://www.prototypejs.org) works.
-#
-module JSON
-  require 'json/version'
-
-  if VARIANT_BINARY
-    require 'json/ext'
-  else
-    begin
-      require 'json/ext'
-    rescue LoadError
-      require 'json/pure'
-    end
-  end
-
-  JSON_LOADED = true
-end
Index: ext/json/lib/json/Array.xpm
===================================================================
--- ext/json/lib/json/Array.xpm	(revision 0)
+++ ext/json/lib/json/Array.xpm	(revision 14100)
@@ -0,0 +1,21 @@
+/* XPM */
+static char * Array_xpm[] = {
+"16 16 2 1",
+" 	c None",
+".	c #000000",
+"                ",
+"                ",
+"                ",
+"   ..........   ",
+"   .        .   ",
+"   .        .   ",
+"   .        .   ",
+"   .        .   ",
+"   .        .   ",
+"   .        .   ",
+"   .        .   ",
+"   .        .   ",
+"   ..........   ",
+"                ",
+"                ",
+"                "};

Property changes on: ext/json/lib/json/Array.xpm
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/FalseClass.xpm
===================================================================
--- ext/json/lib/json/FalseClass.xpm	(revision 0)
+++ ext/json/lib/json/FalseClass.xpm	(revision 14100)
@@ -0,0 +1,21 @@
+/* XPM */
+static char * False_xpm[] = {
+"16 16 2 1",
+" 	c None",
+".	c #FF0000",
+"                ",
+"                ",
+"                ",
+"     ......     ",
+"     .          ",
+"     .          ",
+"     .          ",
+"     ......     ",
+"     .          ",
+"     .          ",
+"     .          ",
+"     .          ",
+"     .          ",
+"                ",
+"                ",
+"                "};

Property changes on: ext/json/lib/json/FalseClass.xpm
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/Hash.xpm
===================================================================
--- ext/json/lib/json/Hash.xpm	(revision 0)
+++ ext/json/lib/json/Hash.xpm	(revision 14100)
@@ -0,0 +1,21 @@
+/* XPM */
+static char * Hash_xpm[] = {
+"16 16 2 1",
+" 	c None",
+".	c #000000",
+"                ",
+"                ",
+"                ",
+"       .  .     ",
+"       .  .     ",
+"       .  .     ",
+"    .........   ",
+"      .  .      ",
+"      .  .      ",
+"   .........    ",
+"     .  .       ",
+"     .  .       ",
+"     .  .       ",
+"                ",
+"                ",
+"                "};

Property changes on: ext/json/lib/json/Hash.xpm
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/version.rb
===================================================================
--- ext/json/lib/json/version.rb	(revision 0)
+++ ext/json/lib/json/version.rb	(revision 14100)
@@ -0,0 +1,9 @@
+module JSON
+  # JSON version
+  VERSION         = '1.1.2'
+  VERSION_ARRAY   = VERSION.split(/\./).map { |x| x.to_i } # :nodoc:
+  VERSION_MAJOR   = VERSION_ARRAY[0] # :nodoc:
+  VERSION_MINOR   = VERSION_ARRAY[1] # :nodoc:
+  VERSION_BUILD   = VERSION_ARRAY[2] # :nodoc:
+  VARIANT_BINARY  = false
+end

Property changes on: ext/json/lib/json/version.rb
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/editor.rb
===================================================================
--- ext/json/lib/json/editor.rb	(revision 0)
+++ ext/json/lib/json/editor.rb	(revision 14100)
@@ -0,0 +1,1363 @@
+# To use the GUI JSON editor, start the edit_json.rb executable script. It
+# requires ruby-gtk to be installed.
+
+require 'gtk2'
+require 'iconv'
+require 'json'
+require 'rbconfig'
+require 'open-uri'
+
+module JSON
+  module Editor
+    include Gtk
+
+    # Beginning of the editor window title
+    TITLE                 = 'JSON Editor'.freeze
+
+    # Columns constants
+    ICON_COL, TYPE_COL, CONTENT_COL = 0, 1, 2
+
+    # JSON primitive types (Containers)
+    CONTAINER_TYPES = %w[Array Hash].sort
+    # All JSON primitive types
+    ALL_TYPES = (%w[TrueClass FalseClass Numeric String NilClass] +
+                 CONTAINER_TYPES).sort
+
+    # The Nodes necessary for the tree representation of a JSON document
+    ALL_NODES = (ALL_TYPES + %w[Key]).sort
+
+    DEFAULT_DIALOG_KEY_PRESS_HANDLER = lambda do |dialog, event|
+      case event.keyval
+      when Gdk::Keyval::GDK_Return
+        dialog.response Dialog::RESPONSE_ACCEPT
+      when Gdk::Keyval::GDK_Escape
+        dialog.response Dialog::RESPONSE_REJECT
+      end
+    end
+
+    # Returns the Gdk::Pixbuf of the icon named _name_ from the icon cache.
+    def Editor.fetch_icon(name)
+      @icon_cache ||= {}
+      unless @icon_cache.key?(name)
+        path = File.dirname(__FILE__)
+        @icon_cache[name] = Gdk::Pixbuf.new(File.join(path, name + '.xpm'))
+      end
+     @icon_cache[name]
+    end
+
+    # Opens an error dialog on top of _window_ showing the error message
+    # _text_.
+    def Editor.error_dialog(window, text)
+      dialog = MessageDialog.new(window, Dialog::MODAL, 
+        MessageDialog::ERROR, 
+        MessageDialog::BUTTONS_CLOSE, text)
+      dialog.show_all
+      dialog.run
+    rescue TypeError
+      dialog = MessageDialog.new(Editor.window, Dialog::MODAL, 
+        MessageDialog::ERROR, 
+        MessageDialog::BUTTONS_CLOSE, text)
+      dialog.show_all
+      dialog.run
+    ensure
+      dialog.destroy if dialog
+    end
+
+    # Opens a yes/no question dialog on top of _window_ showing the error
+    # message _text_. If yes was answered _true_ is returned, otherwise
+    # _false_.
+    def Editor.question_dialog(window, text)
+      dialog = MessageDialog.new(window, Dialog::MODAL, 
+        MessageDialog::QUESTION, 
+        MessageDialog::BUTTONS_YES_NO, text)
+      dialog.show_all
+      dialog.run do |response|
+        return Gtk::Dialog::RESPONSE_YES === response
+      end
+    ensure
+      dialog.destroy if dialog
+    end
+
+    # Convert the tree model starting from Gtk::TreeIter _iter_ into a Ruby
+    # data structure and return it.
+    def Editor.model2data(iter)
+      return nil if iter.nil?
+      case iter.type
+      when 'Hash'
+        hash = {}
+        iter.each { |c| hash[c.content] = Editor.model2data(c.first_child) }
+        hash
+      when 'Array'
+        array = Array.new(iter.n_children)
+        iter.each_with_index { |c, i| array[i] = Editor.model2data(c) }
+        array
+      when 'Key'
+        iter.content
+      when 'String'
+        iter.content
+      when 'Numeric'
+        content = iter.content
+        if /\./.match(content)
+          content.to_f
+        else
+          content.to_i
+        end
+      when 'TrueClass'
+        true
+      when 'FalseClass'
+        false
+      when 'NilClass'
+        nil
+      else
+        fail "Unknown type found in model: #{iter.type}"
+      end
+    end
+
+    # Convert the Ruby data structure _data_ into tree model data for Gtk and
+    # returns the whole model. If the parameter _model_ wasn't given a new
+    # Gtk::TreeStore is created as the model. The _parent_ parameter specifies
+    # the parent node (iter, Gtk:TreeIter instance) to which the data is
+    # appended, alternativeley the result of the yielded block is used as iter.
+    def Editor.data2model(data, model = nil, parent = nil)
+      model ||= TreeStore.new(Gdk::Pixbuf, String, String)
+      iter = if block_given?
+        yield model
+      else
+        model.append(parent)
+      end
+      case data
+      when Hash
+        iter.type = 'Hash'
+        data.sort.each do |key, value|
+          pair_iter = model.append(iter)
+          pair_iter.type    = 'Key'
+          pair_iter.content = key.to_s
+          Editor.data2model(value, model, pair_iter)
+        end
+      when Array
+        iter.type = 'Array'
+        data.each do |value|
+          Editor.data2model(value, model, iter)
+        end
+      when Numeric
+        iter.type = 'Numeric'
+        iter.content = data.to_s
+      when String, true, false, nil
+        iter.type    = data.class.name
+        iter.content = data.nil? ? 'null' : data.to_s
+      else
+        iter.type    = 'String'
+        iter.content = data.to_s
+      end
+      model
+    end
+
+    # The Gtk::TreeIter class is reopened and some auxiliary methods are added.
+    class Gtk::TreeIter
+      include Enumerable
+
+      # Traverse each of this Gtk::TreeIter instance's children
+      # and yield to them.
+      def each
+        n_children.times { |i| yield nth_child(i) }
+      end
+
+      # Recursively traverse all nodes of this Gtk::TreeIter's subtree
+      # (including self) and yield to them.
+      def recursive_each(&block)
+        yield self
+        each do |i|
+          i.recursive_each(&block)
+        end
+      end
+
+      # Remove the subtree of this Gtk::TreeIter instance from the
+      # model _model_.
+      def remove_subtree(model)
+        while current = first_child
+          model.remove(current)
+        end
+      end
+
+      # Returns the type of this node.
+      def type
+        self[TYPE_COL]
+      end
+
+      # Sets the type of this node to _value_. This implies setting
+      # the respective icon accordingly.
+      def type=(value)
+        self[TYPE_COL] = value
+        self[ICON_COL] = Editor.fetch_icon(value)
+      end
+
+      # Returns the content of this node.
+      def content
+        self[CONTENT_COL]
+      end
+
+      # Sets the content of this node to _value_.
+      def content=(value)
+        self[CONTENT_COL] = value
+      end
+    end
+
+    # This module bundles some method, that can be used to create a menu. It
+    # should be included into the class in question.
+    module MenuExtension
+      include Gtk
+
+      # Creates a Menu, that includes MenuExtension. _treeview_ is the
+      # Gtk::TreeView, on which it operates.
+      def initialize(treeview)
+        @treeview = treeview
+        @menu = Menu.new
+      end
+
+      # Returns the Gtk::TreeView of this menu.
+      attr_reader :treeview
+
+      # Returns the menu.
+      attr_reader :menu
+
+      # Adds a Gtk::SeparatorMenuItem to this instance's #menu.
+      def add_separator
+        menu.append SeparatorMenuItem.new
+      end
+
+      # Adds a Gtk::MenuItem to this instance's #menu. _label_ is the label
+      # string, _klass_ is the item type, and _callback_ is the procedure, that
+      # is called if the _item_ is activated.
+      def add_item(label, keyval = nil, klass = MenuItem, &callback)
+        label = "#{label} (C-#{keyval.chr})" if keyval
+        item = klass.new(label)
+        item.signal_connect(:activate, &callback)
+        if keyval
+          self.signal_connect(:'key-press-event') do |item, event|
+            if event.state & Gdk::Window::ModifierType::CONTROL_MASK != 0 and
+              event.keyval == keyval
+              callback.call item
+            end
+          end
+        end
+        menu.append item
+        item
+      end
+
+      # This method should be implemented in subclasses to create the #menu of
+      # this instance. It has to be called after an instance of this class is
+      # created, to build the menu.
+      def create
+        raise NotImplementedError
+      end
+
+      def method_missing(*a, &b)
+        treeview.__send__(*a, &b)
+      end
+    end
+
+    # This class creates the popup menu, that opens when clicking onto the
+    # treeview.
+    class PopUpMenu
+      include MenuExtension
+
+      # Change the type or content of the selected node.
+      def change_node(item)
+        if current = selection.selected
+          parent = current.parent
+          old_type, old_content = current.type, current.content
+          if ALL_TYPES.include?(old_type)
+            @clipboard_data = Editor.model2data(current)
+            type, content = ask_for_element(parent, current.type,
+              current.content)
+            if type
+              current.type, current.content = type, content
+              current.remove_subtree(model)
+              toplevel.display_status("Changed a node in tree.")
+              window.change
+            end
+          else
+            toplevel.display_status(
+              "Cannot change node of type #{old_type} in tree!")
+          end
+        end
+      end
+
+      # Cut the selected node and its subtree, and save it into the
+      # clipboard.
+      def cut_node(item)
+        if current = selection.selected
+          if current and current.type == 'Key'
+            @clipboard_data = {
+              current.content => Editor.model2data(current.first_child)
+            }
+          else
+            @clipboard_data = Editor.model2data(current)
+          end
+          model.remove(current)
+          window.change
+          toplevel.display_status("Cut a node from tree.")
+        end
+      end
+
+      # Copy the selected node and its subtree, and save it into the
+      # clipboard.
+      def copy_node(item)
+        if current = selection.selected
+          if current and current.type == 'Key'
+            @clipboard_data = {
+              current.content => Editor.model2data(current.first_child)
+            }
+          else
+            @clipboard_data = Editor.model2data(current)
+          end
+          window.change
+          toplevel.display_status("Copied a node from tree.")
+        end
+      end
+
+      # Paste the data in the clipboard into the selected Array or Hash by
+      # appending it.
+      def paste_node_appending(item)
+        if current = selection.selected
+          if @clipboard_data
+            case current.type
+            when 'Array'
+              Editor.data2model(@clipboard_data, model, current)
+              expand_collapse(current)
+            when 'Hash'
+              if @clipboard_data.is_a? Hash
+                parent = current.parent
+                hash = Editor.model2data(current)
+                model.remove(current)
+                hash.update(@clipboard_data)
+                Editor.data2model(hash, model, parent)
+                if parent
+                  expand_collapse(parent)
+                elsif @expanded
+                  expand_all
+                end
+                window.change
+              else
+                toplevel.display_status(
+                  "Cannot paste non-#{current.type} data into '#{current.type}'!")
+              end
+            else
+              toplevel.display_status(
+                "Cannot paste node below '#{current.type}'!")
+            end
+          else
+            toplevel.display_status("Nothing to paste in clipboard!")
+          end
+        else
+            toplevel.display_status("Append a node into the root first!")
+        end
+      end
+
+      # Paste the data in the clipboard into the selected Array inserting it
+      # before the selected element.
+      def paste_node_inserting_before(item)
+        if current = selection.selected
+          if @clipboard_data
+            parent = current.parent or return
+            parent_type = parent.type
+            if parent_type == 'Array'
+              selected_index = parent.each_with_index do |c, i|
+                break i if c == current
+              end
+              Editor.data2model(@clipboard_data, model, parent) do |m|
+                m.insert_before(parent, current)
+              end
+              expand_collapse(current)
+              toplevel.display_status("Inserted an element to " +
+                "'#{parent_type}' before index #{selected_index}.")
+              window.change
+            else
+              toplevel.display_status(
+                "Cannot insert node below '#{parent_type}'!")
+            end
+          else
+            toplevel.display_status("Nothing to paste in clipboard!")
+          end
+        else
+            toplevel.display_status("Append a node into the root first!")
+        end
+      end
+
+      # Append a new node to the selected Hash or Array.
+      def append_new_node(item)
+        if parent = selection.selected
+          parent_type = parent.type
+          case parent_type
+          when 'Hash'
+            key, type, content = ask_for_hash_pair(parent)
+            key or return
+            iter = create_node(parent, 'Key', key)
+            iter = create_node(iter, type, content)
+            toplevel.display_status(
+              "Added a (key, value)-pair to '#{parent_type}'.")
+            window.change
+          when 'Array'
+            type, content = ask_for_element(parent)
+            type or return
+            iter = create_node(parent, type, content)
+            window.change
+            toplevel.display_status("Appendend an element to '#{parent_type}'.")
+          else
+            toplevel.display_status("Cannot append to '#{parent_type}'!")
+          end
+        else
+          type, content = ask_for_element
+          type or return
+          iter = create_node(nil, type, content)
+          window.change
+        end
+      end
+
+      # Insert a new node into an Array before the selected element.
+      def insert_new_node(item)
+        if current = selection.selected
+          parent = current.parent or return
+          parent_parent = parent.parent
+          parent_type = parent.type
+          if parent_type == 'Array'
+            selected_index = parent.each_with_index do |c, i|
+              break i if c == current
+            end
+            type, content = ask_for_element(parent)
+            type or return
+            iter = model.insert_before(parent, current)
+            iter.type, iter.content = type, content
+            toplevel.display_status("Inserted an element to " +
+              "'#{parent_type}' before index #{selected_index}.")
+            window.change
+          else
+            toplevel.display_status(
+              "Cannot insert node below '#{parent_type}'!")
+          end
+        else
+            toplevel.display_status("Append a node into the root first!")
+        end
+      end
+
+      # Recursively collapse/expand a subtree starting from the selected node.
+      def collapse_expand(item)
+        if current = selection.selected
+          if row_expanded?(current.path)
+            collapse_row(current.path)
+          else
+            expand_row(current.path, true)
+          end
+        else
+            toplevel.display_status("Append a node into the root first!")
+        end
+      end
+
+      # Create the menu.
+      def create
+        add_item("Change node", ?n, &method(:change_node))
+        add_separator
+        add_item("Cut node", ?X, &method(:cut_node))
+        add_item("Copy node", ?C, &method(:copy_node))
+        add_item("Paste node (appending)", ?A, &method(:paste_node_appending))
+        add_item("Paste node (inserting before)", ?I,
+          &method(:paste_node_inserting_before))
+        add_separator
+        add_item("Append new node", ?a, &method(:append_new_node))
+        add_item("Insert new node before", ?i, &method(:insert_new_node))
+        add_separator 
+        add_item("Collapse/Expand node (recursively)", ?e,
+          &method(:collapse_expand))
+
+        menu.show_all
+        signal_connect(:button_press_event) do |widget, event|
+          if event.kind_of? Gdk::EventButton and event.button == 3
+            menu.popup(nil, nil, event.button, event.time)
+          end
+        end
+        signal_connect(:popup_menu) do
+          menu.popup(nil, nil, 0, Gdk::Event::CURRENT_TIME)
+        end
+      end
+    end
+
+    # This class creates the File pulldown menu.
+    class FileMenu
+      include MenuExtension
+
+      # Clear the model and filename, but ask to save the JSON document, if
+      # unsaved changes have occured.
+      def new(item)
+        window.clear
+      end
+
+      # Open a file and load it into the editor. Ask to save the JSON document
+      # first, if unsaved changes have occured.
+      def open(item)
+        window.file_open
+      end
+
+      def open_location(item)
+        window.location_open
+      end
+
+      # Revert the current JSON document in the editor to the saved version.
+      def revert(item)
+        window.instance_eval do
+          @filename and file_open(@filename) 
+        end
+      end
+
+      # Save the current JSON document.
+      def save(item)
+        window.file_save
+      end
+
+      # Save the current JSON document under the given filename.
+      def save_as(item)
+        window.file_save_as
+      end
+
+      # Quit the editor, after asking to save any unsaved changes first.
+      def quit(item)
+        window.quit
+      end
+
+      # Create the menu.
+      def create
+        title = MenuItem.new('File')
+        title.submenu = menu
+        add_item('New', &method(:new))
+        add_item('Open', ?o, &method(:open))
+        add_item('Open location', ?l, &method(:open_location))
+        add_item('Revert', &method(:revert))
+        add_separator
+        add_item('Save', ?s, &method(:save))
+        add_item('Save As', ?S, &method(:save_as))
+        add_separator
+        add_item('Quit', ?q, &method(:quit))
+        title
+      end
+    end
+
+    # This class creates the Edit pulldown menu.
+    class EditMenu
+      include MenuExtension
+
+      # Copy data from model into primary clipboard.
+      def copy(item)
+        data = Editor.model2data(model.iter_first)
+        json = JSON.pretty_generate(data, :max_nesting => false)
+        c = Gtk::Clipboard.get(Gdk::Selection::PRIMARY)
+        c.text = json
+      end
+
+      # Copy json text from primary clipboard into model.
+      def paste(item)
+        c = Gtk::Clipboard.get(Gdk::Selection::PRIMARY)
+        if json = c.wait_for_text
+          window.ask_save if @changed
+          begin
+            window.edit json
+          rescue JSON::ParserError
+            window.clear
+          end
+        end
+      end
+
+      # Find a string in all nodes' contents and select the found node in the
+      # treeview.
+      def find(item)
+        @search = ask_for_find_term(@search) or return
+        iter = model.get_iter('0') or return
+        iter.recursive_each do |i|
+          if @iter
+            if @iter != i
+              next
+            else
+              @iter = nil
+              next
+            end
+          elsif @search.match(i[CONTENT_COL])
+             set_cursor(i.path, nil, false)
+             @iter = i
+             break
+          end
+        end
+      end
+
+      # Repeat the last search given by #find.
+      def find_again(item)
+        @search or return
+        iter = model.get_iter('0')
+        iter.recursive_each do |i|
+          if @iter
+            if @iter != i
+              next
+            else
+              @iter = nil
+              next
+            end
+          elsif @search.match(i[CONTENT_COL])
+             set_cursor(i.path, nil, false)
+             @iter = i
+             break
+          end
+        end
+      end
+
+      # Sort (Reverse sort) all elements of the selected array by the given
+      # expression. _x_ is the element in question.
+      def sort(item)
+        if current = selection.selected
+          if current.type == 'Array'
+            parent = current.parent
+            ary = Editor.model2data(current)
+            order, reverse = ask_for_order
+            order or return
+            begin
+              block = eval "lambda { |x| #{order} }"
+              if reverse
+                ary.sort! { |a,b| block[b] <=> block[a] }
+              else
+                ary.sort! { |a,b| block[a] <=> block[b] }
+              end
+            rescue => e
+              Editor.error_dialog(self, "Failed to sort Array with #{order}: #{e}!")
+            else
+              Editor.data2model(ary, model, parent) do |m|
+                m.insert_before(parent, current)
+              end
+              model.remove(current)
+              expand_collapse(parent)
+              window.change
+              toplevel.display_status("Array has been sorted.")
+            end
+          else
+            toplevel.display_status("Only Array nodes can be sorted!")
+          end
+        else
+            toplevel.display_status("Select an Array to sort first!")
+        end
+      end
+
+      # Create the menu.
+      def create
+        title = MenuItem.new('Edit')
+        title.submenu = menu
+        add_item('Copy', ?c, &method(:copy))
+        add_item('Paste', ?v, &method(:paste))
+        add_separator
+        add_item('Find', ?f, &method(:find))
+        add_item('Find Again', ?g, &method(:find_again))
+        add_separator
+        add_item('Sort', ?S, &method(:sort))
+        title
+      end
+    end
+
+    class OptionsMenu
+      include MenuExtension
+
+      # Collapse/Expand all nodes by default.
+      def collapsed_nodes(item)
+        if expanded
+          self.expanded = false
+          collapse_all
+        else
+          self.expanded = true
+          expand_all 
+        end
+      end
+
+      # Toggle pretty saving mode on/off.
+      def pretty_saving(item)
+        @pretty_item.toggled
+        window.change
+      end
+
+      attr_reader :pretty_item
+
+      # Create the menu.
+      def create
+        title = MenuItem.new('Options')
+        title.submenu = menu
+        add_item('Collapsed nodes', nil, CheckMenuItem, &method(:collapsed_nodes))
+        @pretty_item = add_item('Pretty saving', nil, CheckMenuItem,
+          &method(:pretty_saving))
+        @pretty_item.active = true
+        window.unchange
+        title
+      end
+    end
+
+    # This class inherits from Gtk::TreeView, to configure it and to add a lot
+    # of behaviour to it.
+    class JSONTreeView < Gtk::TreeView
+      include Gtk
+
+      # Creates a JSONTreeView instance, the parameter _window_ is
+      # a MainWindow instance and used for self delegation.
+      def initialize(window)
+        @window = window
+        super(TreeStore.new(Gdk::Pixbuf, String, String))
+        self.selection.mode = SELECTION_BROWSE
+
+        @expanded = false
+        self.headers_visible = false
+        add_columns
+        add_popup_menu
+      end
+
+      # Returns the MainWindow instance of this JSONTreeView.
+      attr_reader :window
+
+      # Returns true, if nodes are autoexpanding, false otherwise.
+      attr_accessor :expanded
+
+      private
+
+      def add_columns
+        cell = CellRendererPixbuf.new
+        column = TreeViewColumn.new('Icon', cell,
+          'pixbuf'      => ICON_COL
+        )
+        append_column(column)
+
+        cell = CellRendererText.new
+        column = TreeViewColumn.new('Type', cell,
+          'text'      => TYPE_COL
+        )
+        append_column(column)
+
+        cell = CellRendererText.new
+        cell.editable = true
+        column = TreeViewColumn.new('Content', cell,
+          'text'       => CONTENT_COL
+        )
+        cell.signal_connect(:edited, &method(:cell_edited))
+        append_column(column)
+      end
+
+      def unify_key(iter, key)
+        return unless iter.type == 'Key'
+        parent = iter.parent
+        if parent.any? { |c| c != iter and c.content == key }
+          old_key = key
+          i = 0
+          begin
+            key = sprintf("%s.%d", old_key, i += 1)
+          end while parent.any? { |c| c != iter and c.content == key }
+        end
+        iter.content = key
+      end
+
+      def cell_edited(cell, path, value)
+        iter = model.get_iter(path)
+        case iter.type
+        when 'Key'
+          unify_key(iter, value)
+          toplevel.display_status('Key has been changed.')
+        when 'FalseClass'
+          value.downcase!
+          if value == 'true'
+            iter.type, iter.content = 'TrueClass', 'true'
+          end
+        when 'TrueClass'
+          value.downcase!
+          if value == 'false'
+            iter.type, iter.content = 'FalseClass', 'false'
+          end
+        when 'Numeric'
+          iter.content = (Integer(value) rescue Float(value) rescue 0).to_s
+        when 'String'
+          iter.content = value
+        when 'Hash', 'Array'
+          return
+        else
+          fail "Unknown type found in model: #{iter.type}"
+        end
+        window.change
+      end
+
+      def configure_value(value, type)
+        value.editable = false
+        case type
+        when 'Array', 'Hash'
+          value.text = ''
+        when 'TrueClass'
+          value.text = 'true'
+        when 'FalseClass'
+          value.text = 'false'
+        when 'NilClass'
+          value.text = 'null'
+        when 'Numeric', 'String'
+          value.text ||= ''
+          value.editable = true
+        else
+          raise ArgumentError, "unknown type '#{type}' encountered"
+        end
+      end
+
+      def add_popup_menu
+        menu = PopUpMenu.new(self)
+        menu.create
+      end
+
+      public
+
+      # Create a _type_ node with content _content_, and add it to _parent_
+      # in the model. If _parent_ is nil, create a new model and put it into
+      # the editor treeview.
+      def create_node(parent, type, content)
+        iter = if parent
+          model.append(parent)
+        else
+          new_model = Editor.data2model(nil)
+          toplevel.view_new_model(new_model)
+          new_model.iter_first
+        end
+        iter.type, iter.content = type, content
+        expand_collapse(parent) if parent
+        iter
+      end
+
+      # Ask for a hash key, value pair to be added to the Hash node _parent_.
+      def ask_for_hash_pair(parent)
+        key_input = type_input = value_input = nil
+
+        dialog = Dialog.new("New (key, value) pair for Hash", nil, nil,
+          [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
+          [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
+        )
+        dialog.width_request = 640
+
+        hbox = HBox.new(false, 5)
+        hbox.pack_start(Label.new("Key:"), false)
+        hbox.pack_start(key_input = Entry.new)
+        key_input.text = @key || ''
+        dialog.vbox.pack_start(hbox, false)
+        key_input.signal_connect(:activate) do
+          if parent.any? { |c| c.content == key_input.text }
+            toplevel.display_status('Key already exists in Hash!')
+            key_input.text = ''
+          else
+            toplevel.display_status('Key has been changed.')
+          end
+        end
+
+        hbox = HBox.new(false, 5)
+        hbox.pack_start(Label.new("Type:"), false)
+        hbox.pack_start(type_input = ComboBox.new(true))
+        ALL_TYPES.each { |t| type_input.append_text(t) }
+        type_input.active = @type || 0
+        dialog.vbox.pack_start(hbox, false)
+
+        type_input.signal_connect(:changed) do
+          value_input.editable = false
+          case ALL_TYPES[type_input.active]
+          when 'Array', 'Hash'
+            value_input.text = ''
+          when 'TrueClass'
+            value_input.text = 'true'
+          when 'FalseClass'
+            value_input.text = 'false'
+          when 'NilClass'
+            value_input.text = 'null'
+          else
+            value_input.text = ''
+            value_input.editable = true
+          end
+        end
+
+        hbox = HBox.new(false, 5)
+        hbox.pack_start(Label.new("Value:"), false)
+        hbox.pack_start(value_input = Entry.new)
+        value_input.width_chars = 60
+        value_input.text = @value || ''
+        dialog.vbox.pack_start(hbox, false)
+
+        dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
+        dialog.show_all
+        self.focus = dialog
+        dialog.run do |response| 
+          if response == Dialog::RESPONSE_ACCEPT
+            @key = key_input.text
+            type = ALL_TYPES[@type = type_input.active]
+            content = value_input.text
+            return @key, type, content
+          end
+        end
+        return
+      ensure
+        dialog.destroy
+      end
+
+      # Ask for an element to be appended _parent_.
+      def ask_for_element(parent = nil, default_type = nil, value_text = @content)
+        type_input = value_input = nil
+
+        dialog = Dialog.new(
+          "New element into #{parent ? parent.type : 'root'}",
+          nil, nil,
+          [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
+          [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
+        )
+        hbox = HBox.new(false, 5)
+        hbox.pack_start(Label.new("Type:"), false)
+        hbox.pack_start(type_input = ComboBox.new(true))
+        default_active = 0
+        types = parent ? ALL_TYPES : CONTAINER_TYPES
+        types.each_with_index do |t, i|
+          type_input.append_text(t)
+          if t == default_type
+            default_active = i
+          end
+        end
+        type_input.active = default_active
+        dialog.vbox.pack_start(hbox, false)
+        type_input.signal_connect(:changed) do
+          configure_value(value_input, types[type_input.active])
+        end
+
+        hbox = HBox.new(false, 5)
+        hbox.pack_start(Label.new("Value:"), false)
+        hbox.pack_start(value_input = Entry.new)
+        value_input.width_chars = 60
+        value_input.text = value_text if value_text
+        configure_value(value_input, types[type_input.active])
+
+        dialog.vbox.pack_start(hbox, false)
+
+        dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
+        dialog.show_all
+        self.focus = dialog
+        dialog.run do |response| 
+          if response == Dialog::RESPONSE_ACCEPT
+            type = types[type_input.active]
+            @content = case type
+            when 'Numeric'
+              Integer(value_input.text) rescue Float(value_input.text) rescue 0
+            else
+              value_input.text
+            end.to_s
+            return type, @content
+          end
+        end
+        return
+      ensure
+        dialog.destroy if dialog
+      end
+
+      # Ask for an order criteria for sorting, using _x_ for the element in
+      # question. Returns the order criterium, and true/false for reverse
+      # sorting.
+      def ask_for_order
+        dialog = Dialog.new(
+          "Give an order criterium for 'x'.",
+          nil, nil,
+          [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
+          [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
+        )
+        hbox = HBox.new(false, 5)
+
+        hbox.pack_start(Label.new("Order:"), false)
+        hbox.pack_start(order_input = Entry.new)
+        order_input.text = @order || 'x'
+        order_input.width_chars = 60
+
+        hbox.pack_start(reverse_checkbox = CheckButton.new('Reverse'), false)
+
+        dialog.vbox.pack_start(hbox, false)
+
+        dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
+        dialog.show_all
+        self.focus = dialog
+        dialog.run do |response| 
+          if response == Dialog::RESPONSE_ACCEPT
+            return @order = order_input.text, reverse_checkbox.active?
+          end
+        end
+        return
+      ensure
+        dialog.destroy if dialog
+      end
+
+      # Ask for a find term to search for in the tree. Returns the term as a
+      # string.
+      def ask_for_find_term(search = nil)
+        dialog = Dialog.new(
+          "Find a node matching regex in tree.",
+          nil, nil,
+          [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
+          [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
+        )
+        hbox = HBox.new(false, 5)
+
+        hbox.pack_start(Label.new("Regex:"), false)
+        hbox.pack_start(regex_input = Entry.new)
+        hbox.pack_start(icase_checkbox = CheckButton.new('Icase'), false)
+        regex_input.width_chars = 60
+        if search
+          regex_input.text = search.source
+          icase_checkbox.active = search.casefold?
+        end
+
+        dialog.vbox.pack_start(hbox, false)
+
+        dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
+        dialog.show_all
+        self.focus = dialog
+        dialog.run do |response| 
+          if response == Dialog::RESPONSE_ACCEPT
+            begin
+              return Regexp.new(regex_input.text, icase_checkbox.active? ? Regexp::IGNORECASE : 0)
+            rescue => e
+              Editor.error_dialog(self, "Evaluation of regex /#{regex_input.text}/ failed: #{e}!")
+              return
+            end
+          end
+        end
+        return
+      ensure
+        dialog.destroy if dialog
+      end
+
+      # Expand or collapse row pointed to by _iter_ according
+      # to the #expanded attribute.
+      def expand_collapse(iter)
+        if expanded
+          expand_row(iter.path, true)
+        else
+          collapse_row(iter.path)
+        end
+      end
+    end
+
+    # The editor main window
+    class MainWindow < Gtk::Window
+      include Gtk
+
+      def initialize(encoding)
+        @changed  = false
+        @encoding = encoding
+        super(TOPLEVEL)
+        display_title
+        set_default_size(800, 600)
+        signal_connect(:delete_event) { quit }
+
+        vbox = VBox.new(false, 0)
+        add(vbox)
+        #vbox.border_width = 0
+
+        @treeview = JSONTreeView.new(self)
+        @treeview.signal_connect(:'cursor-changed') do
+          display_status('')
+        end
+
+        menu_bar = create_menu_bar
+        vbox.pack_start(menu_bar, false, false, 0)
+
+        sw = ScrolledWindow.new(nil, nil)
+        sw.shadow_type = SHADOW_ETCHED_IN
+        sw.set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC)
+        vbox.pack_start(sw, true, true, 0)
+        sw.add(@treeview)
+
+        @status_bar = Statusbar.new
+        vbox.pack_start(@status_bar, false, false, 0)
+
+        @filename ||= nil
+        if @filename
+          data = read_data(@filename)
+          view_new_model Editor.data2model(data)
+        end
+
+        signal_connect(:button_release_event) do |_,event|
+          if event.button == 2
+            c = Gtk::Clipboard.get(Gdk::Selection::PRIMARY)
+            if url = c.wait_for_text
+              location_open url
+            end
+            false
+          else
+            true
+          end
+        end
+      end
+
+      # Creates the menu bar with the pulldown menus and returns it.
+      def create_menu_bar
+        menu_bar = MenuBar.new
+        @file_menu = FileMenu.new(@treeview)
+        menu_bar.append @file_menu.create
+        @edit_menu = EditMenu.new(@treeview)
+        menu_bar.append @edit_menu.create
+        @options_menu = OptionsMenu.new(@treeview)
+        menu_bar.append @options_menu.create
+        menu_bar
+      end
+
+      # Sets editor status to changed, to indicate that the edited data
+      # containts unsaved changes.
+      def change
+        @changed = true
+        display_title
+      end
+
+      # Sets editor status to unchanged, to indicate that the edited data
+      # doesn't containt unsaved changes.
+      def unchange
+        @changed = false
+        display_title
+      end
+
+      # Puts a new model _model_ into the Gtk::TreeView to be edited.
+      def view_new_model(model)
+        @treeview.model     = model
+        @treeview.expanded  = true
+        @treeview.expand_all
+        unchange
+      end
+
+      # Displays _text_ in the status bar.
+      def display_status(text)
+        @cid ||= nil
+        @status_bar.pop(@cid) if @cid
+        @cid = @status_bar.get_context_id('dummy')
+        @status_bar.push(@cid, text)
+      end
+
+      # Opens a dialog, asking, if changes should be saved to a file.
+      def ask_save
+        if Editor.question_dialog(self,
+          "Unsaved changes to JSON model. Save?")
+          if @filename
+            file_save
+          else
+            file_save_as
+          end
+        end
+      end
+
+      # Quit this editor, that is, leave this editor's main loop.
+      def quit
+        ask_save if @changed
+        if Gtk.main_level > 0
+          destroy
+          Gtk.main_quit
+        end
+        nil
+      end
+
+      # Display the new title according to the editor's current state.
+      def display_title
+        title = TITLE.dup
+        title << ": #@filename" if @filename
+        title << " *" if @changed
+        self.title = title
+      end
+
+      # Clear the current model, after asking to save all unsaved changes.
+      def clear
+        ask_save if @changed
+        @filename = nil
+        self.view_new_model nil
+      end
+
+      def check_pretty_printed(json)
+        pretty = !!((nl_index = json.index("\n")) && nl_index != json.size - 1)
+        @options_menu.pretty_item.active = pretty
+      end
+      private :check_pretty_printed
+
+      # Open the data at the location _uri_, if given. Otherwise open a dialog
+      # to ask for the _uri_.
+      def location_open(uri = nil)
+        uri = ask_for_location unless uri
+        uri or return
+        ask_save if @changed
+        data = load_location(uri) or return
+        view_new_model Editor.data2model(data)
+      end
+
+      # Open the file _filename_ or call the #select_file method to ask for a
+      # filename.
+      def file_open(filename = nil)
+        filename = select_file('Open as a JSON file') unless filename
+        data = load_file(filename) or return
+        view_new_model Editor.data2model(data)
+      end
+
+      # Edit the string _json_ in the editor.
+      def edit(json)
+        if json.respond_to? :read
+          json = json.read
+        end
+        data = parse_json json
+        view_new_model Editor.data2model(data)
+      end
+
+      # Save the current file.
+      def file_save
+        if @filename
+          store_file(@filename)
+        else
+          file_save_as
+        end
+      end
+
+      # Save the current file as the filename 
+      def file_save_as
+        filename = select_file('Save as a JSON file')
+        store_file(filename)
+      end
+
+      # Store the current JSON document to _path_.
+      def store_file(path)
+        if path
+          data = Editor.model2data(@treeview.model.iter_first)
+          File.open(path + '.tmp', 'wb') do |output|
+            data or break
+            if @options_menu.pretty_item.active?
+              output.puts JSON.pretty_generate(data, :max_nesting => false)
+            else
+              output.write JSON.generate(data, :max_nesting => false)
+            end
+          end
+          File.rename path + '.tmp', path
+          @filename = path
+          toplevel.display_status("Saved data to '#@filename'.")
+          unchange
+        end
+      rescue SystemCallError => e
+        Editor.error_dialog(self, "Failed to store JSON file: #{e}!")
+      end
+  
+      # Load the file named _filename_ into the editor as a JSON document.
+      def load_file(filename)
+        if filename
+          if File.directory?(filename)
+            Editor.error_dialog(self, "Try to select a JSON file!")
+            nil
+          else
+            @filename = filename
+            if data = read_data(filename)
+              toplevel.display_status("Loaded data from '#@filename'.")
+            end
+            display_title
+            data
+          end
+        end
+      end
+
+      # Load the data at location _uri_ into the editor as a JSON document.
+      def load_location(uri)
+        data = read_data(uri) or return
+        @filename = nil
+        toplevel.display_status("Loaded data from '#{uri}'.")
+        display_title
+        data
+      end
+
+      def parse_json(json)
+        check_pretty_printed(json)
+        if @encoding && !/^utf8$/i.match(@encoding)
+          iconverter = Iconv.new('utf8', @encoding)
+          json = iconverter.iconv(json)
+        end
+        JSON::parse(json, :max_nesting => false, :create_additions => false)
+      end
+      private :parse_json
+
+      # Read a JSON document from the file named _filename_, parse it into a
+      # ruby data structure, and return the data.
+      def read_data(filename)
+        open(filename) do |f|
+          json = f.read
+          return parse_json(json)
+        end
+      rescue => e
+        Editor.error_dialog(self, "Failed to parse JSON file: #{e}!")
+        return
+      end
+
+      # Open a file selecton dialog, displaying _message_, and return the
+      # selected filename or nil, if no file was selected.
+      def select_file(message)
+        filename = nil
+        fs = FileSelection.new(message)
+        fs.set_modal(true)
+        @default_dir = File.join(Dir.pwd, '') unless @default_dir
+        fs.set_filename(@default_dir)
+        fs.set_transient_for(self)
+        fs.signal_connect(:destroy) { Gtk.main_quit }
+        fs.ok_button.signal_connect(:clicked) do
+          filename = fs.filename
+          @default_dir = File.join(File.dirname(filename), '')
+          fs.destroy
+          Gtk.main_quit
+        end
+        fs.cancel_button.signal_connect(:clicked) do
+          fs.destroy
+          Gtk.main_quit
+        end
+        fs.show_all
+        Gtk.main
+        filename
+      end
+
+      # Ask for location URI a to load data from. Returns the URI as a string.
+      def ask_for_location
+        dialog = Dialog.new(
+          "Load data from location...",
+          nil, nil,
+          [ Stock::OK, Dialog::RESPONSE_ACCEPT ],
+          [ Stock::CANCEL, Dialog::RESPONSE_REJECT ]
+        )
+        hbox = HBox.new(false, 5)
+
+        hbox.pack_start(Label.new("Location:"), false)
+        hbox.pack_start(location_input = Entry.new)
+        location_input.width_chars = 60
+        location_input.text = @location || ''
+
+        dialog.vbox.pack_start(hbox, false)
+
+        dialog.signal_connect(:'key-press-event', &DEFAULT_DIALOG_KEY_PRESS_HANDLER)
+        dialog.show_all
+        dialog.run do |response| 
+          if response == Dialog::RESPONSE_ACCEPT
+            return @location = location_input.text
+          end
+        end
+        return
+      ensure
+        dialog.destroy if dialog
+      end
+    end
+
+    class << self
+      # Starts a JSON Editor. If a block was given, it yields
+      # to the JSON::Editor::MainWindow instance.
+      def start(encoding = 'utf8') # :yield: window
+        Gtk.init
+        @window = Editor::MainWindow.new(encoding)
+        @window.icon_list = [ Editor.fetch_icon('json') ]
+        yield @window if block_given?
+        @window.show_all
+        Gtk.main
+      end
+
+      # Edit the string _json_ with encoding _encoding_ in the editor.
+      def edit(json, encoding = 'utf8')
+        start(encoding) do |window|
+          window.edit json
+        end
+      end
+
+      attr_reader :window
+    end
+  end
+end
+  # vim: set et sw=2 ts=2:

Property changes on: ext/json/lib/json/editor.rb
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/add/core.rb
===================================================================
--- ext/json/lib/json/add/core.rb	(revision 0)
+++ ext/json/lib/json/add/core.rb	(revision 14100)
@@ -0,0 +1,120 @@
+# This file contains implementations of ruby core's custom objects for
+# serialisation/deserialisation.
+
+unless Object.const_defined?(:JSON) and ::JSON.const_defined?(:JSON_LOADED) and
+  ::JSON::JSON_LOADED
+  require 'json'
+end
+require 'date'
+
+class Time
+  def self.json_create(object)
+    at(*object.values_at('s', 'u'))
+  end
+
+  def to_json(*args)
+    {
+      'json_class' => self.class.name.to_s,
+      's' => tv_sec,
+      'u' => tv_usec,
+    }.to_json(*args)
+  end
+end
+
+class Date
+  def self.json_create(object)
+    civil(*object.values_at('y', 'm', 'd', 'sg'))
+  end
+
+  def to_json(*args)
+    {
+      'json_class' => self.class.name.to_s,
+      'y' => year,
+      'm' => month,
+      'd' => day,
+      'sg' => @sg,
+    }.to_json(*args)
+  end
+end
+
+class DateTime
+  def self.json_create(object)
+    args = object.values_at('y', 'm', 'd', 'H', 'M', 'S')
+    of_a, of_b = object['of'].split('/')
+    args << Rational(of_a.to_i, of_b.to_i)
+    args << object['sg']
+    civil(*args)
+  end
+
+  def to_json(*args)
+    {
+      'json_class' => self.class.name.to_s,
+      'y' => year,
+      'm' => month,
+      'd' => day,
+      'H' => hour,
+      'M' => min,
+      'S' => sec,
+      'of' => offset.to_s,
+      'sg' => @sg,
+    }.to_json(*args)
+  end
+end
+
+class Range
+  def self.json_create(object)
+    new(*object['a'])
+  end
+
+  def to_json(*args)
+    {
+      'json_class'   => self.class.name.to_s,
+      'a'         => [ first, last, exclude_end? ]
+    }.to_json(*args)
+  end
+end
+
+class Struct
+  def self.json_create(object)
+    new(*object['v'])
+  end
+
+  def to_json(*args)
+    klass = self.class.name.to_s
+    klass.empty? and raise JSON::JSONError, "Only named structs are supported!"
+    {
+      'json_class' => klass,
+      'v'     => values,
+    }.to_json(*args)
+  end
+end
+
+class Exception
+  def self.json_create(object)
+    result = new(object['m'])
+    result.set_backtrace object['b']
+    result
+  end
+
+  def to_json(*args)
+    {
+      'json_class' => self.class.name.to_s,
+      'm'   => message,
+      'b' => backtrace,
+    }.to_json(*args)
+  end
+end
+
+class Regexp
+  def self.json_create(object)
+    new(object['s'], object['o'])
+  end
+
+  def to_json(*)
+    {
+      'json_class' => self.class.name.to_s,
+      'o' => options,
+      's' => source,
+    }.to_json
+  end
+end

Property changes on: ext/json/lib/json/add/core.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/add/rails.rb
===================================================================
--- ext/json/lib/json/add/rails.rb	(revision 0)
+++ ext/json/lib/json/add/rails.rb	(revision 14100)
@@ -0,0 +1,58 @@
+# This file contains implementations of rails custom objects for
+# serialisation/deserialisation.
+
+unless Object.const_defined?(:JSON) and ::JSON.const_defined?(:JSON_LOADED) and
+  ::JSON::JSON_LOADED
+  require 'json'
+end
+
+class Object
+  def self.json_create(object)
+    obj = new
+    for key, value in object
+      next if key == 'json_class'
+      instance_variable_set "@#{key}", value
+    end
+    obj
+  end
+
+  def to_json(*a)
+    result = {
+      'json_class' => self.class.name
+    }
+    instance_variables.inject(result) do |r, name|
+      r[name[1..-1]] = instance_variable_get name
+      r
+    end
+    result.to_json(*a)
+  end
+end
+
+class Symbol
+  def to_json(*a)
+    to_s.to_json(*a)
+  end
+end
+
+module Enumerable
+  def to_json(*a)
+    to_a.to_json(*a)
+  end
+end
+
+# class Regexp
+#   def to_json(*)
+#     inspect
+#   end
+# end
+#
+# The above rails definition has some problems:
+#
+# 1. { 'foo' => /bar/ }.to_json # => "{foo: /bar/}"
+#    This isn't valid JSON, because the regular expression syntax is not
+#    defined in RFC 4627. (And unquoted strings are disallowed there, too.)
+#    Though it is valid Javascript.
+#
+# 2. { 'foo' => /bar/mix }.to_json # => "{foo: /bar/mix}"
+#    This isn't even valid Javascript.
+

Property changes on: ext/json/lib/json/add/rails.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/common.rb
===================================================================
--- ext/json/lib/json/common.rb	(revision 0)
+++ ext/json/lib/json/common.rb	(revision 14100)
@@ -0,0 +1,354 @@
+require 'json/version'
+
+module JSON
+  class << self
+    # If _object_ is string like parse the string and return the parsed result
+    # as a Ruby data structure. Otherwise generate a JSON text from the Ruby
+    # data structure object and return it.
+    #
+    # The _opts_ argument is passed through to generate/parse respectively, see
+    # generate and parse for their documentation.
+    def [](object, opts = {})
+      if object.respond_to? :to_str
+        JSON.parse(object.to_str, opts => {})
+      else
+        JSON.generate(object, opts => {})
+      end
+    end
+
+    # Returns the JSON parser class, that is used by JSON. This might be either
+    # JSON::Ext::Parser or JSON::Pure::Parser.
+    attr_reader :parser
+
+    # Set the JSON parser class _parser_ to be used by JSON.
+    def parser=(parser) # :nodoc:
+      @parser = parser
+      remove_const :Parser if const_defined? :Parser
+      const_set :Parser, parser
+    end
+
+    # Return the constant located at _path_. The format of _path_ has to be
+    # either ::A::B::C or A::B::C. In any case A has to be located at the top
+    # level (absolute namespace path?). If there doesn't exist a constant at
+    # the given path, an ArgumentError is raised.
+    def deep_const_get(path) # :nodoc:
+      path = path.to_s
+      path.split(/::/).inject(Object) do |p, c|
+        case
+        when c.empty?             then p
+        when p.const_defined?(c)  then p.const_get(c)
+        else                      raise ArgumentError, "can't find const #{path}"
+        end
+      end
+    end
+
+    # Set the module _generator_ to be used by JSON.
+    def generator=(generator) # :nodoc:
+      @generator = generator
+      generator_methods = generator::GeneratorMethods
+      for const in generator_methods.constants
+        klass = deep_const_get(const)
+        modul = generator_methods.const_get(const)
+        klass.class_eval do
+          instance_methods(false).each do |m|
+            m.to_s == 'to_json' and remove_method m
+          end
+          include modul
+        end
+      end
+      self.state = generator::State
+      const_set :State, self.state
+    end
+
+    # Returns the JSON generator modul, that is used by JSON. This might be
+    # either JSON::Ext::Generator or JSON::Pure::Generator.
+    attr_reader :generator
+
+    # Returns the JSON generator state class, that is used by JSON. This might
+    # be either JSON::Ext::Generator::State or JSON::Pure::Generator::State.
+    attr_accessor :state
+
+    # This is create identifier, that is used to decide, if the _json_create_
+    # hook of a class should be called. It defaults to 'json_class'.
+    attr_accessor :create_id
+  end
+  self.create_id = 'json_class'
+
+  NaN           = (-1.0) ** 0.5
+
+  Infinity      = 1.0/0
+
+  MinusInfinity = -Infinity
+
+  # The base exception for JSON errors.
+  class JSONError < StandardError; end
+
+  # This exception is raised, if a parser error occurs.
+  class ParserError < JSONError; end
+
+  # This exception is raised, if the nesting of parsed datastructures is too
+  # deep.
+  class NestingError < ParserError; end
+
+  # This exception is raised, if a generator or unparser error occurs.
+  class GeneratorError < JSONError; end
+  # For backwards compatibility
+  UnparserError = GeneratorError
+
+  # If a circular data structure is encountered while unparsing
+  # this exception is raised.
+  class CircularDatastructure < GeneratorError; end
+
+  # This exception is raised, if the required unicode support is missing on the
+  # system. Usually this means, that the iconv library is not installed.
+  class MissingUnicodeSupport < JSONError; end
+
+  module_function
+
+  # Parse the JSON string _source_ into a Ruby data structure and return it.
+  #
+  # _opts_ can have the following
+  # keys:
+  # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+  #   structures. Disable depth checking with :max_nesting => false, it defaults
+  #   to 19.
+  # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
+  #   defiance of RFC 4627 to be parsed by the Parser. This option defaults
+  #   to false.
+  # * *create_additions*: If set to false, the Parser doesn't create
+  #   additions even if a matchin class and create_id was found. This option
+  #   defaults to true.
+  def parse(source, opts = {})
+    JSON.parser.new(source, opts).parse
+  end
+
+  # Parse the JSON string _source_ into a Ruby data structure and return it.
+  # The bang version of the parse method, defaults to the more dangerous values
+  # for the _opts_ hash, so be sure only to parse trusted _source_ strings.
+  #
+  # _opts_ can have the following keys:
+  # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+  #   structures. Enable depth checking with :max_nesting => anInteger. The parse!
+  #   methods defaults to not doing max depth checking: This can be dangerous,
+  #   if someone wants to fill up your stack.
+  # * *allow_nan*: If set to true, allow NaN, Infinity, and -Infinity in
+  #   defiance of RFC 4627 to be parsed by the Parser. This option defaults
+  #   to true.
+  # * *create_additions*: If set to false, the Parser doesn't create
+  #   additions even if a matchin class and create_id was found. This option
+  #   defaults to true.
+  def parse!(source, opts = {})
+    opts = {
+      :max_nesting => false,
+      :allow_nan => true
+    }.update(opts)
+    JSON.parser.new(source, opts).parse
+  end
+
+  # Unparse the Ruby data structure _obj_ into a single line JSON string and
+  # return it. _state_ is
+  # * a JSON::State object,
+  # * or a Hash like object (responding to to_hash),
+  # * an object convertible into a hash by a to_h method,
+  # that is used as or to configure a State object.
+  #
+  # It defaults to a state object, that creates the shortest possible JSON text
+  # in one line, checks for circular data structures and doesn't allow NaN,
+  # Infinity, and -Infinity.
+  #
+  # A _state_ hash can have the following keys:
+  # * *indent*: a string used to indent levels (default: ''),
+  # * *space*: a string that is put after, a : or , delimiter (default: ''),
+  # * *space_before*: a string that is put before a : pair delimiter (default: ''),
+  # * *object_nl*: a string that is put at the end of a JSON object (default: ''), 
+  # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
+  # * *check_circular*: true if checking for circular data structures
+  #   should be done (the default), false otherwise.
+  # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
+  #   generated, otherwise an exception is thrown, if these values are
+  #   encountered. This options defaults to false.
+  # * *max_nesting*: The maximum depth of nesting allowed in the data
+  #   structures from which JSON is to be generated. Disable depth checking
+  #   with :max_nesting => false, it defaults to 19.
+  #
+  # See also the fast_generate for the fastest creation method with the least
+  # amount of sanity checks, and the pretty_generate method for some
+  # defaults for a pretty output.
+  def generate(obj, state = nil)
+    if state
+      state = State.from_state(state)
+    else
+      state = State.new
+    end
+    obj.to_json(state)
+  end
+
+  # :stopdoc:
+  # I want to deprecate these later, so I'll first be silent about them, and later delete them.
+  alias unparse generate
+  module_function :unparse
+  # :startdoc:
+
+  # Unparse the Ruby data structure _obj_ into a single line JSON string and
+  # return it. This method disables the checks for circles in Ruby objects, and
+  # also generates NaN, Infinity, and, -Infinity float values.
+  #
+  # *WARNING*: Be careful not to pass any Ruby data structures with circles as
+  # _obj_ argument, because this will cause JSON to go into an infinite loop.
+  def fast_generate(obj)
+    obj.to_json(nil)
+  end
+
+  # :stopdoc:
+  # I want to deprecate these later, so I'll first be silent about them, and later delete them.
+  alias fast_unparse fast_generate
+  module_function :fast_unparse
+  # :startdoc:
+
+  # Unparse the Ruby data structure _obj_ into a JSON string and return it. The
+  # returned string is a prettier form of the string returned by #unparse.
+  #
+  # The _opts_ argument can be used to configure the generator, see the
+  # generate method for a more detailed explanation.
+  def pretty_generate(obj, opts = nil)
+    state = JSON.state.new(
+      :indent     => '  ',
+      :space      => ' ',
+      :object_nl  => "\n",
+      :array_nl   => "\n",
+      :check_circular => true
+    )
+    if opts
+      if opts.respond_to? :to_hash
+        opts = opts.to_hash
+      elsif opts.respond_to? :to_h
+        opts = opts.to_h
+      else
+        raise TypeError, "can't convert #{opts.class} into Hash"
+      end
+      state.configure(opts)
+    end
+    obj.to_json(state)
+  end
+
+  # :stopdoc:
+  # I want to deprecate these later, so I'll first be silent about them, and later delete them.
+  alias pretty_unparse pretty_generate
+  module_function :pretty_unparse
+  # :startdoc:
+
+  # Load a ruby data structure from a JSON _source_ and return it. A source can
+  # either be a string like object, an IO like object, or an object responding
+  # to the read method. If _proc_ was given, it will be called with any nested
+  # Ruby object as an argument recursively in depth first order.
+  #
+  # This method is part of the implementation of the load/dump interface of
+  # Marshal and YAML.
+  def load(source, proc = nil)
+    if source.respond_to? :to_str
+      source = source.to_str
+    elsif source.respond_to? :to_io
+      source = source.to_io.read
+    else
+      source = source.read
+    end
+    result = parse(source, :max_nesting => false, :allow_nan => true)
+    recurse_proc(result, &proc) if proc
+    result
+  end
+
+  def recurse_proc(result, &proc)
+    case result
+    when Array
+      result.each { |x| recurse_proc x, &proc }
+      proc.call result
+    when Hash
+      result.each { |x, y| recurse_proc x, &proc; recurse_proc y, &proc }
+      proc.call result
+    else
+      proc.call result
+    end
+  end
+  private :recurse_proc
+  module_function :recurse_proc
+
+  alias restore load
+  module_function :restore
+
+  # Dumps _obj_ as a JSON string, i.e. calls generate on the object and returns
+  # the result.
+  #
+  # If anIO (an IO like object or an object that responds to the write method)
+  # was given, the resulting JSON is written to it.
+  #
+  # If the number of nested arrays or objects exceeds _limit_ an ArgumentError
+  # exception is raised. This argument is similar (but not exactly the
+  # same!) to the _limit_ argument in Marshal.dump.
+  #
+  # This method is part of the implementation of the load/dump interface of
+  # Marshal and YAML.
+  def dump(obj, anIO = nil, limit = nil)
+    if anIO and limit.nil?
+      anIO = anIO.to_io if anIO.respond_to?(:to_io)
+      unless anIO.respond_to?(:write)
+        limit = anIO
+        anIO = nil
+      end
+    end
+    limit ||= 0
+    result = generate(obj, :allow_nan => true, :max_nesting => limit)
+    if anIO
+      anIO.write result
+      anIO
+    else
+      result
+    end
+  rescue JSON::NestingError
+    raise ArgumentError, "exceed depth limit"
+  end
+end
+
+module ::Kernel
+  # Outputs _objs_ to STDOUT as JSON strings in the shortest form, that is in
+  # one line.
+  def j(*objs)
+    objs.each do |obj|
+      puts JSON::generate(obj, :allow_nan => true, :max_nesting => false)
+    end
+    nil
+  end
+
+  # Ouputs _objs_ to STDOUT as JSON strings in a pretty format, with
+  # indentation and over many lines.
+  def jj(*objs)
+    objs.each do |obj|
+      puts JSON::pretty_generate(obj, :allow_nan => true, :max_nesting => false)
+    end
+    nil
+  end
+
+  # If _object_ is string like parse the string and return the parsed result as
+  # a Ruby data structure. Otherwise generate a JSON text from the Ruby data
+  # structure object and return it.
+  #
+  # The _opts_ argument is passed through to generate/parse respectively, see
+  # generate and parse for their documentation.
+  def JSON(object, opts = {})
+    if object.respond_to? :to_str
+      JSON.parse(object.to_str, opts)
+    else
+      JSON.generate(object, opts)
+    end
+  end
+end
+
+class ::Class
+  # Returns true, if this class can be used to create an instance
+  # from a serialised JSON string. The class has to implement a class
+  # method _json_create_ that expects a hash as first parameter, which includes
+  # the required data.
+  def json_creatable?
+    respond_to?(:json_create)
+  end
+end
+  # vim: set et sw=2 ts=2:

Property changes on: ext/json/lib/json/common.rb
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/Key.xpm
===================================================================
--- ext/json/lib/json/Key.xpm	(revision 0)
+++ ext/json/lib/json/Key.xpm	(revision 14100)
@@ -0,0 +1,73 @@
+/* XPM */
+static char * Key_xpm[] = {
+"16 16 54 1",
+" 	c None",
+".	c #110007",
+"+	c #0E0900",
+"@	c #000013",
+"#	c #070600",
+"$	c #F6F006",
+"%	c #ECE711",
+"&	c #E5EE00",
+"*	c #16021E",
+"=	c #120900",
+"-	c #EDF12B",
+";	c #000033",
+">	c #0F0000",
+",	c #FFFE03",
+"'	c #E6E500",
+")	c #16021B",
+"!	c #F7F502",
+"~	c #000E00",
+"{	c #130000",
+"]	c #FFF000",
+"^	c #FFE711",
+"/	c #140005",
+"(	c #190025",
+"_	c #E9DD27",
+":	c #E7DC04",
+"<	c #FFEC09",
+"[	c #FFE707",
+"}	c #FFDE10",
+"|	c #150021",
+"1	c #160700",
+"2	c #FAF60E",
+"3	c #EFE301",
+"4	c #FEF300",
+"5	c #E7E000",
+"6	c #FFFF08",
+"7	c #0E0206",
+"8	c #040000",
+"9	c #03052E",
+"0	c #041212",
+"a	c #070300",
+"b	c #F2E713",
+"c	c #F9DE13",
+"d	c #36091E",
+"e	c #00001C",
+"f	c #1F0010",
+"g	c #FFF500",
+"h	c #DEDE00",
+"i	c #050A00",
+"j	c #FAF14A",
+"k	c #F5F200",
+"l	c #040404",
+"m	c #1A0D00",
+"n	c #EDE43D",
+"o	c #ECE007",
+"                ",
+"                ",
+"    .+@         ",
+"   #$%&*        ",
+"  =-;>,')       ",
+"  >!~{]^/       ",
+"  (_:<[}|       ",
+"   1234567      ",
+"    890abcd     ",
+"       efghi    ",
+"         >jkl   ",
+"          mnol  ",
+"           >kl  ",
+"            ll  ",
+"                ",
+"                "};

Property changes on: ext/json/lib/json/Key.xpm
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/ext.rb
===================================================================
--- ext/json/lib/json/ext.rb	(revision 0)
+++ ext/json/lib/json/ext.rb	(revision 14100)
@@ -0,0 +1,13 @@
+require 'json/common'
+
+module JSON
+  # This module holds all the modules/classes that implement JSON's
+  # functionality as C extensions.
+  module Ext
+    require 'json/ext/parser'
+    require 'json/ext/generator'
+    $DEBUG and warn "Using c extension for JSON."
+    JSON.parser = Parser
+    JSON.generator = Generator
+  end
+end

Property changes on: ext/json/lib/json/ext.rb
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/Numeric.xpm
===================================================================
--- ext/json/lib/json/Numeric.xpm	(revision 0)
+++ ext/json/lib/json/Numeric.xpm	(revision 14100)
@@ -0,0 +1,28 @@
+/* XPM */
+static char * Numeric_xpm[] = {
+"16 16 9 1",
+" 	c None",
+".	c #FF0000",
+"+	c #0000FF",
+"@	c #0023DB",
+"#	c #00EA14",
+"$	c #00FF00",
+"%	c #004FAF",
+"&	c #0028D6",
+"*	c #00F20C",
+"                ",
+"                ",
+"                ",
+" ... +++@#$$$$  ",
+"   .+   %&   $$ ",
+"   .     +    $ ",
+"   .     +   $$ ",
+"   .    ++$$$$  ",
+"   .    +    $$ ",
+"   .   +      $ ",
+"   .  +       $ ",
+"   . +  $    $$ ",
+" .....++++*$$   ",
+"                ",
+"                ",
+"                "};

Property changes on: ext/json/lib/json/Numeric.xpm
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/TrueClass.xpm
===================================================================
--- ext/json/lib/json/TrueClass.xpm	(revision 0)
+++ ext/json/lib/json/TrueClass.xpm	(revision 14100)
@@ -0,0 +1,21 @@
+/* XPM */
+static char * TrueClass_xpm[] = {
+"16 16 2 1",
+" 	c None",
+".	c #0BF311",
+"                ",
+"                ",
+"                ",
+"   .........    ",
+"       .        ",
+"       .        ",
+"       .        ",
+"       .        ",
+"       .        ",
+"       .        ",
+"       .        ",
+"       .        ",
+"       .        ",
+"                ",
+"                ",
+"                "};

Property changes on: ext/json/lib/json/TrueClass.xpm
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/String.xpm
===================================================================
--- ext/json/lib/json/String.xpm	(revision 0)
+++ ext/json/lib/json/String.xpm	(revision 14100)
@@ -0,0 +1,96 @@
+/* XPM */
+static char * String_xpm[] = {
+"16 16 77 1",
+" 	c None",
+".	c #000000",
+"+	c #040404",
+"@	c #080806",
+"#	c #090606",
+"$	c #EEEAE1",
+"%	c #E7E3DA",
+"&	c #E0DBD1",
+"*	c #D4B46F",
+"=	c #0C0906",
+"-	c #E3C072",
+";	c #E4C072",
+">	c #060505",
+",	c #0B0A08",
+"'	c #D5B264",
+")	c #D3AF5A",
+"!	c #080602",
+"~	c #E1B863",
+"{	c #DDB151",
+"]	c #DBAE4A",
+"^	c #DDB152",
+"/	c #DDB252",
+"(	c #070705",
+"_	c #0C0A07",
+":	c #D3A33B",
+"<	c #020201",
+"[	c #DAAA41",
+"}	c #040302",
+"|	c #E4D9BF",
+"1	c #0B0907",
+"2	c #030201",
+"3	c #020200",
+"4	c #C99115",
+"5	c #080704",
+"6	c #DBC8A2",
+"7	c #E7D7B4",
+"8	c #E0CD9E",
+"9	c #080601",
+"0	c #040400",
+"a	c #010100",
+"b	c #0B0B08",
+"c	c #DCBF83",
+"d	c #DCBC75",
+"e	c #DEB559",
+"f	c #040301",
+"g	c #BC8815",
+"h	c #120E07",
+"i	c #060402",
+"j	c #0A0804",
+"k	c #D4A747",
+"l	c #D6A12F",
+"m	c #0E0C05",
+"n	c #C8C1B0",
+"o	c #1D1B15",
+"p	c #D7AD51",
+"q	c #070502",
+"r	c #080804",
+"s	c #BC953B",
+"t	c #C4BDAD",
+"u	c #0B0807",
+"v	c #DBAC47",
+"w	c #1B150A",
+"x	c #B78A2C",
+"y	c #D8A83C",
+"z	c #D4A338",
+"A	c #0F0B03",
+"B	c #181105",
+"C	c #C59325",
+"D	c #C18E1F",
+"E	c #060600",
+"F	c #CC992D",
+"G	c #B98B25",
+"H	c #B3831F",
+"I	c #C08C1C",
+"J	c #060500",
+"K	c #0E0C03",
+"L	c #0D0A00",
+"                ",
+"   .+@#         ",
+"  .$%&*=        ",
+" .-;>,')!       ",
+" .~.  .{].      ",
+" .^/. (_:<      ",
+"  .[.}|$12      ",
+"   345678}90    ",
+"    a2bcdefgh   ",
+"      ijkl.mno  ",
+"      <pq. rstu ",
+"      .]v.  wx= ",
+"       .yzABCDE ",
+"        .FGHIJ  ",
+"         0KL0   ",
+"                "};

Property changes on: ext/json/lib/json/String.xpm
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/pure/generator.rb
===================================================================
--- ext/json/lib/json/pure/generator.rb	(revision 0)
+++ ext/json/lib/json/pure/generator.rb	(revision 14100)
@@ -0,0 +1,394 @@
+module JSON
+  MAP = {
+    "\x0" => '\u0000',
+    "\x1" => '\u0001',
+    "\x2" => '\u0002',
+    "\x3" => '\u0003',
+    "\x4" => '\u0004',
+    "\x5" => '\u0005',
+    "\x6" => '\u0006',
+    "\x7" => '\u0007',
+    "\b"  =>  '\b',
+    "\t"  =>  '\t',
+    "\n"  =>  '\n',
+    "\xb" => '\u000b',
+    "\f"  =>  '\f',
+    "\r"  =>  '\r',
+    "\xe" => '\u000e',
+    "\xf" => '\u000f',
+    "\x10" => '\u0010',
+    "\x11" => '\u0011',
+    "\x12" => '\u0012',
+    "\x13" => '\u0013',
+    "\x14" => '\u0014',
+    "\x15" => '\u0015',
+    "\x16" => '\u0016',
+    "\x17" => '\u0017',
+    "\x18" => '\u0018',
+    "\x19" => '\u0019',
+    "\x1a" => '\u001a',
+    "\x1b" => '\u001b',
+    "\x1c" => '\u001c',
+    "\x1d" => '\u001d',
+    "\x1e" => '\u001e',
+    "\x1f" => '\u001f',
+    '"'   =>  '\"',
+    '\\'  =>  '\\\\',
+    '/'   =>  '\/',
+  } # :nodoc:
+
+  # Convert a UTF8 encoded Ruby string _string_ to a JSON string, encoded with
+  # UTF16 big endian characters as \u????, and return it.
+  def utf8_to_json(string) # :nodoc:
+    string = string.gsub(/["\\\/\x0-\x1f]/) { |c| MAP[c] }
+    string.gsub!(/(
+                    (?:
+                      [\xc2-\xdf][\x80-\xbf]    |
+                      [\xe0-\xef][\x80-\xbf]{2} |
+                      [\xf0-\xf4][\x80-\xbf]{3}
+                    )+ |
+                    [\x80-\xc1\xf5-\xff]       # invalid
+                  )/nx) { |c|
+      c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
+      s = JSON::UTF8toUTF16.iconv(c).unpack('H*')[0]
+      s.gsub!(/.{4}/n, '\\\\u\&')
+    }
+    string
+  rescue Iconv::Failure => e
+    raise GeneratorError, "Caught #{e.class}: #{e}"
+  end
+  module_function :utf8_to_json
+
+  module Pure
+    module Generator
+      # This class is used to create State instances, that are use to hold data
+      # while generating a JSON text from a a Ruby data structure.
+      class State
+        # Creates a State object from _opts_, which ought to be Hash to create
+        # a new State instance configured by _opts_, something else to create
+        # an unconfigured instance. If _opts_ is a State object, it is just
+        # returned.
+        def self.from_state(opts)
+          case opts
+          when self
+            opts
+          when Hash
+            new(opts)
+          else
+            new
+          end
+        end
+
+        # Instantiates a new State object, configured by _opts_.
+        #
+        # _opts_ can have the following keys:
+        #
+        # * *indent*: a string used to indent levels (default: ''),
+        # * *space*: a string that is put after, a : or , delimiter (default: ''),
+        # * *space_before*: a string that is put before a : pair delimiter (default: ''),
+        # * *object_nl*: a string that is put at the end of a JSON object (default: ''), 
+        # * *array_nl*: a string that is put at the end of a JSON array (default: ''),
+        # * *check_circular*: true if checking for circular data structures
+        #   should be done (the default), false otherwise.
+        # * *check_circular*: true if checking for circular data structures
+        #   should be done, false (the default) otherwise.
+        # * *allow_nan*: true if NaN, Infinity, and -Infinity should be
+        #   generated, otherwise an exception is thrown, if these values are
+        #   encountered. This options defaults to false.
+        def initialize(opts = {})
+          @seen = {}
+          @indent         = ''
+          @space          = ''
+          @space_before   = ''
+          @object_nl      = ''
+          @array_nl       = ''
+          @check_circular = true
+          @allow_nan      = false
+          configure opts
+        end
+
+        # This string is used to indent levels in the JSON text.
+        attr_accessor :indent
+
+        # This string is used to insert a space between the tokens in a JSON
+        # string.
+        attr_accessor :space
+
+        # This string is used to insert a space before the ':' in JSON objects.
+        attr_accessor :space_before
+
+        # This string is put at the end of a line that holds a JSON object (or
+        # Hash).
+        attr_accessor :object_nl
+
+        # This string is put at the end of a line that holds a JSON array.
+        attr_accessor :array_nl
+
+        # This integer returns the maximum level of data structure nesting in
+        # the generated JSON, max_nesting = 0 if no maximum is checked.
+        attr_accessor :max_nesting
+
+        def check_max_nesting(depth) # :nodoc:
+          return if @max_nesting.zero?
+          current_nesting = depth + 1
+          current_nesting > @max_nesting and
+            raise NestingError, "nesting of #{current_nesting} is too deep"
+        end
+
+        # Returns true, if circular data structures should be checked,
+        # otherwise returns false.
+        def check_circular?
+          @check_circular
+        end
+
+        # Returns true if NaN, Infinity, and -Infinity should be considered as
+        # valid JSON and output.
+        def allow_nan?
+          @allow_nan
+        end
+
+        # Returns _true_, if _object_ was already seen during this generating
+        # run. 
+        def seen?(object)
+          @seen.key?(object.__id__)
+        end
+
+        # Remember _object_, to find out if it was already encountered (if a
+        # cyclic data structure is if a cyclic data structure is rendered). 
+        def remember(object)
+          @seen[object.__id__] = true
+        end
+
+        # Forget _object_ for this generating run.
+        def forget(object)
+          @seen.delete object.__id__
+        end
+
+        # Configure this State instance with the Hash _opts_, and return
+        # itself.
+        def configure(opts)
+          @indent         = opts[:indent] if opts.key?(:indent)
+          @space          = opts[:space] if opts.key?(:space)
+          @space_before   = opts[:space_before] if opts.key?(:space_before)
+          @object_nl      = opts[:object_nl] if opts.key?(:object_nl)
+          @array_nl       = opts[:array_nl] if opts.key?(:array_nl)
+          @check_circular = !!opts[:check_circular] if opts.key?(:check_circular)
+          @allow_nan      = !!opts[:allow_nan] if opts.key?(:allow_nan)
+          if !opts.key?(:max_nesting) # defaults to 19
+            @max_nesting = 19
+          elsif opts[:max_nesting]
+            @max_nesting = opts[:max_nesting]
+          else
+            @max_nesting = 0
+          end
+          self
+        end
+
+        # Returns the configuration instance variables as a hash, that can be
+        # passed to the configure method.
+        def to_h
+          result = {}
+          for iv in %w[indent space space_before object_nl array_nl check_circular allow_nan max_nesting]
+            result[iv.intern] = instance_variable_get("@#{iv}")
+          end
+          result
+        end
+      end
+
+      module GeneratorMethods
+        module Object
+          # Converts this object to a string (calling #to_s), converts
+          # it to a JSON string, and returns the result. This is a fallback, if no
+          # special method #to_json was defined for some object.
+          def to_json(*) to_s.to_json end
+        end
+
+        module Hash
+          # Returns a JSON string containing a JSON object, that is unparsed from
+          # this Hash instance.
+          # _state_ is a JSON::State object, that can also be used to configure the
+          # produced JSON string output further.
+          # _depth_ is used to find out nesting depth, to indent accordingly.
+          def to_json(state = nil, depth = 0, *)
+            if state
+              state = JSON.state.from_state(state)
+              state.check_max_nesting(depth)
+              json_check_circular(state) { json_transform(state, depth) }
+            else
+              json_transform(state, depth)
+            end
+          end
+
+          private
+
+          def json_check_circular(state)
+            if state and state.check_circular?
+              state.seen?(self) and raise JSON::CircularDatastructure,
+                  "circular data structures not supported!"
+              state.remember self
+            end
+            yield
+          ensure
+            state and state.forget self
+          end
+
+          def json_shift(state, depth)
+            state and not state.object_nl.empty? or return ''
+            state.indent * depth
+          end
+
+          def json_transform(state, depth)
+            delim = ','
+            delim << state.object_nl if state
+            result = '{'
+            result << state.object_nl if state
+            result << map { |key,value|
+              s = json_shift(state, depth + 1)
+              s << key.to_s.to_json(state, depth + 1)
+              s << state.space_before if state
+              s << ':'
+              s << state.space if state
+              s << value.to_json(state, depth + 1)
+            }.join(delim)
+            result << state.object_nl if state
+            result << json_shift(state, depth)
+            result << '}'
+            result
+          end
+        end
+
+        module Array
+          # Returns a JSON string containing a JSON array, that is unparsed from
+          # this Array instance.
+          # _state_ is a JSON::State object, that can also be used to configure the
+          # produced JSON string output further.
+          # _depth_ is used to find out nesting depth, to indent accordingly.
+          def to_json(state = nil, depth = 0, *)
+            if state
+              state = JSON.state.from_state(state)
+              state.check_max_nesting(depth)
+              json_check_circular(state) { json_transform(state, depth) }
+            else
+              json_transform(state, depth)
+            end
+          end
+
+          private
+
+          def json_check_circular(state)
+            if state and state.check_circular?
+              state.seen?(self) and raise JSON::CircularDatastructure,
+                "circular data structures not supported!"
+              state.remember self
+            end
+            yield
+          ensure
+            state and state.forget self
+          end
+
+          def json_shift(state, depth)
+            state and not state.array_nl.empty? or return ''
+            state.indent * depth
+          end
+
+          def json_transform(state, depth)
+            delim = ','
+            delim << state.array_nl if state
+            result = '['
+            result << state.array_nl if state
+            result << map { |value|
+              json_shift(state, depth + 1) << value.to_json(state, depth + 1)
+            }.join(delim)
+            result << state.array_nl if state
+            result << json_shift(state, depth) 
+            result << ']'
+            result
+          end
+        end
+
+        module Integer
+          # Returns a JSON string representation for this Integer number.
+          def to_json(*) to_s end
+        end
+
+        module Float
+          # Returns a JSON string representation for this Float number.
+          def to_json(state = nil, *)
+            case
+            when infinite?
+              if !state || state.allow_nan?
+                to_s
+              else
+                raise GeneratorError, "#{self} not allowed in JSON"
+              end
+            when nan?
+              if !state || state.allow_nan?
+                to_s
+              else
+                raise GeneratorError, "#{self} not allowed in JSON"
+              end
+            else
+              to_s
+            end
+          end
+        end
+
+        module String
+          # This string should be encoded with UTF-8 A call to this method
+          # returns a JSON string encoded with UTF16 big endian characters as
+          # \u????.
+          def to_json(*)
+            '"' << JSON.utf8_to_json(self) << '"'
+          end
+
+          # Module that holds the extinding methods if, the String module is
+          # included.
+          module Extend
+            # Raw Strings are JSON Objects (the raw bytes are stored in an array for the
+            # key "raw"). The Ruby String can be created by this module method.
+            def json_create(o)
+              o['raw'].pack('C*')
+            end
+          end
+
+          # Extends _modul_ with the String::Extend module.
+          def self.included(modul)
+            modul.extend Extend
+          end
+
+          # This method creates a raw object hash, that can be nested into
+          # other data structures and will be unparsed as a raw string. This
+          # method should be used, if you want to convert raw strings to JSON
+          # instead of UTF-8 strings, e. g. binary data.
+          def to_json_raw_object
+            {
+              JSON.create_id  => self.class.name,
+              'raw'           => self.unpack('C*'),
+            }
+          end
+
+          # This method creates a JSON text from the result of
+          # a call to to_json_raw_object of this String.
+          def to_json_raw(*args)
+            to_json_raw_object.to_json(*args)
+          end
+        end
+
+        module TrueClass
+          # Returns a JSON string for true: 'true'.
+          def to_json(*) 'true' end
+        end
+
+        module FalseClass
+          # Returns a JSON string for false: 'false'.
+          def to_json(*) 'false' end
+        end
+
+        module NilClass
+          # Returns a JSON string for nil: 'null'.
+          def to_json(*) 'null' end
+        end
+      end
+    end
+  end
+end

Property changes on: ext/json/lib/json/pure/generator.rb
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/pure/parser.rb
===================================================================
--- ext/json/lib/json/pure/parser.rb	(revision 0)
+++ ext/json/lib/json/pure/parser.rb	(revision 14100)
@@ -0,0 +1,259 @@
+require 'strscan'
+
+module JSON
+  module Pure
+    # This class implements the JSON parser that is used to parse a JSON string
+    # into a Ruby data structure.
+    class Parser < StringScanner
+      STRING                = /" ((?:[^\x0-\x1f"\\] |
+                                  \\["\\\/bfnrt] |
+                                  \\u[0-9a-fA-F]{4} |
+                                  \\[\x20-\xff])*)
+                              "/nx
+      INTEGER               = /(-?0|-?[1-9]\d*)/
+      FLOAT                 = /(-?
+                                (?:0|[1-9]\d*)
+                                (?:
+                                  \.\d+(?i:e[+-]?\d+) |
+                                  \.\d+ |
+                                  (?i:e[+-]?\d+)
+                                )
+                                )/x
+      NAN                   = /NaN/
+      INFINITY              = /Infinity/
+      MINUS_INFINITY        = /-Infinity/
+      OBJECT_OPEN           = /\{/
+      OBJECT_CLOSE          = /\}/
+      ARRAY_OPEN            = /\[/
+      ARRAY_CLOSE           = /\]/
+      PAIR_DELIMITER        = /:/
+      COLLECTION_DELIMITER  = /,/
+      TRUE                  = /true/
+      FALSE                 = /false/
+      NULL                  = /null/
+      IGNORE                = %r(
+        (?:
+         //[^\n\r]*[\n\r]| # line comments
+         /\*               # c-style comments
+         (?:
+          [^*/]|        # normal chars
+          /[^*]|        # slashes that do not start a nested comment
+          \*[^/]|       # asterisks that do not end this comment
+          /(?=\*/)      # single slash before this comment's end 
+         )*
+           \*/               # the End of this comment
+           |[ \t\r\n]+       # whitespaces: space, horicontal tab, lf, cr
+        )+
+      )mx
+
+      UNPARSED = Object.new
+
+      # Creates a new JSON::Pure::Parser instance for the string _source_.
+      #
+      # It will be configured by the _opts_ hash. _opts_ can have the following
+      # keys:
+      # * *max_nesting*: The maximum depth of nesting allowed in the parsed data
+      #   structures. Disable depth checking with :max_nesting => false|nil|0,
+      #   it defaults to 19.
+      # * *allow_nan*: If set to true, allow NaN, Infinity and -Infinity in
+      #   defiance of RFC 4627 to be parsed by the Parser. This option defaults
+      #   to false.
+      # * *create_additions*: If set to false, the Parser doesn't create
+      #   additions even if a matchin class and create_id was found. This option
+      #   defaults to true.
+      def initialize(source, opts = {})
+        super
+        if !opts.key?(:max_nesting) # defaults to 19
+          @max_nesting = 19
+        elsif opts[:max_nesting]
+          @max_nesting = opts[:max_nesting]
+        else
+          @max_nesting = 0
+        end
+        @allow_nan = !!opts[:allow_nan]
+        ca = true
+        ca = opts[:create_additions] if opts.key?(:create_additions)
+        @create_id = ca ? JSON.create_id : nil
+      end
+
+      alias source string
+
+      # Parses the current JSON string _source_ and returns the complete data
+      # structure as a result.
+      def parse
+        reset
+        obj = nil
+        until eos?
+          case
+          when scan(OBJECT_OPEN)
+            obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
+            @current_nesting = 1
+            obj = parse_object
+          when scan(ARRAY_OPEN)
+            obj and raise ParserError, "source '#{peek(20)}' not in JSON!"
+            @current_nesting = 1
+            obj = parse_array
+          when skip(IGNORE)
+            ;
+          else
+            raise ParserError, "source '#{peek(20)}' not in JSON!"
+          end
+        end
+        obj or raise ParserError, "source did not contain any JSON!"
+        obj
+      end
+
+      private
+
+      # Unescape characters in strings.
+      UNESCAPE_MAP = Hash.new { |h, k| h[k] = k.chr }
+      UNESCAPE_MAP.update({
+        ?"  => '"',
+        ?\\ => '\\',
+        ?/  => '/',
+        ?b  => "\b",
+        ?f  => "\f",
+        ?n  => "\n",
+        ?r  => "\r",
+        ?t  => "\t",
+        ?u  => nil, 
+      })
+
+      def parse_string
+        if scan(STRING)
+          return '' if self[1].empty?
+          self[1].gsub(%r((?:\\[\\bfnrt"/]|(?:\\u(?:[A-Fa-f\d]{4}))+|\\[\x20-\xff]))n) do |c|
+            if u = UNESCAPE_MAP[c[1]]
+              u
+            else # \uXXXX
+              bytes = ''
+              i = 0
+              while c[6 * i] == ?\\ && c[6 * i + 1] == ?u 
+                bytes << c[6 * i + 2, 2].to_i(16) << c[6 * i + 4, 2].to_i(16)
+                i += 1
+              end
+              JSON::UTF16toUTF8.iconv(bytes)
+            end
+          end
+        else
+          UNPARSED
+        end
+      rescue Iconv::Failure => e
+        raise GeneratorError, "Caught #{e.class}: #{e}"
+      end
+
+      def parse_value
+        case
+        when scan(FLOAT)
+          Float(self[1])
+        when scan(INTEGER)
+          Integer(self[1])
+        when scan(TRUE)
+          true
+        when scan(FALSE)
+          false
+        when scan(NULL)
+          nil
+        when (string = parse_string) != UNPARSED
+          string
+        when scan(ARRAY_OPEN)
+          @current_nesting += 1
+          ary = parse_array
+          @current_nesting -= 1
+          ary
+        when scan(OBJECT_OPEN)
+          @current_nesting += 1
+          obj = parse_object
+          @current_nesting -= 1
+          obj
+        when @allow_nan && scan(NAN)
+          NaN
+        when @allow_nan && scan(INFINITY)
+          Infinity
+        when @allow_nan && scan(MINUS_INFINITY)
+          MinusInfinity
+        else
+          UNPARSED
+        end
+      end
+
+      def parse_array
+        raise NestingError, "nesting of #@current_nesting is to deep" if
+          @max_nesting.nonzero? && @current_nesting > @max_nesting
+        result = []
+        delim = false
+        until eos?
+          case
+          when (value = parse_value) != UNPARSED
+            delim = false
+            result << value
+            skip(IGNORE)
+            if scan(COLLECTION_DELIMITER)
+              delim = true
+            elsif match?(ARRAY_CLOSE)
+              ;
+            else
+              raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
+            end
+          when scan(ARRAY_CLOSE)
+            if delim
+              raise ParserError, "expected next element in array at '#{peek(20)}'!"
+            end
+            break
+          when skip(IGNORE)
+            ;
+          else
+            raise ParserError, "unexpected token in array at '#{peek(20)}'!"
+          end
+        end
+        result
+      end
+
+      def parse_object
+        raise NestingError, "nesting of #@current_nesting is to deep" if
+          @max_nesting.nonzero? && @current_nesting > @max_nesting
+        result = {}
+        delim = false
+        until eos?
+          case
+          when (string = parse_string) != UNPARSED
+            skip(IGNORE)
+            unless scan(PAIR_DELIMITER)
+              raise ParserError, "expected ':' in object at '#{peek(20)}'!"
+            end
+            skip(IGNORE)
+            unless (value = parse_value).equal? UNPARSED
+              result[string] = value
+              delim = false
+              skip(IGNORE)
+              if scan(COLLECTION_DELIMITER)
+                delim = true
+              elsif match?(OBJECT_CLOSE)
+                ;
+              else
+                raise ParserError, "expected ',' or '}' in object at '#{peek(20)}'!"
+              end
+            else
+              raise ParserError, "expected value in object at '#{peek(20)}'!"
+            end
+          when scan(OBJECT_CLOSE)
+            if delim
+              raise ParserError, "expected next name, value pair in object at '#{peek(20)}'!"
+            end
+            if @create_id and klassname = result[@create_id]
+              klass = JSON.deep_const_get klassname
+              break unless klass and klass.json_creatable?
+              result = klass.json_create(result)
+            end
+            break
+          when skip(IGNORE)
+            ;
+          else
+            raise ParserError, "unexpected token in object at '#{peek(20)}'!"
+          end
+        end
+        result
+      end
+    end
+  end
+end

Property changes on: ext/json/lib/json/pure/parser.rb
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/NilClass.xpm
===================================================================
--- ext/json/lib/json/NilClass.xpm	(revision 0)
+++ ext/json/lib/json/NilClass.xpm	(revision 14100)
@@ -0,0 +1,21 @@
+/* XPM */
+static char * False_xpm[] = {
+"16 16 2 1",
+" 	c None",
+".	c #000000",
+"                ",
+"                ",
+"                ",
+"       ...      ",
+"      .   .     ",
+"     .     .    ",
+"     .     .    ",
+"     .     .    ",
+"     .     .    ",
+"     .     .    ",
+"     .     .    ",
+"      .   .     ",
+"       ...      ",
+"                ",
+"                ",
+"                "};

Property changes on: ext/json/lib/json/NilClass.xpm
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/json.xpm
===================================================================
--- ext/json/lib/json/json.xpm	(revision 0)
+++ ext/json/lib/json/json.xpm	(revision 14100)
@@ -0,0 +1,1499 @@
+/* XPM */
+static char * json_xpm[] = {
+"64 64 1432 2",
+"  	c None",
+". 	c #641839",
+"+ 	c #CF163C",
+"@ 	c #D31C3B",
+"# 	c #E11A38",
+"$ 	c #5F242D",
+"% 	c #320C22",
+"& 	c #9B532D",
+"* 	c #F32E34",
+"= 	c #820F33",
+"- 	c #4B0F34",
+"; 	c #8E1237",
+"> 	c #944029",
+", 	c #961325",
+"' 	c #A00C24",
+") 	c #872C23",
+"! 	c #694021",
+"~ 	c #590D1F",
+"{ 	c #420528",
+"] 	c #D85A2D",
+"^ 	c #7E092B",
+"/ 	c #0E0925",
+"( 	c #0D081F",
+"_ 	c #0F081E",
+": 	c #12071F",
+"< 	c #360620",
+"[ 	c #682A21",
+"} 	c #673F21",
+"| 	c #780E21",
+"1 	c #A82320",
+"2 	c #8D1D1F",
+"3 	c #970127",
+"4 	c #0D0123",
+"5 	c #0D0324",
+"6 	c #3B1E28",
+"7 	c #C28429",
+"8 	c #0C0523",
+"9 	c #0C041E",
+"0 	c #0E031A",
+"a 	c #11031A",
+"b 	c #13031B",
+"c 	c #13031C",
+"d 	c #11031D",
+"e 	c #19051E",
+"f 	c #390E20",
+"g 	c #9C0C20",
+"h 	c #C00721",
+"i 	c #980320",
+"j 	c #14031E",
+"k 	c #CD9F32",
+"l 	c #C29F2E",
+"m 	c #0F0325",
+"n 	c #0D0321",
+"o 	c #0E0324",
+"p 	c #D08329",
+"q 	c #9D1B27",
+"r 	c #1C0320",
+"s 	c #0D011A",
+"t 	c #120117",
+"u 	c #130017",
+"v 	c #150018",
+"w 	c #160119",
+"x 	c #17021A",
+"y 	c #15021B",
+"z 	c #11021E",
+"A 	c #0F021F",
+"B 	c #8C1821",
+"C 	c #CF4522",
+"D 	c #831821",
+"E 	c #BA7033",
+"F 	c #EDB339",
+"G 	c #C89733",
+"H 	c #280727",
+"I 	c #0F051F",
+"J 	c #0E0420",
+"K 	c #591F27",
+"L 	c #E47129",
+"M 	c #612224",
+"N 	c #0C021D",
+"O 	c #120018",
+"P 	c #140017",
+"Q 	c #170017",
+"R 	c #190018",
+"S 	c #1B0019",
+"T 	c #1B011A",
+"U 	c #18011B",
+"V 	c #15011C",
+"W 	c #12031E",
+"X 	c #460A21",
+"Y 	c #A13823",
+"Z 	c #784323",
+"` 	c #5A0C21",
+" .	c #BC4530",
+"..	c #EB5B38",
+"+.	c #CE4E3B",
+"@.	c #DD9334",
+"#.	c #751A27",
+"$.	c #11071E",
+"%.	c #0F041C",
+"&.	c #1E0824",
+"*.	c #955A28",
+"=.	c #9A5027",
+"-.	c #1E0321",
+";.	c #11011A",
+">.	c #140018",
+",.	c #180018",
+"'.	c #1F001A",
+").	c #20001B",
+"!.	c #1E001A",
+"~.	c #1B001A",
+"{.	c #16021B",
+"].	c #16041E",
+"^.	c #220622",
+"/.	c #5F3525",
+"(.	c #DE5724",
+"_.	c #611021",
+":.	c #0F0925",
+"<.	c #D1892E",
+"[.	c #F27036",
+"}.	c #EC633B",
+"|.	c #DA293C",
+"1.	c #E64833",
+"2.	c #912226",
+"3.	c #11081C",
+"4.	c #110419",
+"5.	c #0F041E",
+"6.	c #451425",
+"7.	c #BF6F28",
+"8.	c #332225",
+"9.	c #0E021E",
+"0.	c #13001B",
+"a.	c #17001A",
+"b.	c #1C001B",
+"c.	c #21001C",
+"d.	c #23001C",
+"e.	c #21001B",
+"f.	c #19021A",
+"g.	c #17041E",
+"h.	c #150721",
+"i.	c #602424",
+"j.	c #D51223",
+"k.	c #540820",
+"l.	c #D04D2D",
+"m.	c #EA8933",
+"n.	c #875637",
+"o.	c #88543A",
+"p.	c #E5923A",
+"q.	c #891931",
+"r.	c #130B25",
+"s.	c #10051B",
+"t.	c #110217",
+"u.	c #12021A",
+"v.	c #761826",
+"w.	c #E2A728",
+"x.	c #300224",
+"y.	c #10011E",
+"z.	c #16001B",
+"A.	c #1B001B",
+"B.	c #21001A",
+"C.	c #1E0019",
+"D.	c #1D0019",
+"E.	c #1A011A",
+"F.	c #17031C",
+"G.	c #120720",
+"H.	c #4E0822",
+"I.	c #670721",
+"J.	c #C07630",
+"K.	c #F59734",
+"L.	c #BE1B35",
+"M.	c #0E1435",
+"N.	c #522037",
+"O.	c #DB8039",
+"P.	c #D45933",
+"Q.	c #420927",
+"R.	c #0F041D",
+"S.	c #140118",
+"T.	c #13021D",
+"U.	c #100423",
+"V.	c #7B6227",
+"W.	c #C04326",
+"X.	c #0E0020",
+"Y.	c #13001D",
+"Z.	c #18001B",
+"`.	c #1E001B",
+" +	c #22001C",
+".+	c #22001B",
+"++	c #1B011B",
+"@+	c #16041D",
+"#+	c #130520",
+"$+	c #860521",
+"%+	c #710520",
+"&+	c #670A2A",
+"*+	c #A66431",
+"=+	c #E97536",
+"-+	c #F8833A",
+";+	c #F77A3A",
+">+	c #C45337",
+",+	c #0A1C35",
+"'+	c #993638",
+")+	c #F7863B",
+"!+	c #F49736",
+"~+	c #94462B",
+"{+	c #0E031F",
+"]+	c #130119",
+"^+	c #160018",
+"/+	c #16011B",
+"(+	c #15021F",
+"_+	c #120123",
+":+	c #A65C28",
+"<+	c #5C4D23",
+"[+	c #0F001F",
+"}+	c #14001D",
+"|+	c #1A001B",
+"1+	c #1F001B",
+"2+	c #24001D",
+"3+	c #25001D",
+"4+	c #24001C",
+"5+	c #1F001C",
+"6+	c #1A011C",
+"7+	c #16021E",
+"8+	c #3F0421",
+"9+	c #BC0522",
+"0+	c #1C041E",
+"a+	c #7F5531",
+"b+	c #E68A38",
+"c+	c #F8933E",
+"d+	c #FA7942",
+"e+	c #FB7543",
+"f+	c #FA6F41",
+"g+	c #F1793D",
+"h+	c #7D3B3A",
+"i+	c #28263B",
+"j+	c #D45441",
+"k+	c #F8A238",
+"l+	c #996B2D",
+"m+	c #0E0421",
+"n+	c #12011A",
+"o+	c #180019",
+"p+	c #17001C",
+"q+	c #12001F",
+"r+	c #4C2B2A",
+"s+	c #DB8130",
+"t+	c #540023",
+"u+	c #0F0120",
+"v+	c #16011C",
+"w+	c #22001D",
+"x+	c #25001F",
+"y+	c #26001F",
+"z+	c #25001E",
+"A+	c #24001E",
+"B+	c #1D001C",
+"C+	c #18011D",
+"D+	c #16031F",
+"E+	c #3C0522",
+"F+	c #9B0821",
+"G+	c #13041E",
+"H+	c #F6462E",
+"I+	c #E6AB37",
+"J+	c #E7A03E",
+"K+	c #FA9F44",
+"L+	c #FB8A48",
+"M+	c #FD7A4A",
+"N+	c #FD794A",
+"O+	c #FD7748",
+"P+	c #FD7E45",
+"Q+	c #FD8343",
+"R+	c #FB5D42",
+"S+	c #6E3A40",
+"T+	c #EE8A37",
+"U+	c #7E252B",
+"V+	c #100520",
+"W+	c #13011A",
+"X+	c #170019",
+"Y+	c #15001C",
+"Z+	c #0F0020",
+"`+	c #564427",
+" @	c #E0BA29",
+".@	c #5E2B25",
+"+@	c #10011F",
+"@@	c #17011C",
+"#@	c #1E001D",
+"$@	c #23001F",
+"%@	c #250020",
+"&@	c #24001F",
+"*@	c #23001E",
+"=@	c #21001E",
+"-@	c #1B001C",
+";@	c #17021D",
+">@	c #14041E",
+",@	c #AC0B25",
+"'@	c #5E1420",
+")@	c #F28635",
+"!@	c #C2733E",
+"~@	c #984C44",
+"{@	c #EA9148",
+"]@	c #FB844B",
+"^@	c #FD7E4C",
+"/@	c #FE7E4C",
+"(@	c #FE7E4B",
+"_@	c #FE7749",
+":@	c #FD7148",
+"<@	c #FB7D46",
+"[@	c #F89641",
+"}@	c #B95634",
+"|@	c #0D0927",
+"1@	c #11041D",
+"2@	c #150119",
+"3@	c #180017",
+"4@	c #16001A",
+"5@	c #13001E",
+"6@	c #110023",
+"7@	c #944C29",
+"8@	c #EE6229",
+"9@	c #3D0324",
+"0@	c #12021F",
+"a@	c #19011D",
+"b@	c #21001F",
+"c@	c #22001F",
+"d@	c #20001E",
+"e@	c #1F001D",
+"f@	c #1C001C",
+"g@	c #19011C",
+"h@	c #3D1621",
+"i@	c #B53622",
+"j@	c #31061F",
+"k@	c #841D34",
+"l@	c #F2703F",
+"m@	c #C14445",
+"n@	c #E67349",
+"o@	c #FB8E4B",
+"p@	c #FD834C",
+"q@	c #FE834D",
+"r@	c #FE834C",
+"s@	c #FE804C",
+"t@	c #FD814B",
+"u@	c #FB7D49",
+"v@	c #F79B43",
+"w@	c #AF1234",
+"x@	c #0D0625",
+"y@	c #13021C",
+"z@	c #1A0019",
+"A@	c #190019",
+"B@	c #410225",
+"C@	c #D39729",
+"D@	c #AA5927",
+"E@	c #0E0422",
+"F@	c #15021E",
+"G@	c #1A011D",
+"H@	c #1D001D",
+"I@	c #15031D",
+"J@	c #240820",
+"K@	c #A01023",
+"L@	c #670B21",
+"M@	c #3D0D33",
+"N@	c #E63C3E",
+"O@	c #EF7C45",
+"P@	c #F59048",
+"Q@	c #FB944A",
+"R@	c #FD904A",
+"S@	c #FE8E4B",
+"T@	c #FE854A",
+"U@	c #FE854B",
+"V@	c #FE884C",
+"W@	c #FC954B",
+"X@	c #F8AB45",
+"Y@	c #C37A35",
+"Z@	c #0D0425",
+"`@	c #13011B",
+" #	c #170018",
+".#	c #1A0018",
+"+#	c #1C0019",
+"@#	c #15001B",
+"##	c #100120",
+"$#	c #311F25",
+"%#	c #E68E28",
+"&#	c #7A1425",
+"*#	c #130321",
+"=#	c #17011E",
+"-#	c #1A001D",
+";#	c #19001B",
+">#	c #16021C",
+",#	c #130521",
+"'#	c #6F3123",
+")#	c #6D3022",
+"!#	c #C89433",
+"~#	c #EA7E3E",
+"{#	c #DB2943",
+"]#	c #EF7745",
+"^#	c #FB8544",
+"/#	c #FD9A43",
+"(#	c #FE9941",
+"_#	c #FE9D43",
+":#	c #FEA548",
+"<#	c #FEAE49",
+"[#	c #FCB944",
+"}#	c #CA9F35",
+"|#	c #0E0225",
+"1#	c #11001B",
+"2#	c #160019",
+"3#	c #12011B",
+"4#	c #0F0220",
+"5#	c #351D26",
+"6#	c #D85B28",
+"7#	c #6C0F26",
+"8#	c #190121",
+"9#	c #1B001E",
+"0#	c #1A001C",
+"a#	c #1D001B",
+"b#	c #130220",
+"c#	c #703A23",
+"d#	c #713A23",
+"e#	c #140327",
+"f#	c #411B36",
+"g#	c #C8713E",
+"h#	c #7A3A3F",
+"i#	c #CE2C3C",
+"j#	c #E77338",
+"k#	c #9C6535",
+"l#	c #9C6233",
+"m#	c #9C6332",
+"n#	c #9C6A35",
+"o#	c #C37D3C",
+"p#	c #FEAC41",
+"q#	c #FEC23E",
+"r#	c #826330",
+"s#	c #100122",
+"t#	c #120019",
+"u#	c #150017",
+"v#	c #190017",
+"w#	c #1B0018",
+"x#	c #12001A",
+"y#	c #10021F",
+"z#	c #1A0326",
+"A#	c #5F292A",
+"B#	c #7B4E29",
+"C#	c #3C0E25",
+"D#	c #1A0020",
+"E#	c #14021F",
+"F#	c #723B23",
+"G#	c #14001A",
+"H#	c #58042A",
+"I#	c #A28337",
+"J#	c #C8813B",
+"K#	c #B14B38",
+"L#	c #761231",
+"M#	c #5A132A",
+"N#	c #0D0726",
+"O#	c #0C0623",
+"P#	c #0B0723",
+"Q#	c #0B0A26",
+"R#	c #321C2D",
+"S#	c #C45B33",
+"T#	c #FEBB33",
+"U#	c #13052A",
+"V#	c #13011F",
+"W#	c #160017",
+"X#	c #15001A",
+"Y#	c #12001D",
+"Z#	c #94062A",
+"`#	c #630D2C",
+" $	c #85292B",
+".$	c #AA5E29",
+"+$	c #1F0123",
+"@$	c #19011F",
+"#$	c #1E001C",
+"$$	c #15031F",
+"%$	c #712122",
+"&$	c #712223",
+"*$	c #14011B",
+"=$	c #110321",
+"-$	c #AF0C2B",
+";$	c #E7D534",
+">$	c #EAC934",
+",$	c #84582D",
+"'$	c #1B0824",
+")$	c #11041E",
+"!$	c #10021B",
+"~$	c #100119",
+"{$	c #100218",
+"]$	c #0F041A",
+"^$	c #0E0720",
+"/$	c #2C1026",
+"($	c #D8A328",
+"_$	c #140322",
+":$	c #160016",
+"<$	c #14001F",
+"[$	c #120024",
+"}$	c #100128",
+"|$	c #3C032F",
+"1$	c #2C062E",
+"2$	c #29022B",
+"3$	c #A31D29",
+"4$	c #976A25",
+"5$	c #1A0321",
+"6$	c #17031E",
+"7$	c #1B021D",
+"8$	c #20001C",
+"9$	c #14041F",
+"0$	c #703422",
+"a$	c #6F3522",
+"b$	c #8D0328",
+"c$	c #920329",
+"d$	c #0F0326",
+"e$	c #100321",
+"f$	c #11021B",
+"g$	c #130117",
+"h$	c #140016",
+"i$	c #150015",
+"j$	c #140015",
+"k$	c #130116",
+"l$	c #120219",
+"m$	c #11031C",
+"n$	c #12031D",
+"o$	c #170016",
+"p$	c #160020",
+"q$	c #250029",
+"r$	c #670033",
+"s$	c #DCA238",
+"t$	c #F5C736",
+"u$	c #9A732E",
+"v$	c #110227",
+"w$	c #110324",
+"x$	c #811924",
+"y$	c #A04323",
+"z$	c #250721",
+"A$	c #1A041F",
+"B$	c #1E011D",
+"C$	c #1C011C",
+"D$	c #18031D",
+"E$	c #130721",
+"F$	c #6F3623",
+"G$	c #6B3622",
+"H$	c #1A001A",
+"I$	c #14011F",
+"J$	c #12011E",
+"K$	c #11011C",
+"L$	c #140117",
+"M$	c #170015",
+"N$	c #150016",
+"O$	c #120119",
+"P$	c #11011B",
+"Q$	c #11001A",
+"R$	c #130018",
+"S$	c #170118",
+"T$	c #170119",
+"U$	c #18021E",
+"V$	c #1A0126",
+"W$	c #6F2332",
+"X$	c #E5563B",
+"Y$	c #F1B83F",
+"Z$	c #F6CC38",
+"`$	c #9D7A2D",
+" %	c #130123",
+".%	c #130320",
+"+%	c #2A0721",
+"@%	c #B00E24",
+"#%	c #7D0B23",
+"$%	c #1F0522",
+"%%	c #1E0220",
+"&%	c #1D011E",
+"*%	c #1A031E",
+"=%	c #15051F",
+"-%	c #241322",
+";%	c #A32F23",
+">%	c #670E21",
+",%	c #1C001A",
+"'%	c #19001A",
+")%	c #180016",
+"!%	c #160118",
+"~%	c #140219",
+"{%	c #11021C",
+"]%	c #10021E",
+"^%	c #0F011D",
+"/%	c #170117",
+"(%	c #160219",
+"_%	c #17041D",
+":%	c #190523",
+"<%	c #8C042E",
+"[%	c #B65838",
+"}%	c #E9D73F",
+"|%	c #EED43E",
+"1%	c #D85538",
+"2%	c #493129",
+"3%	c #130120",
+"4%	c #15021D",
+"5%	c #330822",
+"6%	c #8A0825",
+"7%	c #3C0424",
+"8%	c #1E0322",
+"9%	c #1C0321",
+"0%	c #180421",
+"a%	c #130822",
+"b%	c #AF2D24",
+"c%	c #BC5623",
+"d%	c #2F071F",
+"e%	c #1A041C",
+"f%	c #1C031C",
+"g%	c #1D011C",
+"h%	c #160117",
+"i%	c #150419",
+"j%	c #12081D",
+"k%	c #0F0923",
+"l%	c #A77027",
+"m%	c #A60525",
+"n%	c #11021A",
+"o%	c #130218",
+"p%	c #150319",
+"q%	c #16061D",
+"r%	c #180923",
+"s%	c #9C1D2B",
+"t%	c #A32636",
+"u%	c #A66E3B",
+"v%	c #4B2E3C",
+"w%	c #412C36",
+"x%	c #36012D",
+"y%	c #140123",
+"z%	c #17001E",
+"A%	c #19011B",
+"B%	c #1A0421",
+"C%	c #340425",
+"D%	c #9E0326",
+"E%	c #1F0424",
+"F%	c #1C0524",
+"G%	c #180724",
+"H%	c #A91024",
+"I%	c #D55D24",
+"J%	c #90071E",
+"K%	c #3C051D",
+"L%	c #1C021C",
+"M%	c #1C011A",
+"N%	c #1D001A",
+"O%	c #160116",
+"P%	c #150216",
+"Q%	c #140217",
+"R%	c #140618",
+"S%	c #120D1D",
+"T%	c #231925",
+"U%	c #B16A2E",
+"V%	c #FDAC34",
+"W%	c #D58631",
+"X%	c #280E2A",
+"Y%	c #0D0A23",
+"Z%	c #0F0920",
+"`%	c #120C21",
+" &	c #1F1026",
+".&	c #A3352E",
+"+&	c #EE9F36",
+"@&	c #5D2A3C",
+"#&	c #960D3C",
+"$&	c #970638",
+"%&	c #A00330",
+"&&	c #4D0126",
+"*&	c #1C001F",
+"=&	c #280120",
+"-&	c #290223",
+";&	c #1F0425",
+">&	c #260726",
+",&	c #340A26",
+"'&	c #850925",
+")&	c #3A0823",
+"!&	c #82071D",
+"~&	c #5E071D",
+"{&	c #18051C",
+"]&	c #18021A",
+"^&	c #190118",
+"/&	c #160217",
+"(&	c #150418",
+"_&	c #130618",
+":&	c #110718",
+"<&	c #10081A",
+"[&	c #110D1D",
+"}&	c #291C24",
+"|&	c #A73B2D",
+"1&	c #FD6B36",
+"2&	c #FD853C",
+"3&	c #FD863B",
+"4&	c #C24A35",
+"5&	c #6B442F",
+"6&	c #6D302D",
+"7&	c #6E252E",
+"8&	c #8E3B32",
+"9&	c #DE7739",
+"0&	c #F48E3F",
+"a&	c #DD8D41",
+"b&	c #854F3D",
+"c&	c #7E2D35",
+"d&	c #33082B",
+"e&	c #1C0222",
+"f&	c #20001F",
+"g&	c #1F0222",
+"h&	c #1A0524",
+"i&	c #440C27",
+"j&	c #BC1427",
+"k&	c #20041B",
+"l&	c #53061C",
+"m&	c #25071B",
+"n&	c #11061A",
+"o&	c #130418",
+"p&	c #140317",
+"q&	c #150217",
+"r&	c #160318",
+"s&	c #12051B",
+"t&	c #100C1D",
+"u&	c #0E101E",
+"v&	c #0C121F",
+"w&	c #0C1321",
+"x&	c #781725",
+"y&	c #B25D2C",
+"z&	c #FA6335",
+"A&	c #FD633C",
+"B&	c #FE6D42",
+"C&	c #FE7C42",
+"D&	c #FE813F",
+"E&	c #FE873C",
+"F&	c #FD743B",
+"G&	c #FB683B",
+"H&	c #FA7A3E",
+"I&	c #F98242",
+"J&	c #F97844",
+"K&	c #F98943",
+"L&	c #F79C3D",
+"M&	c #A25133",
+"N&	c #280B28",
+"O&	c #1D021F",
+"P&	c #1F011C",
+"Q&	c #280321",
+"R&	c #1C0724",
+"S&	c #3F1C27",
+"T&	c #D33C27",
+"U&	c #0E061B",
+"V&	c #0C091C",
+"W&	c #0C0A1B",
+"X&	c #0E091A",
+"Y&	c #11081B",
+"Z&	c #100A20",
+"`&	c #0E0D23",
+" *	c #551227",
+".*	c #B21829",
+"+*	c #C42329",
+"@*	c #C62C29",
+"#*	c #C55429",
+"$*	c #E76F2B",
+"%*	c #F14232",
+"&*	c #F95E3A",
+"**	c #FC6740",
+"=*	c #FE6E45",
+"-*	c #FE7246",
+";*	c #FE7545",
+">*	c #FE7744",
+",*	c #FD7745",
+"'*	c #FD7845",
+")*	c #FD7847",
+"!*	c #FD7948",
+"~*	c #FD7B44",
+"{*	c #FC7C3B",
+"]*	c #6F3130",
+"^*	c #140B24",
+"/*	c #19031D",
+"(*	c #1C011B",
+"_*	c #5A011F",
+":*	c #B70421",
+"<*	c #380824",
+"[*	c #3E2626",
+"}*	c #9F5626",
+"|*	c #13051E",
+"1*	c #360A21",
+"2*	c #361223",
+"3*	c #371724",
+"4*	c #381824",
+"5*	c #3B1524",
+"6*	c #3E1E26",
+"7*	c #471A29",
+"8*	c #DB252E",
+"9*	c #ED2733",
+"0*	c #EE5436",
+"a*	c #F04237",
+"b*	c #F33934",
+"c*	c #F53D2F",
+"d*	c #D7312B",
+"e*	c #AF212B",
+"f*	c #3A2C31",
+"g*	c #F65F39",
+"h*	c #FB6F41",
+"i*	c #FD6D45",
+"j*	c #FE7047",
+"k*	c #FE7647",
+"l*	c #FE7847",
+"m*	c #FE7848",
+"n*	c #FE7748",
+"o*	c #FE7948",
+"p*	c #FE7C48",
+"q*	c #FE7C47",
+"r*	c #FE7642",
+"s*	c #FE7439",
+"t*	c #6D332C",
+"u*	c #100B21",
+"v*	c #16031B",
+"w*	c #2B001B",
+"x*	c #22011F",
+"y*	c #220521",
+"z*	c #1B0A23",
+"A*	c #421425",
+"B*	c #951924",
+"C*	c #381023",
+"D*	c #E94028",
+"E*	c #E7302B",
+"F*	c #EF432D",
+"G*	c #F4302E",
+"H*	c #F32C30",
+"I*	c #CB4432",
+"J*	c #DD3235",
+"K*	c #EF4B3A",
+"L*	c #F0333E",
+"M*	c #CC3D3F",
+"N*	c #E4313C",
+"O*	c #F34834",
+"P*	c #D13E2C",
+"Q*	c #431825",
+"R*	c #0E1424",
+"S*	c #3C202C",
+"T*	c #F15537",
+"U*	c #F97140",
+"V*	c #FC6E45",
+"W*	c #FE7547",
+"X*	c #FE7947",
+"Y*	c #FE7B48",
+"Z*	c #FE7D48",
+"`*	c #FE8047",
+" =	c #FE7A42",
+".=	c #FE7A38",
+"+=	c #6D442B",
+"@=	c #0F0B21",
+"#=	c #15031A",
+"$=	c #49001B",
+"%=	c #2F001C",
+"&=	c #21021E",
+"*=	c #220620",
+"==	c #1B0D23",
+"-=	c #641625",
+";=	c #951823",
+">=	c #390F25",
+",=	c #AC3A2A",
+"'=	c #B6492E",
+")=	c #ED7531",
+"!=	c #F45A34",
+"~=	c #F54C36",
+"{=	c #C72D39",
+"]=	c #DE283C",
+"^=	c #F33B40",
+"/=	c #F34142",
+"(=	c #D0393F",
+"_=	c #E72E39",
+":=	c #DB3C2E",
+"<=	c #461724",
+"[=	c #0F0D1E",
+"}=	c #140B1E",
+"|=	c #341427",
+"1=	c #CB4834",
+"2=	c #F7743F",
+"3=	c #FB7145",
+"4=	c #FE7747",
+"5=	c #FE7A47",
+"6=	c #FF7B48",
+"7=	c #FF7C48",
+"8=	c #FE7F47",
+"9=	c #FE8247",
+"0=	c #FE8642",
+"a=	c #FE8439",
+"b=	c #6D442D",
+"c=	c #0F0A21",
+"d=	c #14031A",
+"e=	c #20031D",
+"f=	c #210821",
+"g=	c #191024",
+"h=	c #CC1C25",
+"i=	c #961423",
+"j=	c #2C162C",
+"k=	c #BD242E",
+"l=	c #EF2C31",
+"m=	c #F54C34",
+"n=	c #F34037",
+"o=	c #F5353A",
+"p=	c #F7413D",
+"q=	c #F8423D",
+"r=	c #F93A39",
+"s=	c #F95731",
+"t=	c #341425",
+"u=	c #110A1D",
+"v=	c #140619",
+"w=	c #18051B",
+"x=	c #200F26",
+"y=	c #864833",
+"z=	c #F8773F",
+"A=	c #FC7445",
+"B=	c #FF7E48",
+"C=	c #FF7E49",
+"D=	c #FF7D49",
+"E=	c #FF7D48",
+"F=	c #FE8347",
+"G=	c #FE8743",
+"H=	c #FE893B",
+"I=	c #6E452F",
+"J=	c #100E23",
+"K=	c #14041A",
+"L=	c #55041D",
+"M=	c #540921",
+"N=	c #161124",
+"O=	c #CE6A25",
+"P=	c #3F1129",
+"Q=	c #170A29",
+"R=	c #0F0F29",
+"S=	c #15132B",
+"T=	c #1E182D",
+"U=	c #A82B3D",
+"V=	c #CB6633",
+"W=	c #CC6932",
+"X=	c #CC3D2D",
+"Y=	c #331225",
+"Z=	c #0F091C",
+"`=	c #120417",
+" -	c #160216",
+".-	c #190419",
+"+-	c #210F26",
+"@-	c #8C4934",
+"#-	c #F97A40",
+"$-	c #FC7545",
+"%-	c #FF7B49",
+"&-	c #FE7D46",
+"*-	c #FE7E43",
+"=-	c #FD7B3E",
+"--	c #FA6934",
+";-	c #532328",
+">-	c #130B1D",
+",-	c #150519",
+"'-	c #14041C",
+")-	c #120920",
+"!-	c #C43624",
+"~-	c #A21E23",
+"{-	c #F87C30",
+"]-	c #C9302D",
+"^-	c #300F2A",
+"/-	c #591129",
+"(-	c #171328",
+"_-	c #171628",
+":-	c #141829",
+"<-	c #101A2B",
+"[-	c #0F172B",
+"}-	c #0F1226",
+"|-	c #0E0C20",
+"1-	c #100619",
+"2-	c #140316",
+"3-	c #19051B",
+"4-	c #3C1428",
+"5-	c #E04B36",
+"6-	c #FA7B41",
+"7-	c #FD7346",
+"8-	c #FE7548",
+"9-	c #FF7849",
+"0-	c #FF7749",
+"a-	c #FE7B47",
+"b-	c #FE7945",
+"c-	c #FC7740",
+"d-	c #FA7E39",
+"e-	c #C1432F",
+"f-	c #131523",
+"g-	c #130A1C",
+"h-	c #420621",
+"i-	c #D08423",
+"j-	c #F87739",
+"k-	c #C03D37",
+"l-	c #962B34",
+"m-	c #A14332",
+"n-	c #E54B30",
+"o-	c #9E3E2F",
+"p-	c #7F262E",
+"q-	c #922D2E",
+"r-	c #9C4B2E",
+"s-	c #65212C",
+"t-	c #101628",
+"u-	c #101022",
+"v-	c #11091C",
+"w-	c #130619",
+"x-	c #160A1E",
+"y-	c #43252C",
+"z-	c #F66439",
+"A-	c #FA6942",
+"B-	c #FD6C47",
+"C-	c #FE6E48",
+"D-	c #FE6F48",
+"E-	c #FE7049",
+"F-	c #FE714A",
+"G-	c #FE744A",
+"H-	c #FE7846",
+"I-	c #FD7243",
+"J-	c #FC703E",
+"K-	c #FA6C37",
+"L-	c #81312B",
+"M-	c #121123",
+"N-	c #15071D",
+"O-	c #16031A",
+"P-	c #17021B",
+"Q-	c #8F3D22",
+"R-	c #F8393E",
+"S-	c #E42A3D",
+"T-	c #E7473B",
+"U-	c #FB503B",
+"V-	c #FB4F3A",
+"W-	c #F95439",
+"X-	c #ED4C38",
+"Y-	c #F45938",
+"Z-	c #FB6537",
+"`-	c #EA5236",
+" ;	c #CE6232",
+".;	c #CD392C",
+"+;	c #181425",
+"@;	c #120F21",
+"#;	c #130D20",
+"$;	c #151225",
+"%;	c #903431",
+"&;	c #F8703D",
+"*;	c #FB6344",
+"=;	c #FD6748",
+"-;	c #FE6849",
+";;	c #FE6949",
+">;	c #FE6A49",
+",;	c #FE6C4A",
+"';	c #FE704A",
+");	c #FE734A",
+"!;	c #FE7449",
+"~;	c #FE7347",
+"{;	c #FE7145",
+"];	c #FD6C42",
+"^;	c #FD753D",
+"/;	c #F36E35",
+"(;	c #CB452C",
+"_;	c #600D24",
+":;	c #1C061F",
+"<;	c #1E031F",
+"[;	c #5B3821",
+"};	c #CE9822",
+"|;	c #FA4341",
+"1;	c #FB4341",
+"2;	c #FC4541",
+"3;	c #FC4542",
+"4;	c #FC4143",
+"5;	c #FC4D42",
+"6;	c #FB5042",
+"7;	c #FB5342",
+"8;	c #FC5242",
+"9;	c #FD4F40",
+"0;	c #FD503E",
+"a;	c #FB6339",
+"b;	c #F45E33",
+"c;	c #A12A2E",
+"d;	c #401E2C",
+"e;	c #452D2F",
+"f;	c #F74F38",
+"g;	c #FA5940",
+"h;	c #FC6245",
+"i;	c #FE6447",
+"j;	c #FE6449",
+"k;	c #FE6549",
+"l;	c #FE6749",
+"m;	c #FE6B49",
+"n;	c #FE6D49",
+"o;	c #FE6D48",
+"p;	c #FE6D47",
+"q;	c #FE6D45",
+"r;	c #FE6C44",
+"s;	c #FE6A42",
+"t;	c #FE663C",
+"u;	c #FC6233",
+"v;	c #752129",
+"w;	c #1F0922",
+"x;	c #750520",
+"y;	c #81061F",
+"z;	c #FA3D42",
+"A;	c #FB4142",
+"B;	c #FD4543",
+"C;	c #FD4844",
+"D;	c #FD4A45",
+"E;	c #FD4D45",
+"F;	c #FD5045",
+"G;	c #FD5345",
+"H;	c #FE5346",
+"I;	c #FE5445",
+"J;	c #FD5444",
+"K;	c #FC4F41",
+"L;	c #FA513D",
+"M;	c #F95339",
+"N;	c #F63736",
+"O;	c #F75737",
+"P;	c #F95F3B",
+"Q;	c #FB5840",
+"R;	c #FD5F43",
+"S;	c #FE6345",
+"T;	c #FE6547",
+"U;	c #FE6548",
+"V;	c #FE6448",
+"W;	c #FE6248",
+"X;	c #FE6348",
+"Y;	c #FE6748",
+"Z;	c #FE6848",
+"`;	c #FE6846",
+" >	c #FE6A45",
+".>	c #FE6D43",
+"+>	c #FE703F",
+"@>	c #FC6F36",
+"#>	c #6F302B",
+"$>	c #140A22",
+"%>	c #FA3B42",
+"&>	c #FC4243",
+"*>	c #FD4744",
+"=>	c #FE4A45",
+"->	c #FE4C47",
+";>	c #FE4D47",
+">>	c #FE5047",
+",>	c #FE5347",
+"'>	c #FE5447",
+")>	c #FD5246",
+"!>	c #FB503F",
+"~>	c #FA543D",
+"{>	c #9B3D3B",
+"]>	c #A3433B",
+"^>	c #F9683D",
+"/>	c #FC6940",
+"(>	c #FE6342",
+"_>	c #FE6645",
+":>	c #FE6646",
+"<>	c #FE6147",
+"[>	c #FE6048",
+"}>	c #FE6148",
+"|>	c #FE6746",
+"1>	c #FE6A46",
+"2>	c #FE6F45",
+"3>	c #FE7441",
+"4>	c #FC7D39",
+"5>	c #6C422E",
+"6>	c #0F0F23",
+"7>	c #FA4142",
+"8>	c #FC4643",
+"9>	c #FE4D46",
+"0>	c #FE4E47",
+"a>	c #FE4F48",
+"b>	c #FE5148",
+"c>	c #FE5348",
+"d>	c #FE5548",
+"e>	c #FE5247",
+"f>	c #FD5445",
+"g>	c #FC5544",
+"h>	c #F96041",
+"i>	c #D33F3D",
+"j>	c #392D39",
+"k>	c #973C38",
+"l>	c #F94E3A",
+"m>	c #FD693E",
+"n>	c #FE6C43",
+"o>	c #FE6047",
+"p>	c #FE5D47",
+"q>	c #FE5E48",
+"r>	c #FE6948",
+"s>	c #FE6947",
+"t>	c #FE6B47",
+"u>	c #FE6E46",
+"v>	c #FD6D43",
+"w>	c #FB723D",
+"x>	c #D54A33",
+"y>	c #301C29",
+"z>	c #FB4A42",
+"A>	c #FD4B44",
+"B>	c #FE4F47",
+"C>	c #FE5048",
+"D>	c #FE5648",
+"E>	c #FE5848",
+"F>	c #FE5747",
+"G>	c #FE5547",
+"H>	c #FC5945",
+"I>	c #F95742",
+"J>	c #F3543D",
+"K>	c #A33336",
+"L>	c #302032",
+"M>	c #152433",
+"N>	c #CD3E38",
+"O>	c #FD5A3F",
+"P>	c #FE6343",
+"Q>	c #FE6446",
+"R>	c #FE6247",
+"S>	c #FE6A47",
+"T>	c #FC6542",
+"U>	c #FB6A3B",
+"V>	c #FA6D34",
+"W>	c #D73C2D",
+"X>	c #442428",
+"Y>	c #281323",
+"Z>	c #FD4E42",
+"`>	c #FD4D43",
+" ,	c #FE4D45",
+".,	c #FE5248",
+"+,	c #FE5947",
+"@,	c #FE5C47",
+"#,	c #FE5B47",
+"$,	c #FE5A47",
+"%,	c #FE5847",
+"&,	c #FC5C45",
+"*,	c #F95B43",
+"=,	c #F3613F",
+"-,	c #E74F37",
+";,	c #8C2431",
+">,	c #161E2F",
+",,	c #CD4E33",
+"',	c #FD503A",
+"),	c #FE5D40",
+"!,	c #FE6445",
+"~,	c #FE6946",
+"{,	c #FE6847",
+"],	c #FE6747",
+"^,	c #FD6644",
+"/,	c #FD6241",
+"(,	c #FD5B3D",
+"_,	c #FE6739",
+":,	c #FE6135",
+"<,	c #AB4830",
+"[,	c #733E2A",
+"},	c #161224",
+"|,	c #FC4E42",
+"1,	c #FE4D44",
+"2,	c #FE4E46",
+"3,	c #FE5147",
+"4,	c #FE5E47",
+"5,	c #FD5C46",
+"6,	c #FA5B44",
+"7,	c #F45441",
+"8,	c #EB393A",
+"9,	c #CC3433",
+"0,	c #47212F",
+"a,	c #59242F",
+"b,	c #FC6734",
+"c,	c #FC6F3A",
+"d,	c #FC723E",
+"e,	c #FD6540",
+"f,	c #FE6442",
+"g,	c #FE6643",
+"h,	c #FE6944",
+"i,	c #FE6546",
+"j,	c #FE6444",
+"k,	c #FE6143",
+"l,	c #FE5E41",
+"m,	c #FE613F",
+"n,	c #FE683C",
+"o,	c #FE7937",
+"p,	c #A25030",
+"q,	c #692629",
+"r,	c #151122",
+"s,	c #FA573F",
+"t,	c #FB4D40",
+"u,	c #FC4F43",
+"v,	c #FE5246",
+"w,	c #FF6347",
+"x,	c #FE5F48",
+"y,	c #F65942",
+"z,	c #F0493D",
+"A,	c #ED3736",
+"B,	c #73262F",
+"C,	c #10152C",
+"D,	c #3B292F",
+"E,	c #363034",
+"F,	c #AC3938",
+"G,	c #FC6B3B",
+"H,	c #FD763C",
+"I,	c #FE6D3F",
+"J,	c #FE6341",
+"K,	c #FE6642",
+"L,	c #FE6745",
+"M,	c #FE6245",
+"N,	c #FE6244",
+"O,	c #FE6841",
+"P,	c #FF683B",
+"Q,	c #EC7035",
+"R,	c #D0412D",
+"S,	c #3A1627",
+"T,	c #CF3938",
+"U,	c #F6543C",
+"V,	c #FB5040",
+"W,	c #FD5544",
+"X,	c #FE5A48",
+"Y,	c #FE5D48",
+"Z,	c #FE5F47",
+"`,	c #FF6147",
+" '	c #FD5C45",
+".'	c #FB5B43",
+"+'	c #FA5A42",
+"@'	c #F76040",
+"#'	c #F4623D",
+"$'	c #F26D38",
+"%'	c #EC4130",
+"&'	c #380E2B",
+"*'	c #13122C",
+"='	c #362D31",
+"-'	c #353435",
+";'	c #352E37",
+">'	c #2D3337",
+",'	c #CC5838",
+"''	c #CD6F3A",
+")'	c #CE6E3D",
+"!'	c #FE793F",
+"~'	c #FD7541",
+"{'	c #FD6243",
+"]'	c #FE6545",
+"^'	c #FF6543",
+"/'	c #FF6240",
+"('	c #FE723B",
+"_'	c #FE8034",
+":'	c #442D2C",
+"<'	c #311725",
+"['	c #222830",
+"}'	c #B73B36",
+"|'	c #F94C3D",
+"1'	c #FD5543",
+"2'	c #FE5B48",
+"3'	c #FF5E47",
+"4'	c #FE5C48",
+"5'	c #FC5B44",
+"6'	c #F95640",
+"7'	c #C34E3D",
+"8'	c #A45A3A",
+"9'	c #F37438",
+"0'	c #F28935",
+"a'	c #AF422F",
+"b'	c #240D2B",
+"c'	c #88292F",
+"d'	c #FA8E34",
+"e'	c #FC7E38",
+"f'	c #FC5939",
+"g'	c #694A37",
+"h'	c #693437",
+"i'	c #382638",
+"j'	c #142439",
+"k'	c #9F483A",
+"l'	c #C45E3C",
+"m'	c #FD7240",
+"n'	c #FF6645",
+"o'	c #FF6245",
+"p'	c #FF6045",
+"q'	c #FF6146",
+"r'	c #FF6246",
+"s'	c #FF6446",
+"t'	c #FF6545",
+"u'	c #FE763F",
+"v'	c #FE7237",
+"w'	c #C65331",
+"x'	c #3D272A",
+"y'	c #0D1E2B",
+"z'	c #683032",
+"A'	c #F9453A",
+"B'	c #FD5341",
+"C'	c #FE5A46",
+"D'	c #FF5A48",
+"E'	c #FE5948",
+"F'	c #FD5A47",
+"G'	c #FC5D43",
+"H'	c #F95B3D",
+"I'	c #713F37",
+"J'	c #1E2D32",
+"K'	c #C44531",
+"L'	c #EF7A2F",
+"M'	c #6B2E2C",
+"N'	c #0F0E2C",
+"O'	c #F56633",
+"P'	c #FA803A",
+"Q'	c #FC673E",
+"R'	c #FD673E",
+"S'	c #FC6F3C",
+"T'	c #FA6E3B",
+"U'	c #C6633A",
+"V'	c #A06739",
+"W'	c #835638",
+"X'	c #381F38",
+"Y'	c #713B38",
+"Z'	c #7B503C",
+"`'	c #FE7741",
+" )	c #FE7344",
+".)	c #FE6D46",
+"+)	c #FF6946",
+"@)	c #FF5E46",
+"#)	c #FF5D46",
+"$)	c #FF5D47",
+"%)	c #FF5F48",
+"&)	c #FF6248",
+"*)	c #FE6941",
+"=)	c #FC783C",
+"-)	c #C46B35",
+";)	c #892730",
+">)	c #111629",
+",)	c #1F2630",
+"')	c #AD3939",
+"))	c #FC5D41",
+"!)	c #FE5946",
+"~)	c #FF5848",
+"{)	c #FE5549",
+"])	c #FC5E42",
+"^)	c #FA673B",
+"/)	c #DB7033",
+"()	c #392E2B",
+"_)	c #311A28",
+":)	c #3C2127",
+"<)	c #1D1027",
+"[)	c #92102C",
+"})	c #F58336",
+"|)	c #FA673E",
+"1)	c #FD6642",
+"2)	c #FD5A41",
+"3)	c #FC6D41",
+"4)	c #FC6D3F",
+"5)	c #FD683E",
+"6)	c #F38C39",
+"7)	c #CE6535",
+"8)	c #612E34",
+"9)	c #1D2637",
+"0)	c #71513E",
+"a)	c #FF6847",
+"b)	c #FF5F47",
+"c)	c #FF5A46",
+"d)	c #FF5847",
+"e)	c #FF5748",
+"f)	c #FF594A",
+"g)	c #FF5E4B",
+"h)	c #FE654C",
+"i)	c #FE694B",
+"j)	c #FE6B48",
+"k)	c #FC6A43",
+"l)	c #F7683E",
+"m)	c #EC6E39",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                              . + @ # $   %                                                     ",
+"                                                            & * = - ; > , ' ) ! ~                                               ",
+"                                                            { ] ^ / ( _ : < [ } | 1 2                                           ",
+"                                                        3 4 5 6 7 8 9 0 a b c d e f g h i j                                     ",
+"                                                      k l m n o p q r s t u v w x y z A B C D                                   ",
+"                                                    E F G H I J K L M N O P Q R S T U V W X Y Z `                               ",
+"                                                   ...+.@.#.$.%.&.*.=.-.;.>.,.S '.).!.~.{.].^./.(._.                            ",
+"                                              :.<.[.}.|.1.2.3.4.5.6.7.8.9.0.a.b.c.d.e.!.S f.g.h.i.j.k.                          ",
+"                                              l.m.n.o.p.q.r.s.t.u.J v.w.x.y.z.A.c.d.d.B.C.D.E.F.G.H.I.                          ",
+"                                            J.K.L.M.N.O.P.Q.R.t S.T.U.V.W.X.Y.Z.`. +d.d..+B.'.++@+#+$+%+                        ",
+"                                      &+*+=+-+;+>+,+'+)+!+~+{+]+^+/+(+_+:+<+[+}+|+1+d.2+3+4+d.5+6+7+8+9+0+                      ",
+"                                    a+b+c+d+e+f+g+h+i+j+k+l+m+n+^+o+p+q+r+s+t+u+v+b.w+x+y+z+A+w+B+C+D+E+F+G+                    ",
+"                                H+I+J+K+L+M+N+O+P+Q+R+S+T+U+V+W+Q ,.X+Y+Z+`+ @.@+@@@#@$@%@&@*@=@#@-@;@>@,@'@                    ",
+"                                )@!@~@{@]@^@/@(@_@:@<@[@}@|@1@2@3@R ,.4@5@6@7@8@9@0@a@#@b@c@=@d@e@f@g@>@h@i@j@                  ",
+"                                k@l@m@n@o@p@q@r@s@t@u@v@w@x@y@^+R S z@A@z...+B@C@D@E@F@G@H@#@e@#@#@f@g@I@J@K@L@                  ",
+"                                M@N@O@P@Q@R@S@T@U@V@W@X@Y@Z@`@ #.#+#+#S A@@###$#%#&#*#=#-#f@B+B+B+f@;#>#,#'#)#                  ",
+"                                !#~#{#]#^#/#(#(#_#:#<#[#}#|#1#^+.#S +#+#z@2#3#4#5#6#7#8#9#0#A.B+B+a#A.@@b#c#d#                  ",
+"                              e#f#g#h#i#j#k#l#m#n#o#p#q#r#s#t#u#v#.#w#S R ^+x#y#z#A#B#C#D#-#A.a#`.`.b.g@E#d#F#                  ",
+"                          G#0@H#I#J#K#L#M#N#O#P#Q#R#S#T#U#V#>.W#3@v#R R X+X#Y#s#Z#`# $.$+$@$g@f@5+5+#$6+$$%$&$                  ",
+"                          *$=$-$;$>$,$'$)$!$~${$]$^$/$($_$*$u#:$Q 3@,.X+z.<$[$}$|$1$2$3$4$5$6$7$e@8$#$G@9$0$a$                  ",
+"                        ,.4@E#b$c$d$e$f$g$h$i$j$k$l$m$n$`@>.:$o$3@,. #a.p$q$r$s$t$u$v$w$x$y$z$A$B$#@C$D$E$F$G$                  ",
+"                      R S H$v+I$J$K$n+L$:$o$o$M$N$L$O$P$Q$R$N$o$3@S$T$U$V$W$X$Y$Z$`$ %.%+%@%#%$%%%&%*%=%-%;%>%                  ",
+"                      E.,%~.'%Z.4@v W#o$)%)%)%Q !%~%{%]%^%Q$u u#/%(%_%:%<%[%}%|%1%2%3%4%=%5%6%7%8%9%0%a%b%c%d%                  ",
+"                    e%f%g%a#,%,%z@R 3@3@3@)%Q h%i%j%k%l%m%{+n%o%p%q%r%s%t%u%v%w%x%y%z%A%*%B%C%D%E%F%G%H%I%                      ",
+"                    J%K%L%M%N%D.S v#)%)%O%P%Q%R%S%T%U%V%W%X%Y%Z%`% &.&+&@&#&$&%&&&*&f@a##@=&-&;&>&,&'&)&                        ",
+"                  !&~&{&]&^&.#w#^&/%/&(&_&:&<&[&}&|&1&2&3&4&5&6&7&8&9&0&a&b&c&d&e&e@1+5+e@f&g&h&i&j&                            ",
+"                k&l&m&n&o&p&q&r&i%s&3.t&u&v&w&x&y&z&A&B&C&D&E&F&G&H&I&J&K&L&M&N&O&P&1+`.e@f&Q&R&S&T&                            ",
+"                0 U&V&W&X&<&Y&j%Z&`& *.*+*@*#*$*%*&***=*-*;*>*>*,*'*)*!*~*{*]*^*/*(*a#B+#@_*:*<*[*}*                            ",
+"                |*1*2*3*4*5*6*7*8*9*0*a*b*c*d*e*f*g*h*i*j*k*l*m*n*o*p*q*r*s*t*u*v*E.w*d.e@x*y*z*A*B*                            ",
+"                C*D*E*F*G*H*I*J*K*L*M*N*O*P*Q*R*S*T*U*V*W*l*X*o*o*Y*Z*`* =.=+=@=#='%$=%=e@&=*===-=;=                            ",
+"                >=,='=)=!=~={=]=^=/=(=_=:=<=[=}=|=1=2=3=4=5=p*6=6=7=8=9=0=a=b=c=d=A@~.b.B+e=f=g=h=i=                            ",
+"                    j=k=l=m=n=o=p=q=r=s=t=u=v=w=x=y=z=A=5=Z*B=C=D=E=8=F=G=H=I=J=K=S$R z@'%L=M=N=O=                              ",
+"                    P=Q=R=S=T=U=V=W=X=Y=Z=`= -.-+-@-#-$-5=p*E=D=%-%-q*&-*-=---;->-,-/%3@^+'-)-!-~-                              ",
+"                  {-]-^-/-(-_-:-<-[-}-|-1-2- -3-4-5-6-7-8-n*m*9-0-9-o*a-b-c-d-e-f-g-(&h%w c h-i-                                ",
+"                j-k-l-m-n-o-p-q-r-s-t-u-v-w-,-x-y-z-A-B-C-D-E-E-F-G-_@m*H-I-J-K-L-M-N-O-P-(+Q-                                  ",
+"                R-S-T-U-V-W-X-Y-Z-`- ;.;+;@;#;$;%;&;*;=;-;-;;;>;,;';);!;~;{;];^;/;(;_;:;<;[;};                                  ",
+"                |;1;2;3;4;5;6;7;8;9;0;a;b;c;d;e;f;g;h;i;j;j;k;k;l;m;n;o;p;q;r;s;t;u;v;w;x;y;                                    ",
+"                z;A;B;C;D;E;F;G;H;I;J;K;L;M;N;O;P;Q;R;S;T;U;V;W;X;k;Y;Z;`; >r;.>+>@>#>$>                                        ",
+"                %>&>*>=>->;>>>,>'>,>)>F;8;!>~>{>]>^>/>(>_>:>i;<>[>X;}>i;|>1>q;2>3>4>5>6>                                        ",
+"                7>8>=>9>0>a>b>c>d>,>e>e>f>g>h>i>j>k>l>m>n>:>i;o>p>q>W;r>s>t>p;u>v>w>x>y>                                        ",
+"                z>A>9>0>B>C>c>D>E>F>G>G>F>H>I>J>K>L>M>N>O>P>Q>R>o>R>T;s>S>S>S>t>1>T>U>V>W>X>Y>                                  ",
+"                Z>`> ,9>B>.,D>+,@,#,$,%,$,&,*,=,-,;,>,,,',),P>!,!,_>~,t>s>{,],{,],^,/,(,_,:,<,[,},                              ",
+"                |,`>1,2,3,G>+,4,o>o>4,@,@,5,6,7,8,9,0,a,b,c,d,e,f,g,h, >~,|>T;T;T;i,j,k,l,m,n,o,p,q,r,                          ",
+"                s,t,u,v,G>%,@,o>w,R>x,p>@,5,6,y,z,A,B,C,D,E,F,G,H,I,J,K,L,L,i,i;i;i;Q>S;M,N,P>O,P,Q,R,S,                        ",
+"                T,U,V,W,%,X,Y,Z,`,[>q>@, '.'+'@'#'$'%'&'*'='-';'>',''')'!'~'{'N,i,:>_>]'M,M,Q>_>^'/'('_':'<'                    ",
+"                ['}'|'1'$,X,2'p>3'4'2'@,5'6'7'8'9'0'a'b'c'd'e'f'g'h'i'j'k'l'd,m'g, > >n'o'p'q'r's't'.>u'v'w'x'                  ",
+"                y'z'A'B'C'X,X,2'D'E'E'F'G'H'I'J'K'L'M'N'O'P'Q'R'S'T'U'V'W'X'Y'Z'`' ).)+)r'@)#)$)%)&)l;1>*)=)-);)                ",
+"                >),)')))!)X,E'X,~){)d>!)])^)/)()_):)<)[)})|)1)f,2)3)4)5)6)7)8)9)0)*--*a)b)c)d)e)f)g)h)i)j)k)l)m)                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                "};

Property changes on: ext/json/lib/json/json.xpm
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json/pure.rb
===================================================================
--- ext/json/lib/json/pure.rb	(revision 0)
+++ ext/json/lib/json/pure.rb	(revision 14100)
@@ -0,0 +1,75 @@
+require 'json/common'
+require 'json/pure/parser'
+require 'json/pure/generator'
+
+module JSON
+  begin
+    require 'iconv'
+    # An iconv instance to convert from UTF8 to UTF16 Big Endian.
+    UTF16toUTF8 = Iconv.new('utf-8', 'utf-16be') # :nodoc:
+    # An iconv instance to convert from UTF16 Big Endian to UTF8.
+    UTF8toUTF16 = Iconv.new('utf-16be', 'utf-8') # :nodoc:
+    UTF8toUTF16.iconv('no bom')
+  rescue Errno::EINVAL, Iconv::InvalidEncoding
+    # Iconv doesn't support big endian utf-16. Let's try to hack this manually
+    # into the converters.
+    begin
+      old_verbose, $VERBSOSE = $VERBOSE, nil
+      # An iconv instance to convert from UTF8 to UTF16 Big Endian.
+      UTF16toUTF8 = Iconv.new('utf-8', 'utf-16') # :nodoc:
+      # An iconv instance to convert from UTF16 Big Endian to UTF8.
+      UTF8toUTF16 = Iconv.new('utf-16', 'utf-8') # :nodoc:
+      UTF8toUTF16.iconv('no bom')
+      if UTF8toUTF16.iconv("\xe2\x82\xac") == "\xac\x20"
+        swapper = Class.new do
+          def initialize(iconv) # :nodoc:
+            @iconv = iconv
+          end
+
+          def iconv(string) # :nodoc:
+            result = @iconv.iconv(string)
+            JSON.swap!(result)
+          end
+        end
+        UTF8toUTF16 = swapper.new(UTF8toUTF16) # :nodoc:
+      end
+      if UTF16toUTF8.iconv("\xac\x20") == "\xe2\x82\xac"
+        swapper = Class.new do
+          def initialize(iconv) # :nodoc:
+            @iconv = iconv
+          end
+
+          def iconv(string) # :nodoc:
+            string = JSON.swap!(string.dup)
+            @iconv.iconv(string)
+          end
+        end
+        UTF16toUTF8 = swapper.new(UTF16toUTF8) # :nodoc:
+      end
+    rescue Errno::EINVAL, Iconv::InvalidEncoding
+      raise MissingUnicodeSupport, "iconv doesn't seem to support UTF-8/UTF-16 conversions"
+    ensure
+      $VERBOSE = old_verbose
+    end
+  rescue LoadError
+    raise MissingUnicodeSupport,
+      "iconv couldn't be loaded, which is required for UTF-8/UTF-16 conversions"
+  end
+
+  # Swap consecutive bytes of _string_ in place.
+  def self.swap!(string) # :nodoc:
+    0.upto(string.size / 2) do |i|
+      break unless string[2 * i + 1]
+      string[2 * i], string[2 * i + 1] = string[2 * i + 1], string[2 * i]
+    end
+    string
+  end
+
+  # This module holds all the modules/classes that implement JSON's
+  # functionality in pure ruby.
+  module Pure
+    $DEBUG and warn "Using pure library for JSON."
+    JSON.parser = Parser
+    JSON.generator = Generator
+  end
+end

Property changes on: ext/json/lib/json/pure.rb
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/lib/json.rb
===================================================================
--- ext/json/lib/json.rb	(revision 0)
+++ ext/json/lib/json.rb	(revision 14100)
@@ -0,0 +1,235 @@
+require 'json/common'
+# = json - JSON for Ruby
+#
+# == Description
+#
+# This is a implementation of the JSON specification according to RFC 4627
+# (http://www.ietf.org/rfc/rfc4627.txt). Starting from version 1.0.0 on there
+# will be two variants available:
+#
+# * A pure ruby variant, that relies on the iconv and the stringscan
+#   extensions, which are both part of the ruby standard library.
+# * The quite a bit faster C extension variant, which is in parts implemented
+#   in C and comes with its own unicode conversion functions and a parser
+#   generated by the ragel state machine compiler
+#   (http://www.cs.queensu.ca/~thurston/ragel).
+#
+# Both variants of the JSON generator escape all non-ASCII an control
+# characters with \uXXXX escape sequences, and support UTF-16 surrogate pairs
+# in order to be able to generate the whole range of unicode code points. This
+# means that generated JSON text is encoded as UTF-8 (because ASCII is a subset
+# of UTF-8) and at the same time avoids decoding problems for receiving
+# endpoints, that don't expect UTF-8 encoded texts. On the negative side this
+# may lead to a bit longer strings than necessarry.
+#
+# All strings, that are to be encoded as JSON strings, should be UTF-8 byte
+# sequences on the Ruby side. To encode raw binary strings, that aren't UTF-8
+# encoded, please use the to_json_raw_object method of String (which produces
+# an object, that contains a byte array) and decode the result on the receiving
+# endpoint.
+#
+# == Author
+#
+# Florian Frank <mailto:flori@p...>
+#
+# == License
+#
+# This software is distributed under the same license as Ruby itself, see
+# http://www.ruby-lang.org/en/LICENSE.txt.
+#
+# == Download
+#
+# The latest version of this library can be downloaded at
+#
+# * http://rubyforge.org/frs?group_id=953
+#
+# Online Documentation should be located at
+#
+# * http://json.rubyforge.org
+#
+# == Usage
+# 
+# To use JSON you can
+#   require 'json'
+# to load the installed variant (either the extension 'json' or the pure
+# variant 'json_pure'). If you have installed the extension variant, you can
+# pick either the extension variant or the pure variant by typing
+#   require 'json/ext'
+# or
+#   require 'json/pure'
+#
+# You can choose to load a set of common additions to ruby core's objects if
+# you
+#   require 'json/add/core'
+#
+# After requiring this you can, e. g., serialise/deserialise Ruby ranges:
+#
+#   JSON JSON(1..10) # => 1..10
+#
+# To find out how to add JSON support to other or your own classes, read the
+# Examples section below.
+#
+# To get the best compatibility to rails' JSON implementation, you can
+#   require 'json/add/rails'
+#
+# Both of the additions attempt to require 'json' (like above) first, if it has
+# not been required yet.
+#
+# == Speed Comparisons
+#
+# I have created some benchmark results (see the benchmarks subdir of the
+# package) for the JSON-Parser to estimate the speed up in the C extension:
+#
+# JSON::Pure::Parser::  28.90  calls/second
+# JSON::Ext::Parser::  505.50 calls/second
+#
+# This is ca. <b>17.5</b> times the speed of the pure Ruby implementation.
+#
+# I have benchmarked the JSON-Generator as well. This generates a few more
+# values, because there are different modes, that also influence the achieved
+# speed:
+#
+# * JSON::Pure::Generator:
+#   generate::        35.06 calls/second
+#   pretty_generate:: 34.00 calls/second
+#   fast_generate::   41.06 calls/second
+#
+# * JSON::Ext::Generator:
+#   generate::        492.11 calls/second
+#   pretty_generate:: 348.85 calls/second
+#   fast_generate::   541.60 calls/second
+#
+# * Speedup Ext/Pure:
+#   generate safe::   14.0 times
+#   generate pretty:: 10.3 times
+#   generate fast::   13.2 times
+#
+# The rails framework includes a generator as well, also it seems to be rather
+# slow: I measured only 23.87 calls/second which is slower than any of my pure
+# generator results. Here a comparison of the different speedups with the Rails
+# measurement as the divisor:
+#
+# * Speedup Pure/Rails:
+#   generate safe::   1.5 times
+#   generate pretty:: 1.4 times
+#   generate fast::   1.7 times
+#
+# * Speedup Ext/Rails:
+#   generate safe::   20.6 times
+#   generate pretty:: 14.6 times
+#   generate fast::   22.7 times
+#
+# To achieve the fastest JSON text output, you can use the
+# fast_generate/fast_unparse methods. Beware, that this will disable the
+# checking for circular Ruby data structures, which may cause JSON to go into
+# an infinite loop.
+#
+# == Examples
+#
+# To create a JSON text from a ruby data structure, you
+# can call JSON.generate (or JSON.unparse) like that:
+#
+#  json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
+#  # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
+#
+# To create a valid JSON text you have to make sure, that the output is
+# embedded in either a JSON array [] or a JSON object {}. The easiest way to do
+# this, is by putting your values in a Ruby Array or Hash instance.
+#
+# To get back a ruby data structure from a JSON text, you have to call
+# JSON.parse on it:
+#
+#  JSON.parse json
+#  # => [1, 2, {"a"=>3.141}, false, true, nil, "4..10"]
+# 
+# Note, that the range from the original data structure is a simple
+# string now. The reason for this is, that JSON doesn't support ranges
+# or arbitrary classes. In this case the json library falls back to call
+# Object#to_json, which is the same as #to_s.to_json.
+#
+# It's possible to add JSON support serialization to arbitrary classes by
+# simply implementing a more specialized version of the #to_json method, that
+# should return a JSON object (a hash converted to JSON with #to_json) like
+# this (don't forget the *a for all the arguments):
+#
+#  class Range
+#    def to_json(*a)
+#      {
+#        'json_class'   => self.class.name, # = 'Range'
+#        'data'         => [ first, last, exclude_end? ]
+#      }.to_json(*a)
+#    end
+#  end
+#
+# The hash key 'json_class' is the class, that will be asked to deserialise the
+# JSON representation later. In this case it's 'Range', but any namespace of
+# the form 'A::B' or '::A::B' will do. All other keys are arbitrary and can be
+# used to store the necessary data to configure the object to be deserialised.
+#
+# If a the key 'json_class' is found in a JSON object, the JSON parser checks
+# if the given class responds to the json_create class method. If so, it is
+# called with the JSON object converted to a Ruby hash. So a range can
+# be deserialised by implementing Range.json_create like this:
+# 
+#  class Range
+#    def self.json_create(o)
+#      new(*o['data'])
+#    end
+#  end
+#
+# Now it possible to serialise/deserialise ranges as well:
+#
+#  json = JSON.generate [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
+#  # => "[1,2,{\"a\":3.141},false,true,null,{\"json_class\":\"Range\",\"data\":[4,10,false]}]"
+#  JSON.parse json
+#  # => [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
+#
+# JSON.generate always creates the shortest possible string representation of a
+# ruby data structure in one line. This good for data storage or network
+# protocols, but not so good for humans to read. Fortunately there's also
+# JSON.pretty_generate (or JSON.pretty_generate) that creates a more
+# readable output:
+#
+#  puts JSON.pretty_generate([1, 2, {"a"=>3.141}, false, true, nil, 4..10])
+#  [
+#    1,
+#    2,
+#    {
+#      "a": 3.141
+#    },
+#    false,
+#    true,
+#    null,
+#    {
+#      "json_class": "Range",
+#      "data": [
+#        4,
+#        10,
+#        false
+#      ]
+#    }
+#  ]
+#
+# There are also the methods Kernel#j for unparse, and Kernel#jj for
+# pretty_unparse output to the console, that work analogous to Core Ruby's p
+# and the pp library's pp methods.
+#
+# The script tools/server.rb contains a small example if you want to test, how
+# receiving a JSON object from a webrick server in your browser with the
+# javasript prototype library (http://www.prototypejs.org) works.
+#
+module JSON
+  require 'json/version'
+
+  if VARIANT_BINARY
+    require 'json/ext'
+  else
+    begin
+      require 'json/ext'
+    rescue LoadError
+      require 'json/pure'
+    end
+  end
+
+  JSON_LOADED = true
+end

Property changes on: ext/json/lib/json.rb
___________________________________________________________________
Name: svn:eol-style
   + LF

Index: ext/json/extconf.rb
===================================================================
--- ext/json/extconf.rb	(revision 0)
+++ ext/json/extconf.rb	(revision 14100)
@@ -0,0 +1,3 @@
+require 'mkmf'
+create_makefile('json')
+

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml

[前][次][番号順一覧][スレッド一覧]