[Pkg-ruby-extras-maintainers] r166 - in packages: . libjson-ruby libjson-ruby/trunk libjson-ruby/trunk/bin libjson-ruby/trunk/debian libjson-ruby/trunk/lib libjson-ruby/trunk/lib/json libjson-ruby/trunk/tests

Esteban Manchado Velázquez zoso at costa.debian.org
Sat Dec 3 23:26:28 UTC 2005


Author: zoso
Date: 2005-12-03 23:25:52 +0000 (Sat, 03 Dec 2005)
New Revision: 166

Added:
   packages/libjson-ruby/
   packages/libjson-ruby/tags/
   packages/libjson-ruby/trunk/
   packages/libjson-ruby/trunk/GPL
   packages/libjson-ruby/trunk/README
   packages/libjson-ruby/trunk/Rakefile
   packages/libjson-ruby/trunk/TODO
   packages/libjson-ruby/trunk/VERSION
   packages/libjson-ruby/trunk/bin/
   packages/libjson-ruby/trunk/bin/edit_json.rb
   packages/libjson-ruby/trunk/debian/
   packages/libjson-ruby/trunk/debian/changelog
   packages/libjson-ruby/trunk/debian/compat
   packages/libjson-ruby/trunk/debian/control
   packages/libjson-ruby/trunk/debian/control.in
   packages/libjson-ruby/trunk/debian/rules
   packages/libjson-ruby/trunk/install.rb
   packages/libjson-ruby/trunk/lib/
   packages/libjson-ruby/trunk/lib/json.rb
   packages/libjson-ruby/trunk/lib/json/
   packages/libjson-ruby/trunk/lib/json/Array.xpm
   packages/libjson-ruby/trunk/lib/json/FalseClass.xpm
   packages/libjson-ruby/trunk/lib/json/Hash.xpm
   packages/libjson-ruby/trunk/lib/json/Key.xpm
   packages/libjson-ruby/trunk/lib/json/NilClass.xpm
   packages/libjson-ruby/trunk/lib/json/Numeric.xpm
   packages/libjson-ruby/trunk/lib/json/String.xpm
   packages/libjson-ruby/trunk/lib/json/TrueClass.xpm
   packages/libjson-ruby/trunk/lib/json/editor.rb
   packages/libjson-ruby/trunk/lib/json/json.xpm
   packages/libjson-ruby/trunk/setup.rb
   packages/libjson-ruby/trunk/tests/
   packages/libjson-ruby/trunk/tests/runner.rb
   packages/libjson-ruby/trunk/tests/test_json.rb
Log:
[svn-inject] Installing original source of libjson-ruby

Added: packages/libjson-ruby/trunk/GPL
===================================================================
--- packages/libjson-ruby/trunk/GPL	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/GPL	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,340 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.

Added: packages/libjson-ruby/trunk/README
===================================================================
--- packages/libjson-ruby/trunk/README	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/README	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,27 @@
+Installation
+============
+
+Just type into the command line as root:
+
+# ruby install.rb
+
+Testing and Examples
+====================
+
+To run the tests type:
+
+$ ruby -I lib tests/runner.rb
+
+To get an idea how this library is used also look at the tests (until I have
+time to better document it.)
+
+Author
+======
+
+Florian Frank <flori at ping.de>
+
+License
+=======
+
+GNU General Public License (GPL)
+

Added: packages/libjson-ruby/trunk/Rakefile
===================================================================
--- packages/libjson-ruby/trunk/Rakefile	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/Rakefile	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,85 @@
+require 'rake/gempackagetask'
+require 'rbconfig'
+
+include Config
+
+PKG_NAME = 'json'
+PKG_VERSION = File.read('VERSION').chomp
+PKG_FILES = Dir.glob("**/*").delete_if { |item|
+    item.include?("CVS") or item.include?("pkg")
+}
+
+desc "Installing library"
+task :install  do
+    dest = CONFIG["sitelibdir"]
+    install('lib/json.rb', dest)
+    dest = File.join(dest, 'json')
+    mkdir_p dest
+    Dir['lib/json/*.*'].each do |f|
+        install(f, dest)
+    end
+    dest = CONFIG["bindir"]
+    install('bin/edit_json.rb', dest)
+end
+
+desc "Testing library"
+task :test do
+    ruby 'tests/runner.rb'
+end
+
+task :doc do
+    sh 'rdoc -d -S -o doc lib/json.rb lib/json/editor.rb'
+end
+
+spec = Gem::Specification.new do |s|
+
+    #### Basic information.
+
+    s.name = 'json'
+    s.version = PKG_VERSION
+    s.summary = "A JSON implementation in Ruby"
+    s.description = ""
+
+    #### Dependencies and requirements.
+
+    #s.add_dependency('log4r', '> 1.0.4')
+    #s.requirements << ""
+
+    s.files = PKG_FILES
+
+    #### C code extensions.
+
+    #s.extensions << "ext/extconf.rb"
+
+    #### Load-time details: library and application (you will need one or both).
+
+    s.require_path = 'lib'                         # Use these for libraries.
+    s.autorequire = 'json'
+
+    s.bindir = "bin"                               # Use these for applications.
+    s.executables = ["edit_json.rb"]
+    s.default_executable = "edit_json.rb"
+
+    #### Documentation and testing.
+
+    s.has_rdoc = true
+    #s.extra_rdoc_files = rd.rdoc_files.reject { |fn| fn =~ /\.rb$/ }.to_a
+    #s.rdoc_options <<
+    #  '--title' <<  'Rake -- Ruby Make' <<
+    #  '--main' << 'README' <<
+    #  '--line-numbers'
+    s.test_files << 'tests/runner.rb'
+
+    #### Author and project details.
+
+    s.author = "Florian Frank"
+    s.email = "flori at ping.de"
+    s.homepage = "http://json.rubyforge.org"
+    s.rubyforge_project = "json"
+end
+
+Rake::GemPackageTask.new(spec) do |pkg|
+    pkg.need_tar = true
+    pkg.package_files += PKG_FILES
+end
+    # vim: set et sw=4 ts=4:

Added: packages/libjson-ruby/trunk/TODO
===================================================================

Added: packages/libjson-ruby/trunk/VERSION
===================================================================
--- packages/libjson-ruby/trunk/VERSION	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/VERSION	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1 @@
+0.4.0

Added: packages/libjson-ruby/trunk/bin/edit_json.rb
===================================================================
--- packages/libjson-ruby/trunk/bin/edit_json.rb	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/bin/edit_json.rb	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,11 @@
+#!/usr/bin/env ruby
+$KCODE = 'U'
+require 'json/editor'
+
+filename, encoding = ARGV
+JSON::Editor.start(encoding) do |window|
+  if filename and File.exist?(filename)
+    window.file_open(filename)
+  end
+end
+  # vim: set et sw=2 ts=2:


Property changes on: packages/libjson-ruby/trunk/bin/edit_json.rb
___________________________________________________________________
Name: svn:executable
   + 

