diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,674 +1,20 @@
-              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.
+Copyright (c) 2016 Alberto G. Corona
 
-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".
+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:
 
-  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 above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
 
-  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>.
+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.
diff --git a/src/Transient/MapReduce.hs b/src/Transient/MapReduce.hs
--- a/src/Transient/MapReduce.hs
+++ b/src/Transient/MapReduce.hs
@@ -1,12 +1,41 @@
 {-# LANGUAGE  ExistentialQuantification, DeriveDataTypeable
-, FlexibleInstances, FlexibleContexts, UndecidableInstances, MultiParamTypeClasses #-}
+, FlexibleInstances, MultiParamTypeClasses, OverloadedStrings, CPP #-}
 
 
-module Transient.MapReduce   (Distributable(..),distribute, getText, getUrl, getFile,textUrl, textFile, mapKeyB, mapKeyU, reduce) where
+module Transient.MapReduce
+--  (
+--Distributable(..),distribute, getText,
+--getUrl, getFile,textUrl, textFile,
+--mapKeyB, mapKeyU, reduce,eval,
+--PartRef)
+ where
+
+#ifdef ghcjs_HOST_OS
 import Transient.Base
-import Transient.Internals(onNothing)
 import Transient.Move hiding (pack)
 import Transient.Logged
+-- dummy Transient.MapReduce module,
+reduce _ _ = local stop :: Loggable a => Cloud a
+mapKeyB _ _= undefined
+mapKeyU _ _= undefined
+distribute _ = undefined
+getText _ _ = undefined
+textFile _ = undefined
+getUrl _ _ = undefined
+textUrl _ = undefined
+getFile _ _ = undefined
+eval _= local stop
+
+data DDS= DDS
+class Distributable
+data PartRef a=PartRef a
+
+#else
+
+import Transient.Base
+--import Transient.Internals((!>))
+import Transient.Move hiding (pack)
+import Transient.Logged
 import Transient.Indeterminism
 import Control.Applicative
 import System.Random
@@ -23,7 +52,7 @@
 import Control.Concurrent
 --import Data.Time.Clock
 import Network.HTTP
-import Data.TCache hiding (onNothing)
+import Data.TCache
 import Data.TCache.Defs
 
 import Data.ByteString.Lazy.Char8 (pack,unpack)
@@ -48,7 +77,8 @@
     key (Part _ string b _)= keyp string b
 
 
-keyp s True= "PartP@"++s
+
+keyp s True= "PartP@"++s :: String
 keyp s False="PartT@"++s
 
 instance Loggable a => IResource (Partition a) where
@@ -63,8 +93,8 @@
           unless (not save) $ defaultWrite (defPath s ++ key s) (pack $ show s)
 
 
-eval :: DDS a -> TransIO (PartRef a)
-eval (DDS mx) = runCloud mx
+eval :: DDS a -> Cloud (PartRef a)
+eval (DDS mx) =  mx
 
 
 type Path=String
@@ -110,6 +140,9 @@
    splitAt= DVU.splitAt
    fromList= DVU.fromList
 
+
+
+
 -- | perform a map and partition the result with different keys using boxed vectors
 -- The final result will be used by reduce.
 mapKeyB :: (Loggable a, Loggable b,  Loggable k,Ord k)
@@ -132,15 +165,15 @@
      => (a -> (k,b))
      -> DDS  (vector a)
      -> DDS (M.Map k (vector b))
-mapKey f (DDS mx)= DDS $  do
+mapKey f (DDS mx)= DDS $ loggedc $  do
         refs <-  mx
         process refs
 
   where
 --  process ::  Partition a -> Cloud [Partition b]
   process  (ref@(Ref node path sav))= runAt node $ local $ do
-              xs <- getPartitionData ref   -- !> "CMAP"
-              generateRef node $ map1 f xs
+              xs <- getPartitionData ref    -- !> ("CMAP", ref,node)
+              (generateRef  $ map1 f xs)
 
 
 
@@ -166,83 +199,88 @@
 reduce ::  (Hashable k,Ord k, Distributable vector a, Loggable k,Loggable a)
              => (a -> a -> a) -> DDS (M.Map k (vector a)) ->Cloud (M.Map k a)
 
-reduce red  (dds@(DDS mx))= do
-   box <- local newMailBox
-   nodes <- onAll getNodes
+reduce red  (dds@(DDS mx))= loggedc $ do
 
+   box <- lliftIO $ return . Text.pack =<<  replicateM  10 (randomRIO ('a','z'))
+   nodes <- local getNodes
+
    let lengthNodes = length nodes
-       shuffler=   do
-          ref <- mx
-          local $ do
-              mpairs <-  getPartitionData ref   -- !> "GETPARTITIONDATA" ::(M.Map k (vector a))
+       shuffler nodes = do
+          ref@(Ref node path sav) <- mx
+          return ()                                 -- !> ref
+          runAt node  $ local $ runCloud  ( foldAndSend  nodes ref)  -- <***    runCloud sendEnd
 
+          stop
 
-              runCloud ( shuffle mpairs) <*** runCloud sendEnd
+--     groupByDestiny :: (Hashable k, Distributable vector a)  => M.Map k (vector a) -> M.Map Int [(k ,vector a)]
+       groupByDestiny  map =  M.foldlWithKey' f M.empty  map
+              where
+--              f ::  M.Map Int [(k ,vector a)] -> k -> vector a -> M.Map Int [(k ,vector a)]
+              f map k vs= M.insertWith (<>) (hash1 k) [(k,vs)] map
+              hash1 k= abs $ hash k `rem` length nodes
 
-          stop
 
---       shuffle ::( Hashable k, Distributable vector a) =>M.Map k (vector a) -> Cloud ()
-       shuffle mpairs=do
-           let destinations= groupByDestiny mpairs  -- ::  M.Map Int (k, vector a)
-           parallelize foldAndSend $ M.assocs destinations
-           where
 --           foldAndSend :: (Hashable k, Distributable vector a)=> (Int,[(k,vector a)]) -> Cloud ()
-           foldAndSend (i,kvs)= do
-                    let folded= map (\(k,vs) -> (k,foldl1 red vs))  kvs
-                    runAt  (nodes !! i) $ local $ putMailBox box $ Reduce folded
+       foldAndSend nodes ref=  do
+                 nsent <-  onAll $ liftIO $ newMVar 0
+                 pairs <- onAll $ getPartitionData1 ref
+                            <|>  return (error $ "DDS computed out of his node:"++ show ref)
+                 let mpairs = groupByDestiny pairs
+                 length <- local . return $ M.size mpairs
+                 (i,folded) <- loggedc $ parallelize foldthem $  M.assocs  mpairs
 
-            --  agrupa segun nodo de destino:
+                 runAt (nodes !! i) $  (local $ putMailbox box $ Reduce folded)
+                                                            -- !> ("SEND REDUCE DATA",folded)
+                 n <- lliftIO $ modifyMVar nsent $ \r -> return (r+1, r+1)
+                 when (n == length) $ sendEnd  nodes
 
---           groupByDestiny :: (Hashable k, Distributable vector a)
---                          => M.Map k (vector a)
---                          -> M.Map Int [(k ,vector a)]
-           groupByDestiny map= M.foldlWithKey' f M.empty  map
               where
---              f ::  M.Map Int [(k ,vector a)] -> k -> vector a -> M.Map Int [(k ,vector a)]
-              f map k vs= M.insertWith f1 (hash1 k) [(k,vs)] map
+              foldthem (i,kvs)= local . async $ return  (i,map (\(k,vs) -> (k,foldl1 red vs)) kvs)
 
-              f1  v1 v2= v1<> v2
-              hash1 k= abs $ hash k `rem` length nodes
 
+       sendEnd nodes = onNodes nodes . local $  putMailbox box (EndReduce `asTypeOf` paramOf dds)
 
-       sendEnd =  (clustered $ local $ putMailBox box (EndReduce `asTypeOf` paramOf dds))
-                    -- !> "ENDREDUCE"
+       onNodes  nodes f= foldr (<|>) empty $ map (\n -> runAt n f ) nodes
 
+       sumNodes nodes f= foldr (<>) mempty $ map (\n -> runAt n f) nodes
 
-       reducer=   mclustered reduce1    -- a reduce1 process in each node, get the results and mappend them
+       reducer nodes=   sumNodes nodes reduce1    -- a reduce1 process in each node, get the results and mappend them
 
 --     reduce :: (Ord k)  => Cloud (M.Map k v)
 
-       reduce1 =  local $ do
-           reduceResults <- liftIO $ newMVar M.empty  -- !>  "CREATE MVAR for results"
-           numberSent <- liftIO $ newMVar 0
-           minput <- getMailBox box  -- get the chunk once it arrives to the mailbox
+       reduce1 = local $ do
+           reduceResults <- liftIO $ newMVar M.empty
+           numberSent    <- liftIO $ newMVar 0
 
-           case minput  of -- !> ("received",minput) of
+           minput <- getMailbox box  -- get the chunk once it arrives to the mailbox
+
+           case minput  of
+
              EndReduce -> do
+
                 n <- liftIO $ modifyMVar numberSent $ \r -> return (r+1, r+1)
-                if n == lengthNodes                         -- !> ( n, lengthNodes)
-                 then liftIO $ readMVar reduceResults     -- !> "END reduce"
+                if n == lengthNodes                  -- !>("END REDUCE RECEIVED",n, lengthNodes)
+                 then do
+                    cleanMailbox box (EndReduce `asTypeOf` paramOf dds)
+                    r <- liftIO $ readMVar reduceResults
+                    return r                         -- !> ("reduceresult",r)
 
                  else stop
 
-             Reduce kvs ->
-
-
-              do
+             Reduce kvs ->  do
                 let addIt (k,inp) = do
-                            let input= inp `asTypeOf` atype dds
-                            liftIO $ modifyMVar_ reduceResults
-                                   $ \map -> do
-                                      let maccum =  M.lookup k map
-                                      return $ M.insert k (case maccum of
-                                        Just accum ->  red input accum
-                                        Nothing    ->  input) map
-                mapM addIt  (kvs `asTypeOf` paramOf' dds)
+                        let input= inp `asTypeOf` atype dds
+                        liftIO $ modifyMVar_ reduceResults
+                               $ \map -> do
+                                  let maccum =  M.lookup k map
+                                  return $ M.insert k (case maccum of
+                                    Just accum ->  red input accum
+                                    Nothing    ->  input) map
+                mapM addIt  (kvs `asTypeOf` paramOf' dds)         -- !> ("Received Reduce",kvs)
                 stop
 
 
-   reducer <|> shuffler
+   reducer  nodes  <|>  shuffler nodes
    where
      atype ::DDS(M.Map k (vector a)) ->  a
      atype = undefined -- type level
@@ -252,74 +290,9 @@
      paramOf'  :: DDS (M.Map k (vector a)) ->  [( k,  a)]
      paramOf' = undefined -- type level
 
-{-
-reduce red  (dds@(DDS mx))= do
-   box <- local newMailBox
-   nodes <- onAll getNodes
 
-   let lengthNodes = length nodes
-       shuffler=   do
-          ref <- mx
-          local $ do
-              m <-  getPartitionData ref   -- !> "GETPARTITIONDATA"
-              let ass= M.assocs m
 
-              runCloud (parallelize shuffle ass) <*** runCloud sendEnd
 
-          stop
-
---       shuffle ::(k,vector a) -> Cloud ()
-       shuffle part | null part = empty
-                    | otherwise = do
-
-                         let (k,vs)= part
-                             v= foldl1 red vs
-                             i=  abs $ hash k `rem` length nodes
-                         runAt  (nodes !! i) $ local $ putMailBox box $ Reduce (k,v)
-                             -- !> (" PUTMAILBOX ",i,v)
-         stop   :: Cloud ()
-
-       sendEnd =  (clustered $ local $ putMailBox box (EndReduce `asTypeOf` paramOf dds))  -- !> "ENDREDUCE"
-
-
-       reducer=   mclustered reduce    -- a reduce process in each node
-
---     reduce :: (Ord k)  => Cloud (M.Map k v)
-
-       reduce =  local $ do
-           reduceResults <- liftIO $ newMVar M.empty  -- !>  "CREATE MVAR for results"
-           numberSent <- liftIO $ newMVar 0
-           minput <- getMailBox box  -- get the chunk once it arrives to the mailbox
-
-           case minput  of -- !> ("received",minput) of
-             Reduce (k,inp) -> do
-                let input= inp `asTypeOf` atype dds
-
-                liftIO $ modifyMVar_ reduceResults
-                       $ \map -> do
-                          let maccum =  M.lookup k map
-                          return $ M.insert k (case maccum of
-                            Just accum ->  red input accum
-                            Nothing    ->  input) map
-                empty
-
-             EndReduce -> do
-                n <- liftIO $ modifyMVar numberSent $ \r -> return (r+1, r+1)
-                if n == lengthNodes                         -- !> ( n, lengthNodes)
-                 then liftIO $ readMVar reduceResults     -- !> "END reduce"
-
-                 else empty
-
-   reducer <|> shuffler
-   where
-     atype ::DDS(M.Map k (vector a)) ->  a
-     atype = undefined -- type level
-
-     paramOf  :: DDS (M.Map k (vector a)) -> ReduceChunk( k,  a)
-     paramOf = undefined -- type level
--}
-
-
 --parallelize :: Loggable b => (a -> Cloud b) -> [a] -> Cloud b
 parallelize f xs =  foldr (<|>) empty $ map f xs
 
@@ -329,14 +302,36 @@
 
 
 getPartitionData :: Loggable a => PartRef a   -> TransIO  a
-getPartitionData (Ref node path save)  = do
-    (Part _ _ _ xs) <- (liftIO $ atomically
-                                   $ readDBRef
-                                   $ getDBRef
-                                   $ keyp path save)
-                              `onNothing` error ("not found DDS data: "++ keyp path save)
-    return xs  -- !> "getPartitionData"
+getPartitionData (Ref node path save)  = Transient $ do
+    mp <- (liftIO $ atomically
+                       $ readDBRef
+                       $ getDBRef
+                       $ keyp path save)
+                  `onNothing` error ("not found DDS data: "++ keyp path save)
+    case mp of
+       (Part _ _ _ xs) -> return $ Just xs
 
+getPartitionData1 :: Loggable a => PartRef a   -> TransIO  a
+getPartitionData1 (Ref node path save)  = Transient $ do
+    mp <- liftIO $ atomically
+                  $ readDBRef
+                  $ getDBRef
+                  $ keyp path save
+--                  `onNothing` error ("not found DDS data: "++ keyp path save)
+    case mp of
+      Just (Part _ _ _ xs) -> return $ Just xs
+      Nothing -> return Nothing
+
+getPartitionData2 :: Loggable a => PartRef a   -> IO  a
+getPartitionData2 (Ref node path save)  =  do
+    mp <- ( atomically
+                       $ readDBRef
+                       $ getDBRef
+                       $ keyp path save)
+                  `onNothing` error ("not found DDS data: "++ keyp path save)
+    case mp of
+       (Part _ _ _ xs) -> return  xs
+
 -- en caso de fallo de Node, se lanza un clustered en busca del path
 --   si solo uno lo tiene, se copia a otro
 --   se pone ese nodo de referencia en Part
@@ -386,35 +381,43 @@
    parallelize  move $ zip nodes xss   -- !> show xss
    where
    move (node, xs)=  runAt node $ local $ do
-                        par <- generateRef node xs
+                        par <- generateRef  xs
                         return  par
+          --   !> ("move", node,xs)
 
--- | input data from a text that must be static and shared by all the nodes
+-- | input data from a text that must be static and shared by all the nodes.
+-- The function parameter partition the text in words
 getText  :: (Loggable a, Distributable vector a) => (String -> [a]) -> String -> DDS (vector a)
-getText part str= DDS $ do
-   nodes <- onAll getNodes                                        -- !> "DISTRIBUTE"
+getText part str= DDS $ loggedc $ do
+   nodes' <- local getNodes                                        -- !> "DISTRIBUTE"
+   let nodes = filter (not . isWebNode) nodes'
    let lnodes = length nodes
 
-   parallelize  (process lnodes)  $ zip nodes [0..lnodes]    -- !> show xss
+   parallelize  (process lnodes)  $ zip nodes [0..lnodes-1]
    where
-   process lnodes (node,i)= runAt node $ local $   do
-                        let xs = part str
-                            size= case length xs `div` lnodes of 0 ->1 ; n -> n
-                            xss= Transient.MapReduce.fromList $ take size $ drop  (i *  size) xs
-                        par <- generateRef node xss
-                        return  par
+   isWebNode Node {nodeHost="webnode"}= True
+   isWebNode _= False
+   process lnodes (node,i)= do
+      runAt node $ local $ do
+            let xs = part str
+                size= case length xs `div` lnodes of 0 ->1 ; n -> n
+                xss= Transient.MapReduce.fromList $
+                       if i== lnodes-1 then drop (i* size) xs else  take size $ drop  (i *  size) xs
+            par <- generateRef  xss
+            (return  par)
 
 -- | get the worlds of an URL
 textUrl :: String -> DDS (DV.Vector Text.Text)
 textUrl= getUrl  (map Text.pack . words)
 
--- | generate a DDS from the content of a URL
+-- | generate a DDS from the content of a URL.
+-- The first parameter is a function that divide the text in words
 getUrl :: (Loggable a, Distributable vector a) => (String -> [a]) -> String -> DDS (vector a)
 getUrl partitioner url= DDS $ do
-   nodes <- onAll getNodes                                        -- !> "DISTRIBUTE"
+   nodes <- local getNodes                                        -- !> "DISTRIBUTE"
    let lnodes = length nodes
 
-   parallelize  (process lnodes)  $ zip nodes [0..lnodes]    -- !> show xss
+   parallelize  (process lnodes)  $ zip nodes [0..lnodes-1]    -- !> show xss
    where
    process lnodes (node,i)=  runAt node $ local $ do
                         r <- liftIO . simpleHTTP $ getRequest url
@@ -422,7 +425,7 @@
                         let xs = partitioner body
                             size= case length xs `div` lnodes of 0 ->1 ; n -> n
                             xss= Transient.MapReduce.fromList $ take size $ drop  (i *  size) xs
-                        generateRef node xss
+                        generateRef  xss
 
 
 -- | get the words of a file
@@ -436,23 +439,26 @@
    nodes <- local getNodes                                        -- !> "DISTRIBUTE"
    let lnodes = length nodes
 
-   parallelize  (process lnodes) $ zip nodes [0..lnodes]    -- !> show xss
+   parallelize  (process lnodes) $ zip nodes [0..lnodes-1]    -- !> show xss
    where
    process lnodes (node, i)=  runAt node $ local $ do
                         content <- liftIO $ readFile file
                         let xs = partitioner content
                             size= case length xs `div` lnodes of 0 ->1 ; n -> n
-                            xss=Transient.MapReduce.fromList $ take size $ drop  (i *  size) xs                                -- !> size
-                        generateRef node   xss
+                            xss=Transient.MapReduce.fromList $ take size $ drop  (i *  size) xs  -- !> size
+                        generateRef    xss
 
 
 
-generateRef :: Loggable a => Node -> a -> TransIO (PartRef a)
-generateRef node x=  liftIO $ do
+generateRef :: Loggable a =>  a -> TransIO (PartRef a)
+generateRef  x=  do
+    node <- getMyNode
+    liftIO $ do
        temp <- getTempName
        let reg=  Part node temp True  x
        atomically $ newDBRef reg
-       return $ getRef reg
+--       syncCache
+       (return $ getRef reg)     -- !> ("generateRef",reg,node)
 
 getRef (Part n t s x)= Ref n t s
 
@@ -479,13 +485,4 @@
 
 
 
---data CloudArray a= Cloud [a]
---
---instance functor  CloudArray where
---   fmap f mx= do
---        xs <- mx
---        xss <- partition xs
---        rss <- clustered f xss
---        return $ concat rss
-
-
+#endif
diff --git a/src/Transient/Move.hs b/src/Transient/Move.hs
--- a/src/Transient/Move.hs
+++ b/src/Transient/Move.hs
@@ -15,1233 +15,1305 @@
     ,GeneralizedNewtypeDeriving #-}
 module Transient.Move(
 
-Cloud(..),runCloudIO, runCloudIO',local,onAll, loggedc, lliftIO,
-listen, connect,
-
-wormhole, teleport, copyData,
-
-beamTo, forkTo, streamFrom, callTo, callTo',runAt,
-
-clustered, mclustered,
-
-newMailBox, putMailBox,getMailBox, sendNodeEvent, waitNodeEvents,
-setBuffSize, getBuffSize,
-
-createNode, createWebNode, getMyNode, setMyNode, getNodes,
-addNodes, shuffleNodes,
-
-
-
- getWebServerNode, Node(..), nodeList, Connection(..),MyNode(..), Service(),
- isBrowserInstance
-
-
-) where
-import Transient.Base
-import Transient.Internals(killChildren,getCont,runCont,EventF(..),LogElem(..),Log(..),onNothing,RemoteStatus(..),getCont)
-import Transient.Logged
-import Transient.EVars
-import Transient.Stream.Resource
-import Data.Typeable
-import Control.Applicative
-#ifndef ghcjs_HOST_OS
-import Network
-import Network.Info
-import qualified Network.Socket as NS
-import qualified Network.BSD as BSD
-import qualified Network.WebSockets as NS(sendTextData,receiveData, Connection,RequestHead(..),sendClose)
-import qualified Network.WebSockets.Connection   as WS
-import Network.WebSockets.Stream   hiding(parse)
-import           Data.ByteString       as B             (ByteString,concat)
-import qualified Data.ByteString.Char8 as BC
-import qualified Data.ByteString.Lazy as BL
-import Network.Socket.ByteString as SBS(send,sendMany,sendAll,recv)
-import Data.CaseInsensitive(mk)
-import Data.Char(isSpace)
---import GHCJS.Perch (JSString)
-#else
-import  JavaScript.Web.WebSocket
-import  qualified JavaScript.Web.MessageEvent as JM
-import GHCJS.Prim (JSVal)
-import GHCJS.Marshal(fromJSValUnchecked)
-import qualified Data.JSString as JS
-
-
-import           JavaScript.Web.MessageEvent.Internal
-import           GHCJS.Foreign.Callback.Internal (Callback(..))
-import qualified GHCJS.Foreign.Callback          as CB
-import Data.JSString  (JSString(..), pack)
-
-#endif
-
-
-import Control.Monad.State
-import System.IO
-import Control.Exception
-import Data.Maybe
-import Unsafe.Coerce
-
---import System.Directory
-import Control.Monad
-
-import System.IO.Unsafe
-import Control.Concurrent.STM as STM
-import Control.Concurrent.MVar
-
-import Data.Monoid
-import qualified Data.Map as M
-import Data.List (nub,(\\),find)
-import Data.IORef
-
-
-import qualified Data.ByteString.Lazy.Char8 as BS
-import System.IO
-
-import Control.Concurrent
-
-import System.Random
-
-
-
-import Data.Dynamic
-import Data.String
-
-
-#ifdef ghcjs_HOST_OS
-type HostName  = String
-newtype PortID = PortNumber Int deriving (Read, Show, Eq, Typeable)
-#endif
-data Node= Node{ nodeHost   :: HostName
-               , nodePort   :: PortID
-               , connection :: IORef Pool
-               , services   :: [Service]}
-         | WebNode{wconnection:: IORef Pool}
-         deriving (Typeable)
-
-instance Ord Node where
-   compare node1 node2= compare (nodeHost node1,nodePort node1)(nodeHost node2,nodePort node2)
-
--- The cloud monad is a thin layer over Transient in order to make sure that the type system
--- forces the logging of intermediate results
-newtype Cloud a= Cloud {runCloud ::TransIO a} deriving (Functor,Applicative, Alternative, Monad, MonadState EventF, Monoid)
-
-
--- | Means that this computation will be executed in the current node. the result will be logged
--- so the closure will be recovered if the computation is translated to other node by means of
--- primitives like `beamTo`, `forkTo`, `runAt`, `teleport`, `clustered`, `mclustered` etc
-local :: Loggable a => TransIO a -> Cloud a
-local =  Cloud . logged
-
-
-
--- #ifndef ghcjs_HOST_OS
--- | run the cloud computation.
-runCloudIO :: Cloud a -> IO a
-runCloudIO (Cloud mx)= keep mx
-
--- | run the cloud computation with no console input
-runCloudIO' :: Cloud a -> IO a
-runCloudIO' (Cloud mx)= keep' mx
-
--- #endif
-
--- | alternative to `local` It means that if the computation is translated to other node
--- this will be executed again if this has not been executed inside a `local` computation.
---
--- > onAll foo
--- > local foo'
--- > local $ do
--- >       bar
--- >       runCloud $ do
--- >               onAll baz
--- >               runAt node ....
--- > callTo node' .....
---
--- Here foo will be executed in node' but foo' bar and baz don't.
---
--- However foo bar and baz will e executed in node.
---
-
-onAll ::  TransIO a -> Cloud a
-onAll =  Cloud
-
--- log the result a cloud computation. like `loogged`, This eliminated all the log produced by computations
--- inside and substitute it for that single result when the computation is completed.
-loggedc (Cloud mx)= Cloud $ logged mx
-
-lliftIO :: Loggable a => IO a -> Cloud a
-lliftIO= local . liftIO
-
---remote :: Loggable a => TransIO a -> Cloud a
---remote x= Cloud $ step' x $ \full x ->  Transient $ do
---            let add= Wormhole: full
---            setSData $ Log False add add
---
---            r <-  runTrans x
---
---            let add= WaitRemote: full
---            (setSData $ Log False add add)     -- !!> "AFTER STEP"
---            return  r
-
----- | stop the current computation
---stop :: Cloud a
---stop= empty
-
--- | continue the execution in a new node
--- all the previous actions from `listen` to this statement must have been logged
-beamTo :: Node -> Cloud ()
-beamTo node =  local $ do
-  Log rec log _ <-  getSData <|> return (Log False [][])
-  if rec
-    then do
-      setSData WasRemote
-      return ()
-    else  do
-      msendToNode node $ SLast $ reverse log   -- !> "BEAMTO" -- !> ("beamto send", log)
-      empty
-
-
--- | execute in the remote node a process with the same execution state
--- all the previous actions from `listen` to this statement must have been logged
-forkTo  :: Node -> Cloud ()
-forkTo node= local $ do
-  Log rec log _<- getSData <|> return (Log False [][])
-  if rec
-    then do
-      setSData WasRemote
-      return ()
-    else  do
-      msendToNode node $ SLast $ reverse log
-
--- | executes an action in another node.
-callTo :: Loggable a => Node -> Cloud a -> Cloud a
-callTo node  remoteProc=
-   wormhole node $ do
-       teleport     -- !!> "TELEPORT to remote"
-       r <-  loggedc remoteProc
-       teleport     -- !!> "TELEPORT from remote"
-       return r
-
-
--- | synonymous of `callTo`
--- all the previous actions from `listen` to this statement must have been logged
-
-runAt :: Loggable a => Node -> Cloud a -> Cloud a
-runAt= callTo
-
-
-msendToNode node msg= do
-      conn <-  mconnect  node
-      liftIO $ msend conn msg
-
-
-msend :: Loggable a => Connection -> StreamData a -> IO ()
-
-
-#ifndef ghcjs_HOST_OS
-
-msend (Connection _(Just (Node2Node _ h sock)) _ _ blocked _ _ ) r= liftIO $ do
-  withMVar blocked $
-             const $ do
-                     hPutStrLn   h "LOG a b"
-                     hPutStrLn   h ""
-                     hPutStrLn h (show r)
-                     hFlush h                         -- !>  ("msend: ", r)
---             `catch` (\(e::SomeException) -> sClose sock)
-
-
-msend (Connection _(Just (Node2Web sconn)) _ _ blocked _ _) r=
-  withMVar blocked $ const $ NS.sendTextData sconn $ BS.pack (show r)
-
-
-#else
-
-msend (Connection _ (Just (Web2Node sconn)) _ _ blocked _ _) r=
-  withMVar blocked $ const $ JavaScript.Web.WebSocket.send  (JS.pack $ show r) sconn   -- !!> "MSEND SOCKET"
-
-
-
-#endif
-
-msend (Connection _ Nothing _ _  _ _ _ ) _= error "calling msend:  with no connection"
-
-mread :: Loggable a => Connection -> TransIO (StreamData a)
-#ifdef ghcjs_HOST_OS
-
-
-mread (Connection _ (Just (Web2Node sconn)) _ _ _ _ _)=  wsRead sconn
-
-
---wsAsk ws tosend= do
---   liftIO $ send ws tosend
---   wsRead ws
-
-
-wsRead :: Loggable a => WebSocket  -> TransIO  a
-wsRead ws= do
-  dat <- react (hsonmessage ws) (return ())
-  case JM.getData dat of
-    JM.StringData str  ->  return (read $ JS.unpack str)  --  !!> ("WSREAD RECEIVED " ++ show str)
-    JM.BlobData   blob -> error " blob"
-    JM.ArrayBufferData arrBuffer -> error "arrBuffer"
-
-{-
-wsRead1 :: Loggable a => WebSocket  -> TransIO (StreamData a)
-wsRead1 ws= do
-  reactStream (makeCallback MessageEvent) (js_onmessage ws) CB.releaseCallback (return ())
-  where
-  reactStream createHandler setHandler removeHandler iob= Transient $ do
-        cont    <- getCont
-        hand <- liftIO . createHandler $ \dat ->do
-              runStateT (setSData dat >> runCont cont) cont
-              iob
-        mEvData <- getSessionData
-        case mEvData of
-          Nothing -> liftIO $ do
-                        setHandler hand
-                        return Nothing
-
-          Just dat -> do
-             liftIO $ print "callback called 2*****"
-             delSessionData dat
-             dat' <- case getData dat of
-                 StringData str  -> liftIO $ putStrLn "WSREAD RECEIVED " >> print str >> return (read $ JS.unpack str)
-                 BlobData   blob -> error " blob"
-                 ArrayBufferData arrBuffer -> error "arrBuffer"
-             liftIO $ case dat' of
-               SDone -> do
-                        removeHandler $ Callback hand
-                        empty
-               sl@(SLast x) -> do
-                        removeHandler $ Callback hand     -- !!> "REMOVEHANDLER"
-                        return $ Just sl
-               SError e -> do
-                        removeHandler $ Callback hand
-                        print e
-                        empty
-               more -> return (Just  more)
--}
-
-
-wsOpen :: JS.JSString -> TransIO WebSocket
-wsOpen url= do
-   ws <-  liftIO $ js_createDefault url      --  !> ("wsopen",url)
-   react (hsopen ws) (return ())             -- !!> "react"
-   return ws                                 -- !!> "AFTER ReACT"
-
-foreign import javascript safe
-    "window.location.hostname"
-   js_hostname ::    JSVal
-
-foreign import javascript safe
-   "(function(){var res=window.location.href.split(':')[2];if (res === undefined){return 80} else return res.split('/')[0];})()"
-   js_port ::   JSVal
-
-foreign import javascript safe
-    "$1.onmessage =$2;"
-   js_onmessage :: WebSocket  -> JSVal  -> IO ()
-
-getWebServerNode _=
-
-    createNode  <$> ( fromJSValUnchecked js_hostname)
-                <*> (fromIntegral <$> (fromJSValUnchecked js_port :: IO Int))
-
-hsonmessage ::WebSocket -> (MessageEvent ->IO()) -> IO ()
-hsonmessage ws hscb= do
-  cb <- makeCallback MessageEvent hscb
-  js_onmessage ws cb
-
-foreign import javascript safe
-             "$1.onopen =$2;"
-   js_open :: WebSocket  -> JSVal  -> IO ()
-
-newtype OpenEvent = OpenEvent JSVal deriving Typeable
-hsopen ::  WebSocket -> (OpenEvent ->IO()) -> IO ()
-hsopen ws hscb= do
-   cb <- makeCallback OpenEvent hscb
-   js_open ws cb
-
-makeCallback :: (JSVal -> a) ->  (a -> IO ()) -> IO JSVal
-
-makeCallback f g = do
-   Callback cb <- CB.syncCallback1 CB.ContinueAsync (g . f)
-   return cb
-
-
-foreign import javascript safe
-   "new WebSocket($1)" js_createDefault :: JS.JSString -> IO WebSocket
-
-
-#else
-mread (Connection _(Just (Node2Node _ h _)) _ _ blocked _ _ ) =
-       parallel $ do
-              hGetLine h       -- to skip LOG header
-              hGetLine h
-              readHandler  h
-
-
-mread (Connection node  (Just (Node2Web sconn )) bufSize events blocked _ _ )=
-        parallel $ do
-            s <- NS.receiveData sconn
-            return . read $  BS.unpack s         -- !>  ("WS MREAD RECEIVED ---->", s)
-
-getWebServerNode port= return $ createNode "localhost" port
-#endif
-
-
--- | A wormhole opens a connection with another node anywhere in a computation.
-wormhole :: Loggable a => Node -> Cloud a -> Cloud a
-wormhole node (Cloud comp) = local $ Transient $ do
-
-   moldconn <- getData   -- !!> "wormhole"
-
-   Log rec log fulLog <- getData `onNothing` return (Log False [][])
---   initState
-   let lengthLog= length fulLog
-   if not rec                                                     -- !> ("recovery", rec)
-            then runTrans $ (do
-                conn <- mconnect node                             -- !> ("connecting node ", show node)
-                                                                  -- !> "wormhole local"
-
-                liftIO $ msend conn $ SLast $ reverse fulLog      -- !> ("wh sending ", show fulLog) -- SLast will disengage  the previous wormhole/listen
-
-                setSData $ conn{calling= True,offset= lengthLog}
-                (mread conn >>= check fulLog)  <|> return ()      -- !> "MREAD local"
---                putState    !!> "PUTSTATE"
-#ifdef ghcjs_HOST_OS
-                addPrefix    -- for the DOM identifiers
-#endif
-                comp)
-               <** (when (isJust moldconn) $ setSData (fromJust moldconn))
-                    -- <*** is not enough
-
-            else do
-
-             let oldconn = fromMaybe (error "wormhole: no connection in remote node") moldconn
-
-             if null log    -- has recovered state already
-
-              then do
-               setData $ oldconn{calling= False,offset= lengthLog}
-
-               runTrans $ do
-                  mlog <- mread oldconn
-                  check  fulLog mlog           -- !> ("MREAD remote",mlog)
-                  comp
-                 <** do
-                      setSData  oldconn
-                      setSData WasRemote       -- !> " set wasremote in wormhole"
-
-              else do   -- it is recovering a wormhole in the middle of a chain of nested wormholes
-                  setData $ oldconn{calling= False,offset= lengthLog}
-                  runTrans $ comp  <** setSData oldconn
-
-  where
-  -- for state recovery after a remote call.
-  -- it has problems so now the state variables are forwarded to the remote host and returned back
---  initState= do
---       rstat <-liftIO $ newIORef undefined
---       setSData rstat
---       stat <- gets mfData
---       liftIO $ writeIORef rstat stat
---
---  putState = do
---        rstate <- getSData <|> error "rstate not defined" :: TransIO (IORef(M.Map TypeRep SData))
---        st <- get
---        log@(Log _ _ l) <- getSData :: TransIO Log
---        con <-getSData :: TransIO Connection
---        mfDat <- liftIO $ readIORef rstate -- !!> show ("LOG BEFORe",  l)
---        put st {mfData= mfDat}
---        setSData log
---        setSData con
---
-
-
-
-  check fulLog mlog =
-   case  mlog    of                       -- !> ("RECEIVED ", mlog ) of
-             SError e -> do
-                 finish $ Just e
-                 empty
-
-             SDone -> finish Nothing >> empty
-             SMore log -> setSData (Log True log $ reverse log ++  fulLog ) -- !!> ("SETTING "++ show log)
-             SLast log -> setSData (Log True log $ reverse log ++  fulLog ) -- !!> ("SETTING "++ show log)
-
-#ifndef ghcjs_HOST_OS
-type JSString= String
-pack= id
-#endif
-
-
-newtype Prefix= Prefix JSString deriving(Read,Show)
-newtype IdLine= IdLine JSString deriving(Read,Show)
-data Repeat= Repeat | RepeatHandled JSString deriving (Eq, Read, Show)
-
-addPrefix= Transient $ do
-   r <- liftIO $ replicateM  5 (randomRIO ('a','z'))
-
---   n <- genId
---   Prefix s <- getData `onNothing` return ( Prefix "")
---   setSData $ Prefix (pack( 's': show n)<> s)
-   setSData $ Prefix $ pack  r
-   return $ Just ()
-
-
-
-
--- | teleport is a new primitive that translates computations back and forth
--- reusing an already opened connection.
-teleport :: Cloud ()
-teleport =  local $ Transient $ do
-    conn@Connection{calling= calling,offset= n} <- getData
-         `onNothing` error "teleport: No connection defined: use wormhole"
-    when  (saveVars conn) $ runTrans (do
-        let copyCounter= do
-               r <- local $ gets mfSequence
-               onAll $ modify $ \s -> s{mfSequence= r}
-        runCloud $ do
-            copyData $ Prefix ""
-            copyData $ IdLine ""
-            copyData $ Repeat
-            copyCounter)  >> return ()
-
-
-
-    Log rec log fulLog <- getData `onNothing` return (Log False [][])    -- !!> "TELEPORT"
-    if not rec
-      then  do
-         liftIO $ msend conn $ SMore $ drop n $ reverse fulLog
-                --  !!> ("TELEPORT LOCAL sending" ++ show (drop n $ reverse fulLog))
-                 -- will be read by wormhole remote
-         when (not calling) $ setData WasRemote  -- !> "setting WasRemote in telport"
---         getState   !!> "GETSTAT"
-         return Nothing
-      else do  delSData WasRemote                -- !> "deleting wasremote in teleport"
-
-               return (Just ())                             -- !!> "TELEPORT remote"
-
-   where
-#ifndef ghcjs_HOST_OS
-   saveVars Connection{connData= Just(Node2Node{})}= False
-#endif
-   saveVars _ = True
-
--- | copy session data variable from the local to the remote node.
--- The parameter is the default value if there is none set in the local node.
--- Then the default value is also set in the local node.
-copyData def = do
-  r <- local getSData <|> return def
-  onAll $ setSData r
-  return r
-
--- | `callTo` can stream data but can not inform the receiving process about the finalization. This call
--- does it.
-streamFrom :: Loggable a => Node -> Cloud (StreamData a) -> Cloud  (StreamData a)
-streamFrom = callTo
-
-
-
-{- All the previous actions from `listen` to this statement must have been logged
-streamFrom1 :: Loggable a => Node -> TransIO (StreamData a) -> TransIO  a -- (StreamData a)
-streamFrom1 node remoteProc= logged $ Transient $ do
-      liftIO $ print "STREAMFROM"
-      Log rec log fulLog <- getData `onNothing` return (Log False [][])
-      if rec
-         then
-          runTrans $ do
-            liftIO $ print "callTo Remote executing"
-            conn <- getSData  <|> error "callTo receive: no connection data"
-
-            r <- remoteProc                  -- !> "executing remoteProc" !> "CALLTO REMOTE" -- LOg="++ show fulLog
-            n <- liftIO $ msend conn  r      -- !> "sent response"
-            setSData WasRemote
-            stop
-          <|> do
-            setSData WasRemote
-            stop
-
-         else  do
-            cont <- getCont
-            runTrans $ process (return()) (mconnect node) (mcloseRelease cont node) $ \conn _ -> do
-
-                liftIO $ msend conn  (SLast $ reverse fulLog)  !> "CALLTO LOCAL" -- send "++ show  log
-
-                let log'= Wait:tail log
-                setData $ Log rec log' log'
-                liftIO $ print "mread in callTO"
-                mread conn
-
-      where
-      mcloseRelease :: EventF -> Node -> Connection -> Maybe SomeException -> IO ()
-      mcloseRelease cont node conn reason=
-         case reason of
-            Nothing -> release node conn
-            Just r -> do
-              forkIO $ mclose conn
-
-              killChildren cont
--}
-   {-
-         runTrans $ do
-            conn <-  mconnect  node !> "mconnect"
-            onFinish $ \_ -> do
-                   liftIO $ print "MCLOSE"
-                   liftIO $ mclose conn
-                   c <- getCont
-                   liftIO $ killChildren c -- liftIO $ myThreadId >>= \th -> liftIO (print th) >> killThread th
-
-
-            liftIO $ msend conn  (SLast $ reverse fulLog)  !> "CALLTO LOCAL" -- send "++ show  log
-
-            let log'= Wait:tail log
-            setData $ Log rec log' log'
-            liftIO $ print "mread in callTO"
-            r <- mread conn
---              adjustRecThreads h
-
-            case r of
-                 SError e -> do
-                     liftIO $ do
-                        release node conn
-                        print e
-                     stop
-                 SDone ->  release node conn >> empty
-                 smore@(SMore x) -> return smore
-                 other ->  release node conn >> return other
-
--}
---      where
---      adjustRecThreads h= do
---          b <- liftIO $ hWaitForInput  h 1
---          addThreads' $ if b then 1 else 0
---          liftIO $ putStrLn $ "REC "++ show (case b of True -> "INC" ; _ -> "DEC")999999*
---
---      adjustSenderThreads n
---         | n > 2 = addThreads' (-1)  >> liftIO (putStrLn ("SEND DEC"))
---         | n==0 = addThreads' 1  >> liftIO (putStrLn ("SEND INC"))
---         | otherwise= return () >> liftIO(myThreadId >>= \th -> (putStrLn ("SEND "++ show th)))
-
-release (Node h p rpool _) hand= liftIO $ do
---    print "RELEASED"
-    atomicModifyIORef rpool $  \ hs -> (hand:hs,())
-      -- !!> "RELEASED"
-
-mclose :: Connection -> IO ()
-#ifndef ghcjs_HOST_OS
-mclose (Connection _  (Just (Node2Node _ h sock )) _ _ _ _ _ )= hClose h  -- !!> "Handle closed"
-mclose (Connection node  (Just (Node2Web sconn )) bufSize events blocked _ _ )= NS.sendClose sconn ("closemsg" ::ByteString)
-#else
-mclose (Connection _ (Just (Web2Node sconn)) _ _ blocked _ _)= JavaScript.Web.WebSocket.close Nothing Nothing sconn
-#endif
-
-mconnect :: Node -> TransIO Connection
-mconnect  (Node host port  pool _)=  do
-    mh <- liftIO $ atomicModifyIORef pool $ \mh ->
-      case mh of
-       (handle:hs) -> (hs,Just handle)
-       [] -> ([],Nothing)
-    case mh of
-      Just handle ->  return handle   -- !!>   "REUSED!"
-
-      Nothing -> do
-        Connection{comEvent= ev} <- getSData <|> error "connect: listen not set for this node"
-#ifndef ghcjs_HOST_OS
-
-        liftIO $ do
-          let size=8192
-          h <-  connectTo' size host port   -- !!> ("CONNECTING "++ show port)
-          hSetBuffering h $ BlockBuffering $ Just size
-
-          let conn= (defConnection 8100){comEvent= ev,connData= Just $ Node2Node u h u}
---          writeIORef pool [conn]
-          return conn
-#else
-        do
-          ws <- connectToWS host port
-          let conn= (defConnection 8100){myNode=(),comEvent= ev,connData= Just $ Web2Node ws}
---          liftIO $ writeIORef pool [conn]
-          return conn
-#endif
-  where u= undefined
-
-mconnect _ = empty
-
-
-
-#ifndef ghcjs_HOST_OS
-connectTo' bufSize hostname (PortNumber port) =  do
-        proto <- BSD.getProtocolNumber "tcp"
-        bracketOnError
-            (NS.socket NS.AF_INET NS.Stream proto)
-            (sClose)  -- only done if there's an error
-            (\sock -> do
-              NS.setSocketOption sock NS.RecvBuffer bufSize
-              NS.setSocketOption sock NS.SendBuffer bufSize
-              he <- BSD.getHostByName hostname
-              NS.connect sock (NS.SockAddrInet port (BSD.hostAddress he))
-
-              NS.socketToHandle sock ReadWriteMode
-            )
-#else
-connectToWS  h (PortNumber p) =
-   wsOpen $ JS.pack $ "ws://"++ h++ ":"++ show p
-#endif
-#ifndef ghcjs_HOST_OS
--- | A connectionless version of callTo for long running remote calls
--- myNode should be set with `setMyNode`
-callTo' :: (Show a, Read a,Typeable a) => Node -> Cloud a -> Cloud a
-callTo' node remoteProc=  do
-    mynode <-  getMyNode
-    beamTo node
-    r <-  remoteProc
-    beamTo mynode
-    return r
-#endif
-
-type Blocked= MVar ()
-type BuffSize = Int
-data ConnectionData=
-#ifndef ghcjs_HOST_OS
-                   Node2Node{port :: PortID
-                              ,handle :: Handle
-                              ,socket ::Socket
-                                   }
-
-                   | Node2Web{webSocket :: NS.Connection}
-#else
-
-                   Web2Node{webSocket :: WebSocket}
-#endif
-
-
-#ifndef ghcjs_HOST_OS
-data Connection= Connection{myNode :: TVar  MyNode
-#else
-data Connection= Connection{myNode :: ()
-#endif
-                           ,connData :: (Maybe(ConnectionData))
-                           ,bufferSize ::BuffSize
-                           ,comEvent :: EVar Dynamic
-                           ,blocked :: Blocked
-                           ,calling :: Bool
-                           ,offset  :: Int}
-                  deriving Typeable
-
--- | Updates the mailbox of another node. It means that the data is transported trough the network
--- The call does not end until the mailbox entry is porcessed in the remote node.
--- Mailboxes are node-wide, for all processes that share the same connection data, that is, are under the
--- same `listen`  or `connect`
--- while EVars scope are visible for the process where they are initialized and their children.
--- Internally a mailbox is a well known EVar stored by `listen` in the `Connection` state.
-sendRemoteNodeEvent :: Loggable a => Node -> a -> Cloud ()
-sendRemoteNodeEvent node dat= runAt node $ local $ sendNodeEvent dat
-
-newMailBox :: MonadIO m => m String
-newMailBox= liftIO $ replicateM  10 (randomRIO ('a','z'))
-
-putMailBox name dat= sendNodeEvent (name, dat)
-getMailBox name= do
-     (nam, dat) <- waitNodeEvents
-     if nam /= name then empty else  return dat
-
--- | updates the local mailbox.
-sendNodeEvent :: Typeable a => a -> TransIO ()
-sendNodeEvent dat=  Transient $ do
-   Connection{comEvent=comEvent}<- getData
-          `onNothing` error "sendNodeEvent: accessing network events out of listen"
-   (runTrans $  writeEVar comEvent $ toDyn dat)  -- !> "PUTMAILBOXX"
-
-
--- | wait until a message of the type expected appears in the mailbox. Then executes the continuation
--- When the message appears, all the waiting `waitNodeEvents` are executed from newer to the older
--- following the `readEVar` order.
-waitNodeEvents :: Loggable a => TransIO a
-waitNodeEvents = Transient $  do
-       Connection{comEvent=comEvent} <- getData `onNothing` error "waitNodeEvents: accessing network events out of listen"
-       runTrans  $ do
-                     d <-  readEVar comEvent
-                     case fromDynamic d of
-                      Nothing -> empty
-                      Just x -> do
-                         writeEVar comEvent $ toDyn ()
-                         return x
-
-
-
-defConnection :: Int -> Connection
-
-#ifndef ghcjs_HOST_OS
-defConnection size=
- Connection (unsafePerformIO $  newTVarIO $ MyNode  $ createNode "invalid" 0) Nothing  size
-                 (error "defConnection: accessing network events out of listen")
-                 (unsafePerformIO $ newMVar ())
-                 False 0
-#else
-defConnection size= Connection () Nothing  size
-                 (error "defConnection: accessing network events out of listen")
-                 (unsafePerformIO $ newMVar ())
-                 False 0
-#endif
-
-
-#ifndef ghcjs_HOST_OS
-setBuffSize :: Int -> TransIO ()
-setBuffSize size= Transient $ do
-   conn<- getData `onNothing` return (defConnection 8192)
-   setData $ conn{bufferSize= size}
-   return $ Just ()
-
-getBuffSize=
-  (do getSData >>= return . bufferSize) <|> return  8192
-
-readHandler h= do
-    line <- hGetLine h
-
-    let [(v,left)]= readsPrec 0 line
-
-    return  v         --  !>  line
-
-  `catch` (\(e::SomeException) -> return $ SError   e)
---   where
---   hGetLine' h= do
-
-
-
-
-
-
---listen ::  Node ->  TransIO ()
---listen  (node@(Node _  port _ _)) = do
---   addThreads 1
---   setMyNode node
---   setSData $ Log False [] []
---
---   Connection node  _ bufSize events blocked <- getSData <|> return (defConnection 8192)
---
---   sock <- liftIO $  listenOn  port
---   liftIO $ do NS.setSocketOption sock NS.RecvBuffer bufSize
---               NS.setSocketOption sock NS.SendBuffer bufSize
---   SMore(h,host,port1) <- parallel $ (SMore <$> accept sock)
---                          `catch` (\(e::SomeException) -> do
---                               print "socket exception"
---                               sClose sock
---                               return SDone)
---
---
---   setSData $ Connection node  (Just (Node2Node port h sock )) bufSize events blocked
---
---   liftIO $  hSetBuffering h LineBuffering -- !> "LISTEN in "++ show (h,host,port1)
---
---   mlog <- parallel $ readHandler h
---
---   case  mlog  of
---         SError e -> do
---             liftIO $ do
---                hClose h
---                putStr "listen: "
---                print e
---             stop
---
---         SDone -> liftIO (hClose h) >> stop
---         SMore log -> setSData $ Log True log (reverse log)
---         SLast log -> setSData $ Log True log (reverse log)
-
-listen ::  Node ->  Cloud ()
-listen  (node@(Node _  (PortNumber port) _ _)) = onAll $ do
-   addThreads 1
-   setMyNode node
-   setSData $ Log False [] []
-
-   Connection node  _ bufSize events blocked _ _ <- getSData <|> return (defConnection 8192)
-
-   sock <- liftIO . listenOn  $ PortNumber port
-
-   liftIO $ do NS.setSocketOption sock NS.RecvBuffer bufSize
-               NS.setSocketOption sock NS.SendBuffer bufSize
-
-
-   (conn,_) <- waitEvents $  NS.accept sock         -- !!> "BEFORE ACCEPT"
-
-
-   h <- liftIO $ NS.socketToHandle conn ReadWriteMode      -- !!> "NEW SOCKET CONNECTION"
-
---   let conn= Connection node  (Just (Node2Node port h sock )) bufSize events blocked
---   setSData conn
---   mlog <- mread conn
-
-   (method,uri, headers) <- receiveHTTPHead h
---   liftIO $ print ("RECEIVED ---------->",method,uri, headers)
-   mlog <- case method of
-     "LOG" ->
-          do
-           setSData $ (Connection node  (Just (Node2Node (PortNumber port) h sock ))
-                         bufSize events blocked False 0  :: Connection)
-           parallel $ readHandler  h       -- !!> "read Listen"  -- :: TransIO (StreamData [LogElem])
-     _ -> do
-           sconn <- httpMode (method,uri, headers) conn
-           setSData $ (Connection node  (Just (Node2Web sconn ))
-                         bufSize events blocked False 0 :: Connection)
-
-           parallel $ do
-               msg <- WS.receiveData sconn
---               liftIO $ print ("WS RECEIVED: ", msg)
-               return . read $ BC.unpack msg
-
-   -- liftIO $ putStr "LISTEN RECEIVED " >> print mlog
-
-   case  mlog  of
-             SError e -> do
-                 liftIO $ do
-                    hClose h
-                    putStr "listen: "
-                    print e
---                 killChilds
-                 c <- getCont
-                 liftIO $ killChildren . fromJust $ parent c
-                 empty
-
-             SDone ->  empty -- liftIO (hClose h) >> stop
-             SMore log -> setSData $ Log True log (reverse log)
-             SLast log -> setSData $ Log True log (reverse log)
---   liftIO $ print "END LISTEN"
-
-
-
-instance Read PortNumber where
-  readsPrec n str= let [(n,s)]=   readsPrec n str in [(fromIntegral n,s)]
-
-
-deriving instance Read PortID
-deriving instance Typeable PortID
-#endif
-
-
-type Pool= [Connection] --  Pool{free :: [Handle], pending :: Int}
-type Package= String
-type Program= String
-type Service= (Package, Program, Int)
-
-
--- * Level 2: connections node lists and operations with the node list
-
-
-{-# NOINLINE emptyPool #-}
-emptyPool :: MonadIO m => m (IORef Pool)
-emptyPool= liftIO $ newIORef  []
-
-createNode :: HostName -> Integer -> Node
-createNode h p= Node h ( PortNumber $ fromInteger p) (unsafePerformIO emptyPool) []
-
-createWebNode= WebNode  (unsafePerformIO emptyPool)
-
-instance Eq Node where
-    Node h p _ _ ==Node h' p' _ _= h==h' && p==p'
-    _ == _ = False
-
-instance Show Node where
-    show (Node h p _ servs)= show (h,p,servs)
-    show (WebNode _)= "webnode"
-
-instance Read Node where
-    readsPrec _ ('w':'e':'b':'n':'o':'d':'e':xs)=
-          [(WebNode . unsafePerformIO $ emptyPool, xs)]
-    readsPrec _ s=
-          let r= readsPrec 0 s
-          in case r of
-            [] -> []
-            [((h,p,ss),s')] ->  [(Node h p empty ss,s')]
-          where
-          empty= unsafePerformIO  emptyPool
-
-newtype MyNode= MyNode Node deriving(Read,Show,Typeable)
-
-
---instance Indexable MyNode where key (MyNode Node{nodePort=port}) =  "MyNode "++ show port
---
---instance Serializable MyNode where
---    serialize= BS.pack . show
---    deserialize= read . BS.unpack
-
-nodeList :: TVar  [Node]
-nodeList = unsafePerformIO $ newTVarIO []
-
-deriving instance Ord PortID
-
---myNode :: Int -> DBRef  MyNode
---myNode= getDBRef $ key $ MyNode undefined
-
-
-
-
-
-
-errorMyNode f= error $ f ++ ": Node not set. Use setMynode before listen"
-
-#ifdef ghcjs_HOST_OS
-getMyNode :: Cloud ()
-getMyNode= return ()
-
-setMyNode :: Node -> TransIO ()
-setMyNode node= do
-        addNodes [node]
-        events <- newEVar
-        let conn= Connection () Nothing 8192 events (unsafePerformIO $ newMVar ()) False 0  :: Connection
-        setData conn
-#else
-
-getMyNode :: Cloud Node
-getMyNode = local $ do
-    Connection{myNode=rnode} <- getSData <|> errorMyNode "getMyNode"
-    MyNode node <- liftIO $ atomically $ readTVar rnode  -- `onNothing` errorMyNode "getMyNode"
-    return node
-
-
-
-setMyNode :: Node -> TransIO ()
-setMyNode node= do
-        addNodes [node]
-        events <- newEVar
-        rnode <- liftIO $ newTVarIO $ MyNode node
-        let conn= Connection rnode Nothing 8192 events (unsafePerformIO $ newMVar ()) False 0  :: Connection
-        setData conn
---        return $ Just ()
-#endif
-
--- | return the list of nodes connected to the local node
-getNodes :: MonadIO m => m [Node]
-getNodes  = liftIO $ atomically $ readTVar  nodeList
-
-addNodes :: (MonadIO m, MonadState EventF m) => [Node] -> m ()
-addNodes   nodes=  do
-#ifndef ghcjs_HOST_OS
-  mapM_ verifyNode nodes -- if the node is a web one, add his connection
-#endif
-  liftIO . atomically $ do
-    prevnodes <- readTVar nodeList
-    writeTVar nodeList $ nub $ nodes ++ prevnodes
-
-#ifndef ghcjs_HOST_OS
-verifyNode (WebNode pool)= do
-  r <- getData `onNothing` error "adding web node without connection set"
-  case r of
-   conn@(Connection{connData= Just( Node2Web ws)}) ->
-            liftIO $ writeIORef pool [conn]
-   other -> return ()
-
-verifyNode n= return ()
-#endif
-
-shuffleNodes :: MonadIO m => m [Node]
-shuffleNodes=  liftIO . atomically $ do
-  nodes <- readTVar nodeList
-  let nodes'= tail nodes ++ [head nodes]
-  writeTVar nodeList nodes'
-  return nodes'
-
---getInterfaces :: TransIO TransIO HostName
---getInterfaces= do
---   host <- logged $ do
---      ifs <- liftIO $ getNetworkInterfaces
---      liftIO $ mapM_ (\(i,n) ->putStrLn $ show i ++ "\t"++  show (ipv4 n) ++ "\t"++name n)$ zip [0..] ifs
---      liftIO $ putStrLn "Select one: "
---      ind <-  input ( < length ifs)
---      return $ show . ipv4 $ ifs !! ind
-
-
--- | execute a Transient action in each of the nodes connected.
---
--- The response of each node is received by the invoking node and processed by the rest of the procedure.
--- By default, each response is processed in a new thread. To restrict the number of threads
--- use the thread control primitives.
---
--- this snippet receive a message from each of the simulated nodes:
---
--- > main = keep $ do
--- >    let nodes= map createLocalNode [2000..2005]
--- >    addNodes nodes
--- >    (foldl (<|>) empty $ map listen nodes) <|> return ()
--- >
--- >    r <- clustered $ do
--- >               Connection (Just(PortNumber port, _, _, _)) _ <- getSData
--- >               return $ "hi from " ++ show port++ "\n"
--- >    liftIO $ putStrLn r
--- >    where
--- >    createLocalNode n= createNode "localhost" (PortNumber n)
-clustered :: Loggable a  => Cloud a -> Cloud a
-clustered proc= loggedc $ do
-     nodes <-  onAll getNodes
-     foldr (<|>) empty $ map (\node -> runAt node proc) nodes  -- !> ("clustered",nodes)
-
-
-
--- A variant of `clustered` that wait for all the responses and `mappend` them
-mclustered :: (Monoid a, Loggable a)  => Cloud a -> Cloud a
-mclustered proc= loggedc $ do
-     nodes <-  onAll getNodes
-     foldr (<>) mempty $ map (\node -> runAt node proc) nodes  -- !> ("mclustered",nodes)
-
--- | Initiates the transient monad, initialize it as a new node (first parameter) and connect it
--- to an existing node (second parameter).
--- The other node will notify about this connection to
--- all the nodes connected to him. this new connected node will receive the list of nodes
--- the local list of nodes then is updated with this list. it can be retrieved with `getNodes`
-
-connect ::  Node ->  Node -> Cloud ()
-connect  node  remotenode =   do
-    listen node <|> return () -- listen1 node remotenode
-    local $ liftIO $ putStrLn $ "connecting to: "++ show remotenode
-    newnode <- local $ return node -- must pass my node to the remote node or else it will use his own
-
-    nodes <- runAt remotenode $  do
-                   mclustered $ onAll $ addNodes [newnode]
-                   onAll $ do
-                      liftIO $ putStrLn $ "Connected node: " ++ show node
-                      getNodes
-
-    onAll $ liftIO $ putStrLn $ "Connected to nodes: " ++ show nodes
-    onAll $ addNodes nodes
-
-
---------------------------------------------
-
-
-#ifndef ghcjs_HOST_OS
-httpMode (method,uri, headers) conn  = do
-   if isWebSocketsReq headers
-     then  liftIO $ do
-
-         stream <- makeStream                  -- !!> "WEBSOCKETS request"
-            (do
-                bs <- SBS.recv conn  4096
-                return $ if BC.null bs then Nothing else Just bs)
-            (\mbBl -> case mbBl of
-                Nothing -> return ()
-                Just bl ->  SBS.sendMany conn (BL.toChunks bl) >> return())   -- !!> show ("SOCK RESP",bl)
-
-         let
-             pc = WS.PendingConnection
-                { WS.pendingOptions     = WS.defaultConnectionOptions
-                , WS.pendingRequest     =  NS.RequestHead uri headers False -- RequestHead (BC.pack $ show uri)
-                                                      -- (map parseh headers) False
-                , WS.pendingOnAccept    = \_ -> return ()
-                , WS.pendingStream      = stream
-                }
-
-
-         sconn    <- WS.acceptRequest pc               -- !!> "accept request"
-         WS.forkPingThread sconn 30
-         return sconn
-
-
-
-     else do
-          let uri'= BC.tail $ uriPath uri               -- !> "HTTP REQUEST"
-              file= if BC.null uri' then "index.html" else uri'
-
-          content <- liftIO $  BL.readFile ( "static/out.jsexe/"++ BC.unpack file)
-                            `catch` (\(e:: SomeException) -> return "NOT FOUND")
-          return ()
-          n <- liftIO $ SBS.sendMany conn   $  ["HTTP/1.0 200 OK\nContent-Type: text/html\nConnection: close\nContent-Length: " <> BC.pack (show $ BL.length content) <>"\n\n"] ++
-                                  (BL.toChunks content )
-          return ()    -- !> "HTTP sent"
-          empty
-
-      where
-      uriPath = BC.dropWhile (/= '/')
-
-
-
-isWebSocketsReq = not  . null
-    . filter ( (== mk "Sec-WebSocket-Key") . fst)
-
-
-
-data ParseContext a = ParseContext (IO  a) a deriving Typeable
-
-
---giveData h= do
---    r <- BC.hGetLine h
---    return r !> ( "RECEIVED "++ show r)
-
-giveData h= do
-
-   r <- readIORef rend
-
-   if r then return "" else do
-    r<- BC.hGetLine h                    -- !!> "GETLINE"
-
-    if r=="\r" || r == "" then do
-       writeIORef rend True
-       return ""
-       else return r
-  where
-  rend= unsafePerformIO $ newIORef False
-
-
-receiveHTTPHead h = do
-  setSData $ ParseContext (giveData h) ""
-  (method, uri, vers) <- (,,) <$> getMethod <*> getUri <*> getVers
-  headers <- many $ (,) <$> (mk <$> getParam) <*> getParamValue    -- !>  (method, uri, vers)
-  return (method, uri, headers)                                    -- !>  (method, uri, headers)
-
-  where
-
-  getMethod= getString
-  getUri= getString
-  getVers= getString
-  getParam= do
-      dropSpaces
-      r <- tTakeWhile (\x -> x /= ':' && x /= '\r')
-      if BC.null r || r=="\r"  then  empty  else  dropChar >> return r
-
-  getParamValue= dropSpaces >> tTakeWhile  (/= '\r')
-
-  dropSpaces= parse $ \str ->((),BC.dropWhile isSpace str)
-
-  dropChar= parse  $ \r -> ((), BC.tail r)
-
-  getString= do
-    dropSpaces
-
-    tTakeWhile (not . isSpace)
-
-  tTakeWhile :: (Char -> Bool) -> TransIO BC.ByteString
-  tTakeWhile cond= parse (BC.span cond)
-
-  parse :: (Typeable a, Eq a, Show a, Monoid a,Monoid b) => (a -> (b,a)) -> TransIO b
-  parse split= do
-    ParseContext rh str <- getSData <|> error "parse: ParseContext not found"
-    if  str == mempty then do
-          str3 <- liftIO  rh
-
-          setSData $ ParseContext rh str3                     -- !> str3
-
-          if str3== mempty then empty   else  parse split
-
-       else do
-
-          cont <- do
-             let (ret,str3) = split str
-             setSData $ ParseContext rh str3
-             if  str3 == mempty
-                then  return $ Left ret
-                else  return $ Right ret
-          case cont of
-            Left r  ->  (<>) <$> return r  <*> (parse split <|> return mempty)
-
-            Right r ->   return r
-
-
-
-
-#endif
-
-#ifdef ghcjs_HOST_OS
-isBrowserInstance= True
-
-listen node = onAll $ setMyNode node
---   return () -- error "listen not implemented in browser"
+Cloud(..),runCloudIO, runCloudIO',local,onAll,lazy, loggedc, lliftIO,localIO,
+listen, Transient.Move.connect, connect', fullStop,
+
+wormhole, teleport, copyData,
+
+beamTo, forkTo, streamFrom, callTo, runAt, atRemote,
+
+clustered, mclustered,
+
+newMailbox, putMailbox,getMailbox,cleanMailbox,
+
+#ifndef ghcjs_HOST_OS
+setBuffSize, getBuffSize,
+#endif
+
+createNode, createWebNode, getMyNode, getNodes,
+addNodes, shuffleNodes,
+
+-- * low level
+
+ getWebServerNode, Node(..), nodeList, Connection(..), Service(),
+ isBrowserInstance, Prefix(..), addPrefix
+ ,defConnection
+
+
+) where
+import Transient.Base
+import Transient.Internals(killChildren,getCont,runCont,EventF(..),LogElem(..),Log(..)
+       ,onNothing,RemoteStatus(..),getCont,StateIO,readsPrec')
+import Transient.Logged
+import Transient.EVars
+import Data.Typeable
+import Control.Applicative
+#ifndef ghcjs_HOST_OS
+import Network
+import Network.Info
+import qualified Network.Socket as NS
+import qualified Network.BSD as BSD
+import qualified Network.WebSockets as NWS(RequestHead(..))
+
+import qualified Network.WebSockets.Connection   as WS
+
+
+import Network.WebSockets.Stream   hiding(parse)
+import           Data.ByteString       as B             (ByteString,concat)
+import qualified Data.ByteString.Char8 as BC
+import qualified Data.ByteString.Lazy.Char8 as BLC
+import qualified Data.ByteString.Lazy as BL
+import Network.Socket.ByteString as SBS(send,sendMany,sendAll,recv)
+import Data.CaseInsensitive(mk)
+import Data.Char(isSpace)
+--import GHCJS.Perch (JSString)
+#else
+import  JavaScript.Web.WebSocket
+import  qualified JavaScript.Web.MessageEvent as JM
+import GHCJS.Prim (JSVal)
+import GHCJS.Marshal(fromJSValUnchecked)
+import qualified Data.JSString as JS
+
+
+import           JavaScript.Web.MessageEvent.Internal
+import           GHCJS.Foreign.Callback.Internal (Callback(..))
+import qualified GHCJS.Foreign.Callback          as CB
+import Data.JSString  (JSString(..), pack)
+
+#endif
+
+import qualified Data.Text as T
+import Control.Monad.State
+import System.IO
+import Control.Exception
+import Data.Maybe
+import Unsafe.Coerce
+
+--import System.Directory
+import Control.Monad
+
+import System.IO.Unsafe
+import Control.Concurrent.STM as STM
+import Control.Concurrent.MVar
+
+import Data.Monoid
+import qualified Data.Map as M
+import Data.List (nub,(\\),find, insert)
+import Data.IORef
+
+
+import qualified Data.ByteString.Lazy.Char8 as BS
+import System.IO
+
+import Control.Concurrent
+
+import System.Random
+
+
+
+import Data.Dynamic
+import Data.String
+
+
+#ifdef ghcjs_HOST_OS
+type HostName  = String
+newtype PortID = PortNumber Int deriving (Read, Show, Eq, Typeable)
+#endif
+data Node= Node{ nodeHost   :: HostName
+               , nodePort   :: Int
+               , connection :: MVar Pool
+               , nodeServices   :: [Service]
+               }
+
+         deriving (Typeable)
+
+instance Ord Node where
+   compare node1 node2= compare (nodeHost node1,nodePort node1)(nodeHost node2,nodePort node2)
+
+-- The cloud monad is a thin layer over Transient in order to make sure that the type system
+-- forces the logging of intermediate results
+newtype Cloud a= Cloud {runCloud ::TransIO a} deriving (Functor,Applicative,Alternative, Monad, MonadState EventF, Monoid)
+
+
+--instance Alternative Cloud where
+--  empty= Cloud empty
+--
+--  Cloud x <|>  Cloud y= Cloud $  Transient $ do
+--         mx <- runTrans x                -- !!> "RUNTRANS11111"
+--         was <- getData `onNothing` return NoRemote
+--         if was== WasRemote              -- !> was
+--           then return Nothing
+--           else case mx of
+--                     Nothing -> runTrans y      --  !!> "RUNTRANS22222"
+--                     justx -> return justx
+
+
+-- | Means that this computation will be executed in the current node. the result will be logged
+-- so the closure will be recovered if the computation is translated to other node by means of
+-- primitives like `beamTo`, `forkTo`, `runAt`, `teleport`, `clustered`, `mclustered` etc
+local :: Loggable a => TransIO a -> Cloud a
+local =  Cloud . logged
+
+--stream :: Loggable a => TransIO a -> Cloud (StreamVar a)
+--stream= Cloud . transport
+
+-- #ifndef ghcjs_HOST_OS
+-- | run the cloud computation.
+runCloudIO :: Cloud a -> IO a
+runCloudIO (Cloud mx)= keep mx
+
+-- | run the cloud computation with no console input
+runCloudIO' :: Cloud a -> IO a
+runCloudIO' (Cloud mx)= keep' mx
+
+-- #endif
+
+-- | alternative to `local` It means that if the computation is translated to other node
+-- this will be executed again if this has not been executed inside a `local` computation.
+--
+-- > onAll foo
+-- > local foo'
+-- > local $ do
+-- >       bar
+-- >       runCloud $ do
+-- >               onAll baz
+-- >               runAt node ....
+-- > callTo node' .....
+--
+-- Here foo will be executed in node' but foo' bar and baz don't.
+--
+-- However foo bar and baz will e executed in node.
+--
+
+onAll ::  TransIO a -> Cloud a
+onAll =  Cloud
+
+lazy :: TransIO a -> Cloud a
+lazy mx= onAll $ getCont >>= \st -> Transient $
+        return $ unsafePerformIO $  runStateT (runTrans mx) st >>=  return .fst
+
+-- log the result a cloud computation. like `loogged`, This eliminated all the log produced by computations
+-- inside and substitute it for that single result when the computation is completed.
+loggedc :: Loggable a => Cloud a -> Cloud a
+loggedc (Cloud mx)= Cloud $ logged mx
+
+-- | the `Cloud` monad has no `MonadIO` instance. `lliftIO= local . liftIO`
+lliftIO :: Loggable a => IO a -> Cloud a
+lliftIO= local . liftIO
+
+-- | locally perform IO. `localIO = lliftIO`
+localIO :: Loggable a => IO a -> Cloud a
+localIO= lliftIO
+
+--remote :: Loggable a => TransIO a -> Cloud a
+--remote x= Cloud $ step' x $ \full x ->  Transient $ do
+--            let add= Wormhole: full
+--            setData $ Log False add add
+--
+--            r <-  runTrans x
+--
+--            let add= WaitRemote: full
+--            (setData $ Log False add add)     -- !!> "AFTER STEP"
+--            return  r
+
+-- | stop the current computation and does not execute any alternative computation
+fullStop :: Cloud stop
+fullStop= onAll $ setData WasRemote >> stop
+
+
+-- | continue the execution in a new node
+-- all the previous actions from `listen` to this statement must have been logged
+beamTo :: Node -> Cloud ()
+beamTo node =  wormhole node teleport
+
+
+-- | execute in the remote node a process with the same execution state
+forkTo  :: Node -> Cloud ()
+forkTo node= beamTo node <|> return()
+
+-- | open a wormhole to another node and executes an action on it.
+-- currently by default it keep open the connection to receive additional requests
+-- and responses (streaming)
+callTo :: Loggable a => Node -> Cloud a -> Cloud a
+callTo node  remoteProc=
+   wormhole node $ atRemote remoteProc
+
+-- |  Within an open connection to other node opened by `wormhole`, it run the computation in the remote node and return
+-- the result back  to the original node.
+atRemote proc= loggedc $ do
+     teleport                   -- !> "teleport 1111"
+     r <- Cloud $ runCloud proc <** setData WasRemote
+     teleport                  --  !> "teleport 2222"
+     return r
+
+-- | synonymous of `callTo`
+runAt :: Loggable a => Node -> Cloud a -> Cloud a
+runAt= callTo
+
+
+msend :: Loggable a => Connection -> StreamData a -> TransIO ()
+
+
+#ifndef ghcjs_HOST_OS
+
+msend (Connection _(Just (Node2Node _ sock)) _ _ blocked _ _ ) r= do
+  r <- liftIO $ do
+       withMVar blocked $
+             const $ do
+                 SBS.send sock $ BC.pack (show r)
+                 return Nothing
+            `catch` (\(e::SomeException) -> return $ Just e)
+  case r of
+      Nothing -> return()
+      juste -> finish juste
+
+
+msend (Connection _(Just (Node2Web sconn)) _ _ blocked _  _) r=liftIO $
+  withMVar blocked $ const $ WS.sendTextData sconn $ BS.pack (show r)
+
+
+#else
+
+msend (Connection _ (Just (Web2Node sconn)) _ _ blocked _  _) r= liftIO $
+  withMVar blocked $ const $ JavaScript.Web.WebSocket.send  (JS.pack $ show r) sconn   -- !!> "MSEND SOCKET"
+
+
+
+#endif
+
+msend (Connection _ Nothing _ _  _ _ _ ) _= error "msend out of wormhole context"
+
+mread :: Loggable a => Connection -> TransIO (StreamData a)
+
+
+#ifdef ghcjs_HOST_OS
+
+
+mread (Connection _ (Just (Web2Node sconn)) _ _ _ _  _)=  wsRead sconn
+
+
+
+wsRead :: Loggable a => WebSocket  -> TransIO  a
+wsRead ws= do
+  dat <- react (hsonmessage ws) (return ())
+  case JM.getData dat of
+    JM.StringData str  ->  return (read' $ JS.unpack str)
+--                                    !> ("Browser webSocket read", str)  !> "<------<----<----<------"
+    JM.BlobData   blob -> error " blob"
+    JM.ArrayBufferData arrBuffer -> error "arrBuffer"
+
+
+{-
+wsRead1 :: Loggable a => WebSocket  -> TransIO (StreamData a)
+wsRead1 ws= do
+  reactStream (makeCallback MessageEvent) (js_onmessage ws) CB.releaseCallback (return ())
+  where
+  reactStream createHandler setHandler removeHandler iob= Transient $ do
+        cont    <- getCont
+        hand <- liftIO . createHandler $ \dat ->do
+              runStateT (setData dat >> runCont cont) cont
+              iob
+        mEvData <- getSessionData
+        case mEvData of
+          Nothing -> liftIO $ do
+                        setHandler hand
+                        return Nothing
+
+          Just dat -> do
+             liftIO $ print "callback called 2*****"
+             delSessionData dat
+             dat' <- case getData dat of
+                 StringData str  -> liftIO $ putStrLn "WSREAD RECEIVED " >> print str >> return (read $ JS.unpack str)
+                 BlobData   blob -> error " blob"
+                 ArrayBufferData arrBuffer -> error "arrBuffer"
+             liftIO $ case dat' of
+               SDone -> do
+                        removeHandler $ Callback hand
+                        empty
+               sl@(SLast x) -> do
+                        removeHandler $ Callback hand     -- !!> "REMOVEHANDLER"
+                        return $ Just sl
+               SError e -> do
+                        removeHandler $ Callback hand
+                        print e
+                        empty
+               more -> return (Just  more)
+-}
+
+
+wsOpen :: JS.JSString -> TransIO WebSocket
+wsOpen url= do
+   ws <-  liftIO $ js_createDefault url      --  !> ("wsopen",url)
+   react (hsopen ws) (return ())             -- !!> "react"
+   return ws                                 -- !!> "AFTER ReACT"
+
+foreign import javascript safe
+    "window.location.hostname"
+   js_hostname ::    JSVal
+
+foreign import javascript safe
+   "(function(){var res=window.location.href.split(':')[2];if (res === undefined){return 80} else return res.split('/')[0];})()"
+   js_port ::   JSVal
+
+foreign import javascript safe
+    "$1.onmessage =$2;"
+   js_onmessage :: WebSocket  -> JSVal  -> IO ()
+
+
+getWebServerNode :: TransIO Node
+getWebServerNode = liftIO $
+
+   createNode   <$> ( fromJSValUnchecked js_hostname)
+                <*> (fromIntegral <$> (fromJSValUnchecked js_port :: IO Int))
+                <*> (return [])
+
+
+
+hsonmessage ::WebSocket -> (MessageEvent ->IO()) -> IO ()
+hsonmessage ws hscb= do
+  cb <- makeCallback MessageEvent hscb
+  js_onmessage ws cb
+
+foreign import javascript safe
+             "$1.onopen =$2;"
+   js_open :: WebSocket  -> JSVal  -> IO ()
+
+newtype OpenEvent = OpenEvent JSVal deriving Typeable
+hsopen ::  WebSocket -> (OpenEvent ->IO()) -> IO ()
+hsopen ws hscb= do
+   cb <- makeCallback OpenEvent hscb
+   js_open ws cb
+
+makeCallback :: (JSVal -> a) ->  (a -> IO ()) -> IO JSVal
+
+makeCallback f g = do
+   Callback cb <- CB.syncCallback1 CB.ContinueAsync (g . f)
+   return cb
+
+
+foreign import javascript safe
+   "new WebSocket($1)" js_createDefault :: JS.JSString -> IO WebSocket
+
+
+#else
+mread (Connection _(Just (Node2Node _ _)) _ _ blocked _ _ ) =  parallelReadHandler -- !> "mread"
+
+
+mread (Connection node  (Just (Node2Web sconn )) bufSize events blocked _ _)=
+        parallel $ do
+            s <- WS.receiveData sconn
+            return . read' $  BS.unpack s
+--                 !>  ("WS MREAD RECEIVED ---->", s)
+
+--           `catch`(\(e ::SomeException) -> return $ SError e)
+
+getWebServerNode = getMyNode
+#endif
+
+read' s= case readsPrec' 0 s of
+       [(x,"")] -> x
+       _  -> error $ "reading " ++ s
+
+-- | A wormhole opens a connection with another node anywhere in a computation.
+-- `teleport` uses this connection to translate the computation back and forth between the two nodes
+wormhole :: Loggable a => Node -> Cloud a -> Cloud a
+wormhole node (Cloud comp) = local $ Transient $ do
+
+   moldconn <- getData :: StateIO (Maybe Connection)
+   mclosure <- getData :: StateIO (Maybe Closure)
+
+   logdata@(Log rec log fulLog) <- getData `onNothing` return (Log False [][])
+
+   mynode <- runTrans getMyNode     -- debug
+   if not rec                                                    --  !> ("wormhole recovery", rec)
+            then runTrans $ (do
+
+                    conn <-  mconnect node                   --  !> (mynode,"connecting node ",  node)
+                    setData  conn{calling= True}
+#ifdef ghcjs_HOST_OS
+                    addPrefix    -- for the DOM identifiers
+#endif
+                    comp )
+                  <*** do when (isJust moldconn) . setData $ fromJust moldconn
+                          when (isJust mclosure).  setData $ fromJust mclosure
+
+                    -- <** is not enough
+            else do
+             let conn = fromMaybe (error "wormhole: no connection in remote node") moldconn
+--             conn <- getData `onNothing` error "wormhole: no connection in remote node"
+
+             setData $ conn{calling= False}
+
+             runTrans $  comp
+                     <*** do
+--                          when (null log) $ setData WasRemote    !> "NULLLOG"
+                          when (isJust mclosure) . setData $ fromJust mclosure
+
+
+
+
+#ifndef ghcjs_HOST_OS
+type JSString= String
+pack= id
+
+
+
+#endif
+
+newtype Prefix= Prefix JSString deriving(Read,Show)
+addPrefix= Transient $ do
+   r <- liftIO $ replicateM  5 (randomRIO ('a','z'))
+   setData $ Prefix $ pack  r
+   return $ Just ()
+
+
+-- | translates computations back and forth
+-- reusing a connection opened by `wormhole`
+teleport ::   Cloud ()
+teleport =  do
+  local $ Transient $ do
+
+     cont <- get
+
+     -- send log with closure at head
+     Log rec log fulLog <- getData `onNothing` return (Log False [][])
+     if not rec    -- !> ("teleport rec,loc fulLog=",rec,log,fulLog)
+                  -- if is not recovering in the remote node then it is active
+      then  do
+         conn@Connection{closures= closures,calling= calling} <- getData
+             `onNothing` error "teleport: No connection defined: use wormhole"
+
+         --read this Closure
+         Closure closRemote  <- getData `onNothing` return (Closure 0 )
+
+         --set his own closure in his Node data
+
+         let closLocal = sum $ map (\x-> case x of Wait-> 1000; _ -> 1) fulLog
+--         closLocal  <-   liftIO $ randomRIO (0,1000000)
+
+         liftIO $ modifyMVar_ closures $ \map -> return $ M.insert closLocal (fulLog,cont) map
+
+         let tosend= reverse $ if closRemote==0 then fulLog else  log -- drop offset  $ reverse fulLog  !> ("fulLog", fulLog)
+
+         runTrans $ msend conn $ SMore (closRemote,closLocal, tosend )
+--                                                  !> ("teleport sending", tosend )
+--                                                  !> "--------->------>---------->"
+
+         setData $ if (not calling) then  WasRemote else WasParallel
+
+         return Nothing
+
+      else do
+
+         delData WasRemote                -- !> "deleting wasremote in teleport"
+                                          -- it is recovering, therefore it will be the
+                                          -- local, not remote
+
+         return (Just ())                           --  !> "TELEPORT remote"
+
+
+
+
+-- | copy a session data variable from the local to the remote node.
+-- The parameter is the default value, if there is none set in the local node.
+-- Then the default value is also set in the local node.
+copyData def = do
+  r <- local getSData <|> return def
+  onAll $ setData r
+  return r
+
+-- | `callTo` can stream data but can not inform the receiving process about the finalization. This call
+-- does it.
+streamFrom :: Loggable a => Node -> Cloud (StreamData a) -> Cloud  (StreamData a)
+streamFrom = callTo
+
+
+--release (Node h p rpool _) hand= liftIO $ do
+----    print "RELEASED"
+--    atomicModifyIORef rpool $  \ hs -> (hand:hs,())
+--      -- !!> "RELEASED"
+
+mclose :: Connection -> IO ()
+
+#ifndef ghcjs_HOST_OS
+
+mclose (Connection _
+   (Just (Node2Node _  sock )) _ _ _ _ _)= NS.sClose sock
+
+mclose (Connection node
+   (Just (Node2Web sconn ))
+   bufSize events blocked _  _)=
+    WS.sendClose sconn ("closemsg" :: ByteString)
+
+#else
+
+mclose (Connection _ (Just (Web2Node sconn)) _ _ blocked _ _)=
+    JavaScript.Web.WebSocket.close Nothing Nothing sconn
+
+#endif
+
+mconnect :: Node -> TransIO  Connection
+mconnect  node@(Node _ _ _ _ )=  do
+  nodes <- getNodes
+
+  let fnode =  filter (==node) nodes
+  case fnode of
+   [] -> addNodes [node] >> mconnect node
+   [Node host port  pool _] -> do
+--    Log _ _ full <- getSData <|> error "mconnect log error"
+
+    plist <- liftIO $ readMVar pool
+    case plist  of
+      handle:_ -> do
+                  delData $ Closure undefined
+                  return  handle                        -- !>   "REUSED!"
+
+      _ -> do
+--        liftIO $ putStr "*****CONNECTING NODE: " >> print node
+        my <- getMyNode
+--        liftIO  $ putStr "OPENING CONNECTION WITH :" >> print port
+        Connection{comEvent= ev} <- getSData <|> error "connect: listen not set for this node"
+#ifndef ghcjs_HOST_OS
+
+        conn <- liftIO $ do
+          let size=8192
+          sock <-  connectTo' size host $ PortNumber $ fromIntegral port   -- !!> ("CONNECTING "++ show port)
+
+          let conn= (defConnection 8100){myNode= my,comEvent= ev,connData= Just $ Node2Node u  sock}
+          SBS.send sock "CLOS a b\n\n"   -- !> "sending CLOS"
+
+
+          return conn
+
+#else
+        conn <- do
+          ws <- connectToWS host $ PortNumber $ fromIntegral port
+          let conn= (defConnection 8100){comEvent= ev,connData= Just $ Web2Node ws}
+
+          return conn
+#endif
+        liftIO $ modifyMVar_ pool $  \plist -> return $ conn:plist
+
+        putMailbox "connections" (conn,node)
+
+        delData $ Closure undefined
+
+
+
+
+        return  conn
+
+  where u= undefined
+
+-- mconnect _ = empty
+
+
+
+#ifndef ghcjs_HOST_OS
+connectTo' bufSize hostname (PortNumber port) =  do
+        proto <- BSD.getProtocolNumber "tcp"
+        bracketOnError
+            (NS.socket NS.AF_INET NS.Stream proto)
+            (sClose)  -- only done if there's an error
+            (\sock -> do
+              NS.setSocketOption sock NS.RecvBuffer bufSize
+              NS.setSocketOption sock NS.SendBuffer bufSize
+              he <- BSD.getHostByName hostname
+              NS.connect sock (NS.SockAddrInet port (BSD.hostAddress he))
+              return sock
+--              NS.socketToHandle sock ReadWriteMode
+            )
+#else
+connectToWS  h (PortNumber p) =
+   wsOpen $ JS.pack $ "ws://"++ h++ ":"++ show p
+#endif
+#ifndef ghcjs_HOST_OS
+-- | A connectionless version of callTo for long running remote calls
+callTo' :: (Show a, Read a,Typeable a) => Node -> Cloud a -> Cloud a
+callTo' node remoteProc=  do
+    mynode <-  local getMyNode
+    beamTo node
+    r <-  remoteProc
+    beamTo mynode
+    return r
+#endif
+
+type Blocked= MVar ()
+type BuffSize = Int
+data ConnectionData=
+#ifndef ghcjs_HOST_OS
+                   Node2Node{port :: PortID
+
+                              ,socket ::Socket
+                                   }
+
+                   | Node2Web{webSocket :: WS.Connection}
+#else
+
+                   Web2Node{webSocket :: WebSocket}
+#endif
+
+
+
+data Connection= Connection{myNode :: Node
+                           ,connData :: (Maybe(ConnectionData))
+                           ,bufferSize ::BuffSize
+                           ,comEvent :: IORef (M.Map T.Text (EVar Dynamic))
+                           ,blocked :: Blocked
+                           ,calling :: Bool
+                           ,closures   :: MVar (M.Map Int ([LogElem], EventF))}
+
+                  deriving Typeable
+
+
+-- Mailboxes are node-wide, for all processes that share the same connection data, that is, are under the
+-- same `listen`  or `connect`
+-- while EVars are only visible by the process that initialized  it and his children.
+-- Internally, the mailbox is in a well known EVar stored by `listen` in the `Connection` state.
+newMailbox :: T.Text -> TransIO ()
+newMailbox name= do
+   return ()  -- !> "newMailBox"
+   Connection{comEvent= mv} <- getData `onNothing` errorMailBox
+   onFinish . const $ liftIO $ do
+         return ()                        --  !> "NEWMAILBOX finish"
+         mailboxes <- readIORef mv
+         let me = M.lookup name  mailboxes
+         case me of
+             Nothing -> empty             -- !> "EMPTY"
+             Just (EVar id rn ref1) -> do
+                 n <- atomically $ do
+                      (n,n') <- readTVar rn
+                      writeTVar rn (n-1,n'-1)        -- !> ("decreased rn",n-1)
+                      return $ n-1
+                 when (n==0) $ atomicModifyIORef mv $ \mboxes -> (M.delete name mboxes,())
+   ev <- newEVar
+   liftIO $ atomicModifyIORef mv $ \mailboxes ->   (M.insert name ev mailboxes,())
+
+
+-- | write to the mailbox
+putMailbox :: Typeable a => T.Text -> a -> TransIO ()
+putMailbox name dat= do --  sendNodeEvent (name, Just dat)
+   Connection{comEvent= mv} <- getData `onNothing` errorMailBox
+   mbs <- liftIO $ readIORef mv
+   let mev =  M.lookup name mbs
+   case mev of
+     Nothing ->newMailbox name >> putMailbox name dat
+     Just ev -> writeEVar ev $ toDyn dat
+
+errorMailBox= error "MailBox: No connection open.Use wormhole"
+
+-- | get messages from the mailbox that matches with the type expected.
+-- The order of reading is defined by `readTChan`
+-- This is reactive. it means that each new message trigger the execution of the continuation
+-- each message wake up all the `getMailbox` computations waiting for it.
+
+getMailbox name= do
+   Connection{comEvent= mv} <- getData `onNothing` errorMailBox
+   mbs <- liftIO $ readIORef mv
+   let mev =  M.lookup name mbs
+   case mev of
+     Nothing ->newMailbox name >> getMailbox name
+     Just ev ->do
+          d <- readEVar ev
+          case fromDynamic d of  -- !> "getMailBox" of
+             Nothing -> empty
+             Just x -> return x
+
+--getMailBox :: Typeable a => String -> TransIO a
+--getMailBox name= Transient $ do
+--     return () !> "getMailBox"
+--     Connection{comEvent=(EVar id rn ref1)} <- getData `onNothing` error "getMailBox: accessing network events out of listen"
+--     runTrans  $ do
+--         liftIO $ atomically $ readTVar rn >>= \(n,n') -> writeTVar rn (n +1,n'+1)
+--         r <- parallel $  do
+--                  n' <- atomically $ do
+--                              (n,n') <- readTVar rn
+--                              writeTVar rn $ if n' > 1 then   (n,n'-1) else (n, n)
+--                              return n'
+--                  return () !> ("rear rn",name,n')
+--                  atomically $ do
+--                    d <- if n'> 1 then  peekTChan ref1 else readTChan ref1
+--
+--
+--                    return () !> ("readmailbox",name,n')
+--                    case d of
+--                        SDone -> return SDone
+--                        SMore x ->  case fromDynamic x of
+--                              Nothing -> return $ SMore Nothing
+--                              Just (nam, Nothing) -> do
+--                                readTVar rn >>= \(n,n') -> writeTVar rn $ (n,n' -1)
+--                                return SDone
+--                              Just (nam,Just dat) ->
+--                                return $ SMore $  if nam /= name then  Nothing else Just dat
+----                        SLast x -> case fromDynamic x of
+----                              Nothing -> retry
+----                              Just (nam, Nothing) -> return SDone
+----                              Just (nam,Just dat) ->
+----                                if nam /= name !>(nam,name) then retry else return $ SLast dat
+--                        SError e -> return $ SError e
+--
+--         case r of
+--            SDone -> empty
+--            SMore Nothing -> empty
+--            SMore (Just x) -> return x
+--            SLast (Just x) -> return x
+--            SError e -> error $ show e
+
+-- | delete all subscriptions for that mailbox expecting this kind of data.
+cleanMailbox :: Typeable a =>  T.Text ->  a -> TransIO ()
+cleanMailbox name witness= do
+   Connection{comEvent= mv} <- getData `onNothing` error "getMailBox: accessing network events out of listen"
+   mbs <- liftIO $readIORef mv
+   let mev =  M.lookup name mbs
+   case mev of
+     Nothing -> return()
+     Just ev -> do cleanEVar ev
+                   liftIO $ atomicModifyIORef mv $ \mbs -> (M.delete name mbs,())
+
+
+
+
+
+defConnection :: Int -> Connection
+
+-- #ifndef ghcjs_HOST_OS
+defConnection size=
+  Connection (createNode "program" 0 []) Nothing  size
+                 (error "defConnection: accessing network events out of listen")
+                 (unsafePerformIO $ newMVar ())
+                 False (unsafePerformIO $ newMVar M.empty)
+
+
+
+#ifndef ghcjs_HOST_OS
+setBuffSize :: Int -> TransIO ()
+setBuffSize size= Transient $ do
+   conn<- getData `onNothing` return (defConnection 8192)
+   setData $ conn{bufferSize= size}
+   return $ Just ()
+
+getBuffSize=
+  (do getSData >>= return . bufferSize) <|> return  8192
+
+
+
+
+
+listen ::  Node ->  Cloud ()
+listen  (node@(Node _  ( port) _ _ )) = onAll $ do
+   addThreads 1
+   addNodes [node]
+   setData $ Log False [] []
+
+   conn' <- getSData <|> return (defConnection 8192)
+   ev <- liftIO $ newIORef M.empty
+   let conn= conn'{myNode= node , comEvent=ev}
+   setData conn
+
+   mlog <- listenNew (fromIntegral port) conn  <|> listenResponses
+
+
+   checkLog mlog
+
+
+
+listenNew port conn= do --  node bufSize events blocked port= do
+
+
+   sock <- liftIO . listenOn  $ PortNumber port
+
+   let bufSize= bufferSize conn
+   liftIO $ do NS.setSocketOption sock NS.RecvBuffer bufSize
+               NS.setSocketOption sock NS.SendBuffer bufSize
+
+
+   (sock,addr) <- waitEvents $ NS.accept sock         -- !!> "BEFORE ACCEPT"
+
+
+--   case addr of
+--     NS.SockAddrInet port host -> liftIO $ print("connection from", port, host)
+--     NS.SockAddrInet6  a b c d -> liftIO $ print("connection from", a, b,c,d)
+
+
+   initFinish
+   onFinish $ const $ do
+             return()                                 -- !> "onFinish closures receivedd with LISTEN"
+             let Connection{closures=closures}= conn  -- !> "listenNew closures empty"
+             liftIO $ modifyMVar_ closures $ const $ return M.empty
+
+
+   (method,uri, headers) <- receiveHTTPHead sock
+
+   case method of
+     "CLOS" ->
+          do
+           return ()                         -- !> "CLOS detected"
+           setData $ conn{connData=Just (Node2Node (PortNumber port) sock )}
+
+--           killOnFinish $ parallel $ readHandler          -- !> "read Listen"  -- :: TransIO (StreamData [LogElem])
+           parallelReadHandler
+
+     _ -> do
+           sconn <- httpMode (method,uri, headers) sock -- stay serving pages until a websocket request is received
+
+           setData conn{connData= Just (Node2Web sconn )}
+
+
+           killOnFinish $ parallel $ do
+               msg <- WS.receiveData sconn             -- WebSockets
+               return . read $ BC.unpack msg
+--                                                      !> ("Server WebSocket msg read",msg)  !> "<-------<---------<--------------"
+
+
+
+
+
+
+
+instance Read PortNumber where
+  readsPrec n str= let [(n,s)]=   readsPrec n str in [(fromIntegral n,s)]
+
+
+deriving instance Read PortID
+deriving instance Typeable PortID
+#endif
+
+
+listenResponses= do
+
+      (conn, node) <- getMailbox "connections"
+      setData conn
+#ifndef ghcjs_HOST_OS
+      case conn of
+             Connection _(Just (Node2Node _ sock)) _ _ _ _ _ ->
+                 setData $ (ParseContext (giveData sock) "" :: ParseContext ByteString)
+#endif
+      initFinish
+      onFinish $ const $ do
+             liftIO $ putStrLn "removing node: ">> print node
+             nodes <- getNodes
+             setNodes $ nodes \\ [node]
+
+
+             let Connection{closures=closures}= conn
+             liftIO $ modifyMVar_ closures $ const $ return M.empty
+
+
+      killOnFinish $ mread conn
+
+
+type IdClosure= Int
+
+data Closure= Closure IdClosure
+
+checkLog mlog = Transient $ do
+       case  mlog    of                       -- !> ("RECEIVED ", mlog ) of
+             SError e -> do
+                 runTrans $ finish $ Just e
+                 return Nothing
+
+             SDone   -> runTrans(finish Nothing) >> return Nothing
+             SMore r -> process r False
+             SLast r -> process r True
+
+   where
+   process (closl,closr,log) deleteClosure= do
+              Connection {closures=closures} <- getData `onNothing` error "Listen: myNode not set"
+
+              if closl== 0 then do
+                   setData $ Log True log  $ reverse log
+                   setData $ Closure closr
+                   return $ Just ()                        --  !> "executing top level closure"
+
+               else do
+                 mcont <- liftIO $ modifyMVar closures  $ \map ->
+                                               return (if deleteClosure then
+                                                           M.delete closl map
+                                                         else map, M.lookup closl map)
+                                                           -- !> ("closures=", M.size map)
+                 case mcont of
+                   Nothing -> error ("received non existent closure: " ++  show closl)
+                   -- execute the closure
+                   Just (fulLog,cont) -> liftIO $ runStateT (do
+                                     let nlog= reverse log ++  fulLog -- dropWhile (\x -> case x of
+                                                                        --  Exec -> True
+                                                                        --  _ -> False) fulLog
+                                     setData $ Log True  log  nlog
+
+                                     setData $ Closure closr
+                                     runCont cont) cont   -- !> ("executing closure",closr)
+
+
+                 return Nothing                     -- !> "FINISH CLOSURE"
+
+#ifdef ghcjs_HOST_OS
+listen node = onAll $ do
+        addNodes [node]
+        events <- liftIO $ newIORef M.empty
+        let conn=  (defConnection 8192){myNode= node,comEvent=events}--  Connection node Nothing 8192 events (unsafePerformIO $ newMVar ()) False False 0 :: Connection xxxxxx
+        setData conn
+        r <- listenResponses
+        checkLog r
+#endif
+
+type Pool= [Connection]
+type Package= String
+type Program= String
+type Service= (Package, Program)
+
+
+-- * Level 2: connections node lists and operations with the node list
+
+
+{-# NOINLINE emptyPool #-}
+emptyPool :: MonadIO m => m (MVar Pool)
+emptyPool= liftIO $ newMVar  []
+
+createNode :: HostName -> Integer -> [Service] -> Node
+createNode h p svs= Node h ( fromInteger p) (unsafePerformIO emptyPool) svs
+
+
+createWebNode :: Node
+createWebNode= Node "webnode" ( fromInteger 0) (unsafePerformIO emptyPool)
+                      [("webnode","")]
+
+
+instance Eq Node where
+    Node h p _ _ ==Node h' p' _ _= h==h' && p==p'
+
+
+instance Show Node where
+    show (Node h p _ servs )= show (h,p, servs)
+
+
+instance Read Node where
+
+    readsPrec _ s=
+          let r= readsPrec' 0 s
+          in case r of
+            [] -> []
+            [((h,p,ss),s')] ->  [(Node h p empty
+              ( ss),s')]
+          where
+          empty= unsafePerformIO  emptyPool
+
+
+--newtype MyNode= MyNode Node deriving(Read,Show,Typeable)
+
+
+--instance Indexable MyNode where key (MyNode Node{nodePort=port}) =  "MyNode "++ show port
+--
+--instance Serializable MyNode where
+--    serialize= BS.pack . show
+--    deserialize= read . BS.unpack
+
+nodeList :: TVar  [Node]
+nodeList = unsafePerformIO $ newTVarIO []
+
+deriving instance Ord PortID
+
+--myNode :: Int -> DBRef  MyNode
+--myNode= getDBRef $ key $ MyNode undefined
+
+
+
+
+
+
+errorMyNode f= error $ f ++ ": Node not set. Use initConnData before listen"
+
+-- #ifdef ghcjs_HOST_OS
+--getMyNode :: TransIO Node
+--getMyNode= return createWebNode
+--
+----initConnData :: Node -> TransIO ()
+----initConnData node= do
+----        addNodes [node]
+----        events <- newEVar
+----        let conn= Connection () Nothing 8192 events (unsafePerformIO $ newMVar ()) False False 0 :: Connection
+----        setData conn
+-- #else
+
+getMyNode :: TransIO Node
+getMyNode =  do
+    Connection{myNode=node} <- getSData <|> errorMyNode "getMyNode"
+
+    return node
+
+
+
+--initConnData :: Node -> TransIO ()
+--initConnData node= do
+--        addNodes [node]
+--        events <- newEVar
+--        let conn= Connection node Nothing 8192 events (unsafePerformIO $ newMVar ()) False False 0  :: Connection
+--        setData conn
+--        return $ Just ()
+
+
+-- | return the list of nodes connected to the local node
+getNodes :: MonadIO m => m [Node]
+getNodes  = liftIO $ atomically $ readTVar  nodeList
+
+-- | add nodes to the list of nodes
+addNodes :: (MonadIO m, MonadState EventF m) => [Node] -> m ()
+addNodes   nodes=  do
+  liftIO . atomically $ do
+    prevnodes <- readTVar nodeList
+    writeTVar nodeList $ nub $ nodes ++ prevnodes
+
+-- | set the list of nodes
+setNodes nodes= liftIO $ atomically $ writeTVar nodeList $  nodes
+
+
+shuffleNodes :: MonadIO m => m [Node]
+shuffleNodes=  liftIO . atomically $ do
+  nodes <- readTVar nodeList
+  let nodes'= tail nodes ++ [head nodes]
+  writeTVar nodeList nodes'
+  return nodes'
+
+--getInterfaces :: TransIO TransIO HostName
+--getInterfaces= do
+--   host <- logged $ do
+--      ifs <- liftIO $ getNetworkInterfaces
+--      liftIO $ mapM_ (\(i,n) ->putStrLn $ show i ++ "\t"++  show (ipv4 n) ++ "\t"++name n)$ zip [0..] ifs
+--      liftIO $ putStrLn "Select one: "
+--      ind <-  input ( < length ifs)
+--      return $ show . ipv4 $ ifs !! ind
+
+
+-- | execute a Transient action in each of the nodes connected.
+--
+-- The response of each node is received by the invoking node and processed by the rest of the procedure.
+-- By default, each response is processed in a new thread. To restrict the number of threads
+-- use the thread control primitives.
+--
+-- this snippet receive a message from each of the simulated nodes:
+--
+-- > main = keep $ do
+-- >    let nodes= map createLocalNode [2000..2005]
+-- >    addNodes nodes
+-- >    (foldl (<|>) empty $ map listen nodes) <|> return ()
+-- >
+-- >    r <- clustered $ do
+-- >               Connection (Just(PortNumber port, _, _, _)) _ <- getSData
+-- >               return $ "hi from " ++ show port++ "\n"
+-- >    liftIO $ putStrLn r
+-- >    where
+-- >    createLocalNode n= createNode "localhost" (PortNumber n)
+clustered :: Loggable a  => Cloud a -> Cloud a
+clustered proc= callNodes (<|>) empty proc
+
+
+-- A variant of `clustered` that wait for all the responses and `mappend` them
+mclustered :: (Monoid a, Loggable a)  => Cloud a -> Cloud a
+mclustered proc= callNodes (<>) mempty proc
+
+
+callNodes op init proc= loggedc $ do
+    nodes <-  local getNodes
+    let nodes' = filter (not . isWebNode) nodes
+    foldr op init $ map (\node -> runAt node proc) nodes'  -- !> ("mclustered",nodes')
+    where
+    isWebNode Node {nodeServices=srvs}
+         | ("webnode","") `elem` srvs = True
+         | otherwise = False
+
+-- | set the rest of the computation as a new node (first parameter) and connect it
+-- to an existing node (second parameter). then it uses `connect`` to synchronize the list of nodes
+connect ::  Node ->  Node -> Cloud ()
+connect  node  remotenode =   do
+    listen node <|> return () -- listen1 node remotenode
+    connect' remotenode
+
+-- | synchronize the list of nodes with a remote node and all the nodes connected to it
+-- the final effect is that all the nodes share the same list of nodes
+connect'  remotenode= do
+    nodes <- local $ getNodes
+    local $ liftIO $ putStrLn $ "connecting to: "++ show remotenode
+--    newnode <- local $ return node -- must pass my node to the remote node or else it will use his own
+
+    nodes' <- runAt remotenode $  do
+--                   conn <- onAll getSData <|> error "connect: no connnection data"
+                   let nodeConnecting= head nodes
+                   mclustered . local . addNodes $ nodes -- nodeConnecting{connection= unsafePerformIO (newMVar [conn])} : tail nodes
+                   local . onFinish . const $ do
+                       liftIO $ putStrLn "removing node: ">> print nodeConnecting
+                       nodes <- getNodes
+                       setNodes $ nodes \\ [nodeConnecting]
+
+                   local $ do
+                       liftIO $ putStrLn  "New  nodes: " >> print nodes
+                       n <- getNodes
+                       my <- getMyNode
+                       return $ n \\ [my]
+
+    let newNodes = remotenode : nodes'
+    let n = newNodes \\ nodes
+    when (not $ null n) $ mclustered $ local $ do
+          liftIO $ putStrLn  "New  nodes: " >> print n
+          addNodes n   -- add the new discovered nodes to the already known ones.
+    local $ do
+       addNodes  nodes
+       nodes <- getNodes
+       liftIO $ putStrLn  "Known nodes: " >> print nodes
+
+
+--------------------------------------------
+
+
+#ifndef ghcjs_HOST_OS
+httpMode (method,uri, headers) conn  = do
+   return ()                        -- !> ("HTTP request",method,uri, headers)
+   if isWebSocketsReq headers
+     then  liftIO $ do
+
+         stream <- makeStream                  -- !!> "WEBSOCKETS request"
+            (do
+                bs <- SBS.recv conn  4096
+                return $ if BC.null bs then Nothing else Just bs)
+            (\mbBl -> case mbBl of
+                Nothing -> return ()
+                Just bl ->  SBS.sendMany conn (BL.toChunks bl) >> return())   -- !!> show ("SOCK RESP",bl)
+
+         let
+             pc = WS.PendingConnection
+                { WS.pendingOptions     = WS.defaultConnectionOptions
+                , WS.pendingRequest     =  NWS.RequestHead uri headers False -- RequestHead (BC.pack $ show uri)
+                                                      -- (map parseh headers) False
+                , WS.pendingOnAccept    = \_ -> return ()
+                , WS.pendingStream      = stream
+                }
+
+
+         sconn    <- WS.acceptRequest pc               -- !!> "accept request"
+         WS.forkPingThread sconn 30
+         return sconn
+
+
+
+     else do
+          let uri'= BC.tail $ uriPath uri               -- !> "HTTP REQUEST"
+              file= if BC.null uri' then "index.html" else uri'
+
+          content <- liftIO $  BL.readFile ( "./static/out.jsexe/"++ BC.unpack file)
+                            `catch` (\(e:: SomeException) ->
+                                return  "Not found file: Index.html<br/> please compile with ghcjs<br/> ghcjs program.hs -o static/out")
+
+          n <- liftIO $ SBS.sendMany conn   $  ["HTTP/1.0 200 OK\nContent-Type: text/html\nConnection: close\nContent-Length: " <> BC.pack (show $ BL.length content) <>"\n\n"] ++
+                                  (BL.toChunks content )
+
+
+          empty
+
+      where
+      uriPath = BC.dropWhile (/= '/')
+
+
+
+isWebSocketsReq = not  . null
+    . filter ( (== mk "Sec-WebSocket-Key") . fst)
+
+
+
+data ParseContext a = IsString a => ParseContext (IO  a) a deriving Typeable
+
+
+giveData s= do
+    r <- SBS.recv s      4096
+    return r               -- !> ( "giveData ", r)
+
+
+receiveHTTPHead s = do
+  return ()
+  setData $ (ParseContext (giveData s) "" ::ParseContext ByteString)
+  (method, uri, vers) <- (,,) <$> getMethod <*> getUri <*> getVers
+  headers <- many $ (,) <$> (mk <$> getParam) <*> getParamValue    -- !>  (method, uri, vers)
+  return (method, uri, headers)                                    -- !>  (method, uri, headers)
+
+  where
+
+  getMethod= getString
+  getUri= getString
+  getVers= getString
+  getParam= do
+      dropSpaces
+      r <- tTakeWhile (\x -> x /= ':' && not (endline x))
+      if BC.null r || r=="\r"  then  empty  else  dropChar >> return r
+
+  getParamValue= dropSpaces >> tTakeWhile  (\x -> not (endline x))
+
+
+
+
+dropSpaces= parse $ \str ->((),BC.dropWhile isSpace str)
+
+dropChar= parse  $ \r -> ((), BC.tail r)
+
+endline c= c== '\n' || c =='\r'
+
+--tGetLine= tTakeWhile . not . endline
+
+parallelReadHandler :: Loggable a => TransIO (StreamData a)
+parallelReadHandler= do
+      ParseContext readit str <- getSData <|> error "parallelReadHandler: ParseContext not found"
+                                        :: (TransIO (ParseContext ByteString))
+      rbuff <- liftIO $ newIORef str
+      r <- killOnFinish $ parallel $ do
+                    buff <- readIORef rbuff
+                    str3 <- if  buff /= mempty  then return buff
+                                 else  readit
+                    let  [(v,left)] = readsPrec' 0 $ BC.unpack str3
+                    writeIORef rbuff $ BC.pack left
+                    return v
+      left <- liftIO $ readIORef rbuff
+      setData  $ ParseContext readit left
+      return r
+--                !> ("readHandler",r)
+--                !> "<-------<----------<--------<----------"
+
+
+getString= do
+    dropSpaces
+    tTakeWhile (not . isSpace)
+
+tTakeWhile :: (Char -> Bool) -> TransIO BC.ByteString
+tTakeWhile cond= parse (BC.span cond)
+
+
+parse :: Monoid b => (ByteString -> (b,ByteString)) -> TransIO b
+parse split= do
+    ParseContext readit str <- getSData <|> error "parse: ParseContext not found"
+    if  str == mempty
+     then do
+          str3 <- liftIO  readit
+
+          setData $ ParseContext readit str3                     -- !> str3
+
+          if str3== mempty   then empty   else  parse split
+     else if BC.take 2 str =="\n\n"  then do setData $ ParseContext readit  (BC.drop 2 str) ; empty
+     else if BC.take 4 str== "\r\n\r\n" then do setData $ ParseContext readit  (BC.drop 4 str) ; empty
+     else do
+
+          let (ret,str3) = split str
+          setData $ ParseContext readit str3
+
+          if str3== mempty
+            then   return ret  <> (parse split <|> return mempty)
+
+            else   return ret
+
+
+
+
+#endif
+
+
+
+#ifdef ghcjs_HOST_OS
+isBrowserInstance= True
+
 #else
 isBrowserInstance= False
 #endif
diff --git a/src/Transient/Move/Services.hs b/src/Transient/Move/Services.hs
--- a/src/Transient/Move/Services.hs
+++ b/src/Transient/Move/Services.hs
@@ -16,82 +16,68 @@
 
 import Transient.Base
 import Transient.Move
-import Transient.Logged
+import Transient.Logged(Loggable(..))
+--import Transient.Internals((!>))
+import Transient.Move.Utils
+import Transient.Internals(Log(..))
 import Transient.EVars
+import Transient.Indeterminism
 import Control.Monad.IO.Class
 import System.Process
 import System.IO.Unsafe
 import Control.Concurrent.MVar
 import Control.Applicative
-import Network (PortID(..))
-import GHC.Conc
+
 import System.Directory
 import Control.Monad
 import Data.List
-import Data.TCache hiding(onNothing)
+import Data.Maybe
+--import Data.TCache hiding(onNothing)
 
 -- for the example
 import System.Environment
 
-startServices :: Cloud ()
-startServices= do
-  node <- getMyNode
-  onAll . liftIO $ print node
-  mapM_ start $ services node
-  where
-  start (package,program,port)= onAll . liftIO $ do
-          let prog= pathExe (name package) program port
-          liftIO $ print prog
-          createProcess $ shell prog
+--startServices :: Cloud ()
+--startServices= local $ do
+--  node <-  getMyNode
+--  liftIO $ print node
+--  let servs =   nodeServices node
+--  mapM_ start  servs
+--  where
+--  start (package,program)= liftIO $ do
+--          let prog= pathExe (name package) program port
+--          liftIO $ print prog
+--          createProcess $ shell prog
 
 
 pathExe package program port= package++"/dist/build/"++package++"/"++program
-                                       ++ " " ++ show port
+                                       ++ " -p start/" ++ show port
 
 install :: String  -> String -> Int -> Cloud ()
 install package program port =  do
      let packagename = name package
-     exist <-  local $ liftIO $ doesDirectoryExist  packagename
+     when (null packagename) $ error $ "source for \""++package ++ "\" not found"
+     exist <- local $ liftIO $ doesDirectoryExist  packagename
      when (not exist) $ local $ liftIO $ do
          callProcess  "git" ["clone",package]
          liftIO $ print "GIT DONE"
          setCurrentDirectory packagename
-         callProcess  "cabal" ["install"]
+         callProcess  "cabal" ["install","--force-reinstalls"]
          setCurrentDirectory ".."
          return()
-     let prog= pathExe packagename program port
+     let prog = pathExe packagename program port
+     lliftIO $ print prog
      local $ liftIO $ do
            createProcess $ shell program
            return ()
 
-     let service= (package, program,  port)
-
-     Connection{myNode= rnode} <- onAll getSData <|> error "Mynode not set: use setMyNode"
-     local $ liftIO $ do
-       atomically $ do
-        MyNode( Node h p c servs) <- readTVar rnode
-
-        writeTVar rnode $ MyNode $ Node h p c $ service:servs
-       liftIO syncCache
-     node <-  getMyNode
-     notifyService node service
      return()
 
-name url= do
-     let git= "http://github.com/"
-     if not $ isPrefixOf git url
-       then error "install: only github repos are admitted, sorry"
-       else
-        let segments = split '/' $ drop (length git) url
-            segs'= reverse segments
-        in  head  segs'
-
-
-     where
-     split c []= []
-     split c xs=
-        let (h,t)= span  (/= c) xs
-        in  if null t then [h] else h : split c  (tail t)
+name url=  slash . slash . slash $ slash url
+  where
+  slash= tail1 . dropWhile (/='/')
+  tail1 []=[]
+  tail1 x= tail x
 
 rfreePort :: MVar Int
 rfreePort = unsafePerformIO $ newMVar  3000
@@ -99,54 +85,118 @@
 freePort :: MonadIO m => m Int
 freePort= liftIO $ modifyMVar rfreePort $ \ n -> return (n+1,n)
 
-initService node package program= loggedc $
-    case   find  (\(package', program',_) -> package==package' && program== program') $ services node of
-       Just (_,_,port) -> return port
+initService ident service@(package, program)= loggedc $ do
+    nodes <- local getNodes
+    case find (\node  -> service `elem` nodeServices node) nodes  of
+       Just node -> return node
        Nothing -> do
-            beamTo node
-            port <- onAll freePort
-            install package program  port
-            empty
-          <|> do
-            Connection{comEvent=ev} <- onAll getSData
-            (node', (package', program',port)) <- local waitNodeEvents
-            if node'== node && package' == package && program'== program
-                 then return port
-                 else empty
 
-notifyService :: Node -> Service -> Cloud ()
-notifyService node service=  clustered $ do
-     onAll . liftIO $ atomically $ do
-        nodes <- readTVar nodeList
-        let ([nod], nodes')= span (== node) nodes
-        let nod' = nod{services=service:services nod}
-        writeTVar nodeList $ nod' : nodes'
-        return ()
+          nodes <- callOne $ do
+                    yn<- requestService ident service
+                    if yn then do
+                        port <- onAll freePort
+                        install package program  port
+                        nodeService port
+                      else empty
+          local $ addNodes nodes
+          return $ head nodes
+    where
+    nodeService port= local $ do
+       Node h _ _ _ <- getMyNode
+       return $ Node h port (unsafePerformIO $ newMVar []) [service] :: TransIO Node
 
-     local $ sendNodeEvent (node,service)
-     return ()
 
+
+callOne mx= local . collect 1 . runCloud $ clustered mx
+
+rfriends        =   unsafePerformIO $ newMVar []
+rservices       =   unsafePerformIO $ newMVar []
+ridentsBanned    =   unsafePerformIO $ newMVar []
+rServicesBanned =   unsafePerformIO $ newMVar []
+
+requestService ident service= local $  do
+
+     friends            <- liftIO $ readMVar rfriends
+     services           <- liftIO $ readMVar rservices
+     identsBanned       <- liftIO $ readMVar ridentsBanned
+     servicesBanned     <- liftIO $ readMVar rServicesBanned
+
+     return $ if (null friends || ident `elem` friends)
+        && (null services || service `elem` services)
+        && (null identsBanned || ident `notElem` identsBanned)
+        && (null servicesBanned || service `notElem` servicesBanned)
+      then True else False
+  where
+  notElem a b= not $ elem a b
+
+
+callService
+    :: (Loggable a, Loggable b)
+    => String -> Service -> a  -> Cloud b
+callService ident service params = do
+    node <-  initService ident service
+    log <- onAll $ do
+           log  <- getSData <|> return emptyLog
+           setData emptyLog
+           return log
+
+    r <- wormhole node $ loggedc $ do
+             local $ return params
+
+             teleport
+             local empty
+--    return () !> ("r=",r)
+    restoreLog log
+--    local $ do
+--       Log _ _ log <- getSData <|> return emptyLog
+--       return() !> ("log after",log)
+    return  r -- (r `asTypeOf` witness)
+    where
+    restoreLog (Log _ _ logw)= onAll $ do
+       Log _ _ logw' <- getSData <|> return emptyLog
+
+       let newlog= reverse logw' ++ logw
+--       return ()                 !> ("newlog", logw,logw')
+       setData $ Log False newlog newlog
+
+    emptyLog= Log False [] []
+
+
+
 {-
-main= do
---      keep $ install "http://github.com/agocorona/transient" "MainStreamFiles"  3000
-    let node1= createNode "localhost" 2000
-    let node2= createNode "localhost" 2001
-    args <-getArgs
-    let [localNode,remoteNode]= if null args then [node1,node2] else [node2,node1]
+servicios
+      autoinstall service
+      servicio de instalaci¢n de servicios
+  procedurers call services, services install themselves in nodes.
+     clustered oriented call invoke the nodes that shares the same service.
+        if the service variable state is set. if not, invoke all the nodes.
 
+  some service accessing data may move to the machine where the data is if support the service.
 
-    runCloudIO $ do
-      onAll $ addNodes [localNode, remoteNode]
-      onAll $ setMyNode localNode
-      listen localNode <|> return ()
-      local $ option "start" "start"
+  servicio en browser necesita algo que en el server no existe y no pude dar:
+     forward the request to other nodes
+     return the result to the browser.
+  forward service requests:
+     cuando un nodo no puede servir un servicio, puede hacer forward.
+        otros nodos puede instalarlo o hacer forward a su vez
 
-      startServices
-      port <-initService remoteNode "http://github.com/agocorona/transient" "MainStreamFiles"
-      onAll . liftIO $ putStrLn $ "installed at" ++ show port
--}
+  clusterizaci¢n de servicios
+   nodo con database saturado puede hacer automatic sharding
+     siquientes requests retornan los nuevos nodos
+  la resupuesta de un servicio puede incluir una nueva direcci¢n, del nodo donde se ha movido o donde ha delegado.
 
+  servicio wrarpper que ejecuta una libreria no transient
 
+  cat logo de servicios
+  ghcjsi service for notebooks
 
+  web site de compilaci¢n que compile en su propio ordenador
+     opcion descargar el programa de instalacion y hace stack build
+     ventaja: conectar todos los nodos que ejecutan un servicio determinado
+       necesario un deposito de nombres de servicios:: github
+
+  friend ident.... request you to install... in your computer. Do you agree?
+   if ident is the same, this is automatic.
+-}
 
 
diff --git a/src/Transient/Move/Utils.hs b/src/Transient/Move/Utils.hs
new file mode 100644
--- /dev/null
+++ b/src/Transient/Move/Utils.hs
@@ -0,0 +1,139 @@
+-----------------------------------------------------------------------------
+--
+-- Module      :  Transient.Move.Utils
+-- Copyright   :
+-- License     :  GPL-3
+--
+-- Maintainer  :  agocorona@gmail.com
+-- Stability   :
+-- Portability :
+--
+-- |
+--
+-----------------------------------------------------------------------------
+
+module Transient.Move.Utils (initNode,inputNodes, simpleWebApp, initWebApp
+, onServer, onBrowser, runNodes)
+ where
+
+import Transient.Base
+import Transient.Move
+import Control.Applicative
+import Control.Monad.IO.Class
+
+-- | ask in the console for the port number and initializes a node in the port specified
+-- It needs the application to be initialized with `keep` to get input from the user.
+-- the port can be entered in the command line with "<program> -p  start/<PORT>"
+--
+-- A node is also a web server that send to the browser the program if it has been
+-- compiled to JavaScript with ghcjs. `initNode` also initializes the web nodes.
+--
+-- This sequence compiles to JScript and executes the program with a node in the port 8080
+--
+-- > ghc program.hs
+-- > ghcjs program.hs -o static/out
+-- > ./program -p start/8080
+--
+-- `initNode`, when the application has been loaded and executed in the browser, will perform a `wormhole` to his server node.
+--  So the application run within this wormhole.
+--
+--  Since the code is executed both in server node and browser node, to avoid confusion and in order
+-- to execute in a single logical thread, use `onServer` for code that you need to execute only in the server
+-- node, and `onBrowser` for code that you need in the browser, although server code could call the browser
+-- and vice-versa.
+--
+-- To invoke from browser to server and vice-versa, use `atRemote`.
+--
+-- To translate the code from the browser to the server node, use `teleport`.
+--
+
+initNode app= do
+   port <- getPort
+   initWebApp port  app
+
+
+  where
+  getPort :: TransIO Integer
+  getPort =
+      if isBrowserInstance then return 0 else do
+          oneThread $ option "start" "re/start"
+          port <- input (const True) "port to listen? "
+          liftIO $ putStrLn "node started"
+          return port
+
+-- | ask for nodes to be added to the list of known nodes. it also ask to connect to the node to get
+-- his list of known nodes
+inputNodes= do
+   onServer $ do
+          local $ option "add"  "add a new node at any moment"
+
+          host <- local $ do
+                    r <- input (const True) "Host to connect to: (none): "
+                    if r ==  "" then stop else return r
+
+          port <-  local $ input (const True) "port?"
+
+          connectit <- local $ input (\x -> x=="y" || x== "n") "connect to get his list of nodes?"
+          let nnode= createNode host port []
+          if connectit== "y" then connect'  nnode
+                             else local $ addNodes [nnode]
+   empty
+
+
+
+-- | executes the application in the server and the Web browser.
+-- the browser must point to http://hostname:port where port is the first parameter.
+-- It creates a wormhole to the server.
+-- The code of the program after `simpleWebApp` run in the browser unless `teleport` translates the execution to the server.
+-- To run something in the server and get the result back to the browser, use  `atRemote`
+-- This last also works in the other side; If the application was teleported to the server, `atRemote` will
+-- execute his parameter in the browser.
+--
+-- It is necesary to compile the application with ghcjs:
+--
+-- > ghcjs program.js
+-- > ghcjs program.hs -o static/out
+--
+-- > ./program
+--
+--
+simpleWebApp :: Integer -> Cloud () -> IO ()
+simpleWebApp port app =  keep $ initWebApp port app
+
+-- | use this instead of smpleWebApp when you have to do some initializations in the server prior to the
+-- initialization of the web server. Otherwise, the behaviour is the same.
+initWebApp :: Integer -> Cloud () -> TransIO ()
+initWebApp port app=  do
+    let conn= defConnection 8192
+    setData $ conn{myNode= createNode "localhost" port []}
+    serverNode  <-  getWebServerNode  :: TransIO Node
+
+    let mynode = if isBrowserInstance
+                    then createWebNode
+                    else serverNode
+
+    runCloud $ do
+        listen mynode <|> return()
+        wormhole serverNode app
+        return ()
+
+-- only execute if the the program is executing in the browser. The code inside can contain calls to the server.
+-- Otherwise return empty (so it stop the computation).
+onBrowser :: Cloud a -> Cloud a
+onBrowser x= do
+     r <- local $  return isBrowserInstance
+     if r then x else empty
+
+-- only executes the computaion if it is in the server, but the computation can call the browser. Otherwise return empty
+onServer :: Cloud a -> Cloud a
+onServer x= do
+     r <- local $  return isBrowserInstance
+     if not r then x else empty
+
+-- | run N nodes (N ports to listen) in the same program. For testing purposes.
+-- It add them to the list of known nodes, so it is possible to perform `clustered` operations with them.
+runNodes ports= do
+    let nodes=  map (\p -> createNode "localhost" p []) ports
+    onAll $ addNodes nodes
+    foldl (<|>) empty (map listen nodes) <|> return()
+
diff --git a/tests/TestSuite.hs b/tests/TestSuite.hs
deleted file mode 100644
--- a/tests/TestSuite.hs
+++ /dev/null
@@ -1,87 +0,0 @@
-module Main where
-
-import           Control.Monad
-import           Control.Monad.IO.Class
-import           Data.IORef
-import           GHC.Conc
-import           Control.Applicative
-import           Data.Monoid
-import           Transient.Base
-import           Transient.Indeterminism
-import           Transient.Logged
-import           Transient.Move
-import           Transient.Stream.Resource
-import           Transient.DDS
-import Control.Concurrent
-import System.IO.Unsafe
-import Data.List
-import Control.Exception.Base
-import qualified Data.Map as M
-import System.Exit
-
-main= do
-     let numNodes = 3
-         ports = [2000 .. 2000 + numNodes - 1]
-         createLocalNode = createNode "localhost"
-         nodes = map createLocalNode ports
-         node1= head nodes
-         node2= nodes !! 1
-         node3= nodes !! 2
-
-     r <-runCloud'' $ do
-          local $ addNodes nodes
-          runNodes nodes
-          local $ do
-              r <- collect 5 $ (+) <$> choose [1..5]
-              liftIO $ print r
-
-              ev <- newEVar
-              r <- collect 3 $ readEVar ev <|> ((choose [1..3] >> writeEVar ev) >> stop)
-
-              assert (sort r== [1,2,3]) $ print r
-
-          r <-  (runAt node1 (effect "node1" >> return "hello "))
-                    <>  (runAt node2 (effect "node2" >> return "world" ))
-
-          assert(r== "hello world") $ lliftIO $ print r
-          effs <- getEffects
-          assert (sort effs == sort [(node1,"node1"),(node2,"node2")]) $ return ()
-          delEffects
-
-
-          -- monadic
-          r <- runAt node1 (effect "node1" >>
-                   runAt node2 (effect "node2" >>
-                        runAt node3 (effect "node3" >> return "hello")))
-
-          assert(r== "hello") $ lliftIO $ print r
-          effs <- getEffects
-          assert (sort effs == sort [(node1,"node1"),(node2,"node2"),(node3,"node3")]) $ return ()
-          delEffects
-
-
-          r <- reduce  (+)  . cmap (\w -> (w, 1 :: Int))  $ getText  words "hello world hello hi"
-          assert (sort (M.toList r) == sort [("hello",2),("hi",1),("world",1)]) $ return ()
-
-
-          lliftIO $ print r
-          local $ exit ()
-
-
-     exitSuccess
-
-getEffects :: Loggable a =>  Cloud [(Node, a)]
-getEffects=lliftIO $ readMVar effects
-
-runNodes nodes= foldl (<|>) empty (map listen nodes) <|> return()
-
-
-delEffects= lliftIO $ modifyMVar_ effects $ const $ return[]
-effects= unsafePerformIO $ newMVar []
-
-effect x= do
-   node <- getMyNode
-   lliftIO $ modifyMVar_ effects $ \ xs ->  return $ (node,x): xs
-   return()
-
-
diff --git a/transient-universe.cabal b/transient-universe.cabal
--- a/transient-universe.cabal
+++ b/transient-universe.cabal
@@ -1,5 +1,5 @@
 name: transient-universe
-version: 0.2
+version: 0.3
 cabal-version: >=1.10
 build-type: Simple
 license: GPL-3
@@ -24,6 +24,7 @@
             base >4 && <5,
             mtl -any,
             random -any,
+            transient -any,
             containers -any,
             stm -any,
             transformers -any,
@@ -31,7 +32,8 @@
             bytestring -any,
             time -any,
             ghcjs-base -any,
-            ghcjs-prim -any
+            ghcjs-prim -any,
+            text -any
     else
         build-depends:
             base >4 && <5,
@@ -46,7 +48,6 @@
             network -any,
             transformers -any,
             process -any,
-            network -any,
             network-info -any,
             bytestring -any,
             time -any,
@@ -58,58 +59,15 @@
             hashable -any,
             text -any
 
-    exposed-modules:
-            Transient.Move
-    if ! impl(ghcjs >=0.1)
-
+    if !impl(ghcjs >=0.1)
         exposed-modules:
-            Transient.MapReduce
             Transient.Move.Services
-    build-depends:
-        transformers -any,
-        containers >=0.5.6.2 && <0.6
+    exposed-modules:
+        Transient.Move
+        Transient.MapReduce
+        Transient.Move.Utils
     default-language: Haskell2010
     hs-source-dirs: src .
+    other-modules:
 
--- executable DistrbDataSets
---    main-is: DistrbDataSets.hs
---    build-depends:
---        base -any,
---        network -any,
---        transient -any,
---        TCache -any,
---        transformers -any,
---        transient-universe -any,
---        containers -any
---
---    hs-source-dirs: examples
---    ghc-options:
 
-test-suite test-transient
-    type: exitcode-stdio-1.0
-    main-is: TestSuite.hs
-    build-depends:
-        base >4 && <5,
-        mtl -any,
-        random -any,
-        containers -any,
-        directory -any,
-        filepath -any,
-        stm -any,
-        HTTP -any,
-        network -any,
-        transformers -any,
-        process -any,
-        network -any,
-        network-info -any,
-        bytestring -any,
-        time -any,
-        vector -any,
-        TCache -any,
-        websockets -any,
-        network-uri -any,
-        case-insensitive -any,
-        hashable -any,
-        containers >=0.5.6.2 && <0.6
-    default-language: Haskell2010
-    hs-source-dirs: tests src .
