packages feed

transient 0.1.1 → 0.3

raw patch · 13 files changed

+1214/−2446 lines, 13 filesdep −SHAdep −TCachedep −bytestringdep ~HTTPdep ~basedep ~containers

Dependencies removed: SHA, TCache, bytestring, network-info

Dependency ranges changed: HTTP, base, containers, directory, filepath, mtl, network, process, random, stm, time, transformers

Files

LICENSE view
@@ -1,674 +1,18 @@-              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 © 2014-2016 Alberto G. Corona       <https://github.com/agocorona>
 
-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.
src/Transient/Backtrack.hs view
@@ -6,6 +6,7 @@ module Transient.Backtrack (registerUndo, onUndo, undo, retry, undoCut) where
 
 import Transient.Base
+import Transient.Internals(EventF(..),onNothing,runClosure,runContinuation)
 import Data.Typeable
 import Control.Applicative
 import Control.Monad.State
@@ -19,14 +20,14 @@ -- | assures that backtracking will not go further back
 undoCut :: TransientIO ()
 undoCut= Transient $ do
-     delSessionData $ Backtrack False []
+     delSData $ Backtrack False []
      return $ Just ()
 
 -- | the secod parameter will be executed when backtracking
 {-# NOINLINE onUndo #-}
 onUndo :: TransientIO a -> TransientIO a -> TransientIO a
 onUndo ac bac= registerUndo $ Transient $ do
-     Backtrack back _ <- getSessionData `onNothing` return (Backtrack False [])
+     Backtrack back _ <- getData `onNothing` return (Backtrack False [])
      runTrans $ if back then bac  else ac
 
 
@@ -34,24 +35,25 @@ {-# NOINLINE registerUndo #-}
 registerUndo :: TransientIO a -> TransientIO a
 registerUndo f  = Transient $ do
-   cont@(EventF _ x _ _ _ _ _ _ _ _)  <- get   !> "backregister"
-   md  <- getSessionData
+   cont@(EventF _ _ x _ _ _ _ _ _ _ _)  <- get   -- !!> "backregister"
+   md  <- getData
    ss <- case md of
-        Just (bss@(Backtrack b (bs@((EventF _ x'  _ _ _ _ _ _ _ _):_)))) -> do
+        Just (bss@(Backtrack b (bs@((EventF _ _ x'  _ _ _ _ _ _ _ _):_)))) -> do
             addrx  <- addr x
             addrx' <- addr x'         -- to avoid duplicate backtracking points
             return $ if addrx == addrx' then bss else  Backtrack b $ cont:bs
         Nothing ->  return $ Backtrack False [cont]
-   setSessionData ss
+   setData ss
    runTrans f
    where
    addr x = liftIO $ return . hashStableName =<< (makeStableName $! x)
 
 -- | restart the flow forward from this point on
-retry :: TransientIO ()
-retry= do
-    Backtrack _ stack <- getSessionData `onNothing` return (Backtrack False [])
-    setSData $ Backtrack False stack
+retry :: TransIO ()
+retry= Transient $ do
+    Backtrack _ stack <- getData `onNothing` return (Backtrack False [])
+    setData $ Backtrack False stack
+    return $ Just ()
 
 -- | execute backtracking. It execute the registered actions in reverse order.
 --
@@ -60,21 +62,21 @@ --If the backtrack stack is finished or undoCut executed, `undo` will stop.
 undo :: TransientIO a
 undo= Transient $ do
-  bs <- getSessionData  `onNothing` return nullBack            !>"GOBACK"
+  bs <- getData  `onNothing` return nullBack            -- !!>"GOBACK"
   goBackt  bs
 
   where
   nullBack= Backtrack False []
-  goBackt (Backtrack _ [])= return Nothing                     !> "END"
-  goBackt (Backtrack b (stack@(first@(EventF _ x fs _ _  _ _ _ _ _): bs)))= do
+  goBackt (Backtrack _ [])= return Nothing                      -- !!> "END"
+  goBackt (Backtrack b (stack@(first@(EventF _ _ x fs _ _  _ _ _ _ _): bs)))= do
 --        put first{replay=True}
-        setSData $ Backtrack True stack
-        mr <-  runClosure first                                !> "RUNCLOSURE"
-        Backtrack back _ <- getSessionData `onNothing` return nullBack
-                                                               !>"END RUNCLOSURE"
+        setData $ Backtrack True stack
+        mr <-  runClosure first                                 -- !!> "RUNCLOSURE"
+        Backtrack back _ <- getData `onNothing` return nullBack
+                                                                -- !!>"END RUNCLOSURE"
         case back of
-           True ->  goBackt $ Backtrack True bs                !> "BACK AGAIN"
+           True ->  goBackt $ Backtrack True bs                 -- !!> "BACK AGAIN"
            False -> case mr of
-                   Nothing -> return empty                     !> "FORWARD END"
-                   Just x ->  runContinuation first x          !> "FORWARD EXEC"
+                   Nothing -> return empty                      -- !!> "FORWARD END"
+                   Just x ->  runContinuation first x           -- !!> "FORWARD EXEC"
 
src/Transient/Base.hs view
@@ -10,757 +10,24 @@ -- Portability :
 --
 -- | See http://github.com/agocorona/transient
--- everithing in this module is exported in order to allow extensibility.
 -----------------------------------------------------------------------------
-{-# LANGUAGE ExistentialQuantification #-}
-{-# LANGUAGE FlexibleContexts          #-}
-{-# LANGUAGE FlexibleInstances         #-}
-{-# LANGUAGE MultiParamTypeClasses     #-}
-{-# LANGUAGE DeriveDataTypeable        #-}
--- show
-module Transient.Base  where
--- /show
 
-import           Control.Applicative
-import           Control.Monad.State
-import           Data.Dynamic
-import qualified Data.Map               as M
-import           Data.Monoid
-import           Debug.Trace
-import           System.IO.Unsafe
-import           Unsafe.Coerce
-import           Control.Exception
-import           Control.Concurrent
-import           Control.Concurrent.STM
-import           System.Mem.StableName
-import           Data.Maybe
-import           GHC.Conc
-import           Data.List
-import           Data.IORef
-import           System.Environment
-
-
-{-# INLINE (!>) #-}
-(!>) =  const . id -- flip trace
-infixr 0 !>
-(!!>) =   flip trace
-infixr 0 !!>
-
-data TransIO  x = Transient  {runTrans :: StateT EventF IO (Maybe x)}
-type SData= ()
-
-type EventId= Int
-
-type TransientIO= TransIO
-
-data EventF  = forall a b . EventF{event       :: Maybe SData
-                                  ,xcomp       :: TransientIO a
-                                  ,fcomp       :: [b -> TransientIO b]
-                                  ,mfData      :: M.Map TypeRep SData
-                                  ,mfSequence  :: Int
-                                  ,threadId    :: ThreadId
-                                  ,freeTh      :: Bool
-                                  ,parent      :: Maybe EventF
-                                  ,children    :: TVar[EventF]
-                                  ,maxThread   :: Maybe (P Int)
-                                  }
-                                  deriving Typeable
-
-
-type P= IORef
-newp= newIORef
-
-
---(=:) :: P a  -> (a -> a) -> IO()
-(=:) n f= liftIO $ atomicModifyIORef n $  \v ->  ((f v),())
-
-addr x= show $ unsafePerformIO $ do
-       st <- makeStableName $! x
-       return $ hashStableName st
-
-
-
-
-instance MonadState EventF  TransientIO where
-  get=  Transient $ get >>= return . Just
-  put x= Transient $ put x >> return (Just ())
-
-type StateIO= StateT EventF  IO
-
---type TransientIO= Transient StateIO
-
---runTrans ::  TransientIO x -> StateT EventF  IO (Maybe x)
---runTrans (Transient mx) = mx
-
-
-runTransient :: TransientIO x -> IO (Maybe x, EventF)
-runTransient t= do
-
-  th <- myThreadId
-  let eventf0=  EventF  Nothing empty [] M.empty 0
-          th False  Nothing  (unsafePerformIO $ newTVarIO []) Nothing
-
-
-  runStateT (runTrans t) eventf0{threadId=th} !> "MAIN="++show th
-
-
-
-
--- | get the continuation context: closure, continuation, state, child threads etc
-getCont ::(MonadState EventF  m) => m EventF
-getCont = get
-
--- | run the continuation context
-runCont :: EventF -> StateIO ()
-runCont (EventF _ x fs _ _  _ _  _ _ _)= runTrans ((unsafeCoerce x') >>= compose ( fs)) >> return ()
-    where
-    x'=  do
---           modify $ \s -> s{replay=True}
-           r<- x
---           modify $ \s -> s{replay=False}
-           return r
-
-{-
-runCont cont= do
-     mr <- runClosure cont
-     case mr of
-         Nothing -> return Nothing
-         Just r -> runContinuation cont r
--}
-
--- | compose a list of continuations
-compose []= const empty
-compose (f: fs)= \x -> f x >>= compose fs
-
-
--- | run the closure  (the 'x'  in 'x >>= f') of the current bind operation.
-runClosure :: EventF -> StateIO (Maybe a)
-runClosure (EventF _ x _ _ _ _ _ _ _ _) =  unsafeCoerce $ runTrans x
-
--- | run the continuation (the 'f' in 'x >> f') of the current bind operation
-runContinuation ::  EventF -> a -> StateIO (Maybe b)
-runContinuation (EventF _ _ fs _ _ _ _  _ _ _) x=
-   runTrans $  (unsafeCoerce $ compose $  fs)  x
-
--- | run a chain of continuations. It is up to the programmer to assure by construction that
---  each continuation type-check with the next and the parameter type match the input of the first
--- continuation and that the output is of the type intended.
-runContinuations :: [a -> TransIO b] -> c -> TransIO d
-runContinuations fs x= (compose $ unsafeCoerce fs)  x
-
-instance   Functor TransientIO where
-  fmap f mx=   -- Transient $ fmap (fmap f) $ runTrans mx
-    do
-     x <- mx
-     return $ f x
-
-instance Applicative TransientIO where
-  pure a  = Transient . return $ Just a
-
-
-  f <*> g = Transient $ do
-
-         rf <- liftIO $ newIORef Nothing
-         rg <- liftIO $ newIORef Nothing   -- !> "NEWIOREF"
-
-         cont@(EventF _ _ fs a b c d peers children g1) <- get   -- !> "APLICATIVE DOIT"
-
-         let
-             appg x = Transient $  do
-                   liftIO $ writeIORef rg $ Just x :: StateIO ()
-                   k <- liftIO $ readIORef rf
-                   return $ k <*> Just x  -- !> "RETURNED: " ++ show(isJust k)++ show(isJust x)
-
-
-             appf k = Transient $  do
-                   liftIO $ writeIORef rf  $ Just k :: StateIO ()
-                   x<- liftIO $ readIORef rg
-                   return $ Just k <*> x  --  !> "RETURNED: " ++ show(isJust k)++ show(isJust x)
-
-
-
-         put $ EventF Nothing f (unsafeCoerce appf:  fs)
-                                          a b c d peers children g1
-         k <- runTrans f
-         was <- getSessionData `onNothing` return NoRemote
-         if was== WasRemote
-           then  return Nothing
-           else do
-             liftIO $ writeIORef rf  k -- :: StateIO ()
-
-             mfdata <- gets mfData
-             put $ EventF Nothing g (unsafeCoerce appg :  fs) mfdata b c d peers  children g1
-
-
-             x <- runTrans g              !> "RUN g"
-             liftIO $ writeIORef rg  x
-             return $ k <*> x
-
--- | dynamic serializable data for logging
-data IDynamic= IDyns String | forall a.(Read a, Show a,Typeable a) => IDynamic a
-
-instance Show IDynamic where
-  show (IDynamic x)= show $ show x
-  show (IDyns s)= show s
-
-instance Read IDynamic where
-  readsPrec n str= map (\(x,s) -> (IDyns x,s)) $ readsPrec n str
-
-
-type Recover= Bool
-type CurrentPointer= [LogElem]
-type LogEntries= [LogElem]
-data LogElem=  WaitRemote | Exec | Step IDynamic deriving (Read,Show)
-data Log= Log Recover  CurrentPointer LogEntries deriving Typeable
-
-
-instance  Alternative TransientIO where
-  empty = Transient $ return  Nothing
-  (<|>) = mplus
-
---  Transient f <|> Transient g= Transient $ do
---         k <-   f
---         x <-   g
---         return $ k <|> x
-
-data RemoteStatus=  WasRemote | NoRemote deriving (Typeable, Eq, Show)
-
-instance MonadPlus TransientIO where
-    mzero= empty
-    mplus  x y=  Transient $ do
-         mx <- runTrans x    -- !> "RUNTRANS11111"
-         was <- getSessionData `onNothing` return NoRemote
-         if was== WasRemote !> ("WASREMOTE= "++ show was)
-           then return Nothing
-           else case mx of
-             Nothing -> runTrans y   --  !> "RUNTRANS22222"
-             justx -> return justx
-
--- | a sinonym of empty that can be used in a monadic expression. it stop the
--- computation
-stop :: TransientIO a
-stop= Control.Applicative.empty
-
-instance Monoid a => Monoid (TransientIO a) where
-  mappend x y = mappend <$> x <*> y
-  mempty= return mempty
-
--- | set the current closure and continuation for the current statement
-setEventCont ::   TransientIO a -> (a -> TransientIO b) -> StateIO ()
-setEventCont x f  = do
-   st@(EventF  e _ fs d n  r applic  ch rc bs)  <- get
-   put $ EventF e x ( unsafeCoerce f : fs) d n  r applic  ch rc bs
-
-
--- | reset the closure and continuation. remove inner binds than the prevous computations may have stacked
--- in the list of continuations.
-resetEventCont :: Maybe a -> StateIO ()
-resetEventCont mx =do
-   st@(EventF e _ fs d n  r nr  ch rc bs)  <- get
-
-   let f= \mx ->  case mx of
-                       Nothing -> empty
-                       Just x  -> (unsafeCoerce $ head fs)  x
-   put $ EventF e (f mx) ( tailsafe fs)d n  r nr  ch rc bs
-   where
-   tailsafe []=[]
-   tailsafe (x:xs)= xs
-
-
-instance Monad TransientIO where
-      return x = Transient $ return $ Just x
-      x >>= f  = Transient $ do
-        setEventCont x  f
-
-        mk <- runTrans x
-        resetEventCont mk
-        case mk of
-           Just k  -> do
-               runTrans $ f k
-
-           Nothing -> return Nothing
-
-
-
-
---instance MonadTrans (Transient ) where
---  lift mx = Transient $ mx >>= return . Just
-
-instance MonadIO TransientIO where
-  liftIO x = Transient $ liftIO x >>= return . Just --     let x= liftIO io in x `seq` lift x
-
-
-
-
--- * Threads
-
-waitQSemB sem= atomicModifyIORef sem $ \n -> if n > 0 then(n-1,True) else (n,False)
-signalQSemB sem= atomicModifyIORef sem  $ \n ->  (n + 1,())
-
--- | set the maximun number of threads for a procedure. It is useful to limit the
--- parallelization of transient code that uses `parallel` `spawn` and `waitEvents`
-threads :: Int -> TransientIO a -> TransientIO a
-threads n proc= Transient $ do
-   msem <- gets maxThread
-   sem <- liftIO $ newIORef n
-   modify $ \s -> s{maxThread= Just sem}
-   r <- runTrans proc
-   modify $ \s -> s{maxThread = msem} -- restore it
-   return r
--- | delete all the previous childs generated by the expressions and continue execution
--- of the current thread.
-oneThread :: TransientIO a -> TransientIO a
-oneThread comp=  do
-   chs <- liftIO $ newTVarIO []
-   r <- comp
-   modify $ \ s -> s{children= chs}
-   killChilds
-   return r
-
--- | add n threads to the limit of threads. If there is no limit, it set it
-addThreads' :: Int -> TransIO ()
-addThreads' n= do
-   msem <- gets maxThread
-   case msem of
-    Just sem -> liftIO $ modifyIORef sem $ \n' -> n + n'
-    Nothing  -> do
-        sem <- liftIO (newIORef n)
-        modify $ \ s -> s{maxThread= Just sem}
-
--- | assure that at least there are n threads left
-addThreads n= do
-   msem <- gets maxThread
-   case msem of
-     Nothing -> return ()
-     Just sem ->  liftIO $ modifyIORef sem $ \n' -> if n' > n then n' else  n
-
-getNonUsedThreads :: TransIO (Maybe Int)
-getNonUsedThreads= do
-   msem <- gets maxThread
-   case msem of
-    Just sem -> liftIO $ Just <$> readIORef sem
-    Nothing -> return Nothing
-
-
--- | The threads generated in the process passed as parameter will not be killed.
-freeThreads :: TransientIO a -> TransientIO a
-freeThreads proc= Transient $ do
-     st <- get
-     put st{freeTh= True}
-     r <- runTrans proc
-     modify $ \st -> st{freeTh= freeTh st}
-     return r
-
--- | The threads will be killed when the parent thread dies. That is the default.
--- This can be invoked to revert the effect of `freeThreads`
-hookedThreads :: TransientIO a -> TransientIO a
-hookedThreads proc= Transient $ do
-     st <- get
-     put st{freeTh= False}
-     r <- runTrans proc
-     modify $ \st -> st{freeTh= freeTh st}
-     return r
-
-
--- | kill all the child processes
-killChilds :: TransientIO()
-killChilds= Transient $  do
-   cont <- get
-   liftIO $  killChildren cont
-   return $ Just ()
-
--- * extensible state: session data management
-
--- | Get the session data for the desired type if there is any.
-getSessionData ::  (MonadState EventF m,Typeable a) =>  m (Maybe a)
-getSessionData =  resp where
- resp= gets mfData >>= \list  ->
-    case M.lookup ( typeOf $ typeResp resp ) list  of
-      Just x  -> return . Just $ unsafeCoerce x
-      Nothing -> return $ Nothing
- typeResp :: m (Maybe x) -> x
- typeResp= undefined
-
--- | getSessionData specialized for the Transient monad. if Nothing, the
--- monadic computation does not continue.
---
--- If there is no such data, `getSData`  silently stop the computation.
--- That may or may not be the desired behaviour.
--- To make sure that this does not get unnoticed, use this construction:
---
--- >  getSData <|> error "no data"
---
-getSData ::  Typeable a => TransIO  a
-getSData= Transient getSessionData
-
-
--- | set session data for this type. retrieved with getSessionData orr getSData
-setSessionData ::  (MonadState EventF m, Typeable a) => a -> m ()
-setSessionData  x= do
-  let t= typeOf x in  modify $ \st -> st{mfData= M.insert  t (unsafeCoerce x) (mfData st)}
-
--- | a shorter name for setSessionData
-setSData ::  ( MonadState EventF m,Typeable a) => a -> m ()
-setSData= setSessionData
-
-delSessionData x=
-  modify $ \st -> st{mfData= M.delete (typeOf x ) (mfData st)}
-
-delSData :: ( MonadState EventF m,Typeable a) => a -> m ()
-delSData= delSessionData
-
---withSData ::  ( MonadState EventF m,Typeable a) => (Maybe a -> a) -> m ()
---withSData f= modify $ \st -> st{mfData=
---    let dat = mfData st
---        mx= M.lookup typeofx dat
---        mx'= case mx of Nothing -> Nothing; Just x -> unsafeCoerce x
---        fx=  f mx'
---        typeofx= typeOf $ typeoff f
---    in  M.insert typeofx  (unsafeCoerce fx) dat}
---    where
---    typeoff :: (Maybe a -> a) -> a
---    typeoff = undefined
-----
-
--- | generator of identifiers
-genNewId :: MonadIO m => MonadState EventF m =>  m Int
-genNewId=  do
-          st <- get
-
-          let n= mfSequence st
-          put $ st{mfSequence= n+1}
-          return n
-
-refSequence :: IORef Int
-refSequence= unsafePerformIO $ newp 0
-
-
--- | async calls
-
-data StreamData a=  SMore a | SLast a | SDone | SError String deriving (Typeable, Show,Read)
-
-
--- | variant of `parallel` that repeatedly executes the IO computation and kill the previously created childs
---
--- It is useful in single threaded problems where each event discard the computations spawned by
--- previous events
-waitEvents ::   IO b -> TransientIO b
-waitEvents io= do
-   SMore r <- parallel (SMore <$> io)
-   killChilds
-   return r
-
--- Multithreaded version of `waitEvents` that do not kill the computations spawned by previous events
-waitEvents' ::   IO b -> TransientIO b
-waitEvents' io= do
-   SMore r <- parallel (SMore <$> io)
-   return r
-
--- | variant of `parallel` that execute the IO computation once, and kill the previous child threads
-async  ::  IO b -> TransientIO b
-async io= do
-   SLast r <- parallel  (SLast <$>io)
-   killChilds
-   return r
-
--- | variant that spawn free threads. Since there is no thread control, this is faster
-spawn ::  IO b -> TransientIO b
-spawn io= freeThreads $ do
-
-   SMore r <- parallel (SMore <$>io)
-   return r
-
-
-
-
-
--- |  return empty to the current thread, in new thread, execute the IO action,
--- this IO action modify an internal buffer. then, executes the closure where `parallel` is located
--- In this new execution, since the buffer is filled, `paralle¤` return the content of this buffer.
--- Then it launch the continuation after it with this new value returned by the closure.
---
--- If the maximum number of threads, set with `threads` has been reached  `parallel` perform
--- the work sequentially, in the current thread.
--- So `parallel` means that 'it can be parallelized if there are thread available'
---
--- if there is a limitation of threads, when a thread finish, the counter of threads available
--- is increased so another `parallel` can make use of it.
---
--- The behaviour of `parallel` depend on `StreamData`; If `SMore`, `parallel` will excute again the
--- IO action. with `SLast`, `SDone` and `SError`, `parallel` will not repeat the IO action anymore.
-parallel  ::    IO (StreamData b) -> TransientIO (StreamData b)
-parallel  ioaction= Transient $   do
-    cont <- getCont                    -- !> "PARALLEL"
-    case event cont of
-     j@(Just _) -> do
-        put cont{event=Nothing}
-        return $ unsafeCoerce j
-     Nothing -> do
-        liftIO $ loop cont ioaction
-        return Nothing
-
--- executes the IO action and then the continuation included in the first parameter
-loop :: EventF -> IO (StreamData t) -> IO ()
-loop (cont'@(EventF e x fs a b c d peers childs g))  rec  =  do
-  chs <- liftIO $ newTVarIO []
-  let cont = EventF e x fs a b c d (Just cont') chs g
-      iocont dat= do
-          runStateT (runCont cont) cont{event= Just $ unsafeCoerce dat}
-          return ()
-
-      -- execute the IO computation and then the closure-continuation
-      loop'= forkMaybe False cont $ do
-         mdat <- rec
-         case mdat of
-             se@(SError _) -> iocont se
-             SDone -> iocont SDone
-             last@(SLast _) -> iocont last
-
-             more@(SMore _) -> do
-                  forkMaybe False cont $ iocont more
-                  loop'
-
-  loop'
-  return ()
-  where
-  forkMaybe True cont proc = forkMaybe' True cont proc
-  forkMaybe False cont proc = do
-     dofork <- case maxThread cont of
-                  Nothing -> return True
-                  Just sem -> do
-                    dofork <- waitQSemB sem
-                    if dofork then  return True else return False
-     forkMaybe' dofork cont proc
-
-  forkMaybe' dofork cont proc=
-         if dofork
-            then  do
-                 th <- forkFinally1 proc $ \me -> do
-                         case me of -- !> "THREAD END" of
-                          Left  e -> do
-
-                             when (fromException e /= Just ThreadKilled)$ liftIO $ print e
-                             killChildren  cont  !> "KILL RECEIVED" ++ (show $ unsafePerformIO myThreadId)
-
-                          Right _ -> when(not $ freeTh cont') $ do -- if was not a free thread
-                             --  if parent is alive
-                             --  then remove himself from the list (with free)
-                             --  and pass his active children to his parent
-
-                             th <- myThreadId
-                             mparent <- free th cont
-                             case mparent of
-                              Nothing  ->  return()
-                              Just parent -> atomically $ do
-                                     chs' <- readTVar $ children cont
-                                     chs  <- (readTVar $ children parent)
-                                     writeTVar (children parent)$ chs ++ chs'
-                                     return ()
-
-                         case maxThread cont of
-                           Just sem -> signalQSemB sem
-                           Nothing -> return ()
-
-
-                 addThread cont' cont{threadId=th}  -- !>  "thread created: "++ show th
-
-            else proc  -- !> "NO THREAD"
-
-forkFinally1 :: IO a -> (Either SomeException a -> IO ()) -> IO ThreadId
-forkFinally1 action and_then =
-  mask $ \restore ->
-    forkIO $ try (restore action) >>= and_then
-
-free th env= do
-  if isNothing $ parent env
-   then  return Nothing  !>  show th ++ " orphan"
-   else do
-    let msibling= fmap children $ parent env
-
-    case msibling of
-     Nothing -> return Nothing
-     Just sibling  -> do
-       found <- atomically $ do
-                sbs <- readTVar sibling
-                let (sbs', found) = drop [] th  sbs -- !> "search "++show th ++ " in " ++ show (map threadId sbs)
-                when found $ writeTVar sibling sbs'
-                return found
-       if (not found && isJust (parent env))
-         then free th $ fromJust $ parent env -- !> "toparent"
-         else return $ Just env
-
-   where
-   drop processed th []= (processed,False)
-   drop processed th (ev:evts)| th == threadId ev= (processed ++ evts, True)
-                    | otherwise= drop (ev:processed) th evts
-
-
-addThread parent child = when(not $ freeTh parent) $ do
-   let headpths= children parent
-   atomically $ do
-       ths <- readTVar headpths
-       writeTVar headpths $  child:ths
-
--- | kill all the threads associated with the continuation context
-killChildren  cont = do
-     forkIO $ do
-        let childs= children cont   !> "killChildren list= "++ addr (children cont)
-        ths <- atomically $ do
-           ths <- readTVar childs
-           writeTVar childs []
-           return ths
-        mapM_ (killThread . threadId) ths  !> "KILLEVENT " ++ show (map threadId ths)
-     return ()
-
-
-type EventSetter eventdata response= (eventdata ->  IO response) -> IO ()
-type ToReturn  response=  IO response
-
--- | deinvert an event handler. The first parameter is the event handler to be deinverted
--- the second is the value to return to the event handler
--- it configures the event handler by calling the first parameter, that set the event
--- handler, with the current continuation
-react
-  :: Typeable eventdata
-  => EventSetter eventdata response
-  -> ToReturn  response
-  -> TransientIO eventdata
-react setHandler iob= Transient $ do
-        cont    <- getCont
-        mEvData <- getSessionData
-        case mEvData of
-          Nothing -> do
-            liftIO $ setHandler $ \dat ->do
---              let cont'= cont{mfData = M.insert (typeOf dat)(unsafeCoerce dat) (mfData cont)}
-              runStateT (setSData dat >> runCont cont) cont
-              iob
-            return Nothing
-          Just dat -> delSessionData dat >> return (Just  dat)
-
-
--- * non-blocking keyboard input
-
-getLineRef= unsafePerformIO $ newTVarIO Nothing
-
-
-roption= unsafePerformIO $ newMVar []
-
--- | install a event receiver that wait for a string and trigger the continuation when this string arrives.
-option :: (Typeable b, Show b, Read b, Eq b) =>
-     b -> [Char] -> TransientIO b
-option ret message= do
-    let sret= show ret
-
-    liftIO $ putStrLn $ "Enter  "++sret++"\tto: " ++ message
-    liftIO $ modifyMVar_ roption $ \msgs-> return $ sret:msgs
-    waitEvents  $ getLine' (==ret)
-    liftIO $ putStrLn $ show ret ++ " chosen"
-    return ret
-
-
--- | validates an input entered in the keyboard in non blocking mode. non blocking means that
--- the user can enter also anything else to activate other option
--- unlike `option`, input only wait for one valid response
-input :: (Typeable a, Read a) => (a -> Bool) -> TransientIO a
-input cond= Transient . liftIO . atomically $ do
-       mr <- readTVar getLineRef
-       case mr of
-         Nothing -> retry
-         Just r ->
-            case reads1 r  of
-            (s,_):_ -> if cond s  --  !> show (cond s)
-                     then do
-                       writeTVar  getLineRef Nothing -- !>"match"
-                       return $ Just s
-
-                     else return Nothing
-            _ -> return Nothing
-
--- | non blocking `getLine` with a validator
-getLine' cond=    do
-     atomically $ do
-       mr <- readTVar getLineRef
-       case mr of
-         Nothing -> retry
-         Just r ->
-            case reads1 r of --  !> ("received " ++  show r ++ show (unsafePerformIO myThreadId)) of
-            (s,_):_ -> if cond s -- !> show (cond s)
-                     then do
-                       writeTVar  getLineRef Nothing -- !>"match"
-                       return s
-
-                     else retry
-            _ -> retry
-
-reads1 s=x where
-      x= if typeOf(typeOfr x) == typeOf "" then unsafeCoerce[(s,"")] else readsPrec 0 s
-      typeOfr :: [(a,String)] ->  a
-      typeOfr  = undefined
-
-inputLoop=  do
-    putStrLn "Press end to exit"
-    inputLoop'  -- !> "started inputLoop"
-    where
-
-    inputLoop'= do
-           r<- getLine
-           processLine r
-           inputLoop'
-
-processLine r= do
---   when (r=="end") $ putMVar rexit ()
-   let rs = breakSlash [] r
-   mapM_ (\ r -> if (r=="end") then putMVar rexit () else do
-                    threadDelay 1000
-                    atomically . writeTVar  getLineRef $ Just r) rs
-
-    where
-    breakSlash :: [String] -> String -> [String]
-    breakSlash s ""= s
-    breakSlash res s=
-      let (r,rest) = span(/= '/') s
-      in breakSlash (res++[r]) $ tail1 rest
-      where
-      tail1 []=[]
-      tail1 x= tail x
-
+module Transient.Base(
 
-rexit= unsafePerformIO newEmptyMVar
+TransIO(..), TransientIO
+,keep, keep', stop
+,option, input
+,async,waitEvents, spawn, parallel
+,react
 
-stay=  takeMVar rexit
+,setData,setSData,getData,getSData,delSData
 
--- | keep the main thread running, initiate the asynchronous keyboard input and execute
--- the transient computation. It also read a slash separated list of string that are interpreted by
--- `option` and `input` as if they were entered by the keyboard
-keep :: TransIO a -> IO a
-keep mx = do
-   forkIO $ inputLoop
-   forkIO $ runTransient mx  >> return ()
-   threadDelay 100000
-   args <- getArgs
-   let path = filter (\arg -> arg !! 0 == '/') args
-   when (not (null path)) $ do
-        putStr "Executing: " >> print (head path)
-        processLine $  head path
-   stay
+, threads,addThreads, freeThreads, hookedThreads,oneThread, killChilds
 
--- | same than `keep`but do not initiate the asynchronous keyboard input.
--- Useful for debugging
-keep' :: TransIO a -> IO a
-keep' mx  = do
-   forkIO $ runTransient mx  >> return ()
-   stay
+, (<**),(<***)
 
--- | force the finalization of the main thread and thus, all the application
-exit :: TransientIO a
-exit= do
-  liftIO $ putMVar rexit   True
-  stop
+, StreamData(..)
+,genId)  where
+-- /show
 
--- | alternative operator for maybe values. Used  in infix mode
-onNothing :: Monad m => m (Maybe b) -> m b -> m b
-onNothing iox iox'= do
-       mx <- iox
-       case mx of
-           Just x -> return x
-           Nothing -> iox'
+import    Transient.Internals
− src/Transient/DDS.hs
@@ -1,206 +0,0 @@-{-# LANGUAGE  ExistentialQuantification, DeriveDataTypeable #-}
-
-module Transient.DDS(distribute, cmap, reduce) where
-import Transient.Base
-import Transient.Move
-import Transient.Logged
-import Transient.Indeterminism
-
-import Control.Applicative
-import System.Random
-import Control.Monad.IO.Class
-
-import System.IO
-import Control.Monad
-import Data.Monoid
-
-import Data.Typeable
-import Data.List hiding (delete)
-import Control.Exception
-import Control.Concurrent
-import Data.Time.Clock
-
-import Data.TCache
-import Data.TCache.Defs
-
-import Data.ByteString.Lazy.Char8 (pack,unpack)
-import Control.Monad.STM
-
-
-data DDS a= Loggable a => DDS  (TransIO [PartRef a])
-data PartRef a= Ref Node Path Save deriving (Typeable, Read, Show)
-data Partition a=  Part Node Path Save [a] deriving (Typeable,Read,Show)
-type Save= Bool
-
-instance Indexable (Partition a) where
-    key (Part _ string True _)= "PartP@"++string
-    key (Part _ string False _)= "PartT@"++string
-
-instance Loggable a => IResource (Partition a) where
-    keyResource= key
-    readResourceByKey k= if k!! 5 /= 'P' then return Nothing
-        else defaultReadByKey k >>= return . fmap ( read . unpack)
-    writeResource (s@(Part _ _ save _))= if not save then return ()
-        else defaultWrite (defPath s ++ key s) (pack$ show s)
-
-instance Loggable a => Monoid (DDS a) where
-   mempty= DDS mempty
-   mappend (DDS ta) (DDS tb)= DDS $ ta <> tb
-
-
-
-type Path=String
-
-cmap :: Loggable b => (a -> b) -> DDS a -> DDS b
-cmap f (DDS mx)= DDS $ logged $ do
-        refs <- logged mx
-        foldl (<>) mempty $  map process refs
-
-  where
---  process ::  Partition a -> TransIO [Partition b]
-  process  (ref@(Ref node path sav))= runAt node $  do
-              xs <- getPartitionData ref mx
-              ref <- generateRef node $ map f xs
-              return [ref]
-
-
-
-
-
-reduce' :: (Loggable b, Monoid b) => ([a] -> b) -> DDS a -> TransientIO b
-reduce' f = reduce f mappend mempty
-
-reduce ::  Loggable b => ([a] -> b) -> (b -> b -> b)-> b -> DDS a ->TransientIO b
-reduce f f2 seed (DDS mx)= logged $ do
-     refs <- logged mx
-     logged $ foldl (\ x y -> f2 <$> x <*> y)(return seed) $  map process refs
-
-     where
-
---     process :: Partition a -> TransIO b
-     process (ref@(Ref node _ _))= runAt node $ do
-               xs <- getPartitionData ref mx
-               return $ f xs
-
-getPartitionData (Ref node path save) mx= do
-    Just (Part _ _ _ xs) <- liftIO $ atomically
-                                       $ readDBRef
-                                       $ getDBRef
-                                       $ keyResource((Part node path save undefined)
-                                                    `asTypeOf` getPartitionType mx)
-    return xs
-    where
-    getPartitionType :: TransIO [PartRef a]-> Partition a
-    getPartitionType = undefined -- type level only
-
--- 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
-runAtP :: Loggable a => Node  -> (Path -> IO a) -> Path -> TransIO a
-runAtP node f uuid= do
-   r <- streamFrom node $ liftIO $ (SLast <$> f uuid) `catch` sendAnyError
-   case r of
-     SLast r -> return r
-     SError e -> do
-         nodes <-  mclustered $ search uuid
-         when(length nodes < 1) $ asyncDuplicate node uuid
-         runAtP ( head nodes) f uuid
-
-search uuid= error $ "chunk failover not yet defined. Lookin for: "++ uuid
-
-asyncDuplicate node uuid= do
-    forkTo node
-    nodes <- getNodes
-    let node'= head $ nodes \\ [node]
-    content <- liftIO $ readFile uuid
-    runAt node' $ liftIO $ writeFile uuid content
-
-sendAnyError :: SomeException -> IO (StreamData a)
-sendAnyError e= return $ SError $ show e
-
-
-distribute :: Loggable a => [a] -> DDS a
-distribute = DDS  . logged . distribute'
-
-distribute' xs=  do
-   nodes <- logged getNodes
-   let size= length xs `div` length nodes
-       xss = split size xs
-   distribute'' xss nodes
-   where
-   split n []= []
-   split n xs=
-      let (h,t)= splitAt n xs
-      in h : split n t
-
-distribute'' :: Loggable a => [[a]] -> [Node] -> TransIO[PartRef a]
-distribute'' xss nodes =
-   foldl (<>) mempty $ zipWith move nodes xss   !> show xss
-   where
-   move node xs=  runAt node $ do
-                        par <- generateRef node xs
-                        return  [par]
-
-
-
-
-textFile name= DDS $ logged $ do
-   lines <- liftIO $ liftM lines (readFile name)
-   distribute' lines
-
---getId :: DDS a -> TransIO String
---getId (DDS mx)= do
---     ids <- mx
---     let ids' = map (\(Part _  path _ _) -> path) ids
---     return $ "DDS@"++ intercalate ":" ids'
-
-
---fromId :: String -> DDS a
---fromId ('D':'D':'S':'@':id)= do
---   let ids= wordsBy (==':') id
---   nodes <- clustered' $ mapM readDBRef ids
---   return
---
---   where
---   wordsBy :: (a -> Bool) -> [a] -> [[a]]
---   wordsBy f s = case dropWhile f s of
---        [] -> []
---        x:xs -> (x:w) : wordsBy f (drop1 z)
---            where (w,z) = break f xs
-
-
-generateRef :: Loggable a => Node -> [a] -> TransIO (PartRef a)
-generateRef node x= liftIO $ do
-       temp <- getTempName
-       let reg=  Part node temp False  x
-       atomically $ newDBRef reg
-       return $ getRef reg
-
-getRef (Part n t s x)= Ref n t s
-
-getTempName :: IO String
-getTempName=  ("DDS/" ++) <$> replicateM  5 (randomRIO ('a','z'))
-
-
--------------- Distributed  Datasource Streams ---------
--- | produce a stream of DDS's that can be map-reduced. Similar to spark streams.
--- each interval of time,a new DDS is produced.
-streamDDS
-  :: (Typeable a, Show a, Read a) =>
-     Integer -> IO (StreamData a) -> DDS a
-streamDDS time io= DDS $ do
-     xs <- groupByTime time $ do
-               r <- parallel io
-               case r of
-                    SDone -> stop
-                    SLast x -> return x
-                    SMore x -> return x
-                    SError e -> error e
-     distribute'  xs
-
-
-
-
-
-
-
src/Transient/EVars.hs view
@@ -2,25 +2,25 @@ module Transient.EVars where
 
 import Transient.Base
+import Transient.Internals(onNothing, EventF)
 import qualified Data.Map as M
 import Data.Typeable
 
 import Control.Concurrent
 import Control.Applicative
-import Data.IORef
-import Control.Monad.IO.Class
+import Control.Concurrent.STM
 import Control.Monad.State
 import Data.List(nub)
 
-newtype EVars= EVars  (IORef (M.Map Int [EventF]))  deriving Typeable
+--newtype EVars= EVars  (IORef (M.Map Int [EventF]))  deriving Typeable
 
-data EVar a= EVar Int (IORef (Maybe a)) deriving Typeable
+data EVar a= EVar Int  (TChan (StreamData a)) deriving  Typeable
 
 
 -- | creates an EVar.
 --
 -- Evars are event vars. `writeEVar` trigger the execution of all the continuations associated to the  `readEVar` of this variable
--- (the code that is after them) as  stack: the most recent reads are executed first.
+-- (the code that is after them).
 --
 -- It is like the publish-subscribe pattern but without inversion of control, since a readEVar can be inserted at any place in the
 -- Transient flow.
@@ -31,19 +31,20 @@ --
 -- The execution continues after the writeEVar when all subscribers have been executed.
 --
+-- Now the continuations are executed in parallel.
+--
 -- see https://www.fpcomplete.com/user/agocorona/publish-subscribe-variables-transient-effects-v
 --
 
 newEVar ::  TransientIO (EVar a)
 newEVar  = Transient $ do
-   getSessionData `onNothing`  do -- initialize EVars
-                            ref <- liftIO $ newIORef M.empty
-                            setSData $ EVars ref
-                            return  (EVars ref)
-   id <- genNewId
-   ref <- liftIO $ newIORef Nothing
-   return . Just $ EVar id ref
+   id <- genId
+   ref <-liftIO  newTChanIO
+   return . Just $ EVar id  ref
 
+-- | delete al the subscriptions for an evar.
+delEVar :: EVar a -> TransIO ()
+delEVar (EVar id  ref1)= liftIO $ atomically $ writeTChan  ref1 SDone
 
 -- | read the EVar. It only succeed when the EVar is being updated
 -- The continuation gets registered to be executed whenever the variable is updated.
@@ -51,49 +52,16 @@ -- again the continuation. The effect is that the continuation will be executed multiple times
 -- To avoid multiple registrations, use `unsubscribe`
 readEVar :: EVar a -> TransIO a
-readEVar (EVar id ref1)= Transient $ do
-   mr <- liftIO $ readIORef ref1 !> "READEVAR"
-   case mr of
-     Just _ -> return mr
-     Nothing -> do
-         cont <- getCont
-         EVars ref <- getSessionData `onNothing` error "No Events context"
-         map <- liftIO $ readIORef ref
-         let Just conts=  M.lookup id map <|> Just []
-         liftIO $ writeIORef ref $  M.insert id (cont:conts) map
-         return Nothing
-
--- |  update the EVar and execute all readEVar blocks with last in - first out priority
-writeEVar (EVar id ref1) x= Transient $ do
-   EVars ref <- getSessionData `onNothing` error "No Events context"
-   liftIO $ writeIORef ref1 $ Just x
-   map <- liftIO $ readIORef ref
-   let Just conts = M.lookup id map <|> Just []
-       len= length conts
-   runCont'  len id ref
-   liftIO $ writeIORef ref1 Nothing
-   return $ Just ()
-
-   where
-   runCont'  0 _ _ = return ()
-   runCont'  n id ref= do
-       map <- liftIO $ readIORef ref
-       let Just conts= M.lookup id map <|> Just []
-       let current= head conts
-           nexts= tail conts
-       runCont current
-       map' <- liftIO $ readIORef ref
-       let Just conts'= M.lookup id map' <|> Just []
-       if (length conts /= length conts') then return () else liftIO $ writeIORef ref $   M.insert id (nexts ++ [current]) map
-       runCont'  (n - 1) id ref
+readEVar (EVar id  ref1)= do
+     r <- parallel $ atomically $ readTChan ref1     -- !> "READEVAR"
+     case r of
+        SDone -> empty
+        SMore x -> return x
+        SLast x -> return x
+        SError e -> error $ show e
 
--- | unsuscribe the last `readEVar` executed for this EVar
-unsubscribe (EVar id _)= Transient $ do
-   EVars ref <- getSessionData `onNothing` error "No Events context"
-   map <- liftIO $ readIORef ref
-   let Just conts = M.lookup id map <|> Just []
-   liftIO $ writeIORef ref $  M.insert id (tail conts) map
+-- |  update the EVar and execute all readEVar blocks with "last in-first out" priority
+writeEVar (EVar id  ref1) x= liftIO $ atomically $ writeTChan  ref1 $ SMore x
 
-   return $ Just ()
 
 
src/Transient/Indeterminism.hs view
@@ -17,7 +17,7 @@ ) where
 
 import Transient.Base
-import Control.Monad.IO.Class
+import Transient.Internals(killChildren, EventF(..),hangThread)
 import Data.IORef
 import Control.Applicative
 import Data.Monoid
@@ -31,14 +31,14 @@ 
 -- | slurp a list of values and process them in parallel . To limit the number of processing
 -- threads, use `threads`
-choose  ::  [a] -> TransientIO a
+choose  ::  [a] -> TransIO a
 choose []= empty
 choose   xs = do
     evs <- liftIO $ newIORef xs
     r <- parallel $ do
            es <- atomicModifyIORef' evs $ \es -> let !tes= tail es in (tes,es)
            case es of
-            [x]  -> return $ SLast $ head es
+            [x]  -> return $ SLast x
             x:_  -> return $ SMore x
     return $ toData r
 
@@ -47,31 +47,41 @@       SLast x -> x
 
 -- | group the output of a possible multithreaded process in groups of n elements.
-group :: Int -> TransientIO a -> TransientIO [a]
+group :: Int -> TransIO a -> TransIO [a]
 group num proc =  do
     v <- liftIO $ newIORef (0,[])
     x <- proc
-    n <- liftIO $ atomicModifyIORef' v $ \(n,xs) -> let !n'=n +1 in ((n', x:xs),n')
-    if n < num
-      then stop
-      else liftIO $ atomicModifyIORef v $ \(n,xs) ->  ((0,[]),xs)
 
--- | group result for a time interval, measured with `diffUTCTime
-groupByTime :: Integer -> TransientIO a -> TransientIO [a]
+    mn <- liftIO $ atomicModifyIORef' v $ \(n,xs) ->
+            let !n'=n +1
+            in  if n'== num
+
+              then ((0,[]), Just xs)
+              else ((n', x:xs),Nothing)
+    case mn of
+      Nothing -> stop
+      Just xs -> return xs
+
+-- | group result for a time interval, measured with `diffUTCTime`
+groupByTime :: Integer -> TransIO a -> TransIO [a]
+
 groupByTime time proc =  do
     v  <- liftIO $ newIORef (0,[])
     t  <- liftIO getCurrentTime
     x  <- proc
-    n  <- liftIO $ atomicModifyIORef' v $ \(n,xs) -> let !n'=n +1 in ((n', x:xs),n')
     t' <- liftIO getCurrentTime
-    if diffUTCTime t' t < fromIntegral time
-      then stop
-      else liftIO $ atomicModifyIORef v $ \(n,xs) ->  ((0,[]),xs)
-
+    mn <- liftIO $ atomicModifyIORef' v $ \(n,xs) -> let !n'=n +1
+            in
+            if diffUTCTime t' t < fromIntegral time
+             then ((n', x:xs),Nothing)
+             else   ((0,[]), Just xs)
+    case mn of
+      Nothing -> stop
+      Just xs -> return xs
 
--- | alternative definition with more parallelism
-choose' :: [a] -> TransientIO a
-choose'  xs = foldl (<|>) empty $ map (\x -> parallel (return (SLast x)) >>= return . toData) xs
+-- | alternative definition with more parallelism, as the composition of n `async` sentences
+choose' :: [a] -> TransIO a
+choose' xs = foldl (<|>) empty $ map (async . return) xs
 
 
 --newtype Collect a= Collect (MVar (Int, [a])) deriving Typeable
@@ -82,49 +92,50 @@ --
 
 
--- | execute a process and get the first n solutions.
+-- | execute a process and get at least the first n solutions (they could be more).
 -- if the process end without finding the number of solutions requested, it return the found ones
 -- if he find the number of solutions requested, it kill the non-free threads of the process and return
 -- It works monitoring the solutions found and the number of active threads.
 -- If the first parameter is 0, collect will return all the results
-collect ::  Int -> TransientIO a -> TransientIO [a]
-collect n = collect' n 1000 0
+collect ::  Int -> TransIO a -> TransIO [a]
+collect n = collect' n 0.01 0
 
 -- | search also between two time intervals. If the first interval has passed and there is no result,
 --it stops.
 -- After the second interval, it stop unconditionally and return the current results.
--- It also stops as soon as there are enough results.
-collect' :: Int -> NominalDiffTime -> NominalDiffTime -> TransientIO a -> TransientIO [a]
-collect' n t1 t2 search=  do
-  rv <- liftIO $ atomically $ newTVar (0,[]) !> "NEWMVAR"
+-- It also stops as soon as there are enough results specified in the first parameter.
+collect' :: Int -> NominalDiffTime -> NominalDiffTime -> TransIO a -> TransIO [a]
+collect' n t1 t2 search= hookedThreads $  do
+  rv <- liftIO $ atomically $ newTVar (0,[]) -- !> "NEWMVAR"
   endflag <- liftIO $ newTVarIO False
-  st <- get
+  st <-  get
   t <- liftIO getCurrentTime
-  let any1 = do
-        r <- search   !> "ANY"
+  let worker = do
+        r <- search    -- !> "ANY"
         liftIO $ atomically $ do
             (n1,rs) <- readTVar rv
-            writeTVar  rv (n1+1,r:rs) !> "MODIFY"
+            writeTVar  rv (n1+1,r:rs)  -- !> "MODIFY"
         stop
 
-      monitor= freeThreads $ do
+      monitor=  freeThreads $ do
           xs <- async $ atomically $
                           do (n', xs) <- readTVar rv
                              ns <- readTVar $ children st
                              t' <- unsafeIOToSTM getCurrentTime
                              if
                                (n > 0 && n' >= n) ||
-                                 (null ns && (diffUTCTime t' t > t1)) || -- !> show (n, n', length ns)
+                                 (null ns && (diffUTCTime t' t > t1))    ||
                                  (t2 > 0 && diffUTCTime t' t > t2)
+                                        -- !>  (diffUTCTime t' t, n', length ns)
                                then return xs else retry
 
-          th <- liftIO $ myThreadId !> "KILL"
-          stnow <- get
+          th <- liftIO $ myThreadId   -- !> "KILL"
+          stnow <-  get
           liftIO $ killChildren st
-          liftIO $ addThread st stnow
+          liftIO $ hangThread st stnow
           return  xs
 
-  monitor <|> any1
+  monitor <|> worker
 
 
 
+ src/Transient/Internals.hs view
@@ -0,0 +1,883 @@+{-# LANGUAGE ScopedTypeVariables #-}
+-----------------------------------------------------------------------------
+--
+-- Module      :  Base
+-- Copyright   :
+-- License     :  GPL (Just (Version {versionBranch = [3], versionTags = []}))
+--
+-- Maintainer  :  agocorona@gmail.com
+-- Stability   :
+-- Portability :
+--
+-- | See http://github.com/agocorona/transient
+-- everithing in this module is exported in order to allow extensibility.
+-----------------------------------------------------------------------------
+{-# LANGUAGE ExistentialQuantification #-}
+{-# LANGUAGE FlexibleContexts          #-}
+{-# LANGUAGE FlexibleInstances         #-}
+{-# LANGUAGE MultiParamTypeClasses     #-}
+{-# LANGUAGE DeriveDataTypeable        #-}
+{-# LANGUAGE Rank2Types        #-}
+-- show
+module Transient.Internals where
+-- /show
+
+import           Control.Applicative
+import           Control.Monad.State
+import           Data.Dynamic
+import qualified Data.Map               as M
+import           Data.Monoid
+import           Debug.Trace
+import           System.IO.Unsafe
+import           Unsafe.Coerce
+import           Control.Exception
+import           Control.Concurrent
+import           Control.Concurrent.STM
+import           System.Mem.StableName
+import           Data.Maybe
+import           GHC.Conc
+import           Data.List
+import           Data.IORef
+import           System.Environment
+
+{-# INLINE (!>) #-}
+(!>) :: Show a => b -> a -> b
+(!>) x y=   trace (show y) x
+infixr 0 !>
+
+
+data TransIO  x = Transient  {runTrans :: StateT EventF IO (Maybe x)}
+type SData= ()
+
+type EventId= Int
+
+type TransientIO= TransIO
+
+data EventF  = forall a b . EventF{meffects     :: Effects
+                                  ,event       :: Maybe SData
+                                  ,xcomp       :: TransIO a
+                                  ,fcomp       :: [b -> TransIO b]
+                                  ,mfData      :: M.Map TypeRep SData
+                                  ,mfSequence  :: Int
+                                  ,threadId    :: ThreadId
+                                  ,freeTh      :: Bool
+                                  ,parent      :: Maybe EventF
+                                  ,children    :: TVar[EventF]
+                                  ,maxThread   :: Maybe (IORef Int)
+                                  }
+                                  deriving Typeable
+
+
+
+
+type Effects= forall a b c.TransIO a -> TransIO a -> (a -> TransIO b)
+     -> StateIO (StateIO (Maybe c) -> StateIO (Maybe c), Maybe a)
+
+
+
+
+instance MonadState EventF TransIO where
+  get  = Transient $ get >>= return . Just
+  put x= Transient $ put x >> return (Just ())
+  state f =  Transient $ do
+      s <- get
+      let ~(a, s') = f s
+      put s'
+      return $ Just a
+
+type StateIO= StateT EventF  IO
+
+
+
+runTransient :: TransIO x -> IO (Maybe x, EventF)
+runTransient t= do
+  th <- myThreadId
+  let eventf0=  EventF baseEffects Nothing empty [] M.empty 0
+          th False  Nothing  (unsafePerformIO $ newTVarIO []) Nothing
+
+
+  runStateT (runTrans t) eventf0
+
+
+
+
+-- | get the continuation context: closure, continuation, state, child threads etc
+getCont :: TransIO EventF
+getCont = Transient $ Just <$> get
+
+-- | run the closure and the continuation context
+runCont :: EventF -> StateIO (Maybe a)
+runCont (EventF _ _ x fs _ _  _ _  _ _ _)= runTrans $ do
+      r <- (unsafeCoerce x)
+      (compose fs r)
+
+-- | warning: radiactive untyped stuff. handle with care
+getContinuations :: StateIO [a -> TransIO b]
+getContinuations= do
+  EventF _ _ _ fs _ _ _ _ _ _ _  <- get
+  return $ unsafeCoerce fs
+
+{-
+runCont cont= do
+     mr <- runClosure cont
+     case mr of
+         Nothing -> return Nothing
+         Just r -> runContinuation cont r
+-}
+
+
+-- | compose a list of continuations
+compose []= const empty
+compose (f: fs)= \x -> f x >>= compose fs
+
+
+
+-- | run the closure  (the 'x'  in 'x >>= f') of the current bind operation.
+runClosure :: EventF -> StateIO (Maybe a)
+runClosure (EventF _ _ x _ _ _ _ _ _ _ _) =  unsafeCoerce $ runTrans x
+
+-- | run the continuation (the 'f' in 'x >>= f') of the current bind operation
+runContinuation ::  EventF -> a -> StateIO (Maybe b)
+runContinuation (EventF _ _ _ fs _ _ _ _  _ _ _) =
+   runTrans . (unsafeCoerce $ compose $  fs)
+
+
+setContinuation :: TransIO a -> (a -> TransIO b) -> [c -> TransIO c] -> StateIO ()
+setContinuation  b c fs =  do
+    (EventF eff ev _ _ d e f g h i j) <- get
+    put $ EventF eff ev b ( unsafeCoerce c: fs) d e f g h i j
+
+-- | run a chain of continuations. It is up to the programmer to assure by construction that
+--  each continuation type-check with the next, that the parameter type match the input of the first
+-- continuation.
+-- Normally this makes sense if it stop the current flow with `stop` after the invocation
+runContinuations :: [a -> TransIO b] -> c -> TransIO d
+runContinuations fs x= (compose $ unsafeCoerce fs)  x
+
+instance   Functor TransIO where
+  fmap f mx=   -- Transient $ fmap (fmap f) $ runTrans mx
+    do
+     x <- mx
+     return $ f x
+
+instance Applicative TransIO where
+  pure a  = Transient . return $ Just a
+
+  f <*> g = Transient $ do
+         rf <- liftIO $ newIORef (Nothing,[])
+         rg <- liftIO $ newIORef (Nothing,[])   -- !> "NEWIOREF"
+
+
+         fs  <- getContinuations
+
+         let
+
+             hasWait (_:Wait:_)= True
+             hasWait _ = False
+
+             appf k = Transient $  do
+                   Log rec _ full <- getData `onNothing` return (Log False [] [])
+                   liftIO $ writeIORef rf  (Just k,full)
+                   (x, full2)<- liftIO $ readIORef rg
+                   when (hasWait full2) $
+                        let full'= head full2: full
+                        in setData $ Log rec full' full'
+
+
+                   return $ Just k <*> x
+
+             appg x = Transient $  do
+                   Log rec _ full <- getData `onNothing` return (Log False [] [])
+                   liftIO $ writeIORef rg $ (Just x, full)
+                   (k,full1) <- liftIO $ readIORef rf
+                   when (hasWait  full) $
+                        let full'= head full: full1
+                        in setData $ Log rec full' full'
+
+                   return $ k <*> Just x
+
+         setContinuation f appf fs
+
+         k <- runTrans f    -- !> "RUN f"
+         was <- getData `onNothing` return NoRemote
+         when (was == WasParallel) $  setData NoRemote                                    -- !>  ("was=",was)
+
+         Log recovery _ full <- getData `onNothing` return (Log False [] [])
+
+         if was== WasRemote  || (not recovery && was == NoRemote  && isNothing k)
+         -- if the first operand was a remote request
+         -- (so this node is not master and hasn't to execute the whole expression)
+         -- or it was not an asyncronous term (a normal term without async or parallel
+         -- like primitives) and is nothing
+           then  do
+             restoreStack fs
+             return Nothing
+           else do
+             liftIO $ writeIORef rf  (k,full)
+
+             mfdata <- gets mfData
+             seq <- gets mfSequence
+
+             setContinuation g appg fs
+
+             x <- runTrans g             --  !> "RUN g"
+             Log recovery _ full' <- getData `onNothing` return (Log False [] [])
+             liftIO $ writeIORef rg  (x,full')
+             restoreStack fs
+             return $ k <*> x
+
+restoreStack fs=
+       modify $ \(EventF eff _ f _ a b c d parent children g1) ->
+               EventF eff Nothing f fs a b c d parent children g1
+
+
+
+-- | dynamic serializable data for logging
+data IDynamic= IDyns String | forall a.(Read a, Show a,Typeable a) => IDynamic a
+
+instance Show IDynamic where
+  show (IDynamic x)= show $ show x
+  show (IDyns s)= show s
+
+instance Read IDynamic where
+  readsPrec n str= map (\(x,s) -> (IDyns x,s)) $ readsPrec n str
+
+
+type Recover= Bool
+type CurrentPointer= [LogElem]
+type LogEntries= [LogElem]
+data LogElem=   Wait | Exec | Var IDynamic deriving (Read,Show)
+data Log= Log Recover  CurrentPointer LogEntries deriving Typeable
+
+
+instance Alternative TransIO where
+  empty = Transient $ return  Nothing
+  (<|>) = mplus
+
+--  Transient f <|> Transient g= Transient $ do
+--         k <-   f
+--         x <-   g
+--         return $ k <|> x
+
+
+
+data RemoteStatus=   WasRemote | WasParallel | NoRemote deriving (Typeable, Eq, Show)
+
+instance MonadPlus TransIO where
+    mzero= empty
+    mplus  x y=  Transient $ do
+         mx <- runTrans x                -- !!> "RUNTRANS11111"
+         was <- getData `onNothing` return NoRemote
+         if was== WasRemote              -- !!> "check wasremote"
+           then return Nothing           --  !> was
+           else case mx of
+             Nothing -> runTrans y      --  !!> "RUNTRANS22222"
+             justx -> return justx
+
+-- | a sinonym of empty that can be used in a monadic expression. it stop the
+-- computation
+stop :: Alternative m => m a
+stop= empty
+
+infixr 1  <**  ,  <***
+
+-- | forces the execution of the second operand even if the first stop. Return the first result (experimental)
+(<**) :: TransIO a -> TransIO b -> TransIO a
+(<**) ma mb= Transient $ do
+              fs  <- getContinuations
+              setContinuation ma (\x -> mb >> return x)  fs
+              a <- runTrans ma
+              runTrans mb
+              restoreStack fs
+              return  a
+
+atEnd= (<**)
+
+-- | forces the execution of the second operand  if the first fails only if the first operand
+-- is executed normally, that is , it is not a reexecution consequence of an internal event on it.
+-- Return the first result
+(<***) :: TransIO a -> TransIO b -> TransIO a
+(<***) ma mb= Transient $ do
+              a <- runTrans ma    -- !> "ma"
+              runTrans  mb        -- !> "mb"
+              return a
+
+
+atEnd' = (<***)
+
+instance Monoid a => Monoid (TransIO a) where
+  mappend x y = mappend <$> x <*> y
+  mempty= return mempty
+
+-- | set the current closure and continuation for the current statement
+setEventCont ::   TransIO a -> (a -> TransIO b) -> StateIO EventF
+setEventCont x f  = do
+
+   st@(EventF eff e _ fs d n  r applic  ch rc bs)  <- get
+   let cont=  EventF eff e x ( unsafeCoerce f : fs) d n  r applic  ch rc bs
+   put cont
+   return cont
+
+-- | reset the closure and continuation. remove inner binds than the previous computations may have stacked
+-- in the list of continuations.
+--resetEventCont :: Maybe a -> EventF -> StateIO (TransIO b -> TransIO b)
+resetEventCont mx _=do
+   st@(EventF eff e _ fs d n  r nr  ch rc bs)  <- get
+   let f= \mx ->  case mx of
+                       Nothing -> empty
+                       Just x  -> (unsafeCoerce $ head fs)  x
+   put $ EventF eff e (f mx) ( tailsafe fs) d n  r nr  ch rc bs
+   return  id
+
+tailsafe []=[]
+tailsafe (x:xs)= xs
+
+--refEventCont= unsafePerformIO $ newIORef baseEffects
+
+baseEffects :: Effects
+
+baseEffects x  x' f' = do
+            c <-setEventCont x'  f'
+            mk <- runTrans x
+            t <- resetEventCont mk c
+            return (t,mk)
+
+instance Monad TransIO where
+
+      return x = Transient $ return $ Just x
+
+      x >>= f  = Transient $ do
+--            effects <- gets effects -- liftIO $ readIORef refEventCont
+            (t,mk) <- baseEffects x x f
+            t $ case mk of
+                 Just k  ->  runTrans (f k)
+
+                 Nothing ->  return Nothing
+
+--instance MonadTrans (Transient ) where
+--  lift mx = Transient $ mx >>= return . Just
+
+instance MonadIO TransIO where
+  liftIO x = Transient $ liftIO x >>= return . Just --     let x= liftIO io in x `seq` lift x
+
+
+-- * Threads
+
+waitQSemB sem= atomicModifyIORef sem $ \n -> if n > 0 then(n-1,True) else (n,False)
+signalQSemB sem= atomicModifyIORef sem  $ \n ->  (n + 1,())
+
+-- | set the maximun number of threads for a procedure. It is useful to limit the
+-- parallelization of transient code that uses `parallel` `spawn` and `waitEvents`
+threads :: Int -> TransIO a -> TransIO a
+threads n proc= Transient $ do
+   msem <- gets maxThread
+   sem <- liftIO $ newIORef n
+   modify $ \s -> s{maxThread= Just sem}
+   r <- runTrans proc
+   modify $ \s -> s{maxThread = msem} -- restore it
+   return r
+
+-- | delete all the previous childs generated by the expressions and continue execution
+-- of the current thread.
+oneThread :: TransientIO a -> TransientIO a
+oneThread comp=  do
+   chs <- liftIO $ newTVarIO []
+   r <-  comp
+   modify $ \ s -> s{children= chs}
+   killChilds
+   return r
+
+
+
+-- | add n threads to the limit of threads. If there is no limit, it set it
+addThreads' :: Int -> TransIO ()
+addThreads' n= Transient $ do
+   msem <- gets maxThread
+   case msem of
+    Just sem -> liftIO $ modifyIORef sem $ \n' -> n + n'
+    Nothing  -> do
+        sem <- liftIO (newIORef n)
+        modify $ \ s -> s{maxThread= Just sem}
+   return $ Just ()
+
+-- | assure that at least there are n threads available
+addThreads n= Transient $ do
+   msem <- gets maxThread
+   case msem of
+     Nothing -> return ()
+     Just sem ->  liftIO $ modifyIORef sem $ \n' -> if n' > n then n' else  n
+   return $ Just ()
+--getNonUsedThreads :: TransIO (Maybe Int)
+--getNonUsedThreads= Transient $ do
+--   msem <- gets maxThread
+--   case msem of
+--    Just sem -> liftIO $ Just <$> readIORef sem
+--    Nothing -> return Nothing
+
+
+-- | The threads generated in the process passed as parameter will not be killed.
+freeThreads :: TransIO a -> TransIO a
+freeThreads proc= Transient $ do
+     st <- get
+     put st{freeTh= True}
+     r <- runTrans proc
+     modify $ \s -> s{freeTh= freeTh st}
+     return r
+
+-- | The threads will be killed when the parent thread dies. That is the default.
+-- This can be invoked to revert the effect of `freeThreads`
+hookedThreads :: TransIO a -> TransIO a
+hookedThreads proc= Transient $ do
+     st <- get
+     put st{freeTh= False}
+     r <- runTrans proc
+     modify $ \st -> st{freeTh= freeTh st}
+     return r
+
+-- | kill all the child processes
+killChilds :: TransientIO()
+killChilds= Transient $  do
+   cont <- get
+   liftIO $  killChildren cont
+   return $ Just ()
+
+-- * extensible state: session data management
+
+-- | Get the state data for the desired type if there is any.
+getData ::  (MonadState EventF m,Typeable a) =>  m (Maybe a)
+getData =  resp where
+ resp= gets mfData >>= \list  ->
+    case M.lookup ( typeOf $ typeResp resp ) list  of
+      Just x  -> return . Just $ unsafeCoerce x
+      Nothing -> return Nothing
+ typeResp :: m (Maybe x) -> x
+ typeResp= undefined
+
+
+-- | getData specialized for the Transient monad. if Nothing, the
+-- monadic computation does not continue.
+--
+-- If there is no such data, `getSData`  silently stop the computation.
+-- That may or may not be the desired behaviour.
+-- To make sure that this does not get unnoticed, use this construction:
+--
+-- >  getSData <|> error "no data"
+--
+getSData ::  Typeable a => TransIO  a
+getSData= Transient getData
+
+
+
+-- | set session data for this type. retrieved with getData or getSData
+-- Note that this is data in a state monad, that means that the update only affect downstream
+-- in the monad execution. it is not a global state neither a per user or per thread state
+-- it is a monadic state like the one of a state monad.
+setData ::  (MonadState EventF m, Typeable a) => a -> m ()
+setData  x=
+  let t= typeOf x in  modify $ \st -> st{mfData= M.insert  t (unsafeCoerce x) (mfData st)}
+
+-- | a shorter name for setData
+setSData ::  (MonadState EventF m, Typeable a) => a -> m ()
+setSData = setData
+
+delSessionData x=
+  modify $ \st -> st{mfData= M.delete (typeOf x ) (mfData st)}
+
+delSData :: ( MonadState EventF m,Typeable a) => a -> m ()
+delSData= delSessionData
+
+--withSData ::  ( MonadState EventF m,Typeable a) => (Maybe a -> a) -> m ()
+--withSData f= modify $ \st -> st{mfData=
+--    let dat = mfData st
+--        mx= M.lookup typeofx dat
+--        mx'= case mx of Nothing -> Nothing; Just x -> unsafeCoerce x
+--        fx=  f mx'
+--        typeofx= typeOf $ typeoff f
+--    in  M.insert typeofx  (unsafeCoerce fx) dat}
+--    where
+--    typeoff :: (Maybe a -> a) -> a
+--    typeoff = undefined
+----
+
+-- | generator of identifiers that are unique withing the current monadic sequence
+-- They are not unique in the whole program.
+genId :: MonadState EventF m =>  m Int
+genId= do
+      st <- get
+      let n= mfSequence st
+      put st{mfSequence= n+1}
+      return n
+
+getPrevId :: MonadState EventF m =>  m Int
+getPrevId= do
+      n <- gets mfSequence
+      return n
+
+instance Read SomeException where
+   readsPrec n str=
+      let [(s , r)]= read str in [(SomeException $ ErrorCall s,r)]
+
+-- | async calls
+
+data StreamData a=  SMore a | SLast a | SDone | SError SomeException deriving (Typeable, Show,Read)
+
+
+-- | variant of `parallel` that repeatedly executes the IO computation and kill the previously created childs
+--
+-- It is useful in single threaded problems where each event discard the computations spawned by
+-- previous events
+waitEvents ::   IO b -> TransIO b
+waitEvents io= do
+   SMore r <- parallel (SMore <$> io)
+   return r
+
+-- Multithreaded version of `waitEvents` that do not kill the computations spawned by previous events
+waitEvents' ::   IO b -> TransIO b
+waitEvents' io= do
+   SMore r <- parallel (SMore <$> io)
+   return r
+
+-- | variant of `parallel` that execute the IO computation once, and kill the previous child threads
+async  ::  IO b -> TransIO b
+async io= do
+   SLast r <- parallel  (SLast <$>io)
+   return r
+
+-- | variant that spawn free threads. Since there is no thread control, this is faster
+spawn ::  IO b -> TransIO b
+spawn io= freeThreads $ do
+   SMore r <- parallel (SMore <$>io)
+   return r
+
+
+
+
+
+-- |  return empty to the current thread, in new thread, execute the IO action,
+-- this IO action modify an internal buffer. then, executes the closure where `parallel` is located
+-- In this new execution, since the buffer is filled, `parallel` return the content of this buffer.
+-- Then it launch the continuation after it with this new value returned by the closure.
+--
+-- If the maximum number of threads, set with `threads` has been reached  `parallel` perform
+-- the work sequentially, in the current thread.
+-- So `parallel` means that 'it can be parallelized if there are thread available'
+--
+-- if there is a limitation of threads, when a thread finish, the counter of threads available
+-- is increased so another `parallel` can make use of it.
+--
+-- The behaviour of `parallel` depend on `StreamData`; If `SMore`, `parallel` will excute again the
+-- IO action. with `SLast`, `SDone` and `SError`, `parallel` will not repeat the IO action anymore.
+parallel  ::    IO (StreamData b) -> TransIO (StreamData b)
+parallel  ioaction= Transient $   do
+
+    cont <- get                    -- !> "PARALLEL"
+    case event cont of
+     j@(Just _) -> do
+        put cont{event=Nothing}
+        return $ unsafeCoerce j
+     Nothing -> do
+        liftIO $ loop cont ioaction
+        setData WasParallel
+        return Nothing
+
+
+
+
+
+-- executes the IO action and then the continuation included in the first parameter
+loop :: EventF -> IO (StreamData t) -> IO ()
+loop (cont'@(EventF eff e x fs a b c d _ childs g))  rec  =  do
+  chs <- liftIO $ newTVarIO []
+  let cont = EventF eff e x fs a b c d (Just cont') chs g
+      iocont dat= do
+          runStateT (runCont cont) cont{event= Just $ unsafeCoerce dat}
+          return ()
+
+      -- execute the IO computation and then the closure-continuation
+      loop'= forkMaybe False cont $ do
+         mdat <- threadDelay 0 >> rec
+         case mdat of
+             se@(SError _) ->  iocont se
+             SDone ->          iocont SDone
+             last@(SLast _) -> iocont last
+
+             more@(SMore _) -> do
+                  forkMaybe False cont $ iocont more
+                  loop'
+
+  loop'
+  return ()
+  where
+  forkMaybe True cont proc = forkMaybe' True cont proc
+  forkMaybe False cont proc = do
+     dofork <- case maxThread cont of
+                  Nothing -> return True
+                  Just sem -> do
+                    dofork <- waitQSemB sem
+                    if dofork then  return True else return False
+     forkMaybe' dofork cont proc
+
+  forkMaybe' dofork cont proc=
+         if dofork
+            then  do
+                 forkFinally1 (do
+                     th <- myThreadId
+                     hangThread cont' cont{threadId=th}  -- !!>  "thread created: "++ show th
+                     proc)
+                     $ \me -> do
+                         case me of -- !> "THREAD END" of
+                          Left  e -> do
+                             when (fromException e /= Just ThreadKilled)$ liftIO $ print e
+                             killChildren  cont  -- !!> "KILL RECEIVED" ++ (show $ unsafePerformIO myThreadId)
+
+                          Right _ ->  when(not $ freeTh cont') $ do -- if was not a free thread
+                             --  if parent is alive
+                             --  then remove himself from the parent list (with free)
+                             --  and pass his active children to his parent
+
+                             th <- myThreadId
+                             mparent <- free th cont
+                             return ()
+
+--                             case mparent of
+--                              Nothing  ->  return()
+--                              Just parent -> atomically $ do
+--                                     chs' <- readTVar $ children cont
+--                                     chs  <- (readTVar $ children parent)
+--                                     writeTVar (children parent)$ chs ++ chs'
+--                                     return ()
+
+                         case maxThread cont of
+                           Just sem -> signalQSemB sem
+                           Nothing -> return ()
+                 return ()
+
+
+
+
+            else proc  -- !> "NO THREAD"
+
+forkFinally1 :: IO a -> (Either SomeException a -> IO ()) -> IO ThreadId
+forkFinally1 action and_then =
+  mask $ \restore ->
+    forkIO $ try (restore action) >>= and_then
+
+free th env= do
+  if isNothing $ parent env
+   then  return Nothing  -- !!>  show th ++ " orphan"
+   else do
+    let msibling= fmap children $ parent env
+
+    case msibling of
+     Nothing -> return Nothing
+     Just sibling  -> do
+       found <- atomically $ do
+                sbs <- readTVar sibling
+                let (sbs', found) = drop [] th  sbs    -- !!> "search "++show th ++ " in " ++ show (map threadId sbs)
+                when found $ writeTVar sibling sbs'    -- !> ("new list",map threadId sbs')
+                return found
+       if (not found && isJust (parent env))
+         then free th $ fromJust $ parent env         -- !!> "toparent"
+         else return $ Just env
+
+   where
+   drop processed th []= (processed,False)
+   drop processed th (ev:evts)| th ==  threadId ev= (processed ++ evts, True)
+                    | otherwise= drop (ev:processed) th evts
+
+hangThread parent child = when(not $ freeTh parent) $ do
+   let headpths= children parent
+   atomically $ do
+       ths <- readTVar headpths
+       writeTVar headpths $  child:ths   -- !!>  "thread added: "++ show (threadId child)
+
+-- | kill  all the child threads associated with the continuation context
+killChildren cont  = do
+
+     forkIO $ do
+        let childs= children cont
+        ths <- atomically $ do
+           ths <- readTVar childs
+           writeTVar childs []
+           return ths
+--        mapM_ killChildren ths       -- recursive not needed, event handlers do it
+
+        mapM_ (killThread . threadId) ths   -- !!> ("KILLEVENT " ++ show (map threadId ths) ++
+--                                                        if length ths <20 then ""
+--                                                          else error "long list of threads" )
+     return ()
+
+
+type EventSetter eventdata response= (eventdata ->  IO response) -> IO ()
+type ToReturn  response=  IO response
+
+-- | deinvert an event handler. The first parameter is the event handler setter to be
+-- deinverted. Usually it is the primitive provided by a framework to set an event handler
+--
+-- the second is the value to return to the event handler
+-- it configures the event handler by calling the first parameter, that set the event
+-- handler, with the current continuation
+react
+  :: Typeable eventdata
+  => EventSetter eventdata response
+  -> ToReturn  response
+  -> TransIO eventdata
+react setHandler iob= Transient $ do
+        cont    <- get
+        mEvData <- getData
+        case mEvData of
+          Nothing -> do
+            liftIO $ setHandler $ \dat ->do
+              runStateT (setData dat >> runCont cont) cont
+              iob
+            setSData WasParallel
+            return Nothing
+          Just dat -> do
+             delSessionData dat
+             return (Just  dat)
+
+
+
+
+
+-- * non-blocking keyboard input
+
+getLineRef= unsafePerformIO $ newTVarIO Nothing
+
+
+roption= unsafePerformIO $ newMVar []
+
+-- | install a event receiver that wait for a string and trigger the continuation when this string arrives.
+option :: (Typeable b, Show b, Read b, Eq b) =>
+     b -> String -> TransIO b
+option ret message= do
+    let sret= show ret
+
+    liftIO $ putStrLn $ "Enter  "++sret++"\tto: " ++ message
+    liftIO $ modifyMVar_ roption $ \msgs-> return $ sret:msgs
+    waitEvents  $ getLine' (==ret)
+    liftIO $ putStrLn $ show ret ++ " chosen"
+    return ret
+
+
+-- | validates an input entered in the keyboard in non blocking mode. non blocking means that
+-- the user can enter also anything else to activate other option
+-- unlike `option`, wich watch continuously, input only wait for one valid response
+input :: (Typeable a, Read a) => (a -> Bool) -> TransIO a
+input cond= Transient . liftIO . atomically $ do
+       mr <- readTVar getLineRef
+       case mr of
+         Nothing -> retry
+         Just r ->
+            case reads1 r  of
+            (s,_):_ -> if cond s  --  !> show (cond s)
+                     then do
+                       writeTVar  getLineRef Nothing -- !>"match"
+                       return $ Just s
+
+                     else return Nothing
+            _ -> return Nothing
+
+-- | non blocking `getLine` with a validator
+getLine' cond=    do
+     atomically $ do
+       mr <- readTVar getLineRef
+       case mr of
+         Nothing -> retry
+         Just r ->
+            case reads1 r of --  !> ("received " ++  show r ++ show (unsafePerformIO myThreadId)) of
+            (s,_):_ -> if cond s -- !> show (cond s)
+                     then do
+                       writeTVar  getLineRef Nothing -- !>"match"
+                       return s
+
+                     else retry
+            _ -> retry
+
+reads1 s=x where
+      x= if typeOf(typeOfr x) == typeOf "" then unsafeCoerce[(s,"")] else readsPrec 0 s
+      typeOfr :: [(a,String)] ->  a
+      typeOfr  = undefined
+
+inputLoop=  do
+    putStrLn "Press end to exit"
+    inputLoop'  -- !> "started inputLoop"
+    where
+
+    inputLoop'= do
+           r<- getLine
+           processLine r
+           inputLoop'
+
+processLine r= do
+--   when (r=="end") $ atomically $ writeTVar rexit ()
+   let rs = breakSlash [] r
+   mapM_ (\ r -> if (r=="end") then exit' $ Left "terminated by user" else do
+                    threadDelay 1000
+                    atomically . writeTVar  getLineRef $ Just r) rs
+
+    where
+    breakSlash :: [String] -> String -> [String]
+    breakSlash s ""= s
+    breakSlash res s=
+      let (r,rest) = span(/= '/') s
+      in breakSlash (res++[r]) $ tail1 rest
+      where
+      tail1 []=[]
+      tail1 x= tail x
+
+{-# NOINLINE rexit #-}
+rexit= unsafePerformIO $ newEmptyMVar
+
+-- | wait for the execution of `exit` and return the result
+stay=   do
+    mr <- takeMVar rexit
+    case mr of
+      Right Nothing -> stay
+      Right (Just r) -> return r
+      Left msg -> error msg
+
+-- | keep the main thread running, initiate the asynchronous keyboard input and execute
+-- the transient computation. It also read a slash separated list of string that are interpreted by
+-- `option` and `input` as if they were entered by the keyboard
+keep :: TransIO a -> IO a
+keep mx = do
+   forkIO inputLoop
+   forkIO $ do
+           runTransient $  mx >> liftIO (putMVar rexit  $ Right Nothing) -- to avoid takeMVar in a infinite loop
+           return ()
+   threadDelay 100000
+   args <- getArgs
+   let path = filter (\arg -> arg !! 0 == '/') args
+   when (not (null path)) $ do
+        putStr "Executing: " >> print (head path)
+        processLine $  head path
+   stay
+
+-- | same than `keep`but do not initiate the asynchronous keyboard input.
+-- Useful for debugging
+keep' :: TransIO a -> IO a
+keep' mx  = do
+
+   forkIO $ do
+           runTransient $  mx >>   liftIO (putMVar rexit  $ Right Nothing)   -- to avoid takeMVar in a infinite loop
+           return ()
+   threadDelay 100000
+
+   stay
+
+-- | force the finalization of the main thread and thus, all the Transient block (and the application
+-- if there is no more code)
+exit :: a -> TransIO a
+exit x= do
+  liftIO $  putMVar rexit .  Right $ Just   x
+  stop
+
+exit' x= liftIO $  putMVar rexit  x
+-- | alternative operator for maybe values. Used  in infix mode
+onNothing :: Monad m => m (Maybe b) -> m b -> m b
+onNothing iox iox'= do
+       mx <- iox
+       case mx of
+           Just x -> return x
+           Nothing -> iox'
src/Transient/Logged.hs view
@@ -17,54 +17,27 @@ import Data.Typeable
 import Unsafe.Coerce
 import Transient.Base
+import Transient.Internals(onNothing,IDynamic(..),Log(..),LogElem(..),RemoteStatus(..))
 import Control.Applicative
 import Control.Monad.IO.Class
 
 
-newtype TransLIO  a =  TransLIO {runLogged :: TransIO a}
 
---data RLogged= forall a.(Read a, Show a) => RLogged  a
-
-instance Functor TransLIO  where
---   fmap f mx=  mx >>= \(TransLIO x) ->  TransLIO (f x)
-
-instance Applicative TransLIO where
---   pure= return
---   f <*> g= TransLIO $ do
---         x <- f
---         y <- g
---         return $ x y
-
-instance  Monad TransLIO  where
-   return  x=  TransLIO $ return x
-   TransLIO x >>= f =  TransLIO $  do
-         r <- x
-         runLogged $ f r
-
---data IDynamic= IDyns String | forall a.(Read a, Show a,Typeable a) => IDynamic a
-
---instance Show IDynamic where
---  show (IDynamic x)= show $ show x
---  show (IDyns s)= show s
---
---instance Read IDynamic where
---  readsPrec n str= map (\(x,s) -> (IDyns x,s)) $ readsPrec n str
-
 class (Show a, Read a,Typeable a) => Loggable a
 instance (Show a, Read a,Typeable a) => Loggable a
 
 fromIDyn :: (Read a, Show a, Typeable a) => IDynamic -> a
 fromIDyn (IDynamic x)= unsafeCoerce x
 
-fromIDyn (IDyns s)=r where r= read s !> "read " ++ s ++ "to type "++ show (typeOf r)
+fromIDyn (IDyns s)=r where r= read s  -- !!> "read " ++ s ++ "to type "++ show (typeOf r)
 
 toIDyn x= IDynamic x
 
--- | synonymous of `step`
-logged :: (Show a, Read a, Typeable a) => TransientIO a -> TransientIO a
-logged= step
-
+{- TODO add save/recover from log
+rerun :: Log -> TransIO a -> TransIO a
 
+getLog :: TransIO Log
+-}
 
 -- | write the result of the computation in  the log and return it.
 -- but if there is data in the internal log, it read the data from the log and
@@ -75,39 +48,67 @@ -- this reduce the log of large computations to the minimum. That is a feature not present
 -- in the package Workflow.
 --
--- >  r <- step $ do
--- >          step this :: TransIO ()
--- >          step that :: TransIO ()
--- >          step thatOther
+-- >  r <- logged $ do
+-- >          logged this :: TransIO ()
+-- >          logged that :: TransIO ()
+-- >          logged thatOther
 -- >  liftIO $ print r
 --
 --  when `print` is executed, the log is just the value of r.
 --
---  but when `thatOther` is executed the log is: [Exec,(), ()]
+--  but at the `thatOther` execution the log is: [Exec,(), ()]
 --
-step :: (Show a, Read a, Typeable a) => TransientIO a -> TransientIO a
-step mx=  do
-    Log recover rs full <- getSData <|> return ( Log False  [][])
-
+logged :: (Show a, Read a, Typeable a) => TransientIO a -> TransientIO a
+logged mx =  Transient $ do
+   Log recover rs full <- getData `onNothing` return ( Log False  [][])
+   runTrans $
     case (recover,rs) of
-      (True, Step x: rs') -> do
-            setSData $ Log recover rs' full
-            return $ fromIDyn x  !>  "read in step:" ++ show x
+      (True, Var x: rs') -> do setSData $ Log True rs' full
+                               return $ fromIDyn x              -- !!>  "read in Var:" ++ show x
 
-      (True,Exec:rs') -> do
-            setSData $ Log recover rs' full
-            mx
+      (True, Exec:rs') -> do
+            setSData $ Log True  rs' full
+            mx                                 -- !!> "Var True Exec"
 
-      (True, WaitRemote:rs') -> do
-            setSData (Log recover rs' full) !> "waitRemote2"
+      (True, Wait:rs') -> do
+            setSData (Log True  rs' full)      -- !!> "Wait"
             empty
 
       _ -> do
-            let add= Exec:  full
-            setSData $ Log False add add
-            r <-  mx
-            let add= Step (toIDyn r): full
+            let add= Exec: full
             setSData $ Log False add add
+
+            r <-  mx <*** ( do  -- when   p1 <|> p2, to avoid the re-execution of p1 at the
+                                -- recovery when p1 is asynchronous
+                            r <- getSData <|> return NoRemote
+                            case r of
+                                      WasParallel ->
+                                         let add= Wait: full
+                                         in setSData $ Log False add add
+                                      _ -> return ())
+
+
+            let add= Var (toIDyn r): full
+            (setSData $ Log False add add)     -- !!> "AFTER Var"
             return  r
+
+
+
+
+
+
+
+--step :: (Show a, Read a, Typeable a) => TransientIO a -> TransientIO a
+--step mx = step' mx $ \full mx -> do
+--            let add= Exec: full
+--            setSData $ Log False add add
+--
+--            r <-  mx
+--
+--            let add= Step (toIDyn r): full
+--            (setSData $ Log False add add)     -- !!> "AFTER STEP"
+--            return  r
+--
+--
 
 
− src/Transient/Move.hs
@@ -1,453 +0,0 @@------------------------------------------------------------------------------
---
--- Module      :  Transient.Move
--- Copyright   :
--- License     :  GPL-3
---
--- Maintainer  :  agocorona@gmail.com
--- Stability   :
--- Portability :
---
--- | see <https://www.fpcomplete.com/user/agocorona/moving-haskell-processes-between-nodes-transient-effects-iv>
------------------------------------------------------------------------------
-{-# LANGUAGE DeriveDataTypeable , ExistentialQuantification
-    ,ScopedTypeVariables, StandaloneDeriving, RecordWildCards #-}
-module Transient.Move where
-import Transient.Base hiding (onNothing)
-import Transient.Logged
-import Transient.EVars
-import Data.Typeable
-import Control.Applicative
-import Network
-
-
-import Control.Monad.IO.Class
-import Control.Monad.State
-import System.IO
-import Control.Exception
-import Data.Maybe
-import Unsafe.Coerce
-
---import System.Directory
-import Control.Monad
-import Network.Info
-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 Network.Socket as NS
-import qualified Network.BSD as BSD
-
-
-import qualified Data.ByteString.Lazy.Char8 as BS
-import System.IO
-
-import Control.Concurrent
-
-import Data.TCache
-import Data.TCache.DefaultPersistence
-
-
--- | continue the execution in a new node
--- all the previous actions from `listen` to this statement must have been logged
-beamTo :: Node -> TransientIO ()
-beamTo node =  do
-  Log rec log _ <- getSData <|> return (Log False [][])
-  if rec then return () else do
-      Connection{bufferSize=bufSize}
-        <- getSData
-              <|> return (Connection beamToErr Nothing 8192 beamToErr)
-      h <-  assign bufSize node
-      liftIO $ hPutStrLn h (show $ SMore $ reverse log) >> hFlush h
-      release node h
-      let log'= WaitRemote: log
-      setSData $ Log rec log' log'
-      stop
-  where
-  beamToErr= error "beamTo: some connection param has not been set. Use setMyNode and listen"
--- | 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 -> TransientIO ()
-forkTo node= do
-  Log rec log _<- getSData <|> return (Log False [][])
-  if rec then return () else do
-      Connection {bufferSize=bufSize}  <- getSData <|> return (Connection undefined Nothing 8192 undefined)
-      h <-assign bufSize node
-      liftIO $ hPutStrLn h (show $ SMore $ reverse log)  >> hFlush h
-      release node h
-
--- | executes an action in another node.
--- All the previous actions from `listen` to this statement must have been logged
-callTo :: Loggable a => Node -> TransIO a -> TransIO a
-callTo n p = streamFrom n (SMore <$> p) >>= \(SMore x) -> return x
-
-
--- | synonymous of `callTo`
--- all the previous actions from `listen` to this statement must have been logged
-runAt :: Loggable a => Node -> TransIO a -> TransIO a
-runAt= callTo
-
--- | `callTo` can stream data but can not inform the receiving process about the finalization. This call
--- does it.
---
--- All the previous actions from `listen` to this statement must have been logged
-streamFrom :: Loggable a => Node -> TransIO (StreamData a) -> TransIO (StreamData a)
-streamFrom node remoteProc= logged $ Transient $ do
-      Log rec log fulLog <- getSessionData `onNothing` return (Log False [][])
-      if rec
-         then
-          runTrans $ do
---            rnum <- liftIO $ newMVar (0 :: Int)
-            Connection _(Just (ConnectionData _ h sock blocked )) _ _ <- getSData  <|> error "callTo: no hander"
-
-            r <- remoteProc         !> "executing remoteProc" !> "CALLTO REMOTE" -- LOg="++ show fulLog
-            n <- liftIO $ do
---                modifyMVar_ rnum $ \n -> return (n+1)
-                withMVar blocked $ const $ hPutStrLn   h (show r)  `catch` (\(e::SomeException) -> sClose sock)
-                 -- !> "sent response, HANDLE="++ show h
---                modifyMVar rnum $ \n -> return (n-1,n)
-
- --           adjustSenderThreads n
-
-            setSData WasRemote
-            stop
-          <|> do
-            setSData WasRemote
-            stop
-
-         else do
-            Connection _ _ bufSize _<- getSessionData `onNothing` return (Connection undefined Nothing 8192 undefined)
-            h <- assign bufSize node
-            liftIO $ hSetBuffering h LineBuffering
-            liftIO $ hPutStrLn h ( show $ SLast $ reverse fulLog) {- >> hFlush h -} !> "CALLTO LOCAL" -- send "++ show  log
-
-
-            let log'= WaitRemote:tail log
-            setSessionData $ Log rec log' log'
-            runTrans $ do
-              r<- parallel $ do -- local side
-                   r <- readHandler h
-
-                   case r of
-                        SDone -> release node h >> return SDone
-                        other -> return other
-
---              adjustRecThreads h
-              case r of
-                SDone -> empty
-                other  -> 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")
---
---      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)))
-
-
--- | A connectionless version of callTo for long running remote calls
--- myNode should be set with `setMyNode`
-callTo' :: (Show a, Read a,Typeable a) => Node -> TransIO a -> TransIO a
-callTo' node remoteProc= logged $ do
-    mynode <- logged getMyNode
-    beamTo node
-    r <- logged remoteProc
-    beamTo mynode
-    return r
-
-type Blocked= MVar ()
-type BuffSize = Int
-data ConnectionData= ConnectionData{port :: PortID
-                                   ,handle :: Handle
-                                   ,socket ::Socket
-                                   ,blocked :: Blocked}
-
-
-
-
-data Connection= Connection{myNode :: DBRef MyNode
-                           ,connData :: (Maybe(ConnectionData))
-                           ,bufferSize ::BuffSize
-                           ,comEvent :: EVar(Node,Service)}
-                  deriving Typeable
-
-setBufSize :: Int -> TransIO ()
-setBufSize size= Transient $ do
-   Connection n c _ ev <- getSessionData `onNothing`
-              return (Connection (errorMyNode "setBufSize") Nothing  size (error "accessing network events out of listen"))
-   setSessionData $ Connection n c size ev
-   return $ Just ()
-getBuffSize=
-  (do Connection _ _ bufSize _ <- getSData ; return bufSize) <|> return  8192
-readHandler h= do
-    line <- hGetLine h
-
-    let [(v,left)]= readsPrec 0 line
-
-    return  v
-
-  `catch` (\(e::SomeException) -> do
-      hClose h
-      liftIO $ do
-         putStr "readHandler: "
-         print e
-         return SDone)
-   where
---   hGetLine' h= do
-
-
-
-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
-        )
-
--- | Wait for messages and replay the rest of the monadic sequence with the log received.
-listen ::  Node ->  TransIO ()
-listen  (node@(Node _  port _ _)) = do
-   addThreads 1
-   setMyNode node
-   setSData $ Log False [] []
-
-   Connection node _ bufSize events  <- getSData
-
-   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 (ConnectionData port h sock (unsafePerformIO $ newMVar ()))) bufSize events -- !> "setdata port=" ++ show port
-
-   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)
-
-
-
--- | init a Transient process in a interactive as well as in a replay mode.
--- It is intended for twin processes that interact among them in different nodes.
-beamInit :: Node  -> TransIO a -> IO a
-beamInit  node program=  keep $ do
-    listen  node   <|> return ()
-    program
-
-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
-
-
-
-data Pool=  Pool{free :: [Handle], pending :: Int}
-type Package= String
-type Program= String
-type Service= (Package, Program, Int)
-
-data Node= Node{ nodeHost   :: HostName
-               , nodePort   :: PortID
-               , connection :: IORef Pool
-               , services   :: [Service]}
-               deriving Typeable
-
-
-release (Node h p rpool _) hand= liftIO $ do
-  mhs <- atomicModifyIORef rpool $
-            \(Pool hs pend) ->
-               if pend==0
-                 then (Pool [] 0,Just hs)
-                 else (Pool (hand:hs) pend,Nothing)
-  case mhs of
-    Nothing -> return ()
-    Just hs  -> mapM_ hClose hs
-
-
-assign bufSize (Node h p  pool _)= liftIO $ do
-    mh <- atomicModifyIORef pool $
-            \(Pool hs p) ->  if null hs then (Pool hs p, Nothing)
-                                        else (Pool (tail hs) p, Just(head hs)) !> "REUSED"
-    case mh of
-      Just handle -> liftIO (putStrLn "REUSED!") >> return handle
-      Nothing -> liftIO $ do
-                  h <- connectTo' bufSize h p     !>  "REOPEN"
-                  hSetBuffering h LineBuffering
-                  return h
-
-
-
-
--- * Level 2: connections node lists and operations with the node list
-
-
-{-# NOINLINE emptyPool #-}
-emptyPool :: MonadIO m => m (IORef Pool)
-emptyPool= liftIO $ newIORef $ Pool [] 0
-
-createNode :: HostName -> Integer -> Node
-createNode h p= Node h ( PortNumber $ fromInteger p) (unsafePerformIO emptyPool) []
-
-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 setMynode before listen"
-
-getMyNode :: TransIO Node
-getMyNode = do
-    Connection{myNode=rnode} <- getSData <|> errorMyNode "getMyNode"
-    MyNode node <- liftIO $ atomically $ readDBRef rnode `onNothing` errorMyNode "getMyNode"
-    return node
-
-setMyNode :: Node -> TransIO ()
-setMyNode node= do
-        addNodes [node]
-        events <- newEVar
-        rnode <- liftIO $ atomically $ newDBRef $ MyNode node
-        let conn= Connection rnode Nothing 8192 events
-        setSData conn
-        return ()
-
-getNodes :: MonadIO m => m [Node]
-getNodes  = liftIO $ atomically $ readTVar  nodeList
-
-addNodes :: MonadIO m => [Node] -> m ()
-addNodes   nodes=  liftIO . atomically $ do
-  prevnodes <- readTVar nodeList
-  writeTVar nodeList $ nub $ nodes ++ prevnodes
-
-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 returned and processed by the rest of the procedure.
--- By default, the 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  => TransIO a -> TransIO a
-clustered proc= logged $ do
-     nodes <-  getNodes
-     logged $ foldr (<|>) empty $ map (\node -> callTo node proc) nodes !> "fold"
-
--- | a connectionless version of clustered for long running remote computations. Not tested
-clustered' proc= logged $ do
-     nodes <-  getNodes
-     logged $ mapM (\node -> callTo' node proc) nodes
-
--- A variant of clustered that wait for all the responses and `mappend` them
-mclustered :: (Monoid a, Loggable a)  => TransIO a -> TransIO a
-mclustered proc= logged $ do
-     nodes <- step getNodes
-     logged $ foldr (<>) mempty $ map (\node -> callTo node proc) nodes !> "fold"
-
--- | 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 -> TransientIO ()
-connect  node  remotenode=  do
-    listen node <|> return ()
-    logged $ do
-        logged $ do
-             liftIO $ putStrLn $ "connecting to: "++ show remotenode
-        newnode <- logged $ return node -- must pass my node the remote node or else it will use his own
-
-        nodes <- callTo remotenode $ do
-                   mclustered $  addNodes [newnode]
-                   getNodes
-
-        liftIO $ putStrLn $ "Connected to nodes: " ++ show nodes
-        logged $ addNodes nodes
-
-
-
-
− src/Transient/Move/Services.hs
@@ -1,156 +0,0 @@------------------------------------------------------------------------------
---
--- Module      :  Transient.Move.Services
--- Copyright   :
--- License     :  GPL-3
---
--- Maintainer  :  agocorona@gmail.com
--- Stability   :
--- Portability :
---
--- |
---
------------------------------------------------------------------------------
-
-module Transient.Move.Services  where
-
-import Transient.Base
-import Transient.Move
-import Transient.Logged
-import Transient.EVars
-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)
-
--- for the example
-import System.Environment
-
-startServices :: TransIO ()
-startServices= do
-  node <- getMyNode
-  liftIO $ print node
-  mapM_ start $ services node
-  where
-  start (package,program,port)= 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
-
-install :: String  -> String -> Int -> TransIO ()
-install package program port = logged $ do
-     let packagename = name package
-     exist <-  logged $ liftIO $ doesDirectoryExist  packagename
-     when (not exist) $ logged $ liftIO $ do
-         callProcess  "git" ["clone",package]
-         liftIO $ print "GIT DONE"
-         setCurrentDirectory packagename
-         callProcess  "cabal" ["install"]
-         setCurrentDirectory ".."
-         return()
-     let prog= pathExe packagename program port
-     logged $ liftIO $ do
-           createProcess $ shell program
-           return ()
-
-     let service= (package, program,  port)
-
-     Connection{myNode= rnode} <- getSData <|> error "Mynode not set: use setMyNode"
-     logged $ liftIO $ do
-       atomically $ do
-        MyNode( Node h p c servs) <- readDBRef rnode
-                  `onNothing` error "install: myNode: not set with setMyNode"
-        writeDBRef rnode $ MyNode $ Node h p c $ service:servs
-       liftIO syncCache
-     node <- logged getMyNode
-     clustered $ 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)
-
-rfreePort :: MVar Int
-rfreePort = unsafePerformIO $ newMVar  3000
-
-freePort :: MonadIO m => m Int
-freePort= liftIO $ modifyMVar rfreePort $ \ n -> return (n+1,n)
-
-initService node package program= logged $
-    case   find  (\(package', program',_) -> package==package' && program== program') $ services node of
-       Just (_,_,port) -> return port
-       Nothing -> do
-            beamTo node
-            port <- logged freePort
-            install package program  port
-            stop
-          <|> do
-            Connection _ _ _ ev<- getSData
-            (node', (package', program',port)) <- readEVar ev
-            if node'== node && package' == package && program'== program
-                 then return port
-                 else stop
-
-notifyService :: Node -> Service -> TransIO ()
-notifyService node service=  logged $ do
-     liftIO $ atomically $ do
-        nodes <- readTVar nodeList
-        let ([nod], nodes')= span (== node) nodes
-        let nod' = nod{services=service:services nod}
-        writeTVar nodeList $ nod' : nodes'
-        return ()
-
-     Connection _ _ _ ev<- getSData
-     writeEVar ev (node,service)
-     return ()
-
-
-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]
-
-    addNodes [localNode, remoteNode]
-    keep $ do
-      setMyNode localNode
-      listen localNode <|> return ()
-      step $ option "start" "start"
-
-      logged startServices
-      port <-initService remoteNode "http://github.com/agocorona/transient" "MainStreamFiles"
-      liftIO $ putStrLn $ "installed at" ++ show port
---      nodes <- getNodes
---      liftIO $ print nodes
---      liftIO syncCache
---      option "end" "end"
---      liftIO $ print "END"
-
-
-
-
-
src/Transient/Stream/Resource.hs view
@@ -12,20 +12,21 @@ --
 -----------------------------------------------------------------------------
 {-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable  #-}
-module Transient.Stream.Resource(sourceFile, sinkFile, process, finish, onFinish) where
+module Transient.Stream.Resource(sourceFile, sinkFile, process, initFinish, finish,unFinish, onFinish) where
 
 
 import Transient.Base hiding (loop)
 import Transient.EVars
 import Control.Exception
 import Control.Applicative
-import Control.Monad.IO.Class
 import Data.Typeable
 import Data.Char
 import System.IO
 
-
+import Control.Concurrent
 
+import Control.Concurrent.STM
+import Control.Monad.State
 
 
 
@@ -33,9 +34,9 @@ sinkFile :: TransIO String -> String -> TransIO ()
 sinkFile input file= process input (openFile file WriteMode)  hClose' hPutStrLn'
   where
-  hClose' h= putStr "closing " >> putStrLn file >> hClose h
+  hClose' h _= putStr "closing " >> putStrLn file >> hClose h
   hPutStrLn' h  x= liftIO $ (SMore <$>  hPutStrLn h x)
-                  `catch` (\(e::SomeException)-> return $ SError (show e))
+                  `catch` (\(e::SomeException)-> return $ SError e)
 
 -- | slurp input from a file a line at a time. It creates as much threads as possible.
 -- to allow single threaded processing, use it with `threads 0`
@@ -43,77 +44,82 @@ sourceFile file= process (return ()) (openFile file ReadMode)  hClose' read'
       where
       hGetLine' h= (SMore <$> hGetLine h)
-                   `catch` (\(e::SomeException)-> return $ SError(show e))
+                   `catch` (\(e::SomeException)-> return $ SError e)
       read' h _ =  parallel $ hGetLine' h
 
 
-      hClose' h= putStr "closing ">> putStrLn file >> hClose h
+      hClose' h _= putStr "closing ">> putStrLn file >> hClose h
 
 -- | is the general operation for processing a streamed input, with opening  resources before
 -- processing and closing them when finish is called.  The process statements suscribe to the
--- EVar `Finish`.
+-- `Finish` EVar.
 --
--- when this variable is updated, the close section is called.
+-- When this variable is updated, the close procedure is called.
 --
 -- When the processing return `SDone` or `SError`, the `Finish` variable is updated so all the
--- subscribed code that close the resources are executed.
+-- subscribed code, that close the resources, is executed.
 process
-  :: TransIO a
-     -> IO handle
-     -> (handle -> IO ())
-     -> (handle -> a -> TransIO (StreamData b))
+  :: TransIO a       -- ^ input computation
+     -> IO handle    -- ^ open computation that gives resources to be used during the computation
+     -> (handle -> FinishReason -> IO ())   -- ^ close computation that frees the resources
+     -> (handle -> a -> TransIO (StreamData b))   -- ^ process to be done
      -> TransIO b
-process input open close process=do
+process input open close proc=do
    mh <- liftIO $ (Right <$> open)  `catch` (\(e::SomeException)-> return $ Left e)
    case mh of
-      Left e -> liftIO (putStr "process: " >> print e) >> finish  >> stop
+      Left e -> liftIO (putStr "process: " >> print e) >> finish  (Just e) >> stop
       Right h -> do
-       onFinish (liftIO (close h) >> killChilds >> stop) <|> return()
+       onFinish (liftIO . close h)
        some <- input
-       process' h  some
-       where
-       process' h something = do
-           v <- process h  something
-           checkFinalize v
-
+       v <- proc h  some
+       liftIO $ myThreadId >>= print
+       checkFinalize v
 
+type FinishReason= Maybe SomeException
 
 checkFinalize v=
            case v of
-              SDone ->  finish  >> stop
-              SLast x ->  finish >> return x
-              SError e -> liftIO ( putStrLn e) >> finish  >> stop
+              SDone ->  finish Nothing >> stop
+              SLast x ->  finish Nothing >> return x
+              SError e -> liftIO ( print e) >> finish Nothing >> stop
               SMore x -> return x
 
 
 
-newtype Finish= Finish (EVar Bool) deriving Typeable
+data Finish= Finish (EVar FinishReason) deriving Typeable
 
+-- | initialize the event variable for finalization.
+-- all the following computations will share it
 initFinish :: TransIO Finish
 initFinish= do
-      fin <- newEVar
+      fin <-  newEVar
       let f = Finish fin
       setSData  f
-      return f
+      return  f
 
+
 -- | suscribe a computation to be called when the finish event is triggered
-onFinish :: TransIO () -> TransIO a
+onFinish :: (FinishReason ->TransIO ()) -> TransIO ()
 onFinish  close= do
        Finish finish <- getSData <|> initFinish
-       readEVar finish
-       close
+
+       e <- readEVar finish
+--       unsubscribe finish
+       close e  -- !!> "CLOSE"
        stop
+     <|> return()
 
--- | trigger the event for the closing of all the resources
-finish :: TransIO ()
-finish = do
+-- | trigger the event, so this closes all the resources
+finish :: FinishReason -> TransIO ()
+finish e= do
     liftIO $ putStrLn "finish Called"
     Finish finish <- getSData
-    writeEVar finish True
-
-
-
-
-
+    writeEVar finish e
 
+-- | deregister all the finalization actions.
+-- A initFinish is needed to register actions again
+unFinish= do
+    Finish fin <- getSData
+    delEVar fin    -- !!> "DELEVAR"
+   <|> return ()   -- !!> "NOT DELEVAR"
 
+ tests/TestSuite.hs view
@@ -0,0 +1,87 @@+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()
+
+
transient.cabal view
@@ -1,14 +1,17 @@ name: transient
-version: 0.1.1
+
+version: 0.3
 cabal-version: >=1.10
 build-type: Simple
-license: GPL-3
+license: MIT
 license-file: LICENSE
 maintainer: agocorona@gmail.com
 homepage: http://www.fpcomplete.com/user/agocorona
 bug-reports: https://github.com/agocorona/transient/issues
 synopsis: Making composable programs with multithreading, events and distributed computing
 description: see <http://github.com/agocorona/transient>
+             In this release, distributed primitives have been moved to the transient-universe package
+             Web primitives have been moved to the package ghcjs-hplay
 category: Control
 author: Alberto G. Corona
 data-dir: ""
@@ -18,18 +21,29 @@     location: https://github.com/agocorona/transient
 
 library
-    build-depends: base  >4 && <5 , mtl , random , containers ,
-                   directory , filepath , stm , HTTP , network ,
-                   transformers , process , network-info ,
-                   bytestring , time , TCache, SHA
-    exposed-modules: Transient.DDS Transient.Indeterminism
-                     Transient.Base Transient.EVars Transient.Backtrack Transient.Move
-                     Transient.Logged Transient.Stream.Resource
+
+        build-depends: base >4 && <5, containers, mtl, transformers, stm, time
+
+        exposed-modules: Transient.Indeterminism
+                         Transient.Base Transient.EVars Transient.Backtrack
+                         Transient.Logged Transient.Stream.Resource
+                         Transient.Internals
+        exposed: True
+        buildable: True
     exposed: True
     buildable: True
     default-language: Haskell2010
     hs-source-dirs: src .
-    other-modules: Transient.Move.Services
 
+
+test-suite test-transient
+    build-depends: base >4 && <5, mtl , random ,
+                       containers , directory , filepath , stm ,
+                       HTTP , network , transformers , process
+    type: exitcode-stdio-1.0
+    main-is: TestSuite.hs
+    buildable: True
+    default-language: Haskell2010
+    hs-source-dirs: tests src .