Added: packages/libjson-ruby/trunk/debian/changelog
===================================================================
--- packages/libjson-ruby/trunk/debian/changelog	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/debian/changelog	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,5 @@
+libjson-ruby (0.4.0-1) unstable; urgency=low
+
+  * Initial upload (Closes: #341904).
+
+ -- Esteban Manchado Velázquez <zoso at debian.org>  Sat,  3 Dec 2005 23:24:14 +0000

Added: packages/libjson-ruby/trunk/debian/compat
===================================================================
--- packages/libjson-ruby/trunk/debian/compat	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/debian/compat	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1 @@
+4

Added: packages/libjson-ruby/trunk/debian/control
===================================================================
--- packages/libjson-ruby/trunk/debian/control	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/debian/control	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,28 @@
+Source: libjson-ruby
+Section: interpreters
+Priority: optional
+Maintainer: Debian Ruby Extras Maintainers <pkg-ruby-extras-maintainers at lists.alioth.debian.org>
+Uploaders: Antonio S. de A. Terceiro <asaterceiro at inf.ufrgs.br>, David Moreno Garza <damog at debian.org>, David Nusinow <dnusinow at debian.org>, Paul van Tilburg <paulvt at debian.org>, Esteban Manchado Velázquez <zoso at debian.org>, Arnaud Cornet <arnaud.cornet at gmail.com>, Lucas Nussbaum <lucas at lucas-nussbaum.net>
+Build-Depends-Indep: cdbs, debhelper (>= 4.1.0), ruby-pkg-tools, ruby1.8
+Standards-Version: 3.6.2
+
+Package: libjson-ruby
+Architecture: all
+Depends: libjson-ruby1.8
+Description: JSON library for Ruby (default Ruby version)
+ This library implements the JSON (JavaScript Object Notation) specification in
+ Ruby, allowing the developer to easily convert data between Ruby and JSON. You
+ can think of it as a low fat alternative to XML, if you want to store data to
+ disk or transmit it over a network rather than use a verbose markup language.
+ .
+ This is a dummy package depending on the library for the current default
+ version of Ruby.
+
+Package: libjson-ruby1.8
+Architecture: all
+Depends: ruby1.8
+Description: JSON library for Ruby (Ruby 1.8 version)
+ This library implements the JSON (JavaScript Object Notation) specification in
+ Ruby, allowing the developer to easily convert data between Ruby and JSON. You
+ can think of it as a low fat alternative to XML, if you want to store data to
+ disk or transmit it over a network rather than use a verbose markup language.

Added: packages/libjson-ruby/trunk/debian/control.in
===================================================================
--- packages/libjson-ruby/trunk/debian/control.in	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/debian/control.in	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,28 @@
+Source: libjson-ruby
+Section: interpreters
+Priority: optional
+Maintainer: Debian Ruby Extras Maintainers <pkg-ruby-extras-maintainers at lists.alioth.debian.org>
+Uploaders: @RUBY_TEAM@
+Build-Depends-Indep: cdbs, debhelper (>= 4.1.0), ruby-pkg-tools, ruby1.8
+Standards-Version: 3.6.2
+
+Package: libjson-ruby
+Architecture: all
+Depends: libjson-ruby1.8
+Description: JSON library for Ruby (default Ruby version)
+ This library implements the JSON (JavaScript Object Notation) specification in
+ Ruby, allowing the developer to easily convert data between Ruby and JSON. You
+ can think of it as a low fat alternative to XML, if you want to store data to
+ disk or transmit it over a network rather than use a verbose markup language.
+ .
+ This is a dummy package depending on the library for the current default
+ version of Ruby.
+
+Package: libjson-ruby1.8
+Architecture: all
+Depends: ruby1.8
+Description: JSON library for Ruby (Ruby 1.8 version)
+ This library implements the JSON (JavaScript Object Notation) specification in
+ Ruby, allowing the developer to easily convert data between Ruby and JSON. You
+ can think of it as a low fat alternative to XML, if you want to store data to
+ disk or transmit it over a network rather than use a verbose markup language.

Added: packages/libjson-ruby/trunk/debian/rules
===================================================================
--- packages/libjson-ruby/trunk/debian/rules	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/debian/rules	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,5 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/ruby-pkg-tools/1/class/ruby-setup-rb.mk
+include /usr/share/ruby-pkg-tools/1/rules/uploaders.mk


Property changes on: packages/libjson-ruby/trunk/debian/rules
___________________________________________________________________
Name: svn:executable
   + 

Added: packages/libjson-ruby/trunk/install.rb
===================================================================
--- packages/libjson-ruby/trunk/install.rb	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/install.rb	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,21 @@
+#!/usr/bin/env ruby
+
+require 'rbconfig'
+require 'fileutils'
+include FileUtils::Verbose
+
+include Config
+
+dest = CONFIG["bindir"]
+cd 'bin' do
+  filename = 'edit_json.rb'
+  install(filename, dest)
+end
+dest = CONFIG["sitelibdir"]
+cd 'lib' do
+  install('json.rb', dest)
+  mkdir_p File.join(dest,'json')
+  install(File.join('json', 'editor.rb'), File.join(dest,'json'))
+  install(File.join('json', 'json.xpm'), File.join(dest,'json'))
+end
+  # vim: set et sw=2 ts=2:


Property changes on: packages/libjson-ruby/trunk/install.rb
___________________________________________________________________
Name: svn:executable
   + 

Added: packages/libjson-ruby/trunk/lib/json/Array.xpm
===================================================================
--- packages/libjson-ruby/trunk/lib/json/Array.xpm	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/lib/json/Array.xpm	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,21 @@
+/* XPM */
+static char * Array_xpm[] = {
+"16 16 2 1",
+" 	c None",
+".	c #000000",
+"                ",
+"                ",
+"                ",
+"   ..........   ",
+"   .        .   ",
+"   .        .   ",
+"   .        .   ",
+"   .        .   ",
+"   .        .   ",
+"   .        .   ",
+"   .        .   ",
+"   .        .   ",
+"   ..........   ",
+"                ",
+"                ",
+"                "};

Added: packages/libjson-ruby/trunk/lib/json/FalseClass.xpm
===================================================================
--- packages/libjson-ruby/trunk/lib/json/FalseClass.xpm	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/lib/json/FalseClass.xpm	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,21 @@
+/* XPM */
+static char * False_xpm[] = {
+"16 16 2 1",
+" 	c None",
+".	c #FF0000",
+"                ",
+"                ",
+"                ",
+"     ......     ",
+"     .          ",
+"     .          ",
+"     .          ",
+"     ......     ",
+"     .          ",
+"     .          ",
+"     .          ",
+"     .          ",
+"     .          ",
+"                ",
+"                ",
+"                "};

Added: packages/libjson-ruby/trunk/lib/json/Hash.xpm
===================================================================
--- packages/libjson-ruby/trunk/lib/json/Hash.xpm	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/lib/json/Hash.xpm	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,21 @@
+/* XPM */
+static char * Hash_xpm[] = {
+"16 16 2 1",
+" 	c None",
+".	c #000000",
+"                ",
+"                ",
+"                ",
+"       .  .     ",
+"       .  .     ",
+"       .  .     ",
+"    .........   ",
+"      .  .      ",
+"      .  .      ",
+"   .........    ",
+"     .  .       ",
+"     .  .       ",
+"     .  .       ",
+"                ",
+"                ",
+"                "};

Added: packages/libjson-ruby/trunk/lib/json/Key.xpm
===================================================================
--- packages/libjson-ruby/trunk/lib/json/Key.xpm	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/lib/json/Key.xpm	2005-12-03 23:25:52 UTC (rev 166)
@@ -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  ",
+"                ",
+"                "};

Added: packages/libjson-ruby/trunk/lib/json/NilClass.xpm
===================================================================
--- packages/libjson-ruby/trunk/lib/json/NilClass.xpm	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/lib/json/NilClass.xpm	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,21 @@
+/* XPM */
+static char * False_xpm[] = {
+"16 16 2 1",
+" 	c None",
+".	c #000000",
+"                ",
+"                ",
+"                ",
+"       ...      ",
+"      .   .     ",
+"     .     .    ",
+"     .     .    ",
+"     .     .    ",
+"     .     .    ",
+"     .     .    ",
+"     .     .    ",
+"      .   .     ",
+"       ...      ",
+"                ",
+"                ",
+"                "};

Added: packages/libjson-ruby/trunk/lib/json/Numeric.xpm
===================================================================
--- packages/libjson-ruby/trunk/lib/json/Numeric.xpm	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/lib/json/Numeric.xpm	2005-12-03 23:25:52 UTC (rev 166)
@@ -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",
+"                ",
+"                ",
+"                ",
+" ... +++@#$$$$  ",
+"   .+   %&   $$ ",
+"   .     +    $ ",
+"   .     +   $$ ",
+"   .    ++$$$$  ",
+"   .    +    $$ ",
+"   .   +      $ ",
+"   .  +       $ ",
+"   . +  $    $$ ",
+" .....++++*$$   ",
+"                ",
+"                ",
+"                "};

Added: packages/libjson-ruby/trunk/lib/json/String.xpm
===================================================================
--- packages/libjson-ruby/trunk/lib/json/String.xpm	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/lib/json/String.xpm	2005-12-03 23:25:52 UTC (rev 166)
@@ -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   ",
+"                "};

Added: packages/libjson-ruby/trunk/lib/json/TrueClass.xpm
===================================================================
--- packages/libjson-ruby/trunk/lib/json/TrueClass.xpm	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/lib/json/TrueClass.xpm	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,21 @@
+/* XPM */
+static char * TrueClass_xpm[] = {
+"16 16 2 1",
+" 	c None",
+".	c #0BF311",
+"                ",
+"                ",
+"                ",
+"   .........    ",
+"       .        ",
+"       .        ",
+"       .        ",
+"       .        ",
+"       .        ",
+"       .        ",
+"       .        ",
+"       .        ",
+"       .        ",
+"                ",
+"                ",
+"                "};

Added: packages/libjson-ruby/trunk/lib/json/editor.rb
===================================================================
--- packages/libjson-ruby/trunk/lib/json/editor.rb	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/lib/json/editor.rb	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,1195 @@
+# 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'
+
+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
+
+    # All JSON primitive types
+    ALL_TYPES = %w[TrueClass FalseClass Numeric String Array Hash NilClass].sort
+
+    # The Nodes necessary for the tree representation of a JSON document
+    ALL_NODES = (ALL_TYPES + %w[Key]).sort
+
+    # 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.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.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)
+      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, klass = MenuItem, &callback)
+        item = klass.new(label)
+        item.signal_connect(:activate, &callback)
+        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", &method(:change_node))
+        add_separator
+        add_item("Cut node", &method(:cut_node))
+        add_item("Copy node", &method(:copy_node))
+        add_item("Paste node (appending)", &method(:paste_node_appending))
+        add_item("Paste node (inserting before)",
+          &method(:paste_node_inserting_before))
+        add_separator
+        add_item("Append new node", &method(:append_new_node))
+        add_item("Insert new node before", &method(:insert_new_node))
+        add_separator 
+        add_item("Collapse/Expand node (recursively)",
+          &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
+
+      # 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', &method(:open))
+        add_item('Revert', &method(:revert))
+        add_separator
+        add_item('Save', &method(:save))
+        add_item('Save As', &method(:save_as))
+        add_separator
+        add_item('Quit', &method(:quit))
+        title
+      end
+    end
+
+    # This class creates the Edit pulldown menu.
+    class EditMenu
+      include MenuExtension
+
+      # Find a string in all nodes' contents and select the found node in the
+      # treeview.
+      def find(item)
+        search = ask_for_find_term or return
+        begin
+          @search = Regexp.new(search)
+        rescue => e
+          Editor.error_dialog(self, "Evaluation of regex /#{search}/ failed: #{e}!")
+          return
+        end
+        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
+
+      # 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('Find', &method(:find))
+        add_item('Find Again', &method(:find_again))
+        add_separator
+        add_item('Sort', &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', CheckMenuItem, &method(:collapsed_nodes))
+        @pretty_item = add_item('Pretty saving', 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 ]
+        )
+
+        hbox = HBox.new(false, 5)
+        hbox.pack_start(Label.new("Key:"))
+        hbox.pack_start(key_input = Entry.new)
+        key_input.text = @key || ''
+        dialog.vbox.add(hbox)
+        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.add(Label.new("Type:"))
+        hbox.pack_start(type_input = ComboBox.new(true))
+        ALL_TYPES.each { |t| type_input.append_text(t) }
+        type_input.active = @type || 0
+        dialog.vbox.add(hbox)
+
+        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.add(Label.new("Value:"))
+        hbox.pack_start(value_input = Entry.new)
+        value_input.text = @value || ''
+        dialog.vbox.add(hbox)
+
+        dialog.show_all
+        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.add(Label.new("Type:"))
+        hbox.pack_start(type_input = ComboBox.new(true))
+        default_active = 0
+        ALL_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.add(hbox)
+        type_input.signal_connect(:changed) do
+          configure_value(value_input, ALL_TYPES[type_input.active])
+        end
+
+        hbox = HBox.new(false, 5)
+        hbox.add(Label.new("Value:"))
+        hbox.pack_start(value_input = Entry.new)
+        value_input.text = value_text if value_text
+        configure_value(value_input, ALL_TYPES[type_input.active])
+
+        dialog.vbox.add(hbox)
+
+        dialog.show_all
+        dialog.run do |response| 
+          if response == Dialog::RESPONSE_ACCEPT
+            type = ALL_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.add(Label.new("Order:"))
+        hbox.pack_start(order_input = Entry.new)
+        order_input.text = @order || 'x'
+
+        hbox.pack_start(reverse_checkbox = CheckButton.new('Reverse'))
+
+        dialog.vbox.add(hbox)
+
+        dialog.show_all
+        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
+        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.add(Label.new("Regex:"))
+        hbox.pack_start(regex_input = Entry.new)
+        regex_input.text = @regex || ''
+
+        dialog.vbox.add(hbox)
+
+        dialog.show_all
+        dialog.run do |response| 
+          if response == Dialog::RESPONSE_ACCEPT
+            return @regex = regex_input.text
+          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
+      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
+        destroy
+        Gtk.main_quit
+        true
+      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
+
+      # 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
+
+      # 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|
+            json = if @options_menu.pretty_item.active?
+              JSON.pretty_unparse(data)
+            else
+              JSON.unparse(data)
+            end
+            output.write json
+          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!")
+            return
+          else
+            data = read_data(filename)
+            @filename = filename
+            toplevel.display_status("Loaded data from '#@filename'.")
+            display_title
+            return data
+          end
+        end
+      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
+
+      # Read a JSON document from the file named _filename_, parse it into a
+      # ruby data structure, and return the data.
+      def read_data(filename)
+        json = File.read(filename)
+        check_pretty_printed(json)
+        if @encoding && !/^utf8$/i.match(@encoding)
+          iconverter = Iconv.new('utf8', @encoding)
+          json = iconverter.iconv(json)
+        end
+        JSON::parse(json)
+      rescue JSON::JSONError => e
+        Editor.error_dialog(self, "Failed to parse JSON file: #{e}!")
+        return
+      rescue SystemCallError => e
+        quit
+      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).set_modal(true).
+          set_filename(Dir.pwd + "/").set_transient_for(self)
+        fs.signal_connect(:destroy) { Gtk.main_quit }
+        fs.ok_button.signal_connect(:clicked) do
+          filename = fs.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
+    end
+
+    # Starts a JSON Editor. If a block was given, it yields
+    # to the JSON::Editor::MainWindow instance.
+    def Editor.start(encoding = nil) # :yield: window
+      encoding ||= 'utf8'
+      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
+  end
+end
+  # vim: set et sw=2 ts=2:

