changeset 0:add35537fdbb tip

Initial import
author irh <ian.r.hobson@gmail.com>
date Thu, 25 Aug 2011 11:05:55 +0100
parents
children
files .hgignore CMakeLists.txt COPYING README gpsynth.xcodeproj/project.pbxproj gpsynth.xcodeproj/project.xcworkspace/contents.xcworkspacedata gpsynth.xcodeproj/xcshareddata/xcschemes/gpsynth.xcscheme grammar/sc.json src/CMakeLists.txt src/boost_ex.hpp src/converter.hpp src/evaluator.hpp src/feature_extractor.cpp src/feature_extractor.hpp src/file_comparer.cpp src/file_comparer.hpp src/grammar.hpp src/graph_helpers.hpp src/logger.cpp src/logger.hpp src/main.cpp src/mfcc_analyzer.cpp src/mfcc_analyzer.hpp src/population.cpp src/population.hpp src/precompiled_header.hpp src/program_options.cpp src/program_options.hpp src/range.hpp src/sc_converter.cpp src/sc_converter.hpp src/sc_default_grammar.cpp src/sc_default_grammar.hpp src/sc_evaluator.cpp src/sc_evaluator.hpp src/sc_grammar.cpp src/sc_grammar.hpp src/spectrum_analyzer.hpp src/statistics.hpp src/std_ex.hpp src/synth_graph.hpp src/window_makers.hpp third_party/boost/process.hpp third_party/boost/process/all.hpp third_party/boost/process/child.hpp third_party/boost/process/config.hpp third_party/boost/process/context.hpp third_party/boost/process/detail/basic_status.hpp third_party/boost/process/detail/basic_status_service.hpp third_party/boost/process/detail/posix_helpers.hpp third_party/boost/process/detail/status_impl.hpp third_party/boost/process/detail/systembuf.hpp third_party/boost/process/detail/windows_helpers.hpp third_party/boost/process/environment.hpp third_party/boost/process/handle.hpp third_party/boost/process/operations.hpp third_party/boost/process/pid_type.hpp third_party/boost/process/pipe.hpp third_party/boost/process/pistream.hpp third_party/boost/process/postream.hpp third_party/boost/process/process.hpp third_party/boost/process/self.hpp third_party/boost/process/status.hpp third_party/boost/process/stream_behavior.hpp third_party/boost/process/stream_ends.hpp third_party/boost/process/stream_id.hpp third_party/boost/process/stream_type.hpp third_party/cmake_modules/FindFFTW.cmake third_party/cmake_modules/FindSndFile.cmake third_party/json/CMakeLists.txt third_party/json/LICENSE third_party/json/assertions.h third_party/json/autolink.h third_party/json/config.h third_party/json/features.h third_party/json/forwards.h third_party/json/json.h third_party/json/json_batchallocator.h third_party/json/json_internalarray.inl third_party/json/json_internalmap.inl third_party/json/json_reader.cpp third_party/json/json_tool.h third_party/json/json_value.cpp third_party/json/json_valueiterator.inl third_party/json/json_writer.cpp third_party/json/reader.h third_party/json/value.h third_party/json/writer.h
diffstat 88 files changed, 18147 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,8 @@
+syntax:glob
+
+.DS_Store
+build/
+*.swp
+gpsynth.xcodeproj/project.xcworkspace/xcuserdata
+gpsynth.xcodeproj/xcuserdata/
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CMakeLists.txt	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 2.8)
+
+PROJECT(gpsynth)
+
+set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/third_party/cmake_modules)
+
+set(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)
+
+include_directories(third_party)
+include_directories(src)
+
+add_subdirectory(third_party/json)
+add_subdirectory(src)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/COPYING	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,675 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  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.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  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.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     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
+state 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 3 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, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU 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 Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,75 @@
+--------------------------------------------------------------------------------
+GPSynth (c) 2011 Ian Hobson - ian.r.hobson@gmail.com
+--------------------------------------------------------------------------------
+
+GPSynth is a program that uses genetic programming techniques to artificially 
+evolve SuperCollider synthesizers towards the ability to emulate a target sound 
+file.
+
+GPSynth is open source software, released under a GPL license. 
+See the COPYING file for information on how this software can be used.
+
+
+--------------------------------------------------------------------------------
+Requirements
+--------------------------------------------------------------------------------
+
+GPSynth has been tested on OS X 10.6.8. It should compile on Linux but has not
+been tested yet. Support for Linux will be added soon.
+
+GPSynth requires SuperCollider to be installed on your system. If you don't have
+SuperCollider in /Applications/SuperCollider then you need to specify the path
+to its location with the --scpath option.
+
+
+--------------------------------------------------------------------------------
+Usage
+--------------------------------------------------------------------------------
+
+In its most simple form, gpsynth takes a single argument, --target:
+
+gpsynth --target test.wav
+
+GPSynth uses Libsndfile to load audio file data, for a list of supported formats
+see http://www.mega-nerd.com/libsndfile.
+
+A timestamped folder will be created in the current path, use the --workfolder
+option to change where the folder will be created. 
+
+See gpsynth --help for a full list of options.
+
+
+--------------------------------------------------------------------------------
+Build instructions
+--------------------------------------------------------------------------------
+
+Building GPSynth has been tested on Mac OS X 10.6.8 with LLVM 3.0 and GCC 4.2.
+
+You need the following libraries installed on your system to build GPSynth.
+Boost (at least v1.44, tested against v1.47) with libraries compiled with 
+multi-threading enabled.
+LibSndFile
+FFTW
+
+If these libraries are not on your system, an easy way to get them is with 
+Homebrew (http://mxcl.github.com/homebrew/). After installing homebrew the 
+following commands should get your system ready to compile GPSynth:
+
+brew install boost
+brew install libsndfile
+brew install fftw
+
+An XCode 4 project is included with GPSynth for convenience, however the best
+way to install GPSynth is by using the CMake build scripts. If you don't have 
+CMake on your system then it can be installed with Homebrew:
+brew install cmake
+
+cd in to the root of the gpsynth source directory (where this README file is),
+then perform the following commands:
+mkdir build
+cd build
+cmake ..
+sudo make install
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gpsynth.xcodeproj/project.pbxproj	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,411 @@
+// !$*UTF8*$!
+{
+	archiveVersion = 1;
+	classes = {
+	};
+	objectVersion = 46;
+	objects = {
+
+/* Begin PBXBuildFile section */
+		3C646D2513F4720B0058A207 /* feature_extractor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C646D0B13F4720B0058A207 /* feature_extractor.cpp */; };
+		3C646D2613F4720B0058A207 /* file_comparer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C646D0D13F4720B0058A207 /* file_comparer.cpp */; };
+		3C646D2713F4720B0058A207 /* logger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C646D1113F4720B0058A207 /* logger.cpp */; };
+		3C646D2813F4720B0058A207 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C646D1313F4720B0058A207 /* main.cpp */; };
+		3C646D2913F4720B0058A207 /* mfcc_analyzer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C646D1413F4720B0058A207 /* mfcc_analyzer.cpp */; };
+		3C646D2A13F4720B0058A207 /* population.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C646D1613F4720B0058A207 /* population.cpp */; };
+		3C646D2B13F4720B0058A207 /* sc_converter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C646D1A13F4720B0058A207 /* sc_converter.cpp */; };
+		3C646D2C13F4720B0058A207 /* sc_evaluator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C646D1C13F4720B0058A207 /* sc_evaluator.cpp */; };
+		3C646D2D13F4720B0058A207 /* sc_grammar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C646D1E13F4720B0058A207 /* sc_grammar.cpp */; };
+		3C646DA813F701AD0058A207 /* program_options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C646DA713F701AD0058A207 /* program_options.cpp */; };
+		3CC27D2E13B8247000456569 /* libboost_thread-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CC27D2D13B8247000456569 /* libboost_thread-mt.dylib */; };
+		3CC5E42813C0099B0000CF05 /* json_reader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3CC5E41F13C0099B0000CF05 /* json_reader.cpp */; };
+		3CC5E42913C0099B0000CF05 /* json_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3CC5E42113C0099B0000CF05 /* json_value.cpp */; };
+		3CC5E42A13C0099B0000CF05 /* json_writer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3CC5E42313C0099B0000CF05 /* json_writer.cpp */; };
+		3CD21C6913D4973000E33C4F /* libboost_system-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CD21C6813D4973000E33C4F /* libboost_system-mt.dylib */; };
+		3CD21C6B13D4973A00E33C4F /* libboost_filesystem-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CD21C6A13D4973A00E33C4F /* libboost_filesystem-mt.dylib */; };
+		3CD21C6E13D4F10000E33C4F /* libboost_date_time-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CD21C6D13D4F10000E33C4F /* libboost_date_time-mt.dylib */; };
+		3CD21C7013D506F100E33C4F /* libsndfile.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CD21C6F13D506F100E33C4F /* libsndfile.dylib */; };
+		3CD21C7213D51F9000E33C4F /* libfftw3.3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CD21C7113D51F9000E33C4F /* libfftw3.3.dylib */; };
+		3CDEC1E613F2082A0075D229 /* libboost_program_options-mt.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 3CDEC1E513F2082A0075D229 /* libboost_program_options-mt.dylib */; };
+		3CF213E71405FEB20080579B /* sc_default_grammar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3CF213E61405FEB20080579B /* sc_default_grammar.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+		3CC27D1D13B7E6EC00456569 /* CopyFiles */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = /usr/share/man/man1/;
+			dstSubfolderSpec = 0;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 1;
+		};
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+		3C646D0713F4720B0058A207 /* boost_ex.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = boost_ex.hpp; sourceTree = "<group>"; };
+		3C646D0813F4720B0058A207 /* converter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = converter.hpp; sourceTree = "<group>"; };
+		3C646D0A13F4720B0058A207 /* evaluator.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = evaluator.hpp; sourceTree = "<group>"; };
+		3C646D0B13F4720B0058A207 /* feature_extractor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = feature_extractor.cpp; sourceTree = "<group>"; };
+		3C646D0C13F4720B0058A207 /* feature_extractor.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = feature_extractor.hpp; sourceTree = "<group>"; };
+		3C646D0D13F4720B0058A207 /* file_comparer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = file_comparer.cpp; sourceTree = "<group>"; };
+		3C646D0E13F4720B0058A207 /* file_comparer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = file_comparer.hpp; sourceTree = "<group>"; };
+		3C646D0F13F4720B0058A207 /* grammar.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = grammar.hpp; sourceTree = "<group>"; };
+		3C646D1013F4720B0058A207 /* graph_helpers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = graph_helpers.hpp; sourceTree = "<group>"; };
+		3C646D1113F4720B0058A207 /* logger.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = logger.cpp; sourceTree = "<group>"; };
+		3C646D1213F4720B0058A207 /* logger.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = logger.hpp; sourceTree = "<group>"; };
+		3C646D1313F4720B0058A207 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
+		3C646D1413F4720B0058A207 /* mfcc_analyzer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mfcc_analyzer.cpp; sourceTree = "<group>"; };
+		3C646D1513F4720B0058A207 /* mfcc_analyzer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = mfcc_analyzer.hpp; sourceTree = "<group>"; };
+		3C646D1613F4720B0058A207 /* population.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = population.cpp; sourceTree = "<group>"; };
+		3C646D1713F4720B0058A207 /* population.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = population.hpp; sourceTree = "<group>"; };
+		3C646D1813F4720B0058A207 /* precompiled_header.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = precompiled_header.hpp; sourceTree = "<group>"; };
+		3C646D1913F4720B0058A207 /* range.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = range.hpp; sourceTree = "<group>"; };
+		3C646D1A13F4720B0058A207 /* sc_converter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sc_converter.cpp; sourceTree = "<group>"; };
+		3C646D1B13F4720B0058A207 /* sc_converter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = sc_converter.hpp; sourceTree = "<group>"; };
+		3C646D1C13F4720B0058A207 /* sc_evaluator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sc_evaluator.cpp; sourceTree = "<group>"; };
+		3C646D1D13F4720B0058A207 /* sc_evaluator.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = sc_evaluator.hpp; sourceTree = "<group>"; };
+		3C646D1E13F4720B0058A207 /* sc_grammar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sc_grammar.cpp; sourceTree = "<group>"; };
+		3C646D1F13F4720B0058A207 /* sc_grammar.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = sc_grammar.hpp; sourceTree = "<group>"; };
+		3C646D2013F4720B0058A207 /* spectrum_analyzer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = spectrum_analyzer.hpp; sourceTree = "<group>"; };
+		3C646D2113F4720B0058A207 /* statistics.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = statistics.hpp; sourceTree = "<group>"; };
+		3C646D2213F4720B0058A207 /* std_ex.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = std_ex.hpp; sourceTree = "<group>"; };
+		3C646D2313F4720B0058A207 /* synth_graph.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = synth_graph.hpp; sourceTree = "<group>"; };
+		3C646D2413F4720B0058A207 /* window_makers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = window_makers.hpp; sourceTree = "<group>"; };
+		3C646DA713F701AD0058A207 /* program_options.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = program_options.cpp; sourceTree = "<group>"; };
+		3C646DAA13F701C60058A207 /* program_options.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = program_options.hpp; sourceTree = "<group>"; };
+		3CC27D1F13B7E6EC00456569 /* gpsynth */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = gpsynth; sourceTree = BUILT_PRODUCTS_DIR; };
+		3CC27D2D13B8247000456569 /* libboost_thread-mt.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libboost_thread-mt.dylib"; path = "usr/local/lib/libboost_thread-mt.dylib"; sourceTree = SDKROOT; };
+		3CC5E41613C0099B0000CF05 /* assertions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = assertions.h; sourceTree = "<group>"; };
+		3CC5E41713C0099B0000CF05 /* autolink.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = autolink.h; sourceTree = "<group>"; };
+		3CC5E41813C0099B0000CF05 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = "<group>"; };
+		3CC5E41913C0099B0000CF05 /* features.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = features.h; sourceTree = "<group>"; };
+		3CC5E41A13C0099B0000CF05 /* forwards.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = forwards.h; sourceTree = "<group>"; };
+		3CC5E41B13C0099B0000CF05 /* json.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json.h; sourceTree = "<group>"; };
+		3CC5E41C13C0099B0000CF05 /* json_batchallocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_batchallocator.h; sourceTree = "<group>"; };
+		3CC5E41D13C0099B0000CF05 /* json_internalarray.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = json_internalarray.inl; sourceTree = "<group>"; };
+		3CC5E41E13C0099B0000CF05 /* json_internalmap.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = json_internalmap.inl; sourceTree = "<group>"; };
+		3CC5E41F13C0099B0000CF05 /* json_reader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = json_reader.cpp; sourceTree = "<group>"; };
+		3CC5E42013C0099B0000CF05 /* json_tool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = json_tool.h; sourceTree = "<group>"; };
+		3CC5E42113C0099B0000CF05 /* json_value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = json_value.cpp; sourceTree = "<group>"; };
+		3CC5E42213C0099B0000CF05 /* json_valueiterator.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = json_valueiterator.inl; sourceTree = "<group>"; };
+		3CC5E42313C0099B0000CF05 /* json_writer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = json_writer.cpp; sourceTree = "<group>"; };
+		3CC5E42413C0099B0000CF05 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE; sourceTree = "<group>"; };
+		3CC5E42513C0099B0000CF05 /* reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = reader.h; sourceTree = "<group>"; };
+		3CC5E42613C0099B0000CF05 /* value.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = value.h; sourceTree = "<group>"; };
+		3CC5E42713C0099B0000CF05 /* writer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = writer.h; sourceTree = "<group>"; };
+		3CD21C6813D4973000E33C4F /* libboost_system-mt.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libboost_system-mt.dylib"; path = "usr/local/lib/libboost_system-mt.dylib"; sourceTree = SDKROOT; };
+		3CD21C6A13D4973A00E33C4F /* libboost_filesystem-mt.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libboost_filesystem-mt.dylib"; path = "usr/local/lib/libboost_filesystem-mt.dylib"; sourceTree = SDKROOT; };
+		3CD21C6D13D4F10000E33C4F /* libboost_date_time-mt.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libboost_date_time-mt.dylib"; path = "usr/local/lib/libboost_date_time-mt.dylib"; sourceTree = SDKROOT; };
+		3CD21C6F13D506F100E33C4F /* libsndfile.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsndfile.dylib; path = usr/local/lib/libsndfile.dylib; sourceTree = SDKROOT; };
+		3CD21C7113D51F9000E33C4F /* libfftw3.3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libfftw3.3.dylib; path = ../../../../usr/local/Cellar/fftw/3.2.2/lib/libfftw3.3.dylib; sourceTree = "<group>"; };
+		3CDEC1E513F2082A0075D229 /* libboost_program_options-mt.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libboost_program_options-mt.dylib"; path = "usr/local/lib/libboost_program_options-mt.dylib"; sourceTree = SDKROOT; };
+		3CF213E41405FE460080579B /* sc_default_grammar.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = sc_default_grammar.hpp; sourceTree = "<group>"; };
+		3CF213E61405FEB20080579B /* sc_default_grammar.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sc_default_grammar.cpp; sourceTree = "<group>"; };
+		3CF213E8140618AA0080579B /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+		3CC27D1C13B7E6EC00456569 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				3CD21C7213D51F9000E33C4F /* libfftw3.3.dylib in Frameworks */,
+				3CD21C7013D506F100E33C4F /* libsndfile.dylib in Frameworks */,
+				3CD21C6E13D4F10000E33C4F /* libboost_date_time-mt.dylib in Frameworks */,
+				3CD21C6B13D4973A00E33C4F /* libboost_filesystem-mt.dylib in Frameworks */,
+				3CDEC1E613F2082A0075D229 /* libboost_program_options-mt.dylib in Frameworks */,
+				3CD21C6913D4973000E33C4F /* libboost_system-mt.dylib in Frameworks */,
+				3CC27D2E13B8247000456569 /* libboost_thread-mt.dylib in Frameworks */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+		3C646D0613F4720B0058A207 /* src */ = {
+			isa = PBXGroup;
+			children = (
+				3CF213E8140618AA0080579B /* CMakeLists.txt */,
+				3C646D0713F4720B0058A207 /* boost_ex.hpp */,
+				3C646D0813F4720B0058A207 /* converter.hpp */,
+				3C646D0A13F4720B0058A207 /* evaluator.hpp */,
+				3C646D0B13F4720B0058A207 /* feature_extractor.cpp */,
+				3C646D0C13F4720B0058A207 /* feature_extractor.hpp */,
+				3C646D0D13F4720B0058A207 /* file_comparer.cpp */,
+				3C646D0E13F4720B0058A207 /* file_comparer.hpp */,
+				3C646D0F13F4720B0058A207 /* grammar.hpp */,
+				3C646D1013F4720B0058A207 /* graph_helpers.hpp */,
+				3C646D1113F4720B0058A207 /* logger.cpp */,
+				3C646D1213F4720B0058A207 /* logger.hpp */,
+				3C646D1313F4720B0058A207 /* main.cpp */,
+				3C646D1413F4720B0058A207 /* mfcc_analyzer.cpp */,
+				3C646D1513F4720B0058A207 /* mfcc_analyzer.hpp */,
+				3C646D1613F4720B0058A207 /* population.cpp */,
+				3C646D1713F4720B0058A207 /* population.hpp */,
+				3C646DA713F701AD0058A207 /* program_options.cpp */,
+				3C646DAA13F701C60058A207 /* program_options.hpp */,
+				3C646D1813F4720B0058A207 /* precompiled_header.hpp */,
+				3C646D1913F4720B0058A207 /* range.hpp */,
+				3C646D1A13F4720B0058A207 /* sc_converter.cpp */,
+				3C646D1B13F4720B0058A207 /* sc_converter.hpp */,
+				3CF213E41405FE460080579B /* sc_default_grammar.hpp */,
+				3CF213E61405FEB20080579B /* sc_default_grammar.cpp */,
+				3C646D1C13F4720B0058A207 /* sc_evaluator.cpp */,
+				3C646D1D13F4720B0058A207 /* sc_evaluator.hpp */,
+				3C646D1E13F4720B0058A207 /* sc_grammar.cpp */,
+				3C646D1F13F4720B0058A207 /* sc_grammar.hpp */,
+				3C646D2013F4720B0058A207 /* spectrum_analyzer.hpp */,
+				3C646D2113F4720B0058A207 /* statistics.hpp */,
+				3C646D2213F4720B0058A207 /* std_ex.hpp */,
+				3C646D2313F4720B0058A207 /* synth_graph.hpp */,
+				3C646D2413F4720B0058A207 /* window_makers.hpp */,
+			);
+			path = src;
+			sourceTree = "<group>";
+		};
+		3CC27D1413B7E6EC00456569 = {
+			isa = PBXGroup;
+			children = (
+				3C646D0613F4720B0058A207 /* src */,
+				3CC5E41513C0099B0000CF05 /* json */,
+				3CD21C7113D51F9000E33C4F /* libfftw3.3.dylib */,
+				3CD21C6F13D506F100E33C4F /* libsndfile.dylib */,
+				3CD21C6D13D4F10000E33C4F /* libboost_date_time-mt.dylib */,
+				3CD21C6A13D4973A00E33C4F /* libboost_filesystem-mt.dylib */,
+				3CDEC1E513F2082A0075D229 /* libboost_program_options-mt.dylib */,
+				3CD21C6813D4973000E33C4F /* libboost_system-mt.dylib */,
+				3CC27D2D13B8247000456569 /* libboost_thread-mt.dylib */,
+				3CC27D2013B7E6EC00456569 /* Products */,
+			);
+			sourceTree = "<group>";
+		};
+		3CC27D2013B7E6EC00456569 /* Products */ = {
+			isa = PBXGroup;
+			children = (
+				3CC27D1F13B7E6EC00456569 /* gpsynth */,
+			);
+			name = Products;
+			sourceTree = "<group>";
+		};
+		3CC5E41513C0099B0000CF05 /* json */ = {
+			isa = PBXGroup;
+			children = (
+				3CC5E41613C0099B0000CF05 /* assertions.h */,
+				3CC5E41713C0099B0000CF05 /* autolink.h */,
+				3CC5E41813C0099B0000CF05 /* config.h */,
+				3CC5E41913C0099B0000CF05 /* features.h */,
+				3CC5E41A13C0099B0000CF05 /* forwards.h */,
+				3CC5E41B13C0099B0000CF05 /* json.h */,
+				3CC5E41C13C0099B0000CF05 /* json_batchallocator.h */,
+				3CC5E41D13C0099B0000CF05 /* json_internalarray.inl */,
+				3CC5E41E13C0099B0000CF05 /* json_internalmap.inl */,
+				3CC5E41F13C0099B0000CF05 /* json_reader.cpp */,
+				3CC5E42013C0099B0000CF05 /* json_tool.h */,
+				3CC5E42113C0099B0000CF05 /* json_value.cpp */,
+				3CC5E42213C0099B0000CF05 /* json_valueiterator.inl */,
+				3CC5E42313C0099B0000CF05 /* json_writer.cpp */,
+				3CC5E42413C0099B0000CF05 /* LICENSE */,
+				3CC5E42513C0099B0000CF05 /* reader.h */,
+				3CC5E42613C0099B0000CF05 /* value.h */,
+				3CC5E42713C0099B0000CF05 /* writer.h */,
+			);
+			name = json;
+			path = third_party/json;
+			sourceTree = "<group>";
+		};
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+		3CC27D1E13B7E6EC00456569 /* gpsynth */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 3CC27D2813B7E6EC00456569 /* Build configuration list for PBXNativeTarget "gpsynth" */;
+			buildPhases = (
+				3CC27D1B13B7E6EC00456569 /* Sources */,
+				3CC27D1C13B7E6EC00456569 /* Frameworks */,
+				3CC27D1D13B7E6EC00456569 /* CopyFiles */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = gpsynth;
+			productName = gpsynth;
+			productReference = 3CC27D1F13B7E6EC00456569 /* gpsynth */;
+			productType = "com.apple.product-type.tool";
+		};
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+		3CC27D1613B7E6EC00456569 /* Project object */ = {
+			isa = PBXProject;
+			attributes = {
+				LastUpgradeCheck = 0420;
+			};
+			buildConfigurationList = 3CC27D1913B7E6EC00456569 /* Build configuration list for PBXProject "gpsynth" */;
+			compatibilityVersion = "Xcode 3.2";
+			developmentRegion = English;
+			hasScannedForEncodings = 0;
+			knownRegions = (
+				en,
+			);
+			mainGroup = 3CC27D1413B7E6EC00456569;
+			productRefGroup = 3CC27D2013B7E6EC00456569 /* Products */;
+			projectDirPath = "";
+			projectRoot = "";
+			targets = (
+				3CC27D1E13B7E6EC00456569 /* gpsynth */,
+			);
+		};
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+		3CC27D1B13B7E6EC00456569 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				3CC5E42813C0099B0000CF05 /* json_reader.cpp in Sources */,
+				3CC5E42913C0099B0000CF05 /* json_value.cpp in Sources */,
+				3CC5E42A13C0099B0000CF05 /* json_writer.cpp in Sources */,
+				3C646D2513F4720B0058A207 /* feature_extractor.cpp in Sources */,
+				3C646D2613F4720B0058A207 /* file_comparer.cpp in Sources */,
+				3C646D2713F4720B0058A207 /* logger.cpp in Sources */,
+				3C646D2813F4720B0058A207 /* main.cpp in Sources */,
+				3C646D2913F4720B0058A207 /* mfcc_analyzer.cpp in Sources */,
+				3C646D2A13F4720B0058A207 /* population.cpp in Sources */,
+				3C646D2B13F4720B0058A207 /* sc_converter.cpp in Sources */,
+				3C646D2C13F4720B0058A207 /* sc_evaluator.cpp in Sources */,
+				3C646D2D13F4720B0058A207 /* sc_grammar.cpp in Sources */,
+				3C646DA813F701AD0058A207 /* program_options.cpp in Sources */,
+				3CF213E71405FEB20080579B /* sc_default_grammar.cpp in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+		3CC27D2613B7E6EC00456569 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(NATIVE_ARCH_ACTUAL)";
+				DEAD_CODE_STRIPPING = NO;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_OPTIMIZATION_LEVEL = 0;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = src/precompiled_header.hpp;
+				GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
+				GCC_SYMBOLS_PRIVATE_EXTERN = NO;
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = (
+					/usr/local/include,
+					"$(PROJECT_DIR)/../common",
+					"$(PROJECT_DIR)/third_party",
+					/usr/local/include/libjson,
+					"$(PROJECT_DIR/src",
+				);
+				MACOSX_DEPLOYMENT_TARGET = 10.6;
+				ONLY_ACTIVE_ARCH = YES;
+				SDKROOT = macosx;
+			};
+			name = Debug;
+		};
+		3CC27D2713B7E6EC00456569 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ARCHS = "$(NATIVE_ARCH_ACTUAL)";
+				DEAD_CODE_STRIPPING = YES;
+				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_PRECOMPILE_PREFIX_HEADER = YES;
+				GCC_PREFIX_HEADER = src/precompiled_header.hpp;
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+				GCC_WARN_ABOUT_RETURN_TYPE = YES;
+				GCC_WARN_UNUSED_VARIABLE = YES;
+				HEADER_SEARCH_PATHS = (
+					/usr/local/include,
+					"$(PROJECT_DIR)/../common",
+					"$(PROJECT_DIR)/third_party",
+					/usr/local/include/libjson,
+					"$(PROJECT_DIR/src",
+				);
+				MACOSX_DEPLOYMENT_TARGET = 10.6;
+				SDKROOT = macosx;
+			};
+			name = Release;
+		};
+		3CC27D2913B7E6EC00456569 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				COPY_PHASE_STRIP = NO;
+				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_PREFIX_HEADER = "$(PROJECT_DIR)/src/precompiled_header.hpp";
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				HEADER_SEARCH_PATHS = (
+					/usr/local/include,
+					"$(PROJECT_DIR)/third_party",
+					/usr/local/include/libjson,
+					"$(PROJECT_DIR/include",
+				);
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					/usr/local/Cellar/fftw/3.2.2/lib,
+					/usr/local/Cellar/libxtract/0.6.3/lib,
+				);
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Debug;
+		};
+		3CC27D2A13B7E6EC00456569 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_SEARCH_USER_PATHS = NO;
+				COPY_PHASE_STRIP = YES;
+				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+				GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+				GCC_PREFIX_HEADER = "$(PROJECT_DIR)/src/precompiled_header.hpp";
+				GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
+				HEADER_SEARCH_PATHS = (
+					/usr/local/include,
+					"$(PROJECT_DIR)/third_party",
+					/usr/local/include/libjson,
+					"$(PROJECT_DIR/include",
+				);
+				LIBRARY_SEARCH_PATHS = (
+					"$(inherited)",
+					/usr/local/Cellar/fftw/3.2.2/lib,
+					/usr/local/Cellar/libxtract/0.6.3/lib,
+				);
+				PRODUCT_NAME = "$(TARGET_NAME)";
+			};
+			name = Release;
+		};
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+		3CC27D1913B7E6EC00456569 /* Build configuration list for PBXProject "gpsynth" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				3CC27D2613B7E6EC00456569 /* Debug */,
+				3CC27D2713B7E6EC00456569 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		3CC27D2813B7E6EC00456569 /* Build configuration list for PBXNativeTarget "gpsynth" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				3CC27D2913B7E6EC00456569 /* Debug */,
+				3CC27D2A13B7E6EC00456569 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+/* End XCConfigurationList section */
+	};
+	rootObject = 3CC27D1613B7E6EC00456569 /* Project object */;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gpsynth.xcodeproj/project.xcworkspace/contents.xcworkspacedata	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Workspace
+   version = "1.0">
+   <FileRef
+      location = "self:gpsynth.xcodeproj">
+   </FileRef>
+</Workspace>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gpsynth.xcodeproj/xcshareddata/xcschemes/gpsynth.xcscheme	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Scheme
+   version = "1.8">
+   <BuildAction
+      parallelizeBuildables = "YES"
+      buildImplicitDependencies = "YES">
+      <BuildActionEntries>
+         <BuildActionEntry
+            buildForTesting = "YES"
+            buildForRunning = "YES"
+            buildForProfiling = "YES"
+            buildForArchiving = "YES"
+            buildForAnalyzing = "YES">
+            <BuildableReference
+               BuildableIdentifier = "primary"
+               BlueprintIdentifier = "3CC27D1E13B7E6EC00456569"
+               BuildableName = "gpsynth"
+               BlueprintName = "gpsynth"
+               ReferencedContainer = "container:gpsynth.xcodeproj">
+            </BuildableReference>
+         </BuildActionEntry>
+      </BuildActionEntries>
+   </BuildAction>
+   <TestAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      buildConfiguration = "Debug">
+      <Testables>
+      </Testables>
+   </TestAction>
+   <LaunchAction
+      selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.GDB"
+      selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.GDB"
+      displayScaleIsEnabled = "NO"
+      displayScale = "1.00"
+      launchStyle = "0"
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Release"
+      debugDocumentVersioning = "YES"
+      allowLocationSimulation = "YES">
+      <BuildableProductRunnable>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "3CC27D1E13B7E6EC00456569"
+            BuildableName = "gpsynth"
+            BlueprintName = "gpsynth"
+            ReferencedContainer = "container:gpsynth.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+      <CommandLineArguments>
+         <CommandLineArgument
+            argument = "--help"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--maxtreedepth 3"
+            isEnabled = "YES">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--corelimit 1"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--windowsize 1024"
+            isEnabled = "YES">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--hopsize 256"
+            isEnabled = "YES">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--keepfolders 1"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--reproducebest 1"
+            isEnabled = "YES">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--crossover 0.5 --mutation 0.45"
+            isEnabled = "YES">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--tournament 2"
+            isEnabled = "YES">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--population 10000"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--population 1000"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--population 100"
+            isEnabled = "YES">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--generations 20"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--generations 1000"
+            isEnabled = "YES">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--workfolder &quot;/tmp&quot;"
+            isEnabled = "YES">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--grammar &quot;/users/ian/dropbox/uni/Msc Project/sc.json&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/808_snare.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/808_kick_long.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/lfo.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/horn.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/white_noise_lpf_up_32.aif&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/fm_bell.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/rect_110.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/lawnmower.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/piano.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/bloom.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/speak_and_spell_a.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/speak_and_spell_house.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/speak_and_spell_happy.wav&quot;"
+            isEnabled = "YES">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/ghosts.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/omnichord_58.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+         <CommandLineArgument
+            argument = "--target &quot;/users/ian/samples/test/vec2_synth_063.wav&quot;"
+            isEnabled = "NO">
+         </CommandLineArgument>
+      </CommandLineArguments>
+      <AdditionalOptions>
+      </AdditionalOptions>
+   </LaunchAction>
+   <ProfileAction
+      displayScaleIsEnabled = "NO"
+      displayScale = "1.00"
+      shouldUseLaunchSchemeArgsEnv = "YES"
+      savedToolIdentifier = ""
+      useCustomWorkingDirectory = "NO"
+      buildConfiguration = "Release"
+      debugDocumentVersioning = "YES">
+      <BuildableProductRunnable>
+         <BuildableReference
+            BuildableIdentifier = "primary"
+            BlueprintIdentifier = "3CC27D1E13B7E6EC00456569"
+            BuildableName = "gpsynth"
+            BlueprintName = "gpsynth"
+            ReferencedContainer = "container:gpsynth.xcodeproj">
+         </BuildableReference>
+      </BuildableProductRunnable>
+   </ProfileAction>
+   <AnalyzeAction
+      buildConfiguration = "Debug">
+   </AnalyzeAction>
+   <ArchiveAction
+      buildConfiguration = "Release"
+      revealArchiveInOrganizer = "YES">
+   </ArchiveAction>
+</Scheme>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/grammar/sc.json	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,298 @@
+{
+  "sclang-version": "3",
+  "name": "sc3",
+  "arg-types": [
+    {
+      "type": "frequency",
+      "range": [20, 20000],
+      "range_control": [0, 100],
+      "scaling": "log"
+    },
+    {
+      "type": "radians",
+      "range": [0, 6.2831853072]
+    },
+    {
+      "type": "audio",
+      "range": [-1, 1]
+    },
+    {
+      "type": "time",
+      "range": [0, 10],
+      "scaling": "log"
+    },
+    {
+      "type": "trigger",
+      "range": [-1, 1],
+      "fixed_range": true
+    }
+  ],
+
+  "sources": [
+    // oscillators
+    {
+      "name": "SinOsc",
+      "args": [
+        { "name": "freq", "type": "frequency" },
+        { "name": "phase", "type": "radians" }
+      ]
+    },
+    {
+      "name": "Saw",
+      "args": { "name": "freq", "type": "frequency" }
+    },
+    {
+      "name": "SyncSaw",
+      "args": [
+        { "name": "syncFreq", "type": "frequency" },
+        { "name": "sawFreq", "type": "frequency" }
+      ]
+    },
+    {
+      "name": "VarSaw",
+      "args": [ { "name": "freq", "type": "frequency" }, "iphase", "width" ]
+    },
+    {
+      "name": "Pulse",
+      "args": [ { "name": "freq", "type": "frequency" }, "width" ]
+    },
+    {
+      "name": "Impulse",
+      "args": [ { "name": "freq", "type": "frequency" }, "phase" ]
+    },
+    {
+      "name": "Blip",
+      "args": [
+        { "name": "freq", "type": "frequency" },
+        { "name": "numharm", "range": [1, 200] }
+      ]
+    },
+    {
+      "name": "SinOscFB",
+      "args": [
+        { "name": "freq", "type": "frequency" },
+        { "name": "feedback", "type": "radians" }
+      ]
+    },
+    {
+      "name": "PMOsc",
+      "args": [
+        { "name": "carfreq", "type": "frequency" },
+        { "name": "modfreq", "type": "frequency" },
+        { "name": "pmindex", "type": "radians" },
+        { "name": "modphase", "type": "radians" }
+      ]
+    },
+    {
+      "name": "FBSineC",
+      "output": "audio",
+      "args": [
+        { "name": "freq", "type": "frequency" },
+        { "name": "im", "range": [1, 64] },
+        { "name": "fb", "range": [0, 0.5] },
+        { "name": "a", "range": [1, 1.2] },
+        { "name": "c", "range": [0.1, 0.9] }
+      ]
+    },
+    {
+      "name": "FBSineN",
+      "output": "audio",
+      "args": [
+        { "name": "freq", "type": "frequency" },
+        { "name": "im", "range": [1, 64] },
+        { "name": "fb", "range": [0, 0.5] },
+        { "name": "a", "range": [1, 1.2] },
+        { "name": "c", "range": [0.1, 0.9] }
+      ]
+    },
+    {
+      "name": "Logistic",
+      "args": [
+        { "name": "chaosParam", "range": [3, 3.999] },
+        { "name": "freq", "type": "frequency" }
+      ]
+    },
+    // Noise
+    {
+      "name": "LFNoise0",
+      "args": { "name": "freq", "type": "frequency" }
+    },
+    "WhiteNoise",
+    "BrownNoise",
+    "PinkNoise",
+    {
+      "name": "Crackle",
+      "args": { "name": "chaosParam", "range": [1, 2] }
+    },
+    // Lines/Envelopes
+    {
+      "name": "Line",
+      "output": "control",
+      "args": { "name": "dur", "type": "time" }
+    },
+    {
+      "name": "XLine",
+      "output": "control",
+      "args": [ 
+        { "name": "dur", "type": "time" },
+        { "name": "add", "constant": -1 }
+      ]
+    },
+    {
+      "name": "Linen",
+      "output": "control",
+      "args": [
+        "gate",
+        { "name": "attackTime", "type": "time" },
+        "susLevel",        
+        { "name": "releaseTime", "type": "time" }
+      ]
+    }
+  ],
+
+  "modifiers": [
+    // Filters
+    {
+      "name": "LPF",
+      "args": { "name": "freq", "type": "frequency" }
+    },
+    {
+      "name": "HPF",
+      "args": { "name": "freq", "type": "frequency" }
+    },
+    {
+      "name": "BPF",
+      "args": [ { "name": "freq", "type": "frequency" }, "rq" ]
+    },
+    {
+      "name": "BRF",
+      "args": [ { "name": "freq", "type": "frequency" }, "rq" ]
+    },
+    {
+      "name": "RLPF",
+      "args": [ { "name": "freq", "type": "frequency" }, "rq" ]
+    },
+    {
+      "name": "RHPF",
+      "args": [ { "name": "freq", "type": "frequency" }, "rq" ]
+    },
+    {
+      "name": "Resonz",
+      "args": [ { "name": "freq", "type": "frequency" }, "bwr" ]
+    },
+    {
+      "name": "Ringz",
+      "args": [ 
+        { "name": "freq", "type": "frequency" },
+        { "name": "decaytime", "type": "time" }
+      ]
+    },
+    {
+      "name": "Formlet",
+      "args": [
+        { "name": "freq", "type": "frequency" },
+        { "name": "attacktime", "type": "time" },
+        { "name": "decaytime", "type": "time" }
+      ]
+    },
+    {
+      "name": "MoogFF",
+      "args": [ 
+        { "name": "freq", "type": "frequency" },
+        { "name": "gain", "range": [0, 4] }
+      ]
+    },
+    {
+      "name": "FreeVerb",
+      "output": "audio",
+      "args": [ "mix", "room", "damp" ]
+    },
+    // Dynamics
+    {
+      "name": "Limiter",
+      "output": "audio",
+      "args": "level"
+    },
+    {
+      "name": "Amplitude",
+      "output": "control",
+      "args": [
+        { "name": "attackTime", "type": "time" },
+        { "name": "releaseTime", "type": "time" }
+      ]
+    },
+    {
+      "name": "Normalizer",
+      "output": "audio",
+      "args": [ "level", { "name": "dur", "range": [0.001, 0.5] } ]
+    },
+    {
+      "name": "Compander",
+      "output": "audio",
+      "args": [ 
+        { "name": "control", "type": "audio" },
+        "thresh",
+        { "name": "slopeBelow", "type": "time" },
+        { "name": "slopeAbove", "type": "time" },
+        { "name": "clampTime", "range": [0.001, 0.2] },
+        { "name": "relaxTime", "range": [0.001, 0.2] }
+      ]
+    },
+    // shifters
+    {
+      "name": "FreqShift",
+      "output": "audio",
+      "args": [
+        { "name": "freq", "range": [-1000, 1000] },
+        { "name": "phase", "type": "radians" }
+      ]
+    },
+    {
+      "name": "PitchShift",
+      "output": "audio",
+      "args": [
+        { "name": "pitchRatio", "range": [0, 4] },
+        { "name": "pitchDispersion", "range": [0, 4] },
+        { "name": "timeDispersion", "range": [0, 0.2] }
+      ]
+    },
+    // delays
+    {
+      "name": "DelayC",
+      "args": [
+        { "name": "maxdelaytime", "constant": 1 },
+        { "name": "delaytime", "range": [0.001, 1] }
+      ]
+    },
+    {
+      "name": "Pluck",
+      "output": "audio",
+      "args": [
+        { "name": "trig", "type": "trigger" },
+        { "name": "maxdelaytime", "constant": 1 },
+        { "name": "delaytime" },
+        { "name": "decaytime", "type": "time" },
+        { "name": "coef", "range": [-0.9, 0.9] }
+      ]
+    },
+    {
+      "name": "CombC",
+      "args": [
+        { "name": "maxdelaytime", "constant": 1 },
+        { "name": "delaytime" },
+        { "name": "decaytime", "range": [-1, 1] }
+      ]
+    },
+    // misc
+    {
+      "name": "Decay",
+      "args": { "name": "decayTime", "type": "time" }
+    },
+    {
+      "name": "Latch",
+      "args": { "name": "trig", "type": "trigger" }
+    }
+  ] // end of modifiers
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/CMakeLists.txt	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,44 @@
+set(GPSYNTH_SOURCES
+  feature_extractor.cpp
+  file_comparer.cpp
+  logger.cpp
+  main.cpp
+  mfcc_analyzer.cpp
+  population.cpp
+  program_options.cpp
+  sc_converter.cpp
+  sc_default_grammar.cpp
+  sc_evaluator.cpp
+  sc_grammar.cpp
+)
+
+# json
+include_directories("${PROJECT_DIR}/third_party/json")
+set(GPSYNTH_LIBS ${GPSYNTH_LIBS} json)
+
+# fftw
+find_package(FFTW REQUIRED)
+include_directories(${FFTW_INCLUDES})
+set(GPSYNTH_LIBS ${GPSYNTH_LIBS} ${FFTW_LIBRARIES})
+
+# sndfile
+find_package(SndFile REQUIRED)
+include_directories(${SNDFILE_INCLUDE_DIR})
+set(GPSYNTH_LIBS ${GPSYNTH_LIBS} ${SNDFILE_LIBRARY})
+
+# configure boost
+set(Boost_USE_MULTITHREADED ON)
+find_package(Boost 1.44.0 COMPONENTS date_time  
+                                     filesystem
+                                     program_options
+                                     system
+                                     thread
+                                     REQUIRED)
+set(GPSYNTH_LIBS ${GPSYNTH_LIBS} ${Boost_LIBRARIES})
+
+# setup gpsynth
+add_executable(gpsynth ${GPSYNTH_SOURCES})
+target_link_libraries(gpsynth ${GPSYNTH_LIBS})
+
+install(TARGETS gpsynth RUNTIME DESTINATION bin)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/boost_ex.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,73 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// Boost helper functions
+
+#pragma once
+
+#include "boost/foreach.hpp"
+#include "boost/random/mersenne_twister.hpp"
+#include "boost/random/normal_distribution.hpp"
+#include "boost/random/variate_generator.hpp"
+#include "boost/shared_array.hpp"
+#include "boost/thread.hpp"
+
+#include <cstddef>
+#include <ctime>
+
+// foreach macro
+#define foreach BOOST_FOREACH
+#define foreach_reverse BOOST_REVERSE_FOREACH
+
+namespace bx {
+  
+  // Sleep the current thread for a certain number of milliseconds
+  inline void SleepMs(int milliseconds) {
+    boost::this_thread::sleep(boost::posix_time::milliseconds(milliseconds));
+  }
+  
+  // boost.random helpers
+  typedef boost::random::mt19937 EngineType;
+  typedef boost::variate_generator<EngineType, boost::normal_distribution<> >
+    GaussianGenerator;
+  
+  class Random {
+    EngineType engine_;
+    
+  public:
+    Random() : engine_(static_cast<unsigned int>(std::time(0))) {}
+    EngineType& Engine() { return engine_; }
+    
+    static Random& Singleton() {
+      static Random random;
+      return random;
+    }
+  };
+
+  static GaussianGenerator MakeGaussianGenerator(double mean = 0.0,
+                                                 double sigma = 1.0) {
+    boost::normal_distribution<> distribution(mean, sigma);
+    return GaussianGenerator(Random::Singleton().Engine(), distribution);
+  }
+  
+  static EngineType& RandomEngine() {
+    return Random::Singleton().Engine();
+  }
+  
+  
+} // bx namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/converter.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,32 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// Graph Converter Interface
+
+#pragma once
+
+#include "synth_graph.hpp"
+
+#include <string>
+
+struct ConverterInterface {
+  virtual std::string ToDOT(const sg::Graph& graph) = 0;
+  virtual void Export(const sg::Graph& graph,
+                      const std::string& export_folder,
+                      const std::string& export_name) = 0;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/evaluator.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,38 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// Graph evaluator interface
+
+#pragma once
+
+#include "synth_graph.hpp"
+
+#include <cstddef>
+#include <string>
+#include <vector>
+
+// Used to listen to evaluator work thread notifications
+struct EvaluatorListenerInterface {
+  virtual void GraphRatedNotification(std::size_t graphs_rated) = 0;
+};
+
+struct EvaluatorInterface {
+  virtual void RateGraphs(std::vector<sg::Graph>& graph) = 0;
+  virtual void SetWorkFolder(const std::string& path) = 0;
+  virtual void SetListener(EvaluatorListenerInterface* listener) = 0;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/feature_extractor.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,412 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+#include "feature_extractor.hpp"
+
+#include "statistics.hpp"
+#include "std_ex.hpp"
+#include "window_makers.hpp"
+
+#include "sndfile.hh"
+
+#include "boost/bind.hpp"
+#include "boost/filesystem.hpp"
+
+#include <algorithm>
+#include <cmath>
+#include <iostream>
+#include <stdexcept>
+#include <sstream>
+
+namespace bf = boost::filesystem;
+
+namespace dsp {
+
+FeatureExtractor::FeatureExtractor(const std::string& file_path /* = "" */,
+                                   int window_size /* = 2048 */,
+                                   int hop_size /* = 512 */) 
+: window_size_(-1), // initialized by SetFrameSize
+  hop_size_(hop_size),
+  bin_frequencies_(window_size),
+  spectrum_analyzer_(window_size),
+  mfcc_analyzer_(window_size, 40, 13, 30, 10000)
+{
+  SetWindowSize(window_size);
+  if (!file_path.empty()) {
+    LoadFile(file_path);
+  }
+}
+
+void FeatureExtractor::ClearCaches() {
+  spectrum_.clear();
+  magnitude_spectrum_.clear();
+  log_magnitude_spectrum_.clear();
+  spectral_centroid_.clear();
+  spectral_spread_.clear();
+  spectral_flux_.clear();
+  pitch_.clear();
+  energy_.clear();
+  mfccs_.clear();
+  delta_mfccs_.clear();
+  double_delta_mfccs_.clear();
+}
+  
+void FeatureExtractor::SetWindowSize(int window_size) {
+  if (window_size_ != window_size) {
+    window_size_ = window_size;
+    frame_.resize(window_size);
+    // generate new window
+    window_.resize(window_size);
+    dsp::HammingWindow(window_size, window_.begin());
+    ClearCaches();
+  }
+}
+  
+void FeatureExtractor::SetHopSize(int hop_size) {
+  if (hop_size_ != hop_size) {
+    hop_size_ = hop_size;
+    ClearCaches();
+  }
+}
+  
+void FeatureExtractor::LoadFile(const std::string& file_path) {
+  SndfileHandle file(file_path);
+  if (file.error()) {
+    std::stringstream message;
+    message << "FeatureExtractor::ExtractFeaturesFromFile: "
+            << "Error reading from file '" << file_path << "' "
+            << '(' << file.error() << ')';
+    throw std::runtime_error(message.str());
+  }
+  sf_count_t frames = file.frames();
+  int channels = file.channels();
+  file_data_.resize(frames * channels);
+  // read the audio data in to the buffer
+  file.readf(&file_data_[0], frames);
+  // only supporting mono at the moment, remove extra channels
+  if (channels > 1) {
+    for (int i = 0; i < frames; i++) {
+      file_data_[i] = file_data_[i * channels];
+    }
+    file_data_.resize(frames);
+  }
+  // success, clear caches
+  ClearCaches();
+  // update file info
+  file_path_ = file_path;
+  sample_rate_ = file.samplerate();
+  frames_ = static_cast<int>(file_data_.size()) / hop_size_;
+  if (frames_ == 0) {
+    frames_++;
+  }
+  // bin info
+  bin_size_ = sample_rate_ / static_cast<Value>(window_size_);
+  std::generate(bin_frequencies_.begin(), bin_frequencies_.end(),
+                stdx::Stepper<Value>(bin_size_));
+}
+  
+Value FeatureExtractor::Duration() const {
+  return file_data_.size() / static_cast<Value>(sample_rate_);
+}
+
+const std::vector<ComplexValueList>& FeatureExtractor::Spectrum() {
+  if (spectrum_.empty()) {
+    const int frame_size = window_size_;
+    const int half_frame_size = frame_size / 2;
+    const int hop_size = hop_size_;
+    spectrum_.resize(frames_);
+    ValueList::const_iterator data_begin = file_data_.begin();
+    ValueList::const_iterator data_end = file_data_.end();
+    for (int i = 0; i < frames_; i++) {
+      //std::cout << "frame:" << i << '\n';
+      // find the frame bounds
+      ValueList::const_iterator read_start = data_begin + (i * hop_size);
+      ValueList::const_iterator read_end = read_start + frame_size;
+      if (read_end > data_end) {
+        read_end = data_end;
+      }
+      // extract the frame and apply window
+      std::transform(read_start, read_end, window_.begin(), 
+                     frame_.begin(), std::multiplies<Value>());
+      // on the last frame we'll need to fill the rest of the frame with zeros
+      std::size_t data_read = read_end - read_start;
+      if (data_read < frame_size) {
+        std::fill(frame_.begin() + data_read, frame_.end(), 0);
+      }
+      // get the spectrum of the current frame
+      std::copy(frame_.begin(), frame_.end(), spectrum_analyzer_.Input());
+      spectrum_analyzer_.Execute();
+      spectrum_[i].assign(spectrum_analyzer_.Output(),
+                          spectrum_analyzer_.Output() + half_frame_size);
+    }
+  }
+  return spectrum_;
+}
+
+const std::vector<ValueList>& FeatureExtractor::MagnitudeSpectrum() {
+  if (magnitude_spectrum_.empty()) {
+    // get complex spectrum
+    const std::vector<ComplexValueList>& spectrum = Spectrum();
+    // get magnitude spectrum for each frame
+    std::size_t frames = spectrum.size();
+    magnitude_spectrum_.resize(frames);
+    for (int i = 0; i < frames; i++) {
+      // take the absolute value of each complex bin
+      magnitude_spectrum_[i].resize(spectrum[i].size());
+      std::transform(spectrum[i].begin(), spectrum[i].end(),
+                     magnitude_spectrum_[i].begin(), std::abs<Value>);
+    }
+  }
+  return magnitude_spectrum_;
+}
+  
+const std::vector<ValueList>& FeatureExtractor::LogMagnitudeSpectrum() {
+  if (log_magnitude_spectrum_.empty()) {
+    // get magnitude spectrum
+    const std::vector<ValueList>& magnitude_spectrum = MagnitudeSpectrum();
+    // get magnitude spectrum for each frame
+    std::size_t frames = magnitude_spectrum.size();
+    log_magnitude_spectrum_.resize(frames);
+    for (int i = 0; i < frames; i++) {
+      log_magnitude_spectrum_[i].resize(magnitude_spectrum[i].size());
+      // copy magnitudes to log magnitude buffer, avoiding zeros
+      std::replace_copy(magnitude_spectrum[i].begin(),
+                        magnitude_spectrum[i].end(), 
+                        log_magnitude_spectrum_[i].begin(),
+                        0.0,
+                        std::numeric_limits<Value>::min());
+      // take the log of each magnitude (ugly casting for cmath function...)
+      std::transform(log_magnitude_spectrum_[i].begin(),
+                     log_magnitude_spectrum_[i].end(),
+                     log_magnitude_spectrum_[i].begin(),
+                     static_cast<double(*)(double)>(std::log10));
+    }
+  }
+  return log_magnitude_spectrum_;
+}
+
+const ValueList& FeatureExtractor::SpectralCentroid() {
+  if (spectral_centroid_.empty()) {
+    MagnitudeSpectrum();
+    std::size_t frames = magnitude_spectrum_.size();
+    spectral_centroid_.resize(frames);
+    std::size_t bins = magnitude_spectrum_[0].size();
+    ValueList weighted_frequencies(bins);
+    for (int i = 0; i < frames; i++) {
+      const ValueList& magnitudes = magnitude_spectrum_[i];
+      // get bin frequencies weighted by bin magnitudes
+      std::transform(magnitudes.begin(),
+                     magnitudes.end(),
+                     bin_frequencies_.begin(),
+                     weighted_frequencies.begin(),
+                     std::multiplies<Value>());
+      // divide mean of weighted frequencies by mean of bin magnitudes
+      Value magnitude = stats::Sum(magnitudes);
+      if (magnitude > 0) {
+        spectral_centroid_[i] = stats::Sum(weighted_frequencies) / magnitude;
+      } else {
+        spectral_centroid_[i] = 0;
+      }
+    }
+  }
+  return spectral_centroid_;
+}
+
+
+const ValueList& FeatureExtractor::SpectralSpread() {
+  if (spectral_spread_.empty()) {
+    SpectralCentroid();
+    std::size_t frames = magnitude_spectrum_.size();
+    spectral_spread_.resize(frames);
+    std::size_t bins = magnitude_spectrum_[0].size();
+    ValueList weighted_difference(bins);
+    for (int i = 0; i < frames; i++) {
+      Value centroid = spectral_centroid_[i];
+      const ValueList& magnitudes = magnitude_spectrum_[i];
+      for (int bin = 0; bin < bins; bin++) {
+        Value difference = bin_frequencies_[bin] - centroid;
+        weighted_difference[bin] = difference * difference * magnitudes[bin];
+      }
+      Value magnitude = stats::Sum(magnitudes);
+      if (magnitude > 0) {
+        Value variance = stats::Sum(weighted_difference) / magnitude;
+        spectral_spread_[i] = std::sqrt(variance);
+      } else {
+        spectral_spread_[i] = 0;
+      }
+    }
+  }
+  return spectral_spread_;
+}
+
+const ValueList& FeatureExtractor::Pitch() {
+  if (pitch_.empty()) {
+    MagnitudeSpectrum();
+    pitch_.resize(frames_);
+    std::deque<Value> recent_pitches;
+    const int moving_average_size = 8;
+    for (int i = 0; i < frames_; i++) {
+      const ValueList& mags = magnitude_spectrum_[i];
+      // find the peak bin number 
+      std::ptrdiff_t peak_bin = std::distance(mags.begin(),
+                                              std::max_element(mags.begin(),
+                                                               mags.end()));
+      // interpolate peak frequency
+      double offset;
+      double centre = mags[peak_bin];
+      if (centre == 0) {
+        pitch_[i] = 0;
+      } else {
+        if (peak_bin == 0) {
+          // parabolic interpolation of first 2 bin magnitudes
+          double above = mags[peak_bin + 1];
+          offset = above / (2 * (2 * centre - above));        
+        } else if (peak_bin == mags.size() - 1) {
+          // parabolic interpolation of last 2 bin magnitudes
+          double below = mags[peak_bin - 1];
+          offset = (-below) / (2 * (2 * centre - below));
+        } else {
+          double below = mags[peak_bin - 1];
+          double above = mags[peak_bin + 1];
+          // gaussian interpolation
+          offset = std::log(above / below) 
+                   / (2 * std::log((centre * centre) / (above * below)));
+        }
+        Value frame_pitch = bin_size_ * (peak_bin + offset);
+        if (recent_pitches.size() == moving_average_size) {
+          recent_pitches.pop_front();
+        }
+        recent_pitches.push_back(frame_pitch);
+        pitch_[i] = stats::Mean(recent_pitches);
+      }
+    }
+  }
+  return pitch_;
+}
+  
+const ValueList& FeatureExtractor::Energy() {
+  if (energy_.empty()) {
+    const int frame_size = window_size_;
+    const int hop_size = hop_size_;
+    energy_.resize(frames_);
+    ValueList::const_iterator data_begin = file_data_.begin();
+    ValueList::const_iterator data_end = file_data_.end();
+    for (int i = 0; i < frames_; i++) {
+      // find the frame bounds
+      ValueList::const_iterator read_start = data_begin + (i * hop_size);
+      ValueList::const_iterator read_end = read_start + frame_size;
+      if (read_end > data_end) {
+        read_end = data_end;
+      }
+      Value energy(0);
+      std::ptrdiff_t samples = std::distance(read_start, read_end);
+      while (read_start != read_end) {
+        energy += std::pow(*read_start++, 2);
+      }
+      energy_[i] = energy / samples;
+    }
+  }
+  return energy_;
+}
+
+const std::vector<ValueList>& FeatureExtractor::MFCCs() {
+  if (mfccs_.empty()) {
+    const std::vector<ValueList>& magnitude_spectrum = MagnitudeSpectrum();
+    mfcc_analyzer_.SetSampleRate(sample_rate_);
+    mfccs_.resize(frames_);
+    for (int i = 0; i < frames_; i++) {
+      mfccs_[i] = mfcc_analyzer_.ExtractMFCCS(magnitude_spectrum[i]);
+    }
+  }
+  return mfccs_;
+}
+  
+const std::vector<ValueList>& FeatureExtractor::DeltaMFCCs() {
+  if (delta_mfccs_.empty()) {
+    const std::vector<ValueList>& mfccs = MFCCs();
+    // resize buffers
+    const std::size_t number_of_mfccs = mfccs[0].size();
+    ValueList empty_values(number_of_mfccs, 0);
+    delta_mfccs_.resize(mfccs.size(), empty_values);
+    // calculate deltas based on 2 neighbouring frames in either direction
+    for (int i = 2, last_frame = frames_ - 2; i < last_frame; i++) {
+      const ValueList& before_2 = mfccs[i - 2];
+      const ValueList& before_1 = mfccs[i - 1];
+      const ValueList& after_1 = mfccs[i + 1];
+      const ValueList& after_2 = mfccs[i + 2];
+      ValueList& delta_frame = delta_mfccs_[i];
+      for (int m = 0; m < number_of_mfccs; m++) {
+        Value delta = after_1[m] - before_1[m]
+                      + 2.0 * (after_2[m] - before_2[m]);
+        delta_frame[m] = delta / 10.0;
+      }
+    }
+  }
+  return delta_mfccs_;
+}
+
+const std::vector<ValueList>& FeatureExtractor::DoubleDeltaMFCCs() {
+  if (double_delta_mfccs_.empty()) {
+    const std::vector<ValueList>& delta_mfccs = DeltaMFCCs();
+    // resize buffers
+    const std::size_t number_of_mfccs = delta_mfccs[0].size();
+    ValueList empty_values(number_of_mfccs, 0);
+    double_delta_mfccs_.resize(delta_mfccs.size(), empty_values);
+    // calculate deltas based on 2 neighbouring frames in either direction
+    for (int i = 2, last_frame = frames_ - 2; i < last_frame; i++) {
+      const ValueList& before_2 = delta_mfccs[i - 2];
+      const ValueList& before_1 = delta_mfccs[i - 1];
+      const ValueList& after_1 = delta_mfccs[i + 1];
+      const ValueList& after_2 = delta_mfccs[i + 2];
+      ValueList& double_delta_frame = double_delta_mfccs_[i];
+      for (int m = 0; m < number_of_mfccs; m++) {
+        Value delta = after_1[m] - before_1[m]
+                      + 2.0 * (after_2[m] - before_2[m]);
+        double_delta_frame[m] = delta / 10.0;
+      }
+    }
+  }
+  return double_delta_mfccs_;
+}
+  
+const std::vector<ValueList>& FeatureExtractor::SpectralFlux() {
+  if (spectral_flux_.empty()) {
+    // get magnitude spectrum
+    const std::vector<ValueList>& spectrum = MagnitudeSpectrum();
+    // get magnitude spectrum for each frame
+    std::size_t frames = spectrum.size();
+    std::size_t bins = spectrum[0].size();
+    spectral_flux_.resize(frames);
+    // first frame always zeroed
+    spectral_flux_[0].assign(bins, 0);
+    for (int i = 1; i < frames; i++) {
+      const ValueList& spectrum_frame = spectrum[i];
+      const ValueList& previous_spectrum_frame = spectrum[i - 1];
+      ValueList& flux_frame = spectral_flux_[i];
+      flux_frame.resize(bins);
+      // get the difference in magnitudes for each bin
+      for (int bin = 0; bin < bins; bin++) {
+        flux_frame[bin] = spectrum_frame[bin] - previous_spectrum_frame[bin];
+      }
+      //std::cout << i << ": " << stats::Mean(flux_frame) << '\n';
+    }
+  }
+  return spectral_flux_;
+}
+
+} // dsp namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/feature_extractor.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,99 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// FeatureExtractor - responsible for managing the retrieval of features from 
+// audio data. Caches feature data to avoid recalculations when accessing
+// different features that have the same dependencies.
+
+#pragma once
+
+#include "mfcc_analyzer.hpp"
+#include "spectrum_analyzer.hpp"
+
+#include <complex>
+#include <vector>
+
+namespace dsp {
+
+typedef double Value;
+typedef std::vector<Value> ValueList;
+typedef std::complex<Value> ComplexValue;
+typedef std::vector<ComplexValue> ComplexValueList;
+
+class FeatureExtractor {
+  std::string file_path_;
+  ValueList window_;
+  ValueList frame_;
+  ValueList file_data_;
+  ValueList bin_frequencies_;
+  Value bin_size_;
+  std::vector<ComplexValueList> spectrum_;
+  std::vector<ValueList> magnitude_spectrum_;
+  std::vector<ValueList> log_magnitude_spectrum_;
+  std::vector<ValueList> mfccs_;
+  std::vector<ValueList> delta_mfccs_;
+  std::vector<ValueList> double_delta_mfccs_;
+  std::vector<ValueList> spectral_flux_;
+  ValueList pitch_;
+  ValueList spectral_centroid_;
+  ValueList spectral_spread_;
+  ValueList energy_;
+  
+  int frames_;
+  int window_size_;
+  int hop_size_;
+  Value sample_rate_;
+  
+  dsp::SpectrumAnalyzer spectrum_analyzer_;
+  dsp::MFCCAnalyzer mfcc_analyzer_;
+  
+public:
+  FeatureExtractor(const std::string& file_path = "",
+                   int frame_size = 2048,
+                   int hop_size = 512);
+  
+  void LoadFile(const std::string& file_path);
+  void ClearCaches();
+  
+  int Frames() const { return frames_; }
+  
+  int WindowSize() const { return window_size_; }
+  int HopSize() const { return hop_size_; }
+  
+  void SetWindowSize(int window_size);
+  void SetHopSize(int hop_size);
+  
+  Value Duration() const;
+  
+  const std::vector<ComplexValueList>& Spectrum();
+  const std::vector<ValueList>& MagnitudeSpectrum();
+  const std::vector<ValueList>& LogMagnitudeSpectrum();
+  const ValueList& Pitch();
+  const ValueList& SpectralCentroid();
+  const ValueList& SpectralSpread();
+  const std::vector<ValueList>& SpectralFlux();
+  const ValueList& Energy();
+  const std::vector<ValueList>& MFCCs();
+  const std::vector<ValueList>& DeltaMFCCs();
+  const std::vector<ValueList>& DoubleDeltaMFCCs();
+  
+private:
+  void GenerateWindow();
+};
+
+} // dsp namespace 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/file_comparer.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,427 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+#include "file_comparer.hpp"
+
+#include "boost_ex.hpp"
+#include "statistics.hpp"
+#include "std_ex.hpp"
+
+#include "boost/bind.hpp"
+#include "boost/algorithm/string/classification.hpp"
+#include "boost/algorithm/string/split.hpp"
+#include "boost/math/special_functions/fpclassify.hpp"
+
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <iostream>
+#include <iterator>
+
+// maps the frequency range 20-20480Hz to the 0-1 range on a log scale
+// with 0.1 = 1 octave
+namespace {
+ 
+dsp::Value ConvertFrequency(dsp::Value frequency) {
+  frequency = stdx::Clamp(frequency, 20.0, 20480.0);
+  return (::log2(frequency / 440.0) * 10 + 44.5943) / 100.0;
+}
+  
+void ConvertFrequencyList(dsp::ValueList& frequencies) {
+  std::transform(frequencies.begin(), frequencies.end(), frequencies.begin(),
+                 &ConvertFrequency);
+}
+  
+} // namespace
+
+namespace dsp {
+
+// The FeatureComparer class abstracts common code required by feature set
+// comparisons. 
+template<typename T>
+class FeatureComparer : public FeatureComparerInterface {  
+public:
+  typedef void (*ConversionFunction)(T&);
+  typedef const T& (FeatureExtractor::*FeatureFunction)();
+  typedef typename T::value_type ValueT;
+  typedef typename T::const_iterator IteratorT;
+
+private:
+  // 
+  FeatureExtractor* extractor_;
+  // A member function of FeatureExtractor that retrieves an audio feature
+  FeatureFunction feature_function_;
+  // Stores the target feature for comparison
+  T target_buffer_;
+  // Temporary use stored as member to prevent reallocations
+  T comparison_buffer_;
+  // Used if a feature data set needs to have a conversion applied to it
+  ConversionFunction converter_;
+  // the feature's ID
+  int id_;
+  // true if the feature should be scaled by the frame's energy
+  bool scale_by_energy_;
+  
+public:
+  FeatureComparer(int id,
+                  FeatureExtractor* extractor,
+                  FeatureFunction feature_function,
+                  ConversionFunction converter = NULL,
+                  bool scale_by_energy = false) 
+  : id_(id),
+    extractor_(extractor),
+    feature_function_(feature_function),
+    converter_(converter),
+    scale_by_energy_(scale_by_energy)
+  {}
+   
+  // copy constructor
+  FeatureComparer(const FeatureComparer& other)
+  : id_(other.id_),
+    extractor_(other.extractor_),
+    feature_function_(other.feature_function_),
+    converter_(other.converter_),
+    scale_by_energy_(other.scale_by_energy_),
+    target_buffer_(other.target_buffer_) // copy the target value buffer
+    // no need to copy comparison buffer
+  {}
+  
+  virtual void AnalyzeTarget() {
+    // retrieve the target feature
+    target_buffer_ = (extractor_->*feature_function_)();
+    if (converter_ != NULL) {
+      converter_(target_buffer_);
+    }
+    if (scale_by_energy_) {
+      std::transform(target_buffer_.begin(), target_buffer_.end(),
+                     extractor_->Energy().begin(),
+                     target_buffer_.begin(),
+                     std::multiplies<ValueT>());
+    }
+  }
+  
+  virtual Value Compare() {
+    // get the values to compare
+    const ValueList& feature = (extractor_->*feature_function_)();
+    ValueList* feature_buffer;
+    if (converter_ != NULL || scale_by_energy_) {
+      comparison_buffer_ = feature;
+      if (converter_ != NULL) {
+        converter_(comparison_buffer_);
+      }
+      if (scale_by_energy_) {
+        std::transform(comparison_buffer_.begin(), comparison_buffer_.end(),
+                       extractor_->Energy().begin(),
+                       comparison_buffer_.begin(),
+                       std::multiplies<ValueT>());
+      }
+      feature_buffer = &comparison_buffer_;
+    } else {
+      feature_buffer = const_cast<ValueList*>(&feature);
+    }
+    // call conversion function
+
+    // find range of buffer to compare against target
+    IteratorT buffer_start = feature_buffer->begin();
+    IteratorT buffer_end;
+    if (feature_buffer->size() > target_buffer_.size()) {
+      buffer_end = buffer_start + target_buffer_.size();
+    } else {
+      buffer_end = feature_buffer->end();
+    }
+    // return root mean square error of buffer differences
+    return std::sqrt(stats::MeanSquaredError(buffer_start,
+                                             buffer_end,
+                                             target_buffer_.begin()));
+  }
+  
+  virtual FeatureComparerInterface* Clone() const {
+    return new FeatureComparer<T>(*this);
+  }
+
+  virtual void SetExtractor(FeatureExtractor* extractor) {
+    extractor_ = extractor;
+  }
+  
+  virtual int ID() const { return id_; }
+};
+
+// specializations for std::vector<ValueList>
+template<>
+void FeatureComparer<std::vector<ValueList> >::AnalyzeTarget() {
+  target_buffer_ = (extractor_->*feature_function_)();
+  if (converter_ != NULL) {
+    converter_(target_buffer_);
+  }
+  // for vector features we can scale by energy on a frame by frame basis 
+}
+
+template<>
+Value FeatureComparer<std::vector<ValueList> >::Compare() {
+  // get the values to compare
+  const std::vector<ValueList>& feature = (extractor_->*feature_function_)();
+  std::vector<ValueList>* feature_buffer;
+  // call conversion function
+  if (converter_ != NULL) {
+    comparison_buffer_ = feature;
+    converter_(comparison_buffer_);
+    feature_buffer = &comparison_buffer_;
+  } else {
+    // this isn't pretty, but it's the only way to allow avoiding a copy
+    // when no conversion is taking place..
+    feature_buffer = const_cast<std::vector<ValueList>*>(&feature);
+  }
+  // find how many frames to compare
+  std::size_t frames_to_compare;
+  if (feature_buffer->size() > target_buffer_.size()) {
+    frames_to_compare = target_buffer_.size();
+  } else {
+    frames_to_compare = feature_buffer->size();
+  }
+  // take average of RMSE over all frames
+  Value error = 0;
+  const ValueList& energy = extractor_->Energy();
+  if (scale_by_energy_) {
+    for (std::size_t i = 0; i < frames_to_compare; ++i) {
+      Value frame_error;
+      frame_error = std::sqrt(stats::MeanSquaredError(feature_buffer->at(i),
+                                                      target_buffer_[i]));
+      error += frame_error * energy[i];
+    }
+  } else {
+    for (std::size_t i = 0; i < frames_to_compare; ++i) {
+      error += std::sqrt(stats::MeanSquaredError(feature_buffer->at(i),
+                                                 target_buffer_[i]));
+    }
+  }
+  return error / frames_to_compare;
+}
+
+  
+FileComparer::FileComparer(int window_size /* = 1024 */,
+                           int hop_size /* = 256 */)
+: extractor_("", window_size, hop_size),
+  target_duration_(0)
+{
+  EnableFeature(Feature::LogMagnitude);
+  EnableFeature(Feature::Pitch);
+}
+  
+FileComparer::FileComparer(const std::string& feature_list,
+                           int window_size /* = 1024 */,
+                           int hop_size /* = 256 */)
+: extractor_("", window_size, hop_size),
+  target_duration_(0)
+{
+  feature_names_["pitch"] = Feature::Pitch;
+  feature_names_["energy"] = Feature::Energy;
+  feature_names_["mfccs"] = Feature::MFCCs;
+  feature_names_["dmfccs"] = Feature::DeltaMFCCs;
+  feature_names_["ddmfccs"] = Feature::DoubleDeltaMFCCs;
+  feature_names_["mag"] = Feature::Magnitude;
+  feature_names_["logmag"] = Feature::LogMagnitude;
+  feature_names_["centroid"] = Feature::SpectralCentroid;
+  feature_names_["spread"] = Feature::SpectralSpread;
+  feature_names_["flux"] = Feature::SpectralFlux;
+  EnableFeatures(feature_list);
+}
+  
+FileComparer::FileComparer(const FileComparer& other)
+: target_file_(other.target_file_),
+  target_duration_(other.target_duration_),
+  extractor_("",
+             other.extractor_.WindowSize(),
+             other.extractor_.HopSize())
+{
+  foreach (const FeatureComparerPtr& pointer, other.features_) {
+    // clone the feature comparer
+    features_.push_back(FeatureComparerPtr(pointer->Clone()));
+    features_.back()->SetExtractor(&extractor_);
+  }
+}
+  
+void FileComparer::SetFeatureExtractorSettings(int window_size, int hop_size) {
+  bool reload_target = false;
+  if (extractor_.WindowSize() != window_size) {
+    extractor_.SetWindowSize(window_size);
+    reload_target = true;
+  }
+  if (extractor_.HopSize() != hop_size) {
+    extractor_.SetHopSize(hop_size);
+    reload_target = true;
+  }
+  if (reload_target && !target_file_.empty()) {
+    SetTargetFile(target_file_);
+  }
+}
+
+void FileComparer::SetTargetFile(const std::string& target_file) {
+  if (target_file_ != target_file) {
+    target_file_ = target_file;
+    extractor_.LoadFile(target_file);
+    target_duration_ = extractor_.Duration();
+    std::for_each(features_.begin(), features_.end(),
+                  boost::bind(&FeatureComparerInterface::AnalyzeTarget, _1));
+  }
+}
+
+
+Value FileComparer::CompareFile(const std::string& file_path) {
+  extractor_.LoadFile(file_path);
+  Value error;
+  foreach (FeatureComparerPtr& feature, features_) {
+    error += feature->Compare();
+  }
+  return error / features_.size();
+}
+  
+namespace {
+
+// Helper function for creating FeatureComparers
+template<typename T>
+FeatureComparerPtr MakeFeatureComparer(FileComparer::Feature::ID id,
+                                       FeatureExtractor& extractor,
+                                       const T& (FeatureExtractor::*feature)(),
+                                       void (*converter)(T&) = NULL,
+                                       bool scale_by_energy = false) {
+  return FeatureComparerPtr(new FeatureComparer<T>(static_cast<int>(id),
+                                                   &extractor,
+                                                   feature,
+                                                   converter,
+                                                   scale_by_energy));
+}
+
+} // namespace
+  
+void FileComparer::EnableFeature(Feature::ID feature_id, bool enable) {
+  // check if the requested feature is already enabled
+  for (std::vector<FeatureComparerPtr>::iterator feature = features_.begin(),
+       end = features_.end();
+       feature != end;
+       ++feature) {
+    if ((*feature)->ID() == feature_id) {
+      // feature enabled, if enable == false then remove the feature
+      if (!enable) {
+        features_.erase(feature);
+      }
+      return;
+    }
+  }
+  // make the feature comparer
+  FeatureComparerPtr feature;
+  switch (feature_id) {
+    case Feature::Pitch:
+      feature = MakeFeatureComparer(feature_id,
+                                    extractor_,
+                                    &FeatureExtractor::Pitch,
+                                    ConvertFrequencyList,
+                                    true);
+      break;
+    case Feature::Energy:
+      feature = MakeFeatureComparer(feature_id,
+                                    extractor_,
+                                    &FeatureExtractor::Energy);
+      break;
+    case Feature::MFCCs:
+      feature = MakeFeatureComparer(feature_id,
+                                    extractor_,
+                                    &FeatureExtractor::MFCCs);
+      break;
+    case Feature::DeltaMFCCs:
+      feature = MakeFeatureComparer(feature_id,
+                                    extractor_,
+                                    &FeatureExtractor::DeltaMFCCs);
+      break;      
+    case Feature::DoubleDeltaMFCCs:
+      feature = MakeFeatureComparer(feature_id,
+                                    extractor_,
+                                    &FeatureExtractor::DoubleDeltaMFCCs);
+      break;
+    case Feature::Magnitude:
+      feature = MakeFeatureComparer(feature_id,
+                                    extractor_,
+                                    &FeatureExtractor::MagnitudeSpectrum);
+    case Feature::LogMagnitude:
+      feature = MakeFeatureComparer(feature_id,
+                                    extractor_,
+                                    &FeatureExtractor::LogMagnitudeSpectrum);
+      break;
+    case Feature::SpectralCentroid:
+      feature = MakeFeatureComparer(feature_id,
+                                    extractor_,
+                                    &FeatureExtractor::SpectralCentroid,
+                                    ConvertFrequencyList,
+                                    true);
+      break;
+    case Feature::SpectralSpread:
+      feature = MakeFeatureComparer(feature_id,
+                                    extractor_,
+                                    &FeatureExtractor::SpectralSpread,
+                                    ConvertFrequencyList,
+                                    true);
+      break;
+    case Feature::SpectralFlux:
+      feature = MakeFeatureComparer(feature_id,
+                                    extractor_,
+                                    &FeatureExtractor::SpectralFlux);
+      break;
+    default:
+      throw std::runtime_error("FileComparer::EnableFeature - Invalid ID");
+  }
+  // analyze the feature if we already have a target file loaded
+  if (!target_file_.empty()) {
+    feature->AnalyzeTarget();
+  }
+  // store the feature
+  features_.push_back(feature);
+}  
+
+void FileComparer::EnableFeatures(const std::vector<Feature::ID>& features,
+                                  bool enable /* = true */) {
+  foreach (Feature::ID id, features) {
+    EnableFeature(id, enable);
+  }
+}
+  
+void FileComparer::EnableFeatures(std::string feature_name_list,
+                                  bool enable /* = true */) {
+  std::vector<std::string> feature_names;
+  // split the comma separated list of names
+  boost::algorithm::split(feature_names,
+                          feature_name_list,
+                          boost::algorithm::is_any_of(", "),
+                          boost::algorithm::token_compress_on);
+  // enable each feature
+  foreach (const std::string& feature_name, feature_names) {
+    // check if the requested feature name is valid
+    if (feature_names_.find(feature_name) == feature_names_.end()) {
+      std::stringstream message;
+      message << "FileComparer::EnableFeatures - Unknown feature '"
+              << feature_name << "'";
+      throw std::runtime_error(message.str());
+    }
+    EnableFeature(feature_names_[feature_name], enable);
+  }
+}
+  
+void FileComparer::SetFeatures(const std::vector<Feature::ID>& features) {
+  features_.clear();
+  EnableFeatures(features);
+}
+
+} // dsp namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/file_comparer.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,94 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// FileComparer - Compares sounds against a target set of audio features that
+// have been retrieved from FeatureExtractor
+
+#pragma once
+
+#include "feature_extractor.hpp"
+
+#include "boost/shared_ptr.hpp"
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace dsp {
+
+struct FeatureComparerInterface {
+  virtual ~FeatureComparerInterface() {}
+
+  virtual void AnalyzeTarget() = 0;
+  virtual Value Compare() = 0;
+  virtual FeatureComparerInterface* Clone() const = 0;
+  virtual void SetExtractor(FeatureExtractor* extractor) = 0;
+  virtual int ID() const = 0;
+};
+  
+typedef boost::shared_ptr<FeatureComparerInterface> FeatureComparerPtr; 
+
+
+class FileComparer {
+public:
+  
+  struct Feature {
+    enum ID {
+      Pitch,
+      Energy,
+      MFCCs,
+      DeltaMFCCs,
+      DoubleDeltaMFCCs,
+      Magnitude,
+      LogMagnitude,
+      SpectralCentroid,
+      SpectralSpread,
+      SpectralFlux
+    };
+  };
+
+private:
+  std::string target_file_;
+  Value target_duration_;
+  std::vector<FeatureComparerPtr> features_;
+  FeatureExtractor extractor_;
+  std::map<std::string, Feature::ID> feature_names_;
+  
+public:
+  // copy constructor
+  FileComparer(const FileComparer& other);
+  FileComparer(int window_size = 1024,
+               int hop_size = 256);
+  FileComparer(const std::string& feature_list,
+               int window_size = 1024,
+               int hop_size = 256);
+  
+  void SetTargetFile(const std::string& target_file);
+  Value CompareFile(const std::string& file_path);
+  void SetFeatureExtractorSettings(int window_size, int hop_size);
+  
+  Value TargetDuration() const { return target_duration_; }
+  
+  void EnableFeature(Feature::ID feature, bool enable = true);
+  void EnableFeatures(const std::vector<Feature::ID>& features,
+                      bool enable = true);
+  void EnableFeatures(std::string feature_name_list, bool enable = true);
+  void SetFeatures(const std::vector<Feature::ID>& features);
+};
+
+} // dsp namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/grammar.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,44 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// The Grammar interface.
+
+// TODO split out mutation behaviour in to new class
+
+#pragma once
+
+#include "synth_graph.hpp"
+
+struct GrammarInterface {
+  
+  virtual void RandomGraph(sg::Graph& graph) const = 0;
+  
+  //virtual sg::Graph MutateGraph(const sg::Graph& graph) const = 0;
+  
+  virtual void PickCrossoverNodes(const sg::Graph& parent_1, 
+                                  const sg::Graph& parent_2,
+                                  sg::Vertex* node_1,
+                                  sg::Vertex* node_2) const = 0;
+
+  virtual bool MutationAddSubTree(sg::Graph& graph) const = 0;
+  virtual bool MutationReplaceSubTree(sg::Graph& graph) const = 0;
+  virtual bool MutationModifyInputs(sg::Graph& graph) const = 0;
+  virtual bool MutationModifyConnections(sg::Graph& graph) const = 0;
+  virtual bool MutationReplaceCommand(sg::Graph& graph) const = 0;
+  virtual bool MutationInsertCommand(sg::Graph& graph) const = 0;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/graph_helpers.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,104 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// Some helper functions for boost.graph
+
+#pragma once
+
+#include "boost/graph/adjacency_list.hpp"
+#include "boost/tuple/tuple.hpp"
+
+// removes the tree starting at the specified edge from the graph
+template<typename GRAPH>
+void RemoveSubTree(typename boost::graph_traits<GRAPH>::edge_descriptor edge,
+                   GRAPH& graph) {
+  typename boost::graph_traits<GRAPH>::vertex_descriptor source;
+  typename boost::graph_traits<GRAPH>::vertex_descriptor target;
+  source = boost::source(edge, graph);
+  target = boost::target(edge, graph);
+  // avoid iteration as removing edges invalidates iterators
+  while (boost::in_degree(source, graph) > 0) {
+    RemoveSubTree(*(boost::in_edges(source, graph).first), graph);
+  }
+  boost::remove_edge(source, target, graph);
+  boost::remove_vertex(source, graph);
+}
+
+// removes the tree starting at the specified vertex from the graph
+template<typename T>
+void RemoveSubTree(typename boost::graph_traits<T>::vertex_descriptor vertex,
+                   T& graph) {
+  // avoid iteration as removing edges invalidates iterators
+  while (boost::in_degree(vertex, graph) > 0) {
+    RemoveSubTree(*(boost::in_edges(vertex, graph).first), graph);
+  }
+  boost::remove_vertex(vertex, graph);
+}
+
+// inserts the subtree identified by source in to target_graph
+// returns the root vertex of the inserted subtree
+template<typename GRAPH>
+typename boost::graph_traits<GRAPH>::vertex_descriptor
+InsertSubTree(typename boost::graph_traits<GRAPH>::vertex_descriptor source,
+              const GRAPH& source_graph,
+              GRAPH& target_graph) {
+  typedef typename boost::graph_traits<GRAPH>::vertex_descriptor Vertex;
+  typedef typename boost::graph_traits<GRAPH>::in_edge_iterator InEdge;
+  Vertex new_vertex = boost::add_vertex(source_graph[source], target_graph);
+  InEdge in_edge;
+  InEdge in_edges_end;
+  boost::tie(in_edge, in_edges_end) = boost::in_edges(source, source_graph);
+  while (in_edge != in_edges_end) {
+    Vertex input = InsertSubTree(boost::source(*in_edge, source_graph),
+                                 source_graph,
+                                 target_graph);
+    boost::add_edge(input, new_vertex, source_graph[*in_edge], target_graph);
+    ++in_edge;
+  }
+  return new_vertex;
+}
+
+// SwapSubTrees - swaps the subtrees starting at node_1 and node_2
+// writing to graphs passed in as targets
+template<typename GRAPH>
+void SwapSubTrees(typename boost::graph_traits<GRAPH>::vertex_descriptor node_1,
+                  typename boost::graph_traits<GRAPH>::vertex_descriptor node_2,
+                  const GRAPH& source_1, const GRAPH& source_2,
+                  GRAPH& target_1, GRAPH& target_2) {
+
+  typedef typename boost::graph_traits<GRAPH>::vertex_descriptor Vertex;
+  typedef typename boost::graph_traits<GRAPH>::edge_descriptor Edge;
+  // copy sources to targets
+  target_1 = source_1;
+  target_2 = source_2;
+  // get connecting output edges
+  Edge edge_1 = *(boost::out_edges(node_1, source_1).first);
+  Edge edge_2 = *(boost::out_edges(node_2, source_2).first);
+  // get connecting nodes on other end of outputs
+  Vertex target_node_1 = boost::target(edge_1, source_1);
+  Vertex target_node_2 = boost::target(edge_2, source_2);
+  // delete subtrees
+  RemoveSubTree(edge_1, target_1);
+  RemoveSubTree(edge_2, target_2);
+  // insert copies of subtrees in opposing target graphs
+  Vertex new_node_1 = InsertSubTree(node_2, source_2, target_1);
+  Vertex new_node_2 = InsertSubTree(node_1, source_1, target_2);
+  // connect the new subtrees using the same edge properties as old connection
+  boost::add_edge(new_node_1, target_node_1, source_1[edge_1], target_1);
+  boost::add_edge(new_node_2, target_node_2, source_2[edge_2], target_2);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/logger.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,64 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+#include "logger.hpp"
+
+namespace logger {
+
+Logger::Logger()
+: output_stream_(std::cout),
+  quit_thread_(false) {
+  logging_thread_.reset(new boost::thread(&Logger::WorkerThread, this));
+}
+
+Logger::~Logger() {
+  quit_thread_ = true;
+  queue_condition_.notify_one();
+  logging_thread_->join();
+}
+
+void Logger::LogMessage(const std::string& message) {
+  boost::mutex::scoped_lock lock(queue_mutex_);
+  log_queue_.push(message);
+  queue_condition_.notify_one();
+}
+
+void Logger::WorkerThread() {
+  while (!quit_thread_) {
+    boost::mutex::scoped_lock lock(queue_mutex_);
+    while (log_queue_.empty() && !quit_thread_) {
+      queue_condition_.wait(lock);
+    }
+    while (!log_queue_.empty()) {
+      output_stream_ << log_queue_.front();
+      log_queue_.pop();
+    }
+    output_stream_ << std::flush;
+    queue_condition_.notify_one();
+  }
+}
+  
+void Logger::Flush() {
+  // wait for the worker thread to empty the work queue
+  boost::mutex::scoped_lock lock(queue_mutex_);
+  while (!log_queue_.empty()) {
+    queue_condition_.wait(lock);
+  }
+}
+  
+} // logger namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/logger.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,63 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// Simple threadsafe logger class
+
+#pragma once
+
+#include "boost/shared_ptr.hpp"
+#include "boost/thread.hpp"
+
+#include <iostream>
+#include <queue>
+#include <string>
+
+namespace logger {
+
+class Logger {
+  std::ostream& output_stream_;
+  std::queue<std::string> log_queue_;
+  boost::mutex queue_mutex_;
+  boost::shared_ptr<boost::thread> logging_thread_;
+  boost::condition_variable queue_condition_;
+  bool quit_thread_;
+  
+public:
+  Logger();
+  ~Logger();
+  void LogMessage(const std::string& message);
+  void Flush();
+  
+  static Logger& Singleton() {
+    static Logger singleton;
+    return singleton;
+  }
+
+private:
+  void WorkerThread();
+};
+
+inline void Log(const std::string& message) {
+  Logger::Singleton().LogMessage(message);
+}
+
+inline void Flush() {
+  Logger::Singleton().Flush();
+}
+
+} // logger namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,162 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+#include "file_comparer.hpp"
+#include "graph_helpers.hpp"
+#include "logger.hpp"
+#include "population.hpp"
+#include "program_options.hpp"
+#include "sc_converter.hpp"
+#include "sc_default_grammar.hpp"
+#include "sc_evaluator.hpp"
+#include "sc_grammar.hpp"
+
+#include "boost/filesystem.hpp"
+#include "boost/shared_array.hpp"
+
+#include <algorithm>
+#include <ctime>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
+const std::string g_test_grammar_path = "/tmp/sc.json";
+
+template<typename T>
+void SaveToFile(const T& value, const std::string& file_path) {
+  std::ofstream file(file_path.c_str());
+  file << value;
+}
+
+void TestCrossover() {
+  sc::Grammar grammar(g_test_grammar_path);
+  sc::Converter converter(grammar);
+  sg::Graph parent_1;
+  sg::Graph parent_2;
+  grammar.SetMaximumDepth(2);
+  grammar.RandomGraph(parent_1);
+  grammar.RandomGraph(parent_2);
+  sg::Vertex crossover_1;
+  sg::Vertex crossover_2;
+  grammar.PickCrossoverNodes(parent_1, parent_2, &crossover_1, &crossover_2);
+  // swap the subtrees
+  sg::Graph child_1;
+  sg::Graph child_2;
+  SwapSubTrees(crossover_1, crossover_2, parent_1, parent_2, child_1, child_2);
+  SaveToFile(converter.ToDOT(parent_1), "/tmp/parent1.dot");
+  SaveToFile(converter.ToDOT(parent_2), "/tmp/parent2.dot");
+  SaveToFile(converter.ToDOT(child_1), "/tmp/child1.dot");
+  SaveToFile(converter.ToDOT(child_2), "/tmp/child2.dot");
+}
+
+void TestMutationReplaceSubtree() {
+  sc::Grammar grammar(g_test_grammar_path);
+  sc::Converter converter(grammar);
+  sg::Graph graph;
+  grammar.RandomGraph(graph);
+  SaveToFile(converter.ToDOT(graph), "/tmp/mutation_str_before.dot");
+  grammar.MutationReplaceSubTree(graph);
+  SaveToFile(converter.ToDOT(graph), "/tmp/mutation_str_after.dot");
+}
+
+void TestMutationReplaceCommand() {
+  sc::Grammar grammar(g_test_grammar_path);
+  sc::Converter converter(grammar);
+  sg::Graph graph;
+  grammar.SetMaximumDepth(3);
+  grammar.RandomGraph(graph);
+  SaveToFile(converter.ToDOT(graph), "/tmp/mutation_str_before.dot");
+  SaveToFile(converter.ToSynthDef(graph, "before"),
+             "/tmp/mutation_str_before.sc");
+  grammar.MutationReplaceCommand(graph);
+  SaveToFile(converter.ToDOT(graph), "/tmp/mutation_str_after.dot");
+  SaveToFile(converter.ToSynthDef(graph, "after"),
+             "/tmp/mutation_str_after.sc");
+}
+
+void TestMutationInsertCommand() {
+  sc::Grammar grammar(g_test_grammar_path);
+  sc::Converter converter(grammar);
+  sg::Graph graph;
+  grammar.SetMaximumDepth(4);
+  grammar.RandomGraph(graph);
+  SaveToFile(converter.ToDOT(graph), "/tmp/mutation_str_before.dot");
+  SaveToFile(converter.ToSynthDef(graph, "before"),
+             "/tmp/mutation_str_before.sc");
+  grammar.MutationInsertCommand(graph);
+  SaveToFile(converter.ToDOT(graph), "/tmp/mutation_str_after.dot");
+  SaveToFile(converter.ToSynthDef(graph, "after"),
+             "/tmp/mutation_str_after.sc");
+}
+
+void DoEvolution(const ProgramOptions& settings) {
+  // prepare the file comparer
+  dsp::FileComparer target(settings.fitness_features_,
+                           static_cast<int>(settings.analysis_window_size_),
+                           static_cast<int>(settings.analysis_hop_size_));
+  target.SetTargetFile(settings.target_path_);
+  // prepare the supercollider objects
+  std::string grammar_json;
+  if (settings.grammar_path_.empty()) {
+    grammar_json.assign(sc::g_default_grammar);
+  } else {
+    grammar_json = stdx::LoadFile(settings.grammar_path_);
+  }
+  sc::Grammar grammar(grammar_json);
+  grammar.SetMaximumDepth(static_cast<int>(settings.maximum_tree_depth_));
+  sc::Evaluator evaluator(grammar,
+                          settings.sc_app_path_,
+                          target,
+                          static_cast<int>(settings.core_limit_));
+  sc::Converter converter(grammar);
+  // set up the population
+  Population population(&grammar, &converter, &evaluator);
+  population.SetWorkFolder(settings.work_folder_);
+  population.SetFitnessThreshold(settings.fitness_threshold_);
+  population.SetCrossoverRate(settings.crossover_rate_);
+  population.SetMutationRate(settings.mutation_rate_);
+  population.SetTournamentSize(static_cast<int>(settings.tournament_size_));
+  population.SetReproduceBest(settings.reproduce_best_individual_);
+  population.InitializePopulation(settings.population_size_);
+  population.SetKeepTempFolders(settings.keep_temp_folders_);
+  // run the evolution loop
+  population.Evolve(static_cast<int>(settings.generations_));
+}
+
+int main(int argument_count, const char* arguments[])
+{
+  srand(static_cast<unsigned int>(time(NULL)));
+  try {
+    // parse the command line options
+    ProgramOptions settings;
+    ParseCommandLine(argument_count, arguments, &settings);
+    DoEvolution(settings);
+    
+    //TestCrossover();
+    //TestMutationReplaceSubtree();
+    //TestMutationInsertCommand();
+    //TestMutationReplaceCommand();
+  } catch (const std::exception& e) {
+    std::stringstream message;
+    message << "Exception: " << e.what() << '\n';
+    logger::Log(message.str());
+    logger::Flush();
+    return -1;
+  }
+  logger::Flush();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mfcc_analyzer.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,143 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+#include "mfcc_analyzer.hpp"
+
+#include "boost_ex.hpp"
+
+#include <algorithm>
+#include <cmath>
+#include <iostream>
+#include <iterator>
+#include <limits>
+#include <numeric>
+
+namespace {
+  
+// using the scale described in the HTK book
+double MelToHz(double mel) {
+  return 700.0 * (std::pow(10.0, mel / 2595.0) - 1.0);
+}
+
+double HzToMel(double hz) {
+  return 2595.0 * std::log10(1.0 + (hz / 700.0));
+}
+  
+} // namespace
+
+namespace dsp {
+
+MFCCAnalyzer::MFCCAnalyzer(int frame_size,
+                           int mel_bands,
+                           int number_of_mfccs,
+                           double frequency_min,
+                           double frequency_max)
+: frame_size_(frame_size),
+  mel_bands_(mel_bands),
+  number_of_mfccs_(number_of_mfccs),
+  sample_rate_(0),
+  frequency_min_(frequency_min),
+  frequency_max_(frequency_max)
+{
+  InitializeMelDCT();
+}
+  
+MFCCAnalyzer::~MFCCAnalyzer() {
+  fftw_free(mel_bands_dct_in_);
+  fftw_free(mel_bands_dct_out_);
+  fftw_destroy_plan(dct_plan_);
+}
+
+void MFCCAnalyzer::SetSampleRate(double sample_rate) {
+  if (sample_rate_ != sample_rate) {
+    sample_rate_ = sample_rate;
+    InitializeFilters();
+  }
+}
+
+// extracts mfccs from a magnitude spectrum
+const std::vector<double>&
+MFCCAnalyzer::ExtractMFCCS(const std::vector<double>& spectrum) {
+  // filter spectrum
+  for (std::size_t i = 0; i < mel_bands_; i++) {
+    mel_bands_dct_in_[i] = std::inner_product(spectrum.begin(),
+                                              spectrum.end(),
+                                              mel_filters_[i].begin(),
+                                              0.0);
+  }
+  // take the logs of the filter outputs (avoiding log(0) == -inf)
+  std::replace(mel_bands_dct_in_, mel_bands_dct_in_ + mel_bands_,
+               0.0, std::numeric_limits<double>::min());
+  std::transform(mel_bands_dct_in_, mel_bands_dct_in_ + mel_bands_,
+                 mel_bands_dct_in_,
+                 static_cast<double(*)(double)>(std::log10));
+  // take the DCT of the mel bands
+  fftw_execute(dct_plan_);
+  // store result
+  mfccs_.assign(mel_bands_dct_out_, mel_bands_dct_out_ + number_of_mfccs_);
+  return mfccs_;
+}
+
+void MFCCAnalyzer::InitializeMelDCT() {
+  int mem_size = sizeof(double) * mel_bands_;
+  mel_bands_dct_in_ = (double*)fftw_malloc(mem_size);
+  mel_bands_dct_out_ = (double*)fftw_malloc(mem_size);
+  dct_plan_ = fftw_plan_r2r_1d(number_of_mfccs_,
+                               mel_bands_dct_in_,
+                               mel_bands_dct_out_,
+                               FFTW_REDFT10,
+                               FFTW_ESTIMATE);
+}
+
+void MFCCAnalyzer::InitializeFilters() {
+  // create a series of triangular filters mapped linearly on the mel-frequency
+  // scale.
+  double bin_frequency = sample_rate_ / (2 * frame_size_);
+  double mel_min = HzToMel(frequency_min_);
+  double mel_max = HzToMel(frequency_max_);
+  double mel_width = (mel_max - mel_min) / (mel_bands_ + 1.0);
+  double mel_left = mel_min;
+  mel_filters_.resize(mel_bands_);
+  for (int i = 0; i < mel_bands_; i++) {
+    double mel_centre = mel_left + mel_width;
+    double mel_right = mel_centre + mel_width;
+    double left_hz = MelToHz(mel_left);
+    double right_hz = MelToHz(mel_right);
+    int bin_left = left_hz / bin_frequency + 0.5;
+    int bin_right = right_hz / bin_frequency + 0.5;
+    int bin_centre = (bin_left + bin_right) / 2.0 + 0.5;
+    double filter_height = 2.0 / (bin_right - bin_left);
+    mel_filters_[i].assign(frame_size_, 0.0);
+    // generate the up ramp
+    double bin_delta = filter_height / (bin_centre - bin_left);
+    double ramp = 0.0;
+    for (int bin = bin_left; bin < bin_centre; bin++) {
+      mel_filters_[i][bin] = ramp;
+      ramp += bin_delta;
+    }
+    // down ramp
+    for (int bin = bin_centre; bin < bin_right; bin++) {
+      mel_filters_[i][bin] = ramp;
+      ramp -= bin_delta;
+    }
+    // move mel bin along
+    mel_left += mel_width;
+  }
+}
+  
+} // dsp namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/mfcc_analyzer.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,61 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// MFCCAnalyzer - extracts MFCCs from a provided magnitude spectrum
+
+#pragma once
+
+#include "fftw3.h"
+
+#include <vector>
+
+namespace dsp {
+
+class MFCCAnalyzer {  
+  fftw_plan dct_plan_;
+  int frame_size_;
+  double sample_rate_;
+  double frequency_min_;
+  double frequency_max_;
+  std::vector< std::vector<double> > mel_filters_;
+  int mel_bands_;
+  int number_of_mfccs_;
+  std::vector<double> mfccs_;
+  double* mel_bands_dct_in_;
+  double* mel_bands_dct_out_;
+  
+public:
+  MFCCAnalyzer(int frame_size,
+               int mel_bands,
+               int number_of_mfccs,
+               double frequency_min,
+               double frequency_max);
+  
+  ~MFCCAnalyzer();
+  
+  void SetSampleRate(double sample_rate);
+  
+  // extracts mfccs from a magnitude spectrum
+  const std::vector<double>& ExtractMFCCS(const std::vector<double>& spectrum);
+  
+private:
+  void InitializeMelDCT();
+  void InitializeFilters();  
+};
+
+} // dsp namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/population.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,397 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+#include "population.hpp"
+
+#include "boost_ex.hpp"
+#include "graph_helpers.hpp"
+#include "logger.hpp"
+#include "statistics.hpp"
+#include "std_ex.hpp"
+
+#include "boost/bind.hpp"
+#include "boost/filesystem.hpp"
+#include "boost/lexical_cast.hpp"
+#include "boost/math/special_functions/fpclassify.hpp"
+
+#include <algorithm>
+#include <cmath>
+#include <fstream>
+#include <iterator>
+#include <limits>
+#include <map>
+#include <numeric>
+#include <set>
+#include <sstream>
+#include <vector>
+
+namespace bf = boost::filesystem;
+
+namespace {
+  
+  const std::string g_default_work_folder = "/tmp";
+  
+// mutated graphs might have imported parameters outside of the graph's range
+// or removed parameter inputs making some parameters redundant
+void UpdateParameters(sg::Graph& graph) {
+  std::size_t parameter_count = graph[boost::graph_bundle].parameters_.size();
+  // scan through vertices to find parameter inputs
+  std::map<int, std::vector<sg::Vertex> > parameters;
+  sg::VertexIterator vertex;
+  sg::VertexIterator vertex_end;
+  for (boost::tie(vertex, vertex_end) = boost::vertices(graph); 
+       vertex != vertex_end; 
+       ++vertex) {
+    const sg::Node& node_info = graph[*vertex];
+    if (node_info.type_ == sg::kParameter) {
+      parameters[node_info.id_].push_back(*vertex);
+    }
+  }
+  // check if any corrections required
+  if (parameters.size() == parameter_count) {
+    if (parameter_count == 0) {
+      // no parameters in the graph, nothing to do
+      return;
+    }
+    // check that last parameter id is correct, otherwise corrections are needed
+    if (parameters.rbegin()->first == (parameter_count)) {
+      // all seems well, get out of here
+      return;  
+    }
+  } else if (parameters.size() > parameter_count) {
+    // add extra parameters to the graph
+    std::generate_n(std::back_inserter(graph[boost::graph_bundle].parameters_),
+                    parameters.size() - parameter_count,
+                    stdx::RandomCoefficient);
+  } else {
+    // remove redundant parameters
+    graph[boost::graph_bundle].parameters_.resize(parameters.size());
+  }
+  // reassign parameter ids through the graph
+  int parameter_id = 1;
+  typedef std::map<int, std::vector<sg::Vertex> >::value_type ParameterMapping;
+  foreach (ParameterMapping p, parameters) {
+    foreach (sg::Vertex v, p.second) {
+      graph[v].id_ = parameter_id;
+    }
+    ++parameter_id;
+  }
+  // job done
+}
+
+} // namespace
+
+Population::Population(GrammarInterface* grammar,
+                       ConverterInterface* converter,
+                       EvaluatorInterface* evaluator)
+: grammar_(grammar),
+  converter_(converter),
+  evaluator_(evaluator),
+  generation_(0),
+  max_generations_(0),
+  fitness_threshold_(0),
+  tournament_size_(7),
+  crossover_rate_(0.65),
+  mutation_rate_(0.3),
+  reproduce_best_(false),
+  keep_temp_folders_(false)
+{
+  evaluator_->SetListener(this);
+  mutators_.push_back(boost::bind(&GrammarInterface::MutationReplaceSubTree,
+                                  grammar, _1));
+  mutators_.push_back(boost::bind(&GrammarInterface::MutationAddSubTree,
+                                  grammar, _1));
+  mutators_.push_back(boost::bind(&GrammarInterface::MutationModifyInputs,
+                                  grammar, _1));
+  mutators_.push_back(boost::bind(&GrammarInterface::MutationModifyConnections,
+                                  grammar, _1));
+  mutators_.push_back(boost::bind(&GrammarInterface::MutationReplaceCommand,
+                                  grammar, _1));
+//  mutators_.push_back(boost::bind(&GrammarInterface::MutationInsertCommand,
+//                                  grammar, _1));
+  SetupGeneticOperationSelector();
+  SetWorkFolder(g_default_work_folder);
+}
+
+void Population::SetWorkFolder(const std::string &path) {
+  work_folder_ = path;
+  log_folder_ = path + "/logs";
+  render_folder_ = path + "/render";
+  dot_folder_ = path + "/dot";
+  export_folder_ = path + "/export";
+}
+
+void Population::Evolve(int max_generations) {
+  max_generations_ = max_generations;
+  // make sure the folders for storing best outputs are created
+  bf::create_directories(render_folder_);
+  bf::create_directories(dot_folder_);
+  bf::create_directories(export_folder_);
+  bf::create_directories(log_folder_);
+  for (generation_ = 1; generation_ <= max_generations; generation_++) {
+    NewGenerationMessage();
+    SetGenerationFolder();
+    ExportToDOT();
+    EvaluateGeneration();
+    AnalyzeGeneration();
+    SaveGenerationBest();
+    CleanTempFolders();
+    if (CheckThreshold()) {
+      logger::Log("Fitness threshold reached\n");
+      return;
+    }
+    BreedNewGeneration();
+  }
+}
+
+void Population::NewGenerationMessage() const {
+  std::stringstream message;
+  message << "Generation " << generation_ << '\n';
+  logger::Log(message.str());
+}
+
+void Population::SetGenerationFolder() {
+  std::stringstream path;
+  path << work_folder_ << "/generation_" 
+       << std::setw(std::log10(max_generations_) + 1) << std::setfill('0')
+       << generation_ << '/';
+  generation_folder_ = path.str();
+}
+
+bool Population::CheckThreshold() const {
+  double best_fitness = population_[best_fit_][boost::graph_bundle].fitness_;
+  return best_fitness <= fitness_threshold_;
+}
+
+void Population::CleanTempFolders() const {
+  if (!keep_temp_folders_) {
+    bf::remove_all(generation_folder_);
+  }
+}
+
+void Population::InitializePopulation(std::size_t size) {
+  population_.resize(size);
+  fitnesses_.resize(size);
+  for (int i = 0; i < size; i++) {
+    grammar_->RandomGraph(population_[i]);
+    population_[i][boost::graph_bundle].id_ = i;
+  }
+}
+
+void Population::EvaluateGeneration() {
+  // make sure we have a clean temp folder for the generation
+  bf::remove_all(generation_folder_);
+  evaluator_->SetWorkFolder(generation_folder_);
+  evaluator_->RateGraphs(population_);
+  logger::Log("\n");
+  // store graph fitnesses
+  for (std::size_t i = 0, size = population_.size(); i < size; i++) {
+    fitnesses_[i] = population_[i][boost::graph_bundle].fitness_;
+  }
+}
+
+void Population::AnalyzeGeneration() {
+  double mean_fitness = stats::Mean(fitnesses_.begin(), fitnesses_.end());
+  if (boost::math::isnan(mean_fitness)) {
+    logger::Log("ruh roh\n"); // TODO
+  }
+  std::stringstream message;
+  std::vector<double>::const_iterator best_fitness;
+  best_fitness = std::min_element(fitnesses_.begin(), fitnesses_.end());
+  best_fit_ = static_cast<int>(best_fitness - fitnesses_.begin());
+  message << "Average Fitness:" << mean_fitness
+          << " Best"
+          //<< " [" << best_fit_ << "]"
+          << ':' << *best_fitness << '\n';
+  logger::Log(message.str());
+  // save fitness values to logs
+  std::stringstream average;
+  average << generation_ << ' ' << mean_fitness;
+  stdx::AppendToFile(average.str(), log_folder_ + "/average_fitnesses.txt");
+  std::stringstream best;
+  best << generation_ << ' ' << *best_fitness;
+  stdx::AppendToFile(best.str(), log_folder_ + "/best_fitnesses.txt");
+}
+
+void Population::SaveGenerationBest() {
+  std::stringstream generation_prefix;
+  generation_prefix << "generation_" 
+                    << std::setw(std::log10(max_generations_) + 1) 
+                    << std::setfill('0')
+                    << generation_;
+  const sg::Graph& best_graph = population_[best_fit_];
+  const sg::GraphProperties& graph_properties = best_graph[boost::graph_bundle];
+  // copy the rendered output for the graph
+  bf::path path = graph_properties.render_path_;
+  if (bf::exists(path)) {
+    std::string render_path = render_folder_ + '/' 
+                              + generation_prefix.str() 
+                              + path.extension().string();
+    bf::copy_file(path, render_path);
+  }
+  // copy the dot script for the graph
+  path = graph_properties.dot_path_;
+  if (bf::exists(path)) {
+    std::string dot_path = dot_folder_ + '/' 
+                           + generation_prefix.str() 
+                           + path.extension().string();
+    bf::copy_file(path, dot_path);
+  }
+  // tell the converter to export the graph
+  converter_->Export(best_graph, export_folder_, generation_prefix.str());
+}
+
+void Population::PerformCrossover(sg::Graph& child_1, sg::Graph& child_2) {
+  int parent_id_1 = SelectIndividual();
+  int parent_id_2;
+  do {
+    parent_id_2 = SelectIndividual(); 
+  } while (parent_id_1 == parent_id_2);
+  // pick the crossover points via the grammar
+  const sg::Graph& parent_1 = population_[parent_id_1];
+  const sg::Graph& parent_2 = population_[parent_id_2];
+  sg::Vertex crossover_1;
+  sg::Vertex crossover_2;
+  grammar_->PickCrossoverNodes(parent_1, parent_2, &crossover_1, &crossover_2);
+  // swap the subtrees
+  SwapSubTrees(crossover_1, crossover_2, parent_1, parent_2, child_1, child_2);
+}
+
+// called for mutated graphs to prepare for next generation
+void Population::PrepareNewChild(sg::Graph& child) {
+  // reset fitness rating
+  child[boost::graph_bundle].fitness_ = sg::kFitnessUnrated;
+  // make sure parameters in graph are valid
+  UpdateParameters(child);
+}
+
+void Population::BreedNewGeneration() {
+  // Used to store reproduced graph ids, prevents a graph being reproduced
+  // more than once.
+  std::set<int> reproduced;
+  std::vector<sg::Graph> next_generation;
+  next_generation.reserve(population_.size());
+  if (reproduce_best_) {
+    next_generation.push_back(population_[best_fit_]);
+  }
+  std::size_t population_size = population_.size();
+  while (next_generation.size() < population_size) {
+    GeneticOperation operation;
+    operation = static_cast<GeneticOperation>(genetic_operation_selector_());
+    if (operation == kCrossover) {
+      // Crossover
+      // create two empty graphs to receive results of crossover
+      // (creating them directly in the next_generation container causes
+      // memory problems when performing crossover, couldn't fathom why..)
+      sg::Graph child_1;
+      sg::Graph child_2;
+      PerformCrossover(child_1, child_2);
+      PrepareNewChild(child_1);
+      PrepareNewChild(child_2);
+      next_generation.push_back(child_1);
+      next_generation.push_back(child_2);
+    } else if (operation == kMutation) {
+      // mutation
+      // store a copy of an individual from current population
+      next_generation.push_back(population_[SelectIndividual()]);
+      sg::Graph& child = next_generation.back();
+      // call random mutation operator on child
+      bool mutated;
+      do {
+        // some mutators might not be able to operate on a specific graph
+        // and will return false, so try another mutator
+        mutated = mutators_[stdx::Random(mutators_.size())](child);
+      } while (!mutated);
+      PrepareNewChild(child);
+    } else {
+      // reproduction
+      int graph_id = SelectIndividual();
+      // only reproduce the individual if it hasn't already been reproduced
+      if (reproduced.find(graph_id) == reproduced.end()) {
+        next_generation.push_back(population_[graph_id]);
+        reproduced.insert(graph_id);
+      }
+    }
+  }
+  // we might have an extra individual from crossover
+  next_generation.resize(population_size);
+  // reassign graph ids
+  for (std::size_t i = 0, size = population_.size(); i < size; i++) {
+    next_generation[i][boost::graph_bundle].id_ = static_cast<int>(i);
+  }
+  // replace the population with the newly created generation
+  population_.swap(next_generation);
+}
+
+// tournament selection 
+int Population::SelectIndividual() {
+  // select n individuals from the population
+  std::set<std::size_t> tournament;
+  while (tournament.size() < tournament_size_) {
+    tournament.insert(stdx::Random(population_.size()));
+  }
+  double best_fitness = std::numeric_limits<double>::max();
+  std::size_t result = -1;
+  // find best graph from selection
+  foreach (std::size_t graph_id, tournament) {
+    if (fitnesses_[graph_id] < best_fitness) {
+      best_fitness = fitnesses_[graph_id];
+      result = graph_id;
+    }
+  }
+  return static_cast<int>(result);
+}
+
+void Population::ExportToDOT() {
+  std::string dot_folder = generation_folder_ + "/dot/";
+  bf::create_directories(dot_folder);
+  std::stringstream path;
+  foreach (sg::Graph& graph, population_) {
+    path.str("");
+    path << dot_folder 
+         << "gpsynth_" << graph[boost::graph_bundle].id_ << ".dot";
+    std::ofstream file(path.str().c_str());
+    file << converter_->ToDOT(graph);
+    file.close();
+    graph[boost::graph_bundle].dot_path_ = path.str();
+  }
+}
+
+void Population::GraphRatedNotification(std::size_t graphs_rated) {
+  std::stringstream message;
+  message << "\rRated " << graphs_rated << " / " << population_.size();
+  logger::Log(message.str());
+}
+
+void Population::SetCrossoverRate(double rate) {
+  crossover_rate_ = rate;
+  SetupGeneticOperationSelector();
+}
+
+void Population::SetMutationRate(double rate) {
+  mutation_rate_ = rate;
+  SetupGeneticOperationSelector();
+}
+
+void Population::SetupGeneticOperationSelector() {
+  std::vector<double> genetic_probabilities(2);
+  genetic_probabilities[kCrossover] = crossover_rate_;
+  genetic_probabilities[kMutation] = mutation_rate_;
+  // reproduction is left over probability
+  genetic_operation_selector_.SetProbabilities(genetic_probabilities);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/population.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,109 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// Population class, manages a population of synth graphs and their evolution
+
+// TODO - split out evolution behaviour in to a separate class, support
+// multiple populations
+
+#pragma once
+
+#include "converter.hpp"
+#include "evaluator.hpp"
+#include "grammar.hpp"
+#include "statistics.hpp"
+#include "synth_graph.hpp"
+
+#include "boost/function.hpp"
+
+#include <string>
+#include <vector>
+
+typedef boost::function<bool (sg::Graph&)> MutationOperator;
+
+class Population : public EvaluatorListenerInterface {
+  std::vector<sg::Graph> population_;
+  int best_fit_;
+  std::vector<double> fitnesses_;
+  // current generation
+  int generation_;
+  // total generations
+  int max_generations_;
+  int tournament_size_;
+  double fitness_threshold_;
+  double crossover_rate_;
+  double mutation_rate_;
+  bool reproduce_best_;
+  bool keep_temp_folders_;
+  GrammarInterface* grammar_;
+  ConverterInterface* converter_;
+  EvaluatorInterface* evaluator_;
+  // work folder, where all files for current run are placed
+  std::string work_folder_;
+  // folder to write logs to
+  std::string log_folder_;
+  // folder to save best renders
+  std::string render_folder_;
+  // folder to save best dot scripts
+  std::string dot_folder_;
+  // folder to save exported graphs
+  std::string export_folder_;
+  // temp folder for current generation
+  std::string generation_folder_;
+  // available mutation operators
+  std::vector<MutationOperator> mutators_;
+  // selector for genetic operations
+  stats::ProbabilitySelector genetic_operation_selector_;
+  
+  enum GeneticOperation {
+    kCrossover,
+    kMutation,
+    kReproduction
+  };
+  
+public:
+  Population(GrammarInterface* grammar,
+             ConverterInterface* converter,
+             EvaluatorInterface* evaluator);
+  
+  void InitializePopulation(std::size_t size);
+  void SetWorkFolder(const std::string& path);
+  void SetFitnessThreshold(double value) { fitness_threshold_ = value; }
+  void SetTournamentSize(int size) { tournament_size_ = size; }
+  void Evolve(int generations);
+  void ExportToDOT();
+  void SetCrossoverRate(double rate);
+  void SetMutationRate(double rate);
+  void SetReproduceBest(bool value) { reproduce_best_ = value; }
+  void SetKeepTempFolders(bool value) { keep_temp_folders_ = value; }
+  
+private:
+  void EvaluateGeneration();
+  void AnalyzeGeneration();
+  void BreedNewGeneration();
+  int SelectIndividual();
+  void PerformCrossover(sg::Graph& child_1, sg::Graph& child_2);
+  void PrepareNewChild(sg::Graph& child);
+  void GraphRatedNotification(std::size_t graphs_rated);
+  void SetupGeneticOperationSelector();
+  void SaveGenerationBest();
+  bool CheckThreshold() const;
+  void CleanTempFolders() const;
+  void NewGenerationMessage() const;
+  void SetGenerationFolder();
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/precompiled_header.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,62 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// commonly used external libraries
+// code should compile correctly without using precompiled header
+
+#include "boost/algorithm/string/replace.hpp"
+#include "boost/bind.hpp"
+#include "boost/date_time/posix_time/posix_time.hpp"
+#define BOOST_FILESYSTEM_NO_DEPRECATED
+#include "boost/filesystem.hpp"
+#include "boost/foreach.hpp"
+#include "boost/format.hpp"
+#include "boost/function.hpp"
+#include "boost/graph/adjacency_list.hpp"
+#include "boost/graph/graphviz.hpp"
+#include "boost/graph/random.hpp"
+#include "boost/graph/topological_sort.hpp"
+#include "boost/lexical_cast.hpp"
+#include "boost/math/special_functions/fpclassify.hpp"
+#include "boost/random/mersenne_twister.hpp"
+#include "boost/random/normal_distribution.hpp"
+#include "boost/random/variate_generator.hpp"
+#include "boost/shared_array.hpp"
+#include "boost/shared_ptr.hpp"
+#include "boost/thread.hpp"
+#include "boost/tuple/tuple.hpp"
+
+#include "fftw3.h"
+
+#include "json.h"
+
+#include <cmath>
+#include <cstddef>
+#include <ctime>
+#include <iostream>
+#include <iterator>
+#include <fstream>
+#include <limits>
+#include <map>
+#include <numeric>
+#include <queue>
+#include <set>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/program_options.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,180 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+#include "program_options.hpp"
+
+#include "boost/filesystem.hpp"
+#include "boost/program_options.hpp"
+
+#include <ctime>
+
+namespace bf = boost::filesystem;
+namespace bo = boost::program_options;
+
+namespace {
+
+const std::string g_default_sc_app_path = "/Applications/SuperCollider";
+
+void PrintHelpAndQuit(const bo::options_description& options,
+                      int exit_code = 0) {
+  bo::arg = "value";
+  std::cout << '\n' << options << std::endl;
+  exit(exit_code);
+}
+
+std::string GetTimeString() {
+  std::time_t raw_time;
+  time(&raw_time);
+  tm* time_info = localtime(&raw_time);
+  char buffer[20];
+  strftime(buffer, 20, "%Y-%m-%d_%H:%M:%S", time_info);
+  return buffer;
+}
+
+  
+} // namespace
+
+
+void ParseCommandLine(int argument_count,
+                      const char* arguments[],
+                      ProgramOptions* options) {
+  bo::options_description description;
+  description.add_options()
+  ("help,?", "Displays this message")
+  ("target,t",
+   bo::value<std::string>(&options->target_path_)->required(),
+   "Target sound file path")
+  ("grammar,g",
+   bo::value<std::string>(&options->grammar_path_),
+   "Grammar file path")
+  ("scpath,s", 
+   bo::value<std::string>(&options->sc_app_path_),
+   "Path to SuperCollider application folder")
+  ("workfolder,w", 
+   bo::value<std::string>(&options->work_folder_),
+   "Path of folder to place files in")
+  ("population,p",
+   bo::value<std::size_t>(&options->population_size_)->default_value(500),
+   "Population size")
+  ("generations,G",
+   bo::value<std::size_t>(&options->generations_)->default_value(20),
+   "Number of Generations")
+  ("fitness,f",
+   bo::value<double>(&options->fitness_threshold_)->default_value(0),
+   "Fitness threshold")
+  ("tournament,T",
+   bo::value<std::size_t>(&options->tournament_size_)->default_value(7),
+   "Tournament selection size")
+  ("crossover,c",
+   bo::value<double>(&options->crossover_rate_)->default_value(0.6, "0.6"),
+   "Crossover rate")
+  ("mutation,m",
+   bo::value<double>(&options->mutation_rate_)->default_value(0.35, "0.35"),
+   "Mutation rate")
+  ("reproducebest,r",
+   bo::value<bool>(&options->reproduce_best_individual_)->default_value(false),
+   "Automatically reproduce best individual when populating next generation.")
+  ("features,F",
+   bo::value<std::string>(&options->fitness_features_),
+   "Set of features that the fitness function will measure when comparing files."
+   " Must be a comma separated list of feature names, which can be any of the following:"
+   " pitch, energy, mfccs, dmfccs, ddmfccs, mag, logmag, centroid, spread, flux."
+   " Default value is 'mfccs,dmfccs,ddmfccs'.")
+  ("windowsize,w",
+   bo::value<std::size_t>(&options->analysis_window_size_)->default_value(1024),
+   "Analysis Window Size")
+  ("hopsize,h",
+   bo::value<std::size_t>(&options->analysis_hop_size_)->default_value(256),
+   "Analysis Hop Size")
+  ("maxtreedepth,M",
+   bo::value<std::size_t>(&options->maximum_tree_depth_)->default_value(3),
+   "Maximum generated tree depth (can grow bigger through mutation).")
+  ("keepfolders,k",
+   bo::value<bool>(&options->keep_temp_folders_)->default_value(false),
+   "When set to 1 the temporary generation folders won't be deleted")
+  ("corelimit,C",
+   bo::value<std::size_t>(&options->core_limit_)->default_value(0),
+   "Limits the number of cores gpsynth will use simultaneously, 0=unlimited.")
+  ;
+  
+  bo::command_line_parser parser(argument_count, arguments);
+  parser.options(description);
+  bo::variables_map config;
+  try {
+    bo::store(parser.run(), config);
+    bo::notify(config);
+  } catch (std::exception& e) {
+    std::cout << "Error parsing options: " << e.what() << ".\n";
+    PrintHelpAndQuit(description, -1);
+  }
+  
+  if (config.count("help")) {
+    PrintHelpAndQuit(description);
+  }
+  
+  if (config.count("workfolder") == 0) {
+    options->work_folder_ = bf::current_path().string();
+  }
+  // validate the work folder path
+  if (!bf::is_directory(options->work_folder_)) {
+    std::cout << "Work folder path '" << options->work_folder_ 
+              << "' doesn't exist.\n";
+    exit(-1);
+  }
+  options->work_folder_ += "/gpsynth_" + GetTimeString() + "/";
+  
+  if (config.count("scpath") == 0) {
+    options->sc_app_path_ = g_default_sc_app_path;
+  }
+  if (!bf::is_directory(options->sc_app_path_)) {
+    std::cout << "SC App path '" << options->sc_app_path_ 
+              << "' doesn't exist.\n";
+    exit(-1);
+  }
+  
+  if (options->tournament_size_ < 1) {
+    std::cout << "Tournament size must be greater than zero.\n";
+    exit(-1);
+  }
+  
+  if (options->tournament_size_ > options->population_size_) {
+    std::cout << "Tournament size can not be larger than population size.\n";
+    exit(-1);
+  }
+  
+  if (options->crossover_rate_ < 0 || options->crossover_rate_ > 1) {
+    std::cout << "The crossover rate should be between 0-1.\n";
+    exit(-1);
+  }
+  
+  if (options->mutation_rate_ < 0 || options->mutation_rate_ > 1) {
+    std::cout << "The mutation rate should be between 0-1.\n";
+    exit(-1);
+  }
+  
+  if (options->maximum_tree_depth_ < 1) {
+    std::cout << "Maximum tree depth must be greater than zero.\n";
+    exit(-1);
+  }
+  
+  if (options->fitness_features_.empty()) {
+    options->fitness_features_ = "mfccs,dmfccs,ddmfccs";
+  }
+}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/program_options.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,47 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// command line options handler
+
+#pragma once
+
+#include <string>
+
+struct ProgramOptions {
+  std::string target_path_;
+  std::string grammar_path_;
+  std::string sc_app_path_;
+  std::string work_folder_;
+  std::string fitness_features_;
+  std::size_t population_size_;
+  std::size_t generations_;
+  std::size_t tournament_size_;
+  double fitness_threshold_;
+  double crossover_rate_;
+  double mutation_rate_;
+  bool reproduce_best_individual_;
+  std::size_t analysis_window_size_;
+  std::size_t analysis_hop_size_;
+  std::size_t maximum_tree_depth_;
+  bool keep_temp_folders_;
+  std::size_t core_limit_;
+};
+
+void ParseCommandLine(int argument_count,
+                      const char* arguments[],
+                      ProgramOptions* options);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/range.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,201 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+#pragma once
+
+#include <ostream>
+
+namespace stdx {
+
+// like std::pair, designed for minimum/maximum
+template<typename T>
+struct Range {
+  T minimum_;
+  T maximum_;
+
+  Range()
+  : minimum_(T()),
+    maximum_(T())
+  {}
+  
+  Range(T minimum, T maximum)
+  : minimum_(minimum),
+    maximum_(maximum)
+  {}
+
+  template<typename T2>
+  Range(const Range<T2>& other)
+  : minimum_(other.minimum_),
+    maximum_(other.maximum_)
+  {}
+
+  // getters / setters
+  T Minimum() const { return minimum_; }
+  T Maximum() const { return maximum_; }
+
+  void SetMinimum(const T& value) { minimum_ = value; }
+  void SetMaximum(const T& value) { maximum_ = value; }
+
+  void SetRange(const T& minimum, const T& maximum) {
+    minimum_ = minimum;
+    maximum_ = maximum;
+  }
+
+  T Size() const { return maximum_ - minimum_; }
+  
+  // Assignment operators
+  template<typename T2>
+  void operator=(const Range<T2>& other) {
+    minimum_ = other.minumum_;
+    maximum_ = other.maximum_;
+  }
+
+  template<typename T2>
+  Range<T>& operator+=(const Range<T2>& other) {
+    minimum_ += other.minimum_;
+    maximum_ += other.maximum_;
+    return *this;
+  }
+  template<typename T2>
+  Range<T>& operator+=(const T2& value) {
+    minimum_ += value;
+    maximum_ += value;
+    return *this;
+  }
+
+  template<typename T2>
+  Range<T>& operator-=(const Range<T2>& other) {
+    minimum_ -= other.minimum_;
+    maximum_ -= other.maximum_;
+    return *this;
+  }
+  template<typename T2>
+  Range<T>& operator-=(const T2& value) {
+    minimum_ -= value;
+    maximum_ -= value;
+    return *this;
+  }
+
+  template<typename T2>
+  Range<T>& operator*=(const T2& value) {
+    minimum_ *= value;
+    maximum_ *= value;
+    return *this;
+  }
+  template<typename T2>
+  Range<T>& operator/=(const T2& value) {
+    minimum_ /= value;
+    maximum_ /= value;
+    return *this;
+  }
+
+
+  // Arithmetic
+  template<typename T2>
+  Range<T> operator+(const T2& value) {
+    return Range<T>(minimum_ + value, maximum_ + value);
+  }
+  template<typename T2>
+  Range<T> operator+(const Range<T2>& other) {
+    return Range<T>(minimum_ + other.minimum_, maximum_ + other.maximum_);
+  }
+
+  template<typename T2>
+  Range<T> operator-(const T2& value) {
+    return Range<T>(minimum_ - value, maximum_ - value);
+  }
+  template<typename T2>
+  Range<T> operator-(const Range<T2>& other) {
+    return Range<T>(minimum_ - other.minimum_, maximum_ - other.maximum_);
+  }
+
+  template<typename T2>
+  Range<T> operator*(const T2& value) {
+    return Range<T>(minimum_ * value, maximum_ * value);
+  }
+  template<typename T2>
+  Range<T> operator/(const T2& value) {
+    return Range<T>(minimum_ / value, maximum_ / value);
+  }
+
+  // Increments/Decrements
+  Range<T>& operator++() {
+    ++minimum_;
+    ++maximum_;
+    return *this;
+  }
+  Range<T>& operator--() {
+    --minimum_;
+    --maximum_;
+    return *this;
+  }
+
+  Range<T> operator++(int) {
+    Range<T> temp(*this);
+    ++(*this);
+    return temp;
+  }
+  Range<T> operator--(int) {
+    Range<T> temp(*this);
+    --(*this);
+    return temp;
+  }
+
+};
+
+// Comparison operators
+template<typename T>
+bool operator==(const Range<T>& x, const Range<T>& y) {
+  return (x.minimum_ == y.minimum_) && (x.maximum_ == y.maximum_);
+}
+
+template<typename T>
+bool operator<(const Range<T>& x, const Range<T>& y) {
+  return (x.minimum_ < y.minimum_)
+         || (!(y.minimum_ < x.minimum_) && (x.maximum_ < y.maximum_));
+}
+
+template<typename T>
+bool operator!=(const Range<T>& x, const Range<T>& y) {
+  return !(x == y);
+}
+
+template<typename T>
+bool operator>(const Range<T>& x, const Range<T>& y) {
+  return y < x;
+}
+
+template<typename T>
+bool operator<=(const Range<T>& x, const Range<T>& y) {
+  return !(y < x);
+}
+
+template<typename T>
+bool operator>=(const Range<T>& x, const Range<T>& y) {
+  return !(x < y);
+}
+
+// Output
+template<typename T>
+std::ostream& operator<<(std::ostream& out, const Range<T>& range) {
+  out << '[' << range.minimum_ << ',' << range.maximum_ << ']';
+  return out;
+}
+
+} // stdx namespace
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sc_converter.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,449 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+#include "sc_converter.hpp"
+
+#include "boost_ex.hpp"
+#include "logger.hpp"
+
+#include "boost/graph/graphviz.hpp"
+#include "boost/graph/topological_sort.hpp"
+
+#include <iomanip>
+#include <fstream>
+
+
+namespace {
+
+const std::string g_VariablePrefix("v");
+const std::string g_ArgumentPrefix("arg_");
+const int g_label_decimal_places = 2;
+  
+} // namespace
+
+
+namespace sc {
+
+// picks the lowest available variable for a command, or creates a new one 
+int Converter::AssignVariable(sg::Vertex vertex) {
+  int variable;
+  if (available_variables_.size() > 0) {
+    std::set<int>::iterator lowest_variable = available_variables_.begin();
+    variable = *(lowest_variable);
+    available_variables_.erase(lowest_variable);
+  } else {
+    variable = variables_created_++;
+  }
+  // store the command's variable
+  variable_map_[vertex] = variable;
+  return variable;
+}
+
+// retrieves the assigned variable for a specific command vertex
+int Converter::GetVariable(sg::Vertex vertex) {
+  int variable = variable_map_[vertex];
+  variable_map_.erase(vertex);
+  available_variables_.insert(variable);
+  return variable;
+}
+
+void Converter::SynthDefSpecial(sg::Vertex vertex,
+                                const sg::Node& node,
+                                const sg::Graph& graph) {
+  if ((node.id_ == sc::Command::kMixer)
+      || (node.id_ == sc::Command::kMultiplier)) {
+    // e.g. v0 + v1 + v2
+    command_script_ << '\t';
+    // is this the root mixer?
+    bool root_command = (boost::out_degree(vertex, graph) == 0);
+    if (root_command) {
+      command_script_ << "Out.ar([0, 1], ";
+    } else {
+      command_script_ << g_VariablePrefix << AssignVariable(vertex) << " = ";
+    }
+    // clip output
+    command_script_ << "Clip.";
+    if (node.rate_ == sg::kAudioRate) {
+      command_script_ << "ar(";
+    } else {
+      command_script_ << "kr(";
+    }
+    // process command parameter, based on vertex inputs
+    sg::Graph::in_edge_iterator in_edge;
+    sg::Graph::in_edge_iterator in_edge_end;
+    bool first_argument = true;
+    bool parentheses = (boost::in_degree(vertex, graph) > 1);
+    // get separator for this command
+    std::string separator;
+    if (node.id_ == sc::Command::kMixer) {
+      separator = " + ";
+    } else {
+      separator = " * ";
+    }
+    for (boost::tie(in_edge, in_edge_end) = boost::in_edges(vertex, graph);
+         in_edge != in_edge_end;
+         ++in_edge) {
+      const sg::Connection& connection = graph[*in_edge];
+      if (!first_argument) {
+        command_script_ << separator;
+      } else {
+        first_argument = false;
+      }
+      const sg::Vertex& source_vertex = boost::source(*in_edge, graph);
+      const sg::Node& source = graph[source_vertex];
+      sg::NodeType source_type = source.type_;
+      if (source_type == sg::kConstant) {
+        // calculate weighted constant value 
+        double value = source.constant_value_;
+        command_script_ << (value * connection.weight_ + connection.offset_);
+      } else {
+        if (parentheses) {
+          command_script_ << '(';
+        }
+        if (source_type == sg::kParameter) {
+          command_script_ << g_ArgumentPrefix << source.id_;
+        } else if (source_type == sg::kCommand) {
+          command_script_ << g_VariablePrefix << GetVariable(source_vertex);
+        } else if (source_type == sg::kSpecial) {
+          command_script_ << g_VariablePrefix << GetVariable(source_vertex);
+        }
+        if (connection.weight_ != 1) {
+          command_script_ << " * " << connection.weight_;
+        }
+        if (connection.offset_ != 0) {
+          command_script_ << " + " << connection.offset_;
+        }
+        if (parentheses) {
+          command_script_ << ')';
+        }
+      }
+    }
+    // end of Clip command
+    if (node.rate_ == sg::kAudioRate) {
+      command_script_ << ", -1, 1)";
+    } else {
+      command_script_ << ", 0, 1)";
+    }
+    // end of Out.ar command for root mixer
+    if (root_command) {
+      command_script_ << ')';
+    }
+    command_script_ << ";\n";
+  }
+}
+
+void Converter::SynthDefCommand(sg::Vertex vertex,
+                                const sg::Node& node,
+                                const sg::Graph& graph) {
+  const sc::Command& command = commands_[node.id_];
+  command_script_ << '\t';
+  command_script_ << g_VariablePrefix << AssignVariable(vertex) << " = ";
+  command_script_ << command.Name() << '.';
+  // command type
+  if (node.rate_ == sg::kAudioRate) {
+    command_script_ << "ar(";
+  } else {
+    command_script_ << "kr(";
+  }
+  // command inputs
+  sg::Graph::in_edge_iterator in_edge;
+  sg::Graph::in_edge_iterator in_edge_end;
+  bool first_argument = true;
+  for (boost::tie(in_edge, in_edge_end) = boost::in_edges(vertex, graph);
+       in_edge != in_edge_end;
+       ++in_edge) {
+    const sg::Connection& connection = graph[*in_edge];
+    const sc::Argument& argument = command.GetArgument(connection.input_);
+    if (!first_argument) {
+      command_script_ << ", ";
+    } else {
+      first_argument = false; 
+    }
+    // argument value
+    command_script_ << argument.name_ << ": ";
+    const sg::Vertex& source_vertex = boost::source(*in_edge, graph);
+    const sg::Node& source = graph[source_vertex];
+    sg::NodeType source_type = source.type_;
+    if (source_type == sg::kConstant) {
+      // calculate weighted constant value 
+      double value = source.constant_value_;
+      command_script_ << (value * connection.weight_ + connection.offset_);
+    } else {
+      if (source_type == sg::kParameter) {
+        command_script_ << g_ArgumentPrefix << source.id_;
+      } else if (source_type == sg::kCommand) {
+        command_script_ << g_VariablePrefix << GetVariable(source_vertex);
+      } else if (source_type == sg::kSpecial) {
+        command_script_ << g_VariablePrefix << GetVariable(source_vertex);
+      }
+      if (connection.weight_ != 1) {
+        command_script_ << " * " << connection.weight_;
+      }
+      if (connection.offset_ != 0) {
+        command_script_ << " + " << connection.offset_;
+      }
+    }
+  }
+  // write preset constant arguments
+  foreach (const sc::Argument& argument, command.Arguments()) {
+    if (argument.scaling_mode_ == sc::Argument::kConstant) {
+      if (!first_argument) {
+        command_script_ << ", ";
+      }
+      first_argument = false;
+      command_script_ << argument.name_ << ": " << argument.constant_value_;
+    }
+  }
+  //command end
+  command_script_ << ");\n";
+}
+  
+// convert a given vertex
+void Converter::SynthDefVertex(sg::Vertex vertex, const sg::Graph& graph) {
+  const sg::Node& node = graph[vertex];
+  sg::NodeType type = node.type_;
+  if (type == sg::kSpecial) {
+    SynthDefSpecial(vertex, node, graph);
+  }
+  if (type == sg::kCommand) {
+    SynthDefCommand(vertex, node, graph);
+  }
+}
+
+// prepares a synthdef from a synth graph
+std::string Converter::ToSynthDef(const sg::Graph& graph,
+                                  const std::string& synth_name,
+                                  bool convert_for_realtime,
+                                  const std::string& synthdef_path) {
+  command_script_.str("");
+  variable_map_.clear();
+  variables_created_ = 0;
+  available_variables_.clear();
+  
+  // preamble
+  std::stringstream synth_def;
+  synth_def << "SynthDef(\"" << synth_name << "\", {\n";
+  // arguments
+  std::size_t parameters = graph[boost::graph_bundle].parameters_.size();
+  if (parameters > 0) {
+    synth_def << "\targ ";
+    for (std::size_t i = 1; i <= parameters; i++) {
+      synth_def << g_ArgumentPrefix << i;
+      if (i < parameters) {
+        synth_def << ", ";
+      }
+    }
+    synth_def << ";\n";
+  }
+  // commands
+  std::vector<sg::Vertex> vertices;
+  vertices.reserve(boost::num_vertices(graph));
+  // perform topological sort on graph to find dependency order
+  boost::topological_sort(graph, std::back_inserter(vertices));
+  // traverse commands in reversed topological order
+  std::map<sg::Vertex, int> variable_map;
+  foreach_reverse (sg::Vertex& vertex, vertices) {
+    SynthDefVertex(vertex, graph);
+  }
+  // declare variables required by the commands
+  if (variables_created_ > 0) {
+    synth_def << "\tvar ";
+    for (int i = 0; i < variables_created_; i++) {
+      synth_def << g_VariablePrefix << i;  
+      if (i < variables_created_ - 1) {
+        synth_def << ", ";
+      }
+    }
+    synth_def << ";\n";
+  }
+  // store the commands in the synthdef
+  synth_def << command_script_.str();
+  // ending
+  if (convert_for_realtime) {
+    synth_def << "}).add;\n";
+  } else {
+    synth_def << "}).writeDefFile(\"" << synthdef_path << "\");\n";
+  }
+  return synth_def.str();
+}
+
+std::string Converter::ToScore(const sg::Graph& graph,
+                               const std::string& synth_name,
+                               const std::string& score_variable,
+                               bool convert_for_realtime,
+                               const std::string& synthdef_path,
+                               double render_length) {
+  std::stringstream score;
+  score << score_variable << " = [\n";
+  if (!convert_for_realtime) {
+    // load the synthdef
+    score << "[0.0, [\\d_load, \"" 
+          << synthdef_path << '/' << synth_name << ".scsyndef\"]],\n";
+  }
+  // start the synth
+  score << "[0.0, [\\s_new, \\" + synth_name + ", 1000, 0, 0";
+  // initial parameter values
+  const sg::GraphProperties& graph_properties = graph[boost::graph_bundle];
+  const std::vector<double>& parameters = graph_properties.parameters_;
+  for (int i = 0; i < parameters.size(); i++) {
+    score << ", \\" << g_ArgumentPrefix << (i + 1) << ", " << parameters[i];
+  }
+  // end of \s_new command
+  score << "]],\n";
+  if (!convert_for_realtime) {
+    // end of score, stop sound
+    score << "[" << render_length << ", [\\c_set, 0, 0]]\n";
+  }
+  // score end
+  score << "];\n";
+  return score.str();
+}
+  
+void Converter::Export(const sg::Graph& graph,
+                       const std::string& export_folder,
+                       const std::string& export_name) {
+  std::stringstream export_path;
+  export_path << export_folder << '/' << export_name << ".sc";
+  std::ofstream export_file(export_path.str().c_str());
+  export_file << ToSynthDef(graph, export_name)
+              << ToScore(graph, export_name, "x");
+  export_file << "Score.play(x);";
+}
+
+  
+#pragma mark - dot converter
+  
+// formats a command node for dot
+class CommandWriter {
+  const sg::Graph& graph_;
+  const std::vector<sc::Command>& commands_;
+  
+public:
+  CommandWriter(const sg::Graph& graph,
+                const std::vector<sc::Command>& commands) 
+  : graph_(graph),
+    commands_(commands)
+  {}
+  
+  void operator()(std::ostream& out, const sg::Vertex& vertex) const {
+    const sg::Node& command_info = graph_[vertex];
+    sg::NodeType type = command_info.type_;
+    out << " [label=\"";
+    if (type == sg::kConstant) {
+      // calculate weighted constant value
+      const sg::Edge& out_edge = *(boost::out_edges(vertex, graph_).first);
+      const sg::Connection& connection = graph_[out_edge];
+      double value = command_info.constant_value_;
+      value = value * connection.weight_ + connection.offset_;
+      out << std::setprecision(2) << std::fixed << value 
+          << "\", shape=diamond";
+    } else if (type == sg::kSpecial) {
+      if (command_info.id_ == sc::Command::kMixer) {
+        // check if this is the root mixer
+        if (boost::out_degree(vertex, graph_) > 0) {
+          out << "+\"";
+          if (command_info.rate_ == sg::kControlRate) {
+            out << ", shape=box";
+          }
+        } else {
+          out << "Output\"";
+        }
+      } else if (command_info.id_ == sc::Command::kMultiplier) {
+        out << "*\"";
+        if (command_info.rate_ == sg::kControlRate) {
+          out << ", shape=box";
+        }        
+      }
+    } else if (type == sg::kCommand) {
+      out << commands_[command_info.id_].Name() << "\"";
+      if (command_info.rate_ == sg::kControlRate) {
+        out << ", shape=box";
+      }
+    } else if (type == sg::kParameter) {
+      out << g_ArgumentPrefix << command_info.id_ 
+          << "\", shape=invhouse";
+    }
+    // end
+    out << "]";
+  }
+};
+  
+// formats a connection for dot
+class ConnectionWriter {
+  const sg::Graph& graph_;
+  const std::vector<sc::Command>& commands_;
+  
+public:
+  ConnectionWriter(const sg::Graph& graph,
+                   const std::vector<sc::Command>& commands) 
+  : graph_(graph),
+    commands_(commands)
+  {}
+  
+  void operator()(std::ostream& out, const sg::Edge& edge) const {
+    const sg::Connection& connection = graph_[edge];
+    out << "[label=\"";
+    const sg::Node& target = graph_[boost::target(edge, graph_)];
+    if (target.type_ == sg::kCommand) {
+      const sc::Command& command = commands_[target.id_];
+      const sc::Argument& argument = command.GetArgument(connection.input_);
+      out << " [" << argument.name_ << ']';
+    }
+    if (connection.IsActive()) {
+      // connection weighting
+      // skip constants as they have weighting applied to label
+      const sg::Node& source = graph_[boost::source(edge, graph_)];
+      if (source.type_ != sg::kConstant) {
+        out << " (";
+        out << std::fixed << std::setprecision(g_label_decimal_places);
+        if (connection.offset_ != 0) {
+          out << connection.offset_ 
+          << " - " 
+          << (connection.offset_ + connection.weight_);
+        } else {
+          out << "* " << connection.weight_;
+        }
+        out << ")";        
+      }
+    }
+    out << "\"]";
+  }
+};
+
+class GraphPropertiesWriter {
+  const sg::Graph& graph_;
+public:
+  GraphPropertiesWriter(const sg::Graph& graph) : graph_(graph) {}
+  void operator()(std::ostream& out) const {
+    out << "edge[fontsize=10]\n";
+  }
+};
+
+std::string Converter::ToDOT(const sg::Graph& graph) {
+  std::stringstream buffer;
+  // prepare the writer classes
+  CommandWriter command_writer(graph, commands_);
+  ConnectionWriter connection_writer(graph, commands_);
+  GraphPropertiesWriter graph_writer(graph);
+  // write the graph to the buffer
+  boost::write_graphviz(buffer, graph,
+                        command_writer, connection_writer, graph_writer);
+  return buffer.str();
+}
+
+} // sc namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sc_converter.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,80 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// Converter class for SuperCollider, handles converting to synthdefs and dot
+// graphs
+
+#pragma once
+
+#include "converter.hpp"
+#include "sc_grammar.hpp"
+#include "synth_graph.hpp"
+
+#include <map>
+#include <set>
+#include <sstream>
+#include <vector>
+
+namespace sc {
+
+class Converter : public ConverterInterface {
+  const std::vector<sc::Command>& commands_;
+  std::map<sg::Vertex, int> variable_map_;
+  std::set<int> available_variables_;
+  int variables_created_;
+  std::stringstream command_script_;
+
+public:
+  Converter(const sc::Grammar& grammar) : commands_(grammar.Commands()) {}
+  
+  // converts a graph to graphviz DOT format
+  std::string ToDOT(const sg::Graph& graph);
+  
+  // generates a supercollider script intended for realtime use
+  void Export(const sg::Graph& graph,
+              const std::string& export_folder,
+              const std::string& export_name);
+  
+  // converts a graph to a supercollider synthdef
+  std::string ToSynthDef(const sg::Graph& graph,
+                         const std::string& synth_name,
+                         bool prepare_for_render = true,
+                         const std::string& synthdef_path = "");
+  
+  // generates a supercollider score for the graph
+  std::string ToScore(const sg::Graph& graph,
+                      const std::string& synth_name,
+                      const std::string& score_variable,
+                      bool prepare_for_render = true,
+                      const std::string& synthdef_path = "",
+                      double render_length = 0);
+  
+private:
+  void SynthDefVertex(sg::Vertex vertex, const sg::Graph& graph);
+  void SynthDefCommand(sg::Vertex vertex,
+                       const sg::Node& node,
+                       const sg::Graph& graph);
+  void SynthDefSpecial(sg::Vertex vertex,
+                       const sg::Node& node,
+                       const sg::Graph& graph);
+  
+  int AssignVariable(sg::Vertex vertex);
+  int GetVariable(sg::Vertex vertex);
+};
+
+} // sc namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sc_default_grammar.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,324 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// Contents of grammar/sc.json
+
+#include "sc_default_grammar.hpp"
+
+namespace sc {
+
+const char* g_default_grammar = 
+  "{\n"
+  "  \"sclang-version\": \"3\",\n"
+  "  \"name\": \"sc3\",\n"
+  "  \"arg-types\": [\n"
+  "    {\n"
+  "      \"type\": \"frequency\",\n"
+  "      \"range\": [20, 20000],\n"
+  "      \"range_control\": [0, 100],\n"
+  "      \"scaling\": \"log\"\n"
+  "    },\n"
+  "    {\n"
+  "      \"type\": \"radians\",\n"
+  "      \"range\": [0, 6.2831853072]\n"
+  "    },\n"
+  "    {\n"
+  "      \"type\": \"audio\",\n"
+  "      \"range\": [-1, 1]\n"
+  "    },\n"
+  "    {\n"
+  "      \"type\": \"time\",\n"
+  "      \"range\": [0, 10],\n"
+  "      \"scaling\": \"log\"\n"
+  "    },\n"
+  "    {\n"
+  "      \"type\": \"trigger\",\n"
+  "      \"range\": [-1, 1],\n"
+  "      \"fixed_range\": true\n"
+  "    }\n"
+  "  ],\n"
+  "\n"
+  "  \"sources\": [\n"
+  "    // oscillators\n"
+  "    {\n"
+  "      \"name\": \"SinOsc\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"freq\", \"type\": \"frequency\" },\n"
+  "        { \"name\": \"phase\", \"type\": \"radians\" }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Saw\",\n"
+  "      \"args\": { \"name\": \"freq\", \"type\": \"frequency\" }\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"SyncSaw\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"syncFreq\", \"type\": \"frequency\" },\n"
+  "        { \"name\": \"sawFreq\", \"type\": \"frequency\" }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"VarSaw\",\n"
+  "      \"args\": [ { \"name\": \"freq\", \"type\": \"frequency\" }, \"iphase\", \"width\" ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Pulse\",\n"
+  "      \"args\": [ { \"name\": \"freq\", \"type\": \"frequency\" }, \"width\" ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Impulse\",\n"
+  "      \"args\": [ { \"name\": \"freq\", \"type\": \"frequency\" }, \"phase\" ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Blip\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"freq\", \"type\": \"frequency\" },\n"
+  "        { \"name\": \"numharm\", \"range\": [1, 200] }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"SinOscFB\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"freq\", \"type\": \"frequency\" },\n"
+  "        { \"name\": \"feedback\", \"type\": \"radians\" }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"PMOsc\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"carfreq\", \"type\": \"frequency\" },\n"
+  "        { \"name\": \"modfreq\", \"type\": \"frequency\" },\n"
+  "        { \"name\": \"pmindex\", \"type\": \"radians\" },\n"
+  "        { \"name\": \"modphase\", \"type\": \"radians\" }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"FBSineC\",\n"
+  "      \"output\": \"audio\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"freq\", \"type\": \"frequency\" },\n"
+  "        { \"name\": \"im\", \"range\": [1, 64] },\n"
+  "        { \"name\": \"fb\", \"range\": [0, 0.5] },\n"
+  "        { \"name\": \"a\", \"range\": [1, 1.2] },\n"
+  "        { \"name\": \"c\", \"range\": [0.1, 0.9] }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"FBSineN\",\n"
+  "      \"output\": \"audio\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"freq\", \"type\": \"frequency\" },\n"
+  "        { \"name\": \"im\", \"range\": [1, 64] },\n"
+  "        { \"name\": \"fb\", \"range\": [0, 0.5] },\n"
+  "        { \"name\": \"a\", \"range\": [1, 1.2] },\n"
+  "        { \"name\": \"c\", \"range\": [0.1, 0.9] }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Logistic\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"chaosParam\", \"range\": [3, 3.999] },\n"
+  "        { \"name\": \"freq\", \"type\": \"frequency\" }\n"
+  "      ]\n"
+  "    },\n"
+  "    // Noise\n"
+  "    {\n"
+  "      \"name\": \"LFNoise0\",\n"
+  "      \"args\": { \"name\": \"freq\", \"type\": \"frequency\" }\n"
+  "    },\n"
+  "    \"WhiteNoise\",\n"
+  "    \"BrownNoise\",\n"
+  "    \"PinkNoise\",\n"
+  "    {\n"
+  "      \"name\": \"Crackle\",\n"
+  "      \"args\": { \"name\": \"chaosParam\", \"range\": [1, 2] }\n"
+  "    },\n"
+  "    // Lines/Envelopes\n"
+  "    {\n"
+  "      \"name\": \"Line\",\n"
+  "      \"output\": \"control\",\n"
+  "      \"args\": { \"name\": \"dur\", \"type\": \"time\" }\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"XLine\",\n"
+  "      \"output\": \"control\",\n"
+  "      \"args\": [ \n"
+  "        { \"name\": \"dur\", \"type\": \"time\" },\n"
+  "        { \"name\": \"add\", \"constant\": -1 }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Linen\",\n"
+  "      \"output\": \"control\",\n"
+  "      \"args\": [\n"
+  "        \"gate\",\n"
+  "        { \"name\": \"attackTime\", \"type\": \"time\" },\n"
+  "        \"susLevel\",        \n"
+  "        { \"name\": \"releaseTime\", \"type\": \"time\" }\n"
+  "      ]\n"
+  "    }\n"
+  "  ],\n"
+  "\n"
+  "  \"modifiers\": [\n"
+  "    // Filters\n"
+  "    {\n"
+  "      \"name\": \"LPF\",\n"
+  "      \"args\": { \"name\": \"freq\", \"type\": \"frequency\" }\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"HPF\",\n"
+  "      \"args\": { \"name\": \"freq\", \"type\": \"frequency\" }\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"BPF\",\n"
+  "      \"args\": [ { \"name\": \"freq\", \"type\": \"frequency\" }, \"rq\" ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"BRF\",\n"
+  "      \"args\": [ { \"name\": \"freq\", \"type\": \"frequency\" }, \"rq\" ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"RLPF\",\n"
+  "      \"args\": [ { \"name\": \"freq\", \"type\": \"frequency\" }, \"rq\" ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"RHPF\",\n"
+  "      \"args\": [ { \"name\": \"freq\", \"type\": \"frequency\" }, \"rq\" ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Resonz\",\n"
+  "      \"args\": [ { \"name\": \"freq\", \"type\": \"frequency\" }, \"bwr\" ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Ringz\",\n"
+  "      \"args\": [ \n"
+  "        { \"name\": \"freq\", \"type\": \"frequency\" },\n"
+  "        { \"name\": \"decaytime\", \"type\": \"time\" }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Formlet\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"freq\", \"type\": \"frequency\" },\n"
+  "        { \"name\": \"attacktime\", \"type\": \"time\" },\n"
+  "        { \"name\": \"decaytime\", \"type\": \"time\" }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"MoogFF\",\n"
+  "      \"args\": [ \n"
+  "        { \"name\": \"freq\", \"type\": \"frequency\" },\n"
+  "        { \"name\": \"gain\", \"range\": [0, 4] }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"FreeVerb\",\n"
+  "      \"output\": \"audio\",\n"
+  "      \"args\": [ \"mix\", \"room\", \"damp\" ]\n"
+  "    },\n"
+  "    // Dynamics\n"
+  "    {\n"
+  "      \"name\": \"Limiter\",\n"
+  "      \"output\": \"audio\",\n"
+  "      \"args\": \"level\"\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Amplitude\",\n"
+  "      \"output\": \"control\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"attackTime\", \"type\": \"time\" },\n"
+  "        { \"name\": \"releaseTime\", \"type\": \"time\" }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Normalizer\",\n"
+  "      \"output\": \"audio\",\n"
+  "      \"args\": [ \"level\", { \"name\": \"dur\", \"range\": [0.001, 0.5] } ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Compander\",\n"
+  "      \"output\": \"audio\",\n"
+  "      \"args\": [ \n"
+  "        { \"name\": \"control\", \"type\": \"audio\" },\n"
+  "        \"thresh\",\n"
+  "        { \"name\": \"slopeBelow\", \"type\": \"time\" },\n"
+  "        { \"name\": \"slopeAbove\", \"type\": \"time\" },\n"
+  "        { \"name\": \"clampTime\", \"range\": [0.001, 0.2] },\n"
+  "        { \"name\": \"relaxTime\", \"range\": [0.001, 0.2] }\n"
+  "      ]\n"
+  "    },\n"
+  "    // shifters\n"
+  "    {\n"
+  "      \"name\": \"FreqShift\",\n"
+  "      \"output\": \"audio\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"freq\", \"range\": [-1000, 1000] },\n"
+  "        { \"name\": \"phase\", \"type\": \"radians\" }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"PitchShift\",\n"
+  "      \"output\": \"audio\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"pitchRatio\", \"range\": [0, 4] },\n"
+  "        { \"name\": \"pitchDispersion\", \"range\": [0, 4] },\n"
+  "        { \"name\": \"timeDispersion\", \"range\": [0, 0.2] }\n"
+  "      ]\n"
+  "    },\n"
+  "    // delays\n"
+  "    {\n"
+  "      \"name\": \"DelayC\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"maxdelaytime\", \"constant\": 1 },\n"
+  "        { \"name\": \"delaytime\", \"range\": [0.001, 1] }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Pluck\",\n"
+  "      \"output\": \"audio\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"trig\", \"type\": \"trigger\" },\n"
+  "        { \"name\": \"maxdelaytime\", \"constant\": 1 },\n"
+  "        { \"name\": \"delaytime\" },\n"
+  "        { \"name\": \"decaytime\", \"type\": \"time\" },\n"
+  "        { \"name\": \"coef\", \"range\": [-0.9, 0.9] }\n"
+  "      ]\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"CombC\",\n"
+  "      \"args\": [\n"
+  "        { \"name\": \"maxdelaytime\", \"constant\": 1 },\n"
+  "        { \"name\": \"delaytime\" },\n"
+  "        { \"name\": \"decaytime\", \"range\": [-1, 1] }\n"
+  "      ]\n"
+  "    },\n"
+  "    // misc\n"
+  "    {\n"
+  "      \"name\": \"Decay\",\n"
+  "      \"args\": { \"name\": \"decayTime\", \"type\": \"time\" }\n"
+  "    },\n"
+  "    {\n"
+  "      \"name\": \"Latch\",\n"
+  "      \"args\": { \"name\": \"trig\", \"type\": \"trigger\" }\n"
+  "    }\n"
+  "  ] // end of modifiers\n"
+  "}\n"
+;
+
+} // sc namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sc_default_grammar.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,25 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// Default SuperCollider grammar for GPSynth
+
+#pragma once
+
+namespace sc {
+  extern const char* g_default_grammar;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sc_evaluator.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,408 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+#include "sc_evaluator.hpp"
+
+#include "boost_ex.hpp"
+#include "logger.hpp"
+#include "sc_converter.hpp"
+#include "statistics.hpp"
+
+#include "boost/filesystem.hpp"
+#include "boost/format.hpp"
+#include "boost/lexical_cast.hpp"
+#include "boost/process.hpp"
+#include "boost/thread.hpp"
+#include "boost/math/special_functions/fpclassify.hpp"
+
+#include <algorithm>
+#include <cmath>
+#include <functional>
+#include <numeric>
+
+namespace bp = boost::process;
+
+namespace sc {
+  
+  const int g_max_file_wait_time_ms = 10000;
+  const int g_file_wait_increment_ms = 500;
+  const int g_sclang_timeout_s = 10;
+  const double g_fitness_failure_value = 100;
+  const std::string g_score_variable_name = "x";
+ 
+// Worker class, runs in own thread
+class EvaluatorWorker {
+  sc::Converter converter_;
+  int thread_id_;
+  bool quit_threads_;
+  Evaluator* parent_;
+  dsp::FileComparer file_comparer_;
+  // work thread communicates with parent, handles work queue
+  boost::thread work_thread_;
+  // render thread launches child processes
+  boost::thread render_thread_;
+  boost::mutex render_mutex_;
+  // render duration in seconds
+  double render_length_;
+  std::string render_command_path_;
+  std::string render_osc_path_;
+  std::string render_output_path_;
+  // flag for render thread that a synth is ready for rendering
+  bool do_render_;
+  // condition to notify render thread that work is available
+  boost::condition_variable render_start_;
+  // condition to notify work thread that work has been done
+  boost::condition_variable render_finished_;
+  // stores handle to active child process
+  boost::shared_ptr<bp::child> render_process_;
+  
+public:
+  EvaluatorWorker(Evaluator* parent,
+                  int thread_id,
+                  const dsp::FileComparer& target)
+  : parent_(parent),
+    thread_id_(thread_id),
+    converter_(parent->grammar_),
+    quit_threads_(false),
+    file_comparer_(target),
+    render_length_(file_comparer_.TargetDuration()),
+    do_render_(false)
+  {
+    work_thread_ = boost::thread(&EvaluatorWorker::DoWork, this);
+    render_thread_ = boost::thread(&EvaluatorWorker::DoSCRender, this);
+  }
+  
+  ~EvaluatorWorker() {
+    // tell threads to quit
+    quit_threads_ = true;
+    // work thread
+    try {
+      boost::system_time timeout = boost::get_system_time();
+      timeout += boost::posix_time::seconds(g_sclang_timeout_s);
+      parent_->queue_condition_.notify_all();
+      work_thread_.timed_join(timeout);
+      // render thread
+      timeout = boost::get_system_time();
+      timeout += boost::posix_time::seconds(g_sclang_timeout_s);
+      render_start_.notify_one();
+      render_thread_.timed_join(timeout);      
+    }
+    catch (const std::exception& e) {
+      std::stringstream message;
+      message << "~sc::EvaluatorWorker - Exception: " << e.what() << '\n';
+      WorkerLog(message.str());
+    }
+  }
+  
+private:
+  
+  void DoWork() {
+    while (!quit_threads_) {
+      // wait for some work
+      {
+        boost::mutex::scoped_lock lock(parent_->work_mutex_);
+        while (parent_->work_queue_.empty() && !quit_threads_) {
+          parent_->queue_condition_.wait(lock);
+        }
+      }
+      // keep going until the work queue is empty 
+      while (!quit_threads_) {
+        sg::Graph* graph = NULL;
+        {
+          // check there's still work to do
+          boost::mutex::scoped_lock lock(parent_->work_mutex_);
+          if (parent_->work_queue_.empty()) {
+            // wait for all threads to reach this point before continuing
+            lock.unlock();
+            parent_->work_done_barrier_->wait();
+            lock.lock();
+            // notify main thread that work's finished
+            parent_->work_done_condition_.notify_one();
+            break;
+          }
+          // get the next graph from the queue
+          graph = parent_->work_queue_.front();
+          parent_->work_queue_.pop();
+        }
+        // get the graph properties
+        sg::Graph& graph_ref = *graph;
+        sg::GraphProperties& graph_properties = graph_ref[boost::graph_bundle];
+        double fitness;
+        try {
+          // rate the graph
+          fitness = RateGraph(graph_ref);
+        } catch (const std::exception& e) {
+          std::stringstream message;
+          message << "Exception: " << e.what() << '\n';
+          WorkerLog(message.str());
+          fitness = g_fitness_failure_value;
+        }
+        if (boost::math::isinf(fitness)) {
+          fitness = g_fitness_failure_value;
+        } else if (boost::math::isnan(fitness)) {
+          fitness = g_fitness_failure_value;
+        }
+        graph_properties.fitness_ = fitness;
+//        std::stringstream message;
+//        message << "Rated " << graph_properties.id_ << ":" << fitness << '\n';
+//        WorkerLog(message.str());
+        {
+          // decrement the graph queue count
+          boost::mutex::scoped_lock lock(parent_->work_mutex_);
+          parent_->graphs_to_rate_--;
+          parent_->work_done_condition_.notify_one();
+        }
+      }
+    }
+  }
+  
+  void WorkerLog(const std::string& message) {
+    std::stringstream formatter;
+    formatter << "\n[" << thread_id_ << "] " << message;
+    logger::Log(formatter.str());
+  }
+  
+  double RateGraph(sg::Graph& graph) {
+    int id = graph[boost::graph_bundle].id_;
+    std::stringstream name;
+    name << "gpsynth_"
+         << std::setw(parent_->synth_name_zero_pad_length_) << std::setfill('0')
+         << id;
+    std::string synth_name = name.str();
+    // convert the graph to a synthdef and score
+    std::string synthdef = converter_.ToSynthDef(graph,
+                                                 synth_name,
+                                                 false,
+                                                 parent_->synthdef_folder_);
+    std::string score = converter_.ToScore(graph,
+                                           synth_name,
+                                           g_score_variable_name,
+                                           false, // prepare for non-realtime
+                                           parent_->synthdef_folder_,
+                                           render_length_);
+    {
+      // prepare the synthdef and score for the render thread
+      boost::mutex::scoped_lock lock(render_mutex_);
+      render_command_path_ = parent_->sc_folder_ + synth_name + ".sc";
+      render_osc_path_ = parent_->osc_folder_ + synth_name + ".osc";
+      render_output_path_ = parent_->audio_folder_+ synth_name + ".aiff";
+      // prepare render script for sclang
+      std::ofstream command_file(render_command_path_.c_str());
+      // write the synthdef and the score
+      command_file << synthdef << '\n' << score;
+      // tell sclang to write the score as OSC data
+      command_file << "Score.write(" << g_score_variable_name << ", \"" 
+                   << render_osc_path_ << "\");\n";
+      // tell sclang to quit at end of script
+      command_file << "\n0.exit;";
+      // finished, close the file
+      command_file.close();
+      // tell the render thread that work is available
+      do_render_ = true;
+      boost::system_time timeout = boost::get_system_time();
+      timeout += boost::posix_time::seconds(g_sclang_timeout_s);
+      render_start_.notify_one();
+      // wait for the render thread to complete the job
+      if (!render_finished_.timed_wait(lock, timeout)) {
+        // sclang or scsynth timed out, kill process and set fitness to failure
+        // WorkerLog("Render thread timed out.\n");
+        try {
+          render_process_->terminate();
+        }
+        catch (boost::system::system_error& e) {
+          // don't need to do anything here, process may already be terminated.
+        }
+        do_render_ = false;
+        // maximum error
+        return g_fitness_failure_value;
+      }
+    }
+    // check that a rendered file has been produced
+    if (!boost::filesystem::exists(render_output_path_)) {
+      // file missing, something's gone wrong..
+      WorkerLog("Render output missing.\n");
+      return g_fitness_failure_value;
+    }
+    // store render path with graph for future reference
+    graph[boost::graph_bundle].render_path_ = render_output_path_;
+    // compare the rendered file to the target
+    return CompareToTarget(render_output_path_);
+  }
+  
+  void DoSCRender() {
+    std::vector<std::string> args;
+    while (!quit_threads_) {
+      // wait for a command to render
+      {
+        boost::mutex::scoped_lock lock(render_mutex_);
+        do_render_ = false;
+        while (!do_render_ && !quit_threads_) {
+          render_start_.wait(lock);
+        }
+        if (quit_threads_) {
+          return;
+        }
+      }
+      // Call sclang to get OSC command for scsynth
+      args.clear();
+      args.push_back("-d");
+      args.push_back(parent_->sc_app_path_);
+      args.push_back(render_command_path_);
+      // replace process pipes to suppress output
+      bp::context closed_streams;
+      closed_streams.streams[bp::stdout_id] = bp::behavior::close();
+      closed_streams.streams[bp::stderr_id] = bp::behavior::close();
+      bp::child process = bp::create_child(parent_->sclang_path_,
+                                           args,
+                                           closed_streams);
+      // store process handle to allow work thread to kill process if it's hung
+      {
+        boost::mutex::scoped_lock lock(render_mutex_);
+        render_process_.reset(new bp::child(process));
+      }
+      // wait for sclang to finish
+      process.wait();
+      if (!do_render_) {
+        // if do_render_ is false, process was killed by work thread 
+        continue;
+      }
+      // check that sclang generated an osc command
+      if (!boost::filesystem::exists(render_osc_path_)) {
+        // sclang failed, notify work thread and continue
+        boost::mutex::scoped_lock lock(render_mutex_);
+        render_finished_.notify_one();
+        continue;
+      }
+      // render osc with scsynth
+      args.clear();
+      args.push_back("-N");
+      args.push_back(render_osc_path_);
+      args.push_back("_"); // no input file
+      args.push_back(render_output_path_);
+      args.push_back("44100");
+      args.push_back("AIFF");
+      args.push_back("int16");
+      // output channels
+      args.push_back("-o");
+      args.push_back("1");
+      // don't publish to rendevous
+      args.push_back("-R");
+      args.push_back("0");
+      // don't load synthdefs
+      args.push_back("-D");
+      args.push_back("0");
+      // plugins path
+      args.push_back("-U");
+      args.push_back(parent_->sc_plugins_path_);
+      // call scsynth
+      process = bp::create_child(parent_->scsynth_path_, args, closed_streams);
+      {
+        boost::mutex::scoped_lock lock(render_mutex_);
+        render_process_.reset(new bp::child(process));
+      }
+      // wait for scsynth to finish rendering
+      process.wait();
+      if (!do_render_) {
+        // process timed out, killed by work thread
+        continue;
+      }
+      // job done, notify work thread
+      {
+        boost::mutex::scoped_lock lock(render_mutex_);
+        render_finished_.notify_one();
+      }
+    }
+  }
+  
+  double CompareToTarget(const std::string& file_path) {
+    return file_comparer_.CompareFile(file_path);
+  }
+};
+
+
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+Evaluator::Evaluator(const sc::Grammar& grammar,
+                     const std::string& sc_app_path,
+                     const dsp::FileComparer& target,
+                     int core_limit /* = 0 */)
+: grammar_(grammar),
+  listener_(NULL),
+  sc_app_path_(sc_app_path),
+  sc_plugins_path_(sc_app_path + "/plugins"),
+  sclang_path_(sc_app_path + "/sclang"),
+  scsynth_path_(sc_app_path + "/scsynth")
+{
+  SetWorkFolder("/tmp/");
+  int workers = boost::thread::hardware_concurrency();
+  if (core_limit > 0 && core_limit < workers) {
+    workers = core_limit;
+  }
+  work_done_barrier_.reset(new boost::barrier(workers));
+  for (int worker_id = 0; worker_id < workers; worker_id++) {
+    workers_.push_back(EvaluatorWorkerPtr(new EvaluatorWorker(this,
+                                                              worker_id,
+                                                              target)));
+  }
+}
+
+Evaluator::~Evaluator()
+{}
+
+
+void Evaluator::RateGraphs(std::vector<sg::Graph>& graphs) {
+  // make sure necessary subfolders exist in work folder
+  audio_folder_ = work_folder_ + "/audio/";
+  osc_folder_ = work_folder_ + "/osc/";
+  sc_folder_ = work_folder_ + "/sc/";
+  synthdef_folder_ = work_folder_ + "/synthdefs/";
+  boost::filesystem::create_directories(audio_folder_);
+  boost::filesystem::create_directories(osc_folder_);
+  boost::filesystem::create_directories(sc_folder_);
+  boost::filesystem::create_directories(synthdef_folder_);
+  // find zero padding length for synth names
+  synth_name_zero_pad_length_ = std::log10(graphs.size()) + 1;
+  // store the graphs in the work queue
+  boost::mutex::scoped_lock lock(work_mutex_);
+  graphs_to_rate_ = static_cast<int>(graphs.size());
+  for (int i = 0; i < graphs_to_rate_; i++) {
+    work_queue_.push(&graphs[i]);
+  }
+  // wait for graphs to be rated
+  std::size_t last_rated_count = 0;
+  while (graphs_to_rate_ > 0) {
+    queue_condition_.notify_all();
+    work_done_condition_.wait(lock);
+    if (listener_ != NULL) {
+      std::size_t rated_count = graphs.size() - graphs_to_rate_;
+      if (rated_count != last_rated_count) {
+        last_rated_count = rated_count;
+        listener_->GraphRatedNotification(rated_count);
+      }
+    }
+  }
+  // remove OSC folder, no longer required
+  boost::filesystem::remove_all(osc_folder_);
+}
+  
+void Evaluator::SetWorkFolder(const std::string& path) {
+  work_folder_ = path;
+}
+  
+} // sc namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sc_evaluator.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,77 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// Evaluator for SuperCollider synth graphs. Sends converted synthdefs to
+// SuperCollider for rendering.
+
+#pragma once
+
+#include "evaluator.hpp"
+#include "file_comparer.hpp"
+#include "sc_grammar.hpp"
+
+#include "boost/shared_ptr.hpp"
+#include "boost/thread/barrier.hpp"
+#include "boost/thread/condition_variable.hpp"
+#include "boost/thread/mutex.hpp"
+
+#include <queue>
+#include <string>
+
+namespace sc {
+
+// forward declaration of worker
+class EvaluatorWorker;
+typedef boost::shared_ptr<EvaluatorWorker> EvaluatorWorkerPtr;
+
+class Evaluator : public EvaluatorInterface {
+  friend class EvaluatorWorker;
+  const sc::Grammar& grammar_;
+  const std::string sc_app_path_;
+  const std::string sc_plugins_path_;
+  const std::string sclang_path_;
+  const std::string scsynth_path_;
+  std::string work_folder_;
+  std::string osc_folder_;
+  std::string audio_folder_;
+  std::string sc_folder_;
+  std::string synthdef_folder_;
+  std::queue<sg::Graph*> work_queue_;
+  boost::mutex work_mutex_;
+  boost::condition_variable queue_condition_;
+  boost::condition_variable work_done_condition_;
+  boost::shared_ptr<boost::barrier> work_done_barrier_;
+  std::vector<EvaluatorWorkerPtr> workers_;
+  std::size_t graphs_to_rate_;
+  EvaluatorListenerInterface* listener_;
+  int synth_name_zero_pad_length_;
+  
+public:
+  Evaluator(const sc::Grammar& grammar,
+            const std::string& sc_app_path,
+            const dsp::FileComparer& target,
+            int core_limit = 0);
+  ~Evaluator();
+  void RateGraphs(std::vector<sg::Graph>& graphs);
+  void SetWorkFolder(const std::string& path);
+  void SetListener(EvaluatorListenerInterface* listener) { 
+    listener_ = listener;
+  }
+};
+  
+} // sc namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sc_grammar.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,904 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+#include "sc_grammar.hpp"
+
+#include "boost_ex.hpp"
+#include "graph_helpers.hpp"
+#include "logger.hpp"
+#include "statistics.hpp"
+#include "std_ex.hpp"
+
+#include "json/json.h"
+
+#include "boost/graph/random.hpp"
+#include "boost/graph/topological_sort.hpp"
+
+#include <iostream>
+#include <iterator>
+#include <fstream>
+#include <set>
+#include <sstream>
+
+const int g_maximum_mixer_channels = 3;
+
+const double g_probability_command_node_command = 0.85;
+const double g_probability_command_node_special = 0.15;
+
+const double g_probability_mod_node_command = 0.25;
+const double g_probability_mod_node_special = 0.15;
+const double g_probability_mod_node_constant = 0.4;
+
+const double g_probability_argument_affected = 1.0;
+
+const double g_probability_input_mutation = 1.0;
+const double g_probability_connection_mutation = 1.0;
+
+const double g_minimum_connection_weight = 0.001;
+
+namespace {
+  
+  double MapCoefficientToRange(double c, const stdx::Range<double>& range) {
+    return range.minimum_ + (range.Size() * c);
+  }
+  
+  // Returns argument connection weight and offset, scaled to argument input
+  void GenerateWeightAndOffset(const sc::Argument& argument,
+                               sg::CommandRate rate,
+                               sg::Connection* connection) {
+    const stdx::Range<double>& scale_range = (rate == sg::kControlRate) 
+                                             ? argument.range_control_
+                                             : argument.range_;
+    if (argument.fixed_range_) {
+      connection->weight_ = scale_range.Size();
+      connection->offset_ = scale_range.Minimum();
+    } else if (argument.name_ == "in") {
+      // input connections don't have an offset
+      double weight = stdx::RandomCoefficient();
+      if (rate == sg::kAudioRate) {
+        // square audio weightings
+        connection->weight_ = weight * weight;
+      }
+    } else {
+      // generate random weight and offset
+      double weight;
+      do {
+        weight = stdx::RandomCoefficient();
+      } while (weight < g_minimum_connection_weight);
+      double offset = stdx::RandomRange(0.0, 1.0 - weight);
+      switch (argument.scaling_mode_) {
+        case sc::Argument::kScalingLinear:
+          connection->weight_ = MapCoefficientToRange(weight, scale_range);
+          connection->offset_ = MapCoefficientToRange(offset, scale_range);
+          break;
+
+        case sc::Argument::kScalingLog:
+          connection->weight_ = MapCoefficientToRange(weight * weight * weight,
+                                                      scale_range);
+          connection->offset_ = MapCoefficientToRange(offset * offset * offset,
+                                                      scale_range);
+          break;
+
+        case sc::Argument::kConstant:
+          throw std::runtime_error("ApplyRandomWeightAndOffset - preset argument provided");
+      }
+    }
+  }
+
+sc::Argument ParseArgument(const Json::Value& json) {
+  sc::Argument arg;
+  arg.name_ = json.get("name", "").asString();
+  if (json.isMember("constant")) {
+    arg.scaling_mode_ = sc::Argument::kConstant;
+    arg.constant_value_ = json["constant"].asDouble();
+    return arg;
+  }
+  if (json.isMember("range")) {
+    const Json::Value range = json["range"];
+    arg.range_.SetMinimum(range[0].asDouble());
+    arg.range_.SetMaximum(range[1].asDouble());
+  }
+  if (json.isMember("range_control")) {
+    const Json::Value range = json["range_control"];
+    arg.range_control_.SetMinimum(range[0].asDouble());
+    arg.range_control_.SetMaximum(range[1].asDouble());
+  } else {
+    arg.range_control_ = arg.range_;
+  }
+  if (json.isMember("fixed_range")) {
+    arg.fixed_range_ = json["fixed_range"].asBool();
+  }
+  std::string scaling = json.get("scaling", "linear").asString();
+  if (scaling == "linear") {
+    arg.scaling_mode_ = sc::Argument::kScalingLinear;
+  } else if (scaling == "log") {
+    arg.scaling_mode_ = sc::Argument::kScalingLog;
+  }
+  return arg;
+}
+
+sc::Command ParseCommand(const Json::Value& json,
+                         const std::map<std::string, sc::Argument>& types,
+                         sc::Command::CommandMode command_mode) {
+  if (json.type() == Json::stringValue) {
+    return sc::Command(json.asString(), command_mode);
+  }
+  // name
+  std::string name = json["name"].asString();
+  // output type
+  sc::Command::OutputType output_type = sc::Command::kAll;
+  if (json.isMember("output")) {
+    std::string output = json["output"].asString();
+    if (output == "control") {
+      output_type = sc::Command::kControl;
+    } else if (output == "audio") {
+      output_type = sc::Command::kAudio;
+    }
+  }
+  // arguments
+  std::vector<sc::Argument> args;
+  // [in] argument for modifiers
+  if (command_mode == sc::Command::kModifier) {
+    args.push_back(sc::Argument("in"));
+  }
+  Json::Value json_args = json["args"];
+  Json::ValueType arg_type = json_args.type();
+  if (arg_type == Json::stringValue) {
+    // single argument as string
+    args.push_back(sc::Argument(json_args.asString()));
+  } else if (arg_type == Json::objectValue) {
+    // single argument object
+    if (json_args.isMember("type")) {
+      args.push_back(stdx::GetFromMap(types, json_args["type"].asString()));
+      args.back().name_ = json_args["name"].asString();
+    } else {
+      args.push_back(ParseArgument(json_args));
+    }      
+  } else {
+    // array of arguments
+    for (int i = 0; i < json_args.size(); i++) {
+      Json::Value arg = json_args[i];
+      if (arg.type() == Json::stringValue) {
+        args.push_back(sc::Argument(arg.asString()));
+      } else {
+        if (arg.isMember("type")) {
+          args.push_back(stdx::GetFromMap(types, arg["type"].asString()));
+          args.back().name_ = arg["name"].asString();
+        } else {
+          args.push_back(ParseArgument(arg));
+        }
+      }
+    }
+  }
+  // success
+  return sc::Command(name, command_mode, output_type, args);
+}
+
+
+sc::Command ParseSource(const Json::Value& json,
+                        const std::map<std::string, sc::Argument>& types) {
+  return ParseCommand(json, types, sc::Command::kSource);
+}
+
+sc::Command ParseModifier(const Json::Value& json,
+                          const std::map<std::string, sc::Argument>& types) {
+  return ParseCommand(json, types, sc::Command::kModifier);
+}
+
+void MutateValue(double* value, bool* mutation_occurred,
+                 double range_min = 0.0, double range_max = 1.0) {
+  // add gaussian noise to values, low variance 
+  static bx::GaussianGenerator generator = bx::MakeGaussianGenerator(0, 0.125);
+  double new_value = stdx::Clamp(*value + generator(), range_min, range_max);
+  if (*value != new_value) {
+    *value = new_value;
+    *mutation_occurred = true;
+  }
+}
+  
+} // namespace
+
+
+
+namespace sc {
+  
+Grammar::Grammar(const std::string& json_data)
+: max_depth_(3)
+{ 
+  ParseJSON(json_data); 
+}
+
+void Grammar::ParseJSON(const std::string& json_data) {
+  commands_.clear();
+  Json::Reader reader;
+  Json::Value root;
+  if (!reader.parse(json_data, root)) {
+    std::stringstream message;
+    message << "Grammar::Parse: Failed to parse data\n"
+            << reader.getFormattedErrorMessages();
+    throw std::runtime_error(message.str());
+  }
+  try {
+    // argument types
+    // stores predefined argument types while parsing grammar
+    std::map<std::string, Argument> argument_types;
+    const Json::Value& args = root["arg-types"];
+    for (int i = 0; i < args.size(); i++) {
+      const Json::Value& arg = args[i];
+      argument_types[arg["type"].asString()] = ParseArgument(arg);
+    }
+    // sound sources
+    const Json::Value& sources = root["sources"];
+    for (int i = 0; i < sources.size(); i++) {
+      commands_.push_back(ParseSource(sources[i], argument_types)); 
+    }
+    // modifiers
+    const Json::Value& modifiers = root["modifiers"];
+    for (int i = 0; i < modifiers.size(); i++) {
+      commands_.push_back(ParseModifier(modifiers[i], argument_types));
+    }
+  } catch (const std::exception& e) {
+    std::stringstream message;
+    message << "Grammar::Parse: " << e.what();
+    throw std::runtime_error(message.str());
+  }
+}
+  
+int Grammar::RandomCommand(sg::CommandRate rate,
+                           int tree_depth,
+                           bool must_be_modifier /* = false */) const {
+  Command::OutputType output;
+  Command::CommandMode mode;
+  CommandID command = -1;
+  CommandID number_of_commands = commands_.size();
+  // if we're at or one away from maximum depth then the command needs to 
+  // be a source, headroom of 1 for some parameter control
+  bool must_be_source = (tree_depth >= (max_depth_ - 1));
+  do {
+    command = stdx::Random(number_of_commands);
+    output = commands_[command].Output();
+    if (rate == sg::kAudioRate) {
+      do {
+        command = stdx::Random(number_of_commands);
+        output = commands_[command].Output();
+      } while (!(output == Command::kAll || output == Command::kAudio));
+    } else {
+      do {
+        command = stdx::Random(number_of_commands);
+        output = commands_[command].Output();
+      } while (!(output == Command::kAll || output == Command::kControl));
+    }
+    mode = commands_[command].Mode();
+  } while ((must_be_source && (mode != Command::kSource))
+           || (must_be_modifier && (mode != Command::kModifier)));
+  return static_cast<int>(command);
+}
+  
+sg::Vertex Grammar::CreateCommand(sg::Graph &graph,
+                                  sg::CommandRate rate,
+                                  int depth,
+                                  bool must_be_modifier /* = false */,
+                                  bool make_modifier_input /* = true */) const {
+  // select a random command for the node
+  int command_id = RandomCommand(rate, depth, must_be_modifier);
+  // create the node and add it to the graph
+  sg::Node command_info(command_id, sg::kCommand, rate);
+  sg::Vertex vertex = boost::add_vertex(command_info, graph);
+  // a modifier command has to have further nodes added to its main input
+  const Command& command = commands_[command_id];
+  for (int i = 0; i < command.Arguments().size(); i++) {
+    const Argument& argument = command.GetArgument(i);
+    if (argument.name_ == "in") {
+      if (make_modifier_input) {
+        // modifier input must be given a command tree
+        sg::Vertex tree = RandomTree(graph, rate, kTreeMode_Command, depth + 1);
+        sg::Connection connection(i);
+        GenerateWeightAndOffset(argument, rate, &connection);
+        boost::add_edge(tree, vertex, connection, graph);
+      }
+    } else if (argument.scaling_mode_ == sc::Argument::kConstant) {
+      // don't attach inputs to predefined arguments
+      continue;
+    } else if (stdx::Chance(g_probability_argument_affected)) {
+      // randomly create input for command arguments
+      sg::Vertex tree = RandomTree(graph,
+                                   sg::kControlRate,
+                                   kTreeMode_Mod,
+                                   depth + 1);
+      sg::Connection connection(i);
+      GenerateWeightAndOffset(argument, rate, &connection);
+      boost::add_edge(tree, vertex, connection, graph);  
+    }
+  }
+  return vertex;
+}
+  
+sg::Vertex Grammar::RandomTree(sg::Graph &graph,
+                               sg::CommandRate rate,
+                               TreeMode tree_mode,
+                               int depth) const {
+  enum NodeType {
+    kCommand,
+    kSpecial,
+    kConstant,
+    kParameter
+  };
+  static stats::ProbabilitySelector node_type_selector;
+  if (!node_type_selector.Initialized()) {
+    std::vector<double> probabilities(3);
+    probabilities[kCommand] = g_probability_mod_node_command;
+    probabilities[kSpecial] = g_probability_mod_node_special;
+    probabilities[kConstant] = g_probability_mod_node_constant;
+    node_type_selector.SetProbabilities(probabilities);
+  }
+  // establish the type of node to create
+  int node_type;
+  if (depth >= max_depth_) {
+    if (tree_mode == kTreeMode_Command) {
+      // if we're at maximum depth in command mode then create a command
+      node_type = kCommand;
+    } else {
+      // in mod mode at maximum depth pick either a constant or parameter
+      if (stdx::Chance(g_probability_mod_node_constant)) {
+        node_type = kConstant;
+      } else {
+        node_type = kParameter;
+      }
+    }
+  } else {
+    if (tree_mode == kTreeMode_Command) {
+      if (stdx::Chance(g_probability_command_node_command)) {
+        node_type = kCommand;
+      } else {
+        node_type = kSpecial;
+      }
+    } else {
+      // mod mode below max depth, any node type is ok
+      node_type = static_cast<NodeType>(node_type_selector());
+    }   
+  }
+  if (node_type == kCommand) {
+    return CreateCommand(graph, rate, depth);
+  } else if (node_type == kSpecial) {
+    int command = stdx::Random(Command::kNumberOfSpecialCommands);
+    return SpecialCommand(command, graph, rate, tree_mode, depth + 1);   
+  } else if (node_type == kConstant) {
+    return boost::add_vertex(sg::Node(stdx::RandomCoefficient()), graph);
+  } else if (node_type == kParameter) {
+    return boost::add_vertex(sg::Node(RandomParameter(graph), sg::kParameter),
+                             graph);
+  }
+  throw std::runtime_error("Grammar::RandomTree - unknown node type"); 
+}
+
+int Grammar::RandomParameter(sg::Graph& graph) const {
+  // as a simple rule, randomly pick an existing parameter, or if chosen 
+  // parameter is greater than # of parameters, then add a new one
+  std::vector<double>& parameters = graph[boost::graph_bundle].parameters_;
+  int number_of_parameters = static_cast<int>(parameters.size());
+  // parameter ids start at 1
+  int parameter = stdx::RandomRangeInt(1, number_of_parameters + 1);
+  // bump parameter count if we've got a new parameter
+  if (parameter > number_of_parameters) {
+    // store a random value for the new parameter
+    parameters.push_back(stdx::RandomCoefficient());
+  }
+  return parameter;
+}
+
+void Grammar::AddTreeToSpecialCommand(sg::Vertex command_node,
+                                      sg::Graph& graph,
+                                      int input_id,
+                                      TreeMode tree_mode,
+                                      sg::CommandRate command_rate,
+                                      bool* constant_added,
+                                      std::set<int>* parameters,
+                                      int depth) const {
+  bool success = false;
+  while (!success) {
+    sg::Vertex tree;
+    // first channel or audio command should enforce a command source
+    if (input_id == 0) {
+      tree = RandomTree(graph, command_rate, kTreeMode_Command, depth + 1);
+    } else {
+      tree = RandomTree(graph, command_rate, tree_mode, depth + 1);
+    }
+    sg::NodeType tree_type = graph[tree].type_;
+    if (tree_type == sg::kConstant) {
+      // we only need one constant per mixer
+      if (*constant_added) {
+        RemoveSubTree(tree, graph);
+        continue;
+      }
+      *constant_added = true;
+    } else if (tree_type == sg::kParameter) {
+      // we don't want duplicated parameters for special command inputs
+      if (parameters->find(graph[tree].id_) != parameters->end()) {
+        RemoveSubTree(tree, graph);
+        continue;
+      }
+      // store the parameter id
+      parameters->insert(graph[tree].id_);
+    }
+    // apply weighting
+    double weight = stdx::RandomCoefficient();
+    if (command_rate == sg::kAudioRate) {
+      // scale audio to curve
+      weight *= weight;
+    }
+    // make the connection to the generated tree
+    boost::add_edge(tree, command_node, sg::Connection(weight), graph);
+    success = true;
+  }
+}
+  
+sg::Vertex Grammar::SpecialCommand(int command_id,
+                                   sg::Graph& graph,
+                                   sg::CommandRate command_rate,
+                                   TreeMode tree_mode,
+                                   int depth /* = 0 */,
+                                   int minimum_channels /* = 2 */) const {
+  // create the special command node
+  sg::Node command_info(command_id, sg::kSpecial, command_rate);
+  sg::Vertex mixer = boost::add_vertex(command_info, graph);
+  // pick a random number of channels to create for this command
+  int channels = stdx::RandomRangeInt(minimum_channels,
+                                      g_maximum_mixer_channels);
+  bool constant_added = false;
+  std::set<int> parameters;
+  // add a tree for each channel
+  for (int i = 0; i < channels; i++) {
+    AddTreeToSpecialCommand(mixer,
+                            graph,
+                            i,
+                            tree_mode,
+                            command_rate,
+                            &constant_added,
+                            &parameters,
+                            depth);
+  }
+  return mixer;
+}
+
+void Grammar::RandomGraph(sg::Graph& graph) const {
+  graph.clear();
+  // root output node
+  SpecialCommand(sc::Command::kMixer, graph, sg::kAudioRate, kTreeMode_Command);
+}
+  
+void Grammar::PickCrossoverNodes(const sg::Graph& parent_1, 
+                                 const sg::Graph& parent_2,
+                                 sg::Vertex* crossover_node_1,
+                                 sg::Vertex* crossover_node_2) const {
+  sg::Vertex source_node_1;
+  sg::Vertex source_node_2;
+  bool nodes_found = false;
+  do {
+    // pick random edges and their nodes
+    source_node_1 = boost::random_vertex(parent_1, bx::RandomEngine());
+    source_node_2 = boost::random_vertex(parent_2, bx::RandomEngine());
+    // avoid the root output node
+    if ((source_node_1 == 0) || (source_node_2 == 0)) {
+      continue;
+    }
+    // check it's ok to swap these nodes
+    const sg::Node& info_1 = parent_1[source_node_1];
+    const sg::Node& info_2 = parent_2[source_node_2];
+    // command rates need to match
+    if (info_1.rate_ != info_2.rate_) {
+      continue;
+    }
+    // we don't want to swap two constants
+    if (info_1.type_ == sg::kConstant && info_2.type_ == sg::kConstant) {
+      continue;
+    }
+    // we don't want to swap parameter inputs with same parameter id
+    if ((info_1.type_ == sg::kParameter)
+        && (info_2.type_ == sg::kParameter)
+        && (info_1.id_ == info_2.id_)) {
+      continue;
+    }
+    // check that we're not replacing a control modifer's input with non-command
+    sg::Edge connection_1 = *(boost::out_edges(source_node_1, parent_1).first);
+    sg::Edge connection_2 = *(boost::out_edges(source_node_2, parent_2).first);
+    sg::Vertex target_node_1 = boost::target(connection_1, parent_1);
+    sg::Vertex target_node_2 = boost::target(connection_2, parent_2);
+    const sg::Node& info_target_1 = parent_1[target_node_1];
+    const sg::Node& info_target_2 = parent_2[target_node_2];
+    if ((info_target_1.type_ == sg::kCommand)
+        || (info_target_1.type_ == sg::kSpecial)) {
+      const sc::Command& target_command_1 = commands_[info_target_1.id_];
+      const std::vector<Argument>& arguments_1 = target_command_1.Arguments();
+      const sg::Connection& info_connection_1 = parent_1[connection_1];
+      if (arguments_1[info_connection_1.input_].name_ == "in") {
+        // target input is a modifier's 'in' argument, only allow commands to
+        // be swapped in
+        if (!(info_2.type_ == sg::kCommand || info_2.type_ == sg::kSpecial)) {
+          continue;
+        }
+      }
+    }
+    if ((info_target_2.type_ == sg::kCommand)
+        || (info_target_2.type_ == sg::kSpecial)) {
+      const sc::Command& target_command_2 = commands_[info_target_2.id_];
+      const std::vector<Argument>& arguments_2 = target_command_2.Arguments();
+      const sg::Connection& info_connection_2 = parent_1[connection_2];
+      if (arguments_2[info_connection_2.input_].name_ == "in") {
+        // target input is a modifier's 'in' argument, only allow commands to
+        // be swapped in
+        if (!(info_1.type_ == sg::kCommand || info_1.type_ == sg::kSpecial)) {
+          continue;
+        }
+      }
+    }
+    nodes_found = true;
+  } while (!nodes_found);
+  *crossover_node_1 = source_node_1;
+  *crossover_node_2 = source_node_2;
+}
+  
+bool Grammar::MutationReplaceSubTree(sg::Graph& graph) const {
+  // sanity check
+  if (boost::num_vertices(graph) <= 1) {
+    throw std::runtime_error("sc::Grammar::MutationReplaceSubTree - graph has too few nodes");
+  }
+  // pick node to replace
+  sg::Vertex node_to_replace;
+  do {
+    node_to_replace = boost::random_vertex(graph, bx::RandomEngine());
+  } while (node_to_replace == 0);
+  sg::CommandRate new_tree_rate = graph[node_to_replace].rate_;
+  sg::Edge connection = *(boost::out_edges(node_to_replace, graph).first);
+  sg::Vertex connection_target = boost::target(connection, graph);
+  // store the connection info contained in the connection edge
+  sg::Connection connection_info = graph[connection];
+  const sg::Node& target_info = graph[connection_target];
+  // determine new tree mode
+  TreeMode new_tree_mode = kTreeMode_Mod;
+  if (new_tree_rate == sg::kAudioRate) {
+    // audio rate nodes always require command tree replacements
+    new_tree_mode = kTreeMode_Command;
+  } else if (target_info.type_ == sg::kCommand) {
+    // if the connection target is a modifier 
+    // and the connection input is 0 then a command tree is needed
+    if (commands_[target_info.id_].Mode() == Command::kModifier) {
+      if (connection_info.input_ == 0) {
+        new_tree_mode = kTreeMode_Command;
+      }
+    }
+  } else if (target_info.type_ == sg::kSpecial) {
+    // first input to special commands is a command tree
+    if (connection_info.input_ == 0) {
+      new_tree_mode = kTreeMode_Command;
+    }
+  }
+  // remove the sub tree
+  RemoveSubTree(connection, graph);
+  // generate new tree
+  sg::Vertex new_tree = RandomTree(graph, new_tree_rate, new_tree_mode, 0);
+  // connect tree to graph
+  boost::add_edge(new_tree, connection_target, connection_info, graph);
+  return true;
+}
+  
+  
+  
+bool Grammar::MutationAddSubTree(sg::Graph& graph) const {
+  // sanity check
+  if (graph[0].type_ != sg::kSpecial) {
+    throw std::runtime_error("sc::Grammar::MutationAddSubTree - missing root mixer node");
+  }
+  bool mutation_occurred = false;
+  while (!mutation_occurred) {
+    // pick a command or special node to add a tree input to
+    sg::Vertex node;
+    sg::NodeType node_type;
+    do {
+      node = boost::random_vertex(graph, bx::RandomEngine());
+      node_type = graph[node].type_;
+    } while (!(node_type == sg::kCommand || node_type == sg::kSpecial));
+    if (node_type == sg::kCommand) {
+      int node_id = graph[node].id_;
+      const std::vector<Argument>& arguments = commands_[node_id].Arguments();
+      std::size_t number_of_arguments = arguments.size();
+      sg::InEdgeIterator edge;
+      sg::InEdgeIterator edge_end;
+      std::vector<bool> used_arguments(arguments.size(), false);
+      for (boost::tie(edge, edge_end) = boost::in_edges(node, graph);
+           edge != edge_end;
+           ++edge) {
+        used_arguments[graph[*edge].input_] = true;
+      }
+      // check that there is an unused argument available for this command
+      bool argument_available = false;
+      for (std::size_t i = 0; i < number_of_arguments; i++) {
+        if (used_arguments[i] == false) {
+          // we don't want to attach a tree to a preset argument
+          if (arguments[i].scaling_mode_ != Argument::kConstant) {
+            argument_available = true;
+            break;
+          }
+        }
+      }
+      if (argument_available) {
+        // find a random argument to insert a tree into
+        std::size_t argument;
+        do {
+          argument = stdx::Random(arguments.size());
+        } while (used_arguments[argument] == true
+                 || arguments[argument].scaling_mode_ == Argument::kConstant);
+        // add a tree and connect to the unused argument
+        sg::Vertex tree = RandomTree(graph,
+                                     sg::kControlRate,
+                                     kTreeMode_Mod,
+                                     0);
+        sg::Connection connection(static_cast<int>(argument));
+        GenerateWeightAndOffset(arguments[argument],
+                                sg::kControlRate,
+                                &connection);
+        boost::add_edge(tree, node, connection, graph);
+        mutation_occurred = true;
+      }
+    } else if (node_type == sg::kSpecial) {
+      int node_inputs = static_cast<int>(boost::in_degree(node, graph));
+      // we need to check the special command's inputs to avoid adding redundant
+      // constants or parameters
+      bool constant_added = false;
+      std::set<int> parameters;
+      sg::InEdgeIterator edge;
+      sg::InEdgeIterator edge_end;
+      for (boost::tie(edge, edge_end) = boost::in_edges(node, graph);
+           edge != edge_end;
+           ++edge) {
+        const sg::Node& source = graph[boost::source(*edge, graph)];
+        if (source.type_ == sg::kConstant) {
+          constant_added = true;
+        }
+        if (source.type_ == sg::kParameter) {
+          parameters.insert(source.id_);
+        }
+      }
+      // select tree mode based on command rate
+      TreeMode tree_mode;
+      if (graph[node].rate_ == sg::kAudioRate) {
+        tree_mode = kTreeMode_Command;
+      } else {
+        tree_mode = kTreeMode_Mod;
+      }
+      // add the tree
+      AddTreeToSpecialCommand(node,
+                              graph,
+                              node_inputs,
+                              tree_mode,
+                              graph[node].rate_,
+                              &constant_added,
+                              &parameters,
+                              0);
+      mutation_occurred = true;
+    }  
+  }
+  return true;
+}
+
+bool Grammar::MutationModifyInputs(sg::Graph& graph) const {
+  // sanity check
+  if (graph[boost::graph_bundle].parameters_.size() == 0) {
+    sg::VertexIterator vertex;
+    sg::VertexIterator vertex_end;
+    bool constant_found = false;
+    for (boost::tie(vertex, vertex_end) = boost::vertices(graph);
+         vertex != vertex_end;
+         ++vertex) {
+      sg::Node& node = graph[*vertex];
+      if (node.type_ == sg::kConstant) {
+        constant_found = true;
+        break;
+      }
+    }
+    if (!constant_found) {
+      // no parameters, no constants, nothing to do..
+      return false;
+    }
+  }
+  // make a random generator with a narrow guassian distribution 
+  bx::GaussianGenerator gaussian = bx::MakeGaussianGenerator(0, 0.125);
+  bool mutation_occurred = false;
+  while (!mutation_occurred) {
+    // mutate parameters
+    foreach (double& parameter, graph[boost::graph_bundle].parameters_) {
+      if (stdx::Chance(g_probability_input_mutation)) {
+        MutateValue(&parameter, &mutation_occurred);
+      }
+    }
+    // mutate constants
+    sg::VertexIterator vertex;
+    sg::VertexIterator vertex_end;
+    for (boost::tie(vertex, vertex_end) = boost::vertices(graph);
+         vertex != vertex_end;
+         ++vertex) {
+      sg::Node& node = graph[*vertex];
+      if (node.type_ == sg::kConstant) {
+        // constant value
+        if (stdx::Chance(g_probability_input_mutation)) {
+          MutateValue(&node.constant_value_, &mutation_occurred);
+        }
+      }
+    }
+  }
+  return true;
+}
+
+bool Grammar::MutationModifyConnections(sg::Graph& graph) const {
+  // sanity check
+  if (boost::num_edges(graph) < 1) {
+    throw std::runtime_error("sc::Grammar::MutationModifyConnections - graph has no connections");
+  }
+  bx::GaussianGenerator gaussian = bx::MakeGaussianGenerator(0, 0.125);
+  bool mutation_occurred = false;
+  while (!mutation_occurred) {
+    sg::EdgeIterator edge;
+    sg::EdgeIterator edge_end;
+    for (boost::tie(edge, edge_end) = boost::edges(graph);
+         edge != edge_end;
+         ++edge) {
+      if (stdx::Chance(g_probability_connection_mutation)) {
+        sg::Connection& connection = graph[*edge];
+        const sg::Node& target = graph[boost::target(*edge, graph)];
+        const sc::Argument& argument = GetCommandArgument(target.id_,
+                                                          connection.input_);
+        if (!argument.fixed_range_) {
+          // mutate weight
+          MutateValue(&connection.weight_,
+                      &mutation_occurred,
+                      g_minimum_connection_weight);
+          // special command inputs and modifier command input arguments 
+          // have offsets set to zero
+          if ((target.type_ != sg::kSpecial) && (argument.name_ != "in")) {
+            MutateValue(&connection.offset_, &mutation_occurred,
+                        0.0, 1.0 - connection.weight_);
+          }
+        }
+      }
+    }    
+  }
+  return true;
+}
+  
+const std::vector<sc::Argument>& Grammar::CommandArguments(int command) const {
+  return commands_[command].Arguments();
+}
+
+bool Grammar::MutationReplaceCommand(sg::Graph& graph) const {
+  // sanity check
+  if (boost::num_vertices(graph) <= 1) {
+    throw std::runtime_error("sc::Grammar::MutationReplaceCommand - graph has too few nodes");
+  }
+  sg::Vertex node_to_replace;
+  sg::Node* node_info;
+  // find command to replace
+  do {
+    node_to_replace = boost::random_vertex(graph, bx::RandomEngine());
+    node_info = &graph[node_to_replace];
+  } while (node_info->type_ != sg::kCommand);
+  int old_id = node_info->id_;
+  // generate new command id
+  int new_id;
+  int number_of_commands = static_cast<int>(commands_.size());
+  do {
+    // new command must match old output and mode
+    new_id = stdx::Random(number_of_commands);
+  } while (new_id != old_id
+           && commands_[new_id].Output() != commands_[old_id].Output()
+           && commands_[new_id].Mode() != commands_[old_id].Mode());
+  // new command info
+  const std::vector<sc::Argument>& arguments = CommandArguments(new_id);
+  std::size_t number_of_arguments = commands_[new_id].Arguments().size();
+  // remove invalid parameters
+  // removing an in edge invalidates the iterators, so we need to restart the
+  // search each time an edge is removed
+  sg::InEdgeIterator edge;
+  sg::InEdgeIterator edge_end;
+  bool do_it_again;
+  do {
+    do_it_again = false;
+    for (boost::tie(edge, edge_end) = boost::in_edges(node_to_replace, graph);
+         edge != edge_end;
+         ++edge) {
+      int input = graph[*edge].input_;
+      // remove input tree if it's for an extraneous parameter
+      // or if the argument is a constant
+      if (input >= number_of_arguments
+          || arguments[input].scaling_mode_ == sc::Argument::kConstant) {
+        RemoveSubTree(*edge, graph);
+        do_it_again = true;
+        // break out of for loop
+        break;
+      }
+    }
+  } while (do_it_again);
+  // now invalid parameters have been removed, validate the rest
+  for (boost::tie(edge, edge_end) = boost::in_edges(node_to_replace, graph);
+       edge != edge_end;
+       ++edge) {
+    // if the new argument is fixed range then correct the connection weight
+    int input = graph[*edge].input_;
+    if (arguments[input].fixed_range_) {
+      GenerateWeightAndOffset(arguments[input],
+                              node_info->rate_, 
+                              &graph[*edge]);
+    }
+  }
+  // apply new command id
+  node_info->id_ = new_id;
+  return true;
+}
+  
+int Grammar::GetCommandInputID(int command) const {
+  const std::vector<sc::Argument>& arguments = commands_[command].Arguments();
+  for (std::size_t i = 0, size = arguments.size(); i < size; i++) {
+    if (arguments[i].name_ == "in") {
+      return static_cast<int>(i);
+    }
+  }
+  return -1;
+}
+  
+const Argument& Grammar::GetCommandArgument(int command_id,
+                                            int argument_id) const {
+  return commands_[command_id].Arguments()[argument_id];
+}
+
+bool Grammar::MutationInsertCommand(sg::Graph& graph) const {
+  // sanity check
+  if (boost::num_vertices(graph) == 0) {
+    throw std::runtime_error("sc::Grammar::MutationInsertCommand - graph is empty");
+  }
+  // pick a random edge as insertion point
+  sg::Edge edge_to_replace;
+  sg::Vertex source_command;
+  sg::NodeType source_type;
+  do {
+    edge_to_replace = boost::random_edge(graph, bx::RandomEngine());
+    source_command = boost::source(edge_to_replace, graph);
+    source_type = graph[source_command].type_;
+  } while (source_type != sg::kCommand);
+  // store target connection info
+  sg::Vertex target_command = boost::target(edge_to_replace, graph);
+  sg::Connection target_connection = graph[edge_to_replace];
+  // make the new command
+  const sg::Node& source_node = graph[source_command];
+  sg::CommandRate rate = source_node.rate_;
+  sg::Vertex new_command = CreateCommand(graph, rate, 0, true, false);
+  // remove the existing connection
+  boost::remove_edge(source_command, target_command, graph);
+  // connect the new command to the source
+  sg::Connection source_connection(GetCommandInputID(graph[new_command].id_));
+  // generate weighting for new connection
+  double weight = stdx::RandomCoefficient();
+  if (rate == sg::kAudioRate) {
+    weight *= weight;
+  }
+  source_connection.weight_ = weight;
+  boost::add_edge(source_command, new_command, source_connection, graph);
+  // connect new command to the target, use old connection weighting
+  boost::add_edge(new_command, target_command, target_connection, graph);
+  // success!
+  return true;
+}
+
+} // sc namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sc_grammar.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,175 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// SuperCollider grammar, resonsible for generating and altering SuperCollider
+// synth graphs
+
+#pragma once
+
+#include "grammar.hpp"
+#include "range.hpp"
+#include "synth_graph.hpp"
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace sc {
+
+struct Argument {
+  
+  enum ScalingMode {
+    kScalingLinear,
+    kScalingLog,
+    kConstant
+  };
+  
+  std::string name_;
+  stdx::Range<double> range_;
+  stdx::Range<double> range_control_;
+  ScalingMode scaling_mode_;
+  double constant_value_;
+  bool fixed_range_;
+  
+  Argument(const std::string name = "")
+  : name_(name),
+    range_(0, 1),
+    range_control_(0, 1),
+    scaling_mode_(kScalingLinear),
+    constant_value_(0),
+    fixed_range_(false)
+  {}
+};
+
+class Command {
+public:
+  enum CommandMode {
+    kSource,
+    kModifier,
+    kSpecial,
+    kNumberOfModes
+  };
+  
+  enum SpecialCommands {
+    kMixer,
+    kMultiplier,
+    kNumberOfSpecialCommands
+  };
+  
+  enum OutputType {
+    kAll,
+    kAudio,
+    kControl,
+  };
+
+private:
+  std::string name_;
+  std::vector<Argument> arguments_;
+  CommandMode mode_;
+  OutputType output_;
+  
+public:
+  Command(const std::string& name,
+          CommandMode mode,
+          OutputType output = kAll,
+          const std::vector<Argument>& arguments = std::vector<Argument>())
+  : name_(name),
+    mode_(mode),
+    output_(output),
+    arguments_(arguments)
+  {}
+  
+  CommandMode Mode() const { return mode_; }
+  OutputType Output() const { return output_; }
+  const std::string& Name() const { return name_; }
+  const std::vector<Argument>& Arguments() const { return arguments_;}
+  const Argument& GetArgument(int argument) const {
+    return arguments_[argument];
+  }
+  bool IsAudioSource() { return (mode_ == kSource) && (output_ != kControl); }
+};
+
+class Grammar : public GrammarInterface {
+  // holds the commands available to the grammar
+  std::vector<Command> commands_;
+  typedef std::vector<Command>::size_type CommandID;
+  int max_depth_;
+
+public:
+  // used when generating trees to indicate current tree state
+  enum TreeMode {
+    kTreeMode_Command,
+    kTreeMode_Mod
+  };
+  
+  Grammar(const std::string& json_data);
+  
+  void ParseJSON(const std::string& json_data);
+  
+  const std::vector<Command>& Commands() const { return commands_; }
+  
+  void SetMaximumDepth(int max_depth) { max_depth_ = max_depth; }
+  
+  void RandomGraph(sg::Graph& graph) const;
+  void PickCrossoverNodes(const sg::Graph& parent_1, 
+                          const sg::Graph& parent_2,
+                          sg::Vertex* crossover_node_1,
+                          sg::Vertex* crossover_node_2) const;
+  bool MutationReplaceSubTree(sg::Graph& graph) const;
+  bool MutationAddSubTree(sg::Graph& graph) const;
+  bool MutationModifyInputs(sg::Graph& graph) const;
+  bool MutationModifyConnections(sg::Graph& graph) const;
+  bool MutationReplaceCommand(sg::Graph& graph) const;
+  bool MutationInsertCommand(sg::Graph& graph) const;
+  
+private:
+  int RandomCommand(sg::CommandRate rate,
+                    int tree_depth,
+                    bool must_be_modifier) const;
+  int RandomParameter(sg::Graph& graph) const;
+  
+  sg::Vertex RandomTree(sg::Graph& graph,
+                        sg::CommandRate rate,
+                        TreeMode tree_mode,
+                        int depth) const;
+  
+  sg::Vertex SpecialCommand(int command_id,
+                            sg::Graph& graph,
+                            sg::CommandRate output_mode,
+                            TreeMode tree_mode,
+                            int depth = 0,
+                            int minimum_channels = 2) const;
+  void AddTreeToSpecialCommand(sg::Vertex command,
+                               sg::Graph& graph,
+                               int input_id,
+                               TreeMode tree_mode,
+                               sg::CommandRate command_rate,
+                               bool* constant_added,
+                               std::set<int>* parameters,
+                               int depth) const;
+  sg::Vertex CreateCommand(sg::Graph &graph,
+                           sg::CommandRate rate,
+                           int depth,
+                           bool must_be_modifier = false,
+                           bool make_modifier_input = true) const;
+  int GetCommandInputID(int command_id) const;
+  const Argument& GetCommandArgument(int command_id, int argument_id) const;
+  const std::vector<sc::Argument>& CommandArguments(int command) const;
+};
+  
+} // sc namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/spectrum_analyzer.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,99 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// Wrapper classes for FFTW
+
+#pragma once
+
+#include "fftw3.h"
+
+#include <complex>
+
+namespace dsp {
+
+// Float version
+class SpectrumAnalyzerFloat {
+  fftwf_plan plan_;
+  int frame_size_;
+  float* input_;
+  std::complex<float>* output_;
+
+public:
+  SpectrumAnalyzerFloat(int frame_size = 1024)
+  : frame_size_(frame_size)
+  {
+    input_ = (float*)fftw_malloc(sizeof(float) * frame_size);
+    int buffer_size = sizeof(std::complex<float>) * frame_size / 2;
+    output_ = (std::complex<float>*)fftw_malloc(buffer_size);
+    plan_ = fftwf_plan_dft_r2c_1d(frame_size,
+                                  input_,
+                                  reinterpret_cast<fftwf_complex*>(output_),
+                                  FFTW_ESTIMATE);
+  }
+  
+  SpectrumAnalyzerFloat() {
+    fftw_free(input_);
+    fftw_free(output_);
+    fftwf_destroy_plan(plan_);
+  }
+  
+  void Execute() {
+    fftwf_execute(plan_);
+  }
+  
+  int Size() { return frame_size_; }
+  float* Input() { return input_; }
+  std::complex<float>* Output() { return output_; }
+};
+  
+// Double version
+class SpectrumAnalyzer {
+  fftw_plan plan_;
+  int frame_size_;
+  double* input_;
+  std::complex<double>* output_;
+  
+public:
+  SpectrumAnalyzer(int frame_size = 1024)
+  : frame_size_(frame_size)
+  {
+    input_ = (double*)fftw_malloc(sizeof(double) * frame_size);
+    int buffer_size = sizeof(std::complex<double>) * frame_size;
+    output_ = (std::complex<double>*)fftw_malloc(buffer_size);
+    plan_ = fftw_plan_dft_r2c_1d(frame_size,
+                                 input_,
+                                 reinterpret_cast<fftw_complex*>(output_),
+                                 FFTW_ESTIMATE);
+  }
+  
+  SpectrumAnalyzer() {
+    fftw_free(input_);
+    fftw_free(output_);
+    fftw_destroy_plan(plan_);
+  }
+  
+  void Execute() {
+    fftw_execute(plan_);
+  }
+  
+  int Size() { return frame_size_; }
+  double* Input() { return input_; }
+  std::complex<double>* Output() { return output_; }
+};
+
+} // dsp namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/statistics.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,139 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// Some useful stats functions
+
+#pragma once
+
+#include "range.hpp"
+#include "std_ex.hpp"
+
+#include <algorithm>
+#include <iterator>
+#include <numeric>
+#include <sstream>
+#include <stdexcept>
+
+namespace stats {
+
+// Sum
+template<typename Iterator>
+typename std::iterator_traits<Iterator>::value_type Sum(Iterator start,
+                                                        Iterator end) {
+  typename std::iterator_traits<Iterator>::value_type initializer(0);
+  return std::accumulate(start, end, initializer);
+}
+
+// Sum - container
+template<typename Container>
+typename Container::value_type Sum(const Container& container) {
+  return Sum(container.begin(), container.end());
+}
+
+// Mean
+template<typename Iterator>
+typename std::iterator_traits<Iterator>::value_type Mean(Iterator start,
+                                                         Iterator end) {
+  return Sum(start, end) / std::distance(start, end);
+}
+
+// Mean - container
+template<typename Container>
+typename Container::value_type Mean(const Container& container) {
+  return Mean(container.begin(), container.end());
+}
+
+// measures the MSE between a range and a target
+template<typename Iterator1, typename Iterator2>
+typename std::iterator_traits<Iterator1>::value_type 
+MeanSquaredError(Iterator1 start1, Iterator1 end1, Iterator2 start2) {
+  typedef typename std::iterator_traits<Iterator1>::value_type Value;
+  Value n = std::distance(start1, end1);
+  Value error(0);
+  while (start1 != end1) {
+    error += std::pow(*start1 - *start2, Value(2));
+    ++start1;
+    ++start2;
+  }
+  return error / n;
+}
+
+// MeanSquaredError - container adaptor
+template<typename Container>
+typename Container::value_type MeanSquaredError(const Container& x,
+                                                const Container& y) {
+  return MeanSquaredError(x.begin(), x.end(), y.begin());
+}
+
+// root mean square error
+template<typename Iterator1, typename Iterator2>
+double RMSE(Iterator1 start, Iterator1 end, Iterator2 target) {
+  return std::sqrt(MeanSquaredError(start, end, target));
+}
+
+// normalized root mean square error, using precomputed minima and maxima
+template<typename Iterator1, typename Iterator2, typename T>
+T NRMSE(Iterator1 start, Iterator1 end, Iterator2 target,
+        const stdx::Range<T>& range1, const stdx::Range<T>& range2) {
+  T range = std::max(range1.Maximum(), range2.Maximum())
+            - std::min(range1.Minimum(), range2.Minimum());
+  return RMSE(start, end, target) / range;
+}
+
+// Takes a set of numbers with sum <= 1 which define a distribution.
+// operator() returns index chosen randomly with distribution defined by the
+// provided probabilites.
+// if the probabilites have sum < 1 then the difference is taken to imply a 
+// single additional index
+// e.g. given:
+// ProbabilitySelector selector(boost::assign::list_of(0.1)(0.8));
+// selector() will yield 
+// '0' 10%,
+// '1' 80%,
+// '2' 10%
+class ProbabilitySelector {
+  std::vector<double> boundaries_;
+  
+public:
+  ProbabilitySelector() {}
+  ProbabilitySelector(const std::vector<double>& probabilities)
+  {
+    SetProbabilities(probabilities);
+  }
+  
+  void SetProbabilities(const std::vector<double>& probabilities) {
+    if (std::count_if(probabilities.begin(), probabilities.end(),
+                      stdx::LessThan<double>(0.0))) {
+      throw std::runtime_error("ProbabilitySelector: negative value found");
+    }
+    // assign range boundaries
+    std::partial_sum(probabilities.begin(), probabilities.end(), 
+                     std::back_inserter(boundaries_));
+  }
+  
+  std::size_t operator()() const {
+    double random = rand() / static_cast<double>(RAND_MAX);
+    std::vector<double>::const_iterator index;
+    index = std::upper_bound(boundaries_.begin(), boundaries_.end(), random);
+    return std::distance(boundaries_.begin(), index);
+  }
+  
+  bool Initialized() const { return !boundaries_.empty(); }
+};
+
+} // stats namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/std_ex.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,162 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// Miscellaneous C++ stdlib helper utilities
+
+#pragma once
+
+#include <cstdlib>
+#include <iostream>
+#include <iterator>
+#include <fstream>
+#include <map>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+
+namespace stdx {
+  
+typedef unsigned int uint;
+
+// Helper function for retrieving values from const std::maps
+template<typename M>
+const typename M::mapped_type& GetFromMap(const M& map, 
+                                          const typename M::key_type& key) {
+  typename M::const_iterator i = map.find(key);
+  if (i == map.end()) {
+    throw std::runtime_error("GetFromMap: specified key not in map.");
+  }
+  return i->second;
+}
+
+
+template<typename T>
+inline T RandomRange(T min, T max) {
+  return static_cast<T>(((double)rand() / (float)RAND_MAX) * (max - min) + min);
+}
+
+template<typename T>
+inline T RandomRangeInt(T min, T max) {
+  return static_cast<T>(((double)rand() / (float)RAND_MAX) 
+                        * (max - min) 
+                        + min + 0.5);
+}
+  
+template<typename T>
+inline T Random(T maximum) {
+  return static_cast<T>(((double)rand() / (double)RAND_MAX) * maximum);
+}
+
+inline bool Random5050() {
+  return rand() > (RAND_MAX / 2);
+}
+  
+inline double RandomCoefficient() {
+  return static_cast<double>(rand()) / static_cast<double>(RAND_MAX);
+}
+  
+inline bool Chance(double probability) {
+  return RandomCoefficient() < probability;
+}
+
+template<typename T>
+class RandomGenerator {
+  T minimum_;
+  T maximum_;
+  
+public:
+  RandomGenerator(T minimum = 0, T maximum = 1)
+  : minimum_(minimum),
+  maximum_(maximum)
+  {}
+  
+  T operator()() {
+    return RandomRange(minimum_, maximum_);
+  }
+};
+
+
+// clamps input T to range specified by U and V
+template<typename T, typename U, typename V>
+T Clamp(const T& value, const U& minimum, const V& maximum) {
+  return (value > maximum) ? maximum : (value < minimum) ? minimum : value;
+}
+  
+// Function object that increments its internal value by the provided step size
+template<typename T>
+class Stepper {
+  T value_;
+  T step_size_;
+public:
+  Stepper(const T& step_size, const T& initial_value = T())
+  : value_(initial_value),
+    step_size_(step_size)
+  {}
+  
+  T operator()() {
+    T result = value_;
+    value_ += step_size_;
+    return result;
+  }
+};
+  
+// Function object that returns true if value is less than internal value
+template<typename T>
+class LessThan {
+  T value_;
+public:
+  LessThan(const T& value) : value_(value) {}
+  bool operator()(const T& other) { return other < value_; }
+};
+
+// writes a container to a stream
+template<typename Container>
+void DumpContainer(const Container& container,
+                   const std::string& separator = "\n",
+                   std::ostream& output = std::cout) {
+  typedef typename Container::value_type Value;
+  std::copy(container.begin(), container.end(),
+            std::ostream_iterator<Value>(output, separator.c_str()));
+}
+
+// saves a container to a specified file path
+template<typename Container>
+void SaveContainerToFile(const Container& container,
+                         const std::string& file_path,
+                         const std::string& separator = "\n") {
+  std::ofstream file(file_path.c_str());
+  DumpContainer(container, separator, file);
+}
+
+template<typename T>
+void AppendToFile(const T& value_to_append,
+                  const std::string& file_path,
+                  const std::string& separator = "\n") {
+  std::ofstream file(file_path.c_str(),
+                     std::ofstream::app | std::ofstream::out);
+  file << value_to_append << separator;
+}
+  
+inline std::string LoadFile(const std::string& file_path) {
+  std::ifstream file(file_path.c_str());
+  std::stringstream buffer;
+  buffer << file.rdbuf();
+  return buffer.str();
+}
+
+} // stdx namespace
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/synth_graph.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,139 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+// The main synth graph classes
+
+#pragma once
+
+#include "boost/graph/adjacency_list.hpp"
+
+#include <string>
+#include <vector>
+
+namespace synth_graph {
+
+enum NodeType {
+  kUnknown = -1,
+  kCommand,
+  kSpecial,
+  kConstant,
+  kParameter
+};
+  
+enum CommandRate {
+  kAudioRate,
+  kControlRate
+};
+
+// Node, attached to each vertex
+struct Node {
+  int id_;
+  NodeType type_;
+  CommandRate rate_;
+  double constant_value_;
+  
+  Node() 
+  : id_(-1),
+    type_(kUnknown),
+    rate_(kAudioRate),
+    constant_value_(0)
+  {}
+  
+  Node(int id,
+       NodeType type,
+       CommandRate rate = kControlRate)
+  : id_(id),
+    type_(type),
+    rate_(rate),
+    constant_value_(0)
+  {}
+  
+  Node(double constant_value)
+  : id_(-1),
+    type_(kConstant),
+    rate_(kControlRate),
+    constant_value_(constant_value)
+  {}
+};
+
+// Connection, attached to each edge
+struct Connection {
+  // input that the edge is connected to
+  int input_;
+  double weight_;
+  double offset_;
+
+  Connection(int input = -1, double weight = 1, double offset = 0)
+  : input_(input),
+    weight_(weight),
+    offset_(offset)
+  {}
+  
+  // constructor for connection input is irrelevant
+  Connection(double weight, double offset = 0)
+  : input_(0),
+    weight_(weight),
+    offset_(offset)
+  {}
+  
+  bool IsActive() const {
+    return (weight_ != 1) || (offset_ != 0);
+  }
+};
+  
+enum {
+  kFitnessUnrated = -1
+};
+
+// Properties stored with the graph
+struct GraphProperties {
+  // parameter values
+  std::vector<double> parameters_;
+  // graph id
+  int id_;
+  // measured fitness
+  double fitness_;
+  // rendered output path
+  std::string render_path_;
+  // converted graphviz path
+  std::string dot_path_;
+  
+  GraphProperties() 
+  : parameters_(0),
+    fitness_(kFitnessUnrated),
+    id_(0)
+  {}
+};
+
+// defined as bidirectional to allow access to in_edges of a vertex
+// we need to use vecS for storage for to_graphviz
+typedef boost::adjacency_list<boost::vecS,
+                              boost::vecS,
+                              boost::bidirectionalS,
+                              Node,
+                              Connection,
+                              GraphProperties> Graph;
+
+typedef boost::graph_traits<Graph>::vertex_descriptor Vertex;
+typedef boost::graph_traits<Graph>::vertex_iterator VertexIterator;
+typedef boost::graph_traits<Graph>::edge_descriptor Edge;
+typedef boost::graph_traits<Graph>::edge_iterator EdgeIterator;
+typedef boost::graph_traits<Graph>::in_edge_iterator InEdgeIterator;
+
+} // synth_graph namespace
+namespace sg = synth_graph;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/window_makers.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,54 @@
+//  Copyright 2011, Ian Hobson.
+//
+//  This file is part of gpsynth.
+//
+//  gpsynth 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 3 of the License, or
+//  (at your option) any later version.
+//
+//  gpsynth 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 gpsynth in the file COPYING. 
+//  If not, see http://www.gnu.org/licenses/.
+
+#pragma once
+
+#include <cmath>
+#include <iterator>
+
+namespace dsp {
+  
+template<typename OutputIterator>
+void BlackmanWindow(int size, OutputIterator output) {
+  typedef typename std::iterator_traits<OutputIterator>::value_type T;
+  T m1 = (M_PI * 2.0) / (size - 1.0);
+  T m2 = (M_PI * 4.0) / (size - 1.0);
+  for (T i = 0; i < size; i++) {
+    *output++ = 0.42 - 0.5 * std::cos(i * m1) + 0.08 * std::cos(i * m2);
+  }
+}
+
+template<typename OutputIterator>
+void HannWindow(int size, OutputIterator output) {
+  typedef typename std::iterator_traits<OutputIterator>::value_type T;
+  T m = (M_PI * 2.0) / (size - 1.0);
+  for (T i = 0; i < size; i++) {
+    *output++ = 0.5 - 0.5 * std::cos(i * m);
+  }
+}
+
+template<typename OutputIterator>
+void HammingWindow(int size, OutputIterator output) {
+  typedef typename std::iterator_traits<OutputIterator>::value_type T;
+  T m = (M_PI * 2.0) / (size - 1.0);
+  for (T i = 0; i < size; i++) {
+    *output++ = 0.54 - 0.46 * std::cos(i * m);
+  }
+}
+
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,25 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process.hpp
+ *
+ * Convenience header that includes all public Boost.Process header files.
+ */
+
+#ifndef BOOST_PROCESS_HPP
+#define BOOST_PROCESS_HPP
+
+#include <boost/process/all.hpp>
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/all.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,40 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/all.hpp
+ *
+ * Convenience header that includes all public Boost.Process header files.
+ */
+
+#ifndef BOOST_PROCESS_ALL_HPP
+#define BOOST_PROCESS_ALL_HPP
+
+#include <boost/process/child.hpp>
+#include <boost/process/context.hpp>
+#include <boost/process/environment.hpp>
+#include <boost/process/handle.hpp>
+#include <boost/process/operations.hpp>
+#include <boost/process/pid_type.hpp>
+#include <boost/process/pipe.hpp>
+#include <boost/process/pistream.hpp>
+#include <boost/process/postream.hpp>
+#include <boost/process/process.hpp>
+#include <boost/process/self.hpp>
+#include <boost/process/status.hpp>
+#include <boost/process/stream_behavior.hpp>
+#include <boost/process/stream_ends.hpp>
+#include <boost/process/stream_id.hpp>
+#include <boost/process/stream_type.hpp>
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/child.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,92 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/child.hpp
+ *
+ * Includes the declaration of the child class.
+ */
+
+#ifndef BOOST_PROCESS_CHILD_HPP
+#define BOOST_PROCESS_CHILD_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+#elif defined(BOOST_WINDOWS_API)
+#   include <windows.h>
+#else
+#   error "Unsupported platform."
+#endif
+
+#include <boost/process/process.hpp>
+#include <boost/process/pid_type.hpp>
+#include <boost/process/stream_id.hpp>
+#include <boost/process/handle.hpp>
+#include <map>
+
+namespace boost {
+namespace process {
+
+/**
+ * The child class provides access to a child process.
+ */
+class child : public process
+{
+public:
+    /**
+     * Creates a new child object that represents the just spawned child
+     * process \a id.
+     */
+    child(pid_type id, std::map<stream_id, handle> handles)
+        : process(id),
+        handles_(handles)
+    {
+    }
+
+#if defined(BOOST_WINDOWS_API)
+    /**
+     * Creates a new child object that represents the just spawned child
+     * process \a id.
+     *
+     * This operation is only available on Windows systems.
+     */
+    child(handle hprocess, std::map<stream_id, handle> handles)
+        : process(hprocess),
+        handles_(handles)
+    {
+    }
+#endif
+
+    /**
+     * Gets a handle to a stream attached to the child.
+     *
+     * If the handle doesn't exist an invalid handle is returned.
+     */
+    handle get_handle(stream_id id) const
+    {
+        std::map<stream_id, handle>::const_iterator it = handles_.find(id);
+        return (it != handles_.end()) ? it->second : handle();
+    }
+
+private:
+    /**
+     * Handles providing access to streams attached to the child process.
+     */
+    std::map<stream_id, handle> handles_;
+};
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/config.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,74 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/config.hpp
+ *
+ * Defines macros that are used by the library to determine the operating
+ * system it is running under and the features it supports.
+ */
+
+#ifndef BOOST_PROCESS_CONFIG_HPP
+#define BOOST_PROCESS_CONFIG_HPP
+
+#include <boost/config.hpp>
+#include <boost/system/config.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+
+#if defined(BOOST_POSIX_API)
+#   include <errno.h>
+#elif defined(BOOST_WINDOWS_API)
+#   include <windows.h>
+#endif
+
+#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
+#   if !defined(BOOST_PROCESS_POSIX_PATH_MAX) || defined(BOOST_PROCESS_DOXYGEN)
+/**
+ * Specifies the system's maximal supported path length.
+ *
+ * The macro BOOST_PROCESS_POSIX_PATH_MAX is set to a positive integer
+ * value which specifies the system's maximal supported path length. It is
+ * only used if neither PATH_MAX nor _PC_PATH_MAX and HAVE_PATHCONF are defined.
+ * The maximal supported path length is required by
+ * boost::process::self::get_work_dir(). Please note that this function is
+ * also called by the constructor of boost::process::context.
+ */
+#       define BOOST_PROCESS_POSIX_PATH_MAX 259
+#   endif
+#endif
+
+/** \cond */
+#define BOOST_PROCESS_SOURCE_LOCATION \
+    "in file '" __FILE__ "', line " BOOST_STRINGIZE(__LINE__) ": "
+
+#if defined(BOOST_POSIX_API)
+#   define BOOST_PROCESS_LAST_ERROR errno
+#elif defined(BOOST_WINDOWS_API)
+#   define BOOST_PROCESS_LAST_ERROR GetLastError()
+#endif
+
+#define BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(what) \
+    boost::throw_exception(boost::system::system_error( \
+        boost::system::error_code(BOOST_PROCESS_LAST_ERROR, \
+            boost::system::get_system_category()), \
+        BOOST_PROCESS_SOURCE_LOCATION what))
+
+#define BOOST_PROCESS_THROW_ERROR(error, what) \
+    boost::throw_exception(boost::system::system_error( \
+        boost::system::error_code(error, \
+            boost::system::get_system_category()), \
+        BOOST_PROCESS_SOURCE_LOCATION what))
+/** \endcond */
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/context.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,131 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/context.hpp
+ *
+ * Includes the declaration of the context class.
+ */
+
+#ifndef BOOST_PROCESS_CONTEXT_HPP
+#define BOOST_PROCESS_CONTEXT_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+#   include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+#   include <windows.h>
+#endif
+
+#include <boost/process/stream_id.hpp>
+#include <boost/process/stream_ends.hpp>
+#include <boost/process/stream_type.hpp>
+#include <boost/process/environment.hpp>
+#include <boost/process/self.hpp>
+#include <boost/process/stream_behavior.hpp>
+#include <boost/function.hpp>
+#include <string>
+#include <map>
+
+namespace boost {
+namespace process {
+
+/**
+ * Context class to define how a child process is created.
+ *
+ * The context class is used to configure streams, to set the work directory
+ * and define environment variables. It is also used to change a process
+ * name (the variable commonly known as argv[0]).
+ */
+struct context
+{
+    typedef std::map<stream_id, boost::function<stream_ends (stream_type)> >
+        streams_t;
+
+    /**
+     * Streams.
+     *
+     * Streams of a child process can be configured through factory functions
+     * which return a pair of handles - one handle to use as a stream end
+     * in the child process and possibly another handle to use as a stream end
+     * in the parent process (if a pipe is setup both processes can communicate
+     * with each other).
+     */
+    streams_t streams;
+
+    /**
+     * Process name.
+     *
+     * The child process can access the process name via a variable
+     * commonly known as argv[0].
+     */
+    std::string process_name;
+
+    /**
+     * Work directory.
+     */
+    std::string work_dir;
+
+    /**
+     * Environment variables.
+     */
+    environment env;
+
+    /**
+     * Constructs a process context.
+     *
+     * The default behavior of standard streams is to inherit them. The current
+     * work directory is also the work directory of the child process. The child
+     * process also inherits all environment variables.
+     */
+    context()
+        : work_dir(self::get_work_dir()),
+        env(self::get_environment())
+    {
+#if defined(BOOST_POSIX_API)
+        streams[stdin_id] = behavior::inherit(STDIN_FILENO);
+        streams[stdout_id] = behavior::inherit(STDOUT_FILENO);
+        streams[stderr_id] = behavior::inherit(STDERR_FILENO);
+#elif defined(BOOST_WINDOWS_API)
+        streams[stdin_id] = behavior::inherit(GetStdHandle(STD_INPUT_HANDLE));
+        streams[stdout_id] = behavior::inherit(GetStdHandle(STD_OUTPUT_HANDLE));
+        streams[stderr_id] = behavior::inherit(GetStdHandle(STD_ERROR_HANDLE));
+#endif
+    }
+
+#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
+    /**
+     * Setups a child process.
+     *
+     * This is an extension point to support more configuration options for
+     * child processes. You can initialize \a setup with a user-defined function
+     * which is called when a child process is created.
+     *
+     * On POSIX platforms setup() is called in the child process. That's why in
+     * a multithreaded application only async-signal-safe functions must be
+     * called in the function \a setup is bound to.
+     *
+     * On Windows platforms setup() is called in the parent process. A
+     * reference to a STARTUPINFOA structure is passed as parameter.
+     */
+    boost::function<void ()> setup;
+#elif defined(BOOST_WINDOWS_API)
+    boost::function<void (STARTUPINFOA&)> setup;
+#endif
+};
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/detail/basic_status.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,69 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/detail/basic_status.hpp
+ *
+ * Includes the declaration of the basic status class.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_BASIC_STATUS_HPP
+#define BOOST_PROCESS_DETAIL_BASIC_STATUS_HPP
+
+#include <boost/process/config.hpp>
+#include <boost/process/pid_type.hpp>
+#include <boost/asio.hpp>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+/**
+ * The basic_status class to wait for processes to exit.
+ *
+ * The basic_status class is a Boost.Asio I/O object and supports synchronous
+ * and asynchronous wait operations. It must be instantiated with a Service.
+ */
+template <typename Service>
+class basic_status
+    : public boost::asio::basic_io_object<Service>
+{
+public:
+    explicit basic_status(boost::asio::io_service &io_service)
+    : boost::asio::basic_io_object<Service>(io_service)
+    {
+    }
+
+    /**
+     * Waits synchronously for a process to exit.
+     */
+    int wait(pid_type pid)
+    {
+        return this->service.wait(this->implementation, pid);
+    }
+
+    /**
+     * Waits asynchronously for a process to exit.
+     */
+    template <typename Handler>
+    void async_wait(pid_type pid, Handler handler)
+    {
+        this->service.async_wait(this->implementation, pid, handler);
+    }
+};
+
+}
+}
+}
+
+#endif 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/detail/basic_status_service.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,318 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/detail/basic_status_service.hpp
+ *
+ * Includes the declaration of the basic status service class.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_BASIC_STATUS_SERVICE_HPP
+#define BOOST_PROCESS_DETAIL_BASIC_STATUS_SERVICE_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+#   include <boost/process/operations.hpp>
+#   include <string>
+#   include <sys/types.h>
+#   include <sys/wait.h>
+#elif defined(BOOST_WINDOWS_API)
+#   include <windows.h>
+#else
+#   error "Unsupported platform."
+#endif
+
+#include <boost/process/pid_type.hpp>
+#include <boost/process/detail/status_impl.hpp>
+#include <boost/asio.hpp>
+#include <boost/thread.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/unordered_map.hpp>
+#include <vector>
+#include <algorithm>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+/**
+ * The basic_status_service class provides the service to wait for processes
+ * synchronously and asynchronously.
+ */
+template <typename StatusImplementation = status_impl>
+class basic_status_service
+    : public boost::asio::detail::service_base<StatusImplementation>
+{
+public:
+    explicit basic_status_service(boost::asio::io_service &io_service)
+        : boost::asio::detail::service_base<StatusImplementation>(io_service),
+#if defined(BOOST_POSIX_API)
+        interrupt_pid_(-1),
+        pids_(0)
+#elif defined(BOOST_WINDOWS_API)
+        run_(true)
+#endif
+    {
+#if defined(BOOST_WINDOWS_API)
+        handles_.push_back(CreateEvent(NULL, FALSE, FALSE, NULL));
+        if (handles_[0] == NULL)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateEvent() failed");
+        work_thread_ = boost::thread(
+            &basic_status_service<StatusImplementation>::work_thread, this);
+#endif
+    }
+
+    ~basic_status_service()
+    {
+#if defined(BOOST_POSIX_API)
+        boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+        bool worker_thread_active = (pids_ != 0);
+        lock.unlock();
+        if (worker_thread_active)
+        {
+            stop_work_thread();
+            work_thread_.join();
+        }
+#elif defined(BOOST_WINDOWS_API)
+        stop_work_thread();
+        work_thread_.join();
+        CloseHandle(handles_[0]);
+#endif
+    }
+
+    typedef boost::shared_ptr<StatusImplementation> implementation_type;
+
+    void construct(implementation_type &impl)
+    {
+        impl = boost::make_shared<StatusImplementation>();
+        boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+        impls_.push_back(impl);
+    }
+
+    void destroy(implementation_type &impl)
+    {
+        boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+        typename std::vector<implementation_type>::iterator it =
+            std::find(impls_.begin(), impls_.end(), impl);
+        if (it != impls_.end())
+            impls_.erase(it);
+#if defined(BOOST_WINDOWS_API)
+        interrupt_work_thread();
+        work_thread_cond_.wait(work_thread_mutex_);
+        impl->clear(handles_);
+        work_thread_cond_.notify_all();
+#endif
+        impl.reset();
+    }
+
+    int wait(implementation_type &impl, pid_type pid)
+    {
+        boost::system::error_code ec;
+        int status = impl->wait(pid, ec);
+#if defined(BOOST_POSIX_API)
+        if (ec.value() == ECHILD)
+        {
+            boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+            boost::unordered_map<pid_t, int>::iterator it = statuses_.find(pid);
+            if (it == statuses_.end())
+            {
+                work_thread_cond_.wait(work_thread_mutex_);
+                it = statuses_.find(pid);
+            }
+            if (it != statuses_.end())
+            {
+                status = it->second;
+                statuses_.erase(it);
+                ec.clear();
+            }
+        }
+#endif
+        boost::asio::detail::throw_error(ec);
+        return status;
+    }
+
+    template <typename Handler>
+    void async_wait(implementation_type &impl, pid_type pid, Handler handler)
+    {
+#if defined(BOOST_POSIX_API)
+        boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+        if (++pids_ == 1)
+        {
+            work_.reset(new boost::asio::io_service::work(
+                this->get_io_service()));
+            work_thread_ = boost::thread(
+                &basic_status_service<StatusImplementation>::work_thread,
+                this);
+        }
+        impl->async_wait(pid, this->get_io_service().wrap(handler));
+#elif defined(BOOST_WINDOWS_API)
+        HANDLE handle = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
+            FALSE, pid);
+        if (handle == NULL)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed");
+        boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+        if (!work_)
+            work_.reset(new boost::asio::io_service::work(
+                this->get_io_service()));
+        interrupt_work_thread();
+        work_thread_cond_.wait(work_thread_mutex_);
+        handles_.push_back(handle);
+        impl->async_wait(handle, this->get_io_service().wrap(handler));
+        work_thread_cond_.notify_all();
+#endif
+    }
+
+private:
+    void shutdown_service()
+    {
+#if defined(BOOST_WINDOWS_API)
+        boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+        work_.reset();
+#endif
+    }
+
+    void work_thread()
+    {
+#if defined(BOOST_POSIX_API)
+        for (;;)
+        {
+            int status;
+            pid_t pid = ::wait(&status);
+            if (pid == -1)
+            {
+                if (errno != EINTR)
+                    BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("wait(2) failed");
+            }
+            else if (interrupted(pid))
+            {
+                // On POSIX the only reason to interrupt is to break out.
+                break;
+            }
+            else
+            {
+                boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+                bool regchild = false;
+                for (typename std::vector<implementation_type>::iterator it =
+                    impls_.begin(); it != impls_.end(); ++it)
+                    regchild |= (*it)->complete(pid, status);
+                if (regchild && --pids_ == 0)
+                {
+                    work_.reset();
+                    break;
+                }
+                else if (!regchild)
+                {
+                    statuses_.insert(boost::unordered_map<pid_t, int>::
+                        value_type(pid, status));
+                    work_thread_cond_.notify_all();
+                }
+            }
+        }
+#elif defined(BOOST_WINDOWS_API)
+        for (;;)
+        {
+            DWORD res = WaitForMultipleObjects(handles_.size(), &handles_[0],
+                FALSE, INFINITE);
+            if (res == WAIT_FAILED)
+                BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                    "WaitForMultipleObjects() failed");
+            else if (res - WAIT_OBJECT_0 == 0)
+            {
+                boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+                if (!run_)
+                    break;
+                work_thread_cond_.notify_all();
+                work_thread_cond_.wait(work_thread_mutex_);
+            }
+            else if (res - WAIT_OBJECT_0 > 0)
+            {
+                HANDLE handle = handles_[res - WAIT_OBJECT_0];
+                DWORD exit_code;
+                if (!GetExitCodeProcess(handle, &exit_code))
+                    BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                        "GetExitCodeProcess() failed");
+                boost::unique_lock<boost::mutex> lock(work_thread_mutex_);
+                for (typename std::vector<implementation_type>::iterator it =
+                    impls_.begin(); it != impls_.end(); ++it)
+                    (*it)->complete(handle, exit_code);
+                std::vector<HANDLE>::iterator it = handles_.begin();
+                std::advance(it, res - WAIT_OBJECT_0);
+                handles_.erase(it);
+                if (handles_.size() == 1)
+                    work_.reset();
+            }
+        }
+#endif
+    }
+
+    void interrupt_work_thread()
+    {
+#if defined(BOOST_POSIX_API)
+        // By creating a child process which immediately exits
+        // we interrupt wait().
+        std::vector<std::string> args;
+        args.push_back("-c");
+        args.push_back("'exit'");
+        interrupt_pid_ = create_child("/bin/sh", args).get_id();
+#elif defined(BOOST_WINDOWS_API)
+        // By signaling the event in the first slot WaitForMultipleObjects()
+        // will return. The work thread won't do anything except checking if
+        // it should continue to run.
+        if (!SetEvent(handles_[0]))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("SetEvent() failed");
+#endif
+    }
+
+#if defined(BOOST_POSIX_API)
+    bool interrupted(pid_t pid)
+    {
+        boost::mutex::scoped_lock lock(work_thread_mutex_);
+        return interrupt_pid_ == pid;
+    }
+#endif
+
+    void stop_work_thread()
+    {
+        boost::mutex::scoped_lock lock(work_thread_mutex_);
+#if defined(BOOST_WINDOWS_API)
+        // Access to run_ must be sychronized with running().
+        run_ = false;
+#endif
+        // Access to interrupt_pid_ must be sychronized with interrupted().
+        interrupt_work_thread();
+    }
+
+    boost::scoped_ptr<boost::asio::io_service::work> work_;
+    std::vector<implementation_type> impls_;
+    boost::mutex work_thread_mutex_;
+    boost::thread work_thread_;
+    boost::condition_variable_any work_thread_cond_;
+#if defined(BOOST_POSIX_API)
+    pid_t interrupt_pid_;
+    int pids_;
+    boost::unordered_map<pid_t, int> statuses_;
+#elif defined(BOOST_WINDOWS_API)
+    bool run_;
+    std::vector<HANDLE> handles_;
+#endif
+};
+
+}
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/detail/posix_helpers.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,106 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/detail/posix_helpers.hpp
+ *
+ * Includes the declaration of helper functions for POSIX systems.
+ */
+
+#ifndef BOOST_PROCESS_POSIX_HELPERS_HPP
+#define BOOST_PROCESS_POSIX_HELPERS_HPP
+
+#include <boost/process/config.hpp>
+#include <boost/process/environment.hpp>
+#include <string>
+#include <utility>
+#include <cstring>
+#include <cstddef>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+/**
+ * Converts an environment to a char** table as used by execve().
+ *
+ * Converts the environment's contents to the format used by the
+ * execve() system call. The returned char** array is allocated
+ * in dynamic memory; the caller must free it when not used any
+ * more. Each entry is also allocated in dynamic memory and is a
+ * NULL-terminated string of the form var=value; these must also be
+ * released by the caller.
+ *
+ * This operation is only available on POSIX systems.
+ *
+ * \return The first argument of the pair is an integer that indicates
+ *         how many strings are stored in the second argument. The
+ *         second argument is a NULL-terminated, dynamically allocated
+ *         array of dynamically allocated strings representing the
+ *         enviroment's content. Each array entry is a NULL-terminated
+ *         string of the form var=value. The caller is responsible for
+ *         freeing them.
+ */
+inline std::pair<std::size_t, char**> environment_to_envp(const environment
+    &env)
+{
+    std::size_t nargs = env.size();
+    char **envp = new char*[nargs + 1];
+    environment::size_type i = 0;
+    for (environment::const_iterator it = env.begin(); it != env.end(); ++it)
+    {
+        std::string s = it->first + "=" + it->second;
+        envp[i] = new char[s.size() + 1];
+        std::strncpy(envp[i], s.c_str(), s.size() + 1);
+        ++i;
+    }
+    envp[i] = 0;
+    return std::pair<std::size_t, char**>(nargs, envp);
+}
+
+/**
+ * Converts the command line to an array of C strings.
+ *
+ * Converts the command line's list of arguments to the format expected
+ * by the \a argv parameter in the POSIX execve() system call.
+ *
+ * This operation is only available on POSIX systems.
+ *
+ * \return The first argument of the pair is an integer that indicates
+ *         how many strings are stored in the second argument. The
+ *         second argument is a NULL-terminated, dynamically allocated
+ *         array of dynamically allocated strings holding the arguments
+ *         to the executable. The caller is responsible for freeing them.
+ */
+template <class Arguments>
+inline std::pair<std::size_t, char**> collection_to_argv(const Arguments &args)
+{
+    std::size_t nargs = args.size();
+    char **argv = new char*[nargs + 1];
+    typename Arguments::size_type i = 0;
+    for (typename Arguments::const_iterator it = args.begin(); it != args.end();
+        ++it)
+    {
+        argv[i] = new char[it->size() + 1];
+        std::strncpy(argv[i], it->c_str(), it->size() + 1);
+        ++i;
+    }
+    argv[nargs] = 0;
+    return std::pair<std::size_t, char**>(nargs, argv);
+}
+
+}
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/detail/status_impl.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,189 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/detail/status_impl.hpp
+ *
+ * Includes the declaration of the status implementation class.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_STATUS_IMPL_HPP
+#define BOOST_PROCESS_DETAIL_STATUS_IMPL_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+#   include <sys/types.h>
+#   include <signal.h>
+#   include <sys/wait.h>
+#   include <errno.h>
+#elif defined(BOOST_WINDOWS_API)
+#   include <windows.h>
+#else
+#   error "Unsupported platform."
+#endif
+
+#include <boost/process/pid_type.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/ptr_container/ptr_unordered_map.hpp>
+#include <algorithm>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+#if defined(BOOST_POSIX_API)
+typedef pid_t phandle;
+#elif defined(BOOST_WINDOWS_API)
+typedef HANDLE phandle;
+#endif
+
+struct operation
+{
+    virtual void operator()(int exit_code)
+    {
+#if defined(BOOST_MSVC)
+        exit_code;
+#endif
+    }
+};
+
+template <typename Handler>
+class wrapped_handler : public operation
+{
+public:
+    wrapped_handler(Handler handler)
+    : handler_(handler)
+    {
+    }
+
+    void operator()(int exit_code)
+    {
+        handler_(boost::system::error_code(), exit_code);
+    }
+
+private:
+    Handler handler_;
+};
+
+/**
+ * The status_impl class saves internal data of every status I/O object.
+ */
+class status_impl
+{
+public:
+#if defined(BOOST_WINDOWS_API)
+    template <typename Container>
+    void clear(Container &handles)
+    {
+        for (operations_type::iterator it = ops_.begin(); it != ops_.end();
+            ++it)
+        {
+            for (typename Container::iterator it2 = handles.begin(); it2 !=
+                handles.end(); ++it2)
+            {
+                if (*it2 == it->first)
+                {
+                    handles.erase(it2);
+                    break;
+                }
+            }
+            CloseHandle(it->first);
+        }
+    }
+#endif
+
+    int wait(pid_type pid, boost::system::error_code &ec)
+    {
+#if defined(BOOST_POSIX_API)
+        pid_t p;
+        int status;
+        do
+        {
+            p = waitpid(pid, &status, 0);
+        } while (p == -1 && errno == EINTR);
+        if (p == -1)
+        {
+            ec = boost::system::error_code(errno,
+                    boost::system::get_system_category());
+            return -1;
+        }
+        return status;
+#elif defined(BOOST_WINDOWS_API)
+        HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE,
+            pid);
+        if (h == NULL)
+        {
+            ec = boost::system::error_code(GetLastError(),
+                    boost::system::get_system_category());
+            return -1;
+        }
+
+        if (WaitForSingleObject(h, INFINITE) == WAIT_FAILED)
+        {
+            CloseHandle(h);
+            ec = boost::system::error_code(GetLastError(),
+                    boost::system::get_system_category());
+            return -1;
+        }
+
+        DWORD exit_code;
+        if (!GetExitCodeProcess(h, &exit_code))
+        {
+            CloseHandle(h);
+            ec = boost::system::error_code(GetLastError(),
+                    boost::system::get_system_category());
+            return -1;
+        }
+        if (!CloseHandle(h))
+        {
+            ec = boost::system::error_code(GetLastError(),
+                    boost::system::get_system_category());
+            return -1;
+        }
+        return exit_code;
+#endif
+    }
+
+    template <typename Handler>
+    void async_wait(phandle ph, Handler handler)
+    {
+        ops_.insert(ph, new wrapped_handler<Handler>(handler));
+    }
+
+    bool complete(phandle ph, int exit_code)
+    {
+        boost::iterator_range<operations_type::iterator> r =
+            ops_.equal_range(ph);
+        if (r.empty())
+            return false;
+        for (operations_type::iterator it = r.begin(); it != r.end(); ++it)
+            (*it->second)(exit_code);
+        ops_.erase(r.begin(), r.end());
+#if defined(BOOST_WINDOWS_API)
+        if (!CloseHandle(ph))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed");
+#endif
+        return true;
+    }
+
+private:
+    typedef boost::ptr_unordered_multimap<phandle, operation> operations_type;
+    operations_type ops_;
+};
+
+}
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/detail/systembuf.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,228 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/detail/systembuf.hpp
+ *
+ * Includes the declaration of the systembuf class.
+ */
+
+#ifndef BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP
+#define BOOST_PROCESS_DETAIL_SYSTEMBUF_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+#   include <sys/types.h>
+#   include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+#   include <windows.h>
+#else
+#   error "Unsupported platform."
+#endif
+
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/assert.hpp>
+#include <streambuf>
+#include <cstddef>
+
+namespace boost {
+namespace process {
+
+class postream;
+
+namespace detail {
+
+/**
+ * std::streambuf implementation for handles.
+ *
+ * systembuf provides a std::streambuf implementation for handles.
+ * Contrarywise to the handle class, this class does \b not take
+ * ownership of the native handle; this should be taken care of
+ * somewhere else.
+ *
+ * This class follows the expected semantics of a std::streambuf object.
+ * However, it is not copyable to avoid introducing inconsistences with
+ * the on-disk file and the in-memory buffers.
+ */
+class systembuf : public std::streambuf, public boost::noncopyable
+{
+    friend class boost::process::postream;
+
+public:
+#if defined(BOOST_PROCESS_DOXYGEN)
+    /**
+     * Opaque name for the native handle type.
+     */
+    typedef NativeHandleType handle_type;
+#elif defined(BOOST_POSIX_API)
+    typedef int handle_type;
+#elif defined(BOOST_WINDOWS_API)
+    typedef HANDLE handle_type;
+#endif
+
+    /**
+     * Constructs a new systembuf for the given handle.
+     *
+     * This constructor creates a new systembuf object that reads or
+     * writes data from/to the \a h native handle. This handle
+     * is \b not owned by the created systembuf object; the code
+     * should take care of it externally.
+     *
+     * This class buffers input and output; the buffer size may be
+     * tuned through the \a bufsize parameter, which defaults to 8192
+     * bytes.
+     *
+     * \see pistream and postream
+     */
+    explicit systembuf(handle_type h, std::size_t bufsize = 8192)
+        : handle_(h),
+          bufsize_(bufsize),
+          read_buf_(new char[bufsize]),
+          write_buf_(new char[bufsize])
+    {
+#if defined(BOOST_POSIX_API)
+        BOOST_ASSERT(handle_ >= 0);
+#elif defined(BOOST_WINDOWS_API)
+        BOOST_ASSERT(handle_ != INVALID_HANDLE_VALUE);
+#endif
+        BOOST_ASSERT(bufsize_ > 0);
+        setp(write_buf_.get(), write_buf_.get() + bufsize_);
+    }
+
+protected:
+    /**
+     * Reads new data from the native handle.
+     *
+     * This operation is called by input methods when there is no more
+     * data in the input buffer. The function fills the buffer with new
+     * data, if available.
+     *
+     * \pre All input positions are exhausted (gptr() >= egptr()).
+     * \post The input buffer has new data, if available.
+     * \returns traits_type::eof() if a read error occurrs or there are
+     *          no more data to be read. Otherwise returns
+     *          traits_type::to_int_type(*gptr()).
+     */
+    virtual int_type underflow()
+    {
+        BOOST_ASSERT(gptr() >= egptr());
+
+        bool ok;
+#if defined(BOOST_POSIX_API)
+        ssize_t cnt = read(handle_, read_buf_.get(), bufsize_);
+        ok = (cnt != -1 && cnt != 0);
+#elif defined(BOOST_WINDOWS_API)
+        DWORD cnt;
+        BOOL res = ReadFile(handle_, read_buf_.get(), bufsize_, &cnt, NULL);
+        ok = (res && cnt > 0);
+#endif
+
+        if (!ok)
+            return traits_type::eof();
+        else
+        {
+            setg(read_buf_.get(), read_buf_.get(), read_buf_.get() + cnt);
+            return traits_type::to_int_type(*gptr());
+        }
+    }
+
+    /**
+     * Makes room in the write buffer for additional data.
+     *
+     * This operation is called by output methods when there is no more
+     * space in the output buffer to hold a new element. The function
+     * first flushes the buffer's contents to disk and then clears it to
+     * leave room for more characters. The given \a c character is
+     * stored at the beginning of the new space.
+     *
+     * \pre All output positions are exhausted (pptr() >= epptr()).
+     * \post The output buffer has more space if no errors occurred
+     *       during the write to disk.
+     * \post *(pptr() - 1) is \a c.
+     * \returns traits_type::eof() if a write error occurrs. Otherwise
+     *          returns traits_type::not_eof(c).
+     */
+    virtual int_type overflow(int c)
+    {
+        BOOST_ASSERT(pptr() >= epptr());
+
+        if (sync() == -1)
+            return traits_type::eof();
+
+        if (!traits_type::eq_int_type(c, traits_type::eof()))
+        {
+            traits_type::assign(*pptr(), static_cast<traits_type::char_type>(
+                c));
+            pbump(1);
+        }
+
+        return traits_type::not_eof(c);
+    }
+
+    /**
+     * Flushes the output buffer to disk.
+     *
+     * Synchronizes the systembuf buffers with the contents of the file
+     * associated to this object through the native handle. The output buffer
+     * is flushed to disk and cleared to leave new room for more data.
+     *
+     * \returns 0 on success, -1 if an error occurred.
+     */
+    virtual int sync()
+    {
+#if defined(BOOST_POSIX_API)
+        ssize_t cnt = pptr() - pbase();
+        bool ok = (write(handle_, pbase(), cnt) == cnt);
+        if (ok)
+            pbump(static_cast<int>(-cnt));
+        return ok ? 0 : -1;
+#elif defined(BOOST_WINDOWS_API)
+        long cnt = pptr() - pbase();
+        DWORD rcnt;
+        BOOL res = WriteFile(handle_, pbase(), cnt, &rcnt, NULL);
+        bool ok = (res && static_cast<long>(rcnt) == cnt);
+        if (ok)
+            pbump(-cnt);
+        return ok ? 0 : -1;
+#endif
+    }
+
+private:
+    /**
+     * Native handle used by the systembuf object.
+     */
+    handle_type handle_;
+
+    /**
+     * Internal buffer size used during read and write operations.
+     */
+    std::size_t bufsize_;
+
+    /**
+     * Internal buffer used during read operations.
+     */
+    boost::scoped_array<char> read_buf_;
+
+    /**
+     * Internal buffer used during write operations.
+     */
+    boost::scoped_array<char> write_buf_;
+};
+
+}
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/detail/windows_helpers.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,138 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/detail/windows_helpers.hpp
+ *
+ * Includes the declaration of helper functions for Windows systems.
+ */
+
+#ifndef BOOST_PROCESS_WINDOWS_HELPERS_HPP
+#define BOOST_PROCESS_WINDOWS_HELPERS_HPP
+
+#include <boost/process/config.hpp>
+#include <boost/process/environment.hpp>
+#include <boost/shared_array.hpp>
+#include <string>
+#include <vector>
+#include <cstddef>
+#include <string.h>
+#include <windows.h>
+
+namespace boost {
+namespace process {
+namespace detail {
+
+/**
+ * Converts an environment to a string used by CreateProcess().
+ *
+ * Converts the environment's contents to the format used by the
+ * CreateProcess() system call. The returned char* string is
+ * allocated in dynamic memory; the caller must free it when not
+ * used any more. This is enforced by the use of a shared pointer.
+ *
+ * This operation is only available on Windows systems.
+ *
+ * \return A dynamically allocated char* string that represents
+ *         the environment's content. This string is of the form
+ *         var1=value1\\0var2=value2\\0\\0.
+ */
+inline boost::shared_array<char> environment_to_windows_strings(environment
+    &env)
+{
+    boost::shared_array<char> envp;
+
+    if (env.empty())
+    {
+        envp.reset(new char[2]);
+        ZeroMemory(envp.get(), 2);
+    }
+    else
+    {
+        std::string s;
+        for (environment::const_iterator it = env.begin(); it != env.end();
+            ++it)
+        {
+            s += it->first + "=" + it->second;
+            s.push_back(0);
+        }
+        envp.reset(new char[s.size() + 1]);
+#if (BOOST_MSVC >= 1400)
+        memcpy_s(envp.get(), s.size() + 1, s.c_str(), s.size() + 1);
+#else
+        memcpy(envp.get(), s.c_str(), s.size() + 1);
+#endif
+    }
+
+    return envp;
+}
+
+/**
+ * Converts the command line to a plain string.
+ *
+ * Converts the command line's list of arguments to the format expected by the
+ * \a lpCommandLine parameter in the CreateProcess() system call.
+ *
+ * This operation is only available on Windows systems.
+ *
+ * \return A dynamically allocated string holding the command line
+ *         to be passed to the executable. It is returned in a
+ *         shared_array object to ensure its release at some point.
+ */
+template <class Arguments>
+inline boost::shared_array<char> collection_to_windows_cmdline(const Arguments
+    &args)
+{
+    typedef std::vector<std::string> arguments_t;
+    arguments_t args2;
+    typename Arguments::size_type i = 0;
+    std::size_t size = 0;
+    for (typename Arguments::const_iterator it = args.begin(); it != args.end();
+        ++it)
+    {
+        std::string arg = *it;
+
+        std::string::size_type pos = 0;
+        while ( (pos = arg.find('"', pos)) != std::string::npos)
+        {
+            arg.replace(pos, 1, "\\\"");
+            pos += 2;
+        }
+
+        if (arg.find(' ') != std::string::npos)
+            arg = '\"' + arg + '\"';
+
+        if (i++ != args.size() - 1)
+            arg += ' ';
+
+        args2.push_back(arg);
+        size += arg.size() + 1;
+    }
+
+    boost::shared_array<char> cmdline(new char[size]);
+    cmdline.get()[0] = '\0';
+    for (arguments_t::size_type i = 0; i < args.size(); ++i)
+#if (BOOST_MSVC >= 1400)
+        strcat_s(cmdline.get(), size, args2[i].c_str());
+#else
+        strncat(cmdline.get(), args2[i].c_str(), args2[i].size());
+#endif
+
+    return cmdline;
+}
+
+}
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/environment.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,52 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/environment.hpp
+ *
+ * Includes the declaration of the environment class.
+ */
+
+#ifndef BOOST_PROCESS_ENVIRONMENT_HPP
+#define BOOST_PROCESS_ENVIRONMENT_HPP
+
+#include <map>
+#include <string>
+
+namespace boost {
+namespace process {
+
+/**
+ * Representation of a process' environment variables.
+ *
+ * The environment is a map that establishes an unidirectional
+ * association between variable names and their values and is
+ * represented by a string to string map.
+ *
+ * Variables may be defined to the empty string. Be aware that doing so
+ * is not portable: POSIX systems will treat such variables as being
+ * defined to the empty value, but Windows systems are not able to
+ * distinguish them from undefined variables.
+ *
+ * Neither POSIX nor Windows systems support a variable with no name.
+ *
+ * It is worthy to note that the environment is sorted alphabetically.
+ * This is provided for-free by the map container used to implement this
+ * type, and this behavior is required by Windows systems.
+ */
+typedef std::map<std::string, std::string> environment;
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/handle.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,231 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/handle.hpp
+ *
+ * Includes the declaration of the handle class.
+ */
+
+#ifndef BOOST_PROCESS_HANDLE_HPP
+#define BOOST_PROCESS_HANDLE_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+#   include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+#   include <windows.h>
+#else
+#   error "Unsupported platform."
+#endif
+
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+
+namespace boost {
+namespace process {
+
+/**
+ * RAII model for handles.
+ *
+ * The \a handle class is a RAII model for native handles. This class wraps
+ * one of such handles grabbing its ownership, and automaticaly closes it
+ * upon destruction. It is used to avoid leaking open handles, shall an
+ * unexpected execution trace occur.
+ */
+class handle
+{
+public:
+#if defined(BOOST_PROCESS_DOXYGEN)
+    /**
+     * Opaque name for the native handle type.
+     *
+     * On POSIX systems \a NativeSystemHandle is an integer type while it is
+     * a \a HANDLE on Windows systems.
+     */
+    typedef NativeSystemHandle native_type;
+#elif defined(BOOST_POSIX_API)
+    typedef int native_type;
+#elif defined(BOOST_WINDOWS_API)
+    typedef HANDLE native_type;
+#endif
+
+    /**
+     * Constructs an invalid handle.
+     *
+     * \see valid()
+     */
+    handle()
+    {
+    }
+
+    /**
+     * RAII settings to specify if handle should be automatically closed.
+     */
+    enum close_type { do_close, dont_close };
+
+    /**
+     * Constructs a handle from a native handle.
+     *
+     * This constructor creates a new \a handle object that takes
+     * ownership of the given \a native handle. If \a close is set to
+     * handle::dont_close the \a native handle is not closed upon destruction.
+     * The user must not close \a native if it is owned by a \a handle object.
+     * Ownership can be reclaimed using release().
+     *
+     * \see release()
+     */
+    handle(native_type native, close_type close = handle::do_close)
+    : impl_(boost::make_shared<impl>(native, close))
+    {
+    }
+
+    /**
+     * Checks whether the handle is valid or not.
+     *
+     * \return true if the handle is valid; false otherwise.
+     */
+    bool valid() const
+    {
+        return impl_ && impl_->valid();
+    }
+
+    /**
+     * Closes the handle.
+     *
+     * \post The handle is invalid.
+     * \post The native handle is closed.
+     */
+    void close()
+    {
+        if (impl_)
+            impl_->close();
+    }
+
+    /**
+     * Gets the native handle.
+     *
+     * The caller can issue any operation on it except closing it.
+     * If closing is required, release() shall be used.
+     *
+     * \return The native handle.
+     */
+    native_type native() const
+    {
+        return impl_ ? impl_->native() : invalid_handle();
+    }
+
+    /**
+     * Reclaims ownership of the native handle.
+     *
+     * The caller is responsible of closing the native handle.
+     *
+     * \post The handle is invalid.
+     * \return The native handle.
+     */
+    native_type release()
+    {
+        return impl_ ? impl_->release() : invalid_handle();
+    }
+
+private:
+    class impl
+    {
+    public:
+        typedef handle::native_type native_type;
+
+        impl(native_type native, close_type close)
+        : native_(native),
+        close_(close)
+        {
+        }
+
+        ~impl()
+        {
+            if (valid() && close_ == handle::do_close)
+            {
+#if defined(BOOST_POSIX_API)
+                ::close(native_);
+#elif defined(BOOST_WINDOWS_API)
+                CloseHandle(native_);
+#endif
+            }
+        }
+
+        bool valid() const
+        {
+            return native_ != handle::invalid_handle();
+        }
+
+        void close()
+        {
+            if (valid())
+            {
+#if defined(BOOST_POSIX_API)
+                ::close(native_);
+#elif defined(BOOST_WINDOWS_API)
+                CloseHandle(native_);
+#endif
+                native_ = handle::invalid_handle();
+            }
+        }
+
+        native_type native() const
+        {
+            return native_;
+        }
+
+        native_type release()
+        {
+            native_type native = native_;
+            native_ = handle::invalid_handle();
+            return native;
+        }
+
+    private:
+        native_type native_;
+        close_type close_;
+    };
+
+    /**
+     * Implementation of handle to store native handle value.
+     *
+     * A shared pointer is used as handles represent system resources. If a
+     * handle is closed and becomes invalid the state of copies of the handle
+     * object will be updated as they all share the handle implementation.
+     */
+    boost::shared_ptr<impl> impl_;
+
+    /**
+     * Constant function representing an invalid handle value.
+     *
+     * Returns the platform-specific handle value that represents an
+     * invalid handle. This is a constant function rather than a regular
+     * constant because, in the latter case, we cannot define it under
+     * Windows due to the value being of a complex type.
+     */
+    static const native_type invalid_handle()
+    {
+#if defined(BOOST_POSIX_API)
+        return -1;
+#elif defined(BOOST_WINDOWS_API)
+        return INVALID_HANDLE_VALUE;
+#endif
+    }
+};
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/operations.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,432 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/operations.hpp
+ *
+ * Provides miscellaneous free functions.
+ */
+
+#ifndef BOOST_PROCESS_OPERATIONS_HPP
+#define BOOST_PROCESS_OPERATIONS_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+#   include <boost/process/detail/posix_helpers.hpp>
+#   include <utility>
+#   include <cstddef>
+#   include <stdlib.h>
+#   include <unistd.h>
+#   include <fcntl.h>
+#   if defined(__CYGWIN__)
+#       include <boost/scoped_array.hpp>
+#       include <sys/cygwin.h>
+#   endif
+#elif defined(BOOST_WINDOWS_API)
+#   include <boost/process/detail/windows_helpers.hpp>
+#   include <boost/scoped_array.hpp>
+#   include <boost/shared_array.hpp>
+#   include <windows.h>
+#else
+#   error "Unsupported platform."
+#endif
+
+#include <boost/process/child.hpp>
+#include <boost/process/context.hpp>
+#include <boost/process/stream_id.hpp>
+#include <boost/process/stream_ends.hpp>
+#include <boost/process/handle.hpp>
+#include <boost/filesystem/path.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/system/system_error.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/assert.hpp>
+#include <string>
+#include <vector>
+#include <map>
+#include <utility>
+
+namespace boost {
+namespace process {
+
+/**
+ * Locates the executable program \a file in all the directory components
+ * specified in \a path. If \a path is empty, the value of the PATH
+ * environment variable is used.
+ *
+ * The path variable is interpreted following the same conventions used
+ * to parse the PATH environment variable in the underlying platform.
+ *
+ * \throw boost::filesystem::filesystem_error If the file cannot be found
+ *        in the path.
+ */
+inline std::string find_executable_in_path(const std::string &file,
+    std::string path = "")
+{
+#if defined(BOOST_POSIX_API)
+    BOOST_ASSERT(file.find('/') == std::string::npos);
+#elif defined(BOOST_WINDOWS_API)
+    BOOST_ASSERT(file.find_first_of("\\/") == std::string::npos);
+#endif
+
+    std::string result;
+
+#if defined(BOOST_POSIX_API)
+    if (path.empty())
+    {
+        const char *envpath = getenv("PATH");
+        if (!envpath)
+            boost::throw_exception(boost::filesystem::filesystem_error(
+                BOOST_PROCESS_SOURCE_LOCATION "file not found", file,
+                boost::system::errc::make_error_code(
+                boost::system::errc::no_such_file_or_directory)));
+        path = envpath;
+    }
+    BOOST_ASSERT(!path.empty());
+
+#if defined(__CYGWIN__)
+    if (!cygwin_posix_path_list_p(path.c_str()))
+    {
+        int size = cygwin_win32_to_posix_path_list_buf_size(path.c_str());
+        boost::scoped_array<char> cygpath(new char[size]);
+        cygwin_win32_to_posix_path_list(path.c_str(), cygpath.get());
+        path = cygpath.get();
+    }
+#endif
+
+    std::string::size_type pos1 = 0, pos2;
+    do
+    {
+        pos2 = path.find(':', pos1);
+        std::string dir = (pos2 != std::string::npos) ?
+            path.substr(pos1, pos2 - pos1) : path.substr(pos1);
+        std::string f = dir +
+            (boost::algorithm::ends_with(dir, "/") ? "" : "/") + file;
+        if (!access(f.c_str(), X_OK))
+            result = f;
+        pos1 = pos2 + 1;
+    } while (pos2 != std::string::npos && result.empty());
+#elif defined(BOOST_WINDOWS_API)
+    const char *exts[] = { "", ".exe", ".com", ".bat", NULL };
+    const char **ext = exts;
+    while (*ext)
+    {
+        char buf[MAX_PATH];
+        char *dummy;
+        DWORD size = SearchPathA(path.empty() ? NULL : path.c_str(),
+            file.c_str(), *ext, MAX_PATH, buf, &dummy);
+        BOOST_ASSERT(size < MAX_PATH);
+        if (size > 0)
+        {
+            result = buf;
+            break;
+        }
+        ++ext;
+    }
+#endif
+
+    if (result.empty())
+        boost::throw_exception(boost::filesystem::filesystem_error(
+            BOOST_PROCESS_SOURCE_LOCATION "file not found", file,
+            boost::system::errc::make_error_code(
+            boost::system::errc::no_such_file_or_directory)));
+
+    return result;
+}
+
+/**
+ * Extracts the program name from a given executable.
+ *
+ * \return The program name. On Windows the program name
+ *         is returned without a file extension.
+ */
+inline std::string executable_to_progname(const std::string &exe)
+{
+    std::string::size_type begin = 0;
+    std::string::size_type end = std::string::npos;
+
+#if defined(BOOST_POSIX_API)
+    std::string::size_type slash = exe.rfind('/');
+#elif defined(BOOST_WINDOWS_API)
+    std::string::size_type slash = exe.find_last_of("/\\");
+#endif
+    if (slash != std::string::npos)
+        begin = slash + 1;
+
+#if defined(BOOST_WINDOWS_API)
+    if (exe.size() > 4 && (boost::algorithm::iends_with(exe, ".exe") ||
+        boost::algorithm::iends_with(exe, ".com") ||
+        boost::algorithm::iends_with(exe, ".bat")))
+        end = exe.size() - 4;
+#endif
+
+    return exe.substr(begin, end - begin);
+}
+
+/**
+ * Starts a new child process.
+ *
+ * Launches a new process based on the binary image specified by the
+ * executable, the set of arguments passed to it and the execution context.
+ *
+ * \remark Blocking remarks: This function may block if the device holding the
+ *         executable blocks when loading the image. This might happen if, e.g.,
+ *         the binary is being loaded from a network share.
+ *
+ * \return A handle to the new child process.
+ */
+template <typename Arguments, typename Context>
+inline child create_child(const std::string &executable, Arguments args,
+    Context ctx)
+{
+    typedef std::map<stream_id, stream_ends> handles_t;
+    handles_t handles;
+    typename Context::streams_t::iterator it = ctx.streams.begin();
+    for (; it != ctx.streams.end(); ++it)
+    {
+        if (it->first == stdin_id)
+            handles[it->first] = it->second(input_stream);
+        else if (it->first == stdout_id)
+            handles[it->first] = it->second(output_stream);
+        else if (it->first == stderr_id)
+            handles[it->first] = it->second(output_stream);
+#if defined(BOOST_POSIX_API)
+        else
+            handles[it->first] = it->second(unknown_stream);
+#endif
+    }
+
+    std::string p_name = ctx.process_name.empty() ?
+        executable_to_progname(executable) : ctx.process_name;
+    args.insert(args.begin(), p_name);
+
+#if defined(BOOST_POSIX_API)
+    // Between fork() and execve() only async-signal-safe functions
+    // must be called if multithreaded applications should be supported.
+    // That's why the following code is executed before fork() is called.
+#if defined(F_MAXFD)
+    int maxdescs = fcntl(-1, F_MAXFD, 0);
+    if (maxdescs == -1)
+        maxdescs = sysconf(_SC_OPEN_MAX);
+#else
+    int maxdescs = static_cast<int>(sysconf(_SC_OPEN_MAX));
+#endif
+    if (maxdescs == -1)
+        maxdescs = 1024;
+    std::vector<bool> closeflags(maxdescs, true);
+    std::pair<std::size_t, char**> argv = detail::collection_to_argv(args);
+    std::pair<std::size_t, char**> envp =
+        detail::environment_to_envp(ctx.env);
+
+    const char *work_dir = ctx.work_dir.c_str();
+
+    pid_t pid = fork();
+    if (pid == -1)
+        BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("fork(2) failed");
+    else if (pid == 0)
+    {
+        if (chdir(work_dir) == -1)
+        {
+            write(STDERR_FILENO, "chdir() failed\n", 15);
+            _exit(127);
+        }
+
+        for (handles_t::iterator it = handles.begin(); it != handles.end();
+            ++it)
+        {
+            if (it->second.child.valid())
+            {
+                handles_t::iterator it2 = it;
+                ++it2;
+                for (; it2 != handles.end(); ++it2)
+                {
+                    if (it2->second.child.native() == it->first)
+                    {
+                        int fd = fcntl(it2->second.child.native(), F_DUPFD,
+                            it->first + 1);
+                        if (fd == -1)
+                        {
+                            write(STDERR_FILENO, "fcntl() failed\n", 15);
+                            _exit(127);
+                        }
+                        it2->second.child = fd;
+                    }
+                }
+
+                if (dup2(it->second.child.native(), it->first) == -1)
+                {
+                    write(STDERR_FILENO, "dup2() failed\n", 14);
+                    _exit(127);
+                }
+                closeflags[it->first] = false;
+            }
+        }
+
+        if (ctx.setup)
+            ctx.setup();
+
+        for (std::size_t i = 0; i < closeflags.size(); ++i)
+        {
+            if (closeflags[i])
+                close(static_cast<int>(i));
+        }
+
+        execve(executable.c_str(), argv.second, envp.second);
+
+        // Actually we should delete argv and envp data. As we must not
+        // call any non-async-signal-safe functions though we simply exit.
+        write(STDERR_FILENO, "execve() failed\n", 16);
+        _exit(127);
+    }
+    else
+    {
+        BOOST_ASSERT(pid > 0);
+
+        for (std::size_t i = 0; i < argv.first; ++i)
+            delete[] argv.second[i];
+        delete[] argv.second;
+
+        for (std::size_t i = 0; i < envp.first; ++i)
+            delete[] envp.second[i];
+        delete[] envp.second;
+
+        std::map<stream_id, handle> parent_ends;
+        for (handles_t::iterator it = handles.begin(); it != handles.end();
+            ++it)
+            parent_ends[it->first] = it->second.parent;
+
+        return child(pid, parent_ends);
+    }
+#elif defined(BOOST_WINDOWS_API)
+    STARTUPINFOA startup_info;
+    ZeroMemory(&startup_info, sizeof(startup_info));
+    startup_info.cb = sizeof(startup_info);
+    startup_info.dwFlags |= STARTF_USESTDHANDLES;
+    startup_info.hStdInput = handles[stdin_id].child.native();
+    startup_info.hStdOutput = handles[stdout_id].child.native();
+    startup_info.hStdError = handles[stderr_id].child.native();
+
+    if (ctx.setup)
+        ctx.setup(startup_info);
+
+    PROCESS_INFORMATION pi;
+    ZeroMemory(&pi, sizeof(pi));
+
+    boost::shared_array<char> cmdline =
+        detail::collection_to_windows_cmdline(args);
+
+    boost::scoped_array<char> exe(new char[executable.size() + 1]);
+#if (BOOST_MSVC >= 1400)
+    strcpy_s(exe.get(), executable.size() + 1, executable.c_str());
+#else
+    strcpy(exe.get(), executable.c_str());
+#endif
+
+    boost::scoped_array<char> workdir(new char[ctx.work_dir.size() + 1]);
+#if (BOOST_MSVC >= 1400)
+    strcpy_s(workdir.get(), ctx.work_dir.size() + 1, ctx.work_dir.c_str());
+#else
+    strcpy(workdir.get(), ctx.work_dir.c_str());
+#endif
+
+    boost::shared_array<char> envstrs =
+        detail::environment_to_windows_strings(ctx.env);
+
+    if (CreateProcessA(exe.get(), cmdline.get(), NULL, NULL, TRUE, 0,
+        envstrs.get(), workdir.get(), &startup_info, &pi) == 0)
+        BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateProcess() failed");
+
+    handle hprocess(pi.hProcess);
+
+    if (!CloseHandle(pi.hThread))
+        BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed");
+
+    std::map<stream_id, handle> parent_ends;
+    parent_ends[stdin_id] = handles[stdin_id].parent;
+    parent_ends[stdout_id] = handles[stdout_id].parent;
+    parent_ends[stderr_id] = handles[stderr_id].parent;
+
+    return child(hprocess, parent_ends);
+#endif
+}
+
+/**
+ * \overload
+ */
+inline child create_child(const std::string &executable)
+{
+    return create_child(executable, std::vector<std::string>(), context());
+}
+
+/**
+ * \overload
+ */
+template <typename Arguments>
+inline child create_child(const std::string &executable, Arguments args)
+{
+    return create_child(executable, args, context());
+}
+
+/**
+ * Starts a shell-based command.
+ *
+ * Executes the given command through the default system shell. The
+ * command is subject to pattern expansion, redirection and pipelining.
+ * The shell is launched as described by the parameters in the context.
+ *
+ * This function behaves similarly to the system(3) system call. In a
+ * POSIX system, the command is fed to /bin/sh whereas under a Windows
+ * system, it is fed to cmd.exe. It is difficult to write portable
+ * commands, but this function comes in handy in multiple situations.
+ *
+ * \remark Blocking remarks: This function may block if the device holding the
+ *         executable blocks when loading the image. This might happen if, e.g.,
+ *         the binary is being loaded from a network share.
+ *
+ * \return A handle to the new child process.
+ */
+template <typename Context>
+inline child shell(const std::string &command, Context ctx)
+{
+#if defined(BOOST_POSIX_API)
+    std::string executable = "/bin/sh";
+    std::vector<std::string> args;
+    args.push_back("-c");
+    args.push_back(command);
+#elif defined(BOOST_WINDOWS_API)
+    char sysdir[MAX_PATH];
+    UINT size = GetSystemDirectoryA(sysdir, sizeof(sysdir));
+    if (!size)
+        BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("GetSystemDirectory() failed");
+    std::string executable = std::string(sysdir) +
+        (sysdir[size - 1] != '\\' ? "\\cmd.exe" : "cmd.exe");
+    std::vector<std::string> args;
+    args.push_back("/c");
+    args.push_back(command);
+#endif
+    return create_child(executable, args, ctx);
+}
+
+/**
+ * \overload
+ */
+inline child shell(const std::string &command)
+{
+    return shell(command, context());
+}
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/pid_type.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,56 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/pid_type.hpp
+ *
+ * Includes the declaration of the pid type.
+ */
+
+#ifndef BOOST_PROCESS_PID_TYPE_HPP
+#define BOOST_PROCESS_PID_TYPE_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+#   include <sys/types.h>
+#elif defined(BOOST_WINDOWS_API)
+#   include <windows.h>
+#endif
+
+namespace boost {
+namespace process {
+
+#if defined(BOOST_PROCESS_DOXYGEN)
+/**
+ * Opaque name for the process identifier type.
+ *
+ * Each operating system identifies processes using a specific type.
+ * The \a pid_type type is used to transparently refer to a process
+ * regardless of the operating system.
+ *
+ * This type is guaranteed to be an integral type on all supported
+ * platforms. On POSIX systems it is defined as pid_t, on Windows systems as
+ * DWORD.
+ */
+typedef NativeProcessId pid_type;
+#elif defined(BOOST_POSIX_API)
+typedef pid_t pid_type;
+#elif defined(BOOST_WINDOWS_API)
+typedef DWORD pid_type;
+#endif
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/pipe.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,49 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/pipe.hpp
+ *
+ * Includes the declaration of the pipe class.
+ */
+
+#ifndef BOOST_PROCESS_PIPE_HPP
+#define BOOST_PROCESS_PIPE_HPP
+
+#include <boost/process/config.hpp>
+#include <boost/asio.hpp>
+
+namespace boost {
+namespace process {
+
+#if defined(BOOST_PROCESS_DOXYGEN)
+/**
+ * The pipe class is a type definition for stream-based classes defined by
+ * Boost.Asio.
+ *
+ * The type definition is provided for convenience. You can also use Boost.Asio
+ * classes directly for asynchronous I/O operations.
+ */
+typedef BoostAsioPipe pipe;
+#elif defined(BOOST_POSIX_API)
+typedef boost::asio::posix::stream_descriptor pipe;
+#elif defined(BOOST_WINDOWS_API)
+typedef boost::asio::windows::stream_handle pipe;
+#else
+#   error "Unsupported platform."
+#endif
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/pistream.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,114 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/pistream.hpp
+ *
+ * Includes the declaration of the pistream class.
+ */
+
+#ifndef BOOST_PROCESS_PISTREAM_HPP
+#define BOOST_PROCESS_PISTREAM_HPP
+
+#include <boost/process/handle.hpp>
+#include <boost/process/detail/systembuf.hpp>
+#include <boost/noncopyable.hpp>
+#include <istream>
+
+namespace boost {
+namespace process {
+
+/**
+ * Child process' output stream.
+ *
+ * The pistream class represents an output communication channel with the
+ * child process. The child process writes data to this stream and the
+ * parent process can read it through the pistream object. In other
+ * words, from the child's point of view, the communication channel is an
+ * output one, but from the parent's point of view it is an input one;
+ * hence the confusing pistream name.
+ *
+ * pistream objects cannot be copied because they buffer data
+ * that flows through the communication channel.
+ *
+ * A pistream object behaves as a std::istream stream in all senses.
+ * The class is only provided because it must provide a method to let
+ * the caller explicitly close the communication channel.
+ *
+ * \remark Blocking remarks: Functions that read data from this
+ *         stream can block if the associated handle blocks during
+ *         the read. As this class is used to communicate with child
+ *         processes through anonymous pipes, the most typical blocking
+ *         condition happens when the child has no more data to send to
+ *         the pipe's system buffer. When this happens, the buffer
+ *         eventually empties and the system blocks until the writer
+ *         generates some data.
+ */
+class pistream : public std::istream, public boost::noncopyable
+{
+public:
+    /**
+     * Creates a new process' output stream.
+     */
+    explicit pistream(boost::process::handle h)
+        : std::istream(0),
+          handle_(h),
+          systembuf_(handle_.native())
+    {
+        rdbuf(&systembuf_);
+    }
+
+    /**
+     * Returns the handle managed by this stream.
+     */
+    const boost::process::handle &handle() const
+    {
+        return handle_;
+    }
+
+    /**
+     * Returns the handle managed by this stream.
+     */
+    boost::process::handle &handle()
+    {
+        return handle_;
+    }
+
+    /**
+     * Closes the handle managed by this stream.
+     *
+     * Explicitly closes the handle managed by this stream. This
+     * function can be used by the user to tell the child process it's
+     * not willing to receive more data.
+     */
+    void close()
+    {
+        handle_.close();
+    }
+
+private:
+    /**
+     * The handle managed by this stream.
+     */
+    boost::process::handle handle_;
+
+    /**
+     * The systembuf object used to manage this stream's data.
+     */
+    detail::systembuf systembuf_;
+};
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/postream.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,115 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/postream.hpp
+ *
+ * Includes the declaration of the postream class.
+ */
+
+#ifndef BOOST_PROCESS_POSTREAM_HPP
+#define BOOST_PROCESS_POSTREAM_HPP
+
+#include <boost/process/handle.hpp>
+#include <boost/process/detail/systembuf.hpp>
+#include <boost/noncopyable.hpp>
+#include <ostream>
+
+namespace boost {
+namespace process {
+
+/**
+ * Child process' input stream.
+ *
+ * The postream class represents an input communication channel with the
+ * child process. The child process reads data from this stream and the
+ * parent process can write to it through the postream object. In other
+ * words, from the child's point of view, the communication channel is an
+ * input one, but from the parent's point of view it is an output one;
+ * hence the confusing postream name.
+ *
+ * postream objects cannot be copied because they buffer data that flows
+ * through the communication channel.
+ *
+ * A postream object behaves as a std::ostream stream in all senses.
+ * The class is only provided because it must provide a method to let
+ * the caller explicitly close the communication channel.
+ *
+ * \remark Blocking remarks: Functions that write data to this
+ *         stream can block if the associated handle blocks during
+ *         the write. As this class is used to communicate with child
+ *         processes through anonymous pipes, the most typical blocking
+ *         condition happens when the child is not processing the data
+ *         in the pipe's system buffer. When this happens, the buffer
+ *         eventually fills up and the system blocks until the reader
+ *         consumes some data, leaving some new room.
+ */
+class postream : public std::ostream, public boost::noncopyable
+{
+public:
+    /**
+     * Creates a new process' input stream.
+     */
+    explicit postream(boost::process::handle h)
+        : std::ostream(0),
+          handle_(h),
+          systembuf_(handle_.native())
+    {
+        rdbuf(&systembuf_);
+    }
+
+    /**
+     * Returns the handle managed by this stream.
+     */
+    const boost::process::handle &handle() const
+    {
+        return handle_;
+    }
+
+    /**
+     * Returns the handle managed by this stream.
+     */
+    boost::process::handle &handle()
+    {
+        return handle_;
+    }
+
+    /**
+     * Closes the handle managed by this stream.
+     *
+     * Explicitly closes the handle managed by this stream. This
+     * function can be used by the user to tell the child process there
+     * is no more data to send.
+     */
+    void close()
+    {
+        systembuf_.sync();
+        handle_.close();
+    }
+
+private:
+    /**
+     * The handle managed by this stream.
+     */
+    boost::process::handle handle_;
+
+    /**
+     * The systembuf object used to manage this stream's data.
+     */
+    detail::systembuf systembuf_;
+};
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/process.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,212 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/process.hpp
+ *
+ * Includes the declaration of the process class.
+ */
+
+#ifndef BOOST_PROCESS_PROCESS_HPP
+#define BOOST_PROCESS_PROCESS_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+#   include <unistd.h>
+#   include <sys/types.h>
+#   include <signal.h>
+#   include <sys/wait.h>
+#   include <errno.h>
+#elif defined(BOOST_WINDOWS_API)
+#   include <boost/process/handle.hpp>
+#   include <cstdlib>
+#   include <windows.h>
+#else
+#   error "Unsupported platform."
+#endif
+
+#include <boost/process/pid_type.hpp>
+
+namespace boost {
+namespace process {
+
+/**
+ * Process class to represent any running process.
+ */
+class process
+{
+public:
+    /**
+     * Constructs a new process object.
+     *
+     * Creates a new process object that represents a running process
+     * within the system.
+     *
+     * On Windows the process is opened and a handle saved. This is required
+     * to avoid the operating system removing process resources when the
+     * process exits. The handle is closed when the process instance (and all
+     * of its copies) is destroyed.
+     */
+    process(pid_type id)
+        : id_(id)
+#if defined(BOOST_WINDOWS_API)
+        , handle_(open_process(id))
+#endif
+    {
+    }
+
+#if defined(BOOST_WINDOWS_API) || defined(BOOST_PROCESS_DOXYGEN)
+    /**
+     * Constructs a new process object.
+     *
+     * Creates a new process object that represents a running process
+     * within the system.
+     *
+     * This operation is only available on Windows systems. The handle is
+     * closed when the process instance (and all of its copies) is destroyed.
+     */
+    process(handle h)
+        : id_(GetProcessId(h.native())),
+        handle_(h)
+    {
+    }
+#endif
+
+    /**
+     * Returns the process identifier.
+     */
+    pid_type get_id() const
+    {
+        return id_;
+    }
+
+    /**
+     * Terminates the process execution.
+     *
+     * Forces the termination of the process execution. Some platforms
+     * allow processes to ignore some external termination notifications
+     * or to capture them for a proper exit cleanup. You can set the
+     * \a force flag to true to force their termination regardless
+     * of any exit handler.
+     *
+     * After this call, accessing this object can be dangerous because the
+     * process identifier may have been reused by a different process. It
+     * might still be valid, though, if the process has refused to die.
+     *
+     * \throw boost::system::system_error If system calls used to terminate the
+     *        process fail.
+     */
+    void terminate(bool force = false) const
+    {
+#if defined(BOOST_POSIX_API)
+        if (kill(id_, force ? SIGKILL : SIGTERM) == -1)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("kill(2) failed");
+#elif defined(BOOST_WINDOWS_API)
+#if defined(BOOST_MSVC)
+        force;
+#endif
+        HANDLE h = OpenProcess(PROCESS_TERMINATE, FALSE, id_);
+        if (h == NULL)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed");
+        if (!TerminateProcess(h, EXIT_FAILURE))
+        {
+            CloseHandle(h);
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("TerminateProcess() failed");
+        }
+        if (!CloseHandle(h))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed");
+#endif
+    }
+
+    /**
+     * Blocks and waits for the process to terminate.
+     *
+     * Returns an exit code. The process object ceases to be valid after this
+     * call.
+     *
+     * \remark Blocking remarks: This call blocks if the process has not
+     *         finalized execution and waits until it terminates.
+     *
+     * \throw boost::system::system_error If system calls used to wait for the
+     *        process fail.
+     */
+    int wait() const
+    {
+#if defined(BOOST_POSIX_API)
+        pid_t p;
+        int status;
+        do
+        {
+            p = waitpid(id_, &status, 0);
+        } while (p == -1 && errno == EINTR);
+        if (p == -1)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("waitpid(2) failed");
+        return status;
+#elif defined(BOOST_WINDOWS_API)
+        HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE,
+            id_);
+        if (h == NULL) 
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed");
+        if (WaitForSingleObject(h, INFINITE) == WAIT_FAILED)
+        {
+            CloseHandle(h);
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                "WaitForSingleObject() failed");
+        }
+        DWORD exit_code;
+        if (!GetExitCodeProcess(h, &exit_code))
+        {
+            CloseHandle(h);
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                "GetExitCodeProcess() failed");
+        }
+        if (!CloseHandle(h))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CloseHandle() failed");
+        return exit_code;
+#endif
+    }
+
+private:
+    /**
+     * The process identifier.
+     */
+    pid_type id_;
+
+#if defined(BOOST_WINDOWS_API)
+    /**
+     * Opens a process and returns a handle.
+     *
+     * OpenProcess() returns NULL and not INVALID_HANDLE_VALUE on failure.
+     * That's why the return value is manually checked in this helper function
+     * instead of simply passing it to the constructor of the handle class.
+     */
+    HANDLE open_process(pid_type id)
+    {
+        HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, id);
+        if (h == NULL)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("OpenProcess() failed");
+        return h;
+    }
+
+    /**
+     * The process handle.
+     */
+    handle handle_;
+#endif
+};
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/self.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,188 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/self.hpp
+ *
+ * Includes the declaration of the self class.
+ */
+
+#ifndef BOOST_PROCESS_SELF_HPP
+#define BOOST_PROCESS_SELF_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+#   include <boost/scoped_array.hpp>
+#   include <errno.h>
+#   include <unistd.h>
+#   include <limits.h>
+#   if defined(__APPLE__)
+#       include <crt_externs.h>
+#   endif
+#elif defined(BOOST_WINDOWS_API)
+#   include <windows.h>
+#else
+#   error "Unsupported platform." 
+#endif
+
+#include <boost/process/process.hpp>
+#include <boost/process/environment.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/assert.hpp>
+#include <string>
+
+#if defined(BOOST_POSIX_API)
+extern "C"
+{
+    extern char **environ;
+}
+#endif
+
+namespace boost {
+namespace process {
+
+/**
+ * The self class provides access to the process itself.
+ */
+class self : public process, public boost::noncopyable
+{
+public:
+    /**
+     * Returns the self instance representing the caller's process.
+     */
+    static self &get_instance()
+    {
+        static self *instance = 0;
+        if (!instance)
+            instance = new self;
+        return *instance;
+    }
+
+    /**
+     * Returns the current environment.
+     *
+     * Returns the current process environment variables. Modifying the
+     * returned object has no effect on the current environment.
+     */
+    static environment get_environment()
+    {
+        environment e;
+
+#if defined(BOOST_POSIX_API)
+#   if defined(__APPLE__)
+        char **env = *_NSGetEnviron();
+#   else
+        char **env = environ;
+#   endif
+
+        while (*env)
+        {
+            std::string s = *env;
+            std::string::size_type pos = s.find('=');
+            e.insert(environment::value_type(s.substr(0, pos),
+                s.substr(pos + 1)));
+            ++env;
+        }
+#elif defined(BOOST_WINDOWS_API)
+#   ifdef GetEnvironmentStrings
+#   undef GetEnvironmentStrings
+#   endif
+
+        char *ms_environ = GetEnvironmentStrings();
+        if (!ms_environ)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                "GetEnvironmentStrings() failed");
+        try
+        {
+            char *env = ms_environ;
+            while (*env)
+            {
+                std::string s = env;
+                std::string::size_type pos = s.find('=');
+                e.insert(environment::value_type(s.substr(0, pos),
+                    s.substr(pos + 1)));
+                env += s.size() + 1;
+            }
+        }
+        catch (...)
+        {
+            FreeEnvironmentStringsA(ms_environ);
+            throw;
+        }
+        FreeEnvironmentStringsA(ms_environ);
+#endif
+
+        return e;
+    }
+
+    /**
+     * Returns the current work directory.
+     */
+    static std::string get_work_dir()
+    {
+#if defined(BOOST_POSIX_API)
+#if defined(PATH_MAX)
+        char buffer[PATH_MAX];
+        char *cwd = buffer;
+        long size = PATH_MAX;
+#elif defined(_PC_PATH_MAX)
+        errno = 0;
+        long size = pathconf("/", _PC_PATH_MAX);
+        if (size == -1 && errno)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("pathconf(2) failed");
+        else if (size == -1)
+            size = BOOST_PROCESS_POSIX_PATH_MAX;
+        BOOST_ASSERT(size > 0);
+        boost::scoped_array<char> buffer(new char[size]);
+        char *cwd = buffer.get();
+#else
+        char buffer[BOOST_PROCESS_POSIX_PATH_MAX];
+        char *cwd = buffer;
+        long size = BOOST_PROCESS_POSIX_PATH_MAX;
+#endif
+        if (!getcwd(cwd, size))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("getcwd(2) failed");
+        BOOST_ASSERT(cwd[0] != '\0');
+        return cwd;
+#elif defined(BOOST_WINDOWS_API)
+        BOOST_ASSERT(MAX_PATH > 0);
+        char cwd[MAX_PATH];
+        if (!GetCurrentDirectoryA(sizeof(cwd), cwd))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                "GetCurrentDirectory() failed");
+        BOOST_ASSERT(cwd[0] != '\0');
+        return cwd;
+#endif
+    }
+
+private:
+    /**
+     * Constructs a new self object.
+     *
+     * Creates a new self object that represents the current process.
+     */
+    self() :
+#if defined(BOOST_POSIX_API)
+        process(getpid())
+#elif defined(BOOST_WINDOWS_API)
+        process(GetCurrentProcessId())
+#endif
+    {
+    }
+};
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/status.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,41 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/status.hpp
+ *
+ * Includes the declaration of the status class.
+ */
+
+#ifndef BOOST_PROCESS_STATUS_HPP
+#define BOOST_PROCESS_STATUS_HPP
+
+#include <boost/process/config.hpp>
+#include <boost/process/detail/basic_status.hpp>
+#include <boost/process/detail/basic_status_service.hpp>
+
+namespace boost {
+namespace process {
+
+/**
+ * The status class to wait for processes to exit.
+ *
+ * The status class is a Boost.Asio I/O object and supports synchronous
+ * and asynchronous wait operations.
+ */
+typedef detail::basic_status<detail::basic_status_service<> > status;
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/stream_behavior.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,326 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/stream_behavior.hpp
+ *
+ * Includes the declaration of stream behavior classes.
+ */
+
+#ifndef BOOST_PROCESS_STREAM_BEHAVIOR_HPP
+#define BOOST_PROCESS_STREAM_BEHAVIOR_HPP
+
+#include <boost/process/config.hpp>
+
+#if defined(BOOST_POSIX_API)
+#   include <sys/stat.h>
+#   include <fcntl.h>
+#   include <unistd.h>
+#elif defined(BOOST_WINDOWS_API)
+#   include <windows.h>
+#   include <rpc.h>
+#endif
+
+#include <boost/process/stream_ends.hpp>
+#include <boost/process/stream_type.hpp>
+#include <boost/process/handle.hpp>
+#include <string>
+#include <algorithm>
+
+namespace boost {
+namespace process {
+namespace behavior {
+
+/**
+ * Stream behavior to close streams of a child process.
+ *
+ * A child process will not be able to use the stream.
+ */
+class close
+{
+public:
+    stream_ends operator()(stream_type) const
+    {
+        return stream_ends();
+    }
+};
+
+/**
+ * Stream behavior to make a child process inherit streams.
+ *
+ * A child process will use the very same stream of its parent process.
+ */
+class inherit
+{
+public:
+    inherit(handle::native_type h)
+    : h_(h, handle::dont_close)
+    {
+#if defined(BOOST_WINDOWS_API)
+        if (h != INVALID_HANDLE_VALUE)
+        {
+            if (!SetHandleInformation(h_.native(), HANDLE_FLAG_INHERIT,
+                HANDLE_FLAG_INHERIT))
+            {
+                HANDLE proc = GetCurrentProcess();
+                HANDLE dup;
+                if (!DuplicateHandle(proc, h_.native(), proc, &dup, 0,
+                    TRUE, DUPLICATE_SAME_ACCESS))
+                {
+                    BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                        "DuplicateHandle() failed");
+                }
+                h_ = dup;
+            }
+        }
+#endif
+    }
+
+    stream_ends operator()(stream_type) const
+    {
+        return stream_ends(h_, handle());
+    }
+
+private:
+    handle h_;
+};
+
+/**
+ * Stream behavior to redirect streams with a pipe.
+ *
+ * A child process will be able to communicate with its parent process.
+ */
+class pipe
+{
+public:
+#if defined(BOOST_POSIX_API)
+    pipe()
+    : stype_(unknown_stream)
+    {
+    }
+
+    pipe(stream_type stype)
+    : stype_(stype)
+    {
+    }
+#endif
+
+    stream_ends operator()(stream_type stype) const
+    {
+        handle::native_type ends[2];
+#if defined(BOOST_POSIX_API)
+        if (::pipe(ends) == -1)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("pipe(2) failed");
+        if (stype_ != unknown_stream)
+            stype = stype_;
+#elif defined(BOOST_WINDOWS_API)
+        SECURITY_ATTRIBUTES sa;
+        ZeroMemory(&sa, sizeof(sa));
+        sa.nLength = sizeof(sa);
+        sa.lpSecurityDescriptor = NULL;
+        sa.bInheritHandle = FALSE;
+        if (!CreatePipe(&ends[0], &ends[1], &sa, 0))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreatePipe() failed");
+#endif 
+        handle child_end = ends[stype == input_stream ? 0 : 1];
+        handle parent_end = ends[stype == input_stream ? 1 : 0];
+#if defined(BOOST_WINDOWS_API)
+        if (!SetHandleInformation(child_end.native(), HANDLE_FLAG_INHERIT,
+            HANDLE_FLAG_INHERIT))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                "SetHandleInformation() failed");
+#endif
+        return stream_ends(child_end, parent_end);
+    }
+
+#if defined(BOOST_POSIX_API)
+private:
+    stream_type stype_;
+#endif
+};
+
+/**
+ * Stream behavior to redirect streams with a named pipe.
+ *
+ * A child process will be able to communicate with its parent process.
+ */
+class named_pipe
+{
+public:
+    named_pipe(const std::string &name)
+    : name_(name)
+#if defined(BOOST_POSIX_API)
+    , stype_(unknown_stream)
+#endif
+    {
+    }
+
+#if defined(BOOST_POSIX_API)
+    named_pipe(const std::string &name, stream_type stype)
+    : name_(name),
+    stype_(stype)
+    {
+    }
+#endif
+
+    stream_ends operator()(stream_type stype) const
+    {
+#if defined(BOOST_POSIX_API)
+        if (mkfifo(name_.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) == -1)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("mkfifo(3) failed");
+        handle child_end = open(name_.c_str(), O_RDONLY | O_NONBLOCK);
+        if (!child_end.valid())
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("open(2) failed");
+        int opts = fcntl(child_end.native(), F_GETFL);
+        if (opts == -1)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("fcntl(2) failed");
+        opts ^= O_NONBLOCK;
+        if (fcntl(child_end.native(), F_SETFL, opts) == -1)
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("fcntl(2) failed");
+        handle parent_end = open(name_.c_str(), O_WRONLY);
+        if (!parent_end.valid())
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("open(2) failed");
+        if (stype_ != unknown_stream)
+            stype = stype_;
+#elif defined(BOOST_WINDOWS_API)
+        SECURITY_ATTRIBUTES sa;
+        ZeroMemory(&sa, sizeof(sa));
+        sa.nLength = sizeof(sa);
+        sa.lpSecurityDescriptor = NULL;
+        sa.bInheritHandle = TRUE;
+        handle child_end = CreateNamedPipeA(name_.c_str(), PIPE_ACCESS_INBOUND |
+            FILE_FLAG_OVERLAPPED, 0, 1, 8192, 8192, 0, &sa);
+        if (!child_end.valid())
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateNamedPipe() failed");
+        handle parent_end = CreateFileA(name_.c_str(), GENERIC_WRITE, 0, NULL,
+            OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+        if (!parent_end.valid())
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateFile() failed");
+#endif
+        if (stype == output_stream)
+            std::swap(child_end, parent_end);
+#if defined(BOOST_WINDOWS_API)
+        if (!SetHandleInformation(child_end.native(), HANDLE_FLAG_INHERIT,
+            HANDLE_FLAG_INHERIT))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                "SetHandleInformation() failed");
+#endif
+        return stream_ends(child_end, parent_end);
+    }
+
+private:
+    std::string name_;
+
+#if defined(BOOST_POSIX_API)
+    stream_type stype_;
+#endif
+};
+
+/**
+ * Stream behavior to redirect streams with a pipe which supports asynchronous
+ * I/O.
+ *
+ * As platforms require different types of pipes for asynchronous I/O this
+ * stream behavior is provided for convenience. It uses the minimum required
+ * pipe type on a platform in order to be able to use asynchronous I/O.
+ */
+#if defined(BOOST_POSIX_API) || defined(BOOST_PROCESS_DOXYGEN)
+typedef pipe async_pipe;
+#elif defined(BOOST_WINDOWS_API)
+class async_pipe
+{
+public:
+    stream_ends operator()(stream_type stype) const
+    {
+        UUID uuid;
+        RPC_STATUS s = UuidCreateSequential(&uuid);
+        if (s != RPC_S_OK && s != RPC_S_UUID_LOCAL_ONLY)
+            BOOST_PROCESS_THROW_ERROR(s, "UuidCreateSequential() failed");
+        unsigned char *c;
+        s = UuidToStringA(&uuid, &c);
+        if (s != RPC_S_OK)
+            BOOST_PROCESS_THROW_ERROR(s, "UuidToString() failed");
+        std::string name;
+        try
+        {
+            name = reinterpret_cast<char*>(c);
+        }
+        catch (...)
+        {
+            RpcStringFreeA(&c);
+            throw;
+        }
+        RpcStringFreeA(&c);
+        named_pipe p("\\\\.\\pipe\\boost_process_" + name);
+        return p(stype);
+    }
+};
+#endif
+
+/**
+ * Stream behavior to mute streams.
+ *
+ * A child process will be able to use streams. But data written to an
+ * output stream is discarded and data read from an input stream is 0.
+ */
+class null
+{
+public:
+#if defined(BOOST_POSIX_API)
+    null()
+    : stype_(unknown_stream)
+    {
+    }
+
+    null(stream_type stype)
+    : stype_(stype)
+    {
+    }
+#endif
+
+    stream_ends operator()(stream_type stype) const
+    {
+#if defined(BOOST_POSIX_API)
+        if (stype_ != unknown_stream)
+            stype = stype_;
+        std::string filename = (stype == input_stream) ? "/dev/zero" :
+            "/dev/null";
+        int flag = (stype == input_stream) ? O_RDONLY : O_WRONLY;
+        handle child_end = open(filename.c_str(), flag);
+        if (!child_end.valid())
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("open(2) failed");
+#elif defined(BOOST_WINDOWS_API)
+        DWORD access = (stype == input_stream) ? GENERIC_READ : GENERIC_WRITE;
+        handle child_end = CreateFileA("NUL", access, 0, NULL, OPEN_EXISTING,
+            FILE_ATTRIBUTE_NORMAL, NULL);
+        if (!child_end.valid())
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR("CreateFile() failed");
+        if (!SetHandleInformation(child_end.native(), HANDLE_FLAG_INHERIT,
+            HANDLE_FLAG_INHERIT))
+            BOOST_PROCESS_THROW_LAST_SYSTEM_ERROR(
+                "SetHandleInformation() failed");
+#endif
+        return stream_ends(child_end, handle());
+    }
+
+#if defined(BOOST_POSIX_API)
+private:
+    stream_type stype_;
+#endif
+};
+
+}
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/stream_ends.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,68 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/stream_ends.hpp
+ *
+ * Includes the declaration of the stream_ends class.
+ */
+
+#ifndef BOOST_PROCESS_STREAM_ENDS_HPP
+#define BOOST_PROCESS_STREAM_ENDS_HPP
+
+#include <boost/process/config.hpp>
+#include <boost/process/handle.hpp>
+
+namespace boost {
+namespace process {
+
+/**
+ * A pair of handles to configure streams.
+ *
+ * Stream behaviors return a pair of handles to specify how a child's stream
+ * should be configured and possibly the opposite end of a child's end. This
+ * is the end remaining in the parent process and which can be used for example
+ * to communicate with a child process through its standard streams.
+ */
+struct stream_ends {
+    /**
+     * The child's end.
+     */
+    handle child;
+
+    /**
+     * The parent's end.
+     */
+    handle parent;
+
+    /**
+     * Standard constructor creating two invalid handles.
+     */
+    stream_ends()
+    {
+    }
+
+    /**
+     * Helper constructor to easily initialize handles.
+     */
+    stream_ends(handle c, handle p)
+    : child(c),
+    parent(p)
+    {
+    }
+};
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/stream_id.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,50 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/stream_id.hpp
+ *
+ * Includes the declaration of the stream_id type.
+ */
+
+#ifndef BOOST_PROCESS_STREAM_ID_HPP
+#define BOOST_PROCESS_STREAM_ID_HPP
+
+#include <boost/process/config.hpp>
+
+namespace boost {
+namespace process {
+
+/**
+ * Standard stream id to refer to standard streams in a cross-platform manner.
+ */
+enum std_stream_id { stdin_id, stdout_id, stderr_id };
+
+#if defined(BOOST_PROCESS_DOXYGEN)
+/**
+ * Stream id type.
+ *
+ * Depending on the platform the stream id type is defined to refer to standard
+ * streams only or to support more streams.
+ */
+typedef NativeStreamId stream_id;
+#elif defined(BOOST_POSIX_API)
+typedef int stream_id;
+#elif defined(BOOST_WINDOWS_API)
+typedef std_stream_id stream_id;
+#endif
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/boost/process/stream_type.hpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,45 @@
+//
+// Boost.Process
+// ~~~~~~~~~~~~~
+//
+// Copyright (c) 2006, 2007 Julio M. Merino Vidal
+// Copyright (c) 2008 Ilya Sokolov, Boris Schaeling
+// Copyright (c) 2009 Boris Schaeling
+// Copyright (c) 2010 Felipe Tanus, Boris Schaeling
+//
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+/**
+ * \file boost/process/stream_type.hpp
+ *
+ * Includes the declaration of the stream_type enumeration.
+ */
+
+#ifndef BOOST_PROCESS_STREAM_TYPE_HPP
+#define BOOST_PROCESS_STREAM_TYPE_HPP
+
+#include <boost/process/config.hpp>
+
+namespace boost {
+namespace process {
+
+/**
+ * Stream type to differentiate between input and output streams.
+ *
+ * On POSIX systems another value unknown_stream is defined. It is passed
+ * to stream behaviors for file descriptors greater than 2.
+ */
+enum stream_type {
+    input_stream,
+    output_stream
+#if defined(BOOST_POSIX_API)
+    , unknown_stream
+#endif
+};
+
+}
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/cmake_modules/FindFFTW.cmake	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,28 @@
+if (FFTW_INCLUDES AND FFTW_LIBRARIES)
+  set(FFTW_FIND_QUIETLY TRUE)
+endif (FFTW_INCLUDES AND FFTW_LIBRARIES)
+
+find_path(FFTW_INCLUDES
+  NAMES
+  fftw3.h
+  PATHS
+  $ENV{FFTWDIR}
+  ${INCLUDE_INSTALL_DIR}
+)
+
+find_library(FFTWF_LIB NAMES fftw3f PATHS $ENV{FFTWDIR} ${LIB_INSTALL_DIR})
+find_library(FFTW_LIB NAMES fftw3 PATHS $ENV{FFTWDIR} ${LIB_INSTALL_DIR})
+set(FFTW_LIBRARIES "${FFTWF_LIB};${FFTW_LIB}" )
+
+find_library(FFTWL_LIB NAMES fftw3l  PATHS $ENV{FFTWDIR} ${LIB_INSTALL_DIR})
+
+if(FFTWL_LIB)
+set(FFTW_LIBRARIES "${FFTW_LIBRARIES};${FFTWL_LIB}")
+endif()
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(FFTW DEFAULT_MSG
+                                  FFTW_INCLUDES FFTW_LIBRARIES)
+
+mark_as_advanced(FFTW_INCLUDES FFTW_LIBRARIES)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/cmake_modules/FindSndFile.cmake	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,55 @@
+# Locate sndfile
+# This module defines
+# SNDFILE_LIBRARY
+# SNDFILE_FOUND, if false, do not try to link to sndfile
+# SNDFILE_INCLUDE_DIR, where to find the headers
+#
+# $SNDFILE_DIR is an environment variable that would
+# correspond to the ./configure --prefix=$SNDFILE_DIR
+
+FIND_PATH(SNDFILE_INCLUDE_DIR sndfile.h
+    PATH_SUFFIXES sndfile
+    PATHS
+    ${SNDFILE_DIR}/include
+    $ENV{SNDFILE_DIR}/include
+    $ENV{SNDFILE_DIR}
+    ~/Library/Frameworks
+    /Library/Frameworks
+    /usr/local/include
+    /usr/include
+    /usr/include/sndfile
+    /sw/include # Fink
+    /opt/local/include # DarwinPorts
+    /opt/csw/include # Blastwave
+    /opt/include
+    [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/include
+    /usr/freeware/include
+)
+
+find_library(SNDFILE_LIBRARY
+    NAMES "sndfile"
+    PATHS
+    ${SNDFILE_DIR}/lib
+    $ENV{SNDFILE_DIR}/lib
+    $ENV{SNDFILE_DIR}
+    ~/Library/Frameworks
+    /Library/Frameworks
+    /usr/local/lib
+    /usr/lib
+    /usr/lib64
+    /sw/lib
+    /opt/local/lib
+    /opt/csw/lib
+    /opt/lib
+    [HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\Session\ Manager\\Environment;OSG_ROOT]/lib
+    /usr/freeware/lib64
+    PATH_SUFFIXES
+    win32 Darwin Linux ""
+)
+
+
+SET(SNDFILE_FOUND "NO")
+IF(SNDFILE_LIBRARY AND SNDFILE_INCLUDE_DIR)
+    SET(SNDFILE_FOUND "YES")
+ENDIF(SNDFILE_LIBRARY AND SNDFILE_INCLUDE_DIR)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/CMakeLists.txt	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,8 @@
+set(JSON_SOURCES
+  json_reader.cpp
+  json_value.cpp
+  json_writer.cpp
+)
+
+add_library(json STATIC ${JSON_SOURCES})
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/LICENSE	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,55 @@
+The JsonCpp library's source code, including accompanying documentation, 
+tests and demonstration applications, are licensed under the following
+conditions...
+
+The author (Baptiste Lepilleur) explicitly disclaims copyright in all 
+jurisdictions which recognize such a disclaimer. In such jurisdictions, 
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
+released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this 
+software may choose to accept it either as 1) Public Domain, 2) under the 
+conditions of the MIT License (see below), or 3) under the terms of dual 
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+   http://en.wikipedia.org/wiki/MIT_License
+   
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/assertions.h	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,26 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
+# define CPPTL_JSON_ASSERTIONS_H_INCLUDED
+
+#include <stdlib.h>
+#include <iostream>
+
+#if !defined(JSON_IS_AMALGAMATION)
+# include <json/config.h>
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+#if defined(JSON_USE_EXCEPTION)
+#define JSON_ASSERT( condition ) assert( condition );  // @todo <= change this into an exception throw
+#define JSON_FAIL_MESSAGE( message ) throw std::runtime_error( message );
+#else  // defined(JSON_USE_EXCEPTION)
+#define JSON_ASSERT( condition ) assert( condition );
+#define JSON_FAIL_MESSAGE( message ) { std::cerr << std::endl << message << std::endl; exit(123); }
+#endif
+
+#define JSON_ASSERT_MESSAGE( condition, message ) if (!( condition )) { JSON_FAIL_MESSAGE( message ) }
+
+#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/autolink.h	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,24 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_AUTOLINK_H_INCLUDED
+# define JSON_AUTOLINK_H_INCLUDED
+
+# include "config.h"
+
+# ifdef JSON_IN_CPPTL
+#  include <cpptl/cpptl_autolink.h>
+# endif
+
+# if !defined(JSON_NO_AUTOLINK)  &&  !defined(JSON_DLL_BUILD)  &&  !defined(JSON_IN_CPPTL)
+#  define CPPTL_AUTOLINK_NAME "json"
+#  undef CPPTL_AUTOLINK_DLL
+#  ifdef JSON_DLL
+#   define CPPTL_AUTOLINK_DLL
+#  endif
+#  include "autolink.h"
+# endif
+
+#endif // JSON_AUTOLINK_H_INCLUDED
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/config.h	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,96 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_CONFIG_H_INCLUDED
+# define JSON_CONFIG_H_INCLUDED
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//#  define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of std::map
+/// as Value container.
+//#  define JSON_USE_CPPTL_SMALLMAP 1
+/// If defined, indicates that Json specific container should be used
+/// (hash table & simple deque container with customizable allocator).
+/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332
+//#  define JSON_VALUE_USE_INTERNAL_MAP 1
+/// Force usage of standard new/malloc based allocator instead of memory pool based allocator.
+/// The memory pools allocator used optimization (initializing Value and ValueInternalLink
+/// as if it was a POD) that may cause some validation tool to report errors.
+/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
+//#  define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
+
+/// If defined, indicates that Json use exception to report invalid type manipulation
+/// instead of C assert macro.
+# define JSON_USE_EXCEPTION 1
+
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+/// Remarks: it is automatically defined in the generated amalgated header.
+// #define JSON_IS_AMALGAMATION
+
+
+# ifdef JSON_IN_CPPTL
+#  include <cpptl/config.h>
+#  ifndef JSON_USE_CPPTL
+#   define JSON_USE_CPPTL 1
+#  endif
+# endif
+
+# ifdef JSON_IN_CPPTL
+#  define JSON_API CPPTL_API
+# elif defined(JSON_DLL_BUILD)
+#  define JSON_API __declspec(dllexport)
+# elif defined(JSON_DLL)
+#  define JSON_API __declspec(dllimport)
+# else
+#  define JSON_API
+# endif
+
+// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for integer
+// Storages, and 64 bits integer support is disabled.
+// #define JSON_NO_INT64 1
+
+#if defined(_MSC_VER)  &&  _MSC_VER <= 1200 // MSVC 6
+// Microsoft Visual Studio 6 only support conversion from __int64 to double
+// (no conversion from unsigned __int64).
+#define JSON_USE_INT64_DOUBLE_CONVERSION 1
+#endif // if defined(_MSC_VER)  &&  _MSC_VER < 1200 // MSVC 6
+
+#if defined(_MSC_VER)  &&  _MSC_VER >= 1500 // MSVC 2008
+/// Indicates that the following function is deprecated.
+# define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+#endif
+
+#if !defined(JSONCPP_DEPRECATED)
+# define JSONCPP_DEPRECATED(message)
+#endif // if !defined(JSONCPP_DEPRECATED)
+
+namespace Json {
+   typedef int Int;
+   typedef unsigned int UInt;
+# if defined(JSON_NO_INT64)
+   typedef int LargestInt;
+   typedef unsigned int LargestUInt;
+#  undef JSON_HAS_INT64
+# else // if defined(JSON_NO_INT64)
+   // For Microsoft Visual use specific types as long long is not supported
+#  if defined(_MSC_VER) // Microsoft Visual Studio
+   typedef __int64 Int64;
+   typedef unsigned __int64 UInt64;
+#  else // if defined(_MSC_VER) // Other platforms, use long long
+   typedef long long int Int64;
+   typedef unsigned long long int UInt64;
+#  endif // if defined(_MSC_VER)
+   typedef Int64 LargestInt;
+   typedef UInt64 LargestUInt;
+#  define JSON_HAS_INT64
+# endif // if defined(JSON_NO_INT64)
+} // end namespace Json
+
+
+#endif // JSON_CONFIG_H_INCLUDED
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/features.h	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,49 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
+# define CPPTL_JSON_FEATURES_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+# include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+   /** \brief Configuration passed to reader and writer.
+    * This configuration object can be used to force the Reader or Writer
+    * to behave in a standard conforming way.
+    */
+   class JSON_API Features
+   {
+   public:
+      /** \brief A configuration that allows all features and assumes all strings are UTF-8.
+       * - C & C++ comments are allowed
+       * - Root object can be any JSON value
+       * - Assumes Value strings are encoded in UTF-8
+       */
+      static Features all();
+
+      /** \brief A configuration that is strictly compatible with the JSON specification.
+       * - Comments are forbidden.
+       * - Root object must be either an array or an object value.
+       * - Assumes Value strings are encoded in UTF-8
+       */
+      static Features strictMode();
+
+      /** \brief Initialize the configuration like JsonConfig::allFeatures;
+       */
+      Features();
+
+      /// \c true if comments are allowed. Default: \c true.
+      bool allowComments_;
+
+      /// \c true if root must be either an array or an object value. Default: \c false.
+      bool strictRoot_;
+   };
+
+} // namespace Json
+
+#endif // CPPTL_JSON_FEATURES_H_INCLUDED
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/forwards.h	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,44 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_FORWARDS_H_INCLUDED
+# define JSON_FORWARDS_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+# include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+   // writer.h
+   class FastWriter;
+   class StyledWriter;
+
+   // reader.h
+   class Reader;
+
+   // features.h
+   class Features;
+
+   // value.h
+   typedef unsigned int ArrayIndex;
+   class StaticString;
+   class Path;
+   class PathArgument;
+   class Value;
+   class ValueIteratorBase;
+   class ValueIterator;
+   class ValueConstIterator;
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+   class ValueMapAllocator;
+   class ValueInternalLink;
+   class ValueInternalArray;
+   class ValueInternalMap;
+#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+} // namespace Json
+
+
+#endif // JSON_FORWARDS_H_INCLUDED
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/json.h	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,15 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_JSON_H_INCLUDED
+# define JSON_JSON_H_INCLUDED
+
+# include "autolink.h"
+# include "value.h"
+# include "reader.h"
+# include "writer.h"
+# include "features.h"
+
+#endif // JSON_JSON_H_INCLUDED
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/json_batchallocator.h	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,127 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
+# define JSONCPP_BATCHALLOCATOR_H_INCLUDED
+
+# include <stdlib.h>
+# include <assert.h>
+
+# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+namespace Json {
+
+/* Fast memory allocator.
+ *
+ * This memory allocator allocates memory for a batch of object (specified by
+ * the page size, the number of object in each page).
+ *
+ * It does not allow the destruction of a single object. All the allocated objects
+ * can be destroyed at once. The memory can be either released or reused for future
+ * allocation.
+ * 
+ * The in-place new operator must be used to construct the object using the pointer
+ * returned by allocate.
+ */
+template<typename AllocatedType
+        ,const unsigned int objectPerAllocation>
+class BatchAllocator
+{
+public:
+   BatchAllocator( unsigned int objectsPerPage = 255 )
+      : freeHead_( 0 )
+      , objectsPerPage_( objectsPerPage )
+   {
+//      printf( "Size: %d => %s\n", sizeof(AllocatedType), typeid(AllocatedType).name() );
+      assert( sizeof(AllocatedType) * objectPerAllocation >= sizeof(AllocatedType *) ); // We must be able to store a slist in the object free space.
+      assert( objectsPerPage >= 16 );
+      batches_ = allocateBatch( 0 );   // allocated a dummy page
+      currentBatch_ = batches_;
+   }
+
+   ~BatchAllocator()
+   {
+      for ( BatchInfo *batch = batches_; batch;  )
+      {
+         BatchInfo *nextBatch = batch->next_;
+         free( batch );
+         batch = nextBatch;
+      }
+   }
+
+   /// allocate space for an array of objectPerAllocation object.
+   /// @warning it is the responsability of the caller to call objects constructors.
+   AllocatedType *allocate()
+   {
+      if ( freeHead_ ) // returns node from free list.
+      {
+         AllocatedType *object = freeHead_;
+         freeHead_ = *(AllocatedType **)object;
+         return object;
+      }
+      if ( currentBatch_->used_ == currentBatch_->end_ )
+      {
+         currentBatch_ = currentBatch_->next_;
+         while ( currentBatch_  &&  currentBatch_->used_ == currentBatch_->end_ )
+            currentBatch_ = currentBatch_->next_;
+
+         if ( !currentBatch_  ) // no free batch found, allocate a new one
+         { 
+            currentBatch_ = allocateBatch( objectsPerPage_ );
+            currentBatch_->next_ = batches_; // insert at the head of the list
+            batches_ = currentBatch_;
+         }
+      }
+      AllocatedType *allocated = currentBatch_->used_;
+      currentBatch_->used_ += objectPerAllocation;
+      return allocated;
+   }
+
+   /// Release the object.
+   /// @warning it is the responsability of the caller to actually destruct the object.
+   void release( AllocatedType *object )
+   {
+      assert( object != 0 );
+      *(AllocatedType **)object = freeHead_;
+      freeHead_ = object;
+   }
+
+private:
+   struct BatchInfo
+   {
+      BatchInfo *next_;
+      AllocatedType *used_;
+      AllocatedType *end_;
+      AllocatedType buffer_[objectPerAllocation];
+   };
+
+   // disabled copy constructor and assignement operator.
+   BatchAllocator( const BatchAllocator & );
+   void operator =( const BatchAllocator &);
+
+   static BatchInfo *allocateBatch( unsigned int objectsPerPage )
+   {
+      const unsigned int mallocSize = sizeof(BatchInfo) - sizeof(AllocatedType)* objectPerAllocation
+                                + sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
+      BatchInfo *batch = static_cast<BatchInfo*>( malloc( mallocSize ) );
+      batch->next_ = 0;
+      batch->used_ = batch->buffer_;
+      batch->end_ = batch->buffer_ + objectsPerPage;
+      return batch;
+   }
+
+   BatchInfo *batches_;
+   BatchInfo *currentBatch_;
+   /// Head of a single linked list within the allocated space of freeed object
+   AllocatedType *freeHead_;
+   unsigned int objectsPerPage_;
+};
+
+
+} // namespace Json
+
+# endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
+
+#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/json_internalarray.inl	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,454 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+// included by json_value.cpp
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalArray
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueArrayAllocator::~ValueArrayAllocator()
+{
+}
+
+// //////////////////////////////////////////////////////////////////
+// class DefaultValueArrayAllocator
+// //////////////////////////////////////////////////////////////////
+#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+class DefaultValueArrayAllocator : public ValueArrayAllocator
+{
+public: // overridden from ValueArrayAllocator
+   virtual ~DefaultValueArrayAllocator()
+   {
+   }
+
+   virtual ValueInternalArray *newArray()
+   {
+      return new ValueInternalArray();
+   }
+
+   virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+   {
+      return new ValueInternalArray( other );
+   }
+
+   virtual void destructArray( ValueInternalArray *array )
+   {
+      delete array;
+   }
+
+   virtual void reallocateArrayPageIndex( Value **&indexes, 
+                                          ValueInternalArray::PageIndex &indexCount,
+                                          ValueInternalArray::PageIndex minNewIndexCount )
+   {
+      ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+      if ( minNewIndexCount > newIndexCount )
+         newIndexCount = minNewIndexCount;
+      void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+      JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
+      indexCount = newIndexCount;
+      indexes = static_cast<Value **>( newIndexes );
+   }
+   virtual void releaseArrayPageIndex( Value **indexes, 
+                                       ValueInternalArray::PageIndex indexCount )
+   {
+      if ( indexes )
+         free( indexes );
+   }
+
+   virtual Value *allocateArrayPage()
+   {
+      return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
+   }
+
+   virtual void releaseArrayPage( Value *value )
+   {
+      if ( value )
+         free( value );
+   }
+};
+
+#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+/// @todo make this thread-safe (lock when accessign batch allocator)
+class DefaultValueArrayAllocator : public ValueArrayAllocator
+{
+public: // overridden from ValueArrayAllocator
+   virtual ~DefaultValueArrayAllocator()
+   {
+   }
+
+   virtual ValueInternalArray *newArray()
+   {
+      ValueInternalArray *array = arraysAllocator_.allocate();
+      new (array) ValueInternalArray(); // placement new
+      return array;
+   }
+
+   virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+   {
+      ValueInternalArray *array = arraysAllocator_.allocate();
+      new (array) ValueInternalArray( other ); // placement new
+      return array;
+   }
+
+   virtual void destructArray( ValueInternalArray *array )
+   {
+      if ( array )
+      {
+         array->~ValueInternalArray();
+         arraysAllocator_.release( array );
+      }
+   }
+
+   virtual void reallocateArrayPageIndex( Value **&indexes, 
+                                          ValueInternalArray::PageIndex &indexCount,
+                                          ValueInternalArray::PageIndex minNewIndexCount )
+   {
+      ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+      if ( minNewIndexCount > newIndexCount )
+         newIndexCount = minNewIndexCount;
+      void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+      JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
+      indexCount = newIndexCount;
+      indexes = static_cast<Value **>( newIndexes );
+   }
+   virtual void releaseArrayPageIndex( Value **indexes, 
+                                       ValueInternalArray::PageIndex indexCount )
+   {
+      if ( indexes )
+         free( indexes );
+   }
+
+   virtual Value *allocateArrayPage()
+   {
+      return static_cast<Value *>( pagesAllocator_.allocate() );
+   }
+
+   virtual void releaseArrayPage( Value *value )
+   {
+      if ( value )
+         pagesAllocator_.release( value );
+   }
+private:
+   BatchAllocator<ValueInternalArray,1> arraysAllocator_;
+   BatchAllocator<Value,ValueInternalArray::itemsPerPage> pagesAllocator_;
+};
+#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+
+static ValueArrayAllocator *&arrayAllocator()
+{
+   static DefaultValueArrayAllocator defaultAllocator;
+   static ValueArrayAllocator *arrayAllocator = &defaultAllocator;
+   return arrayAllocator;
+}
+
+static struct DummyArrayAllocatorInitializer {
+   DummyArrayAllocatorInitializer() 
+   {
+      arrayAllocator();      // ensure arrayAllocator() statics are initialized before main().
+   }
+} dummyArrayAllocatorInitializer;
+
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalArray
+// //////////////////////////////////////////////////////////////////
+bool 
+ValueInternalArray::equals( const IteratorState &x, 
+                            const IteratorState &other )
+{
+   return x.array_ == other.array_  
+          &&  x.currentItemIndex_ == other.currentItemIndex_  
+          &&  x.currentPageIndex_ == other.currentPageIndex_;
+}
+
+
+void 
+ValueInternalArray::increment( IteratorState &it )
+{
+   JSON_ASSERT_MESSAGE( it.array_  &&
+      (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
+      != it.array_->size_,
+      "ValueInternalArray::increment(): moving iterator beyond end" );
+   ++(it.currentItemIndex_);
+   if ( it.currentItemIndex_ == itemsPerPage )
+   {
+      it.currentItemIndex_ = 0;
+      ++(it.currentPageIndex_);
+   }
+}
+
+
+void 
+ValueInternalArray::decrement( IteratorState &it )
+{
+   JSON_ASSERT_MESSAGE( it.array_  &&  it.currentPageIndex_ == it.array_->pages_ 
+                        &&  it.currentItemIndex_ == 0,
+      "ValueInternalArray::decrement(): moving iterator beyond end" );
+   if ( it.currentItemIndex_ == 0 )
+   {
+      it.currentItemIndex_ = itemsPerPage-1;
+      --(it.currentPageIndex_);
+   }
+   else
+   {
+      --(it.currentItemIndex_);
+   }
+}
+
+
+Value &
+ValueInternalArray::unsafeDereference( const IteratorState &it )
+{
+   return (*(it.currentPageIndex_))[it.currentItemIndex_];
+}
+
+
+Value &
+ValueInternalArray::dereference( const IteratorState &it )
+{
+   JSON_ASSERT_MESSAGE( it.array_  &&
+      (it.currentPageIndex_ - it.array_->pages_)*itemsPerPage + it.currentItemIndex_
+      < it.array_->size_,
+      "ValueInternalArray::dereference(): dereferencing invalid iterator" );
+   return unsafeDereference( it );
+}
+
+void 
+ValueInternalArray::makeBeginIterator( IteratorState &it ) const
+{
+   it.array_ = const_cast<ValueInternalArray *>( this );
+   it.currentItemIndex_ = 0;
+   it.currentPageIndex_ = pages_;
+}
+
+
+void 
+ValueInternalArray::makeIterator( IteratorState &it, ArrayIndex index ) const
+{
+   it.array_ = const_cast<ValueInternalArray *>( this );
+   it.currentItemIndex_ = index % itemsPerPage;
+   it.currentPageIndex_ = pages_ + index / itemsPerPage;
+}
+
+
+void 
+ValueInternalArray::makeEndIterator( IteratorState &it ) const
+{
+   makeIterator( it, size_ );
+}
+
+
+ValueInternalArray::ValueInternalArray()
+   : pages_( 0 )
+   , size_( 0 )
+   , pageCount_( 0 )
+{
+}
+
+
+ValueInternalArray::ValueInternalArray( const ValueInternalArray &other )
+   : pages_( 0 )
+   , size_( other.size_ )
+   , pageCount_( 0 )
+{
+   PageIndex minNewPages = other.size_ / itemsPerPage;
+   arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
+   JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, 
+                        "ValueInternalArray::reserve(): bad reallocation" );
+   IteratorState itOther;
+   other.makeBeginIterator( itOther );
+   Value *value;
+   for ( ArrayIndex index = 0; index < size_; ++index, increment(itOther) )
+   {
+      if ( index % itemsPerPage == 0 )
+      {
+         PageIndex pageIndex = index / itemsPerPage;
+         value = arrayAllocator()->allocateArrayPage();
+         pages_[pageIndex] = value;
+      }
+      new (value) Value( dereference( itOther ) );
+   }
+}
+
+
+ValueInternalArray &
+ValueInternalArray::operator =( const ValueInternalArray &other )
+{
+   ValueInternalArray temp( other );
+   swap( temp );
+   return *this;
+}
+
+
+ValueInternalArray::~ValueInternalArray()
+{
+   // destroy all constructed items
+   IteratorState it;
+   IteratorState itEnd;
+   makeBeginIterator( it);
+   makeEndIterator( itEnd );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      Value *value = &dereference(it);
+      value->~Value();
+   }
+   // release all pages
+   PageIndex lastPageIndex = size_ / itemsPerPage;
+   for ( PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex )
+      arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
+   // release pages index
+   arrayAllocator()->releaseArrayPageIndex( pages_, pageCount_ );
+}
+
+
+void 
+ValueInternalArray::swap( ValueInternalArray &other )
+{
+   Value **tempPages = pages_;
+   pages_ = other.pages_;
+   other.pages_ = tempPages;
+   ArrayIndex tempSize = size_;
+   size_ = other.size_;
+   other.size_ = tempSize;
+   PageIndex tempPageCount = pageCount_;
+   pageCount_ = other.pageCount_;
+   other.pageCount_ = tempPageCount;
+}
+
+void 
+ValueInternalArray::clear()
+{
+   ValueInternalArray dummy;
+   swap( dummy );
+}
+
+
+void 
+ValueInternalArray::resize( ArrayIndex newSize )
+{
+   if ( newSize == 0 )
+      clear();
+   else if ( newSize < size_ )
+   {
+      IteratorState it;
+      IteratorState itEnd;
+      makeIterator( it, newSize );
+      makeIterator( itEnd, size_ );
+      for ( ; !equals(it,itEnd); increment(it) )
+      {
+         Value *value = &dereference(it);
+         value->~Value();
+      }
+      PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
+      PageIndex lastPageIndex = size_ / itemsPerPage;
+      for ( ; pageIndex < lastPageIndex; ++pageIndex )
+         arrayAllocator()->releaseArrayPage( pages_[pageIndex] );
+      size_ = newSize;
+   }
+   else if ( newSize > size_ )
+      resolveReference( newSize );
+}
+
+
+void 
+ValueInternalArray::makeIndexValid( ArrayIndex index )
+{
+   // Need to enlarge page index ?
+   if ( index >= pageCount_ * itemsPerPage )
+   {
+      PageIndex minNewPages = (index + 1) / itemsPerPage;
+      arrayAllocator()->reallocateArrayPageIndex( pages_, pageCount_, minNewPages );
+      JSON_ASSERT_MESSAGE( pageCount_ >= minNewPages, "ValueInternalArray::reserve(): bad reallocation" );
+   }
+
+   // Need to allocate new pages ?
+   ArrayIndex nextPageIndex = 
+      (size_ % itemsPerPage) != 0 ? size_ - (size_%itemsPerPage) + itemsPerPage
+                                  : size_;
+   if ( nextPageIndex <= index )
+   {
+      PageIndex pageIndex = nextPageIndex / itemsPerPage;
+      PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
+      for ( ; pageToAllocate-- > 0; ++pageIndex )
+         pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
+   }
+
+   // Initialize all new entries
+   IteratorState it;
+   IteratorState itEnd;
+   makeIterator( it, size_ );
+   size_ = index + 1;
+   makeIterator( itEnd, size_ );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      Value *value = &dereference(it);
+      new (value) Value(); // Construct a default value using placement new
+   }
+}
+
+Value &
+ValueInternalArray::resolveReference( ArrayIndex index )
+{
+   if ( index >= size_ )
+      makeIndexValid( index );
+   return pages_[index/itemsPerPage][index%itemsPerPage];
+}
+
+Value *
+ValueInternalArray::find( ArrayIndex index ) const
+{
+   if ( index >= size_ )
+      return 0;
+   return &(pages_[index/itemsPerPage][index%itemsPerPage]);
+}
+
+ValueInternalArray::ArrayIndex 
+ValueInternalArray::size() const
+{
+   return size_;
+}
+
+int 
+ValueInternalArray::distance( const IteratorState &x, const IteratorState &y )
+{
+   return indexOf(y) - indexOf(x);
+}
+
+
+ValueInternalArray::ArrayIndex 
+ValueInternalArray::indexOf( const IteratorState &iterator )
+{
+   if ( !iterator.array_ )
+      return ArrayIndex(-1);
+   return ArrayIndex(
+      (iterator.currentPageIndex_ - iterator.array_->pages_) * itemsPerPage 
+      + iterator.currentItemIndex_ );
+}
+
+
+int 
+ValueInternalArray::compare( const ValueInternalArray &other ) const
+{
+   int sizeDiff( size_ - other.size_ );
+   if ( sizeDiff != 0 )
+      return sizeDiff;
+   
+   for ( ArrayIndex index =0; index < size_; ++index )
+   {
+      int diff = pages_[index/itemsPerPage][index%itemsPerPage].compare( 
+         other.pages_[index/itemsPerPage][index%itemsPerPage] );
+      if ( diff != 0 )
+         return diff;
+   }
+   return 0;
+}
+
+} // namespace Json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/json_internalmap.inl	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,615 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+// included by json_value.cpp
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalMap
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/** \internal MUST be safely initialized using memset( this, 0, sizeof(ValueInternalLink) );
+   * This optimization is used by the fast allocator.
+   */
+ValueInternalLink::ValueInternalLink()
+   : previous_( 0 )
+   , next_( 0 )
+{
+}
+
+ValueInternalLink::~ValueInternalLink()
+{ 
+   for ( int index =0; index < itemPerLink; ++index )
+   {
+      if ( !items_[index].isItemAvailable() )
+      {
+         if ( !items_[index].isMemberNameStatic() )
+            free( keys_[index] );
+      }
+      else
+         break;
+   }
+}
+
+
+
+ValueMapAllocator::~ValueMapAllocator()
+{
+}
+
+#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+class DefaultValueMapAllocator : public ValueMapAllocator
+{
+public: // overridden from ValueMapAllocator
+   virtual ValueInternalMap *newMap()
+   {
+      return new ValueInternalMap();
+   }
+
+   virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+   {
+      return new ValueInternalMap( other );
+   }
+
+   virtual void destructMap( ValueInternalMap *map )
+   {
+      delete map;
+   }
+
+   virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+   {
+      return new ValueInternalLink[size];
+   }
+
+   virtual void releaseMapBuckets( ValueInternalLink *links )
+   {
+      delete [] links;
+   }
+
+   virtual ValueInternalLink *allocateMapLink()
+   {
+      return new ValueInternalLink();
+   }
+
+   virtual void releaseMapLink( ValueInternalLink *link )
+   {
+      delete link;
+   }
+};
+#else
+/// @todo make this thread-safe (lock when accessign batch allocator)
+class DefaultValueMapAllocator : public ValueMapAllocator
+{
+public: // overridden from ValueMapAllocator
+   virtual ValueInternalMap *newMap()
+   {
+      ValueInternalMap *map = mapsAllocator_.allocate();
+      new (map) ValueInternalMap(); // placement new
+      return map;
+   }
+
+   virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+   {
+      ValueInternalMap *map = mapsAllocator_.allocate();
+      new (map) ValueInternalMap( other ); // placement new
+      return map;
+   }
+
+   virtual void destructMap( ValueInternalMap *map )
+   {
+      if ( map )
+      {
+         map->~ValueInternalMap();
+         mapsAllocator_.release( map );
+      }
+   }
+
+   virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+   {
+      return new ValueInternalLink[size];
+   }
+
+   virtual void releaseMapBuckets( ValueInternalLink *links )
+   {
+      delete [] links;
+   }
+
+   virtual ValueInternalLink *allocateMapLink()
+   {
+      ValueInternalLink *link = linksAllocator_.allocate();
+      memset( link, 0, sizeof(ValueInternalLink) );
+      return link;
+   }
+
+   virtual void releaseMapLink( ValueInternalLink *link )
+   {
+      link->~ValueInternalLink();
+      linksAllocator_.release( link );
+   }
+private:
+   BatchAllocator<ValueInternalMap,1> mapsAllocator_;
+   BatchAllocator<ValueInternalLink,1> linksAllocator_;
+};
+#endif
+
+static ValueMapAllocator *&mapAllocator()
+{
+   static DefaultValueMapAllocator defaultAllocator;
+   static ValueMapAllocator *mapAllocator = &defaultAllocator;
+   return mapAllocator;
+}
+
+static struct DummyMapAllocatorInitializer {
+   DummyMapAllocatorInitializer() 
+   {
+      mapAllocator();      // ensure mapAllocator() statics are initialized before main().
+   }
+} dummyMapAllocatorInitializer;
+
+
+
+// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
+
+/*
+use linked list hash map. 
+buckets array is a container.
+linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
+value have extra state: valid, available, deleted
+*/
+
+
+ValueInternalMap::ValueInternalMap()
+   : buckets_( 0 )
+   , tailLink_( 0 )
+   , bucketsSize_( 0 )
+   , itemCount_( 0 )
+{
+}
+
+
+ValueInternalMap::ValueInternalMap( const ValueInternalMap &other )
+   : buckets_( 0 )
+   , tailLink_( 0 )
+   , bucketsSize_( 0 )
+   , itemCount_( 0 )
+{
+   reserve( other.itemCount_ );
+   IteratorState it;
+   IteratorState itEnd;
+   other.makeBeginIterator( it );
+   other.makeEndIterator( itEnd );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      bool isStatic;
+      const char *memberName = key( it, isStatic );
+      const Value &aValue = value( it );
+      resolveReference(memberName, isStatic) = aValue;
+   }
+}
+
+
+ValueInternalMap &
+ValueInternalMap::operator =( const ValueInternalMap &other )
+{
+   ValueInternalMap dummy( other );
+   swap( dummy );
+   return *this;
+}
+
+
+ValueInternalMap::~ValueInternalMap()
+{
+   if ( buckets_ )
+   {
+      for ( BucketIndex bucketIndex =0; bucketIndex < bucketsSize_; ++bucketIndex )
+      {
+         ValueInternalLink *link = buckets_[bucketIndex].next_;
+         while ( link )
+         {
+            ValueInternalLink *linkToRelease = link;
+            link = link->next_;
+            mapAllocator()->releaseMapLink( linkToRelease );
+         }
+      }
+      mapAllocator()->releaseMapBuckets( buckets_ );
+   }
+}
+
+
+void 
+ValueInternalMap::swap( ValueInternalMap &other )
+{
+   ValueInternalLink *tempBuckets = buckets_;
+   buckets_ = other.buckets_;
+   other.buckets_ = tempBuckets;
+   ValueInternalLink *tempTailLink = tailLink_;
+   tailLink_ = other.tailLink_;
+   other.tailLink_ = tempTailLink;
+   BucketIndex tempBucketsSize = bucketsSize_;
+   bucketsSize_ = other.bucketsSize_;
+   other.bucketsSize_ = tempBucketsSize;
+   BucketIndex tempItemCount = itemCount_;
+   itemCount_ = other.itemCount_;
+   other.itemCount_ = tempItemCount;
+}
+
+
+void 
+ValueInternalMap::clear()
+{
+   ValueInternalMap dummy;
+   swap( dummy );
+}
+
+
+ValueInternalMap::BucketIndex 
+ValueInternalMap::size() const
+{
+   return itemCount_;
+}
+
+bool 
+ValueInternalMap::reserveDelta( BucketIndex growth )
+{
+   return reserve( itemCount_ + growth );
+}
+
+bool 
+ValueInternalMap::reserve( BucketIndex newItemCount )
+{
+   if ( !buckets_  &&  newItemCount > 0 )
+   {
+      buckets_ = mapAllocator()->allocateMapBuckets( 1 );
+      bucketsSize_ = 1;
+      tailLink_ = &buckets_[0];
+   }
+//   BucketIndex idealBucketCount = (newItemCount + ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
+   return true;
+}
+
+
+const Value *
+ValueInternalMap::find( const char *key ) const
+{
+   if ( !bucketsSize_ )
+      return 0;
+   HashKey hashedKey = hash( key );
+   BucketIndex bucketIndex = hashedKey % bucketsSize_;
+   for ( const ValueInternalLink *current = &buckets_[bucketIndex]; 
+         current != 0; 
+         current = current->next_ )
+   {
+      for ( BucketIndex index=0; index < ValueInternalLink::itemPerLink; ++index )
+      {
+         if ( current->items_[index].isItemAvailable() )
+            return 0;
+         if ( strcmp( key, current->keys_[index] ) == 0 )
+            return &current->items_[index];
+      }
+   }
+   return 0;
+}
+
+
+Value *
+ValueInternalMap::find( const char *key )
+{
+   const ValueInternalMap *constThis = this;
+   return const_cast<Value *>( constThis->find( key ) );
+}
+
+
+Value &
+ValueInternalMap::resolveReference( const char *key,
+                                    bool isStatic )
+{
+   HashKey hashedKey = hash( key );
+   if ( bucketsSize_ )
+   {
+      BucketIndex bucketIndex = hashedKey % bucketsSize_;
+      ValueInternalLink **previous = 0;
+      BucketIndex index;
+      for ( ValueInternalLink *current = &buckets_[bucketIndex]; 
+            current != 0; 
+            previous = &current->next_, current = current->next_ )
+      {
+         for ( index=0; index < ValueInternalLink::itemPerLink; ++index )
+         {
+            if ( current->items_[index].isItemAvailable() )
+               return setNewItem( key, isStatic, current, index );
+            if ( strcmp( key, current->keys_[index] ) == 0 )
+               return current->items_[index];
+         }
+      }
+   }
+
+   reserveDelta( 1 );
+   return unsafeAdd( key, isStatic, hashedKey );
+}
+
+
+void 
+ValueInternalMap::remove( const char *key )
+{
+   HashKey hashedKey = hash( key );
+   if ( !bucketsSize_ )
+      return;
+   BucketIndex bucketIndex = hashedKey % bucketsSize_;
+   for ( ValueInternalLink *link = &buckets_[bucketIndex]; 
+         link != 0; 
+         link = link->next_ )
+   {
+      BucketIndex index;
+      for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
+      {
+         if ( link->items_[index].isItemAvailable() )
+            return;
+         if ( strcmp( key, link->keys_[index] ) == 0 )
+         {
+            doActualRemove( link, index, bucketIndex );
+            return;
+         }
+      }
+   }
+}
+
+void 
+ValueInternalMap::doActualRemove( ValueInternalLink *link, 
+                                  BucketIndex index,
+                                  BucketIndex bucketIndex )
+{
+   // find last item of the bucket and swap it with the 'removed' one.
+   // set removed items flags to 'available'.
+   // if last page only contains 'available' items, then desallocate it (it's empty)
+   ValueInternalLink *&lastLink = getLastLinkInBucket( index );
+   BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
+   for ( ;   
+         lastItemIndex < ValueInternalLink::itemPerLink; 
+         ++lastItemIndex ) // may be optimized with dicotomic search
+   {
+      if ( lastLink->items_[lastItemIndex].isItemAvailable() )
+         break;
+   }
+   
+   BucketIndex lastUsedIndex = lastItemIndex - 1;
+   Value *valueToDelete = &link->items_[index];
+   Value *valueToPreserve = &lastLink->items_[lastUsedIndex];
+   if ( valueToDelete != valueToPreserve )
+      valueToDelete->swap( *valueToPreserve );
+   if ( lastUsedIndex == 0 )  // page is now empty
+   {  // remove it from bucket linked list and delete it.
+      ValueInternalLink *linkPreviousToLast = lastLink->previous_;
+      if ( linkPreviousToLast != 0 )   // can not deleted bucket link.
+      {
+         mapAllocator()->releaseMapLink( lastLink );
+         linkPreviousToLast->next_ = 0;
+         lastLink = linkPreviousToLast;
+      }
+   }
+   else
+   {
+      Value dummy;
+      valueToPreserve->swap( dummy ); // restore deleted to default Value.
+      valueToPreserve->setItemUsed( false );
+   }
+   --itemCount_;
+}
+
+
+ValueInternalLink *&
+ValueInternalMap::getLastLinkInBucket( BucketIndex bucketIndex )
+{
+   if ( bucketIndex == bucketsSize_ - 1 )
+      return tailLink_;
+   ValueInternalLink *&previous = buckets_[bucketIndex+1].previous_;
+   if ( !previous )
+      previous = &buckets_[bucketIndex];
+   return previous;
+}
+
+
+Value &
+ValueInternalMap::setNewItem( const char *key, 
+                              bool isStatic,
+                              ValueInternalLink *link, 
+                              BucketIndex index )
+{
+   char *duplicatedKey = makeMemberName( key );
+   ++itemCount_;
+   link->keys_[index] = duplicatedKey;
+   link->items_[index].setItemUsed();
+   link->items_[index].setMemberNameIsStatic( isStatic );
+   return link->items_[index]; // items already default constructed.
+}
+
+
+Value &
+ValueInternalMap::unsafeAdd( const char *key, 
+                             bool isStatic, 
+                             HashKey hashedKey )
+{
+   JSON_ASSERT_MESSAGE( bucketsSize_ > 0, "ValueInternalMap::unsafeAdd(): internal logic error." );
+   BucketIndex bucketIndex = hashedKey % bucketsSize_;
+   ValueInternalLink *&previousLink = getLastLinkInBucket( bucketIndex );
+   ValueInternalLink *link = previousLink;
+   BucketIndex index;
+   for ( index =0; index < ValueInternalLink::itemPerLink; ++index )
+   {
+      if ( link->items_[index].isItemAvailable() )
+         break;
+   }
+   if ( index == ValueInternalLink::itemPerLink ) // need to add a new page
+   {
+      ValueInternalLink *newLink = mapAllocator()->allocateMapLink();
+      index = 0;
+      link->next_ = newLink;
+      previousLink = newLink;
+      link = newLink;
+   }
+   return setNewItem( key, isStatic, link, index );
+}
+
+
+ValueInternalMap::HashKey 
+ValueInternalMap::hash( const char *key ) const
+{
+   HashKey hash = 0;
+   while ( *key )
+      hash += *key++ * 37;
+   return hash;
+}
+
+
+int 
+ValueInternalMap::compare( const ValueInternalMap &other ) const
+{
+   int sizeDiff( itemCount_ - other.itemCount_ );
+   if ( sizeDiff != 0 )
+      return sizeDiff;
+   // Strict order guaranty is required. Compare all keys FIRST, then compare values.
+   IteratorState it;
+   IteratorState itEnd;
+   makeBeginIterator( it );
+   makeEndIterator( itEnd );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      if ( !other.find( key( it ) ) )
+         return 1;
+   }
+
+   // All keys are equals, let's compare values
+   makeBeginIterator( it );
+   for ( ; !equals(it,itEnd); increment(it) )
+   {
+      const Value *otherValue = other.find( key( it ) );
+      int valueDiff = value(it).compare( *otherValue );
+      if ( valueDiff != 0 )
+         return valueDiff;
+   }
+   return 0;
+}
+
+
+void 
+ValueInternalMap::makeBeginIterator( IteratorState &it ) const
+{
+   it.map_ = const_cast<ValueInternalMap *>( this );
+   it.bucketIndex_ = 0;
+   it.itemIndex_ = 0;
+   it.link_ = buckets_;
+}
+
+
+void 
+ValueInternalMap::makeEndIterator( IteratorState &it ) const
+{
+   it.map_ = const_cast<ValueInternalMap *>( this );
+   it.bucketIndex_ = bucketsSize_;
+   it.itemIndex_ = 0;
+   it.link_ = 0;
+}
+
+
+bool 
+ValueInternalMap::equals( const IteratorState &x, const IteratorState &other )
+{
+   return x.map_ == other.map_  
+          &&  x.bucketIndex_ == other.bucketIndex_  
+          &&  x.link_ == other.link_
+          &&  x.itemIndex_ == other.itemIndex_;
+}
+
+
+void 
+ValueInternalMap::incrementBucket( IteratorState &iterator )
+{
+   ++iterator.bucketIndex_;
+   JSON_ASSERT_MESSAGE( iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
+      "ValueInternalMap::increment(): attempting to iterate beyond end." );
+   if ( iterator.bucketIndex_ == iterator.map_->bucketsSize_ )
+      iterator.link_ = 0;
+   else
+      iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
+   iterator.itemIndex_ = 0;
+}
+
+
+void 
+ValueInternalMap::increment( IteratorState &iterator )
+{
+   JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterator using invalid iterator." );
+   ++iterator.itemIndex_;
+   if ( iterator.itemIndex_ == ValueInternalLink::itemPerLink )
+   {
+      JSON_ASSERT_MESSAGE( iterator.link_ != 0,
+         "ValueInternalMap::increment(): attempting to iterate beyond end." );
+      iterator.link_ = iterator.link_->next_;
+      if ( iterator.link_ == 0 )
+         incrementBucket( iterator );
+   }
+   else if ( iterator.link_->items_[iterator.itemIndex_].isItemAvailable() )
+   {
+      incrementBucket( iterator );
+   }
+}
+
+
+void 
+ValueInternalMap::decrement( IteratorState &iterator )
+{
+   if ( iterator.itemIndex_ == 0 )
+   {
+      JSON_ASSERT_MESSAGE( iterator.map_, "Attempting to iterate using invalid iterator." );
+      if ( iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_] )
+      {
+         JSON_ASSERT_MESSAGE( iterator.bucketIndex_ > 0, "Attempting to iterate beyond beginning." );
+         --(iterator.bucketIndex_);
+      }
+      iterator.link_ = iterator.link_->previous_;
+      iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
+   }
+}
+
+
+const char *
+ValueInternalMap::key( const IteratorState &iterator )
+{
+   JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
+   return iterator.link_->keys_[iterator.itemIndex_];
+}
+
+const char *
+ValueInternalMap::key( const IteratorState &iterator, bool &isStatic )
+{
+   JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
+   isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
+   return iterator.link_->keys_[iterator.itemIndex_];
+}
+
+
+Value &
+ValueInternalMap::value( const IteratorState &iterator )
+{
+   JSON_ASSERT_MESSAGE( iterator.link_, "Attempting to iterate using invalid iterator." );
+   return iterator.link_->items_[iterator.itemIndex_];
+}
+
+
+int 
+ValueInternalMap::distance( const IteratorState &x, const IteratorState &y )
+{
+   int offset = 0;
+   IteratorState it = x;
+   while ( !equals( it, y ) )
+      increment( it );
+   return offset;
+}
+
+} // namespace Json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/json_reader.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,912 @@
+// Copyright 2007-2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+# include <json/assertions.h>
+# include <json/reader.h>
+# include <json/value.h>
+# include "json_tool.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <utility>
+#include <cstdio>
+#include <cassert>
+#include <cstring>
+#include <iostream>
+#include <stdexcept>
+
+#if _MSC_VER >= 1400 // VC++ 8.0
+#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.
+#endif
+
+namespace Json {
+
+// Implementation of class Features
+// ////////////////////////////////
+
+Features::Features()
+   : allowComments_( true )
+   , strictRoot_( false )
+{
+}
+
+
+Features 
+Features::all()
+{
+   return Features();
+}
+
+
+Features 
+Features::strictMode()
+{
+   Features features;
+   features.allowComments_ = false;
+   features.strictRoot_ = true;
+   return features;
+}
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+
+static inline bool 
+in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4 )
+{
+   return c == c1  ||  c == c2  ||  c == c3  ||  c == c4;
+}
+
+static inline bool 
+in( Reader::Char c, Reader::Char c1, Reader::Char c2, Reader::Char c3, Reader::Char c4, Reader::Char c5 )
+{
+   return c == c1  ||  c == c2  ||  c == c3  ||  c == c4  ||  c == c5;
+}
+
+
+static bool 
+containsNewLine( Reader::Location begin, 
+                 Reader::Location end )
+{
+   for ( ;begin < end; ++begin )
+      if ( *begin == '\n'  ||  *begin == '\r' )
+         return true;
+   return false;
+}
+
+
+// Class Reader
+// //////////////////////////////////////////////////////////////////
+
+Reader::Reader()
+    : errors_(),
+      document_(),
+      begin_(),
+      end_(),
+      current_(),
+      lastValueEnd_(),
+      lastValue_(),
+      commentsBefore_(),
+      features_( Features::all() ),
+      collectComments_()
+{
+}
+
+
+Reader::Reader( const Features &features )
+    : errors_(),
+      document_(),
+      begin_(),
+      end_(),
+      current_(),
+      lastValueEnd_(),
+      lastValue_(),
+      commentsBefore_(),
+      features_( features ),
+      collectComments_()
+{
+}
+
+
+bool
+Reader::parse( const std::string &document, 
+               Value &root,
+               bool collectComments )
+{
+   document_ = document;
+   const char *begin = document_.c_str();
+   const char *end = begin + document_.length();
+   return parse( begin, end, root, collectComments );
+}
+
+
+bool
+Reader::parse( std::istream& sin,
+               Value &root,
+               bool collectComments )
+{
+   //std::istream_iterator<char> begin(sin);
+   //std::istream_iterator<char> end;
+   // Those would allow streamed input from a file, if parse() were a
+   // template function.
+
+   // Since std::string is reference-counted, this at least does not
+   // create an extra copy.
+   std::string doc;
+   std::getline(sin, doc, (char)EOF);
+   return parse( doc, root, collectComments );
+}
+
+bool 
+Reader::parse( const char *beginDoc, const char *endDoc, 
+               Value &root,
+               bool collectComments )
+{
+   if ( !features_.allowComments_ )
+   {
+      collectComments = false;
+   }
+
+   begin_ = beginDoc;
+   end_ = endDoc;
+   collectComments_ = collectComments;
+   current_ = begin_;
+   lastValueEnd_ = 0;
+   lastValue_ = 0;
+   commentsBefore_ = "";
+   errors_.clear();
+   while ( !nodes_.empty() )
+      nodes_.pop();
+   nodes_.push( &root );
+   
+   bool successful = readValue();
+   Token token;
+   skipCommentTokens( token );
+   if ( collectComments_  &&  !commentsBefore_.empty() )
+      root.setComment( commentsBefore_, commentAfter );
+   if ( features_.strictRoot_ )
+   {
+      if ( !root.isArray()  &&  !root.isObject() )
+      {
+         // Set error location to start of doc, ideally should be first token found in doc
+         token.type_ = tokenError;
+         token.start_ = beginDoc;
+         token.end_ = endDoc;
+         addError( "A valid JSON document must be either an array or an object value.",
+                   token );
+         return false;
+      }
+   }
+   return successful;
+}
+
+
+bool
+Reader::readValue()
+{
+   Token token;
+   skipCommentTokens( token );
+   bool successful = true;
+
+   if ( collectComments_  &&  !commentsBefore_.empty() )
+   {
+      currentValue().setComment( commentsBefore_, commentBefore );
+      commentsBefore_ = "";
+   }
+
+
+   switch ( token.type_ )
+   {
+   case tokenObjectBegin:
+      successful = readObject( token );
+      break;
+   case tokenArrayBegin:
+      successful = readArray( token );
+      break;
+   case tokenNumber:
+      successful = decodeNumber( token );
+      break;
+   case tokenString:
+      successful = decodeString( token );
+      break;
+   case tokenTrue:
+      currentValue() = true;
+      break;
+   case tokenFalse:
+      currentValue() = false;
+      break;
+   case tokenNull:
+      currentValue() = Value();
+      break;
+   default:
+      return addError( "Syntax error: value, object or array expected.", token );
+   }
+
+   if ( collectComments_ )
+   {
+      lastValueEnd_ = current_;
+      lastValue_ = &currentValue();
+   }
+
+   return successful;
+}
+
+
+void 
+Reader::skipCommentTokens( Token &token )
+{
+   if ( features_.allowComments_ )
+   {
+      do
+      {
+         readToken( token );
+      }
+      while ( token.type_ == tokenComment );
+   }
+   else
+   {
+      readToken( token );
+   }
+}
+
+
+bool 
+Reader::expectToken( TokenType type, Token &token, const char *message )
+{
+   readToken( token );
+   if ( token.type_ != type )
+      return addError( message, token );
+   return true;
+}
+
+
+bool 
+Reader::readToken( Token &token )
+{
+   skipSpaces();
+   token.start_ = current_;
+   Char c = getNextChar();
+   bool ok = true;
+   switch ( c )
+   {
+   case '{':
+      token.type_ = tokenObjectBegin;
+      break;
+   case '}':
+      token.type_ = tokenObjectEnd;
+      break;
+   case '[':
+      token.type_ = tokenArrayBegin;
+      break;
+   case ']':
+      token.type_ = tokenArrayEnd;
+      break;
+   case '"':
+      token.type_ = tokenString;
+      ok = readString();
+      break;
+   case '/':
+      token.type_ = tokenComment;
+      ok = readComment();
+      break;
+   case '0':
+   case '1':
+   case '2':
+   case '3':
+   case '4':
+   case '5':
+   case '6':
+   case '7':
+   case '8':
+   case '9':
+   case '-':
+      token.type_ = tokenNumber;
+      readNumber();
+      break;
+   case 't':
+      token.type_ = tokenTrue;
+      ok = match( "rue", 3 );
+      break;
+   case 'f':
+      token.type_ = tokenFalse;
+      ok = match( "alse", 4 );
+      break;
+   case 'n':
+      token.type_ = tokenNull;
+      ok = match( "ull", 3 );
+      break;
+   case ',':
+      token.type_ = tokenArraySeparator;
+      break;
+   case ':':
+      token.type_ = tokenMemberSeparator;
+      break;
+   case 0:
+      token.type_ = tokenEndOfStream;
+      break;
+   default:
+      ok = false;
+      break;
+   }
+   if ( !ok )
+      token.type_ = tokenError;
+   token.end_ = current_;
+   return true;
+}
+
+
+void 
+Reader::skipSpaces()
+{
+   while ( current_ != end_ )
+   {
+      Char c = *current_;
+      if ( c == ' '  ||  c == '\t'  ||  c == '\r'  ||  c == '\n' )
+         ++current_;
+      else
+         break;
+   }
+}
+
+
+bool 
+Reader::match( Location pattern, 
+               int patternLength )
+{
+   if ( end_ - current_ < patternLength )
+      return false;
+   int index = patternLength;
+   while ( index-- )
+      if ( current_[index] != pattern[index] )
+         return false;
+   current_ += patternLength;
+   return true;
+}
+
+
+bool
+Reader::readComment()
+{
+   Location commentBegin = current_ - 1;
+   Char c = getNextChar();
+   bool successful = false;
+   if ( c == '*' )
+      successful = readCStyleComment();
+   else if ( c == '/' )
+      successful = readCppStyleComment();
+   if ( !successful )
+      return false;
+
+   if ( collectComments_ )
+   {
+      CommentPlacement placement = commentBefore;
+      if ( lastValueEnd_  &&  !containsNewLine( lastValueEnd_, commentBegin ) )
+      {
+         if ( c != '*'  ||  !containsNewLine( commentBegin, current_ ) )
+            placement = commentAfterOnSameLine;
+      }
+
+      addComment( commentBegin, current_, placement );
+   }
+   return true;
+}
+
+
+void 
+Reader::addComment( Location begin, 
+                    Location end, 
+                    CommentPlacement placement )
+{
+   assert( collectComments_ );
+   if ( placement == commentAfterOnSameLine )
+   {
+      assert( lastValue_ != 0 );
+      lastValue_->setComment( std::string( begin, end ), placement );
+   }
+   else
+   {
+      if ( !commentsBefore_.empty() )
+         commentsBefore_ += "\n";
+      commentsBefore_ += std::string( begin, end );
+   }
+}
+
+
+bool 
+Reader::readCStyleComment()
+{
+   while ( current_ != end_ )
+   {
+      Char c = getNextChar();
+      if ( c == '*'  &&  *current_ == '/' )
+         break;
+   }
+   return getNextChar() == '/';
+}
+
+
+bool 
+Reader::readCppStyleComment()
+{
+   while ( current_ != end_ )
+   {
+      Char c = getNextChar();
+      if (  c == '\r'  ||  c == '\n' )
+         break;
+   }
+   return true;
+}
+
+
+void 
+Reader::readNumber()
+{
+   while ( current_ != end_ )
+   {
+      if ( !(*current_ >= '0'  &&  *current_ <= '9')  &&
+           !in( *current_, '.', 'e', 'E', '+', '-' ) )
+         break;
+      ++current_;
+   }
+}
+
+bool
+Reader::readString()
+{
+   Char c = 0;
+   while ( current_ != end_ )
+   {
+      c = getNextChar();
+      if ( c == '\\' )
+         getNextChar();
+      else if ( c == '"' )
+         break;
+   }
+   return c == '"';
+}
+
+
+bool 
+Reader::readObject( Token &/*tokenStart*/ )
+{
+   Token tokenName;
+   std::string name;
+   currentValue() = Value( objectValue );
+   while ( readToken( tokenName ) )
+   {
+      bool initialTokenOk = true;
+      while ( tokenName.type_ == tokenComment  &&  initialTokenOk )
+         initialTokenOk = readToken( tokenName );
+      if  ( !initialTokenOk )
+         break;
+      if ( tokenName.type_ == tokenObjectEnd  &&  name.empty() )  // empty object
+         return true;
+      if ( tokenName.type_ != tokenString )
+         break;
+      
+      name = "";
+      if ( !decodeString( tokenName, name ) )
+         return recoverFromError( tokenObjectEnd );
+
+      Token colon;
+      if ( !readToken( colon ) ||  colon.type_ != tokenMemberSeparator )
+      {
+         return addErrorAndRecover( "Missing ':' after object member name", 
+                                    colon, 
+                                    tokenObjectEnd );
+      }
+      Value &value = currentValue()[ name ];
+      nodes_.push( &value );
+      bool ok = readValue();
+      nodes_.pop();
+      if ( !ok ) // error already set
+         return recoverFromError( tokenObjectEnd );
+
+      Token comma;
+      if ( !readToken( comma )
+            ||  ( comma.type_ != tokenObjectEnd  &&  
+                  comma.type_ != tokenArraySeparator &&
+                  comma.type_ != tokenComment ) )
+      {
+         return addErrorAndRecover( "Missing ',' or '}' in object declaration", 
+                                    comma, 
+                                    tokenObjectEnd );
+      }
+      bool finalizeTokenOk = true;
+      while ( comma.type_ == tokenComment &&
+              finalizeTokenOk )
+         finalizeTokenOk = readToken( comma );
+      if ( comma.type_ == tokenObjectEnd )
+         return true;
+   }
+   return addErrorAndRecover( "Missing '}' or object member name", 
+                              tokenName, 
+                              tokenObjectEnd );
+}
+
+
+bool 
+Reader::readArray( Token &/*tokenStart*/ )
+{
+   currentValue() = Value( arrayValue );
+   skipSpaces();
+   if ( *current_ == ']' ) // empty array
+   {
+      Token endArray;
+      readToken( endArray );
+      return true;
+   }
+   int index = 0;
+   for (;;)
+   {
+      Value &value = currentValue()[ index++ ];
+      nodes_.push( &value );
+      bool ok = readValue();
+      nodes_.pop();
+      if ( !ok ) // error already set
+         return recoverFromError( tokenArrayEnd );
+
+      Token token;
+      // Accept Comment after last item in the array.
+      ok = readToken( token );
+      while ( token.type_ == tokenComment  &&  ok )
+      {
+         ok = readToken( token );
+      }
+      bool badTokenType = ( token.type_ != tokenArraySeparator  &&
+                            token.type_ != tokenArrayEnd );
+      if ( !ok  ||  badTokenType )
+      {
+         return addErrorAndRecover( "Missing ',' or ']' in array declaration", 
+                                    token, 
+                                    tokenArrayEnd );
+      }
+      if ( token.type_ == tokenArrayEnd )
+         break;
+   }
+   return true;
+}
+
+
+bool 
+Reader::decodeNumber( Token &token )
+{
+   bool isDouble = false;
+   for ( Location inspect = token.start_; inspect != token.end_; ++inspect )
+   {
+      isDouble = isDouble  
+                 ||  in( *inspect, '.', 'e', 'E', '+' )  
+                 ||  ( *inspect == '-'  &&  inspect != token.start_ );
+   }
+   if ( isDouble )
+      return decodeDouble( token );
+   // Attempts to parse the number as an integer. If the number is
+   // larger than the maximum supported value of an integer then
+   // we decode the number as a double.
+   Location current = token.start_;
+   bool isNegative = *current == '-';
+   if ( isNegative )
+      ++current;
+   Value::LargestUInt maxIntegerValue = isNegative ? Value::LargestUInt(-Value::minLargestInt) 
+                                                   : Value::maxLargestUInt;
+   Value::LargestUInt threshold = maxIntegerValue / 10;
+   Value::LargestUInt value = 0;
+   while ( current < token.end_ )
+   {
+      Char c = *current++;
+      if ( c < '0'  ||  c > '9' )
+         return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
+      Value::UInt digit(c - '0');
+      if ( value >= threshold )
+      {
+         // We've hit or exceeded the max value divided by 10 (rounded down). If
+         // a) we've only just touched the limit, b) this is the last digit, and
+         // c) it's small enough to fit in that rounding delta, we're okay.
+         // Otherwise treat this number as a double to avoid overflow.
+         if (value > threshold ||
+             current != token.end_ ||
+             digit > maxIntegerValue % 10)
+         {
+            return decodeDouble( token );
+         }
+      }
+      value = value * 10 + digit;
+   }
+   if ( isNegative )
+      currentValue() = -Value::LargestInt( value );
+   else if ( value <= Value::LargestUInt(Value::maxInt) )
+      currentValue() = Value::LargestInt( value );
+   else
+      currentValue() = value;
+   return true;
+}
+
+
+bool 
+Reader::decodeDouble( Token &token )
+{
+   double value = 0;
+   const int bufferSize = 32;
+   int count;
+   int length = int(token.end_ - token.start_);
+
+   // Sanity check to avoid buffer overflow exploits.
+   if (length < 0) {
+      return addError( "Unable to parse token length", token );
+   }
+
+   // Avoid using a string constant for the format control string given to
+   // sscanf, as this can cause hard to debug crashes on OS X. See here for more
+   // info:
+   //
+   //     http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
+   char format[] = "%lf";
+
+   if ( length <= bufferSize )
+   {
+      Char buffer[bufferSize+1];
+      memcpy( buffer, token.start_, length );
+      buffer[length] = 0;
+      count = sscanf( buffer, format, &value );
+   }
+   else
+   {
+      std::string buffer( token.start_, token.end_ );
+      count = sscanf( buffer.c_str(), format, &value );
+   }
+
+   if ( count != 1 )
+      return addError( "'" + std::string( token.start_, token.end_ ) + "' is not a number.", token );
+   currentValue() = value;
+   return true;
+}
+
+
+bool 
+Reader::decodeString( Token &token )
+{
+   std::string decoded;
+   if ( !decodeString( token, decoded ) )
+      return false;
+   currentValue() = decoded;
+   return true;
+}
+
+
+bool 
+Reader::decodeString( Token &token, std::string &decoded )
+{
+   decoded.reserve( token.end_ - token.start_ - 2 );
+   Location current = token.start_ + 1; // skip '"'
+   Location end = token.end_ - 1;      // do not include '"'
+   while ( current != end )
+   {
+      Char c = *current++;
+      if ( c == '"' )
+         break;
+      else if ( c == '\\' )
+      {
+         if ( current == end )
+            return addError( "Empty escape sequence in string", token, current );
+         Char escape = *current++;
+         switch ( escape )
+         {
+         case '"': decoded += '"'; break;
+         case '/': decoded += '/'; break;
+         case '\\': decoded += '\\'; break;
+         case 'b': decoded += '\b'; break;
+         case 'f': decoded += '\f'; break;
+         case 'n': decoded += '\n'; break;
+         case 'r': decoded += '\r'; break;
+         case 't': decoded += '\t'; break;
+         case 'u':
+            {
+               unsigned int unicode;
+               if ( !decodeUnicodeCodePoint( token, current, end, unicode ) )
+                  return false;
+               decoded += codePointToUTF8(unicode);
+            }
+            break;
+         default:
+            return addError( "Bad escape sequence in string", token, current );
+         }
+      }
+      else
+      {
+         decoded += c;
+      }
+   }
+   return true;
+}
+
+bool
+Reader::decodeUnicodeCodePoint( Token &token, 
+                                     Location &current, 
+                                     Location end, 
+                                     unsigned int &unicode )
+{
+
+   if ( !decodeUnicodeEscapeSequence( token, current, end, unicode ) )
+      return false;
+   if (unicode >= 0xD800 && unicode <= 0xDBFF)
+   {
+      // surrogate pairs
+      if (end - current < 6)
+         return addError( "additional six characters expected to parse unicode surrogate pair.", token, current );
+      unsigned int surrogatePair;
+      if (*(current++) == '\\' && *(current++)== 'u')
+      {
+         if (decodeUnicodeEscapeSequence( token, current, end, surrogatePair ))
+         {
+            unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+         } 
+         else
+            return false;
+      } 
+      else
+         return addError( "expecting another \\u token to begin the second half of a unicode surrogate pair", token, current );
+   }
+   return true;
+}
+
+bool 
+Reader::decodeUnicodeEscapeSequence( Token &token, 
+                                     Location &current, 
+                                     Location end, 
+                                     unsigned int &unicode )
+{
+   if ( end - current < 4 )
+      return addError( "Bad unicode escape sequence in string: four digits expected.", token, current );
+   unicode = 0;
+   for ( int index =0; index < 4; ++index )
+   {
+      Char c = *current++;
+      unicode *= 16;
+      if ( c >= '0'  &&  c <= '9' )
+         unicode += c - '0';
+      else if ( c >= 'a'  &&  c <= 'f' )
+         unicode += c - 'a' + 10;
+      else if ( c >= 'A'  &&  c <= 'F' )
+         unicode += c - 'A' + 10;
+      else
+         return addError( "Bad unicode escape sequence in string: hexadecimal digit expected.", token, current );
+   }
+   return true;
+}
+
+
+bool 
+Reader::addError( const std::string &message, 
+                  Token &token,
+                  Location extra )
+{
+   ErrorInfo info;
+   info.token_ = token;
+   info.message_ = message;
+   info.extra_ = extra;
+   errors_.push_back( info );
+   return false;
+}
+
+
+bool 
+Reader::recoverFromError( TokenType skipUntilToken )
+{
+   int errorCount = int(errors_.size());
+   Token skip;
+   for (;;)
+   {
+      if ( !readToken(skip) )
+         errors_.resize( errorCount ); // discard errors caused by recovery
+      if ( skip.type_ == skipUntilToken  ||  skip.type_ == tokenEndOfStream )
+         break;
+   }
+   errors_.resize( errorCount );
+   return false;
+}
+
+
+bool 
+Reader::addErrorAndRecover( const std::string &message, 
+                            Token &token,
+                            TokenType skipUntilToken )
+{
+   addError( message, token );
+   return recoverFromError( skipUntilToken );
+}
+
+
+Value &
+Reader::currentValue()
+{
+   return *(nodes_.top());
+}
+
+
+Reader::Char 
+Reader::getNextChar()
+{
+   if ( current_ == end_ )
+      return 0;
+   return *current_++;
+}
+
+
+void 
+Reader::getLocationLineAndColumn( Location location,
+                                  int &line,
+                                  int &column ) const
+{
+   Location current = begin_;
+   Location lastLineStart = current;
+   line = 0;
+   while ( current < location  &&  current != end_ )
+   {
+      Char c = *current++;
+      if ( c == '\r' )
+      {
+         if ( *current == '\n' )
+            ++current;
+         lastLineStart = current;
+         ++line;
+      }
+      else if ( c == '\n' )
+      {
+         lastLineStart = current;
+         ++line;
+      }
+   }
+   // column & line start at 1
+   column = int(location - lastLineStart) + 1;
+   ++line;
+}
+
+
+std::string
+Reader::getLocationLineAndColumn( Location location ) const
+{
+   int line, column;
+   getLocationLineAndColumn( location, line, column );
+   char buffer[18+16+16+1];
+   sprintf( buffer, "Line %d, Column %d", line, column );
+   return buffer;
+}
+
+
+// Deprecated. Preserved for backward compatibility
+std::string 
+Reader::getFormatedErrorMessages() const
+{
+    return getFormattedErrorMessages();
+}
+
+
+std::string 
+Reader::getFormattedErrorMessages() const
+{
+   std::string formattedMessage;
+   for ( Errors::const_iterator itError = errors_.begin();
+         itError != errors_.end();
+         ++itError )
+   {
+      const ErrorInfo &error = *itError;
+      formattedMessage += "* " + getLocationLineAndColumn( error.token_.start_ ) + "\n";
+      formattedMessage += "  " + error.message_ + "\n";
+      if ( error.extra_ )
+         formattedMessage += "See " + getLocationLineAndColumn( error.extra_ ) + " for detail.\n";
+   }
+   return formattedMessage;
+}
+
+
+std::istream& operator>>( std::istream &sin, Value &root )
+{
+    Json::Reader reader;
+    bool ok = reader.parse(sin, root, true);
+    if (!ok) JSON_FAIL_MESSAGE(reader.getFormattedErrorMessages());
+    return sin;
+}
+
+
+} // namespace Json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/json_tool.h	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,93 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+# define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+
+/* This header provides common string manipulation support, such as UTF-8,
+ * portable conversion from/to string...
+ *
+ * It is an internal header that must not be exposed.
+ */
+
+namespace Json {
+
+/// Converts a unicode code-point to UTF-8.
+static inline std::string 
+codePointToUTF8(unsigned int cp)
+{
+   std::string result;
+   
+   // based on description from http://en.wikipedia.org/wiki/UTF-8
+
+   if (cp <= 0x7f) 
+   {
+      result.resize(1);
+      result[0] = static_cast<char>(cp);
+   } 
+   else if (cp <= 0x7FF) 
+   {
+      result.resize(2);
+      result[1] = static_cast<char>(0x80 | (0x3f & cp));
+      result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
+   } 
+   else if (cp <= 0xFFFF) 
+   {
+      result.resize(3);
+      result[2] = static_cast<char>(0x80 | (0x3f & cp));
+      result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
+      result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
+   }
+   else if (cp <= 0x10FFFF) 
+   {
+      result.resize(4);
+      result[3] = static_cast<char>(0x80 | (0x3f & cp));
+      result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
+      result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
+      result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
+   }
+
+   return result;
+}
+
+
+/// Returns true if ch is a control character (in range [0,32[).
+static inline bool 
+isControlCharacter(char ch)
+{
+   return ch > 0 && ch <= 0x1F;
+}
+
+
+enum { 
+   /// Constant that specify the size of the buffer that must be passed to uintToString.
+   uintToStringBufferSize = 3*sizeof(LargestUInt)+1 
+};
+
+// Defines a char buffer for use with uintToString().
+typedef char UIntToStringBuffer[uintToStringBufferSize];
+
+
+/** Converts an unsigned integer to string.
+ * @param value Unsigned interger to convert to string
+ * @param current Input/Output string buffer. 
+ *        Must have at least uintToStringBufferSize chars free.
+ */
+static inline void 
+uintToString( LargestUInt value, 
+              char *&current )
+{
+   *--current = 0;
+   do
+   {
+      *--current = char(value % 10) + '0';
+      value /= 10;
+   }
+   while ( value != 0 );
+}
+
+} // namespace Json {
+
+#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/json_value.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,1921 @@
+// Copyright 2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+# include <json/assertions.h>
+# include <json/value.h>
+# include <json/writer.h>
+# ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+#  include "json_batchallocator.h"
+# endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <math.h>
+#include <iostream>
+#include <sstream>
+#include <utility>
+#include <stdexcept>
+#include <cstring>
+#include <cassert>
+#ifdef JSON_USE_CPPTL
+# include <cpptl/conststring.h>
+#endif
+#include <cstddef>    // size_t
+
+#define JSON_ASSERT_UNREACHABLE assert( false )
+
+namespace Json {
+
+const Value Value::null;
+const Int Value::minInt = Int( ~(UInt(-1)/2) );
+const Int Value::maxInt = Int( UInt(-1)/2 );
+const UInt Value::maxUInt = UInt(-1);
+# if defined(JSON_HAS_INT64)
+const Int64 Value::minInt64 = Int64( ~(UInt64(-1)/2) );
+const Int64 Value::maxInt64 = Int64( UInt64(-1)/2 );
+const UInt64 Value::maxUInt64 = UInt64(-1);
+// The constant is hard-coded because some compiler have trouble
+// converting Value::maxUInt64 to a double correctly (AIX/xlC).
+// Assumes that UInt64 is a 64 bits integer.
+static const double maxUInt64AsDouble = 18446744073709551615.0;
+#endif // defined(JSON_HAS_INT64)
+const LargestInt Value::minLargestInt = LargestInt( ~(LargestUInt(-1)/2) );
+const LargestInt Value::maxLargestInt = LargestInt( LargestUInt(-1)/2 );
+const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
+
+
+/// Unknown size marker
+static const unsigned int unknown = (unsigned)-1;
+
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+template <typename T, typename U>
+static inline bool InRange(double d, T min, U max) {
+   return d >= min && d <= max;
+}
+#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+static inline double integerToDouble( Json::UInt64 value )
+{
+    return static_cast<double>( Int64(value/2) ) * 2.0 + Int64(value & 1);
+}
+
+template<typename T>
+static inline double integerToDouble( T value )
+{
+    return static_cast<double>( value );
+}
+
+template <typename T, typename U>
+static inline bool InRange(double d, T min, U max) {
+   return d >= integerToDouble(min) && d <= integerToDouble(max);
+}
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+
+
+/** Duplicates the specified string value.
+ * @param value Pointer to the string to duplicate. Must be zero-terminated if
+ *              length is "unknown".
+ * @param length Length of the value. if equals to unknown, then it will be
+ *               computed using strlen(value).
+ * @return Pointer on the duplicate instance of string.
+ */
+static inline char *
+duplicateStringValue( const char *value, 
+                      unsigned int length = unknown )
+{
+   if ( length == unknown )
+      length = (unsigned int)strlen(value);
+
+   // Avoid an integer overflow in the call to malloc below by limiting length
+   // to a sane value.
+   if (length >= (unsigned)Value::maxInt)
+      length = Value::maxInt - 1;
+
+   char *newString = static_cast<char *>( malloc( length + 1 ) );
+   JSON_ASSERT_MESSAGE( newString != 0, "Failed to allocate string value buffer" );
+   memcpy( newString, value, length );
+   newString[length] = 0;
+   return newString;
+}
+
+
+/** Free the string duplicated by duplicateStringValue().
+ */
+static inline void 
+releaseStringValue( char *value )
+{
+   if ( value )
+      free( value );
+}
+
+} // namespace Json
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// ValueInternals...
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+#if !defined(JSON_IS_AMALGAMATION)
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+#  include "json_internalarray.inl"
+#  include "json_internalmap.inl"
+# endif // JSON_VALUE_USE_INTERNAL_MAP
+
+# include "json_valueiterator.inl"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CommentInfo
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+
+Value::CommentInfo::CommentInfo()
+   : comment_( 0 )
+{
+}
+
+Value::CommentInfo::~CommentInfo()
+{
+   if ( comment_ )
+      releaseStringValue( comment_ );
+}
+
+
+void 
+Value::CommentInfo::setComment( const char *text )
+{
+   if ( comment_ )
+      releaseStringValue( comment_ );
+   JSON_ASSERT( text != 0 );
+   JSON_ASSERT_MESSAGE( text[0]=='\0' || text[0]=='/', "Comments must start with /");
+   // It seems that /**/ style comments are acceptable as well.
+   comment_ = duplicateStringValue( text );
+}
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CZString
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+# ifndef JSON_VALUE_USE_INTERNAL_MAP
+
+// Notes: index_ indicates if the string was allocated when
+// a string is stored.
+
+Value::CZString::CZString( ArrayIndex index )
+   : cstr_( 0 )
+   , index_( index )
+{
+}
+
+Value::CZString::CZString( const char *cstr, DuplicationPolicy allocate )
+   : cstr_( allocate == duplicate ? duplicateStringValue(cstr) 
+                                  : cstr )
+   , index_( allocate )
+{
+}
+
+Value::CZString::CZString( const CZString &other )
+: cstr_( other.index_ != noDuplication &&  other.cstr_ != 0
+                ?  duplicateStringValue( other.cstr_ )
+                : other.cstr_ )
+   , index_( other.cstr_ ? (other.index_ == noDuplication ? noDuplication : duplicate)
+                         : other.index_ )
+{
+}
+
+Value::CZString::~CZString()
+{
+   if ( cstr_  &&  index_ == duplicate )
+      releaseStringValue( const_cast<char *>( cstr_ ) );
+}
+
+void 
+Value::CZString::swap( CZString &other )
+{
+   std::swap( cstr_, other.cstr_ );
+   std::swap( index_, other.index_ );
+}
+
+Value::CZString &
+Value::CZString::operator =( const CZString &other )
+{
+   CZString temp( other );
+   swap( temp );
+   return *this;
+}
+
+bool 
+Value::CZString::operator<( const CZString &other ) const 
+{
+   if ( cstr_ )
+      return strcmp( cstr_, other.cstr_ ) < 0;
+   return index_ < other.index_;
+}
+
+bool 
+Value::CZString::operator==( const CZString &other ) const 
+{
+   if ( cstr_ )
+      return strcmp( cstr_, other.cstr_ ) == 0;
+   return index_ == other.index_;
+}
+
+
+ArrayIndex 
+Value::CZString::index() const
+{
+   return index_;
+}
+
+
+const char *
+Value::CZString::c_str() const
+{
+   return cstr_;
+}
+
+bool 
+Value::CZString::isStaticString() const
+{
+   return index_ == noDuplication;
+}
+
+#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::Value
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/*! \internal Default constructor initialization must be equivalent to:
+ * memset( this, 0, sizeof(Value) )
+ * This optimization is used in ValueInternalMap fast allocator.
+ */
+Value::Value( ValueType type )
+   : type_( type )
+   , allocated_( false )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+   , comments_( 0 )
+{
+   switch ( type )
+   {
+   case nullValue:
+      break;
+   case intValue:
+   case uintValue:
+      value_.int_ = 0;
+      break;
+   case realValue:
+      value_.real_ = 0.0;
+      break;
+   case stringValue:
+      value_.string_ = 0;
+      break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+   case objectValue:
+      value_.map_ = new ObjectValues();
+      break;
+#else
+   case arrayValue:
+      value_.array_ = arrayAllocator()->newArray();
+      break;
+   case objectValue:
+      value_.map_ = mapAllocator()->newMap();
+      break;
+#endif
+   case booleanValue:
+      value_.bool_ = false;
+      break;
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+}
+
+
+Value::Value( UInt value )
+   : type_( uintValue )
+   , allocated_( false )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+   , comments_( 0 )
+{
+   value_.uint_ = value;
+}
+
+Value::Value( Int value )
+   : type_( intValue )
+   , allocated_( false )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+   , comments_( 0 )
+{
+   value_.int_ = value;
+}
+
+
+# if defined(JSON_HAS_INT64)
+Value::Value( Int64 value )
+   : type_( intValue )
+   , allocated_( false )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+   , comments_( 0 )
+{
+   value_.int_ = value;
+}
+
+
+Value::Value( UInt64 value )
+   : type_( uintValue )
+   , allocated_( false )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+   , comments_( 0 )
+{
+   value_.uint_ = value;
+}
+#endif // defined(JSON_HAS_INT64)
+
+Value::Value( double value )
+   : type_( realValue )
+   , allocated_( false )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+   , comments_( 0 )
+{
+   value_.real_ = value;
+}
+
+Value::Value( const char *value )
+   : type_( stringValue )
+   , allocated_( true )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+   , comments_( 0 )
+{
+   value_.string_ = duplicateStringValue( value );
+}
+
+
+Value::Value( const char *beginValue, 
+              const char *endValue )
+   : type_( stringValue )
+   , allocated_( true )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+   , comments_( 0 )
+{
+   value_.string_ = duplicateStringValue( beginValue, 
+                                          (unsigned int)(endValue - beginValue) );
+}
+
+
+Value::Value( const std::string &value )
+   : type_( stringValue )
+   , allocated_( true )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+   , comments_( 0 )
+{
+   value_.string_ = duplicateStringValue( value.c_str(), 
+                                          (unsigned int)value.length() );
+
+}
+
+Value::Value( const StaticString &value )
+   : type_( stringValue )
+   , allocated_( false )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+   , comments_( 0 )
+{
+   value_.string_ = const_cast<char *>( value.c_str() );
+}
+
+
+# ifdef JSON_USE_CPPTL
+Value::Value( const CppTL::ConstString &value )
+   : type_( stringValue )
+   , allocated_( true )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+   , comments_( 0 )
+{
+   value_.string_ = duplicateStringValue( value, value.length() );
+}
+# endif
+
+Value::Value( bool value )
+   : type_( booleanValue )
+   , allocated_( false )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+   , comments_( 0 )
+{
+   value_.bool_ = value;
+}
+
+
+Value::Value( const Value &other )
+   : type_( other.type_ )
+   , allocated_( false )
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+   , itemIsUsed_( 0 )
+#endif
+   , comments_( 0 )
+{
+   switch ( type_ )
+   {
+   case nullValue:
+   case intValue:
+   case uintValue:
+   case realValue:
+   case booleanValue:
+      value_ = other.value_;
+      break;
+   case stringValue:
+      if ( other.value_.string_ )
+      {
+         value_.string_ = duplicateStringValue( other.value_.string_ );
+         allocated_ = true;
+      }
+      else
+         value_.string_ = 0;
+      break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+   case objectValue:
+      value_.map_ = new ObjectValues( *other.value_.map_ );
+      break;
+#else
+   case arrayValue:
+      value_.array_ = arrayAllocator()->newArrayCopy( *other.value_.array_ );
+      break;
+   case objectValue:
+      value_.map_ = mapAllocator()->newMapCopy( *other.value_.map_ );
+      break;
+#endif
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   if ( other.comments_ )
+   {
+      comments_ = new CommentInfo[numberOfCommentPlacement];
+      for ( int comment =0; comment < numberOfCommentPlacement; ++comment )
+      {
+         const CommentInfo &otherComment = other.comments_[comment];
+         if ( otherComment.comment_ )
+            comments_[comment].setComment( otherComment.comment_ );
+      }
+   }
+}
+
+
+Value::~Value()
+{
+   switch ( type_ )
+   {
+   case nullValue:
+   case intValue:
+   case uintValue:
+   case realValue:
+   case booleanValue:
+      break;
+   case stringValue:
+      if ( allocated_ )
+         releaseStringValue( value_.string_ );
+      break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+   case objectValue:
+      delete value_.map_;
+      break;
+#else
+   case arrayValue:
+      arrayAllocator()->destructArray( value_.array_ );
+      break;
+   case objectValue:
+      mapAllocator()->destructMap( value_.map_ );
+      break;
+#endif
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+
+   if ( comments_ )
+      delete[] comments_;
+}
+
+Value &
+Value::operator=( const Value &other )
+{
+   Value temp( other );
+   swap( temp );
+   return *this;
+}
+
+void 
+Value::swap( Value &other )
+{
+   ValueType temp = type_;
+   type_ = other.type_;
+   other.type_ = temp;
+   std::swap( value_, other.value_ );
+   int temp2 = allocated_;
+   allocated_ = other.allocated_;
+   other.allocated_ = temp2;
+}
+
+ValueType 
+Value::type() const
+{
+   return type_;
+}
+
+
+int 
+Value::compare( const Value &other ) const
+{
+   if ( *this < other )
+      return -1;
+   if ( *this > other )
+      return 1;
+   return 0;
+}
+
+
+bool 
+Value::operator <( const Value &other ) const
+{
+   int typeDelta = type_ - other.type_;
+   if ( typeDelta )
+      return typeDelta < 0 ? true : false;
+   switch ( type_ )
+   {
+   case nullValue:
+      return false;
+   case intValue:
+      return value_.int_ < other.value_.int_;
+   case uintValue:
+      return value_.uint_ < other.value_.uint_;
+   case realValue:
+      return value_.real_ < other.value_.real_;
+   case booleanValue:
+      return value_.bool_ < other.value_.bool_;
+   case stringValue:
+      return ( value_.string_ == 0  &&  other.value_.string_ )
+             || ( other.value_.string_  
+                  &&  value_.string_  
+                  && strcmp( value_.string_, other.value_.string_ ) < 0 );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+   case objectValue:
+      {
+         int delta = int( value_.map_->size() - other.value_.map_->size() );
+         if ( delta )
+            return delta < 0;
+         return (*value_.map_) < (*other.value_.map_);
+      }
+#else
+   case arrayValue:
+      return value_.array_->compare( *(other.value_.array_) ) < 0;
+   case objectValue:
+      return value_.map_->compare( *(other.value_.map_) ) < 0;
+#endif
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   return false;  // unreachable
+}
+
+bool 
+Value::operator <=( const Value &other ) const
+{
+   return !(other < *this);
+}
+
+bool 
+Value::operator >=( const Value &other ) const
+{
+   return !(*this < other);
+}
+
+bool 
+Value::operator >( const Value &other ) const
+{
+   return other < *this;
+}
+
+bool 
+Value::operator ==( const Value &other ) const
+{
+   //if ( type_ != other.type_ )
+   // GCC 2.95.3 says:
+   // attempt to take address of bit-field structure member `Json::Value::type_'
+   // Beats me, but a temp solves the problem.
+   int temp = other.type_;
+   if ( type_ != temp )
+      return false;
+   switch ( type_ )
+   {
+   case nullValue:
+      return true;
+   case intValue:
+      return value_.int_ == other.value_.int_;
+   case uintValue:
+      return value_.uint_ == other.value_.uint_;
+   case realValue:
+      return value_.real_ == other.value_.real_;
+   case booleanValue:
+      return value_.bool_ == other.value_.bool_;
+   case stringValue:
+      return ( value_.string_ == other.value_.string_ )
+             || ( other.value_.string_  
+                  &&  value_.string_  
+                  && strcmp( value_.string_, other.value_.string_ ) == 0 );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+   case objectValue:
+      return value_.map_->size() == other.value_.map_->size()
+             && (*value_.map_) == (*other.value_.map_);
+#else
+   case arrayValue:
+      return value_.array_->compare( *(other.value_.array_) ) == 0;
+   case objectValue:
+      return value_.map_->compare( *(other.value_.map_) ) == 0;
+#endif
+   default:
+      JSON_ASSERT_UNREACHABLE;
+   }
+   return false;  // unreachable
+}
+
+bool 
+Value::operator !=( const Value &other ) const
+{
+   return !( *this == other );
+}
+
+const char *
+Value::asCString() const
+{
+   JSON_ASSERT( type_ == stringValue );
+   return value_.string_;
+}
+
+
+std::string 
+Value::asString() const
+{
+   switch ( type_ )
+   {
+   case nullValue:
+      return "";
+   case stringValue:
+      return value_.string_ ? value_.string_ : "";
+   case booleanValue:
+      return value_.bool_ ? "true" : "false";
+   case intValue:
+      return valueToString( value_.int_ );
+   case uintValue:
+      return valueToString( value_.uint_ );
+   case realValue:
+      return valueToString( value_.real_ );
+   default:
+      JSON_FAIL_MESSAGE( "Type is not convertible to string" );
+   }
+}
+
+# ifdef JSON_USE_CPPTL
+CppTL::ConstString 
+Value::asConstString() const
+{
+   return CppTL::ConstString( asString().c_str() );
+}
+# endif
+
+
+Value::Int 
+Value::asInt() const
+{
+   switch ( type_ )
+   {
+   case intValue:
+      JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
+      return Int(value_.int_);
+   case uintValue:
+      JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
+      return Int(value_.uint_);
+   case realValue:
+      JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt), "double out of Int range");
+      return Int(value_.real_);
+   case nullValue:
+      return 0;
+   case booleanValue:
+      return value_.bool_ ? 1 : 0;
+   default:
+      break;
+   }
+   JSON_FAIL_MESSAGE("Value is not convertible to Int.");
+}
+
+
+Value::UInt 
+Value::asUInt() const
+{
+   switch ( type_ )
+   {
+   case intValue:
+      JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
+      return UInt(value_.int_);
+   case uintValue:
+      JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
+      return UInt(value_.uint_);
+   case realValue:
+      JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt), "double out of UInt range");
+      return UInt( value_.real_ );
+   case nullValue:
+      return 0;
+   case booleanValue:
+      return value_.bool_ ? 1 : 0;
+   default:
+      break;
+   }
+   JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
+}
+
+
+# if defined(JSON_HAS_INT64)
+
+Value::Int64
+Value::asInt64() const
+{
+   switch ( type_ )
+   {
+   case intValue:
+      return Int64(value_.int_);
+   case uintValue:
+      JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
+      return Int64(value_.uint_);
+   case realValue:
+      JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64), "double out of Int64 range");
+      return Int64(value_.real_);
+   case nullValue:
+      return 0;
+   case booleanValue:
+      return value_.bool_ ? 1 : 0;
+   default:
+      break;
+   }
+   JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
+}
+
+
+Value::UInt64
+Value::asUInt64() const
+{
+   switch ( type_ )
+   {
+   case intValue:
+      JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
+      return UInt64(value_.int_);
+   case uintValue:
+      return UInt64(value_.uint_);
+   case realValue:
+      JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64), "double out of UInt64 range");
+      return UInt64( value_.real_ );
+   case nullValue:
+      return 0;
+   case booleanValue:
+      return value_.bool_ ? 1 : 0;
+   default:
+      break;
+   }
+   JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
+}
+# endif // if defined(JSON_HAS_INT64)
+
+
+LargestInt 
+Value::asLargestInt() const
+{
+#if defined(JSON_NO_INT64)
+    return asInt();
+#else
+    return asInt64();
+#endif
+}
+
+
+LargestUInt 
+Value::asLargestUInt() const
+{
+#if defined(JSON_NO_INT64)
+    return asUInt();
+#else
+    return asUInt64();
+#endif
+}
+
+
+double 
+Value::asDouble() const
+{
+   switch ( type_ )
+   {
+   case intValue:
+      return static_cast<double>( value_.int_ );
+   case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+      return static_cast<double>( value_.uint_ );
+#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+      return integerToDouble( value_.uint_ );
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+   case realValue:
+      return value_.real_;
+   case nullValue:
+      return 0.0;
+   case booleanValue:
+      return value_.bool_ ? 1.0 : 0.0;
+   default:
+      break;
+   }
+   JSON_FAIL_MESSAGE("Value is not convertible to double.");
+}
+
+float
+Value::asFloat() const
+{
+   switch ( type_ )
+   {
+   case intValue:
+      return static_cast<float>( value_.int_ );
+   case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+      return static_cast<float>( value_.uint_ );
+#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+      return integerToDouble( value_.uint_ );
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+   case realValue:
+      return static_cast<float>( value_.real_ );
+   case nullValue:
+      return 0.0;
+   case booleanValue:
+      return value_.bool_ ? 1.0f : 0.0f;
+   default:
+      break;
+   }
+   JSON_FAIL_MESSAGE("Value is not convertible to float.");
+}
+
+bool 
+Value::asBool() const
+{
+   switch ( type_ )
+   {
+   case booleanValue:
+      return value_.bool_;
+   case nullValue:
+      return false;
+   case intValue:
+      return value_.int_ ? true : false;
+   case uintValue:
+      return value_.uint_ ? true : false;
+   case realValue:
+      return value_.real_ ? true : false;
+   default:
+      break;
+   }
+   JSON_FAIL_MESSAGE("Value is not convertible to bool.");
+}
+
+
+bool 
+Value::isConvertibleTo( ValueType other ) const
+{
+   switch ( other )
+   {
+   case nullValue:
+      return ( isNumeric() && asDouble() == 0.0 )
+             || ( type_ == booleanValue && value_.bool_ == false )
+             || ( type_ == stringValue && asString() == "" )
+             || ( type_ == arrayValue && value_.map_->size() == 0 )
+             || ( type_ == objectValue && value_.map_->size() == 0 )
+             || type_ == nullValue;
+   case intValue:
+      return isInt()
+             || (type_ == realValue && InRange(value_.real_, minInt, maxInt))
+             || type_ == booleanValue
+             || type_ == nullValue;
+   case uintValue:
+      return isUInt()
+             || (type_ == realValue && InRange(value_.real_, 0, maxUInt))
+             || type_ == booleanValue
+             || type_ == nullValue;
+   case realValue:
+      return isNumeric()
+             || type_ == booleanValue
+             || type_ == nullValue;
+   case booleanValue:
+      return isNumeric()
+             || type_ == booleanValue
+             || type_ == nullValue;
+   case stringValue:
+      return isNumeric()
+             || type_ == booleanValue
+             || type_ == stringValue
+             || type_ == nullValue;
+   case arrayValue:
+      return type_ == arrayValue
+             || type_ == nullValue;
+   case objectValue:
+      return type_ == objectValue
+             || type_ == nullValue;
+   }
+   JSON_ASSERT_UNREACHABLE;
+   return false;
+}
+
+
+/// Number of values in array or object
+ArrayIndex 
+Value::size() const
+{
+   switch ( type_ )
+   {
+   case nullValue:
+   case intValue:
+   case uintValue:
+   case realValue:
+   case booleanValue:
+   case stringValue:
+      return 0;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:  // size of the array is highest index + 1
+      if ( !value_.map_->empty() )
+      {
+         ObjectValues::const_iterator itLast = value_.map_->end();
+         --itLast;
+         return (*itLast).first.index()+1;
+      }
+      return 0;
+   case objectValue:
+      return ArrayIndex( value_.map_->size() );
+#else
+   case arrayValue:
+      return Int( value_.array_->size() );
+   case objectValue:
+      return Int( value_.map_->size() );
+#endif
+   }
+   JSON_ASSERT_UNREACHABLE;
+   return 0; // unreachable;
+}
+
+
+bool 
+Value::empty() const
+{
+   if ( isNull() || isArray() || isObject() )
+      return size() == 0u;
+   else
+      return false;
+}
+
+
+bool
+Value::operator!() const
+{
+   return isNull();
+}
+
+
+void 
+Value::clear()
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue  || type_ == objectValue );
+
+   switch ( type_ )
+   {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+   case objectValue:
+      value_.map_->clear();
+      break;
+#else
+   case arrayValue:
+      value_.array_->clear();
+      break;
+   case objectValue:
+      value_.map_->clear();
+      break;
+#endif
+   default:
+      break;
+   }
+}
+
+void 
+Value::resize( ArrayIndex newSize )
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue );
+   if ( type_ == nullValue )
+      *this = Value( arrayValue );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   ArrayIndex oldSize = size();
+   if ( newSize == 0 )
+      clear();
+   else if ( newSize > oldSize )
+      (*this)[ newSize - 1 ];
+   else
+   {
+      for ( ArrayIndex index = newSize; index < oldSize; ++index )
+      {
+         value_.map_->erase( index );
+      }
+      assert( size() == newSize );
+   }
+#else
+   value_.array_->resize( newSize );
+#endif
+}
+
+
+Value &
+Value::operator[]( ArrayIndex index )
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue );
+   if ( type_ == nullValue )
+      *this = Value( arrayValue );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   CZString key( index );
+   ObjectValues::iterator it = value_.map_->lower_bound( key );
+   if ( it != value_.map_->end()  &&  (*it).first == key )
+      return (*it).second;
+
+   ObjectValues::value_type defaultValue( key, null );
+   it = value_.map_->insert( it, defaultValue );
+   return (*it).second;
+#else
+   return value_.array_->resolveReference( index );
+#endif
+}
+
+
+Value &
+Value::operator[]( int index )
+{
+   JSON_ASSERT( index >= 0 );
+   return (*this)[ ArrayIndex(index) ];
+}
+
+
+const Value &
+Value::operator[]( ArrayIndex index ) const
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == arrayValue );
+   if ( type_ == nullValue )
+      return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   CZString key( index );
+   ObjectValues::const_iterator it = value_.map_->find( key );
+   if ( it == value_.map_->end() )
+      return null;
+   return (*it).second;
+#else
+   Value *value = value_.array_->find( index );
+   return value ? *value : null;
+#endif
+}
+
+
+const Value &
+Value::operator[]( int index ) const
+{
+   JSON_ASSERT( index >= 0 );
+   return (*this)[ ArrayIndex(index) ];
+}
+
+
+Value &
+Value::operator[]( const char *key )
+{
+   return resolveReference( key, false );
+}
+
+
+Value &
+Value::resolveReference( const char *key, 
+                         bool isStatic )
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );
+   if ( type_ == nullValue )
+      *this = Value( objectValue );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   CZString actualKey( key, isStatic ? CZString::noDuplication 
+                                     : CZString::duplicateOnCopy );
+   ObjectValues::iterator it = value_.map_->lower_bound( actualKey );
+   if ( it != value_.map_->end()  &&  (*it).first == actualKey )
+      return (*it).second;
+
+   ObjectValues::value_type defaultValue( actualKey, null );
+   it = value_.map_->insert( it, defaultValue );
+   Value &value = (*it).second;
+   return value;
+#else
+   return value_.map_->resolveReference( key, isStatic );
+#endif
+}
+
+
+Value 
+Value::get( ArrayIndex index, 
+            const Value &defaultValue ) const
+{
+   const Value *value = &((*this)[index]);
+   return value == &null ? defaultValue : *value;
+}
+
+
+bool 
+Value::isValidIndex( ArrayIndex index ) const
+{
+   return index < size();
+}
+
+
+
+const Value &
+Value::operator[]( const char *key ) const
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );
+   if ( type_ == nullValue )
+      return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   CZString actualKey( key, CZString::noDuplication );
+   ObjectValues::const_iterator it = value_.map_->find( actualKey );
+   if ( it == value_.map_->end() )
+      return null;
+   return (*it).second;
+#else
+   const Value *value = value_.map_->find( key );
+   return value ? *value : null;
+#endif
+}
+
+
+Value &
+Value::operator[]( const std::string &key )
+{
+   return (*this)[ key.c_str() ];
+}
+
+
+const Value &
+Value::operator[]( const std::string &key ) const
+{
+   return (*this)[ key.c_str() ];
+}
+
+Value &
+Value::operator[]( const StaticString &key )
+{
+   return resolveReference( key, true );
+}
+
+
+# ifdef JSON_USE_CPPTL
+Value &
+Value::operator[]( const CppTL::ConstString &key )
+{
+   return (*this)[ key.c_str() ];
+}
+
+
+const Value &
+Value::operator[]( const CppTL::ConstString &key ) const
+{
+   return (*this)[ key.c_str() ];
+}
+# endif
+
+
+Value &
+Value::append( const Value &value )
+{
+   return (*this)[size()] = value;
+}
+
+
+Value 
+Value::get( const char *key, 
+            const Value &defaultValue ) const
+{
+   const Value *value = &((*this)[key]);
+   return value == &null ? defaultValue : *value;
+}
+
+
+Value 
+Value::get( const std::string &key,
+            const Value &defaultValue ) const
+{
+   return get( key.c_str(), defaultValue );
+}
+
+Value
+Value::removeMember( const char* key )
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );
+   if ( type_ == nullValue )
+      return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   CZString actualKey( key, CZString::noDuplication );
+   ObjectValues::iterator it = value_.map_->find( actualKey );
+   if ( it == value_.map_->end() )
+      return null;
+   Value old(it->second);
+   value_.map_->erase(it);
+   return old;
+#else
+   Value *value = value_.map_->find( key );
+   if (value){
+      Value old(*value);
+      value_.map_.remove( key );
+      return old;
+   } else {
+      return null;
+   }
+#endif
+}
+
+Value
+Value::removeMember( const std::string &key )
+{
+   return removeMember( key.c_str() );
+}
+
+# ifdef JSON_USE_CPPTL
+Value 
+Value::get( const CppTL::ConstString &key,
+            const Value &defaultValue ) const
+{
+   return get( key.c_str(), defaultValue );
+}
+# endif
+
+bool 
+Value::isMember( const char *key ) const
+{
+   const Value *value = &((*this)[key]);
+   return value != &null;
+}
+
+
+bool 
+Value::isMember( const std::string &key ) const
+{
+   return isMember( key.c_str() );
+}
+
+
+# ifdef JSON_USE_CPPTL
+bool 
+Value::isMember( const CppTL::ConstString &key ) const
+{
+   return isMember( key.c_str() );
+}
+#endif
+
+Value::Members 
+Value::getMemberNames() const
+{
+   JSON_ASSERT( type_ == nullValue  ||  type_ == objectValue );
+   if ( type_ == nullValue )
+       return Value::Members();
+   Members members;
+   members.reserve( value_.map_->size() );
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   ObjectValues::const_iterator it = value_.map_->begin();
+   ObjectValues::const_iterator itEnd = value_.map_->end();
+   for ( ; it != itEnd; ++it )
+      members.push_back( std::string( (*it).first.c_str() ) );
+#else
+   ValueInternalMap::IteratorState it;
+   ValueInternalMap::IteratorState itEnd;
+   value_.map_->makeBeginIterator( it );
+   value_.map_->makeEndIterator( itEnd );
+   for ( ; !ValueInternalMap::equals( it, itEnd ); ValueInternalMap::increment(it) )
+      members.push_back( std::string( ValueInternalMap::key( it ) ) );
+#endif
+   return members;
+}
+//
+//# ifdef JSON_USE_CPPTL
+//EnumMemberNames
+//Value::enumMemberNames() const
+//{
+//   if ( type_ == objectValue )
+//   {
+//      return CppTL::Enum::any(  CppTL::Enum::transform(
+//         CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
+//         MemberNamesTransform() ) );
+//   }
+//   return EnumMemberNames();
+//}
+//
+//
+//EnumValues 
+//Value::enumValues() const
+//{
+//   if ( type_ == objectValue  ||  type_ == arrayValue )
+//      return CppTL::Enum::anyValues( *(value_.map_), 
+//                                     CppTL::Type<const Value &>() );
+//   return EnumValues();
+//}
+//
+//# endif
+
+static bool IsIntegral(double d) {
+  double integral_part;
+  return modf(d, &integral_part) == 0.0;
+}
+
+
+bool
+Value::isNull() const
+{
+   return type_ == nullValue;
+}
+
+
+bool 
+Value::isBool() const
+{
+   return type_ == booleanValue;
+}
+
+
+bool 
+Value::isInt() const
+{
+   switch ( type_ )
+   {
+   case intValue:
+      return value_.int_ >= minInt  &&  value_.int_ <= maxInt;
+   case uintValue:
+      return value_.uint_ <= UInt(maxInt);
+   case realValue:
+      return value_.real_ >= minInt &&
+             value_.real_ <= maxInt &&
+             IsIntegral(value_.real_);
+   default:
+      break;
+   }
+   return false;
+}
+
+
+bool 
+Value::isUInt() const
+{
+   switch ( type_ )
+   {
+   case intValue:
+      return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
+   case uintValue:
+      return value_.uint_ <= maxUInt;
+   case realValue:
+      return value_.real_ >= 0 &&
+             value_.real_ <= maxUInt &&
+             IsIntegral(value_.real_);
+   default:
+      break;
+   }
+   return false;
+}
+
+bool 
+Value::isInt64() const
+{
+# if defined(JSON_HAS_INT64)
+   switch ( type_ )
+   {
+   case intValue:
+     return true;
+   case uintValue:
+      return value_.uint_ <= UInt64(maxInt64);
+   case realValue:
+      // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
+      // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
+      // require the value to be strictly less than the limit.
+      return value_.real_ >= double(minInt64) &&
+             value_.real_ < double(maxInt64) &&
+             IsIntegral(value_.real_);
+   default:
+      break;
+   }
+# endif  // JSON_HAS_INT64
+   return false;
+}
+
+bool 
+Value::isUInt64() const
+{
+# if defined(JSON_HAS_INT64)
+   switch ( type_ )
+   {
+   case intValue:
+     return value_.int_ >= 0;
+   case uintValue:
+      return true;
+   case realValue:
+      // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
+      // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
+      // require the value to be strictly less than the limit.
+      return value_.real_ >= 0 &&
+             value_.real_ < maxUInt64AsDouble &&
+             IsIntegral(value_.real_);
+   default:
+      break;
+   }
+# endif  // JSON_HAS_INT64
+   return false;
+}
+
+
+bool 
+Value::isIntegral() const
+{
+#if defined(JSON_HAS_INT64)
+  return isInt64() || isUInt64();
+#else
+  return isInt() || isUInt();
+#endif
+}
+
+
+bool 
+Value::isDouble() const
+{
+   return type_ == realValue || isIntegral();
+}
+
+
+bool 
+Value::isNumeric() const
+{
+   return isIntegral() || isDouble();
+}
+
+
+bool 
+Value::isString() const
+{
+   return type_ == stringValue;
+}
+
+
+bool 
+Value::isArray() const
+{
+   return type_ == arrayValue;
+}
+
+
+bool 
+Value::isObject() const
+{
+   return type_ == objectValue;
+}
+
+
+void 
+Value::setComment( const char *comment,
+                   CommentPlacement placement )
+{
+   if ( !comments_ )
+      comments_ = new CommentInfo[numberOfCommentPlacement];
+   comments_[placement].setComment( comment );
+}
+
+
+void 
+Value::setComment( const std::string &comment,
+                   CommentPlacement placement )
+{
+   setComment( comment.c_str(), placement );
+}
+
+
+bool 
+Value::hasComment( CommentPlacement placement ) const
+{
+   return comments_ != 0  &&  comments_[placement].comment_ != 0;
+}
+
+std::string 
+Value::getComment( CommentPlacement placement ) const
+{
+   if ( hasComment(placement) )
+      return comments_[placement].comment_;
+   return "";
+}
+
+
+std::string 
+Value::toStyledString() const
+{
+   StyledWriter writer;
+   return writer.write( *this );
+}
+
+
+Value::const_iterator 
+Value::begin() const
+{
+   switch ( type_ )
+   {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+      if ( value_.array_ )
+      {
+         ValueInternalArray::IteratorState it;
+         value_.array_->makeBeginIterator( it );
+         return const_iterator( it );
+      }
+      break;
+   case objectValue:
+      if ( value_.map_ )
+      {
+         ValueInternalMap::IteratorState it;
+         value_.map_->makeBeginIterator( it );
+         return const_iterator( it );
+      }
+      break;
+#else
+   case arrayValue:
+   case objectValue:
+      if ( value_.map_ )
+         return const_iterator( value_.map_->begin() );
+      break;
+#endif
+   default:
+      break;
+   }
+   return const_iterator();
+}
+
+Value::const_iterator 
+Value::end() const
+{
+   switch ( type_ )
+   {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+      if ( value_.array_ )
+      {
+         ValueInternalArray::IteratorState it;
+         value_.array_->makeEndIterator( it );
+         return const_iterator( it );
+      }
+      break;
+   case objectValue:
+      if ( value_.map_ )
+      {
+         ValueInternalMap::IteratorState it;
+         value_.map_->makeEndIterator( it );
+         return const_iterator( it );
+      }
+      break;
+#else
+   case arrayValue:
+   case objectValue:
+      if ( value_.map_ )
+         return const_iterator( value_.map_->end() );
+      break;
+#endif
+   default:
+      break;
+   }
+   return const_iterator();
+}
+
+
+Value::iterator 
+Value::begin()
+{
+   switch ( type_ )
+   {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+      if ( value_.array_ )
+      {
+         ValueInternalArray::IteratorState it;
+         value_.array_->makeBeginIterator( it );
+         return iterator( it );
+      }
+      break;
+   case objectValue:
+      if ( value_.map_ )
+      {
+         ValueInternalMap::IteratorState it;
+         value_.map_->makeBeginIterator( it );
+         return iterator( it );
+      }
+      break;
+#else
+   case arrayValue:
+   case objectValue:
+      if ( value_.map_ )
+         return iterator( value_.map_->begin() );
+      break;
+#endif
+   default:
+      break;
+   }
+   return iterator();
+}
+
+Value::iterator 
+Value::end()
+{
+   switch ( type_ )
+   {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+   case arrayValue:
+      if ( value_.array_ )
+      {
+         ValueInternalArray::IteratorState it;
+         value_.array_->makeEndIterator( it );
+         return iterator( it );
+      }
+      break;
+   case objectValue:
+      if ( value_.map_ )
+      {
+         ValueInternalMap::IteratorState it;
+         value_.map_->makeEndIterator( it );
+         return iterator( it );
+      }
+      break;
+#else
+   case arrayValue:
+   case objectValue:
+      if ( value_.map_ )
+         return iterator( value_.map_->end() );
+      break;
+#endif
+   default:
+      break;
+   }
+   return iterator();
+}
+
+
+// class PathArgument
+// //////////////////////////////////////////////////////////////////
+
+PathArgument::PathArgument()
+   : key_()
+   , index_()
+   , kind_( kindNone )
+{
+}
+
+
+PathArgument::PathArgument( ArrayIndex index )
+   : key_()
+   , index_( index )
+   , kind_( kindIndex )
+{
+}
+
+
+PathArgument::PathArgument( const char *key )
+   : key_( key )
+   , index_()
+   , kind_( kindKey )
+{
+}
+
+
+PathArgument::PathArgument( const std::string &key )
+   : key_( key.c_str() )
+   , index_()
+   , kind_( kindKey )
+{
+}
+
+// class Path
+// //////////////////////////////////////////////////////////////////
+
+Path::Path( const std::string &path,
+            const PathArgument &a1,
+            const PathArgument &a2,
+            const PathArgument &a3,
+            const PathArgument &a4,
+            const PathArgument &a5 )
+{
+   InArgs in;
+   in.push_back( &a1 );
+   in.push_back( &a2 );
+   in.push_back( &a3 );
+   in.push_back( &a4 );
+   in.push_back( &a5 );
+   makePath( path, in );
+}
+
+
+void 
+Path::makePath( const std::string &path,
+                const InArgs &in )
+{
+   const char *current = path.c_str();
+   const char *end = current + path.length();
+   InArgs::const_iterator itInArg = in.begin();
+   while ( current != end )
+   {
+      if ( *current == '[' )
+      {
+         ++current;
+         if ( *current == '%' )
+            addPathInArg( path, in, itInArg, PathArgument::kindIndex );
+         else
+         {
+            ArrayIndex index = 0;
+            for ( ; current != end && *current >= '0'  &&  *current <= '9'; ++current )
+               index = index * 10 + ArrayIndex(*current - '0');
+            args_.push_back( index );
+         }
+         if ( current == end  ||  *current++ != ']' )
+            invalidPath( path, int(current - path.c_str()) );
+      }
+      else if ( *current == '%' )
+      {
+         addPathInArg( path, in, itInArg, PathArgument::kindKey );
+         ++current;
+      }
+      else if ( *current == '.' )
+      {
+         ++current;
+      }
+      else
+      {
+         const char *beginName = current;
+         while ( current != end  &&  !strchr( "[.", *current ) )
+            ++current;
+         args_.push_back( std::string( beginName, current ) );
+      }
+   }
+}
+
+
+void 
+Path::addPathInArg( const std::string &path, 
+                    const InArgs &in, 
+                    InArgs::const_iterator &itInArg, 
+                    PathArgument::Kind kind )
+{
+   if ( itInArg == in.end() )
+   {
+      // Error: missing argument %d
+   }
+   else if ( (*itInArg)->kind_ != kind )
+   {
+      // Error: bad argument type
+   }
+   else
+   {
+      args_.push_back( **itInArg );
+   }
+}
+
+
+void 
+Path::invalidPath( const std::string &path, 
+                   int location )
+{
+   // Error: invalid path.
+}
+
+
+const Value &
+Path::resolve( const Value &root ) const
+{
+   const Value *node = &root;
+   for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )
+   {
+      const PathArgument &arg = *it;
+      if ( arg.kind_ == PathArgument::kindIndex )
+      {
+         if ( !node->isArray()  ||  !node->isValidIndex( arg.index_ ) )
+         {
+            // Error: unable to resolve path (array value expected at position...
+         }
+         node = &((*node)[arg.index_]);
+      }
+      else if ( arg.kind_ == PathArgument::kindKey )
+      {
+         if ( !node->isObject() )
+         {
+            // Error: unable to resolve path (object value expected at position...)
+         }
+         node = &((*node)[arg.key_]);
+         if ( node == &Value::null )
+         {
+            // Error: unable to resolve path (object has no member named '' at position...)
+         }
+      }
+   }
+   return *node;
+}
+
+
+Value 
+Path::resolve( const Value &root, 
+               const Value &defaultValue ) const
+{
+   const Value *node = &root;
+   for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )
+   {
+      const PathArgument &arg = *it;
+      if ( arg.kind_ == PathArgument::kindIndex )
+      {
+         if ( !node->isArray()  ||  !node->isValidIndex( arg.index_ ) )
+            return defaultValue;
+         node = &((*node)[arg.index_]);
+      }
+      else if ( arg.kind_ == PathArgument::kindKey )
+      {
+         if ( !node->isObject() )
+            return defaultValue;
+         node = &((*node)[arg.key_]);
+         if ( node == &Value::null )
+            return defaultValue;
+      }
+   }
+   return *node;
+}
+
+
+Value &
+Path::make( Value &root ) const
+{
+   Value *node = &root;
+   for ( Args::const_iterator it = args_.begin(); it != args_.end(); ++it )
+   {
+      const PathArgument &arg = *it;
+      if ( arg.kind_ == PathArgument::kindIndex )
+      {
+         if ( !node->isArray() )
+         {
+            // Error: node is not an array at position ...
+         }
+         node = &((*node)[arg.index_]);
+      }
+      else if ( arg.kind_ == PathArgument::kindKey )
+      {
+         if ( !node->isObject() )
+         {
+            // Error: node is not an object at position...
+         }
+         node = &((*node)[arg.key_]);
+      }
+   }
+   return *node;
+}
+
+
+} // namespace Json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/json_valueiterator.inl	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,299 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+// included by json_value.cpp
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIteratorBase
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIteratorBase::ValueIteratorBase()
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   : current_()
+   , isNull_( true )
+{
+}
+#else
+   : isArray_( true )
+   , isNull_( true )
+{
+   iterator_.array_ = ValueInternalArray::IteratorState();
+}
+#endif
+
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueIteratorBase::ValueIteratorBase( const Value::ObjectValues::iterator &current )
+   : current_( current )
+   , isNull_( false )
+{
+}
+#else
+ValueIteratorBase::ValueIteratorBase( const ValueInternalArray::IteratorState &state )
+   : isArray_( true )
+{
+   iterator_.array_ = state;
+}
+
+
+ValueIteratorBase::ValueIteratorBase( const ValueInternalMap::IteratorState &state )
+   : isArray_( false )
+{
+   iterator_.map_ = state;
+}
+#endif
+
+Value &
+ValueIteratorBase::deref() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   return current_->second;
+#else
+   if ( isArray_ )
+      return ValueInternalArray::dereference( iterator_.array_ );
+   return ValueInternalMap::value( iterator_.map_ );
+#endif
+}
+
+
+void 
+ValueIteratorBase::increment()
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   ++current_;
+#else
+   if ( isArray_ )
+      ValueInternalArray::increment( iterator_.array_ );
+   ValueInternalMap::increment( iterator_.map_ );
+#endif
+}
+
+
+void 
+ValueIteratorBase::decrement()
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   --current_;
+#else
+   if ( isArray_ )
+      ValueInternalArray::decrement( iterator_.array_ );
+   ValueInternalMap::decrement( iterator_.map_ );
+#endif
+}
+
+
+ValueIteratorBase::difference_type 
+ValueIteratorBase::computeDistance( const SelfType &other ) const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+# ifdef JSON_USE_CPPTL_SMALLMAP
+   return current_ - other.current_;
+# else
+   // Iterator for null value are initialized using the default
+   // constructor, which initialize current_ to the default
+   // std::map::iterator. As begin() and end() are two instance 
+   // of the default std::map::iterator, they can not be compared.
+   // To allow this, we handle this comparison specifically.
+   if ( isNull_  &&  other.isNull_ )
+   {
+      return 0;
+   }
+
+
+   // Usage of std::distance is not portable (does not compile with Sun Studio 12 RogueWave STL,
+   // which is the one used by default).
+   // Using a portable hand-made version for non random iterator instead:
+   //   return difference_type( std::distance( current_, other.current_ ) );
+   difference_type myDistance = 0;
+   for ( Value::ObjectValues::iterator it = current_; it != other.current_; ++it )
+   {
+      ++myDistance;
+   }
+   return myDistance;
+# endif
+#else
+   if ( isArray_ )
+      return ValueInternalArray::distance( iterator_.array_, other.iterator_.array_ );
+   return ValueInternalMap::distance( iterator_.map_, other.iterator_.map_ );
+#endif
+}
+
+
+bool 
+ValueIteratorBase::isEqual( const SelfType &other ) const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   if ( isNull_ )
+   {
+      return other.isNull_;
+   }
+   return current_ == other.current_;
+#else
+   if ( isArray_ )
+      return ValueInternalArray::equals( iterator_.array_, other.iterator_.array_ );
+   return ValueInternalMap::equals( iterator_.map_, other.iterator_.map_ );
+#endif
+}
+
+
+void 
+ValueIteratorBase::copy( const SelfType &other )
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   current_ = other.current_;
+#else
+   if ( isArray_ )
+      iterator_.array_ = other.iterator_.array_;
+   iterator_.map_ = other.iterator_.map_;
+#endif
+}
+
+
+Value 
+ValueIteratorBase::key() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   const Value::CZString czstring = (*current_).first;
+   if ( czstring.c_str() )
+   {
+      if ( czstring.isStaticString() )
+         return Value( StaticString( czstring.c_str() ) );
+      return Value( czstring.c_str() );
+   }
+   return Value( czstring.index() );
+#else
+   if ( isArray_ )
+      return Value( ValueInternalArray::indexOf( iterator_.array_ ) );
+   bool isStatic;
+   const char *memberName = ValueInternalMap::key( iterator_.map_, isStatic );
+   if ( isStatic )
+      return Value( StaticString( memberName ) );
+   return Value( memberName );
+#endif
+}
+
+
+UInt 
+ValueIteratorBase::index() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   const Value::CZString czstring = (*current_).first;
+   if ( !czstring.c_str() )
+      return czstring.index();
+   return Value::UInt( -1 );
+#else
+   if ( isArray_ )
+      return Value::UInt( ValueInternalArray::indexOf( iterator_.array_ ) );
+   return Value::UInt( -1 );
+#endif
+}
+
+
+const char *
+ValueIteratorBase::memberName() const
+{
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+   const char *name = (*current_).first.c_str();
+   return name ? name : "";
+#else
+   if ( !isArray_ )
+      return ValueInternalMap::key( iterator_.map_ );
+   return "";
+#endif
+}
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueConstIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueConstIterator::ValueConstIterator()
+{
+}
+
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueConstIterator::ValueConstIterator( const Value::ObjectValues::iterator &current )
+   : ValueIteratorBase( current )
+{
+}
+#else
+ValueConstIterator::ValueConstIterator( const ValueInternalArray::IteratorState &state )
+   : ValueIteratorBase( state )
+{
+}
+
+ValueConstIterator::ValueConstIterator( const ValueInternalMap::IteratorState &state )
+   : ValueIteratorBase( state )
+{
+}
+#endif
+
+ValueConstIterator &
+ValueConstIterator::operator =( const ValueIteratorBase &other )
+{
+   copy( other );
+   return *this;
+}
+
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIterator::ValueIterator()
+{
+}
+
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueIterator::ValueIterator( const Value::ObjectValues::iterator &current )
+   : ValueIteratorBase( current )
+{
+}
+#else
+ValueIterator::ValueIterator( const ValueInternalArray::IteratorState &state )
+   : ValueIteratorBase( state )
+{
+}
+
+ValueIterator::ValueIterator( const ValueInternalMap::IteratorState &state )
+   : ValueIteratorBase( state )
+{
+}
+#endif
+
+ValueIterator::ValueIterator( const ValueConstIterator &other )
+   : ValueIteratorBase( other )
+{
+}
+
+ValueIterator::ValueIterator( const ValueIterator &other )
+   : ValueIteratorBase( other )
+{
+}
+
+ValueIterator &
+ValueIterator::operator =( const SelfType &other )
+{
+   copy( other );
+   return *this;
+}
+
+} // namespace Json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/json_writer.cpp	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,842 @@
+// Copyright 2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+# include <json/writer.h>
+# include "json_tool.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <utility>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+#if _MSC_VER >= 1400 // VC++ 8.0
+#pragma warning( disable : 4996 )   // disable warning about strdup being deprecated.
+#endif
+
+namespace Json {
+
+static bool containsControlCharacter( const char* str )
+{
+   while ( *str ) 
+   {
+      if ( isControlCharacter( *(str++) ) )
+         return true;
+   }
+   return false;
+}
+
+
+std::string valueToString( LargestInt value )
+{
+   UIntToStringBuffer buffer;
+   char *current = buffer + sizeof(buffer);
+   bool isNegative = value < 0;
+   if ( isNegative )
+      value = -value;
+   uintToString( LargestUInt(value), current );
+   if ( isNegative )
+      *--current = '-';
+   assert( current >= buffer );
+   return current;
+}
+
+
+std::string valueToString( LargestUInt value )
+{
+   UIntToStringBuffer buffer;
+   char *current = buffer + sizeof(buffer);
+   uintToString( value, current );
+   assert( current >= buffer );
+   return current;
+}
+
+#if defined(JSON_HAS_INT64)
+
+std::string valueToString( Int value )
+{
+   return valueToString( LargestInt(value) );
+}
+
+
+std::string valueToString( UInt value )
+{
+   return valueToString( LargestUInt(value) );
+}
+
+#endif // # if defined(JSON_HAS_INT64)
+
+
+std::string valueToString( double value )
+{
+   char buffer[32];
+#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with visual studio 2005 to avoid warning. 
+   sprintf_s(buffer, sizeof(buffer), "%#.16g", value); 
+#else	
+   sprintf(buffer, "%#.16g", value); 
+#endif
+   char* ch = buffer + strlen(buffer) - 1;
+   if (*ch != '0') return buffer; // nothing to truncate, so save time
+   while(ch > buffer && *ch == '0'){
+     --ch;
+   }
+   char* last_nonzero = ch;
+   while(ch >= buffer){
+     switch(*ch){
+     case '0':
+     case '1':
+     case '2':
+     case '3':
+     case '4':
+     case '5':
+     case '6':
+     case '7':
+     case '8':
+     case '9':
+       --ch;
+       continue;
+     case '.':
+       // Truncate zeroes to save bytes in output, but keep one.
+       *(last_nonzero+2) = '\0';
+       return buffer;
+     default:
+       return buffer;
+     }
+   }
+   return buffer;
+}
+
+
+std::string valueToString( bool value )
+{
+   return value ? "true" : "false";
+}
+
+std::string valueToQuotedString( const char *value )
+{
+   if (value == NULL)
+      return "";
+   // Not sure how to handle unicode...
+   if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL && !containsControlCharacter( value ))
+      return std::string("\"") + value + "\"";
+   // We have to walk value and escape any special characters.
+   // Appending to std::string is not efficient, but this should be rare.
+   // (Note: forward slashes are *not* rare, but I am not escaping them.)
+   std::string::size_type maxsize = strlen(value)*2 + 3; // allescaped+quotes+NULL
+   std::string result;
+   result.reserve(maxsize); // to avoid lots of mallocs
+   result += "\"";
+   for (const char* c=value; *c != 0; ++c)
+   {
+      switch(*c)
+      {
+         case '\"':
+            result += "\\\"";
+            break;
+         case '\\':
+            result += "\\\\";
+            break;
+         case '\b':
+            result += "\\b";
+            break;
+         case '\f':
+            result += "\\f";
+            break;
+         case '\n':
+            result += "\\n";
+            break;
+         case '\r':
+            result += "\\r";
+            break;
+         case '\t':
+            result += "\\t";
+            break;
+         //case '/':
+            // Even though \/ is considered a legal escape in JSON, a bare
+            // slash is also legal, so I see no reason to escape it.
+            // (I hope I am not misunderstanding something.
+            // blep notes: actually escaping \/ may be useful in javascript to avoid </ 
+            // sequence.
+            // Should add a flag to allow this compatibility mode and prevent this 
+            // sequence from occurring.
+         default:
+            if ( isControlCharacter( *c ) )
+            {
+               std::ostringstream oss;
+               oss << "\\u" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << static_cast<int>(*c);
+               result += oss.str();
+            }
+            else
+            {
+               result += *c;
+            }
+            break;
+      }
+   }
+   result += "\"";
+   return result;
+}
+
+// Class Writer
+// //////////////////////////////////////////////////////////////////
+Writer::~Writer()
+{
+}
+
+
+// Class FastWriter
+// //////////////////////////////////////////////////////////////////
+
+FastWriter::FastWriter()
+   : yamlCompatiblityEnabled_( false )
+{
+}
+
+
+void 
+FastWriter::enableYAMLCompatibility()
+{
+   yamlCompatiblityEnabled_ = true;
+}
+
+
+std::string 
+FastWriter::write( const Value &root )
+{
+   document_ = "";
+   writeValue( root );
+   document_ += "\n";
+   return document_;
+}
+
+
+void 
+FastWriter::writeValue( const Value &value )
+{
+   switch ( value.type() )
+   {
+   case nullValue:
+      document_ += "null";
+      break;
+   case intValue:
+      document_ += valueToString( value.asLargestInt() );
+      break;
+   case uintValue:
+      document_ += valueToString( value.asLargestUInt() );
+      break;
+   case realValue:
+      document_ += valueToString( value.asDouble() );
+      break;
+   case stringValue:
+      document_ += valueToQuotedString( value.asCString() );
+      break;
+   case booleanValue:
+      document_ += valueToString( value.asBool() );
+      break;
+   case arrayValue:
+      {
+         document_ += "[";
+         int size = value.size();
+         for ( int index =0; index < size; ++index )
+         {
+            if ( index > 0 )
+               document_ += ",";
+            writeValue( value[index] );
+         }
+         document_ += "]";
+      }
+      break;
+   case objectValue:
+      {
+         Value::Members members( value.getMemberNames() );
+         document_ += "{";
+         for ( Value::Members::iterator it = members.begin(); 
+               it != members.end(); 
+               ++it )
+         {
+            const std::string &name = *it;
+            if ( it != members.begin() )
+               document_ += ",";
+            document_ += valueToQuotedString( name.c_str() );
+            document_ += yamlCompatiblityEnabled_ ? ": " 
+                                                  : ":";
+            writeValue( value[name] );
+         }
+         document_ += "}";
+      }
+      break;
+   }
+}
+
+
+// Class StyledWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledWriter::StyledWriter()
+   : rightMargin_( 74 )
+   , indentSize_( 3 )
+   , addChildValues_()
+{
+}
+
+
+std::string 
+StyledWriter::write( const Value &root )
+{
+   document_ = "";
+   addChildValues_ = false;
+   indentString_ = "";
+   writeCommentBeforeValue( root );
+   writeValue( root );
+   writeCommentAfterValueOnSameLine( root );
+   document_ += "\n";
+   return document_;
+}
+
+
+void 
+StyledWriter::writeValue( const Value &value )
+{
+   switch ( value.type() )
+   {
+   case nullValue:
+      pushValue( "null" );
+      break;
+   case intValue:
+      pushValue( valueToString( value.asLargestInt() ) );
+      break;
+   case uintValue:
+      pushValue( valueToString( value.asLargestUInt() ) );
+      break;
+   case realValue:
+      pushValue( valueToString( value.asDouble() ) );
+      break;
+   case stringValue:
+      pushValue( valueToQuotedString( value.asCString() ) );
+      break;
+   case booleanValue:
+      pushValue( valueToString( value.asBool() ) );
+      break;
+   case arrayValue:
+      writeArrayValue( value);
+      break;
+   case objectValue:
+      {
+         Value::Members members( value.getMemberNames() );
+         if ( members.empty() )
+            pushValue( "{}" );
+         else
+         {
+            writeWithIndent( "{" );
+            indent();
+            Value::Members::iterator it = members.begin();
+            for (;;)
+            {
+               const std::string &name = *it;
+               const Value &childValue = value[name];
+               writeCommentBeforeValue( childValue );
+               writeWithIndent( valueToQuotedString( name.c_str() ) );
+               document_ += " : ";
+               writeValue( childValue );
+               if ( ++it == members.end() )
+               {
+                  writeCommentAfterValueOnSameLine( childValue );
+                  break;
+               }
+               document_ += ",";
+               writeCommentAfterValueOnSameLine( childValue );
+            }
+            unindent();
+            writeWithIndent( "}" );
+         }
+      }
+      break;
+   }
+}
+
+
+void 
+StyledWriter::writeArrayValue( const Value &value )
+{
+   unsigned size = value.size();
+   if ( size == 0 )
+      pushValue( "[]" );
+   else
+   {
+      bool isArrayMultiLine = isMultineArray( value );
+      if ( isArrayMultiLine )
+      {
+         writeWithIndent( "[" );
+         indent();
+         bool hasChildValue = !childValues_.empty();
+         unsigned index =0;
+         for (;;)
+         {
+            const Value &childValue = value[index];
+            writeCommentBeforeValue( childValue );
+            if ( hasChildValue )
+               writeWithIndent( childValues_[index] );
+            else
+            {
+               writeIndent();
+               writeValue( childValue );
+            }
+            if ( ++index == size )
+            {
+               writeCommentAfterValueOnSameLine( childValue );
+               break;
+            }
+            document_ += ",";
+            writeCommentAfterValueOnSameLine( childValue );
+         }
+         unindent();
+         writeWithIndent( "]" );
+      }
+      else // output on a single line
+      {
+         assert( childValues_.size() == size );
+         document_ += "[ ";
+         for ( unsigned index =0; index < size; ++index )
+         {
+            if ( index > 0 )
+               document_ += ", ";
+            document_ += childValues_[index];
+         }
+         document_ += " ]";
+      }
+   }
+}
+
+
+bool 
+StyledWriter::isMultineArray( const Value &value )
+{
+   int size = value.size();
+   bool isMultiLine = size*3 >= rightMargin_ ;
+   childValues_.clear();
+   for ( int index =0; index < size  &&  !isMultiLine; ++index )
+   {
+      const Value &childValue = value[index];
+      isMultiLine = isMultiLine  ||
+                     ( (childValue.isArray()  ||  childValue.isObject())  &&  
+                        childValue.size() > 0 );
+   }
+   if ( !isMultiLine ) // check if line length > max line length
+   {
+      childValues_.reserve( size );
+      addChildValues_ = true;
+      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
+      for ( int index =0; index < size  &&  !isMultiLine; ++index )
+      {
+         writeValue( value[index] );
+         lineLength += int( childValues_[index].length() );
+         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
+      }
+      addChildValues_ = false;
+      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
+   }
+   return isMultiLine;
+}
+
+
+void 
+StyledWriter::pushValue( const std::string &value )
+{
+   if ( addChildValues_ )
+      childValues_.push_back( value );
+   else
+      document_ += value;
+}
+
+
+void 
+StyledWriter::writeIndent()
+{
+   if ( !document_.empty() )
+   {
+      char last = document_[document_.length()-1];
+      if ( last == ' ' )     // already indented
+         return;
+      if ( last != '\n' )    // Comments may add new-line
+         document_ += '\n';
+   }
+   document_ += indentString_;
+}
+
+
+void 
+StyledWriter::writeWithIndent( const std::string &value )
+{
+   writeIndent();
+   document_ += value;
+}
+
+
+void 
+StyledWriter::indent()
+{
+   indentString_ += std::string( indentSize_, ' ' );
+}
+
+
+void 
+StyledWriter::unindent()
+{
+   assert( int(indentString_.size()) >= indentSize_ );
+   indentString_.resize( indentString_.size() - indentSize_ );
+}
+
+
+void 
+StyledWriter::writeCommentBeforeValue( const Value &root )
+{
+   if ( !root.hasComment( commentBefore ) )
+      return;
+   document_ += normalizeEOL( root.getComment( commentBefore ) );
+   document_ += "\n";
+}
+
+
+void 
+StyledWriter::writeCommentAfterValueOnSameLine( const Value &root )
+{
+   if ( root.hasComment( commentAfterOnSameLine ) )
+      document_ += " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
+
+   if ( root.hasComment( commentAfter ) )
+   {
+      document_ += "\n";
+      document_ += normalizeEOL( root.getComment( commentAfter ) );
+      document_ += "\n";
+   }
+}
+
+
+bool 
+StyledWriter::hasCommentForValue( const Value &value )
+{
+   return value.hasComment( commentBefore )
+          ||  value.hasComment( commentAfterOnSameLine )
+          ||  value.hasComment( commentAfter );
+}
+
+
+std::string 
+StyledWriter::normalizeEOL( const std::string &text )
+{
+   std::string normalized;
+   normalized.reserve( text.length() );
+   const char *begin = text.c_str();
+   const char *end = begin + text.length();
+   const char *current = begin;
+   while ( current != end )
+   {
+      char c = *current++;
+      if ( c == '\r' ) // mac or dos EOL
+      {
+         if ( *current == '\n' ) // convert dos EOL
+            ++current;
+         normalized += '\n';
+      }
+      else // handle unix EOL & other char
+         normalized += c;
+   }
+   return normalized;
+}
+
+
+// Class StyledStreamWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledStreamWriter::StyledStreamWriter( std::string indentation )
+   : document_(NULL)
+   , rightMargin_( 74 )
+   , indentation_( indentation )
+   , addChildValues_()
+{
+}
+
+
+void
+StyledStreamWriter::write( std::ostream &out, const Value &root )
+{
+   document_ = &out;
+   addChildValues_ = false;
+   indentString_ = "";
+   writeCommentBeforeValue( root );
+   writeValue( root );
+   writeCommentAfterValueOnSameLine( root );
+   *document_ << "\n";
+   document_ = NULL; // Forget the stream, for safety.
+}
+
+
+void 
+StyledStreamWriter::writeValue( const Value &value )
+{
+   switch ( value.type() )
+   {
+   case nullValue:
+      pushValue( "null" );
+      break;
+   case intValue:
+      pushValue( valueToString( value.asLargestInt() ) );
+      break;
+   case uintValue:
+      pushValue( valueToString( value.asLargestUInt() ) );
+      break;
+   case realValue:
+      pushValue( valueToString( value.asDouble() ) );
+      break;
+   case stringValue:
+      pushValue( valueToQuotedString( value.asCString() ) );
+      break;
+   case booleanValue:
+      pushValue( valueToString( value.asBool() ) );
+      break;
+   case arrayValue:
+      writeArrayValue( value);
+      break;
+   case objectValue:
+      {
+         Value::Members members( value.getMemberNames() );
+         if ( members.empty() )
+            pushValue( "{}" );
+         else
+         {
+            writeWithIndent( "{" );
+            indent();
+            Value::Members::iterator it = members.begin();
+            for (;;)
+            {
+               const std::string &name = *it;
+               const Value &childValue = value[name];
+               writeCommentBeforeValue( childValue );
+               writeWithIndent( valueToQuotedString( name.c_str() ) );
+               *document_ << " : ";
+               writeValue( childValue );
+               if ( ++it == members.end() )
+               {
+                  writeCommentAfterValueOnSameLine( childValue );
+                  break;
+               }
+               *document_ << ",";
+               writeCommentAfterValueOnSameLine( childValue );
+            }
+            unindent();
+            writeWithIndent( "}" );
+         }
+      }
+      break;
+   }
+}
+
+
+void 
+StyledStreamWriter::writeArrayValue( const Value &value )
+{
+   unsigned size = value.size();
+   if ( size == 0 )
+      pushValue( "[]" );
+   else
+   {
+      bool isArrayMultiLine = isMultineArray( value );
+      if ( isArrayMultiLine )
+      {
+         writeWithIndent( "[" );
+         indent();
+         bool hasChildValue = !childValues_.empty();
+         unsigned index =0;
+         for (;;)
+         {
+            const Value &childValue = value[index];
+            writeCommentBeforeValue( childValue );
+            if ( hasChildValue )
+               writeWithIndent( childValues_[index] );
+            else
+            {
+               writeIndent();
+               writeValue( childValue );
+            }
+            if ( ++index == size )
+            {
+               writeCommentAfterValueOnSameLine( childValue );
+               break;
+            }
+            *document_ << ",";
+            writeCommentAfterValueOnSameLine( childValue );
+         }
+         unindent();
+         writeWithIndent( "]" );
+      }
+      else // output on a single line
+      {
+         assert( childValues_.size() == size );
+         *document_ << "[ ";
+         for ( unsigned index =0; index < size; ++index )
+         {
+            if ( index > 0 )
+               *document_ << ", ";
+            *document_ << childValues_[index];
+         }
+         *document_ << " ]";
+      }
+   }
+}
+
+
+bool 
+StyledStreamWriter::isMultineArray( const Value &value )
+{
+   int size = value.size();
+   bool isMultiLine = size*3 >= rightMargin_ ;
+   childValues_.clear();
+   for ( int index =0; index < size  &&  !isMultiLine; ++index )
+   {
+      const Value &childValue = value[index];
+      isMultiLine = isMultiLine  ||
+                     ( (childValue.isArray()  ||  childValue.isObject())  &&  
+                        childValue.size() > 0 );
+   }
+   if ( !isMultiLine ) // check if line length > max line length
+   {
+      childValues_.reserve( size );
+      addChildValues_ = true;
+      int lineLength = 4 + (size-1)*2; // '[ ' + ', '*n + ' ]'
+      for ( int index =0; index < size  &&  !isMultiLine; ++index )
+      {
+         writeValue( value[index] );
+         lineLength += int( childValues_[index].length() );
+         isMultiLine = isMultiLine  &&  hasCommentForValue( value[index] );
+      }
+      addChildValues_ = false;
+      isMultiLine = isMultiLine  ||  lineLength >= rightMargin_;
+   }
+   return isMultiLine;
+}
+
+
+void 
+StyledStreamWriter::pushValue( const std::string &value )
+{
+   if ( addChildValues_ )
+      childValues_.push_back( value );
+   else
+      *document_ << value;
+}
+
+
+void 
+StyledStreamWriter::writeIndent()
+{
+  /*
+    Some comments in this method would have been nice. ;-)
+
+   if ( !document_.empty() )
+   {
+      char last = document_[document_.length()-1];
+      if ( last == ' ' )     // already indented
+         return;
+      if ( last != '\n' )    // Comments may add new-line
+         *document_ << '\n';
+   }
+  */
+   *document_ << '\n' << indentString_;
+}
+
+
+void 
+StyledStreamWriter::writeWithIndent( const std::string &value )
+{
+   writeIndent();
+   *document_ << value;
+}
+
+
+void 
+StyledStreamWriter::indent()
+{
+   indentString_ += indentation_;
+}
+
+
+void 
+StyledStreamWriter::unindent()
+{
+   assert( indentString_.size() >= indentation_.size() );
+   indentString_.resize( indentString_.size() - indentation_.size() );
+}
+
+
+void 
+StyledStreamWriter::writeCommentBeforeValue( const Value &root )
+{
+   if ( !root.hasComment( commentBefore ) )
+      return;
+   *document_ << normalizeEOL( root.getComment( commentBefore ) );
+   *document_ << "\n";
+}
+
+
+void 
+StyledStreamWriter::writeCommentAfterValueOnSameLine( const Value &root )
+{
+   if ( root.hasComment( commentAfterOnSameLine ) )
+      *document_ << " " + normalizeEOL( root.getComment( commentAfterOnSameLine ) );
+
+   if ( root.hasComment( commentAfter ) )
+   {
+      *document_ << "\n";
+      *document_ << normalizeEOL( root.getComment( commentAfter ) );
+      *document_ << "\n";
+   }
+}
+
+
+bool 
+StyledStreamWriter::hasCommentForValue( const Value &value )
+{
+   return value.hasComment( commentBefore )
+          ||  value.hasComment( commentAfterOnSameLine )
+          ||  value.hasComment( commentAfter );
+}
+
+
+std::string 
+StyledStreamWriter::normalizeEOL( const std::string &text )
+{
+   std::string normalized;
+   normalized.reserve( text.length() );
+   const char *begin = text.c_str();
+   const char *end = begin + text.length();
+   const char *current = begin;
+   while ( current != end )
+   {
+      char c = *current++;
+      if ( c == '\r' ) // mac or dos EOL
+      {
+         if ( *current == '\n' ) // convert dos EOL
+            ++current;
+         normalized += '\n';
+      }
+      else // handle unix EOL & other char
+         normalized += c;
+   }
+   return normalized;
+}
+
+
+std::ostream& operator<<( std::ostream &sout, const Value &root )
+{
+   Json::StyledStreamWriter writer;
+   writer.write(sout, root);
+   return sout;
+}
+
+
+} // namespace Json
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/reader.h	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,214 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_READER_H_INCLUDED
+# define CPPTL_JSON_READER_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+# include "features.h"
+# include "value.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+# include <deque>
+# include <stack>
+# include <string>
+# include <iostream>
+
+namespace Json {
+
+   /** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a Value.
+    *
+    */
+   class JSON_API Reader
+   {
+   public:
+      typedef char Char;
+      typedef const Char *Location;
+
+      /** \brief Constructs a Reader allowing all features
+       * for parsing.
+       */
+      Reader();
+
+      /** \brief Constructs a Reader allowing the specified feature set
+       * for parsing.
+       */
+      Reader( const Features &features );
+
+      /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
+       * \param document UTF-8 encoded string containing the document to read.
+       * \param root [out] Contains the root value of the document if it was
+       *             successfully parsed.
+       * \param collectComments \c true to collect comment and allow writing them back during
+       *                        serialization, \c false to discard comments.
+       *                        This parameter is ignored if Features::allowComments_
+       *                        is \c false.
+       * \return \c true if the document was successfully parsed, \c false if an error occurred.
+       */
+      bool parse( const std::string &document, 
+                  Value &root,
+                  bool collectComments = true );
+
+      /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a> document.
+       * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the document to read.
+       * \param endDoc Pointer on the end of the UTF-8 encoded string of the document to read. 
+       \               Must be >= beginDoc.
+       * \param root [out] Contains the root value of the document if it was
+       *             successfully parsed.
+       * \param collectComments \c true to collect comment and allow writing them back during
+       *                        serialization, \c false to discard comments.
+       *                        This parameter is ignored if Features::allowComments_
+       *                        is \c false.
+       * \return \c true if the document was successfully parsed, \c false if an error occurred.
+       */
+      bool parse( const char *beginDoc, const char *endDoc, 
+                  Value &root,
+                  bool collectComments = true );
+
+      /// \brief Parse from input stream.
+      /// \see Json::operator>>(std::istream&, Json::Value&).
+      bool parse( std::istream &is,
+                  Value &root,
+                  bool collectComments = true );
+
+      /** \brief Returns a user friendly string that list errors in the parsed document.
+       * \return Formatted error message with the list of errors with their location in 
+       *         the parsed document. An empty string is returned if no error occurred
+       *         during parsing.
+       * \deprecated Use getFormattedErrorMessages() instead (typo fix).
+       */
+      JSONCPP_DEPRECATED("Use getFormattedErrorMessages instead") 
+      std::string getFormatedErrorMessages() const;
+
+      /** \brief Returns a user friendly string that list errors in the parsed document.
+       * \return Formatted error message with the list of errors with their location in 
+       *         the parsed document. An empty string is returned if no error occurred
+       *         during parsing.
+       */
+      std::string getFormattedErrorMessages() const;
+
+   private:
+      enum TokenType
+      {
+         tokenEndOfStream = 0,
+         tokenObjectBegin,
+         tokenObjectEnd,
+         tokenArrayBegin,
+         tokenArrayEnd,
+         tokenString,
+         tokenNumber,
+         tokenTrue,
+         tokenFalse,
+         tokenNull,
+         tokenArraySeparator,
+         tokenMemberSeparator,
+         tokenComment,
+         tokenError
+      };
+
+      class Token
+      {
+      public:
+         TokenType type_;
+         Location start_;
+         Location end_;
+      };
+
+      class ErrorInfo
+      {
+      public:
+         Token token_;
+         std::string message_;
+         Location extra_;
+      };
+
+      typedef std::deque<ErrorInfo> Errors;
+
+      bool expectToken( TokenType type, Token &token, const char *message );
+      bool readToken( Token &token );
+      void skipSpaces();
+      bool match( Location pattern, 
+                  int patternLength );
+      bool readComment();
+      bool readCStyleComment();
+      bool readCppStyleComment();
+      bool readString();
+      void readNumber();
+      bool readValue();
+      bool readObject( Token &token );
+      bool readArray( Token &token );
+      bool decodeNumber( Token &token );
+      bool decodeString( Token &token );
+      bool decodeString( Token &token, std::string &decoded );
+      bool decodeDouble( Token &token );
+      bool decodeUnicodeCodePoint( Token &token, 
+                                   Location &current, 
+                                   Location end, 
+                                   unsigned int &unicode );
+      bool decodeUnicodeEscapeSequence( Token &token, 
+                                        Location &current, 
+                                        Location end, 
+                                        unsigned int &unicode );
+      bool addError( const std::string &message, 
+                     Token &token,
+                     Location extra = 0 );
+      bool recoverFromError( TokenType skipUntilToken );
+      bool addErrorAndRecover( const std::string &message, 
+                               Token &token,
+                               TokenType skipUntilToken );
+      void skipUntilSpace();
+      Value &currentValue();
+      Char getNextChar();
+      void getLocationLineAndColumn( Location location,
+                                     int &line,
+                                     int &column ) const;
+      std::string getLocationLineAndColumn( Location location ) const;
+      void addComment( Location begin, 
+                       Location end, 
+                       CommentPlacement placement );
+      void skipCommentTokens( Token &token );
+   
+      typedef std::stack<Value *> Nodes;
+      Nodes nodes_;
+      Errors errors_;
+      std::string document_;
+      Location begin_;
+      Location end_;
+      Location current_;
+      Location lastValueEnd_;
+      Value *lastValue_;
+      std::string commentsBefore_;
+      Features features_;
+      bool collectComments_;
+   };
+
+   /** \brief Read from 'sin' into 'root'.
+
+    Always keep comments from the input JSON.
+
+    This can be used to read a file into a particular sub-object.
+    For example:
+    \code
+    Json::Value root;
+    cin >> root["dir"]["file"];
+    cout << root;
+    \endcode
+    Result:
+    \verbatim
+    {
+    "dir": {
+        "file": {
+        // The input stream JSON would be nested here.
+        }
+    }
+    }
+    \endverbatim
+    \throw std::exception on parse error.
+    \see Json::operator<<()
+   */
+   std::istream& operator>>( std::istream&, Value& );
+
+} // namespace Json
+
+#endif // CPPTL_JSON_READER_H_INCLUDED
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/value.h	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,1109 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_H_INCLUDED
+# define CPPTL_JSON_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+# include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+# include <string>
+# include <vector>
+
+# ifndef JSON_USE_CPPTL_SMALLMAP
+#  include <map>
+# else
+#  include <cpptl/smallmap.h>
+# endif
+# ifdef JSON_USE_CPPTL
+#  include <cpptl/forwards.h>
+# endif
+
+/** \brief JSON (JavaScript Object Notation).
+ */
+namespace Json {
+
+   /** \brief Type of the value held by a Value object.
+    */
+   enum ValueType
+   {
+      nullValue = 0, ///< 'null' value
+      intValue,      ///< signed integer value
+      uintValue,     ///< unsigned integer value
+      realValue,     ///< double value
+      stringValue,   ///< UTF-8 string value
+      booleanValue,  ///< bool value
+      arrayValue,    ///< array value (ordered list)
+      objectValue    ///< object value (collection of name/value pairs).
+   };
+
+   enum CommentPlacement
+   {
+      commentBefore = 0,        ///< a comment placed on the line before a value
+      commentAfterOnSameLine,   ///< a comment just after a value on the same line
+      commentAfter,             ///< a comment on the line after a value (only make sense for root value)
+      numberOfCommentPlacement
+   };
+
+//# ifdef JSON_USE_CPPTL
+//   typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
+//   typedef CppTL::AnyEnumerator<const Value &> EnumValues;
+//# endif
+
+   /** \brief Lightweight wrapper to tag static string.
+    *
+    * Value constructor and objectValue member assignement takes advantage of the
+    * StaticString and avoid the cost of string duplication when storing the
+    * string or the member name.
+    *
+    * Example of usage:
+    * \code
+    * Json::Value aValue( StaticString("some text") );
+    * Json::Value object;
+    * static const StaticString code("code");
+    * object[code] = 1234;
+    * \endcode
+    */
+   class JSON_API StaticString
+   {
+   public:
+      explicit StaticString( const char *czstring )
+         : str_( czstring )
+      {
+      }
+
+      operator const char *() const
+      {
+         return str_;
+      }
+
+      const char *c_str() const
+      {
+         return str_;
+      }
+
+   private:
+      const char *str_;
+   };
+
+   /** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
+    *
+    * This class is a discriminated union wrapper that can represents a:
+    * - signed integer [range: Value::minInt - Value::maxInt]
+    * - unsigned integer (range: 0 - Value::maxUInt)
+    * - double
+    * - UTF-8 string
+    * - boolean
+    * - 'null'
+    * - an ordered list of Value
+    * - collection of name/value pairs (javascript object)
+    *
+    * The type of the held value is represented by a #ValueType and 
+    * can be obtained using type().
+    *
+    * values of an #objectValue or #arrayValue can be accessed using operator[]() methods. 
+    * Non const methods will automatically create the a #nullValue element 
+    * if it does not exist. 
+    * The sequence of an #arrayValue will be automatically resize and initialized 
+    * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
+    *
+    * The get() methods can be used to obtanis default value in the case the required element
+    * does not exist.
+    *
+    * It is possible to iterate over the list of a #objectValue values using 
+    * the getMemberNames() method.
+    */
+   class JSON_API Value 
+   {
+      friend class ValueIteratorBase;
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+      friend class ValueInternalLink;
+      friend class ValueInternalMap;
+# endif
+   public:
+      typedef std::vector<std::string> Members;
+      typedef ValueIterator iterator;
+      typedef ValueConstIterator const_iterator;
+      typedef Json::UInt UInt;
+      typedef Json::Int Int;
+# if defined(JSON_HAS_INT64)
+      typedef Json::UInt64 UInt64;
+      typedef Json::Int64 Int64;
+#endif // defined(JSON_HAS_INT64)
+      typedef Json::LargestInt LargestInt;
+      typedef Json::LargestUInt LargestUInt;
+      typedef Json::ArrayIndex ArrayIndex;
+
+      static const Value null;
+      /// Minimum signed integer value that can be stored in a Json::Value.
+      static const LargestInt minLargestInt;
+      /// Maximum signed integer value that can be stored in a Json::Value.
+      static const LargestInt maxLargestInt;
+      /// Maximum unsigned integer value that can be stored in a Json::Value.
+      static const LargestUInt maxLargestUInt;
+
+      /// Minimum signed int value that can be stored in a Json::Value.
+      static const Int minInt;
+      /// Maximum signed int value that can be stored in a Json::Value.
+      static const Int maxInt;
+      /// Maximum unsigned int value that can be stored in a Json::Value.
+      static const UInt maxUInt;
+
+# if defined(JSON_HAS_INT64)
+      /// Minimum signed 64 bits int value that can be stored in a Json::Value.
+      static const Int64 minInt64;
+      /// Maximum signed 64 bits int value that can be stored in a Json::Value.
+      static const Int64 maxInt64;
+      /// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
+      static const UInt64 maxUInt64;
+#endif // defined(JSON_HAS_INT64)
+
+   private:
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+# ifndef JSON_VALUE_USE_INTERNAL_MAP
+      class CZString 
+      {
+      public:
+         enum DuplicationPolicy 
+         {
+            noDuplication = 0,
+            duplicate,
+            duplicateOnCopy
+         };
+         CZString( ArrayIndex index );
+         CZString( const char *cstr, DuplicationPolicy allocate );
+         CZString( const CZString &other );
+         ~CZString();
+         CZString &operator =( const CZString &other );
+         bool operator<( const CZString &other ) const;
+         bool operator==( const CZString &other ) const;
+         ArrayIndex index() const;
+         const char *c_str() const;
+         bool isStaticString() const;
+      private:
+         void swap( CZString &other );
+         const char *cstr_;
+         ArrayIndex index_;
+      };
+
+   public:
+#  ifndef JSON_USE_CPPTL_SMALLMAP
+      typedef std::map<CZString, Value> ObjectValues;
+#  else
+      typedef CppTL::SmallMap<CZString, Value> ObjectValues;
+#  endif // ifndef JSON_USE_CPPTL_SMALLMAP
+# endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
+#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+   public:
+      /** \brief Create a default Value of the given type.
+
+        This is a very useful constructor.
+        To create an empty array, pass arrayValue.
+        To create an empty object, pass objectValue.
+        Another Value can then be set to this one by assignment.
+    This is useful since clear() and resize() will not alter types.
+
+        Examples:
+    \code
+    Json::Value null_value; // null
+    Json::Value arr_value(Json::arrayValue); // []
+    Json::Value obj_value(Json::objectValue); // {}
+    \endcode
+      */
+      Value( ValueType type = nullValue );
+      Value( Int value );
+      Value( UInt value );
+#if defined(JSON_HAS_INT64)
+      Value( Int64 value );
+      Value( UInt64 value );
+#endif // if defined(JSON_HAS_INT64)
+      Value( double value );
+      Value( const char *value );
+      Value( const char *beginValue, const char *endValue );
+      /** \brief Constructs a value from a static string.
+
+       * Like other value string constructor but do not duplicate the string for
+       * internal storage. The given string must remain alive after the call to this
+       * constructor.
+       * Example of usage:
+       * \code
+       * Json::Value aValue( StaticString("some text") );
+       * \endcode
+       */
+      Value( const StaticString &value );
+      Value( const std::string &value );
+# ifdef JSON_USE_CPPTL
+      Value( const CppTL::ConstString &value );
+# endif
+      Value( bool value );
+      Value( const Value &other );
+      ~Value();
+
+      Value &operator=( const Value &other );
+      /// Swap values.
+      /// \note Currently, comments are intentionally not swapped, for
+      /// both logic and efficiency.
+      void swap( Value &other );
+
+      ValueType type() const;
+
+      bool operator <( const Value &other ) const;
+      bool operator <=( const Value &other ) const;
+      bool operator >=( const Value &other ) const;
+      bool operator >( const Value &other ) const;
+
+      bool operator ==( const Value &other ) const;
+      bool operator !=( const Value &other ) const;
+
+      int compare( const Value &other ) const;
+
+      const char *asCString() const;
+      std::string asString() const;
+# ifdef JSON_USE_CPPTL
+      CppTL::ConstString asConstString() const;
+# endif
+      Int asInt() const;
+      UInt asUInt() const;
+#if defined(JSON_HAS_INT64)
+      Int64 asInt64() const;
+      UInt64 asUInt64() const;
+#endif // if defined(JSON_HAS_INT64)
+      LargestInt asLargestInt() const;
+      LargestUInt asLargestUInt() const;
+      float asFloat() const;
+      double asDouble() const;
+      bool asBool() const;
+
+      bool isNull() const;
+      bool isBool() const;
+      bool isInt() const;
+      bool isInt64() const;
+      bool isUInt() const;
+      bool isUInt64() const;
+      bool isIntegral() const;
+      bool isDouble() const;
+      bool isNumeric() const;
+      bool isString() const;
+      bool isArray() const;
+      bool isObject() const;
+
+      bool isConvertibleTo( ValueType other ) const;
+
+      /// Number of values in array or object
+      ArrayIndex size() const;
+
+      /// \brief Return true if empty array, empty object, or null;
+      /// otherwise, false.
+      bool empty() const;
+
+      /// Return isNull()
+      bool operator!() const;
+
+      /// Remove all object members and array elements.
+      /// \pre type() is arrayValue, objectValue, or nullValue
+      /// \post type() is unchanged
+      void clear();
+
+      /// Resize the array to size elements. 
+      /// New elements are initialized to null.
+      /// May only be called on nullValue or arrayValue.
+      /// \pre type() is arrayValue or nullValue
+      /// \post type() is arrayValue
+      void resize( ArrayIndex size );
+
+      /// Access an array element (zero based index ).
+      /// If the array contains less than index element, then null value are inserted
+      /// in the array so that its size is index+1.
+      /// (You may need to say 'value[0u]' to get your compiler to distinguish
+      ///  this from the operator[] which takes a string.)
+      Value &operator[]( ArrayIndex index );
+
+      /// Access an array element (zero based index ).
+      /// If the array contains less than index element, then null value are inserted
+      /// in the array so that its size is index+1.
+      /// (You may need to say 'value[0u]' to get your compiler to distinguish
+      ///  this from the operator[] which takes a string.)
+      Value &operator[]( int index );
+
+      /// Access an array element (zero based index )
+      /// (You may need to say 'value[0u]' to get your compiler to distinguish
+      ///  this from the operator[] which takes a string.)
+      const Value &operator[]( ArrayIndex index ) const;
+
+      /// Access an array element (zero based index )
+      /// (You may need to say 'value[0u]' to get your compiler to distinguish
+      ///  this from the operator[] which takes a string.)
+      const Value &operator[]( int index ) const;
+
+      /// If the array contains at least index+1 elements, returns the element value, 
+      /// otherwise returns defaultValue.
+      Value get( ArrayIndex index, 
+                 const Value &defaultValue ) const;
+      /// Return true if index < size().
+      bool isValidIndex( ArrayIndex index ) const;
+      /// \brief Append value to array at the end.
+      ///
+      /// Equivalent to jsonvalue[jsonvalue.size()] = value;
+      Value &append( const Value &value );
+
+      /// Access an object value by name, create a null member if it does not exist.
+      Value &operator[]( const char *key );
+      /// Access an object value by name, returns null if there is no member with that name.
+      const Value &operator[]( const char *key ) const;
+      /// Access an object value by name, create a null member if it does not exist.
+      Value &operator[]( const std::string &key );
+      /// Access an object value by name, returns null if there is no member with that name.
+      const Value &operator[]( const std::string &key ) const;
+      /** \brief Access an object value by name, create a null member if it does not exist.
+
+       * If the object as no entry for that name, then the member name used to store
+       * the new entry is not duplicated.
+       * Example of use:
+       * \code
+       * Json::Value object;
+       * static const StaticString code("code");
+       * object[code] = 1234;
+       * \endcode
+       */
+      Value &operator[]( const StaticString &key );
+# ifdef JSON_USE_CPPTL
+      /// Access an object value by name, create a null member if it does not exist.
+      Value &operator[]( const CppTL::ConstString &key );
+      /// Access an object value by name, returns null if there is no member with that name.
+      const Value &operator[]( const CppTL::ConstString &key ) const;
+# endif
+      /// Return the member named key if it exist, defaultValue otherwise.
+      Value get( const char *key, 
+                 const Value &defaultValue ) const;
+      /// Return the member named key if it exist, defaultValue otherwise.
+      Value get( const std::string &key,
+                 const Value &defaultValue ) const;
+# ifdef JSON_USE_CPPTL
+      /// Return the member named key if it exist, defaultValue otherwise.
+      Value get( const CppTL::ConstString &key,
+                 const Value &defaultValue ) const;
+# endif
+      /// \brief Remove and return the named member.  
+      ///
+      /// Do nothing if it did not exist.
+      /// \return the removed Value, or null.
+      /// \pre type() is objectValue or nullValue
+      /// \post type() is unchanged
+      Value removeMember( const char* key );
+      /// Same as removeMember(const char*)
+      Value removeMember( const std::string &key );
+
+      /// Return true if the object has a member named key.
+      bool isMember( const char *key ) const;
+      /// Return true if the object has a member named key.
+      bool isMember( const std::string &key ) const;
+# ifdef JSON_USE_CPPTL
+      /// Return true if the object has a member named key.
+      bool isMember( const CppTL::ConstString &key ) const;
+# endif
+
+      /// \brief Return a list of the member names.
+      ///
+      /// If null, return an empty list.
+      /// \pre type() is objectValue or nullValue
+      /// \post if type() was nullValue, it remains nullValue
+      Members getMemberNames() const;
+
+//# ifdef JSON_USE_CPPTL
+//      EnumMemberNames enumMemberNames() const;
+//      EnumValues enumValues() const;
+//# endif
+
+      /// Comments must be //... or /* ... */
+      void setComment( const char *comment,
+                       CommentPlacement placement );
+      /// Comments must be //... or /* ... */
+      void setComment( const std::string &comment,
+                       CommentPlacement placement );
+      bool hasComment( CommentPlacement placement ) const;
+      /// Include delimiters and embedded newlines.
+      std::string getComment( CommentPlacement placement ) const;
+
+      std::string toStyledString() const;
+
+      const_iterator begin() const;
+      const_iterator end() const;
+
+      iterator begin();
+      iterator end();
+
+   private:
+      Value &resolveReference( const char *key, 
+                               bool isStatic );
+
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+      inline bool isItemAvailable() const
+      {
+         return itemIsUsed_ == 0;
+      }
+
+      inline void setItemUsed( bool isUsed = true )
+      {
+         itemIsUsed_ = isUsed ? 1 : 0;
+      }
+
+      inline bool isMemberNameStatic() const
+      {
+         return memberNameIsStatic_ == 0;
+      }
+
+      inline void setMemberNameIsStatic( bool isStatic )
+      {
+         memberNameIsStatic_ = isStatic ? 1 : 0;
+      }
+# endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+   private:
+      struct CommentInfo
+      {
+         CommentInfo();
+         ~CommentInfo();
+
+         void setComment( const char *text );
+
+         char *comment_;
+      };
+
+      //struct MemberNamesTransform
+      //{
+      //   typedef const char *result_type;
+      //   const char *operator()( const CZString &name ) const
+      //   {
+      //      return name.c_str();
+      //   }
+      //};
+
+      union ValueHolder
+      {
+         LargestInt int_;
+         LargestUInt uint_;
+         double real_;
+         bool bool_;
+         char *string_;
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+         ValueInternalArray *array_;
+         ValueInternalMap *map_;
+#else
+         ObjectValues *map_;
+# endif
+      } value_;
+      ValueType type_ : 8;
+      int allocated_ : 1;     // Notes: if declared as bool, bitfield is useless.
+# ifdef JSON_VALUE_USE_INTERNAL_MAP
+      unsigned int itemIsUsed_ : 1;      // used by the ValueInternalMap container.
+      int memberNameIsStatic_ : 1;       // used by the ValueInternalMap container.
+# endif
+      CommentInfo *comments_;
+   };
+
+
+   /** \brief Experimental and untested: represents an element of the "path" to access a node.
+    */
+   class PathArgument
+   {
+   public:
+      friend class Path;
+
+      PathArgument();
+      PathArgument( ArrayIndex index );
+      PathArgument( const char *key );
+      PathArgument( const std::string &key );
+
+   private:
+      enum Kind
+      {
+         kindNone = 0,
+         kindIndex,
+         kindKey
+      };
+      std::string key_;
+      ArrayIndex index_;
+      Kind kind_;
+   };
+
+   /** \brief Experimental and untested: represents a "path" to access a node.
+    *
+    * Syntax:
+    * - "." => root node
+    * - ".[n]" => elements at index 'n' of root node (an array value)
+    * - ".name" => member named 'name' of root node (an object value)
+    * - ".name1.name2.name3"
+    * - ".[0][1][2].name1[3]"
+    * - ".%" => member name is provided as parameter
+    * - ".[%]" => index is provied as parameter
+    */
+   class Path
+   {
+   public:
+      Path( const std::string &path,
+            const PathArgument &a1 = PathArgument(),
+            const PathArgument &a2 = PathArgument(),
+            const PathArgument &a3 = PathArgument(),
+            const PathArgument &a4 = PathArgument(),
+            const PathArgument &a5 = PathArgument() );
+
+      const Value &resolve( const Value &root ) const;
+      Value resolve( const Value &root, 
+                     const Value &defaultValue ) const;
+      /// Creates the "path" to access the specified node and returns a reference on the node.
+      Value &make( Value &root ) const;
+
+   private:
+      typedef std::vector<const PathArgument *> InArgs;
+      typedef std::vector<PathArgument> Args;
+
+      void makePath( const std::string &path,
+                     const InArgs &in );
+      void addPathInArg( const std::string &path, 
+                         const InArgs &in, 
+                         InArgs::const_iterator &itInArg, 
+                         PathArgument::Kind kind );
+      void invalidPath( const std::string &path, 
+                        int location );
+
+      Args args_;
+   };
+
+
+
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+   /** \brief Allocator to customize Value internal map.
+    * Below is an example of a simple implementation (default implementation actually
+    * use memory pool for speed).
+    * \code
+      class DefaultValueMapAllocator : public ValueMapAllocator
+      {
+      public: // overridden from ValueMapAllocator
+         virtual ValueInternalMap *newMap()
+         {
+            return new ValueInternalMap();
+         }
+
+         virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+         {
+            return new ValueInternalMap( other );
+         }
+
+         virtual void destructMap( ValueInternalMap *map )
+         {
+            delete map;
+         }
+
+         virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+         {
+            return new ValueInternalLink[size];
+         }
+
+         virtual void releaseMapBuckets( ValueInternalLink *links )
+         {
+            delete [] links;
+         }
+
+         virtual ValueInternalLink *allocateMapLink()
+         {
+            return new ValueInternalLink();
+         }
+
+         virtual void releaseMapLink( ValueInternalLink *link )
+         {
+            delete link;
+         }
+      };
+    * \endcode
+    */ 
+   class JSON_API ValueMapAllocator
+   {
+   public:
+      virtual ~ValueMapAllocator();
+      virtual ValueInternalMap *newMap() = 0;
+      virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other ) = 0;
+      virtual void destructMap( ValueInternalMap *map ) = 0;
+      virtual ValueInternalLink *allocateMapBuckets( unsigned int size ) = 0;
+      virtual void releaseMapBuckets( ValueInternalLink *links ) = 0;
+      virtual ValueInternalLink *allocateMapLink() = 0;
+      virtual void releaseMapLink( ValueInternalLink *link ) = 0;
+   };
+
+   /** \brief ValueInternalMap hash-map bucket chain link (for internal use only).
+    * \internal previous_ & next_ allows for bidirectional traversal.
+    */
+   class JSON_API ValueInternalLink
+   {
+   public:
+      enum { itemPerLink = 6 };  // sizeof(ValueInternalLink) = 128 on 32 bits architecture.
+      enum InternalFlags { 
+         flagAvailable = 0,
+         flagUsed = 1
+      };
+
+      ValueInternalLink();
+
+      ~ValueInternalLink();
+
+      Value items_[itemPerLink];
+      char *keys_[itemPerLink];
+      ValueInternalLink *previous_;
+      ValueInternalLink *next_;
+   };
+
+
+   /** \brief A linked page based hash-table implementation used internally by Value.
+    * \internal ValueInternalMap is a tradional bucket based hash-table, with a linked
+    * list in each bucket to handle collision. There is an addional twist in that
+    * each node of the collision linked list is a page containing a fixed amount of
+    * value. This provides a better compromise between memory usage and speed.
+    * 
+    * Each bucket is made up of a chained list of ValueInternalLink. The last
+    * link of a given bucket can be found in the 'previous_' field of the following bucket.
+    * The last link of the last bucket is stored in tailLink_ as it has no following bucket.
+    * Only the last link of a bucket may contains 'available' item. The last link always
+    * contains at least one element unless is it the bucket one very first link.
+    */
+   class JSON_API ValueInternalMap
+   {
+      friend class ValueIteratorBase;
+      friend class Value;
+   public:
+      typedef unsigned int HashKey;
+      typedef unsigned int BucketIndex;
+
+# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+      struct IteratorState
+      {
+         IteratorState() 
+            : map_(0)
+            , link_(0)
+            , itemIndex_(0)
+            , bucketIndex_(0) 
+         {
+         }
+         ValueInternalMap *map_;
+         ValueInternalLink *link_;
+         BucketIndex itemIndex_;
+         BucketIndex bucketIndex_;
+      };
+# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+      ValueInternalMap();
+      ValueInternalMap( const ValueInternalMap &other );
+      ValueInternalMap &operator =( const ValueInternalMap &other );
+      ~ValueInternalMap();
+
+      void swap( ValueInternalMap &other );
+
+      BucketIndex size() const;
+
+      void clear();
+
+      bool reserveDelta( BucketIndex growth );
+
+      bool reserve( BucketIndex newItemCount );
+
+      const Value *find( const char *key ) const;
+
+      Value *find( const char *key );
+
+      Value &resolveReference( const char *key, 
+                               bool isStatic );
+
+      void remove( const char *key );
+
+      void doActualRemove( ValueInternalLink *link, 
+                           BucketIndex index,
+                           BucketIndex bucketIndex );
+
+      ValueInternalLink *&getLastLinkInBucket( BucketIndex bucketIndex );
+
+      Value &setNewItem( const char *key, 
+                         bool isStatic, 
+                         ValueInternalLink *link, 
+                         BucketIndex index );
+
+      Value &unsafeAdd( const char *key, 
+                        bool isStatic, 
+                        HashKey hashedKey );
+
+      HashKey hash( const char *key ) const;
+
+      int compare( const ValueInternalMap &other ) const;
+
+   private:
+      void makeBeginIterator( IteratorState &it ) const;
+      void makeEndIterator( IteratorState &it ) const;
+      static bool equals( const IteratorState &x, const IteratorState &other );
+      static void increment( IteratorState &iterator );
+      static void incrementBucket( IteratorState &iterator );
+      static void decrement( IteratorState &iterator );
+      static const char *key( const IteratorState &iterator );
+      static const char *key( const IteratorState &iterator, bool &isStatic );
+      static Value &value( const IteratorState &iterator );
+      static int distance( const IteratorState &x, const IteratorState &y );
+
+   private:
+      ValueInternalLink *buckets_;
+      ValueInternalLink *tailLink_;
+      BucketIndex bucketsSize_;
+      BucketIndex itemCount_;
+   };
+
+   /** \brief A simplified deque implementation used internally by Value.
+   * \internal
+   * It is based on a list of fixed "page", each page contains a fixed number of items.
+   * Instead of using a linked-list, a array of pointer is used for fast item look-up.
+   * Look-up for an element is as follow:
+   * - compute page index: pageIndex = itemIndex / itemsPerPage
+   * - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]
+   *
+   * Insertion is amortized constant time (only the array containing the index of pointers
+   * need to be reallocated when items are appended).
+   */
+   class JSON_API ValueInternalArray
+   {
+      friend class Value;
+      friend class ValueIteratorBase;
+   public:
+      enum { itemsPerPage = 8 };    // should be a power of 2 for fast divide and modulo.
+      typedef Value::ArrayIndex ArrayIndex;
+      typedef unsigned int PageIndex;
+
+# ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+      struct IteratorState // Must be a POD
+      {
+         IteratorState() 
+            : array_(0)
+            , currentPageIndex_(0)
+            , currentItemIndex_(0) 
+         {
+         }
+         ValueInternalArray *array_;
+         Value **currentPageIndex_;
+         unsigned int currentItemIndex_;
+      };
+# endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+      ValueInternalArray();
+      ValueInternalArray( const ValueInternalArray &other );
+      ValueInternalArray &operator =( const ValueInternalArray &other );
+      ~ValueInternalArray();
+      void swap( ValueInternalArray &other );
+
+      void clear();
+      void resize( ArrayIndex newSize );
+
+      Value &resolveReference( ArrayIndex index );
+
+      Value *find( ArrayIndex index ) const;
+
+      ArrayIndex size() const;
+
+      int compare( const ValueInternalArray &other ) const;
+
+   private:
+      static bool equals( const IteratorState &x, const IteratorState &other );
+      static void increment( IteratorState &iterator );
+      static void decrement( IteratorState &iterator );
+      static Value &dereference( const IteratorState &iterator );
+      static Value &unsafeDereference( const IteratorState &iterator );
+      static int distance( const IteratorState &x, const IteratorState &y );
+      static ArrayIndex indexOf( const IteratorState &iterator );
+      void makeBeginIterator( IteratorState &it ) const;
+      void makeEndIterator( IteratorState &it ) const;
+      void makeIterator( IteratorState &it, ArrayIndex index ) const;
+
+      void makeIndexValid( ArrayIndex index );
+
+      Value **pages_;
+      ArrayIndex size_;
+      PageIndex pageCount_;
+   };
+
+   /** \brief Experimental: do not use. Allocator to customize Value internal array.
+    * Below is an example of a simple implementation (actual implementation use
+    * memory pool).
+      \code
+class DefaultValueArrayAllocator : public ValueArrayAllocator
+{
+public: // overridden from ValueArrayAllocator
+   virtual ~DefaultValueArrayAllocator()
+   {
+   }
+
+   virtual ValueInternalArray *newArray()
+   {
+      return new ValueInternalArray();
+   }
+
+   virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+   {
+      return new ValueInternalArray( other );
+   }
+
+   virtual void destruct( ValueInternalArray *array )
+   {
+      delete array;
+   }
+
+   virtual void reallocateArrayPageIndex( Value **&indexes, 
+                                          ValueInternalArray::PageIndex &indexCount,
+                                          ValueInternalArray::PageIndex minNewIndexCount )
+   {
+      ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+      if ( minNewIndexCount > newIndexCount )
+         newIndexCount = minNewIndexCount;
+      void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+      if ( !newIndexes )
+         throw std::bad_alloc();
+      indexCount = newIndexCount;
+      indexes = static_cast<Value **>( newIndexes );
+   }
+   virtual void releaseArrayPageIndex( Value **indexes, 
+                                       ValueInternalArray::PageIndex indexCount )
+   {
+      if ( indexes )
+         free( indexes );
+   }
+
+   virtual Value *allocateArrayPage()
+   {
+      return static_cast<Value *>( malloc( sizeof(Value) * ValueInternalArray::itemsPerPage ) );
+   }
+
+   virtual void releaseArrayPage( Value *value )
+   {
+      if ( value )
+         free( value );
+   }
+};
+      \endcode
+    */ 
+   class JSON_API ValueArrayAllocator
+   {
+   public:
+      virtual ~ValueArrayAllocator();
+      virtual ValueInternalArray *newArray() = 0;
+      virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other ) = 0;
+      virtual void destructArray( ValueInternalArray *array ) = 0;
+      /** \brief Reallocate array page index.
+       * Reallocates an array of pointer on each page.
+       * \param indexes [input] pointer on the current index. May be \c NULL.
+       *                [output] pointer on the new index of at least 
+       *                         \a minNewIndexCount pages. 
+       * \param indexCount [input] current number of pages in the index.
+       *                   [output] number of page the reallocated index can handle.
+       *                            \b MUST be >= \a minNewIndexCount.
+       * \param minNewIndexCount Minimum number of page the new index must be able to
+       *                         handle.
+       */
+      virtual void reallocateArrayPageIndex( Value **&indexes, 
+                                             ValueInternalArray::PageIndex &indexCount,
+                                             ValueInternalArray::PageIndex minNewIndexCount ) = 0;
+      virtual void releaseArrayPageIndex( Value **indexes, 
+                                          ValueInternalArray::PageIndex indexCount ) = 0;
+      virtual Value *allocateArrayPage() = 0;
+      virtual void releaseArrayPage( Value *value ) = 0;
+   };
+#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+
+   /** \brief base class for Value iterators.
+    *
+    */
+   class ValueIteratorBase
+   {
+   public:
+      typedef unsigned int size_t;
+      typedef int difference_type;
+      typedef ValueIteratorBase SelfType;
+
+      ValueIteratorBase();
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+      explicit ValueIteratorBase( const Value::ObjectValues::iterator &current );
+#else
+      ValueIteratorBase( const ValueInternalArray::IteratorState &state );
+      ValueIteratorBase( const ValueInternalMap::IteratorState &state );
+#endif
+
+      bool operator ==( const SelfType &other ) const
+      {
+         return isEqual( other );
+      }
+
+      bool operator !=( const SelfType &other ) const
+      {
+         return !isEqual( other );
+      }
+
+      difference_type operator -( const SelfType &other ) const
+      {
+         return computeDistance( other );
+      }
+
+      /// Return either the index or the member name of the referenced value as a Value.
+      Value key() const;
+
+      /// Return the index of the referenced Value. -1 if it is not an arrayValue.
+      UInt index() const;
+
+      /// Return the member name of the referenced Value. "" if it is not an objectValue.
+      const char *memberName() const;
+
+   protected:
+      Value &deref() const;
+
+      void increment();
+
+      void decrement();
+
+      difference_type computeDistance( const SelfType &other ) const;
+
+      bool isEqual( const SelfType &other ) const;
+
+      void copy( const SelfType &other );
+
+   private:
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+      Value::ObjectValues::iterator current_;
+      // Indicates that iterator is for a null value.
+      bool isNull_;
+#else
+      union
+      {
+         ValueInternalArray::IteratorState array_;
+         ValueInternalMap::IteratorState map_;
+      } iterator_;
+      bool isArray_;
+#endif
+   };
+
+   /** \brief const iterator for object and array value.
+    *
+    */
+   class ValueConstIterator : public ValueIteratorBase
+   {
+      friend class Value;
+   public:
+      typedef unsigned int size_t;
+      typedef int difference_type;
+      typedef const Value &reference;
+      typedef const Value *pointer;
+      typedef ValueConstIterator SelfType;
+
+      ValueConstIterator();
+   private:
+      /*! \internal Use by Value to create an iterator.
+       */
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+      explicit ValueConstIterator( const Value::ObjectValues::iterator &current );
+#else
+      ValueConstIterator( const ValueInternalArray::IteratorState &state );
+      ValueConstIterator( const ValueInternalMap::IteratorState &state );
+#endif
+   public:
+      SelfType &operator =( const ValueIteratorBase &other );
+
+      SelfType operator++( int )
+      {
+         SelfType temp( *this );
+         ++*this;
+         return temp;
+      }
+
+      SelfType operator--( int )
+      {
+         SelfType temp( *this );
+         --*this;
+         return temp;
+      }
+
+      SelfType &operator--()
+      {
+         decrement();
+         return *this;
+      }
+
+      SelfType &operator++()
+      {
+         increment();
+         return *this;
+      }
+
+      reference operator *() const
+      {
+         return deref();
+      }
+   };
+
+
+   /** \brief Iterator for object and array value.
+    */
+   class ValueIterator : public ValueIteratorBase
+   {
+      friend class Value;
+   public:
+      typedef unsigned int size_t;
+      typedef int difference_type;
+      typedef Value &reference;
+      typedef Value *pointer;
+      typedef ValueIterator SelfType;
+
+      ValueIterator();
+      ValueIterator( const ValueConstIterator &other );
+      ValueIterator( const ValueIterator &other );
+   private:
+      /*! \internal Use by Value to create an iterator.
+       */
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+      explicit ValueIterator( const Value::ObjectValues::iterator &current );
+#else
+      ValueIterator( const ValueInternalArray::IteratorState &state );
+      ValueIterator( const ValueInternalMap::IteratorState &state );
+#endif
+   public:
+
+      SelfType &operator =( const SelfType &other );
+
+      SelfType operator++( int )
+      {
+         SelfType temp( *this );
+         ++*this;
+         return temp;
+      }
+
+      SelfType operator--( int )
+      {
+         SelfType temp( *this );
+         --*this;
+         return temp;
+      }
+
+      SelfType &operator--()
+      {
+         decrement();
+         return *this;
+      }
+
+      SelfType &operator++()
+      {
+         increment();
+         return *this;
+      }
+
+      reference operator *() const
+      {
+         return deref();
+      }
+   };
+
+
+} // namespace Json
+
+
+#endif // CPPTL_JSON_H_INCLUDED
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/third_party/json/writer.h	Thu Aug 25 11:05:55 2011 +0100
@@ -0,0 +1,185 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_WRITER_H_INCLUDED
+# define JSON_WRITER_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+# include "value.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+# include <vector>
+# include <string>
+# include <iostream>
+
+namespace Json {
+
+   class Value;
+
+   /** \brief Abstract class for writers.
+    */
+   class JSON_API Writer
+   {
+   public:
+      virtual ~Writer();
+
+      virtual std::string write( const Value &root ) = 0;
+   };
+
+   /** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format without formatting (not human friendly).
+    *
+    * The JSON document is written in a single line. It is not intended for 'human' consumption,
+    * but may be usefull to support feature such as RPC where bandwith is limited.
+    * \sa Reader, Value
+    */
+   class JSON_API FastWriter : public Writer
+   {
+   public:
+      FastWriter();
+      virtual ~FastWriter(){}
+
+      void enableYAMLCompatibility();
+
+   public: // overridden from Writer
+      virtual std::string write( const Value &root );
+
+   private:
+      void writeValue( const Value &value );
+
+      std::string document_;
+      bool yamlCompatiblityEnabled_;
+   };
+
+   /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way.
+    *
+    * The rules for line break and indent are as follow:
+    * - Object value:
+    *     - if empty then print {} without indent and line break
+    *     - if not empty the print '{', line break & indent, print one value per line
+    *       and then unindent and line break and print '}'.
+    * - Array value:
+    *     - if empty then print [] without indent and line break
+    *     - if the array contains no object value, empty array or some other value types,
+    *       and all the values fit on one lines, then print the array on a single line.
+    *     - otherwise, it the values do not fit on one line, or the array contains
+    *       object or non empty array, then print one value per line.
+    *
+    * If the Value have comments then they are outputed according to their #CommentPlacement.
+    *
+    * \sa Reader, Value, Value::setComment()
+    */
+   class JSON_API StyledWriter: public Writer
+   {
+   public:
+      StyledWriter();
+      virtual ~StyledWriter(){}
+
+   public: // overridden from Writer
+      /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+       * \param root Value to serialize.
+       * \return String containing the JSON document that represents the root value.
+       */
+      virtual std::string write( const Value &root );
+
+   private:
+      void writeValue( const Value &value );
+      void writeArrayValue( const Value &value );
+      bool isMultineArray( const Value &value );
+      void pushValue( const std::string &value );
+      void writeIndent();
+      void writeWithIndent( const std::string &value );
+      void indent();
+      void unindent();
+      void writeCommentBeforeValue( const Value &root );
+      void writeCommentAfterValueOnSameLine( const Value &root );
+      bool hasCommentForValue( const Value &value );
+      static std::string normalizeEOL( const std::string &text );
+
+      typedef std::vector<std::string> ChildValues;
+
+      ChildValues childValues_;
+      std::string document_;
+      std::string indentString_;
+      int rightMargin_;
+      int indentSize_;
+      bool addChildValues_;
+   };
+
+   /** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a human friendly way,
+        to a stream rather than to a string.
+    *
+    * The rules for line break and indent are as follow:
+    * - Object value:
+    *     - if empty then print {} without indent and line break
+    *     - if not empty the print '{', line break & indent, print one value per line
+    *       and then unindent and line break and print '}'.
+    * - Array value:
+    *     - if empty then print [] without indent and line break
+    *     - if the array contains no object value, empty array or some other value types,
+    *       and all the values fit on one lines, then print the array on a single line.
+    *     - otherwise, it the values do not fit on one line, or the array contains
+    *       object or non empty array, then print one value per line.
+    *
+    * If the Value have comments then they are outputed according to their #CommentPlacement.
+    *
+    * \param indentation Each level will be indented by this amount extra.
+    * \sa Reader, Value, Value::setComment()
+    */
+   class JSON_API StyledStreamWriter
+   {
+   public:
+      StyledStreamWriter( std::string indentation="\t" );
+      ~StyledStreamWriter(){}
+
+   public:
+      /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+       * \param out Stream to write to. (Can be ostringstream, e.g.)
+       * \param root Value to serialize.
+       * \note There is no point in deriving from Writer, since write() should not return a value.
+       */
+      void write( std::ostream &out, const Value &root );
+
+   private:
+      void writeValue( const Value &value );
+      void writeArrayValue( const Value &value );
+      bool isMultineArray( const Value &value );
+      void pushValue( const std::string &value );
+      void writeIndent();
+      void writeWithIndent( const std::string &value );
+      void indent();
+      void unindent();
+      void writeCommentBeforeValue( const Value &root );
+      void writeCommentAfterValueOnSameLine( const Value &root );
+      bool hasCommentForValue( const Value &value );
+      static std::string normalizeEOL( const std::string &text );
+
+      typedef std::vector<std::string> ChildValues;
+
+      ChildValues childValues_;
+      std::ostream* document_;
+      std::string indentString_;
+      int rightMargin_;
+      std::string indentation_;
+      bool addChildValues_;
+   };
+
+# if defined(JSON_HAS_INT64)
+   std::string JSON_API valueToString( Int value );
+   std::string JSON_API valueToString( UInt value );
+# endif // if defined(JSON_HAS_INT64)
+   std::string JSON_API valueToString( LargestInt value );
+   std::string JSON_API valueToString( LargestUInt value );
+   std::string JSON_API valueToString( double value );
+   std::string JSON_API valueToString( bool value );
+   std::string JSON_API valueToQuotedString( const char *value );
+
+   /// \brief Output using the StyledStreamWriter.
+   /// \see Json::operator>>()
+   std::ostream& operator<<( std::ostream&, const Value &root );
+
+} // namespace Json
+
+
+
+#endif // JSON_WRITER_H_INCLUDED