Added: packages/libjson-ruby/trunk/lib/json/json.xpm
===================================================================
--- packages/libjson-ruby/trunk/lib/json/json.xpm	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/lib/json/json.xpm	2005-12-03 23:25:52 UTC (rev 166)
@@ -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 `                               ",
+"                                                   ...+. at .#.$.%.&.*.=.-.;.>.,.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.'.++ at +#+$+%+                        ",
+"                                      &+*+=+-+;+>+,+'+)+!+~+{+]+^+/+(+_+:+<+[+}+|+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+`+ @. at +@@@#@$@%@&@*@=@#@-@;@>@,@'@                    ",
+"                                )@!@~@{@]@^@/@(@_@:@<@[@}@|@1 at 2@3 at R ,.4 at 5@6 at 7@8 at 9@0 at a@#@b at c@=@d at e@f at g@>@h at i@j@                  ",
+"                                k at l@m at n@o at p@q at r@s at t@u at v@w at x@y@^+R S z at A@z.q+B at C@D at E@F at G@H@#@e@#@#@f at g@I at J@K at L@                  ",
+"                                M at N@O at P@Q at R@S at T@U at V@W at X@Y at Z@`@ #.#+#+#S A@@###$#%#&#*#=#-#f at B+B+B+f@;#>#,#'#)#                  ",
+"                                !#~#{#]#^#/#(#(#_#:#<#[#}#|#1#^+.#S +#+#z at 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 at E#d#F#                  ",
+"                          G#0 at H#I#J#K#L#M#N#O#P#Q#R#S#T#U#V#>.W#3 at v#R R X+X#Y#s#Z#`# $.$+$@$g at f@5+5+#$6+$$%$&$                  ",
+"                          *$=$-$;$>$,$'$)$!$~${$]$^$/$($_$*$u#:$Q 3@,.X+z.<$[$}$|$1$2$3$4$5$6$7$e at 8$#$G at 9$0$a$                  ",
+"                        ,.4 at 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 at S$T$U$V$W$X$Y$Z$`$ %.%+%@%#%$%%%&%*%=%-%;%>%                  ",
+"                      E.,%~.'%Z.4 at 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 at R 3 at 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 at a##@=&-&;&>&,&'&)&                        ",
+"                  !&~&{&]&^&.#w#^&/%/&(&_&:&<&[&}&|&1&2&3&4&5&6&7&8&9&0&a&b&c&d&e&e at 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 at 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 at 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=`= -.-+- at -#-$-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-_ at 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)                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                ",
+"                                                                                                                                "};

Added: packages/libjson-ruby/trunk/lib/json.rb
===================================================================
--- packages/libjson-ruby/trunk/lib/json.rb	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/lib/json.rb	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,652 @@
+# = json - JSON library for Ruby
+#
+# == Description
+#
+# == Author
+#
+# Florian Frank <mailto:flori at ping.de>
+#
+# == License
+#
+# This is free software; you can redistribute it and/or modify it under the
+# terms of the GNU General Public License Version 2 as published by the Free
+# Software Foundation: www.gnu.org/copyleft/gpl.html
+#
+# == 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
+#
+# == Examples
+#
+# To create a JSON string from a ruby data structure, you
+# can call JSON.unparse like that:
+#
+#  json = JSON.unparse [1, 2, {"a"=>3.141}, false, true, nil, 4..10]
+#  # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
+#
+# It's also possible to call the #to_json method directly.
+#
+#  json = [1, 2, {"a"=>3.141}, false, true, nil, 4..10].to_json
+#  # => "[1,2,{\"a\":3.141},false,true,null,\"4..10\"]"
+#
+# To get back a ruby data structure, you have to call
+# JSON.parse on the JSON string:
+#
+#  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 extend JSON to support serialization of arbitray 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,
+#        'data'         => [ first, last, exclude_end? ]
+#      }.to_json(*a)
+#    end
+#  end
+#
+# The hash key 'json_class' is the class, that will be asked to deserialize 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 deserialized.
+#
+# 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 deserialized by implementing Range.json_create like this:
+# 
+#  class Range
+#    def self.json_create(o)
+#      new(*o['data'])
+#    end
+#  end
+#
+# Now it possible to serialize/deserialize ranges as well:
+#
+#  json = JSON.unparse [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.unparse always creates the shortes 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_unparse that creates a more readable output:
+#
+#  puts JSON.pretty_unparse([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 Kernel#p and
+# Kernel#pp.
+#
+
+require 'strscan'
+
+# This module is the namespace for all the JSON related classes. It also 
+# defines some module functions to expose a nicer API to users, instead
+# of using the parser and other classes directly.
+module JSON
+  # The base exception for JSON errors.
+  JSONError             = Class.new StandardError
+
+  # This exception is raise, if a parser error occurs.
+  ParserError           = Class.new JSONError
+
+  # This exception is raise, if a unparser error occurs.
+  UnparserError         = Class.new JSONError
+
+  # If a circular data structure is encountered while unparsing
+  # this exception is raised.
+  CircularDatastructure = Class.new UnparserError
+
+  class << self
+    # Switches on Unicode support, if _enable_ is _true_. Otherwise switches
+    # Unicode support off.
+    def support_unicode=(enable)
+      @support_unicode = enable
+    end
+
+    # Returns _true_ if JSON supports unicode, otherwise _false_ is returned.
+    def support_unicode?
+      !!@support_unicode
+    end
+  end
+  JSON.support_unicode = true # default, hower it's possible to switch off full
+                              # unicode support, if non-ascii bytes should be
+                              # just passed through.
+
+  begin
+    require 'iconv'
+    # An iconv instance to convert from UTF8 to UTF16 Big Endian.
+    UTF16toUTF8 = Iconv.new('utf-8', 'utf-16be')
+    # An iconv instance to convert from UTF16 Big Endian to UTF8.
+    UTF8toUTF16 = Iconv.new('utf-16be', 'utf-8'); UTF8toUTF16.iconv('no bom')
+  rescue LoadError
+    JSON.support_unicode = false # enforce disabling of unicode support
+  end
+
+  # This class implements the JSON parser that is used to parse a JSON string
+  # into a Ruby data structure.
+  class Parser < StringScanner
+    STRING                = /"((?:[^"\\]|\\.)*)"/
+    INTEGER               = /-?\d+/
+    FLOAT                 = /-?\d+\.(\d*)(?i:e[+-]?\d+)?/
+    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
+        |\s+              # whitespaces
+      )+
+    )mx
+
+    UNPARSED = Object.new
+
+    # Parses the current JSON string and returns the complete data structure
+    # as a result.
+    def parse
+      reset
+      until eos?
+        case
+        when scan(ARRAY_OPEN)
+          return parse_array
+        when scan(OBJECT_OPEN)
+          return parse_object
+        when skip(IGNORE)
+          ;
+        when !((value = parse_value).equal? UNPARSED)
+          return value
+        else
+          raise ParserError, "source '#{peek(20)}' not in JSON!"
+        end
+      end
+    end
+
+    private
+
+    def parse_string
+      if scan(STRING)
+        return '' if self[1].empty?
+        self[1].gsub(/\\(?:[\\bfnrt"]|u([A-Fa-f\d]{4}))/) do
+          case $~[0]
+          when '\\\\' then '\\'
+          when '\\b'  then "\b"
+          when '\\f'  then "\f"
+          when '\\n'  then "\n"
+          when '\\r'  then "\r"
+          when '\\t'  then "\t"
+          when '\"'   then '"'
+          else
+            if JSON.support_unicode? and $KCODE == 'UTF8'
+              JSON.utf16_to_utf8($~[1])
+            else
+              # if utf8 mode is switched off or unicode not supported, try to
+              # transform unicode \u-notation to bytes directly:
+              $~[1].to_i(16).chr
+            end
+          end
+        end
+      else
+        UNPARSED
+      end
+    end
+
+    def parse_value
+      case
+      when scan(FLOAT)
+        Float(self[0])
+      when scan(INTEGER)
+        Integer(self[0])
+      when scan(TRUE)
+        true
+      when scan(FALSE)
+        false
+      when scan(NULL)
+        nil
+      when (string = parse_string) != UNPARSED
+        string
+      when scan(ARRAY_OPEN)
+        parse_array
+      when scan(OBJECT_OPEN)
+        parse_object
+      else
+        UNPARSED
+      end
+    end
+
+    def parse_array
+      result = []
+      until eos?
+        case
+        when (value = parse_value) != UNPARSED
+          result << value
+          skip(IGNORE)
+          unless scan(COLLECTION_DELIMITER) or match?(ARRAY_CLOSE)
+            raise ParserError, "expected ',' or ']' in array at '#{peek(20)}'!"
+          end
+        when scan(ARRAY_CLOSE)
+          break
+        when skip(IGNORE)
+          ;
+        else
+          raise ParserError, "unexpected token in array at '#{peek(20)}'!"
+        end
+      end
+      result
+    end
+
+    def parse_object
+      result = {}
+      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
+            skip(IGNORE)
+            unless scan(COLLECTION_DELIMITER) or match?(OBJECT_CLOSE)
+              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 klassname = result['json_class']
+            klass = klassname.sub(/^:+/, '').split(/::/).inject(Object) do |p,k|
+              p.const_get(k) rescue nil
+            end
+            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
+
+  # This class is used to create State instances, that are use to hold data
+  # while unparsing a Ruby data structure into a JSON string.
+  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_.
+    def initialize(opts = {})
+      @indent     = opts[:indent]     || ''
+      @space      = opts[:space]      || ''
+      @object_nl  = opts[:object_nl]  || ''
+      @array_nl   = opts[:array_nl]   || ''
+      @seen       = {}
+    end
+
+    # This string is used to indent levels in the JSON string.
+    attr_accessor :indent
+
+    # This string is used to include a space between the tokens in a JSON
+    # string.
+    attr_accessor :space
+
+    # 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
+
+    # Returns _true_, if _object_ was already seen during this Unparsing run. 
+    def seen?(object)
+      @seen.key?(object.__id__)
+    end
+
+    # Remember _object_, to find out if it was already encountered (to find out
+    # if a cyclic data structure is unparsed). 
+    def remember(object)
+      @seen[object.__id__] = true
+    end
+
+    # Forget _object_ for this Unparsing run.
+    def forget(object)
+      @seen.delete object.__id__
+    end
+  end
+
+  module_function
+
+  # Convert _string_ from UTF8 encoding to UTF16 (big endian) encoding and
+  # return it.
+  def utf8_to_utf16(string)
+    JSON::UTF8toUTF16.iconv(string).unpack('H*')[0]
+  end
+
+  # Convert _string_ from UTF16 (big endian) encoding to UTF8 encoding and
+  # return it.
+  def utf16_to_utf8(string)
+    bytes = '' << string[0, 2].to_i(16) << string[2, 2].to_i(16)
+    JSON::UTF16toUTF8.iconv(bytes)
+  end
+
+  # 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)
+    i, n, result = 0, string.size, ''
+    while i < n
+      char = string[i]
+      case
+      when char == ?\b then result << '\b'
+      when char == ?\t then result << '\t'
+      when char == ?\n then result << '\n'
+      when char == ?\f then result << '\f'
+      when char == ?\r then result << '\r'
+      when char == ?"  then result << '\"'
+      when char == ?\\ then result << '\\'
+      when char.between?(0x0, 0x1f) then result << "\\u%04x" % char
+      when char.between?(0x20, 0x7f) then result << char
+      when !(JSON.support_unicode? && $KCODE == 'UTF8')
+        # if utf8 mode is switched off or unicode not supported, just pass
+        # bytes through:
+        result << char
+      when char & 0xe0 == 0xc0
+        result << '\u' << utf8_to_utf16(string[i, 2])
+        i += 1
+      when char & 0xf0 == 0xe0
+        result << '\u' << utf8_to_utf16(string[i, 3])
+        i += 2
+      when char & 0xf8 == 0xf0
+        result << '\u' << utf8_to_utf16(string[i, 4])
+        i += 3
+      when char & 0xfc == 0xf8
+        result << '\u' << utf8_to_utf16(string[i, 5])
+        i += 4
+      when char & 0xfe == 0xfc
+        result << '\u' << utf8_to_utf16(string[i, 6])
+        i += 5
+      else
+        raise JSON::UnparserError, "Encountered unknown UTF-8 byte: %x!" % char
+      end
+      i += 1
+    end
+    result
+  end
+
+  # Parse the JSON string _source_ into a Ruby data structure and return it.
+  def parse(source)
+    Parser.new(source).parse
+  end
+
+  # Unparse the Ruby data structure _obj_ into a single line JSON string and
+  # return it. _state_ is a JSON::State object, that can be used to configure
+  # the output further.
+  def unparse(obj, state = nil)
+    obj.to_json(JSON::State.from_state(state))
+  end
+
+  # 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.
+  def pretty_unparse(obj)
+    state = JSON::State.new(
+      :indent     => '  ',
+      :space      => ' ',
+      :object_nl  => "\n",
+      :array_nl   => "\n"
+    )
+    obj.to_json(state)
+  end
+end
+
+class 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.
+  # _state_ is a JSON::State object, that can also be used
+  # to configure the produced JSON string output further.
+
+  def to_json(*) to_s.to_json end
+end
+
+class 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)
+    state = JSON::State.from_state(state)
+    json_check_circular(state) { json_transform(state, depth) }
+  end
+
+  private
+
+  def json_check_circular(state)
+    if state
+      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|
+      json_shift(state, depth + 1) <<
+        key.to_s.to_json(state, depth + 1) <<
+        ':' << state.space << value.to_json(state, depth + 1)
+    }.join(delim)
+    result << state.object_nl if state
+    result << json_shift(state, depth)
+    result << '}'
+    result
+  end
+end
+
+class 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)
+    state = JSON::State.from_state(state)
+    json_check_circular(state) { json_transform(state, depth) }
+  end
+
+  private
+
+  def json_check_circular(state)
+    if state
+      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
+
+class Integer
+  # Returns a JSON string representation for this Integer number.
+  def to_json(*) to_s end
+end
+
+class Float
+  # Returns a JSON string representation for this Float number.
+  def to_json(*) to_s end
+end
+
+class String
+  # This string should be encoded with UTF-8 (if JSON unicode support is
+  # enabled). A call to this method returns a JSON string
+  # encoded with UTF16 big endian characters as \u????. If
+  # JSON.support_unicode? is false only control characters are encoded this
+  # way, all 8-bit bytes are just passed through.
+  def to_json(*)
+    '"' << JSON::utf8_to_json(self) << '"'
+  end
+
+  # 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 class method.
+  def self.json_create(o)
+    o['raw'].pack('C*')
+  end
+
+  # This method creates a raw object, that can be nested into other data
+  # structures and will be unparsed as a raw string.
+  def to_json_raw_object
+    {
+      'json_class'  => self.class.name,
+      'raw'         => self.unpack('C*'),
+    }
+  end
+
+  # This method should be used, if you want to convert raw strings to JSON
+  # instead of UTF-8 strings, e. g. binary data (and JSON Unicode support is
+  # enabled).
+  def to_json_raw(*args)
+    to_json_raw_object.to_json(*args)
+  end
+end
+
+class TrueClass
+  # Returns a JSON string for true: 'true'.
+  def to_json(*) to_s end
+end
+
+class FalseClass
+  # Returns a JSON string for false: 'false'.
+  def to_json(*) to_s end
+end
+
+class NilClass
+  # Returns a JSON string for nil: 'null'.
+  def to_json(*) 'null' 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::unparse(obj)
+    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_unparse(obj)
+    end
+    nil
+  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:

Added: packages/libjson-ruby/trunk/setup.rb
===================================================================
--- packages/libjson-ruby/trunk/setup.rb	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/setup.rb	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,1360 @@
+#
+# setup.rb
+#
+# Copyright (c) 2000-2004 Minero Aoki
+#
+# This program is free software.
+# You can distribute/modify this program under the terms of
+# the GNU LGPL, Lesser General Public License version 2.1.
+#
+
+unless Enumerable.method_defined?(:map)   # Ruby 1.4.6
+  module Enumerable
+    alias map collect
+  end
+end
+
+unless File.respond_to?(:read)   # Ruby 1.6
+  def File.read(fname)
+    open(fname) {|f|
+      return f.read
+    }
+  end
+end
+
+def File.binread(fname)
+  open(fname, 'rb') {|f|
+    return f.read
+  }
+end
+
+# for corrupted windows stat(2)
+def File.dir?(path)
+  File.directory?((path[-1,1] == '/') ? path : path + '/')
+end
+
+
+class SetupError < StandardError; end
+
+def setup_rb_error(msg)
+  raise SetupError, msg
+end
+
+#
+# Config
+#
+
+if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg }
+  ARGV.delete(arg)
+  require arg.split(/=/, 2)[1]
+  $".push 'rbconfig.rb'
+else
+  require 'rbconfig'
+end
+
+def multipackage_install?
+  FileTest.directory?(File.dirname($0) + '/packages')
+end
+
+
+class ConfigItem
+  def initialize(name, template, default, desc)
+    @name = name.freeze
+    @template = template
+    @value = default
+    @default = default.dup.freeze
+    @description = desc
+  end
+
+  attr_reader :name
+  attr_reader :description
+
+  attr_accessor :default
+  alias help_default default
+
+  def help_opt
+    "--#{@name}=#{@template}"
+  end
+
+  def value
+    @value
+  end
+
+  def eval(table)
+    @value.gsub(%r<\$([^/]+)>) { table[$1] }
+  end
+
+  def set(val)
+    @value = check(val)
+  end
+
+  private
+
+  def check(val)
+    setup_rb_error "config: --#{name} requires argument" unless val
+    val
+  end
+end
+
+class BoolItem < ConfigItem
+  def config_type
+    'bool'
+  end
+
+  def help_opt
+    "--#{@name}"
+  end
+
+  private
+
+  def check(val)
+    return 'yes' unless val
+    unless /\A(y(es)?|n(o)?|t(rue)?|f(alse))\z/i =~ val
+      setup_rb_error "config: --#{@name} accepts only yes/no for argument"
+    end
+    (/\Ay(es)?|\At(rue)/i =~ value) ? 'yes' : 'no'
+  end
+end
+
+class PathItem < ConfigItem
+  def config_type
+    'path'
+  end
+
+  private
+
+  def check(path)
+    setup_rb_error "config: --#{@name} requires argument"  unless path
+    path[0,1] == '$' ? path : File.expand_path(path)
+  end
+end
+
+class ProgramItem < ConfigItem
+  def config_type
+    'program'
+  end
+end
+
+class SelectItem < ConfigItem
+  def initialize(name, template, default, desc)
+    super
+    @ok = template.split('/')
+  end
+
+  def config_type
+    'select'
+  end
+
+  private
+
+  def check(val)
+    unless @ok.include?(val.strip)
+      setup_rb_error "config: use --#{@name}=#{@template} (#{val})"
+    end
+    val.strip
+  end
+end
+
+class PackageSelectionItem < ConfigItem
+  def initialize(name, template, default, help_default, desc)
+    super name, template, default, desc
+    @help_default = help_default
+  end
+
+  attr_reader :help_default
+
+  def config_type
+    'package'
+  end
+
+  private
+
+  def check(val)
+    unless File.dir?("packages/#{val}")
+      setup_rb_error "config: no such package: #{val}"
+    end
+    val
+  end
+end
+
+class ConfigTable_class
+
+  def initialize(items)
+    @items = items
+    @table = {}
+    items.each do |i|
+      @table[i.name] = i
+    end
+    ALIASES.each do |ali, name|
+      @table[ali] = @table[name]
+    end
+  end
+
+  include Enumerable
+
+  def each(&block)
+    @items.each(&block)
+  end
+
+  def key?(name)
+    @table.key?(name)
+  end
+
+  def lookup(name)
+    @table[name] or raise ArgumentError, "no such config item: #{name}"
+  end
+
+  def add(item)
+    @items.push item
+    @table[item.name] = item
+  end
+
+  def remove(name)
+    item = lookup(name)
+    @items.delete_if {|i| i.name == name }
+    @table.delete_if {|name, i| i.name == name }
+    item
+  end
+
+  def new
+    dup()
+  end
+
+  def savefile
+    '.config'
+  end
+
+  def load
+    begin
+      t = dup()
+      File.foreach(savefile()) do |line|
+        k, v = *line.split(/=/, 2)
+        t[k] = v.strip
+      end
+      t
+    rescue Errno::ENOENT
+      setup_rb_error $!.message + "#{File.basename($0)} config first"
+    end
+  end
+
+  def save
+    @items.each {|i| i.value }
+    File.open(savefile(), 'w') {|f|
+      @items.each do |i|
+        f.printf "%s=%s\n", i.name, i.value if i.value
+      end
+    }
+  end
+
+  def [](key)
+    lookup(key).eval(self)
+  end
+
+  def []=(key, val)
+    lookup(key).set val
+  end
+
+end
+
+c = ::Config::CONFIG
+
+rubypath = c['bindir'] + '/' + c['ruby_install_name']
+
+major = c['MAJOR'].to_i
+minor = c['MINOR'].to_i
+teeny = c['TEENY'].to_i
+version = "#{major}.#{minor}"
+
+# ruby ver. >= 1.4.4?
+newpath_p = ((major >= 2) or
+             ((major == 1) and
+              ((minor >= 5) or
+               ((minor == 4) and (teeny >= 4)))))
+
+if c['rubylibdir']
+  # V < 1.6.3
+  _stdruby         = c['rubylibdir']
+  _siteruby        = c['sitedir']
+  _siterubyver     = c['sitelibdir']
+  _siterubyverarch = c['sitearchdir']
+elsif newpath_p
+  # 1.4.4 <= V <= 1.6.3
+  _stdruby         = "$prefix/lib/ruby/#{version}"
+  _siteruby        = c['sitedir']
+  _siterubyver     = "$siteruby/#{version}"
+  _siterubyverarch = "$siterubyver/#{c['arch']}"
+else
+  # V < 1.4.4
+  _stdruby         = "$prefix/lib/ruby/#{version}"
+  _siteruby        = "$prefix/lib/ruby/#{version}/site_ruby"
+  _siterubyver     = _siteruby
+  _siterubyverarch = "$siterubyver/#{c['arch']}"
+end
+libdir = '-* dummy libdir *-'
+stdruby = '-* dummy rubylibdir *-'
+siteruby = '-* dummy site_ruby *-'
+siterubyver = '-* dummy site_ruby version *-'
+parameterize = lambda {|path|
+  path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix')\
+      .sub(/\A#{Regexp.quote(libdir)}/,      '$libdir')\
+      .sub(/\A#{Regexp.quote(stdruby)}/,     '$stdruby')\
+      .sub(/\A#{Regexp.quote(siteruby)}/,    '$siteruby')\
+      .sub(/\A#{Regexp.quote(siterubyver)}/, '$siterubyver')
+}
+libdir          = parameterize.call(c['libdir'])
+stdruby         = parameterize.call(_stdruby)
+siteruby        = parameterize.call(_siteruby)
+siterubyver     = parameterize.call(_siterubyver)
+siterubyverarch = parameterize.call(_siterubyverarch)
+
+if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg }
+  makeprog = arg.sub(/'/, '').split(/=/, 2)[1]
+else
+  makeprog = 'make'
+end
+
+common_conf = [
+  PathItem.new('prefix', 'path', c['prefix'],
+               'path prefix of target environment'),
+  PathItem.new('bindir', 'path', parameterize.call(c['bindir']),
+               'the directory for commands'),
+  PathItem.new('libdir', 'path', libdir,
+               'the directory for libraries'),
+  PathItem.new('datadir', 'path', parameterize.call(c['datadir']),
+               'the directory for shared data'),
+  PathItem.new('mandir', 'path', parameterize.call(c['mandir']),
+               'the directory for man pages'),
+  PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']),
+               'the directory for man pages'),
+  PathItem.new('stdruby', 'path', stdruby,
+               'the directory for standard ruby libraries'),
+  PathItem.new('siteruby', 'path', siteruby,
+      'the directory for version-independent aux ruby libraries'),
+  PathItem.new('siterubyver', 'path', siterubyver,
+               'the directory for aux ruby libraries'),
+  PathItem.new('siterubyverarch', 'path', siterubyverarch,
+               'the directory for aux ruby binaries'),
+  PathItem.new('rbdir', 'path', '$siterubyver',
+               'the directory for ruby scripts'),
+  PathItem.new('sodir', 'path', '$siterubyverarch',
+               'the directory for ruby extentions'),
+  PathItem.new('rubypath', 'path', rubypath,
+               'the path to set to #! line'),
+  ProgramItem.new('rubyprog', 'name', rubypath,
+                  'the ruby program using for installation'),
+  ProgramItem.new('makeprog', 'name', makeprog,
+                  'the make program to compile ruby extentions'),
+  SelectItem.new('shebang', 'all/ruby/never', 'ruby',
+                 'shebang line (#!) editing mode'),
+  BoolItem.new('without-ext', 'yes/no', 'no',
+               'does not compile/install ruby extentions')
+]
+class ConfigTable_class   # open again
+  ALIASES = {
+    'std-ruby'         => 'stdruby',
+    'site-ruby-common' => 'siteruby',     # For backward compatibility
+    'site-ruby'        => 'siterubyver',  # For backward compatibility
+    'bin-dir'          => 'bindir',
+    'bin-dir'          => 'bindir',
+    'rb-dir'           => 'rbdir',
+    'so-dir'           => 'sodir',
+    'data-dir'         => 'datadir',
+    'ruby-path'        => 'rubypath',
+    'ruby-prog'        => 'rubyprog',
+    'ruby'             => 'rubyprog',
+    'make-prog'        => 'makeprog',
+    'make'             => 'makeprog'
+  }
+end
+multipackage_conf = [
+  PackageSelectionItem.new('with', 'name,name...', '', 'ALL',
+                           'package names that you want to install'),
+  PackageSelectionItem.new('without', 'name,name...', '', 'NONE',
+                           'package names that you do not want to install')
+]
+if multipackage_install?
+  ConfigTable = ConfigTable_class.new(common_conf + multipackage_conf)
+else
+  ConfigTable = ConfigTable_class.new(common_conf)
+end
+
+
+module MetaConfigAPI
+
+  def eval_file_ifexist(fname)
+    instance_eval File.read(fname), fname, 1 if File.file?(fname)
+  end
+
+  def config_names
+    ConfigTable.map {|i| i.name }
+  end
+
+  def config?(name)
+    ConfigTable.key?(name)
+  end
+
+  def bool_config?(name)
+    ConfigTable.lookup(name).config_type == 'bool'
+  end
+
+  def path_config?(name)
+    ConfigTable.lookup(name).config_type == 'path'
+  end
+
+  def value_config?(name)
+    case ConfigTable.lookup(name).config_type
+    when 'bool', 'path'
+      true
+    else
+      false
+    end
+  end
+
+  def add_config(item)
+    ConfigTable.add item
+  end
+
+  def add_bool_config(name, default, desc)
+    ConfigTable.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc)
+  end
+
+  def add_path_config(name, default, desc)
+    ConfigTable.add PathItem.new(name, 'path', default, desc)
+  end
+
+  def set_config_default(name, default)
+    ConfigTable.lookup(name).default = default
+  end
+
+  def remove_config(name)
+    ConfigTable.remove(name)
+  end
+
+end
+
+
+#
+# File Operations
+#
+
+module FileOperations
+
+  def mkdir_p(dirname, prefix = nil)
+    dirname = prefix + File.expand_path(dirname) if prefix
+    $stderr.puts "mkdir -p #{dirname}" if verbose?
+    return if no_harm?
+
+    # does not check '/'... it's too abnormal case
+    dirs = File.expand_path(dirname).split(%r<(?=/)>)
+    if /\A[a-z]:\z/i =~ dirs[0]
+      disk = dirs.shift
+      dirs[0] = disk + dirs[0]
+    end
+    dirs.each_index do |idx|
+      path = dirs[0..idx].join('')
+      Dir.mkdir path unless File.dir?(path)
+    end
+  end
+
+  def rm_f(fname)
+    $stderr.puts "rm -f #{fname}" if verbose?
+    return if no_harm?
+
+    if File.exist?(fname) or File.symlink?(fname)
+      File.chmod 0777, fname
+      File.unlink fname
+    end
+  end
+
+  def rm_rf(dn)
+    $stderr.puts "rm -rf #{dn}" if verbose?
+    return if no_harm?
+
+    Dir.chdir dn
+    Dir.foreach('.') do |fn|
+      next if fn == '.'
+      next if fn == '..'
+      if File.dir?(fn)
+        verbose_off {
+          rm_rf fn
+        }
+      else
+        verbose_off {
+          rm_f fn
+        }
+      end
+    end
+    Dir.chdir '..'
+    Dir.rmdir dn
+  end
+
+  def move_file(src, dest)
+    File.unlink dest if File.exist?(dest)
+    begin
+      File.rename src, dest
+    rescue
+      File.open(dest, 'wb') {|f| f.write File.binread(src) }
+      File.chmod File.stat(src).mode, dest
+      File.unlink src
+    end
+  end
+
+  def install(from, dest, mode, prefix = nil)
+    $stderr.puts "install #{from} #{dest}" if verbose?
+    return if no_harm?
+
+    realdest = prefix ? prefix + File.expand_path(dest) : dest
+    realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest)
+    str = File.binread(from)
+    if diff?(str, realdest)
+      verbose_off {
+        rm_f realdest if File.exist?(realdest)
+      }
+      File.open(realdest, 'wb') {|f|
+        f.write str
+      }
+      File.chmod mode, realdest
+
+      File.open("#{objdir_root()}/InstalledFiles", 'a') {|f|
+        if prefix
+          f.puts realdest.sub(prefix, '')
+        else
+          f.puts realdest
+        end
+      }
+    end
+  end
+
+  def diff?(new_content, path)
+    return true unless File.exist?(path)
+    new_content != File.binread(path)
+  end
+
+  def command(str)
+    $stderr.puts str if verbose?
+    system str or raise RuntimeError, "'system #{str}' failed"
+  end
+
+  def ruby(str)
+    command config('rubyprog') + ' ' + str
+  end
+  
+  def make(task = '')
+    command config('makeprog') + ' ' + task
+  end
+
+  def extdir?(dir)
+    File.exist?(dir + '/MANIFEST')
+  end
+
+  def all_files_in(dirname)
+    Dir.open(dirname) {|d|
+      return d.select {|ent| File.file?("#{dirname}/#{ent}") }
+    }
+  end
+
+  REJECT_DIRS = %w(
+    CVS SCCS RCS CVS.adm .svn
+  )
+
+  def all_dirs_in(dirname)
+    Dir.open(dirname) {|d|
+      return d.select {|n| File.dir?("#{dirname}/#{n}") } - %w(. ..) - REJECT_DIRS
+    }
+  end
+
+end
+
+
+#
+# Main Installer
+#
+
+module HookUtils
+
+  def run_hook(name)
+    try_run_hook "#{curr_srcdir()}/#{name}" or
+    try_run_hook "#{curr_srcdir()}/#{name}.rb"
+  end
+
+  def try_run_hook(fname)
+    return false unless File.file?(fname)
+    begin
+      instance_eval File.read(fname), fname, 1
+    rescue
+      setup_rb_error "hook #{fname} failed:\n" + $!.message
+    end
+    true
+  end
+
+end
+
+
+module HookScriptAPI
+
+  def get_config(key)
+    @config[key]
+  end
+
+  alias config get_config
+
+  def set_config(key, val)
+    @config[key] = val
+  end
+
+  #
+  # srcdir/objdir (works only in the package directory)
+  #
+
+  #abstract srcdir_root
+  #abstract objdir_root
+  #abstract relpath
+
+  def curr_srcdir
+    "#{srcdir_root()}/#{relpath()}"
+  end
+
+  def curr_objdir
+    "#{objdir_root()}/#{relpath()}"
+  end
+
+  def srcfile(path)
+    "#{curr_srcdir()}/#{path}"
+  end
+
+  def srcexist?(path)
+    File.exist?(srcfile(path))
+  end
+
+  def srcdirectory?(path)
+    File.dir?(srcfile(path))
+  end
+  
+  def srcfile?(path)
+    File.file? srcfile(path)
+  end
+
+  def srcentries(path = '.')
+    Dir.open("#{curr_srcdir()}/#{path}") {|d|
+      return d.to_a - %w(. ..)
+    }
+  end
+
+  def srcfiles(path = '.')
+    srcentries(path).select {|fname|
+      File.file?(File.join(curr_srcdir(), path, fname))
+    }
+  end
+
+  def srcdirectories(path = '.')
+    srcentries(path).select {|fname|
+      File.dir?(File.join(curr_srcdir(), path, fname))
+    }
+  end
+
+end
+
+
+class ToplevelInstaller
+
+  Version   = '3.3.1'
+  Copyright = 'Copyright (c) 2000-2004 Minero Aoki'
+
+  TASKS = [
+    [ 'all',      'do config, setup, then install' ],
+    [ 'config',   'saves your configurations' ],
+    [ 'show',     'shows current configuration' ],
+    [ 'setup',    'compiles ruby extentions and others' ],
+    [ 'install',  'installs files' ],
+    [ 'clean',    "does `make clean' for each extention" ],
+    [ 'distclean',"does `make distclean' for each extention" ]
+  ]
+
+  def ToplevelInstaller.invoke
+    instance().invoke
+  end
+
+  @singleton = nil
+
+  def ToplevelInstaller.instance
+    @singleton ||= new(File.dirname($0))
+    @singleton
+  end
+
+  include MetaConfigAPI
+
+  def initialize(ardir_root)
+    @config = nil
+    @options = { 'verbose' => true }
+    @ardir = File.expand_path(ardir_root)
+  end
+
+  def inspect
+    "#<#{self.class} #{__id__()}>"
+  end
+
+  def invoke
+    run_metaconfigs
+    case task = parsearg_global()
+    when nil, 'all'
+      @config = load_config('config')
+      parsearg_config
+      init_installers
+      exec_config
+      exec_setup
+      exec_install
+    else
+      @config = load_config(task)
+      __send__ "parsearg_#{task}"
+      init_installers
+      __send__ "exec_#{task}"
+    end
+  end
+  
+  def run_metaconfigs
+    eval_file_ifexist "#{@ardir}/metaconfig"
+  end
+
+  def load_config(task)
+    case task
+    when 'config'
+      ConfigTable.new
+    when 'clean', 'distclean'
+      if File.exist?(ConfigTable.savefile)
+      then ConfigTable.load
+      else ConfigTable.new
+      end
+    else
+      ConfigTable.load
+    end
+  end
+
+  def init_installers
+    @installer = Installer.new(@config, @options, @ardir, File.expand_path('.'))
+  end
+
+  #
+  # Hook Script API bases
+  #
+
+  def srcdir_root
+    @ardir
+  end
+
+  def objdir_root
+    '.'
+  end
+
+  def relpath
+    '.'
+  end
+
+  #
+  # Option Parsing
+  #
+
+  def parsearg_global
+    valid_task = /\A(?:#{TASKS.map {|task,desc| task }.join '|'})\z/
+
+    while arg = ARGV.shift
+      case arg
+      when /\A\w+\z/
+        setup_rb_error "invalid task: #{arg}" unless valid_task =~ arg
+        return arg
+
+      when '-q', '--quiet'
+        @options['verbose'] = false
+
+      when       '--verbose'
+        @options['verbose'] = true
+
+      when '-h', '--help'
+        print_usage $stdout
+        exit 0
+
+      when '-v', '--version'
+        puts "#{File.basename($0)} version #{Version}"
+        exit 0
+      
+      when '--copyright'
+        puts Copyright
+        exit 0
+
+      else
+        setup_rb_error "unknown global option '#{arg}'"
+      end
+    end
+
+    nil
+  end
+
+
+  def parsearg_no_options
+    unless ARGV.empty?
+      setup_rb_error "#{task}:  unknown options: #{ARGV.join ' '}"
+    end
+  end
+
+  alias parsearg_show       parsearg_no_options
+  alias parsearg_setup      parsearg_no_options
+  alias parsearg_clean      parsearg_no_options
+  alias parsearg_distclean  parsearg_no_options
+
+  def parsearg_config
+    re = /\A--(#{ConfigTable.map {|i| i.name }.join('|')})(?:=(.*))?\z/
+    @options['config-opt'] = []
+
+    while i = ARGV.shift
+      if /\A--?\z/ =~ i
+        @options['config-opt'] = ARGV.dup
+        break
+      end
+      m = re.match(i)  or setup_rb_error "config: unknown option #{i}"
+      name, value = *m.to_a[1,2]
+      @config[name] = value
+    end
+  end
+
+  def parsearg_install
+    @options['no-harm'] = false
+    @options['install-prefix'] = ''
+    while a = ARGV.shift
+      case a
+      when /\A--no-harm\z/
+        @options['no-harm'] = true
+      when /\A--prefix=(.*)\z/
+        path = $1
+        path = File.expand_path(path) unless path[0,1] == '/'
+        @options['install-prefix'] = path
+      else
+        setup_rb_error "install: unknown option #{a}"
+      end
+    end
+  end
+
+  def print_usage(out)
+    out.puts 'Typical Installation Procedure:'
+    out.puts "  $ ruby #{File.basename $0} config"
+    out.puts "  $ ruby #{File.basename $0} setup"
+    out.puts "  # ruby #{File.basename $0} install (may require root privilege)"
+    out.puts
+    out.puts 'Detailed Usage:'
+    out.puts "  ruby #{File.basename $0} <global option>"
+    out.puts "  ruby #{File.basename $0} [<global options>] <task> [<task options>]"
+
+    fmt = "  %-24s %s\n"
+    out.puts
+    out.puts 'Global options:'
+    out.printf fmt, '-q,--quiet',   'suppress message outputs'
+    out.printf fmt, '   --verbose', 'output messages verbosely'
+    out.printf fmt, '-h,--help',    'print this message'
+    out.printf fmt, '-v,--version', 'print version and quit'
+    out.printf fmt, '   --copyright',  'print copyright and quit'
+    out.puts
+    out.puts 'Tasks:'
+    TASKS.each do |name, desc|
+      out.printf fmt, name, desc
+    end
+
+    fmt = "  %-24s %s [%s]\n"
+    out.puts
+    out.puts 'Options for CONFIG or ALL:'
+    ConfigTable.each do |item|
+      out.printf fmt, item.help_opt, item.description, item.help_default
+    end
+    out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's"
+    out.puts
+    out.puts 'Options for INSTALL:'
+    out.printf fmt, '--no-harm', 'only display what to do if given', 'off'
+    out.printf fmt, '--prefix=path',  'install path prefix', '$prefix'
+    out.puts
+  end
+
+  #
+  # Task Handlers
+  #
+
+  def exec_config
+    @installer.exec_config
+    @config.save   # must be final
+  end
+
+  def exec_setup
+    @installer.exec_setup
+  end
+
+  def exec_install
+    @installer.exec_install
+  end
+
+  def exec_show
+    ConfigTable.each do |i|
+      printf "%-20s %s\n", i.name, i.value
+    end
+  end
+
+  def exec_clean
+    @installer.exec_clean
+  end
+
+  def exec_distclean
+    @installer.exec_distclean
+  end
+
+end
+
+
+class ToplevelInstallerMulti < ToplevelInstaller
+
+  include HookUtils
+  include HookScriptAPI
+  include FileOperations
+
+  def initialize(ardir)
+    super
+    @packages = all_dirs_in("#{@ardir}/packages")
+    raise 'no package exists' if @packages.empty?
+  end
+
+  def run_metaconfigs
+    eval_file_ifexist "#{@ardir}/metaconfig"
+    @packages.each do |name|
+      eval_file_ifexist "#{@ardir}/packages/#{name}/metaconfig"
+    end
+  end
+
+  def init_installers
+    @installers = {}
+    @packages.each do |pack|
+      @installers[pack] = Installer.new(@config, @options,
+                                       "#{@ardir}/packages/#{pack}",
+                                       "packages/#{pack}")
+    end
+
+    with    = extract_selection(config('with'))
+    without = extract_selection(config('without'))
+    @selected = @installers.keys.select {|name|
+                  (with.empty? or with.include?(name)) \
+                      and not without.include?(name)
+                }
+  end
+
+  def extract_selection(list)
+    a = list.split(/,/)
+    a.each do |name|
+      setup_rb_error "no such package: #{name}"  unless @installers.key?(name)
+    end
+    a
+  end
+
+  def print_usage(f)
+    super
+    f.puts 'Inluded packages:'
+    f.puts '  ' + @packages.sort.join(' ')
+    f.puts
+  end
+
+  #
+  # multi-package metaconfig API
+  #
+
+  attr_reader :packages
+
+  def declare_packages(list)
+    raise 'package list is empty' if list.empty?
+    list.each do |name|
+      raise "directory packages/#{name} does not exist"\
+              unless File.dir?("#{@ardir}/packages/#{name}")
+    end
+    @packages = list
+  end
+
+  #
+  # Task Handlers
+  #
+
+  def exec_config
+    run_hook 'pre-config'
+    each_selected_installers {|inst| inst.exec_config }
+    run_hook 'post-config'
+    @config.save   # must be final
+  end
+
+  def exec_setup
+    run_hook 'pre-setup'
+    each_selected_installers {|inst| inst.exec_setup }
+    run_hook 'post-setup'
+  end
+
+  def exec_install
+    run_hook 'pre-install'
+    each_selected_installers {|inst| inst.exec_install }
+    run_hook 'post-install'
+  end
+
+  def exec_clean
+    rm_f ConfigTable.savefile
+    run_hook 'pre-clean'
+    each_selected_installers {|inst| inst.exec_clean }
+    run_hook 'post-clean'
+  end
+
+  def exec_distclean
+    rm_f ConfigTable.savefile
+    run_hook 'pre-distclean'
+    each_selected_installers {|inst| inst.exec_distclean }
+    run_hook 'post-distclean'
+  end
+
+  #
+  # lib
+  #
+
+  def each_selected_installers
+    Dir.mkdir 'packages' unless File.dir?('packages')
+    @selected.each do |pack|
+      $stderr.puts "Processing the package `#{pack}' ..." if @options['verbose']
+      Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}")
+      Dir.chdir "packages/#{pack}"
+      yield @installers[pack]
+      Dir.chdir '../..'
+    end
+  end
+
+  def verbose?
+    @options['verbose']
+  end
+
+  def no_harm?
+    @options['no-harm']
+  end
+
+end
+
+
+class Installer
+
+  FILETYPES = %w( bin lib ext data )
+
+  include HookScriptAPI
+  include HookUtils
+  include FileOperations
+
+  def initialize(config, opt, srcroot, objroot)
+    @config = config
+    @options = opt
+    @srcdir = File.expand_path(srcroot)
+    @objdir = File.expand_path(objroot)
+    @currdir = '.'
+  end
+
+  def inspect
+    "#<#{self.class} #{File.basename(@srcdir)}>"
+  end
+
+  #
+  # Hook Script API base methods
+  #
+
+  def srcdir_root
+    @srcdir
+  end
+
+  def objdir_root
+    @objdir
+  end
+
+  def relpath
+    @currdir
+  end
+
+  #
+  # configs/options
+  #
+
+  def no_harm?
+    @options['no-harm']
+  end
+
+  def verbose?
+    @options['verbose']
+  end
+
+  def verbose_off
+    begin
+      save, @options['verbose'] = @options['verbose'], false
+      yield
+    ensure
+      @options['verbose'] = save
+    end
+  end
+
+  #
+  # TASK config
+  #
+
+  def exec_config
+    exec_task_traverse 'config'
+  end
+
+  def config_dir_bin(rel)
+  end
+
+  def config_dir_lib(rel)
+  end
+
+  def config_dir_ext(rel)
+    extconf if extdir?(curr_srcdir())
+  end
+
+  def extconf
+    opt = @options['config-opt'].join(' ')
+    command "#{config('rubyprog')} #{curr_srcdir()}/extconf.rb #{opt}"
+  end
+
+  def config_dir_data(rel)
+  end
+
+  #
+  # TASK setup
+  #
+
+  def exec_setup
+    exec_task_traverse 'setup'
+  end
+
+  def setup_dir_bin(rel)
+    all_files_in(curr_srcdir()).each do |fname|
+      adjust_shebang "#{curr_srcdir()}/#{fname}"
+    end
+  end
+
+  def adjust_shebang(path)
+    return if no_harm?
+    tmpfile = File.basename(path) + '.tmp'
+    begin
+      File.open(path, 'rb') {|r|
+        first = r.gets
+        return unless File.basename(config('rubypath')) == 'ruby'
+        return unless File.basename(first.sub(/\A\#!/, '').split[0]) == 'ruby'
+        $stderr.puts "adjusting shebang: #{File.basename(path)}" if verbose?
+        File.open(tmpfile, 'wb') {|w|
+          w.print first.sub(/\A\#!\s*\S+/, '#! ' + config('rubypath'))
+          w.write r.read
+        }
+        move_file tmpfile, File.basename(path)
+      }
+    ensure
+      File.unlink tmpfile if File.exist?(tmpfile)
+    end
+  end
+
+  def setup_dir_lib(rel)
+  end
+
+  def setup_dir_ext(rel)
+    make if extdir?(curr_srcdir())
+  end
+
+  def setup_dir_data(rel)
+  end
+
+  #
+  # TASK install
+  #
+
+  def exec_install
+    rm_f 'InstalledFiles'
+    exec_task_traverse 'install'
+  end
+
+  def install_dir_bin(rel)
+    install_files collect_filenames_auto(), "#{config('bindir')}/#{rel}", 0755
+  end
+
+  def install_dir_lib(rel)
+    install_files ruby_scripts(), "#{config('rbdir')}/#{rel}", 0644
+  end
+
+  def install_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    install_files ruby_extentions('.'),
+                  "#{config('sodir')}/#{File.dirname(rel)}",
+                  0644  # This was 0555, why?! - Paul <paulvt at debian.org>
+  end
+
+  def install_dir_data(rel)
+    install_files collect_filenames_auto(), "#{config('datadir')}/#{rel}", 0644
+  end
+
+  def install_files(list, dest, mode)
+    mkdir_p dest, @options['install-prefix']
+    list.each do |fname|
+      install fname, dest, mode, @options['install-prefix']
+    end
+  end
+
+  def ruby_scripts
+    collect_filenames_auto().select {|n| /\.rb\z/ =~ n }
+  end
+  
+  # picked up many entries from cvs-1.11.1/src/ignore.c
+  reject_patterns = %w( 
+    core RCSLOG tags TAGS .make.state
+    .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb
+    *~ *.old *.bak *.BAK *.orig *.rej _$* *$
+
+    *.org *.in .*
+  )
+  mapping = {
+    '.' => '\.',
+    '$' => '\$',
+    '#' => '\#',
+    '*' => '.*'
+  }
+  REJECT_PATTERNS = Regexp.new('\A(?:' +
+                               reject_patterns.map {|pat|
+                                 pat.gsub(/[\.\$\#\*]/) {|ch| mapping[ch] }
+                               }.join('|') +
+                               ')\z')
+
+  def collect_filenames_auto
+    mapdir((existfiles() - hookfiles()).reject {|fname|
+             REJECT_PATTERNS =~ fname
+           })
+  end
+
+  def existfiles
+    all_files_in(curr_srcdir()) | all_files_in('.')
+  end
+
+  def hookfiles
+    %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt|
+      %w( config setup install clean ).map {|t| sprintf(fmt, t) }
+    }.flatten
+  end
+
+  def mapdir(filelist)
+    filelist.map {|fname|
+      if File.exist?(fname)   # objdir
+        fname
+      else                    # srcdir
+        File.join(curr_srcdir(), fname)
+      end
+    }
+  end
+
+  def ruby_extentions(dir)
+    Dir.open(dir) {|d|
+      ents = d.select {|fname| /\.#{::Config::CONFIG['DLEXT']}\z/ =~ fname }
+      if ents.empty?
+        setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first"
+      end
+      return ents
+    }
+  end
+
+  #
+  # TASK clean
+  #
+
+  def exec_clean
+    exec_task_traverse 'clean'
+    rm_f ConfigTable.savefile
+    rm_f 'InstalledFiles'
+  end
+
+  def clean_dir_bin(rel)
+  end
+
+  def clean_dir_lib(rel)
+  end
+
+  def clean_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    make 'clean' if File.file?('Makefile')
+  end
+
+  def clean_dir_data(rel)
+  end
+
+  #
+  # TASK distclean
+  #
+
+  def exec_distclean
+    exec_task_traverse 'distclean'
+    rm_f ConfigTable.savefile
+    rm_f 'InstalledFiles'
+  end
+
+  def distclean_dir_bin(rel)
+  end
+
+  def distclean_dir_lib(rel)
+  end
+
+  def distclean_dir_ext(rel)
+    return unless extdir?(curr_srcdir())
+    make 'distclean' if File.file?('Makefile')
+  end
+
+  #
+  # lib
+  #
+
+  def exec_task_traverse(task)
+    run_hook "pre-#{task}"
+    FILETYPES.each do |type|
+      if config('without-ext') == 'yes' and type == 'ext'
+        $stderr.puts 'skipping ext/* by user option' if verbose?
+        next
+      end
+      traverse task, type, "#{task}_dir_#{type}"
+    end
+    run_hook "post-#{task}"
+  end
+
+  def traverse(task, rel, mid)
+    dive_into(rel) {
+      run_hook "pre-#{task}"
+      __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '')
+      all_dirs_in(curr_srcdir()).each do |d|
+        traverse task, "#{rel}/#{d}", mid
+      end
+      run_hook "post-#{task}"
+    }
+  end
+
+  def dive_into(rel)
+    return unless File.dir?("#{@srcdir}/#{rel}")
+
+    dir = File.basename(rel)
+    Dir.mkdir dir unless File.dir?(dir)
+    prevdir = Dir.pwd
+    Dir.chdir dir
+    $stderr.puts '---> ' + rel if verbose?
+    @currdir = rel
+    yield
+    Dir.chdir prevdir
+    $stderr.puts '<--- ' + rel if verbose?
+    @currdir = File.dirname(rel)
+  end
+
+end
+
+
+if $0 == __FILE__
+  begin
+    if multipackage_install?
+      ToplevelInstallerMulti.invoke
+    else
+      ToplevelInstaller.invoke
+    end
+  rescue SetupError
+    raise if $DEBUG
+    $stderr.puts $!.message
+    $stderr.puts "Try 'ruby #{$0} --help' for detailed usage."
+    exit 1
+  end
+end

Added: packages/libjson-ruby/trunk/tests/runner.rb
===================================================================
--- packages/libjson-ruby/trunk/tests/runner.rb	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/tests/runner.rb	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,18 @@
+#!/usr/bin/env ruby
+
+require 'test/unit/ui/console/testrunner'
+require 'test/unit/testsuite'
+$:.unshift File.expand_path(File.dirname($0))
+$:.unshift 'lib'
+$:.unshift '../lib'
+#require 'coverage'
+require 'test_json'
+
+class TS_AllTests
+  def self.suite
+    suite = Test::Unit::TestSuite.new
+    suite << TC_JSON.suite
+  end
+end
+Test::Unit::UI::Console::TestRunner.run(TS_AllTests)
+  # vim: set et sw=2 ts=2:

Added: packages/libjson-ruby/trunk/tests/test_json.rb
===================================================================
--- packages/libjson-ruby/trunk/tests/test_json.rb	2005-12-03 22:58:36 UTC (rev 165)
+++ packages/libjson-ruby/trunk/tests/test_json.rb	2005-12-03 23:25:52 UTC (rev 166)
@@ -0,0 +1,209 @@
+#!/usr/bin/env ruby
+
+require 'test/unit'
+require 'json'
+
+class TC_JSON < Test::Unit::TestCase
+  include JSON
+
+  class A
+    def initialize(a)
+      @a = a
+    end
+
+    attr_reader :a
+
+    def ==(other)
+      a == other.a
+    end
+    
+    def self.json_create(object)
+      new(*object['args'])
+    end
+
+    def to_json(*args)
+      {
+        'json_class'  => self.class,
+        'args'        => [ @a ],
+      }.to_json(*args)
+    end
+  end
+
+  def setup
+    $KCODE = 'UTF8'
+    @ary = [1, "foo", 3.14, 4711.0, 2.718, nil, [1,-2,3], false, true]
+    @ary_to_parse = ["1", '"foo"', "3.14", "4711.0", "2.718", "null",
+      "[1,-2,3]", "false", "true"]
+    @hash = {
+      'a' => 2,
+      'b' => 3.141,
+      'c' => 'c',
+      'd' => [ 1, "b", 3.14 ],
+      'e' => { 'foo' => 'bar' },
+      'g' => "\"\0\037",
+      'h' => 1000.0,
+      'i' => 0.001
+    }
+    @json = '{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},' +
+      '"g":"\\"\\u0000\\u001f","h":1.0E3,"i":1.0E-3}'
+    @json2 = '{"a":2,"b":3.141,"c":"c","d":[1,"b",3.14],"e":{"foo":"bar"},' +
+      '"g":"\\"\\u0000\\u001f","h":1000.0,"i":0.001}'
+  end
+
+  def test_parse_value
+    assert_equal("", parse('""'))
+    assert_equal("\\", parse('"\\\\"'))
+    assert_equal('"', parse('"\""'))
+    assert_equal('\\"\\', parse('"\\\\\\"\\\\"'))
+    assert_equal("\\a\"\b\f\n\r\t\0\037",
+      parse('"\\a\"\b\f\n\r\t\u0000\u001f"'))
+    for i in 0 ... @ary.size
+      assert_equal(@ary[i], parse(@ary_to_parse[i]))
+    end
+  end
+
+  def test_parse_array
+    assert_equal([], parse('[]'))
+    assert_equal([], parse('  [  ]  '))
+    assert_equal([1], parse('[1]'))
+    assert_equal([1], parse('  [ 1  ]  '))
+    assert_equal(@ary,
+      parse('[1,"foo",3.14,47.11e+2,2718.E-3,null,[1,-2,3],false,true]'))
+    assert_equal(@ary, parse(%Q{   [   1 , "foo"  ,  3.14 \t ,  47.11e+2 
+      , 2718.E-3 ,\n null , [1, -2, 3 ], false , true\n ]  }))
+  end
+
+  def test_parse_object
+    assert_equal({}, parse('{}'))
+    assert_equal({}, parse('  {  }  '))
+    assert_equal({'foo'=>'bar'}, parse('{"foo":"bar"}'))
+    assert_equal({'foo'=>'bar'}, parse('    { "foo"  :   "bar"   }   '))
+  end
+
+  def test_unparse
+    json = unparse(@hash)
+    assert_equal(@json2, json)
+    parsed_json = parse(json)
+    assert_equal(@hash, parsed_json)
+    json = unparse({1=>2})
+    assert_equal('{"1":2}', json)
+    parsed_json = parse(json)
+    assert_equal({"1"=>2}, parsed_json)
+  end
+
+  def test_parser_reset
+    parser = Parser.new(@json)
+    assert_equal(@hash, parser.parse)
+    assert_equal(@hash, parser.parse)
+  end
+
+  def test_unicode
+    assert_equal '""', ''.to_json
+    assert_equal '"\\b"', "\b".to_json
+    assert_equal '"\u0001"', 0x1.chr.to_json
+    assert_equal '"\u001f"', 0x1f.chr.to_json
+    assert_equal '" "', ' '.to_json
+    assert_equal "\"#{0x7f.chr}\"", 0x7f.chr.to_json
+    utf8 = '© ≠ €!'
+    json = '"\u00a9 \u2260 \u20ac!"'
+    assert_equal json, utf8.to_json
+    assert_equal utf8, parse(json)
+    utf8 = "\343\201\202\343\201\204\343\201\206\343\201\210\343\201\212"
+    json = '"\u3042\u3044\u3046\u3048\u304a"'
+    assert_equal json, utf8.to_json
+    assert_equal utf8, parse(json)
+    utf8 = 'საქართველო'
+    json = '"\u10e1\u10d0\u10e5\u10d0\u10e0\u10d7\u10d5\u10d4\u10da\u10dd"'
+    assert_equal json, utf8.to_json
+    assert_equal utf8, parse(json)
+  end
+
+  def test_comments
+    json = <<EOT
+{
+  "key1":"value1", // eol comment
+  "key2":"value2"  /* multi line
+                    *  comment */,
+  "key3":"value3"  /* multi line
+                    // nested eol comment
+                    *  comment */
+}
+EOT
+    assert_equal(
+      { "key1" => "value1", "key2" => "value2", "key3" => "value3" },
+      parse(json))
+    json = <<EOT
+{
+  "key1":"value1"  /* multi line
+                    // nested eol comment
+                    /* illegal nested multi line comment */
+                    *  comment */
+}
+EOT
+    assert_raises(ParserError) { parse(json) }
+    json = <<EOT
+{
+  "key1":"value1"  /* multi line
+                   // nested eol comment
+                   closed multi comment */
+                   and again, throw an Error */
+}
+EOT
+    assert_raises(ParserError) { parse(json) }
+    json = <<EOT
+{
+  "key1":"value1"  /*/*/
+}
+EOT
+    assert_equal({ "key1" => "value1" }, parse(json))
+  end
+
+  def test_extended_json
+    a = A.new(666)
+    json = a.to_json
+    a_again = JSON.parse(json)
+    assert_kind_of a.class, a_again
+    assert_equal a, a_again
+  end
+
+  def test_raw_strings
+    raw = ''
+    raw_array = []
+    for i in 0..255
+      raw << i
+      raw_array << i
+    end
+    json = raw.to_json_raw
+    json_raw_object = raw.to_json_raw_object
+    hash = { 'json_class' => 'String', 'raw'=> raw_array }
+    assert_equal hash, json_raw_object
+    json_raw = <<EOT.chomp
+{\"json_class\":\"String\",\"raw\":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255]}
+EOT
+# "
+    assert_equal json_raw, json
+    raw_again = JSON.parse(json)
+    assert_equal raw, raw_again
+  end
+
+  def test_utf8_mode
+    $KCODE = 'NONE'
+    utf8 = "© ≠ €! - \001"
+    json = "\"© ≠ €! - \\u0001\""
+    assert_equal json, utf8.to_json
+    assert_equal utf8, parse(json)
+    assert JSON.support_unicode?
+    $KCODE = 'UTF8'
+    utf8 = '© ≠ €!'
+    json = '"\u00a9 \u2260 \u20ac!"'
+    assert_equal json, utf8.to_json
+    assert_equal utf8, parse(json)
+    JSON.support_unicode = false
+    assert !JSON.support_unicode?
+    utf8 = "© ≠ €! - \001"
+    json = "\"© ≠ €! - \\u0001\""
+    assert_equal json, utf8.to_json
+    assert_equal utf8, parse(json)
+  end
+end
+  # vim: set et sw=2 ts=2:


Property changes on: packages/libjson-ruby/trunk/tests/test_json.rb
___________________________________________________________________
Name: svn:executable
   + 




More information about the pkg-ruby-extras-maintainers mailing list