packages feed

scidb-hquery (empty) → 2.8.0.432

raw patch · 13 files changed

+3829/−0 lines, 13 filesdep +HTTPdep +arraydep +basebuild-type:Customsetup-changed

Dependencies added: HTTP, array, base, bytestring, connection, cryptonite, data-default-class, directory, exceptions, filepath, haskeline, hostname-validate, http-client, http-client-tls, http-conduit, http-types, memory, mtl, network, process, regex, safe, split, terminal-size, text, tls, x509-store

Files

+ CHANGELOG.md view
@@ -0,0 +1,13 @@+# Revision history for scidb-hquery++## 2.8.0.429 -- 2019-07-06++* First packaged version of SciDB hquery released to git and cabal.++## 2.8.0.431 -- 2019-07-06++* Ready to be uploaded to hackage.++## 2.8.0.432 -- 2019-07-08++* Corrected problems discovered with cabal candidate package 2.8.0.431.
+ LICENSE view
@@ -0,0 +1,674 @@+              GNU GENERAL PUBLIC LICENSE+                Version 3, 29 June 2007++ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>+ Everyone is permitted to copy and distribute verbatim copies+ of this license document, but changing it is not allowed.++                     Preamble++  The GNU General Public License is a free, copyleft license for+software and other kinds of works.++  The licenses for most software and other practical works are designed+to take away your freedom to share and change the works.  By contrast,+the GNU General Public License is intended to guarantee your freedom to+share and change all versions of a program--to make sure it remains free+software for all its users.  We, the Free Software Foundation, use the+GNU General Public License for most of our software; it applies also to+any other work released this way by its authors.  You can apply it to+your programs, too.++  When we speak of free software, we are referring to freedom, not+price.  Our General Public Licenses are designed to make sure that you+have the freedom to distribute copies of free software (and charge for+them if you wish), that you receive source code or can get it if you+want it, that you can change the software or use pieces of it in new+free programs, and that you know you can do these things.++  To protect your rights, we need to prevent others from denying you+these rights or asking you to surrender the rights.  Therefore, you have+certain responsibilities if you distribute copies of the software, or if+you modify it: responsibilities to respect the freedom of others.++  For example, if you distribute copies of such a program, whether+gratis or for a fee, you must pass on to the recipients the same+freedoms that you received.  You must make sure that they, too, receive+or can get the source code.  And you must show them these terms so they+know their rights.++  Developers that use the GNU GPL protect your rights with two steps:+(1) assert copyright on the software, and (2) offer you this License+giving you legal permission to copy, distribute and/or modify it.++  For the developers' and authors' protection, the GPL clearly explains+that there is no warranty for this free software.  For both users' and+authors' sake, the GPL requires that modified versions be marked as+changed, so that their problems will not be attributed erroneously to+authors of previous versions.++  Some devices are designed to deny users access to install or run+modified versions of the software inside them, although the manufacturer+can do so.  This is fundamentally incompatible with the aim of+protecting users' freedom to change the software.  The systematic+pattern of such abuse occurs in the area of products for individuals to+use, which is precisely where it is most unacceptable.  Therefore, we+have designed this version of the GPL to prohibit the practice for those+products.  If such problems arise substantially in other domains, we+stand ready to extend this provision to those domains in future versions+of the GPL, as needed to protect the freedom of users.++  Finally, every program is threatened constantly by software patents.+States should not allow patents to restrict development and use of+software on general-purpose computers, but in those that do, we wish to+avoid the special danger that patents applied to a free program could+make it effectively proprietary.  To prevent this, the GPL assures that+patents cannot be used to render the program non-free.++  The precise terms and conditions for copying, distribution and+modification follow.++                TERMS AND CONDITIONS++  0. Definitions.++  "This License" refers to version 3 of the GNU General Public License.++  "Copyright" also means copyright-like laws that apply to other kinds of+works, such as semiconductor masks.++  "The Program" refers to any copyrightable work licensed under this+License.  Each licensee is addressed as "you".  "Licensees" and+"recipients" may be individuals or organizations.++  To "modify" a work means to copy from or adapt all or part of the work+in a fashion requiring copyright permission, other than the making of an+exact copy.  The resulting work is called a "modified version" of the+earlier work or a work "based on" the earlier work.++  A "covered work" means either the unmodified Program or a work based+on the Program.++  To "propagate" a work means to do anything with it that, without+permission, would make you directly or secondarily liable for+infringement under applicable copyright law, except executing it on a+computer or modifying a private copy.  Propagation includes copying,+distribution (with or without modification), making available to the+public, and in some countries other activities as well.++  To "convey" a work means any kind of propagation that enables other+parties to make or receive copies.  Mere interaction with a user through+a computer network, with no transfer of a copy, is not conveying.++  An interactive user interface displays "Appropriate Legal Notices"+to the extent that it includes a convenient and prominently visible+feature that (1) displays an appropriate copyright notice, and (2)+tells the user that there is no warranty for the work (except to the+extent that warranties are provided), that licensees may convey the+work under this License, and how to view a copy of this License.  If+the interface presents a list of user commands or options, such as a+menu, a prominent item in the list meets this criterion.++  1. Source Code.++  The "source code" for a work means the preferred form of the work+for making modifications to it.  "Object code" means any non-source+form of a work.++  A "Standard Interface" means an interface that either is an official+standard defined by a recognized standards body, or, in the case of+interfaces specified for a particular programming language, one that+is widely used among developers working in that language.++  The "System Libraries" of an executable work include anything, other+than the work as a whole, that (a) is included in the normal form of+packaging a Major Component, but which is not part of that Major+Component, and (b) serves only to enable use of the work with that+Major Component, or to implement a Standard Interface for which an+implementation is available to the public in source code form.  A+"Major Component", in this context, means a major essential component+(kernel, window system, and so on) of the specific operating system+(if any) on which the executable work runs, or a compiler used to+produce the work, or an object code interpreter used to run it.++  The "Corresponding Source" for a work in object code form means all+the source code needed to generate, install, and (for an executable+work) run the object code and to modify the work, including scripts to+control those activities.  However, it does not include the work's+System Libraries, or general-purpose tools or generally available free+programs which are used unmodified in performing those activities but+which are not part of the work.  For example, Corresponding Source+includes interface definition files associated with source files for+the work, and the source code for shared libraries and dynamically+linked subprograms that the work is specifically designed to require,+such as by intimate data communication or control flow between those+subprograms and other parts of the work.++  The Corresponding Source need not include anything that users+can regenerate automatically from other parts of the Corresponding+Source.++  The Corresponding Source for a work in source code form is that+same work.++  2. Basic Permissions.++  All rights granted under this License are granted for the term of+copyright on the Program, and are irrevocable provided the stated+conditions are met.  This License explicitly affirms your unlimited+permission to run the unmodified Program.  The output from running a+covered work is covered by this License only if the output, given its+content, constitutes a covered work.  This License acknowledges your+rights of fair use or other equivalent, as provided by copyright law.++  You may make, run and propagate covered works that you do not+convey, without conditions so long as your license otherwise remains+in force.  You may convey covered works to others for the sole purpose+of having them make modifications exclusively for you, or provide you+with facilities for running those works, provided that you comply with+the terms of this License in conveying all material for which you do+not control copyright.  Those thus making or running the covered works+for you must do so exclusively on your behalf, under your direction+and control, on terms that prohibit them from making any copies of+your copyrighted material outside their relationship with you.++  Conveying under any other circumstances is permitted solely under+the conditions stated below.  Sublicensing is not allowed; section 10+makes it unnecessary.++  3. Protecting Users' Legal Rights From Anti-Circumvention Law.++  No covered work shall be deemed part of an effective technological+measure under any applicable law fulfilling obligations under article+11 of the WIPO copyright treaty adopted on 20 December 1996, or+similar laws prohibiting or restricting circumvention of such+measures.++  When you convey a covered work, you waive any legal power to forbid+circumvention of technological measures to the extent such circumvention+is effected by exercising rights under this License with respect to+the covered work, and you disclaim any intention to limit operation or+modification of the work as a means of enforcing, against the work's+users, your or third parties' legal rights to forbid circumvention of+technological measures.++  4. Conveying Verbatim Copies.++  You may convey verbatim copies of the Program's source code as you+receive it, in any medium, provided that you conspicuously and+appropriately publish on each copy an appropriate copyright notice;+keep intact all notices stating that this License and any+non-permissive terms added in accord with section 7 apply to the code;+keep intact all notices of the absence of any warranty; and give all+recipients a copy of this License along with the Program.++  You may charge any price or no price for each copy that you convey,+and you may offer support or warranty protection for a fee.++  5. Conveying Modified Source Versions.++  You may convey a work based on the Program, or the modifications to+produce it from the Program, in the form of source code under the+terms of section 4, provided that you also meet all of these conditions:++    a) The work must carry prominent notices stating that you modified+    it, and giving a relevant date.++    b) The work must carry prominent notices stating that it is+    released under this License and any conditions added under section+    7.  This requirement modifies the requirement in section 4 to+    "keep intact all notices".++    c) You must license the entire work, as a whole, under this+    License to anyone who comes into possession of a copy.  This+    License will therefore apply, along with any applicable section 7+    additional terms, to the whole of the work, and all its parts,+    regardless of how they are packaged.  This License gives no+    permission to license the work in any other way, but it does not+    invalidate such permission if you have separately received it.++    d) If the work has interactive user interfaces, each must display+    Appropriate Legal Notices; however, if the Program has interactive+    interfaces that do not display Appropriate Legal Notices, your+    work need not make them do so.++  A compilation of a covered work with other separate and independent+works, which are not by their nature extensions of the covered work,+and which are not combined with it such as to form a larger program,+in or on a volume of a storage or distribution medium, is called an+"aggregate" if the compilation and its resulting copyright are not+used to limit the access or legal rights of the compilation's users+beyond what the individual works permit.  Inclusion of a covered work+in an aggregate does not cause this License to apply to the other+parts of the aggregate.++  6. Conveying Non-Source Forms.++  You may convey a covered work in object code form under the terms+of sections 4 and 5, provided that you also convey the+machine-readable Corresponding Source under the terms of this License,+in one of these ways:++    a) Convey the object code in, or embodied in, a physical product+    (including a physical distribution medium), accompanied by the+    Corresponding Source fixed on a durable physical medium+    customarily used for software interchange.++    b) Convey the object code in, or embodied in, a physical product+    (including a physical distribution medium), accompanied by a+    written offer, valid for at least three years and valid for as+    long as you offer spare parts or customer support for that product+    model, to give anyone who possesses the object code either (1) a+    copy of the Corresponding Source for all the software in the+    product that is covered by this License, on a durable physical+    medium customarily used for software interchange, for a price no+    more than your reasonable cost of physically performing this+    conveying of source, or (2) access to copy the+    Corresponding Source from a network server at no charge.++    c) Convey individual copies of the object code with a copy of the+    written offer to provide the Corresponding Source.  This+    alternative is allowed only occasionally and noncommercially, and+    only if you received the object code with such an offer, in accord+    with subsection 6b.++    d) Convey the object code by offering access from a designated+    place (gratis or for a charge), and offer equivalent access to the+    Corresponding Source in the same way through the same place at no+    further charge.  You need not require recipients to copy the+    Corresponding Source along with the object code.  If the place to+    copy the object code is a network server, the Corresponding Source+    may be on a different server (operated by you or a third party)+    that supports equivalent copying facilities, provided you maintain+    clear directions next to the object code saying where to find the+    Corresponding Source.  Regardless of what server hosts the+    Corresponding Source, you remain obligated to ensure that it is+    available for as long as needed to satisfy these requirements.++    e) Convey the object code using peer-to-peer transmission, provided+    you inform other peers where the object code and Corresponding+    Source of the work are being offered to the general public at no+    charge under subsection 6d.++  A separable portion of the object code, whose source code is excluded+from the Corresponding Source as a System Library, need not be+included in conveying the object code work.++  A "User Product" is either (1) a "consumer product", which means any+tangible personal property which is normally used for personal, family,+or household purposes, or (2) anything designed or sold for incorporation+into a dwelling.  In determining whether a product is a consumer product,+doubtful cases shall be resolved in favor of coverage.  For a particular+product received by a particular user, "normally used" refers to a+typical or common use of that class of product, regardless of the status+of the particular user or of the way in which the particular user+actually uses, or expects or is expected to use, the product.  A product+is a consumer product regardless of whether the product has substantial+commercial, industrial or non-consumer uses, unless such uses represent+the only significant mode of use of the product.++  "Installation Information" for a User Product means any methods,+procedures, authorization keys, or other information required to install+and execute modified versions of a covered work in that User Product from+a modified version of its Corresponding Source.  The information must+suffice to ensure that the continued functioning of the modified object+code is in no case prevented or interfered with solely because+modification has been made.++  If you convey an object code work under this section in, or with, or+specifically for use in, a User Product, and the conveying occurs as+part of a transaction in which the right of possession and use of the+User Product is transferred to the recipient in perpetuity or for a+fixed term (regardless of how the transaction is characterized), the+Corresponding Source conveyed under this section must be accompanied+by the Installation Information.  But this requirement does not apply+if neither you nor any third party retains the ability to install+modified object code on the User Product (for example, the work has+been installed in ROM).++  The requirement to provide Installation Information does not include a+requirement to continue to provide support service, warranty, or updates+for a work that has been modified or installed by the recipient, or for+the User Product in which it has been modified or installed.  Access to a+network may be denied when the modification itself materially and+adversely affects the operation of the network or violates the rules and+protocols for communication across the network.++  Corresponding Source conveyed, and Installation Information provided,+in accord with this section must be in a format that is publicly+documented (and with an implementation available to the public in+source code form), and must require no special password or key for+unpacking, reading or copying.++  7. Additional Terms.++  "Additional permissions" are terms that supplement the terms of this+License by making exceptions from one or more of its conditions.+Additional permissions that are applicable to the entire Program shall+be treated as though they were included in this License, to the extent+that they are valid under applicable law.  If additional permissions+apply only to part of the Program, that part may be used separately+under those permissions, but the entire Program remains governed by+this License without regard to the additional permissions.++  When you convey a copy of a covered work, you may at your option+remove any additional permissions from that copy, or from any part of+it.  (Additional permissions may be written to require their own+removal in certain cases when you modify the work.)  You may place+additional permissions on material, added by you to a covered work,+for which you have or can give appropriate copyright permission.++  Notwithstanding any other provision of this License, for material you+add to a covered work, you may (if authorized by the copyright holders of+that material) supplement the terms of this License with terms:++    a) Disclaiming warranty or limiting liability differently from the+    terms of sections 15 and 16 of this License; or++    b) Requiring preservation of specified reasonable legal notices or+    author attributions in that material or in the Appropriate Legal+    Notices displayed by works containing it; or++    c) Prohibiting misrepresentation of the origin of that material, or+    requiring that modified versions of such material be marked in+    reasonable ways as different from the original version; or++    d) Limiting the use for publicity purposes of names of licensors or+    authors of the material; or++    e) Declining to grant rights under trademark law for use of some+    trade names, trademarks, or service marks; or++    f) Requiring indemnification of licensors and authors of that+    material by anyone who conveys the material (or modified versions of+    it) with contractual assumptions of liability to the recipient, for+    any liability that these contractual assumptions directly impose on+    those licensors and authors.++  All other non-permissive additional terms are considered "further+restrictions" within the meaning of section 10.  If the Program as you+received it, or any part of it, contains a notice stating that it is+governed by this License along with a term that is a further+restriction, you may remove that term.  If a license document contains+a further restriction but permits relicensing or conveying under this+License, you may add to a covered work material governed by the terms+of that license document, provided that the further restriction does+not survive such relicensing or conveying.++  If you add terms to a covered work in accord with this section, you+must place, in the relevant source files, a statement of the+additional terms that apply to those files, or a notice indicating+where to find the applicable terms.++  Additional terms, permissive or non-permissive, may be stated in the+form of a separately written license, or stated as exceptions;+the above requirements apply either way.++  8. Termination.++  You may not propagate or modify a covered work except as expressly+provided under this License.  Any attempt otherwise to propagate or+modify it is void, and will automatically terminate your rights under+this License (including any patent licenses granted under the third+paragraph of section 11).++  However, if you cease all violation of this License, then your+license from a particular copyright holder is reinstated (a)+provisionally, unless and until the copyright holder explicitly and+finally terminates your license, and (b) permanently, if the copyright+holder fails to notify you of the violation by some reasonable means+prior to 60 days after the cessation.++  Moreover, your license from a particular copyright holder is+reinstated permanently if the copyright holder notifies you of the+violation by some reasonable means, this is the first time you have+received notice of violation of this License (for any work) from that+copyright holder, and you cure the violation prior to 30 days after+your receipt of the notice.++  Termination of your rights under this section does not terminate the+licenses of parties who have received copies or rights from you under+this License.  If your rights have been terminated and not permanently+reinstated, you do not qualify to receive new licenses for the same+material under section 10.++  9. Acceptance Not Required for Having Copies.++  You are not required to accept this License in order to receive or+run a copy of the Program.  Ancillary propagation of a covered work+occurring solely as a consequence of using peer-to-peer transmission+to receive a copy likewise does not require acceptance.  However,+nothing other than this License grants you permission to propagate or+modify any covered work.  These actions infringe copyright if you do+not accept this License.  Therefore, by modifying or propagating a+covered work, you indicate your acceptance of this License to do so.++  10. Automatic Licensing of Downstream Recipients.++  Each time you convey a covered work, the recipient automatically+receives a license from the original licensors, to run, modify and+propagate that work, subject to this License.  You are not responsible+for enforcing compliance by third parties with this License.++  An "entity transaction" is a transaction transferring control of an+organization, or substantially all assets of one, or subdividing an+organization, or merging organizations.  If propagation of a covered+work results from an entity transaction, each party to that+transaction who receives a copy of the work also receives whatever+licenses to the work the party's predecessor in interest had or could+give under the previous paragraph, plus a right to possession of the+Corresponding Source of the work from the predecessor in interest, if+the predecessor has it or can get it with reasonable efforts.++  You may not impose any further restrictions on the exercise of the+rights granted or affirmed under this License.  For example, you may+not impose a license fee, royalty, or other charge for exercise of+rights granted under this License, and you may not initiate litigation+(including a cross-claim or counterclaim in a lawsuit) alleging that+any patent claim is infringed by making, using, selling, offering for+sale, or importing the Program or any portion of it.++  11. Patents.++  A "contributor" is a copyright holder who authorizes use under this+License of the Program or a work on which the Program is based.  The+work thus licensed is called the contributor's "contributor version".++  A contributor's "essential patent claims" are all patent claims+owned or controlled by the contributor, whether already acquired or+hereafter acquired, that would be infringed by some manner, permitted+by this License, of making, using, or selling its contributor version,+but do not include claims that would be infringed only as a+consequence of further modification of the contributor version.  For+purposes of this definition, "control" includes the right to grant+patent sublicenses in a manner consistent with the requirements of+this License.++  Each contributor grants you a non-exclusive, worldwide, royalty-free+patent license under the contributor's essential patent claims, to+make, use, sell, offer for sale, import and otherwise run, modify and+propagate the contents of its contributor version.++  In the following three paragraphs, a "patent license" is any express+agreement or commitment, however denominated, not to enforce a patent+(such as an express permission to practice a patent or covenant not to+sue for patent infringement).  To "grant" such a patent license to a+party means to make such an agreement or commitment not to enforce a+patent against the party.++  If you convey a covered work, knowingly relying on a patent license,+and the Corresponding Source of the work is not available for anyone+to copy, free of charge and under the terms of this License, through a+publicly available network server or other readily accessible means,+then you must either (1) cause the Corresponding Source to be so+available, or (2) arrange to deprive yourself of the benefit of the+patent license for this particular work, or (3) arrange, in a manner+consistent with the requirements of this License, to extend the patent+license to downstream recipients.  "Knowingly relying" means you have+actual knowledge that, but for the patent license, your conveying the+covered work in a country, or your recipient's use of the covered work+in a country, would infringe one or more identifiable patents in that+country that you have reason to believe are valid.++  If, pursuant to or in connection with a single transaction or+arrangement, you convey, or propagate by procuring conveyance of, a+covered work, and grant a patent license to some of the parties+receiving the covered work authorizing them to use, propagate, modify+or convey a specific copy of the covered work, then the patent license+you grant is automatically extended to all recipients of the covered+work and works based on it.++  A patent license is "discriminatory" if it does not include within+the scope of its coverage, prohibits the exercise of, or is+conditioned on the non-exercise of one or more of the rights that are+specifically granted under this License.  You may not convey a covered+work if you are a party to an arrangement with a third party that is+in the business of distributing software, under which you make payment+to the third party based on the extent of your activity of conveying+the work, and under which the third party grants, to any of the+parties who would receive the covered work from you, a discriminatory+patent license (a) in connection with copies of the covered work+conveyed by you (or copies made from those copies), or (b) primarily+for and in connection with specific products or compilations that+contain the covered work, unless you entered into that arrangement,+or that patent license was granted, prior to 28 March 2007.++  Nothing in this License shall be construed as excluding or limiting+any implied license or other defenses to infringement that may+otherwise be available to you under applicable patent law.++  12. No Surrender of Others' Freedom.++  If conditions are imposed on you (whether by court order, agreement or+otherwise) that contradict the conditions of this License, they do not+excuse you from the conditions of this License.  If you cannot convey a+covered work so as to satisfy simultaneously your obligations under this+License and any other pertinent obligations, then as a consequence you may+not convey it at all.  For example, if you agree to terms that obligate you+to collect a royalty for further conveying from those to whom you convey+the Program, the only way you could satisfy both those terms and this+License would be to refrain entirely from conveying the Program.++  13. Use with the GNU Affero General Public License.++  Notwithstanding any other provision of this License, you have+permission to link or combine any covered work with a work licensed+under version 3 of the GNU Affero General Public License into a single+combined work, and to convey the resulting work.  The terms of this+License will continue to apply to the part which is the covered work,+but the special requirements of the GNU Affero General Public License,+section 13, concerning interaction through a network will apply to the+combination as such.++  14. Revised Versions of this License.++  The Free Software Foundation may publish revised and/or new versions of+the GNU General Public License from time to time.  Such new versions will+be similar in spirit to the present version, but may differ in detail to+address new problems or concerns.++  Each version is given a distinguishing version number.  If the+Program specifies that a certain numbered version of the GNU General+Public License "or any later version" applies to it, you have the+option of following the terms and conditions either of that numbered+version or of any later version published by the Free Software+Foundation.  If the Program does not specify a version number of the+GNU General Public License, you may choose any version ever published+by the Free Software Foundation.++  If the Program specifies that a proxy can decide which future+versions of the GNU General Public License can be used, that proxy's+public statement of acceptance of a version permanently authorizes you+to choose that version for the Program.++  Later license versions may give you additional or different+permissions.  However, no additional obligations are imposed on any+author or copyright holder as a result of your choosing to follow a+later version.++  15. Disclaimer of Warranty.++  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.++  16. Limitation of Liability.++  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF+SUCH DAMAGES.++  17. Interpretation of Sections 15 and 16.++  If the disclaimer of warranty and limitation of liability provided+above cannot be given local legal effect according to their terms,+reviewing courts shall apply local law that most closely approximates+an absolute waiver of all civil liability in connection with the+Program, unless a warranty or assumption of liability accompanies a+copy of the Program in return for a fee.++              END OF TERMS AND CONDITIONS++     How to Apply These Terms to Your New Programs++  If you develop a new program, and you want it to be of the greatest+possible use to the public, the best way to achieve this is to make it+free software which everyone can redistribute and change under these terms.++  To do so, attach the following notices to the program.  It is safest+to attach them to the start of each source file to most effectively+state the exclusion of warranty; and each file should have at least+the "copyright" line and a pointer to where the full notice is found.++    <one line to give the program's name and a brief idea of what it does.>+    Copyright (C) <year>  <name of author>++    This program is free software: you can redistribute it and/or modify+    it under the terms of the GNU General Public License as published by+    the Free Software Foundation, either version 3 of the License, or+    (at your option) any later version.++    This program is distributed in the hope that it will be useful,+    but WITHOUT ANY WARRANTY; without even the implied warranty of+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+    GNU General Public License for more details.++    You should have received a copy of the GNU General Public License+    along with this program.  If not, see <http://www.gnu.org/licenses/>.++Also add information on how to contact you by electronic and paper mail.++  If the program does terminal interaction, make it output a short+notice like this when it starts in an interactive mode:++    <program>  Copyright (C) <year>  <name of author>+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.+    This is free software, and you are welcome to redistribute it+    under certain conditions; type `show c' for details.++The hypothetical commands `show w' and `show c' should show the appropriate+parts of the General Public License.  Of course, your program's commands+might be different; for a GUI interface, you would use an "about box".++  You should also get your employer (if you work as a programmer) or school,+if any, to sign a "copyright disclaimer" for the program, if necessary.+For more information on this, and how to apply and follow the GNU GPL, see+<http://www.gnu.org/licenses/>.++  The GNU General Public License does not permit incorporating your program+into proprietary programs.  If your program is a subroutine library, you+may consider it more useful to permit linking proprietary applications with+the library.  If this is what you want to do, use the GNU Lesser General+Public License instead of this License.  But first, please read+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+ Setup.hs view
@@ -0,0 +1,52 @@+import Distribution.PackageDescription (BuildInfo)+import Distribution.Simple (UserHooks(..),defaultMainWithHooks,simpleUserHooks)+import Distribution.Simple.BuildPaths (autogenComponentModulesDir)+import Distribution.Simple.LocalBuildInfo (LocalBuildInfo(..),ComponentLocalBuildInfo)+import Distribution.Simple.PreProcess (PreProcessor(..),knownSuffixHandlers,mkSimplePreProcessor)+import Distribution.Simple.Program (Program(..),findProgramVersion,runDbProgram,simpleProgram)+import Distribution.Simple.Utils (info)+import System.FilePath (takeBaseName,takeDirectory)++main :: IO ()+main =+    defaultMainWithHooks simpleUserHooks{hookedPreProcessors = ("cf",ppBnfc):knownSuffixHandlers}++ppBnfc :: BuildInfo -> LocalBuildInfo -> ComponentLocalBuildInfo -> PreProcessor+ppBnfc _ lbi clbi =+    PreProcessor {platformIndependent = True+                 ,runPreProcessor = mkSimplePreProcessor $ \inFile outFile verbosity ->+                  do info verbosity ("Running "++programName bnfcProgram+                                    ++" --outputdir="++autogenDir+                                    ++" --haskell " ++ inFile+                                    )+                     runDbProgram verbosity bnfcProgram (withPrograms lbi)+                         ["--outputdir="++autogenDir, "--haskell", inFile]+                     info verbosity ("Creating "++programName bnfcProgram++" output file '"++outFile++"'"+                                    ++" from input file '"++inFile++"'")+                     outFile `makeFrom` inFile+                 }+        where autogenDir = autogenComponentModulesDir lbi clbi++bnfcProgram :: Program+bnfcProgram = (simpleProgram "bnfc") {+    -- Invoking "bnfc --version" gives a string like "2.8.2"+    programFindVersion = findProgramVersion "--version" id+  }++makeFrom :: String -> String -> IO ()+makeFrom outFile inFile = do inFileStr <- readFile inFile+                             writeFile outFile (outFileStrFrom inFileStr)+    where outFileStrFrom inFileStr =+              "{- |\n"+              ++"This is the SciDB AFL BNFC file:\n"+              ++"\n"+              ++quote inFileStr++"\n"+              ++"-}\n"+              ++"\n"+              ++"module "++takeBaseName inFile++" where\n"+              ++"\n"+              ++"-- | BNFC configuration file as a string, for the purposes of documentation.\n"+              ++"bnfcFile :: String\n"+              ++"bnfcFile = "++show inFileStr++"\n"+          quote inFileStr = unlines $ fmap ("> "++) $ lines inFileStr+
+ scidb-hquery.cabal view
@@ -0,0 +1,145 @@+cabal-version: 2.4+name: scidb-hquery+version: 2.8.0.432+license: GPL-3.0-only+license-file: LICENSE+copyright: All rights reserved 2014-19(c).+maintainer: marcus@gabriel.name+author: Marcus D. Gabriel+homepage: https://github.com/mdgabriel/scidb-hquery.git+bug-reports: https://github.com/mdgabriel/scidb-hquery/issues+synopsis: Haskell query for SciDB via shim+description:+     The command @hquery@ with no operands and no options will begin an+     interacitve session with a SciDB server using SciDB's shim+     protocol at host localhost and port 8080.  See+     https:\/\/github.com\/mdgabriel\/scidb-hquery.git,+     @hquery -m@, and+     http:\/\/www.paradigm4.com+     for more infomation.+category: program, client, database, library+build-type: Custom+-- The entry src/SciDbAFL.cf in extra-source-files below is a+-- workaround for issue https://github.com/haskell/cabal/issues/6124+-- so that cabal new-sdist works.+extra-source-files:+    CHANGELOG.md+    src/SciDbAFL.cf++source-repository head+    type: git+    location: https://github.com/mdgabriel/scidb-hquery.git+    tag: 2.8.0.432++custom-setup+    setup-depends: base >=4.12.0.0 && <4.13,+                   Cabal >=2.4.1.0 && <2.5,+                   filepath >=1.4.2.1 && <1.5++library+    exposed-modules:+        SciDbAFL+        Environment+        ErrM+        HQuery+        License+        Manual+        Utils+        UtilsUnsafe+    build-tool-depends: BNFC:bnfc >=2.8.2, alex:alex >=3.2.4,+                        happy:happy >=1.19.9+    hs-source-dirs: src+    other-modules:+        AbsSciDbAFL+        Interpreter+        LexSciDbAFL+        ParSciDbAFL+        PrintSciDbAFL+    autogen-modules:+        SciDbAFL+        AbsSciDbAFL+        ErrM+        LexSciDbAFL+        ParSciDbAFL+        PrintSciDbAFL+    default-language: Haskell2010+    build-depends:+        base >=4.12.0.0 && <4.13,+        HTTP >=4000.3.14 && <4000.4,+        array >=0.5.3.0 && <0.6,+        bytestring >=0.10.8.2 && <0.11,+        connection >=0.3.0 && <0.4,+        cryptonite ==0.26.*,+        data-default-class >=0.1.2.0 && <0.2,+        exceptions >=0.10.2 && <0.11,+        haskeline >=0.7.4.3 && <0.8,+        hostname-validate >=1.0.0 && <1.1,+        http-client >=0.6.4 && <0.7,+        http-client-tls >=0.3.5.3 && <0.4,+        http-conduit >=2.3.7.1 && <2.4,+        http-types >=0.12.3 && <0.13,+        memory >=0.14.18 && <0.15,+        mtl >=2.2.2 && <2.3,+        network >=3.1.0.1 && <3.2,+        process >=1.6.5.0 && <1.7,+        regex >=1.0.0.0 && <1.1,+        safe >=0.3.17 && <0.4,+        split >=0.2.3.3 && <0.3,+        terminal-size >=0.3.2.1 && <0.4,+        text >=1.2.3.1 && <1.3,+        tls >=1.5.0 && <1.6,+        x509-store >=1.6.7 && <1.7++executable hquery+    main-is: Main.hs+    hs-source-dirs: src+    other-modules:+        SciDbAFL+        AbsSciDbAFL+        Environment+        ErrM+        HQuery+        LexSciDbAFL+        Interpreter+        License+        Manual+        ParSciDbAFL+        PrintSciDbAFL+        Utils+        UtilsUnsafe+    autogen-modules:+        SciDbAFL+        AbsSciDbAFL+        ErrM+        LexSciDbAFL+        ParSciDbAFL+        PrintSciDbAFL+    default-language: Haskell2010+    build-depends:+        base >=4.12.0.0 && <4.13,+        HTTP >=4000.3.14 && <4000.4,+        array >=0.5.3.0 && <0.6,+        bytestring >=0.10.8.2 && <0.11,+        connection >=0.3.0 && <0.4,+        cryptonite ==0.26.*,+        data-default-class >=0.1.2.0 && <0.2,+        directory >=1.3.3.0 && <1.4,+        exceptions >=0.10.2 && <0.11,+        filepath >=1.4.2.1 && <1.5,+        haskeline >=0.7.4.3 && <0.8,+        hostname-validate >=1.0.0 && <1.1,+        http-client >=0.6.4 && <0.7,+        http-client-tls >=0.3.5.3 && <0.4,+        http-conduit >=2.3.7.1 && <2.4,+        http-types >=0.12.3 && <0.13,+        memory >=0.14.18 && <0.15,+        mtl >=2.2.2 && <2.3,+        network >=3.1.0.1 && <3.2,+        process >=1.6.5.0 && <1.7,+        regex >=1.0.0.0 && <1.1,+        safe >=0.3.17 && <0.4,+        split >=0.2.3.3 && <0.3,+        terminal-size >=0.3.2.1 && <0.4,+        text >=1.2.3.1 && <1.3,+        tls >=1.5.0 && <1.6,+        x509-store >=1.6.7 && <1.7
+ src/Environment.hs view
@@ -0,0 +1,97 @@++module Environment(Environment(..), defaultEnv, maybePort,Verbosity(..)) where++import Data.Maybe (fromMaybe)+import Network.HTTP.Types.Header (RequestHeaders)++data Verbosity = Verbose0   -- ^ Verbosity level 0, no information to stderr+               | VerboseDef -- ^ Default verbosity, only relevant HTTP exceptions to stderr+               | Verbose1   -- ^ Verbosity level 1, additional HTTP exceptions and trace information to stderr+               | Verbose2   -- ^ Verbosity level 2, additional URL information to stderr+                 deriving (Show,Eq,Ord)++{- | Given an 'Environment', return a port or a default port.+-}+maybePort :: Environment -> String+maybePort e = fromMaybe port' (port e)+    where port' = (if protocol e == "https" then secPort else defPort) e++-- Section: Environment+{- |+The 'Environment' contains the command name, operands, defaults, and the+result of every option amongst other entries.  It is set by 'main' and+otherwise to be used as a read-only 'Environment'.+-}+data Environment =+    Env { command     :: String       -- ^ Program name+        , pwd         :: String       -- ^ Present Working Directory (PWD)+        , home        :: String       -- ^ Home directory or /tmp+        , history     :: String       -- ^ History file for command+        , protocol    :: String       -- ^ Protoocl http or https+        , certStore   :: String       -- ^ Load and use certificate store+        , insecure    :: Bool         -- ^ Use "insecure" SSL/TLS, i.e., no cert validation+        , scidbAuth   :: Bool         -- ^ Use SciDB authentication+        , digestAuth  :: Bool         -- ^ Use basic digest access authentication+        , digestHeaders::RequestHeaders-- ^ Digest request headers or nothing for the GET method+        , defFetch    :: Maybe Bool   -- ^ True fetch lines, false do not fetch lines+        , defFormat   :: String       -- ^ Format dcsv, csv, csv+, etc.+        , defNumber   :: String       -- ^ Number of lines to fetch, n=0 for all; default for bad number+        , defReadingLines::Maybe Bool -- ^ True to read lines from shim otheriwise read bytes+        , defPrefix   :: String       -- ^ Prefix to execute before a query by shim+        , host        :: String       -- ^ Hostname or IP address+        , port        :: Maybe String -- ^ Port number+        , defPort     :: String       -- ^ Default insecure or unencypted port number+        , secPort     :: String       -- ^ Default secure or encypted port number+        , username    :: String       -- ^ Username+        , password    :: String       -- ^ Password for username+        , operands    :: [String]     -- ^ List of queries+        , file        :: String       -- ^ File of queries+        , help        :: Bool         -- ^ @-h@, display help summary+        , license     :: Bool         -- ^ @-l@, display license terms+        , manual      :: Bool         -- ^ @-m@, display internal man page+        , version     :: Bool         -- ^ @-v@, display version+        , synopsis    :: Bool         -- ^ @-y@, display manual synopsis+        , verbose     :: Verbosity    -- ^ @-V|-V[012]@, display verbose information to stderr+        , sciDbVersion:: String       -- ^ Store SciDB version, e.g., 18.1.0+        , versionSciDb:: Bool         -- ^ True to display SciDB version via shim+        } deriving Show++-- The default Environment+{- |+The defualt values, otherwise updated from the flags supplied by the+command line options.  The default program name is 'hquery'.+-}+defaultEnv :: Environment+defaultEnv =+    Env { command     = "hquery"                -- Default program name+        , pwd         = ""                      -- No PWD by default+        , home        = "/tmp"                  -- /tmp if $HOME does not exist+        , history     = ""                      -- History file for command+        , protocol    = "http"                  -- No authentication needed for http+        , certStore   = ""                      -- Load and use certificate store+        , insecure    = False                   -- Use "insecure" SSL/TLS, i.e., no cert validation+        , scidbAuth   = False                   -- Use SciDB authentication+        , digestAuth  = False                   -- Use basic digest access authentication+        , digestHeaders=[]                      -- Digest request headers or nothing for the GET method+        , defFetch    = Just True               -- True fetch lines, false do not fetch lines+        , defFormat   = "dcsv"                  -- Format dcsv, csv, csv+, etc.+        , defNumber   = "23"                    -- Default 23 lines, default for bad number+        , defReadingLines=Just True             -- True to read lines from shim otheriwise read bytes+        , defPrefix   = ""                      -- Prefix to execute before a query by shim+        , host        = "localhost"             -- Use local shim connection+        , port        = Nothing                 -- Nothing for default port number not needing authentication+        , defPort     = "8080"                  -- Default port number not needing authentication+        , secPort     = "8083"                  -- Default port number needing authentication+        , username    = ""                      -- Username needed for -d or -s option+        , password    = ""                      -- Password needed for -d or -s option+        , operands    = []                      -- No operands by default, i.e., interactive mode+        , file        = ""                      -- No file of queries by default+        , help        = False                   -- False or off by default+        , license     = False                   -- False or off by default+        , manual      = False                   -- False or off by default+        , synopsis    = False                   -- False or off by default+        , version     = False                   -- False or off by default+        , verbose     = VerboseDef              -- Default verbosity+        , sciDbVersion= ""                      -- Store SciDB version, e.g., 18.1.0+        , versionSciDb= False                   -- True to display SciDB version via shim+        }
+ src/HQuery.hs view
@@ -0,0 +1,525 @@+{-# LANGUAGE FlexibleContexts, OverloadedStrings, LambdaCase #-}++{- |+There is a primitive API derived after the creation of 'hquery'+defined by the following data structures and actions:++    * 'Environment', the API only uses the following fields:++        * 'certStore'+        * 'defFetch'+        * 'defFormat'+        * 'defNumber'+        * 'defPrefix'+        * 'defReadingLines'+        * 'digestAuth'+        * 'host'+        * 'insecure'+        * 'password'+        * 'port'+        * 'protocol'+        * 'scidbAuth'+        * 'username'+        * 'verbose'++    * 'Err'+    * 'mkGlobalManagerEnv'+    * 'runQueries'+    * 'unsafeRunQuery'+    * 'getSciDbVersion'+-}++module HQuery (hquery+              ,getSciDbVersion+              ,mkGlobalManagerEnv+              ,runQueries+              ,unsafeRunQuery+              ) where++import Control.Monad                          (unless,when)+import Control.Monad.Catch                    (try,MonadCatch,MonadThrow)+import Control.Monad.IO.Class                 (MonadIO)+import Control.Monad.Reader                   (MonadReader,ReaderT,runReaderT,ask)+import Control.Monad.State                    (StateT,evalStateT,liftIO,get,put)+import Control.Monad.State.Class              (MonadState)+import Control.Monad.Trans                    (lift)+import Data.Char                              (toLower)+import Data.List                              (intercalate)+import Data.Maybe                             (isNothing,isJust,fromJust,fromMaybe)+import Data.X509.CertificateStore             (readCertificateStore)+import Network.Socket                         (withSocketsDo)+import Network.Connection                     (TLSSettings(..))+import Network.HTTP.Base                      (urlEncode,urlDecode)+import Network.HTTP.Client                    (defaultManagerSettings,requestHeaders,defaultRequest+                                              ,RequestBody,streamFile,requestBody,method,Request)+import Network.HTTP.Client.TLS                (getGlobalManager,setGlobalManager,applyDigestAuth)+import Network.HTTP.Simple                    (parseRequestThrow,httpLBS,setRequestManager)+import Network.HTTP.Conduit                   (HttpException(..),HttpExceptionContent(..),Response(..)+                                              ,managerResponseTimeout,responseTimeoutNone,newManager+                                              ,mkManagerSettings)+import Network.HTTP.Types.Status              (Status(..))+import Safe                                   (tailSafe,headMay)+import System.Console.Haskeline               (runInputT,defaultSettings,getInputLine,historyFile+                                              ,withInterrupt,handleInterrupt,outputStrLn)+import System.Console.Terminal.Size           (Window(..),size)+import System.Exit                            (exitWith,ExitCode(..))+import System.IO                              (stderr,stdin,hPutStrLn,hReady,getContents)++import qualified Data.Text.Lazy.Encoding as L (decodeUtf8)+import qualified Data.Text.Lazy          as L (unpack)+import qualified Data.ByteString.Char8   as C (pack,unpack)+import qualified Network.HTTP.Client     as H (Request(..))++import Environment                            (Environment(certStore,defFetch,defFormat,defNumber+                                                          ,defReadingLines,defPrefix,digestAuth+                                                          ,digestHeaders,file,history,host,insecure+                                                          ,operands,password,port,protocol,sciDbVersion+                                                          ,scidbAuth,username,verbose)+                                               ,defaultEnv,maybePort,Verbosity(..))+import ErrM                                   (Err(..))+import Interpreter                            (Results(..),interpret)+import Utils                                  (strip,wrap,nolines,cleanDoubleQuotes,replace,toSingleQuotedStr+                                              ,escapeSingleQuotes,toSingleQuotedStr,checkMajorVersion)+import UtilsUnsafe                            (managerSettings,valid,VALID(..))++-- | The 'Param' is a structure of parameters that can change during+-- execution. For example, see 'executeCommand'.  When 'readingLines'+-- is false, the value of ''number' is ignored and the entire output+-- buffer is downloaded.  This follows the recommendataion of the shim+-- documentation.++data Param =+    Param {session     :: String   -- ^ The current session id, a number+          ,number      :: String   -- ^ Number of lines to display+          ,fetch       :: Bool     -- ^ Fetch lines yes (true) or no (false)+          ,format      :: String   -- ^ Available base_format values are: csv, text, ...+                                   --     *** + becomes %2B ***+                                   --     csv     - Comma separated values+                                   --     csv+    - Comma separated values including coordinates+                                   --     dcsv    - "Display CSV", a more human-readable CSV variant+                                   --     dense   - A variant of 'text' suitable for dense data+                                   --     sparse  - A variant of 'text' suitable for sparse data+                                   --     opaque  - SciDB raw storage format+                                   --     store   - A variant of 'text' that includes overlap regions+                                   --     text    - SciDB native text format+                                   --     tsv     - Tab separated values (LinearTSV dialect)+                                   --     tsv+    - Tab separated values including coordinates (LinearTSV dialect)+          ,readingLines:: Bool     -- ^ True for path /read_lines, the default, and false for /read_bytes+          ,prefix      :: String   -- ^ An optional semi-colon separated, URL encoded, AFL statements to precede+                                   -- a query in the same SciDB  connection context. Mainly used for SciDB+                                   -- namespace and role setting.  There is no terminating semi-colon so+                                   -- trailing semi-colons are removed.+          ,fileBody    :: Maybe RequestBody -- ^ Just send a file as a request body otherwise Nothing+          }++defaultParam = Param {session = ""+                     ,number       = defNumber defaultEnv+                     ,fetch        = fromJust $ defFetch defaultEnv+                     ,format       = defFormat defaultEnv+                     ,readingLines = fromJust $ defReadingLines defaultEnv+                     ,prefix       = ""+                     ,fileBody     = Nothing+                     }++initParam :: StateT Param (ReaderT Environment IO) ()+initParam = do e <- ask+               p <- get+               put p{number       = defNumber e+                    ,fetch        = fromJust $ defFetch e+                    ,format       = defFormat e+                    ,readingLines = fromJust $ defReadingLines e+                    ,prefix       = defPrefix e+                    }++-- | Get the version of SciDB, e.g., 18.1.0, via shim given an 'Environment'.++getSciDbVersion :: Environment -> IO String+getSciDbVersion e = withSocketsDo (runReaderT (evalStateT fetchVersion defaultParam{number="0"}) e)+    where+      fetchVersion = do e <- ask+                        let url = urlPrefix e ++ "/version"+                        fetchURL (verbose e) url++-- | Given an 'Environment', make and set the global network manager,+-- check for digest authorization and the SciDB version, and update+-- the 'Environment'.  Either return 'Just Environment' or 'Nothing'+-- in the IO monad in the case of an invalid certificate store when+-- the protocol is HTTPS and insecure validation is not used.  Be+-- careful: no resolving or verification of the 'Environment' is+-- performed.  When 'mkGlobalManagerEnv' returns 'Just Environment',+-- this is the initialized 'Environment' to be used with the actions+-- 'runQueries' and 'unsafeRunQuery'.++mkGlobalManagerEnv :: Environment -> IO (Maybe Environment)+mkGlobalManagerEnv env =+    do mstore  <- readCertificateStore (certStore env)+       let defSettings = defaultManagerSettings+           tlsSettings = mkManagerSettings (TLSSettingsSimple True False False) Nothing+           caStore     = fromJust mstore+           caSettings  = managerSettings caStore+       s <- if protocol env /= "https"+            then return $ Just defSettings+            else if insecure env+                 then return $ Just tlsSettings+                 else if isJust mstore+                      then return $ Just caSettings+                      else return Nothing+       if isNothing s+       then return Nothing+       else do let s' = fromJust s+               manager <- newManager s'{managerResponseTimeout=responseTimeoutNone}+               liftIO $ setGlobalManager manager+               request <- maybeSetDigestAuth' env -- Used to throw HTTP exceptions early+               let env' = env{digestHeaders = maybe [] requestHeaders request}+               if digestAuth env+               then do v <- getSciDbVersion env'+                       return $ Just env'{sciDbVersion=v}+               else do v <- getSciDbVersion env+                       return $ Just env{sciDbVersion=v}+    where+      maybeSetDigestAuth' =+          runReaderT (do env <- ask+                         maybeSetDigestAuth defaultRequest{H.host   = C.pack $ host env+                                                          ,H.port   = read $ maybePort env :: Int+                                                          ,H.secure = protocol env == "https"+                                                          }+                     )++maybeSetDigestAuth :: (MonadReader Environment m, MonadIO m, MonadThrow n) => Request -> m (n Request)+maybeSetDigestAuth r =+    do e <- ask+       m <- liftIO getGlobalManager+       let user = C.pack $ username e+           pass = C.pack $ password e+       if digestAuth e+       then liftIO $ applyDigestAuth user pass r{H.secure = protocol e == "https"} m+       else return $ return r++-- | Given an 'Environment', run a string that is one SciDB AFL+-- query without terminating semicolon (;).  The string is sent to the+-- shim server without modification or verification.  Fetch+-- 'defNumber' lines (23 by default); an exception occurs when+-- attempting to fetch no returned lines.  If fetch is false, do not+-- fetch any lines. For exmample, fetch should be set to false for+-- store, create and load.  See 'interpretOperatorId' in+-- Interpreter.hs for details.++unsafeRunQuery :: Environment -> String -> IO String+unsafeRunQuery e s =+    withSocketsDo (runReaderT (evalStateT _executeQuery defaultParam) e)+    where _executeQuery = do initParam+                             p <- get+                             executeAndGet (fetch p) s++-- | Given an 'Environment', run a string of semi-colon (;)+-- separated SciDB AFL queries and fetch 'defNumber' lines (23 by+-- default) from the result of each query if the query returns a+-- result. Like 'hquery', 'runQueries' determines if the SciDB+-- operator returns lines or not via 'interpretOperatorId' in+-- Interpreter.hs.++runQueries :: Environment -> String -> IO [Err String]+runQueries e s =+    withSocketsDo (runReaderT (evalStateT (executeQueries s) defaultParam) e)++executeQueries :: String -> StateT Param (ReaderT Environment IO) [Err String]+executeQueries s =+    do initParam+       case interpret s of+         Ok rs  -> filter (\case Ok "" -> False; _ -> True) <$> mapM executeResult rs+         Bad s' -> return [Bad s']++data ExitOrDont = ExitOnBad | DontExitOnBad deriving Eq++-- | Given an 'Environment', either run the given file of queries and+-- the operands on the command line as queries or run queries interactively.++hquery :: Environment -> IO ()+hquery e = withSocketsDo (runReaderT (evalStateT _hquery defaultParam) e)+    where _hquery =+              do initParam+                 e <- ask+                 r <- liftIO $ hReady stdin+                 if null (operands e) && null (file e) && not r+                 then do liftIO $ putStrLn ("SciDB version "++sciDbVersion e)+                         executeQuery DontExitOnBad "list('instances');"+                         iQuery+                 else do c <- liftIO $ if r then getContents else return ""+                         f <- liftIO $ (if null (file e) then return else readFile) (file e)+                         let a = intercalate "\n" ("":(nolines <$> operands e))+                         executeQuery ExitOnBad (c ++ f ++ a)+          iQuery =+              do e <- ask+                 p <- get+                 liftIO $ runInputT defaultSettings{historyFile = Just (history e)} (loop e p)+          loop e p = withInterrupt (_loop p)+              where+                _loop p = handleInterrupt (outputStrLn "^C" >> _loop p) $+                    do minput <- fmap strip <$> getInput (prompt p ++ " ")+                       case minput of+                         Nothing     -> return ()+                         Just ""     -> _loop p+                         Just q      -> do p' <- lift $ runReaderT (evalStateT (do executeQuery DontExitOnBad q+                                                                                   get+                                                                               ) p) e+                                           _loop p'+          getInput p = getInput' p False ""+              where getInput' p insideQuote q =+                        do mi <- getInputLine p+                           case mi of+                             Nothing -> return Nothing+                             Just "" -> return $ Just ""+                             Just l  -> processInput insideQuote q l+                    processInput insideQuote q []     = getInput' "Con> " insideQuote (q++"\n")+                    processInput insideQuote q (c:cs) =+                        case c of+                          '\\' -> case headMay cs of+                                    Nothing -> getInput' "Con> " insideQuote (q++[c,'\n'])+                                    Just hd -> processInput insideQuote (q++[c,hd]) (tailSafe cs)+                          '\'' -> processInput (toggle insideQuote) (q++[c]) cs where toggle=not+                          ';' | insideQuote     -> processInput insideQuote (q ++ [c]) cs+                              | null (strip cs) -> return $ Just (q ++ [c] ++ cs ++ "\n")+                              | otherwise       -> processInput insideQuote (q ++ [c]) cs+                          _    -> processInput insideQuote (q++[c]) cs+          prompt param = (if not (readingLines param) && fetch param then "Bytes" else show (fetch param))+                         ++"/"++format param++"/"++number param+                         ++(if null (prefix param) then "?" else "p")+          executeQuery f s =+              case interpret s of+                Ok rs  -> let n    = length rs+                              bads = findBads rs+                          in if null bads+                             then mapM_ executeResult' rs+                             else liftIO $+                                  mapM_ (\(i,r) -> putStderr ("Query "++show i++" of "++show n++": ") (show r))+                                  bads+                Bad s -> liftIO (putStderr "Input " s >> if f == DontExitOnBad then return () else exit 12)+          findBads rs = filter (\(_,r) -> case r of BadNesting _ -> True ; _ -> False) $ zip [1..] rs+          executeResult' r = do err <- executeResult r+                                liftIO $ case err of+                                           Bad s -> putStderr "Input " s+                                           Ok s  -> putStr s++executeResult :: Results -> StateT Param (ReaderT Environment IO) (Err String)+executeResult r =+    case r of+      BadNesting s -> return $ Bad ("bad nesting " ++ toSingleQuotedStr s)+      No s         -> do executeAndGet False s+                         return $ Ok ""+      Yes s        -> do p <- get+                         if fetch p+                         then Ok <$> executeAndGet True s+                         else executeResult (No s)+      Upload (q,ss)-> executeUpload q ss+      Unknown s    -> executeResult (Yes s)+      _            -> do executeCommand r+                         return $ Ok ""+    where+      executeUpload s []      = do let q = s++";" -- Trailing semi-colon (;) needed by executeQueries+                                   (intercalate "\n" <$>) . sequence <$> executeQueries q+      executeUpload s (p:ps) =+          do let fp     = fst p+                 needle = snd p+             b <- liftIO $ valid READABLE fp+             if b+             then do fetchSession+                     putVerbose "filepath to upload=" fp+                     u <- toSingleQuotedStr <$> uploadFile fp+                     putVerbose "uploaded filepath=" u+                     p <- get+                     err <- executeUpload (replace needle u s) ps+                     put p+                     releaseSession+                     return err+             else return $ Bad ("Bad filepath '"++escapeSingleQuotes fp++"'")+      uploadFile fp = do e  <- ask+                         p  <- get+                         rb <- liftIO $ streamFile fp+                         put p{fileBody=Just rb}+                         let url = urlPrefix e ++ "/upload?id=" ++ session p+                         fetchURL (verbose e) url+      executeCommand :: (MonadIO m, MonadState Param m) => Results -> m ()+      executeCommand r =+          case r of+            Command s -> case fmap toLower s of+                           "quit" -> exit 0+                           "exit" -> exit 0+                           "funs" -> liftIO $ putStrLn (    "exit   - exit or quit interpreter"+                                                       ++ "\nfuns   - list interpreter functions"+                                                       ++ "\nquit   - quit or exit interpreter"+                                                       ++ "\nupload - upload a file and run a query using it"+                                                       ++ "\nvars   - list interpreter variables and values"+                                                       )+                           "vars" -> do p <- get+                                        liftIO $ putStrLn (    "fetch        = " ++ show (fetch p)+                                                          ++ "\nreadinglines = " ++ show (readingLines p)+                                                          ++ "\nformat       = " ++ format p+                                                          ++ "\nnumber       = " ++ number p+                                                          ++ "\nprefix       = " ++ prefix p+                                                          )+                           _      -> liftIO $ putStderr "Ignored unknown command: " s+            Fetch mb  -> unless (isNothing mb) $ do p <- get+                                                    put $ p{fetch=fromJust mb}+            Format ms -> unless (isNothing ms) $ do p <- get+                                                    put $ p{format=fromJust ms}+            Lines mi  -> unless (isNothing mi) $ do p <- get+                                                    put $ p{number=show$fromJust mi}+            ReadingLines mb -> unless (isNothing mb) $ do p <- get+                                                          put p{readingLines=fromJust mb}+            Prefix s  -> do p <- get+                            put p{prefix=s}++executeAndGet :: Bool -> String -> StateT Param (ReaderT Environment IO) String+executeAndGet f s =+    do fetchSession+       e <- ask+       p <- get+       let url = urlPrefix e ++ "/execute_query?id=" ++ session p ++ addPrefix p ++ "&query=" ++ urlEncode s+                 ++ (if f then "&save=" ++ urlEncode (format p) else "") ++ addAuthCode e+       putVerbose "execute_query=" s+       fetchURL (verbose e) url+       d <- if f then readData else return ""+       releaseSession+       return d+    where+      addPrefix p = if null (prefix p) then "" else "&prefix=" ++ prefix p+      readData  =+            do e <- ask+               p <- get+               let url = urlPrefix e ++ (if readingLines p then "/read_lines" else "/read_bytes")+                         ++ "?id=" ++ session p+                         ++ "&n=" ++ (if readingLines p then number p else "0")+                   v   = quietIfDef (verbose e)+               fetchURL v url++fetchURL :: (MonadReader Environment m, MonadState Param m, MonadIO m, MonadCatch m)+            => Verbosity -> String -> m String+fetchURL v s =+               do env <- ask+                  r <- try (continueHttp s)+                  case r of +                    Left  e -> do let prefix = "SciDB " ++ sciDbVersion env ++ " URL exception\n    "+                                  when (v > Verbose0) $ liftIO $ putHttpException prefix s e+                                  return ""+                    Right b -> do when (v > Verbose1) $ liftIO $ putStderr "URL=" s+                                  return $ L.unpack $ L.decodeUtf8 b+    where continueHttp s =+              do e <- ask+                 p <- get+                 request <- parseRequestThrow s+                 let request'=request{requestHeaders=digestHeaders e++requestHeaders request}+                 response <- if isNothing (fileBody p)+                             then httpLBS request'+                             else do -- The digest for the POST method apparently depends on the requestBody(?)+                                     mrequest <- maybeSetDigestAuth request{method="POST",requestBody=fromJust$fileBody p}+                                     httpLBS $ fromMaybe request' mrequest+                 return (responseBody response)+          putHttpException prefix s e =+              do putStderr prefix s+                 putStderr (tailSafe $ dropWhile (/='\n') prefix) (urlDecode s)+                 case e of+                   InvalidUrlException url reason -> putStderr (url ++ ": ") reason+                   HttpExceptionRequest req e ->+                       do w <- maybe consoleWidth width <$> size+                          case e of+                            StatusCodeException responseBody s ->+                                do let status = responseStatus responseBody+                                   putStderr "HTTP code     = " $ show $ statusCode status+                                   let m = statusMessage status+                                   putStderr "     message  = " $ C.unpack m+                                   putStderr response_          $ format w i0 $ C.unpack s+                                   when (unauthorized == m) (exit 10)+                                   when (noSciDBconnect == s) (exit 11)+                            TooManyRedirects _                  -> putStderr "TooManyRedirects" "" >> exit 8+                            OverlongHeaders                     -> putStderr "OverlongHeaders" "" >> exit 8+                            ResponseTimeout                     -> putStderr "ResponseTimeout" ""+                            ConnectionTimeout                   -> putStderr "ConnectionTimeout" ""+                            ConnectionFailure _                 -> putStderr "ConnectionFailure" ""+                            InvalidStatusLine _                 -> putStderr "InvalidStatusLine" "" >> exit 8+                            InvalidHeader _                     -> putStderr "InvalidHeader" "" >> exit 8+                            InvalidRequestHeader _              -> putStderr "InvalidRequestHeader" "" >> exit 8+                            InternalException _                 -> putStderr internalException (format w i1 $ cleanDoubleQuotes $ show e) >> exit 8+                            ProxyConnectException{}             -> putStderr "ProxyConnectException" "" >> exit 8+                            NoResponseDataReceived              -> putStderr "NoResponseDataReceived" ""+                            TlsNotSupported                     -> putStderr "TlsNotSupported" "" >> exit 8+                            WrongRequestBodyStreamSize _ _      -> putStderr "WrongRequestBodyStreamSize" "" >> exit 8+                            ResponseBodyTooShort _ _            -> putStderr "ResponseBodyTooShort" "" >> exit 8+                            InvalidChunkHeaders                 -> putStderr "InvalidChunkHeaders" "" >> exit 8+                            IncompleteHeaders                   -> putStderr "IncompleteHeaders" "" >> exit 8+                            InvalidDestinationHost _            -> putStderr "InvalidDestinationHost" "" >> exit 8+                            HttpZlibException _                 -> putStderr "HttpZlibException" ""+                            InvalidProxyEnvironmentVariable _ _ -> putStderr "InvalidProxyEnvironmentVariable" "" >> exit 8+                            ConnectionClosed                    -> putStderr "ConnectionClosed" ""+                            InvalidProxySettings _              -> putStderr "InvalidProxySettings" "" >> exit 8+                     where response_            = "     response = "+                           internalException    = "InternalException: " :: String {- Why is this needed? -}+                           i0                   = length response_+                           i1                   = length internalException+                           unauthorized         = C.pack "Unauthorized"+                           noSciDBconnect       = C.pack "Could not connect to SciDB"+                           -- Console terminal default width is 80 characters+                           consoleWidth         = 80+                           format w i s         = (intercalate "\n" . indent) ls+                               where ls         = (concatMap (wrap l) . lines) s+                                     l          = max consoleWidth w - i+                                     indent []  = []+                                     indent ls  = hd:((ss++) <$> tl)+                                         where hd = head ls+                                               tl = tail ls+                                               ss = replicate i ' '++fetchSession :: StateT Param (ReaderT Environment IO) ()+fetchSession =+         do e <- ask+            p <- get+            let url = urlPrefix e ++ "/new_session" ++ addAuthCode e+            s <- fetchURL (verbose e) url+            put p{session = strip s}+            p' <- get+            putVerbose "session=" (session p')+    where addAuthCode e = if scidbAuth e && checkMajorVersion (>=19) (sciDbVersion e)+                          then "?user=" ++ username e ++ "&password=" ++ password e+                          else ""++releaseSession :: StateT Param (ReaderT Environment IO) ()+releaseSession =+           do e <- ask+              p <- get+              let url = urlPrefix e ++ "/release_session?id=" ++ session p+                  v   = quietIfDef (verbose e)+              s <- fetchURL v url+              putVerbose "release_session=" (session p ++ s)++-- Not used: for documentation purposes+cancelSession :: StateT Param (ReaderT Environment IO) ()+cancelSession =+          do e <- ask+             p <- get+             let url = urlPrefix e ++ "/cancel?id=" ++ session p ++ addAuthCode e+                 v   = quietIfDef (verbose e)+             s <- fetchURL v url+             putVerbose "cancel_session=" (session p ++ s)++addAuthCode :: Environment -> String+addAuthCode e = if scidbAuth e && checkMajorVersion (18>=) (sciDbVersion e)+                then "&user=" ++ username e ++ "&password=" ++ password e+                else ""++putVerbose :: (MonadReader Environment m, MonadIO m) => String -> String -> m ()+putVerbose s t = do e <- ask+                    when (verbose e > VerboseDef) (putStderr s t)++quietIfDef :: Verbosity -> Verbosity+quietIfDef v = if v /= VerboseDef then v else Verbose0++urlPrefix :: Environment -> String+urlPrefix env  = protocol' ++ "://" ++ host' ++ ":" ++ port'+    where protocol' = protocol  env+          host'     = host      env+          port'     = maybePort env++putStderr :: MonadIO m => String -> String -> m ()+putStderr s t = unless (null t) $ liftIO $ hPutStrLn stderr (s++t)++exit :: MonadIO m => Int -> m a+exit i = liftIO $ exitWith $ if i == 0 then ExitSuccess else ExitFailure i
+ src/Interpreter.hs view
@@ -0,0 +1,222 @@+{-# LANGUAGE QuasiQuotes #-}+{- |+The 'hquery' command via 'interpret' is based on the BNFC language defined+by [SciDbAFL.cf](SciDbAFL.html).+-}+module Interpreter(Results(..)+                  ,interpret+                  ) where++import Data.Char (toLower)+import Data.List (nub)+import System.IO (stderr,hPutStrLn)+import Text.RE.TDFA.String ((*=~),matches,re)++import AbsSciDbAFL (AFL(..),Query(..),Exp(..),Id(..),AString(..))+import ErrM (Err(..))+import ParSciDbAFL (myLexer,pAFL)+import PrintSciDbAFL (printTree)+import Utils (deEscapeSingleQuotes,stripUsing,toDoubleQuotedStr,)++data Results = Yes String -- ^ One can fetch a result if desired; it+                          -- is not an error to do so+             | No String -- ^ One cannot and should not fetch a+                         -- result; it is an error to do so+             | Unknown String -- ^ Unknown, possible user query+                              -- operator; could be Yes or No+             | BadNesting String -- ^ An argument query contains a No+                                 -- query; they should only contain+                                 -- Yes or Unknown queries+             | Command String -- ^ Command to be executed by hquery+             | Fetch (Maybe Bool) -- ^ Fetch lines: true (yes) or+                                  -- false (no); Nothing means no+                                  -- change+             | Format (Maybe String) -- ^ Format string, e.g., dcsv,+                                     -- csv+ (csv%2B); Nothing means+                                     -- no change+             | Lines (Maybe Integer) -- ^ Number of lines to fetch;+                                     -- Nothing means no change+             | ReadingLines  (Maybe Bool) -- ^ Reading lines: true to+                                          -- read lines and false to+                                          -- read bytes; Nothing means+                                          -- no change+             | Prefix String -- ^ An optional semi-colon separated,+                             -- URL encoded, AFL statements to precede+                             -- a query in the same SciDB connection+                             -- context. Mainly used for SciDB+                             -- namespace and role setting.  There is+                             -- no terminating semi-colon so trailing+                             -- semi-colons are removed.+             | Upload (String,[(FilePath,String)])+                       -- ^ The first String is the query with uploads+                       -- to perform and without a trailing semi-colon+                       -- (;).  The FilePath is the file to upload and+                       -- the second String is the String to replace+                       -- with the uploaded filepath, a single quoted+                       -- SciDB string.+               deriving (Eq, Ord, Show, Read)++-- | Return a list of results as an 'Err'.+interpret :: String -> Err [Results]+interpret s =+    let err = pAFL $ myLexer s+    in case err of+         Ok (Queries qs) -> let qs' = filter (/=QueryNil) qs+                            in Ok (fmap interpretQuery qs')+         Bad s'          -> Bad s'++interpretQuery :: Query -> Results+interpretQuery q =+    case q of+      QueryNil     -> No ""+      QueryArray{} -> No s+      QueryTemp{}  -> No s+      QueryExp exp -> interpretExp exp+    where+      s = printTree q+      interpretExp exp = case exp of+                           EFunc id es | any no es  -> BadNesting s+                                       | any up es  -> Upload (s,uploadMatches s)+                                       | otherwise  -> interpretId id+                           EVar (Id var)            -> Command var+                           Eeq a b                  -> interpretEeq a b+                           _                        -> Unknown s+      interpretId (Id id) = interpretFuncId id s+      no e = case e of+               EFunc id es -> bad id || any no es+               _           -> False+      bad (Id id) = interpretFuncId id "" == No ""+      up e = case e of+               EFunc id es -> anUp id es || any up es+               _           -> False+      anUp (Id id) [EString (AString _)] = fmap toLower id == "upload"+      anUp _       _                     = False+      interpretEeq a b = case a of+                           EVar (Id var) -> interpretVar var b+                           _             -> Unknown s+      interpretVar var b = case fmap toLower var of+                             "fetch"  -> case b of+                                           ETrue _  -> Fetch $ Just True+                                           EFalse _ -> Fetch $ Just False+                                           _        -> Fetch Nothing+                             "format" -> case b of+                                           EString (AString str) -> Format $ Just $ toDoubleQuotedStr str+                                           _                     -> Format Nothing+                             "n"      -> case b of+                                           EInt n -> Lines $ Just n+                                           _      -> Lines Nothing+                             "readinglines"  -> case b of+                                                  ETrue _  -> ReadingLines $ Just True+                                                  EFalse _ -> ReadingLines $ Just False+                                                  _        -> ReadingLines Nothing+                             "prefix" -> case b of+                                           EString (AString str) -> Prefix+                                                                    $ deEscapeSingleQuotes+                                                                    $ stripUsing (\c -> c=='\'' || c==';') str+                             _        -> Unknown s+++uploadMatches :: String -> [(FilePath,String)]+uploadMatches s = fmap pair $ nub $ matches $ s *=~ uploadRe+    where+      uploadRe = [re|[Uu][Pp][Ll][Oo][Aa][Dd][[:space:]]*[(][[:space:]]*'([^']|\\')*'[[:space:]]*[)]|]+      pair s = ((tail . dropWhile (/='\'') . reverse . tail . dropWhile (/='\'') . reverse) s, s)++-- Determined by experience and particular to shim+interpretFuncId :: String -> (String -> Results)+interpretFuncId id =+    case fmap toLower id of+      "add_instances" -> No+      "add_user_to_role" -> No+      "aggregate" -> Yes+      "apply" -> Yes+      "attributes" -> Yes+      "avg_rank" -> Yes+      "bernoulli" -> Yes+      "between" -> Yes+      "build" -> Yes+      "cancel" -> No+      "cast" -> Yes+      "change_user" -> No+      "consume" -> No+      "create_namespace" -> No+      "create_role" -> No+      "create_user" -> No+      "cross_between" -> Yes+      "cross_join" -> Yes+      "cumulate" -> Yes+      "delete" -> Yes+      "dimensions" -> Yes+      "drop_namespace" -> No+      "drop_role" -> No+      "drop_role_for_user" -> No+      "drop_user" -> No+      "drop_user_from_role" -> No+      "filter" -> Yes+      "gemm" -> Yes+      "gesvd" -> Yes+      "glm" -> Yes+      "help" -> Yes+      "index_lookup" -> Yes+      "input" -> Yes+      "insert" -> Yes+      "join" -> Yes+      "kendall" -> Yes+      "limit" -> Yes+      "list" -> Yes+      "list_array_residency" -> Yes+      "list_instances" -> Yes+      "load" -> No+      "load_module" -> No+      "load_library" -> No+      "merge" -> Yes+      "move_array_to_namespace" -> No+      "mpi_init" -> No+      "pearson" -> Yes+      "project" -> Yes+      "quantile" -> Yes+      "rank" -> Yes+      "redimension" -> Yes+      "redistribute" -> Yes+      "regrid" -> Yes+      "remove" -> No+      "remove_instances" -> No+      "remove_versions" -> No+      "rename" -> No+      "repart" -> Yes+      "reshape" -> Yes+      "rng_uniform" -> Yes+      "save" -> No+      "scan" -> Yes+      "set_namespace" -> No+      "set_role_permissions" -> No+      "show" -> Yes+      "show_namespace" -> Yes+      "show_role_permissions" -> Yes+      "show_roles_for_user" -> Yes+      "show_user" -> Yes+      "show_user_in_role" -> Yes+      "slice" -> Yes+      "sort" -> Yes+      "spearman" -> Yes+      "spgemm" -> Yes+      "stats_instance" -> Yes+      "stats_instance_reset" -> No+      "stats_query" -> Yes+      "store" -> No+      "subarray" -> Yes+      "substitute" -> Yes+      "summarize" -> Yes+      "sync" -> No+      "transpose" -> Yes+      "tsvd" -> Yes+      "unfold" -> Yes+      "uniq" -> Yes+      "unload_library" -> No+      "unpack" -> Yes+      "unregister_instances" -> No+      "variable_window" -> Yes+      "versions" -> Yes+      "window" -> Yes+      "xgrid" -> Yes+      _ -> Unknown
+ src/License.hs view
@@ -0,0 +1,691 @@+module License(putLicense) where++import System.Exit (exitWith)+import UtilsUnsafe (putOrPageStrLn)++-- | Display the license terms (GNU GPLv3).++putLicense :: IO ()+putLicense = putOrPageStrLn gpl30License >>= exitWith++-- | Derived from gpl-3.0.txt (GNU GENERAL PUBLIC LICENSE, Version 3,+-- 29 June 2007).++gpl30License :: String+gpl30License =+    "        License terms: GNU GPL version 3 or any later version\n"+++    "\n"+++    "                    GNU GENERAL PUBLIC LICENSE\n"+++    "                       Version 3, 29 June 2007\n"+++    "\n"+++    " Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n"+++    " Everyone is permitted to copy and distribute verbatim copies\n"+++    " of this license document, but changing it is not allowed.\n"+++    "\n"+++    "                            Preamble\n"+++    "\n"+++    "  The GNU General Public License is a free, copyleft license for\n"+++    "software and other kinds of works.\n"+++    "\n"+++    "  The licenses for most software and other practical works are designed\n"+++    "to take away your freedom to share and change the works.  By contrast,\n"+++    "the GNU General Public License is intended to guarantee your freedom to\n"+++    "share and change all versions of a program--to make sure it remains free\n"+++    "software for all its users.  We, the Free Software Foundation, use the\n"+++    "GNU General Public License for most of our software; it applies also to\n"+++    "any other work released this way by its authors.  You can apply it to\n"+++    "your programs, too.\n"+++    "\n"+++    "  When we speak of free software, we are referring to freedom, not\n"+++    "price.  Our General Public Licenses are designed to make sure that you\n"+++    "have the freedom to distribute copies of free software (and charge for\n"+++    "them if you wish), that you receive source code or can get it if you\n"+++    "want it, that you can change the software or use pieces of it in new\n"+++    "free programs, and that you know you can do these things.\n"+++    "\n"+++    "  To protect your rights, we need to prevent others from denying you\n"+++    "these rights or asking you to surrender the rights.  Therefore, you have\n"+++    "certain responsibilities if you distribute copies of the software, or if\n"+++    "you modify it: responsibilities to respect the freedom of others.\n"+++    "\n"+++    "  For example, if you distribute copies of such a program, whether\n"+++    "gratis or for a fee, you must pass on to the recipients the same\n"+++    "freedoms that you received.  You must make sure that they, too, receive\n"+++    "or can get the source code.  And you must show them these terms so they\n"+++    "know their rights.\n"+++    "\n"+++    "  Developers that use the GNU GPL protect your rights with two steps:\n"+++    "(1) assert copyright on the software, and (2) offer you this License\n"+++    "giving you legal permission to copy, distribute and/or modify it.\n"+++    "\n"+++    "  For the developers' and authors' protection, the GPL clearly explains\n"+++    "that there is no warranty for this free software.  For both users' and\n"+++    "authors' sake, the GPL requires that modified versions be marked as\n"+++    "changed, so that their problems will not be attributed erroneously to\n"+++    "authors of previous versions.\n"+++    "\n"+++    "  Some devices are designed to deny users access to install or run\n"+++    "modified versions of the software inside them, although the manufacturer\n"+++    "can do so.  This is fundamentally incompatible with the aim of\n"+++    "protecting users' freedom to change the software.  The systematic\n"+++    "pattern of such abuse occurs in the area of products for individuals to\n"+++    "use, which is precisely where it is most unacceptable.  Therefore, we\n"+++    "have designed this version of the GPL to prohibit the practice for those\n"+++    "products.  If such problems arise substantially in other domains, we\n"+++    "stand ready to extend this provision to those domains in future versions\n"+++    "of the GPL, as needed to protect the freedom of users.\n"+++    "\n"+++    "  Finally, every program is threatened constantly by software patents.\n"+++    "States should not allow patents to restrict development and use of\n"+++    "software on general-purpose computers, but in those that do, we wish to\n"+++    "avoid the special danger that patents applied to a free program could\n"+++    "make it effectively proprietary.  To prevent this, the GPL assures that\n"+++    "patents cannot be used to render the program non-free.\n"+++    "\n"+++    "  The precise terms and conditions for copying, distribution and\n"+++    "modification follow.\n"+++    "\n"+++    "                       TERMS AND CONDITIONS\n"+++    "\n"+++    "  0. Definitions.\n"+++    "\n"+++    "  \"This License\" refers to version 3 of the GNU General Public License.\n"+++    "\n"+++    "  \"Copyright\" also means copyright-like laws that apply to other kinds of\n"+++    "works, such as semiconductor masks.\n"+++    "\n"+++    "  \"The Program\" refers to any copyrightable work licensed under this\n"+++    "License.  Each licensee is addressed as \"you\".  \"Licensees\" and\n"+++    "\"recipients\" may be individuals or organizations.\n"+++    "\n"+++    "  To \"modify\" a work means to copy from or adapt all or part of the work\n"+++    "in a fashion requiring copyright permission, other than the making of an\n"+++    "exact copy.  The resulting work is called a \"modified version\" of the\n"+++    "earlier work or a work \"based on\" the earlier work.\n"+++    "\n"+++    "  A \"covered work\" means either the unmodified Program or a work based\n"+++    "on the Program.\n"+++    "\n"+++    "  To \"propagate\" a work means to do anything with it that, without\n"+++    "permission, would make you directly or secondarily liable for\n"+++    "infringement under applicable copyright law, except executing it on a\n"+++    "computer or modifying a private copy.  Propagation includes copying,\n"+++    "distribution (with or without modification), making available to the\n"+++    "public, and in some countries other activities as well.\n"+++    "\n"+++    "  To \"convey\" a work means any kind of propagation that enables other\n"+++    "parties to make or receive copies.  Mere interaction with a user through\n"+++    "a computer network, with no transfer of a copy, is not conveying.\n"+++    "\n"+++    "  An interactive user interface displays \"Appropriate Legal Notices\"\n"+++    "to the extent that it includes a convenient and prominently visible\n"+++    "feature that (1) displays an appropriate copyright notice, and (2)\n"+++    "tells the user that there is no warranty for the work (except to the\n"+++    "extent that warranties are provided), that licensees may convey the\n"+++    "work under this License, and how to view a copy of this License.  If\n"+++    "the interface presents a list of user commands or options, such as a\n"+++    "menu, a prominent item in the list meets this criterion.\n"+++    "\n"+++    "  1. Source Code.\n"+++    "\n"+++    "  The \"source code\" for a work means the preferred form of the work\n"+++    "for making modifications to it.  \"Object code\" means any non-source\n"+++    "form of a work.\n"+++    "\n"+++    "  A \"Standard Interface\" means an interface that either is an official\n"+++    "standard defined by a recognized standards body, or, in the case of\n"+++    "interfaces specified for a particular programming language, one that\n"+++    "is widely used among developers working in that language.\n"+++    "\n"+++    "  The \"System Libraries\" of an executable work include anything, other\n"+++    "than the work as a whole, that (a) is included in the normal form of\n"+++    "packaging a Major Component, but which is not part of that Major\n"+++    "Component, and (b) serves only to enable use of the work with that\n"+++    "Major Component, or to implement a Standard Interface for which an\n"+++    "implementation is available to the public in source code form.  A\n"+++    "\"Major Component\", in this context, means a major essential component\n"+++    "(kernel, window system, and so on) of the specific operating system\n"+++    "(if any) on which the executable work runs, or a compiler used to\n"+++    "produce the work, or an object code interpreter used to run it.\n"+++    "\n"+++    "  The \"Corresponding Source\" for a work in object code form means all\n"+++    "the source code needed to generate, install, and (for an executable\n"+++    "work) run the object code and to modify the work, including scripts to\n"+++    "control those activities.  However, it does not include the work's\n"+++    "System Libraries, or general-purpose tools or generally available free\n"+++    "programs which are used unmodified in performing those activities but\n"+++    "which are not part of the work.  For example, Corresponding Source\n"+++    "includes interface definition files associated with source files for\n"+++    "the work, and the source code for shared libraries and dynamically\n"+++    "linked subprograms that the work is specifically designed to require,\n"+++    "such as by intimate data communication or control flow between those\n"+++    "subprograms and other parts of the work.\n"+++    "\n"+++    "  The Corresponding Source need not include anything that users\n"+++    "can regenerate automatically from other parts of the Corresponding\n"+++    "Source.\n"+++    "\n"+++    "  The Corresponding Source for a work in source code form is that\n"+++    "same work.\n"+++    "\n"+++    "  2. Basic Permissions.\n"+++    "\n"+++    "  All rights granted under this License are granted for the term of\n"+++    "copyright on the Program, and are irrevocable provided the stated\n"+++    "conditions are met.  This License explicitly affirms your unlimited\n"+++    "permission to run the unmodified Program.  The output from running a\n"+++    "covered work is covered by this License only if the output, given its\n"+++    "content, constitutes a covered work.  This License acknowledges your\n"+++    "rights of fair use or other equivalent, as provided by copyright law.\n"+++    "\n"+++    "  You may make, run and propagate covered works that you do not\n"+++    "convey, without conditions so long as your license otherwise remains\n"+++    "in force.  You may convey covered works to others for the sole purpose\n"+++    "of having them make modifications exclusively for you, or provide you\n"+++    "with facilities for running those works, provided that you comply with\n"+++    "the terms of this License in conveying all material for which you do\n"+++    "not control copyright.  Those thus making or running the covered works\n"+++    "for you must do so exclusively on your behalf, under your direction\n"+++    "and control, on terms that prohibit them from making any copies of\n"+++    "your copyrighted material outside their relationship with you.\n"+++    "\n"+++    "  Conveying under any other circumstances is permitted solely under\n"+++    "the conditions stated below.  Sublicensing is not allowed; section 10\n"+++    "makes it unnecessary.\n"+++    "\n"+++    "  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n"+++    "\n"+++    "  No covered work shall be deemed part of an effective technological\n"+++    "measure under any applicable law fulfilling obligations under article\n"+++    "11 of the WIPO copyright treaty adopted on 20 December 1996, or\n"+++    "similar laws prohibiting or restricting circumvention of such\n"+++    "measures.\n"+++    "\n"+++    "  When you convey a covered work, you waive any legal power to forbid\n"+++    "circumvention of technological measures to the extent such circumvention\n"+++    "is effected by exercising rights under this License with respect to\n"+++    "the covered work, and you disclaim any intention to limit operation or\n"+++    "modification of the work as a means of enforcing, against the work's\n"+++    "users, your or third parties' legal rights to forbid circumvention of\n"+++    "technological measures.\n"+++    "\n"+++    "  4. Conveying Verbatim Copies.\n"+++    "\n"+++    "  You may convey verbatim copies of the Program's source code as you\n"+++    "receive it, in any medium, provided that you conspicuously and\n"+++    "appropriately publish on each copy an appropriate copyright notice;\n"+++    "keep intact all notices stating that this License and any\n"+++    "non-permissive terms added in accord with section 7 apply to the code;\n"+++    "keep intact all notices of the absence of any warranty; and give all\n"+++    "recipients a copy of this License along with the Program.\n"+++    "\n"+++    "  You may charge any price or no price for each copy that you convey,\n"+++    "and you may offer support or warranty protection for a fee.\n"+++    "\n"+++    "  5. Conveying Modified Source Versions.\n"+++    "\n"+++    "  You may convey a work based on the Program, or the modifications to\n"+++    "produce it from the Program, in the form of source code under the\n"+++    "terms of section 4, provided that you also meet all of these conditions:\n"+++    "\n"+++    "    a) The work must carry prominent notices stating that you modified\n"+++    "    it, and giving a relevant date.\n"+++    "\n"+++    "    b) The work must carry prominent notices stating that it is\n"+++    "    released under this License and any conditions added under section\n"+++    "    7.  This requirement modifies the requirement in section 4 to\n"+++    "    \"keep intact all notices\".\n"+++    "\n"+++    "    c) You must license the entire work, as a whole, under this\n"+++    "    License to anyone who comes into possession of a copy.  This\n"+++    "    License will therefore apply, along with any applicable section 7\n"+++    "    additional terms, to the whole of the work, and all its parts,\n"+++    "    regardless of how they are packaged.  This License gives no\n"+++    "    permission to license the work in any other way, but it does not\n"+++    "    invalidate such permission if you have separately received it.\n"+++    "\n"+++    "    d) If the work has interactive user interfaces, each must display\n"+++    "    Appropriate Legal Notices; however, if the Program has interactive\n"+++    "    interfaces that do not display Appropriate Legal Notices, your\n"+++    "    work need not make them do so.\n"+++    "\n"+++    "  A compilation of a covered work with other separate and independent\n"+++    "works, which are not by their nature extensions of the covered work,\n"+++    "and which are not combined with it such as to form a larger program,\n"+++    "in or on a volume of a storage or distribution medium, is called an\n"+++    "\"aggregate\" if the compilation and its resulting copyright are not\n"+++    "used to limit the access or legal rights of the compilation's users\n"+++    "beyond what the individual works permit.  Inclusion of a covered work\n"+++    "in an aggregate does not cause this License to apply to the other\n"+++    "parts of the aggregate.\n"+++    "\n"+++    "  6. Conveying Non-Source Forms.\n"+++    "\n"+++    "  You may convey a covered work in object code form under the terms\n"+++    "of sections 4 and 5, provided that you also convey the\n"+++    "machine-readable Corresponding Source under the terms of this License,\n"+++    "in one of these ways:\n"+++    "\n"+++    "    a) Convey the object code in, or embodied in, a physical product\n"+++    "    (including a physical distribution medium), accompanied by the\n"+++    "    Corresponding Source fixed on a durable physical medium\n"+++    "    customarily used for software interchange.\n"+++    "\n"+++    "    b) Convey the object code in, or embodied in, a physical product\n"+++    "    (including a physical distribution medium), accompanied by a\n"+++    "    written offer, valid for at least three years and valid for as\n"+++    "    long as you offer spare parts or customer support for that product\n"+++    "    model, to give anyone who possesses the object code either (1) a\n"+++    "    copy of the Corresponding Source for all the software in the\n"+++    "    product that is covered by this License, on a durable physical\n"+++    "    medium customarily used for software interchange, for a price no\n"+++    "    more than your reasonable cost of physically performing this\n"+++    "    conveying of source, or (2) access to copy the\n"+++    "    Corresponding Source from a network server at no charge.\n"+++    "\n"+++    "    c) Convey individual copies of the object code with a copy of the\n"+++    "    written offer to provide the Corresponding Source.  This\n"+++    "    alternative is allowed only occasionally and noncommercially, and\n"+++    "    only if you received the object code with such an offer, in accord\n"+++    "    with subsection 6b.\n"+++    "\n"+++    "    d) Convey the object code by offering access from a designated\n"+++    "    place (gratis or for a charge), and offer equivalent access to the\n"+++    "    Corresponding Source in the same way through the same place at no\n"+++    "    further charge.  You need not require recipients to copy the\n"+++    "    Corresponding Source along with the object code.  If the place to\n"+++    "    copy the object code is a network server, the Corresponding Source\n"+++    "    may be on a different server (operated by you or a third party)\n"+++    "    that supports equivalent copying facilities, provided you maintain\n"+++    "    clear directions next to the object code saying where to find the\n"+++    "    Corresponding Source.  Regardless of what server hosts the\n"+++    "    Corresponding Source, you remain obligated to ensure that it is\n"+++    "    available for as long as needed to satisfy these requirements.\n"+++    "\n"+++    "    e) Convey the object code using peer-to-peer transmission, provided\n"+++    "    you inform other peers where the object code and Corresponding\n"+++    "    Source of the work are being offered to the general public at no\n"+++    "    charge under subsection 6d.\n"+++    "\n"+++    "  A separable portion of the object code, whose source code is excluded\n"+++    "from the Corresponding Source as a System Library, need not be\n"+++    "included in conveying the object code work.\n"+++    "\n"+++    "  A \"User Product\" is either (1) a \"consumer product\", which means any\n"+++    "tangible personal property which is normally used for personal, family,\n"+++    "or household purposes, or (2) anything designed or sold for incorporation\n"+++    "into a dwelling.  In determining whether a product is a consumer product,\n"+++    "doubtful cases shall be resolved in favor of coverage.  For a particular\n"+++    "product received by a particular user, \"normally used\" refers to a\n"+++    "typical or common use of that class of product, regardless of the status\n"+++    "of the particular user or of the way in which the particular user\n"+++    "actually uses, or expects or is expected to use, the product.  A product\n"+++    "is a consumer product regardless of whether the product has substantial\n"+++    "commercial, industrial or non-consumer uses, unless such uses represent\n"+++    "the only significant mode of use of the product.\n"+++    "\n"+++    "  \"Installation Information\" for a User Product means any methods,\n"+++    "procedures, authorization keys, or other information required to install\n"+++    "and execute modified versions of a covered work in that User Product from\n"+++    "a modified version of its Corresponding Source.  The information must\n"+++    "suffice to ensure that the continued functioning of the modified object\n"+++    "code is in no case prevented or interfered with solely because\n"+++    "modification has been made.\n"+++    "\n"+++    "  If you convey an object code work under this section in, or with, or\n"+++    "specifically for use in, a User Product, and the conveying occurs as\n"+++    "part of a transaction in which the right of possession and use of the\n"+++    "User Product is transferred to the recipient in perpetuity or for a\n"+++    "fixed term (regardless of how the transaction is characterized), the\n"+++    "Corresponding Source conveyed under this section must be accompanied\n"+++    "by the Installation Information.  But this requirement does not apply\n"+++    "if neither you nor any third party retains the ability to install\n"+++    "modified object code on the User Product (for example, the work has\n"+++    "been installed in ROM).\n"+++    "\n"+++    "  The requirement to provide Installation Information does not include a\n"+++    "requirement to continue to provide support service, warranty, or updates\n"+++    "for a work that has been modified or installed by the recipient, or for\n"+++    "the User Product in which it has been modified or installed.  Access to a\n"+++    "network may be denied when the modification itself materially and\n"+++    "adversely affects the operation of the network or violates the rules and\n"+++    "protocols for communication across the network.\n"+++    "\n"+++    "  Corresponding Source conveyed, and Installation Information provided,\n"+++    "in accord with this section must be in a format that is publicly\n"+++    "documented (and with an implementation available to the public in\n"+++    "source code form), and must require no special password or key for\n"+++    "unpacking, reading or copying.\n"+++    "\n"+++    "  7. Additional Terms.\n"+++    "\n"+++    "  \"Additional permissions\" are terms that supplement the terms of this\n"+++    "License by making exceptions from one or more of its conditions.\n"+++    "Additional permissions that are applicable to the entire Program shall\n"+++    "be treated as though they were included in this License, to the extent\n"+++    "that they are valid under applicable law.  If additional permissions\n"+++    "apply only to part of the Program, that part may be used separately\n"+++    "under those permissions, but the entire Program remains governed by\n"+++    "this License without regard to the additional permissions.\n"+++    "\n"+++    "  When you convey a copy of a covered work, you may at your option\n"+++    "remove any additional permissions from that copy, or from any part of\n"+++    "it.  (Additional permissions may be written to require their own\n"+++    "removal in certain cases when you modify the work.)  You may place\n"+++    "additional permissions on material, added by you to a covered work,\n"+++    "for which you have or can give appropriate copyright permission.\n"+++    "\n"+++    "  Notwithstanding any other provision of this License, for material you\n"+++    "add to a covered work, you may (if authorized by the copyright holders of\n"+++    "that material) supplement the terms of this License with terms:\n"+++    "\n"+++    "    a) Disclaiming warranty or limiting liability differently from the\n"+++    "    terms of sections 15 and 16 of this License; or\n"+++    "\n"+++    "    b) Requiring preservation of specified reasonable legal notices or\n"+++    "    author attributions in that material or in the Appropriate Legal\n"+++    "    Notices displayed by works containing it; or\n"+++    "\n"+++    "    c) Prohibiting misrepresentation of the origin of that material, or\n"+++    "    requiring that modified versions of such material be marked in\n"+++    "    reasonable ways as different from the original version; or\n"+++    "\n"+++    "    d) Limiting the use for publicity purposes of names of licensors or\n"+++    "    authors of the material; or\n"+++    "\n"+++    "    e) Declining to grant rights under trademark law for use of some\n"+++    "    trade names, trademarks, or service marks; or\n"+++    "\n"+++    "    f) Requiring indemnification of licensors and authors of that\n"+++    "    material by anyone who conveys the material (or modified versions of\n"+++    "    it) with contractual assumptions of liability to the recipient, for\n"+++    "    any liability that these contractual assumptions directly impose on\n"+++    "    those licensors and authors.\n"+++    "\n"+++    "  All other non-permissive additional terms are considered \"further\n"+++    "restrictions\" within the meaning of section 10.  If the Program as you\n"+++    "received it, or any part of it, contains a notice stating that it is\n"+++    "governed by this License along with a term that is a further\n"+++    "restriction, you may remove that term.  If a license document contains\n"+++    "a further restriction but permits relicensing or conveying under this\n"+++    "License, you may add to a covered work material governed by the terms\n"+++    "of that license document, provided that the further restriction does\n"+++    "not survive such relicensing or conveying.\n"+++    "\n"+++    "  If you add terms to a covered work in accord with this section, you\n"+++    "must place, in the relevant source files, a statement of the\n"+++    "additional terms that apply to those files, or a notice indicating\n"+++    "where to find the applicable terms.\n"+++    "\n"+++    "  Additional terms, permissive or non-permissive, may be stated in the\n"+++    "form of a separately written license, or stated as exceptions;\n"+++    "the above requirements apply either way.\n"+++    "\n"+++    "  8. Termination.\n"+++    "\n"+++    "  You may not propagate or modify a covered work except as expressly\n"+++    "provided under this License.  Any attempt otherwise to propagate or\n"+++    "modify it is void, and will automatically terminate your rights under\n"+++    "this License (including any patent licenses granted under the third\n"+++    "paragraph of section 11).\n"+++    "\n"+++    "  However, if you cease all violation of this License, then your\n"+++    "license from a particular copyright holder is reinstated (a)\n"+++    "provisionally, unless and until the copyright holder explicitly and\n"+++    "finally terminates your license, and (b) permanently, if the copyright\n"+++    "holder fails to notify you of the violation by some reasonable means\n"+++    "prior to 60 days after the cessation.\n"+++    "\n"+++    "  Moreover, your license from a particular copyright holder is\n"+++    "reinstated permanently if the copyright holder notifies you of the\n"+++    "violation by some reasonable means, this is the first time you have\n"+++    "received notice of violation of this License (for any work) from that\n"+++    "copyright holder, and you cure the violation prior to 30 days after\n"+++    "your receipt of the notice.\n"+++    "\n"+++    "  Termination of your rights under this section does not terminate the\n"+++    "licenses of parties who have received copies or rights from you under\n"+++    "this License.  If your rights have been terminated and not permanently\n"+++    "reinstated, you do not qualify to receive new licenses for the same\n"+++    "material under section 10.\n"+++    "\n"+++    "  9. Acceptance Not Required for Having Copies.\n"+++    "\n"+++    "  You are not required to accept this License in order to receive or\n"+++    "run a copy of the Program.  Ancillary propagation of a covered work\n"+++    "occurring solely as a consequence of using peer-to-peer transmission\n"+++    "to receive a copy likewise does not require acceptance.  However,\n"+++    "nothing other than this License grants you permission to propagate or\n"+++    "modify any covered work.  These actions infringe copyright if you do\n"+++    "not accept this License.  Therefore, by modifying or propagating a\n"+++    "covered work, you indicate your acceptance of this License to do so.\n"+++    "\n"+++    "  10. Automatic Licensing of Downstream Recipients.\n"+++    "\n"+++    "  Each time you convey a covered work, the recipient automatically\n"+++    "receives a license from the original licensors, to run, modify and\n"+++    "propagate that work, subject to this License.  You are not responsible\n"+++    "for enforcing compliance by third parties with this License.\n"+++    "\n"+++    "  An \"entity transaction\" is a transaction transferring control of an\n"+++    "organization, or substantially all assets of one, or subdividing an\n"+++    "organization, or merging organizations.  If propagation of a covered\n"+++    "work results from an entity transaction, each party to that\n"+++    "transaction who receives a copy of the work also receives whatever\n"+++    "licenses to the work the party's predecessor in interest had or could\n"+++    "give under the previous paragraph, plus a right to possession of the\n"+++    "Corresponding Source of the work from the predecessor in interest, if\n"+++    "the predecessor has it or can get it with reasonable efforts.\n"+++    "\n"+++    "  You may not impose any further restrictions on the exercise of the\n"+++    "rights granted or affirmed under this License.  For example, you may\n"+++    "not impose a license fee, royalty, or other charge for exercise of\n"+++    "rights granted under this License, and you may not initiate litigation\n"+++    "(including a cross-claim or counterclaim in a lawsuit) alleging that\n"+++    "any patent claim is infringed by making, using, selling, offering for\n"+++    "sale, or importing the Program or any portion of it.\n"+++    "\n"+++    "  11. Patents.\n"+++    "\n"+++    "  A \"contributor\" is a copyright holder who authorizes use under this\n"+++    "License of the Program or a work on which the Program is based.  The\n"+++    "work thus licensed is called the contributor's \"contributor version\".\n"+++    "\n"+++    "  A contributor's \"essential patent claims\" are all patent claims\n"+++    "owned or controlled by the contributor, whether already acquired or\n"+++    "hereafter acquired, that would be infringed by some manner, permitted\n"+++    "by this License, of making, using, or selling its contributor version,\n"+++    "but do not include claims that would be infringed only as a\n"+++    "consequence of further modification of the contributor version.  For\n"+++    "purposes of this definition, \"control\" includes the right to grant\n"+++    "patent sublicenses in a manner consistent with the requirements of\n"+++    "this License.\n"+++    "\n"+++    "  Each contributor grants you a non-exclusive, worldwide, royalty-free\n"+++    "patent license under the contributor's essential patent claims, to\n"+++    "make, use, sell, offer for sale, import and otherwise run, modify and\n"+++    "propagate the contents of its contributor version.\n"+++    "\n"+++    "  In the following three paragraphs, a \"patent license\" is any express\n"+++    "agreement or commitment, however denominated, not to enforce a patent\n"+++    "(such as an express permission to practice a patent or covenant not to\n"+++    "sue for patent infringement).  To \"grant\" such a patent license to a\n"+++    "party means to make such an agreement or commitment not to enforce a\n"+++    "patent against the party.\n"+++    "\n"+++    "  If you convey a covered work, knowingly relying on a patent license,\n"+++    "and the Corresponding Source of the work is not available for anyone\n"+++    "to copy, free of charge and under the terms of this License, through a\n"+++    "publicly available network server or other readily accessible means,\n"+++    "then you must either (1) cause the Corresponding Source to be so\n"+++    "available, or (2) arrange to deprive yourself of the benefit of the\n"+++    "patent license for this particular work, or (3) arrange, in a manner\n"+++    "consistent with the requirements of this License, to extend the patent\n"+++    "license to downstream recipients.  \"Knowingly relying\" means you have\n"+++    "actual knowledge that, but for the patent license, your conveying the\n"+++    "covered work in a country, or your recipient's use of the covered work\n"+++    "in a country, would infringe one or more identifiable patents in that\n"+++    "country that you have reason to believe are valid.\n"+++    "\n"+++    "  If, pursuant to or in connection with a single transaction or\n"+++    "arrangement, you convey, or propagate by procuring conveyance of, a\n"+++    "covered work, and grant a patent license to some of the parties\n"+++    "receiving the covered work authorizing them to use, propagate, modify\n"+++    "or convey a specific copy of the covered work, then the patent license\n"+++    "you grant is automatically extended to all recipients of the covered\n"+++    "work and works based on it.\n"+++    "\n"+++    "  A patent license is \"discriminatory\" if it does not include within\n"+++    "the scope of its coverage, prohibits the exercise of, or is\n"+++    "conditioned on the non-exercise of one or more of the rights that are\n"+++    "specifically granted under this License.  You may not convey a covered\n"+++    "work if you are a party to an arrangement with a third party that is\n"+++    "in the business of distributing software, under which you make payment\n"+++    "to the third party based on the extent of your activity of conveying\n"+++    "the work, and under which the third party grants, to any of the\n"+++    "parties who would receive the covered work from you, a discriminatory\n"+++    "patent license (a) in connection with copies of the covered work\n"+++    "conveyed by you (or copies made from those copies), or (b) primarily\n"+++    "for and in connection with specific products or compilations that\n"+++    "contain the covered work, unless you entered into that arrangement,\n"+++    "or that patent license was granted, prior to 28 March 2007.\n"+++    "\n"+++    "  Nothing in this License shall be construed as excluding or limiting\n"+++    "any implied license or other defenses to infringement that may\n"+++    "otherwise be available to you under applicable patent law.\n"+++    "\n"+++    "  12. No Surrender of Others' Freedom.\n"+++    "\n"+++    "  If conditions are imposed on you (whether by court order, agreement or\n"+++    "otherwise) that contradict the conditions of this License, they do not\n"+++    "excuse you from the conditions of this License.  If you cannot convey a\n"+++    "covered work so as to satisfy simultaneously your obligations under this\n"+++    "License and any other pertinent obligations, then as a consequence you may\n"+++    "not convey it at all.  For example, if you agree to terms that obligate you\n"+++    "to collect a royalty for further conveying from those to whom you convey\n"+++    "the Program, the only way you could satisfy both those terms and this\n"+++    "License would be to refrain entirely from conveying the Program.\n"+++    "\n"+++    "  13. Use with the GNU Affero General Public License.\n"+++    "\n"+++    "  Notwithstanding any other provision of this License, you have\n"+++    "permission to link or combine any covered work with a work licensed\n"+++    "under version 3 of the GNU Affero General Public License into a single\n"+++    "combined work, and to convey the resulting work.  The terms of this\n"+++    "License will continue to apply to the part which is the covered work,\n"+++    "but the special requirements of the GNU Affero General Public License,\n"+++    "section 13, concerning interaction through a network will apply to the\n"+++    "combination as such.\n"+++    "\n"+++    "  14. Revised Versions of this License.\n"+++    "\n"+++    "  The Free Software Foundation may publish revised and/or new versions of\n"+++    "the GNU General Public License from time to time.  Such new versions will\n"+++    "be similar in spirit to the present version, but may differ in detail to\n"+++    "address new problems or concerns.\n"+++    "\n"+++    "  Each version is given a distinguishing version number.  If the\n"+++    "Program specifies that a certain numbered version of the GNU General\n"+++    "Public License \"or any later version\" applies to it, you have the\n"+++    "option of following the terms and conditions either of that numbered\n"+++    "version or of any later version published by the Free Software\n"+++    "Foundation.  If the Program does not specify a version number of the\n"+++    "GNU General Public License, you may choose any version ever published\n"+++    "by the Free Software Foundation.\n"+++    "\n"+++    "  If the Program specifies that a proxy can decide which future\n"+++    "versions of the GNU General Public License can be used, that proxy's\n"+++    "public statement of acceptance of a version permanently authorizes you\n"+++    "to choose that version for the Program.\n"+++    "\n"+++    "  Later license versions may give you additional or different\n"+++    "permissions.  However, no additional obligations are imposed on any\n"+++    "author or copyright holder as a result of your choosing to follow a\n"+++    "later version.\n"+++    "\n"+++    "  15. Disclaimer of Warranty.\n"+++    "\n"+++    "  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\n"+++    "APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\n"+++    "HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\n"+++    "OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\n"+++    "THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n"+++    "PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\n"+++    "IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\n"+++    "ALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n"+++    "\n"+++    "  16. Limitation of Liability.\n"+++    "\n"+++    "  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\n"+++    "WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\n"+++    "THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\n"+++    "GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\n"+++    "USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\n"+++    "DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\n"+++    "PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\n"+++    "EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\n"+++    "SUCH DAMAGES.\n"+++    "\n"+++    "  17. Interpretation of Sections 15 and 16.\n"+++    "\n"+++    "  If the disclaimer of warranty and limitation of liability provided\n"+++    "above cannot be given local legal effect according to their terms,\n"+++    "reviewing courts shall apply local law that most closely approximates\n"+++    "an absolute waiver of all civil liability in connection with the\n"+++    "Program, unless a warranty or assumption of liability accompanies a\n"+++    "copy of the Program in return for a fee.\n"+++    "\n"+++    "                     END OF TERMS AND CONDITIONS\n"+++    "\n"+++    "            How to Apply These Terms to Your New Programs\n"+++    "\n"+++    "  If you develop a new program, and you want it to be of the greatest\n"+++    "possible use to the public, the best way to achieve this is to make it\n"+++    "free software which everyone can redistribute and change under these terms.\n"+++    "\n"+++    "  To do so, attach the following notices to the program.  It is safest\n"+++    "to attach them to the start of each source file to most effectively\n"+++    "state the exclusion of warranty; and each file should have at least\n"+++    "the \"copyright\" line and a pointer to where the full notice is found.\n"+++    "\n"+++    "    <one line to give the program's name and a brief idea of what it does.>\n"+++    "    Copyright (C) <year>  <name of author>\n"+++    "\n"+++    "    This program is free software: you can redistribute it and/or modify\n"+++    "    it under the terms of the GNU General Public License as published by\n"+++    "    the Free Software Foundation, either version 3 of the License, or\n"+++    "    (at your option) any later version.\n"+++    "\n"+++    "    This program is distributed in the hope that it will be useful,\n"+++    "    but WITHOUT ANY WARRANTY; without even the implied warranty of\n"+++    "    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"+++    "    GNU General Public License for more details.\n"+++    "\n"+++    "    You should have received a copy of the GNU General Public License\n"+++    "    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n"+++    "\n"+++    "Also add information on how to contact you by electronic and paper mail.\n"+++    "\n"+++    "  If the program does terminal interaction, make it output a short\n"+++    "notice like this when it starts in an interactive mode:\n"+++    "\n"+++    "    <program>  Copyright (C) <year>  <name of author>\n"+++    "    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n"+++    "    This is free software, and you are welcome to redistribute it\n"+++    "    under certain conditions; type `show c' for details.\n"+++    "\n"+++    "The hypothetical commands `show w' and `show c' should show the appropriate\n"+++    "parts of the General Public License.  Of course, your program's commands\n"+++    "might be different; for a GUI interface, you would use an \"about box\".\n"+++    "\n"+++    "  You should also get your employer (if you work as a programmer) or school,\n"+++    "if any, to sign a \"copyright disclaimer\" for the program, if necessary.\n"+++    "For more information on this, and how to apply and follow the GNU GPL, see\n"+++    "<http://www.gnu.org/licenses/>.\n"+++    "\n"+++    "  The GNU General Public License does not permit incorporating your program\n"+++    "into proprietary programs.  If your program is a subroutine library, you\n"+++    "may consider it more useful to permit linking proprietary applications with\n"+++    "the library.  If this is what you want to do, use the GNU Lesser General\n"+++    "Public License instead of this License.  But first, please read\n"+++    "<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
+ src/Main.hs view
@@ -0,0 +1,679 @@+{- | SciDB is a column-oriented database management system (DBMS)+designed for multidimensional data management and analytics common to+scientific, geospatial, industrial, and financial applications.  See+<http://www.paradigm4.com/> and <http://www.paradigm4.com/forum> for+more information about the Data Management and Analytics Software+System (DMAS) known as SciDB.++The documenation of 'main' is the manual page for 'hquery', a Haskell+command line and interactive interpreter for SciDB AFL queries via+shim.  See also++  * 'hquery' @-y@,+  * 'hquery' @-h@, or+  * 'hquery' @-m@++for more information++There is a primitive API derived after the creation of 'hquery'+defined by the following data structures and actions:++  * 'Environment'+  * 'Err'+  * 'mkGlobalManagerEnv'+  * 'runQueries'+  * 'unsafeRunQuery'+  * 'getSciDbVersion'+-}++module Main (main) where+++-- Section: imports+import qualified Network.HTTP.Client    as HTTP (Request(..))++import Environment           (Environment(..),defaultEnv,maybePort,Verbosity(..))+import ErrM                  (Err(..))+import HQuery                (hquery,getSciDbVersion,mkGlobalManagerEnv+                             -- Below is added for Haddock documentation+                             ,runQueries,unsafeRunQuery)+import License               (putLicense)+import Manual                (putManual)+import Utils                 (dot,wrap,cleanDoubleQuotes,checkMajorVersion,stripUsing)+import UtilsUnsafe           (valid,VALID(..),fetchUsername,fetchPassword+                             ,isConnectable,managerSettings,base64Sha512Hash)++import Control.Exception     (try)+import Control.Monad         (unless,when)+import Data.Char             (toLower)+import Data.List             (intercalate)+import Data.Maybe            (fromMaybe,isJust,fromJust)+import Network.HTTP.Client   (HttpException(..))+import Safe                  (readMay)+import System.Console.GetOpt (ArgDescr(..),OptDescr(..),ArgOrder(..),usageInfo,getOpt)+import System.Directory      (getCurrentDirectory)+import System.Environment    (getEnvironment,getProgName,getArgs)+import System.Exit           (exitSuccess,exitWith,ExitCode(..))+import System.FilePath       (takeFileName,pathSeparator)+import System.IO             (stderr,stdout,hPutStrLn,Handle(..))++-- Section: main+{- |+The Haskell command line and interactive interpreter manual page+for 'hquery':++> hquery(1)                    User Command                   hquery(1)+> +> NAME+>    hquery - Haskell query for SciDB via shim+> +> SYNOPSIS+>    hquery [-V n] [-t hstfile] [-c certstore] [-n]+>              [-r http[s]] [-i host] [-p port] [-a true|false]+>                [-e true|false] [-o fmt] [-b num] [-d|-s] [-u usr] [-w pw]+>                  [-f qyfile] [query...]+>    hquery -g+>    hquery -h+>    hquery -l+>    hquery -m+>    hquery -v+>    hquery -y+> +> AVAILABILITY+>    Marcus D. Gabriel.  All rights reserved 2014-19(c).+> +>    marcus@gabriel.name+> +>    License terms: GNU GPL version 3 (hquery -l)+> +> DESCRIPTION+>    The command hquery with no operands and no options will begin an+>    interacitve session with a SciDB server using SciDB's shim+>    protocol at http://localhost:8080.+> +>    With operands, each string will be executed as a SciDB AFL (Array+>    Functional Language) query returning a result in SciDB DCSV+>    format and fetching only 23 lines per query by default.  If+>    stdin is non-empty, it will be execute before the operands.+>    SciDB AFL queries are case insensitive and terminated by+>    semi-colons (;).+> +>    Before submitting a query to the shim server, the command+>    hquery will+>      1. return syntax and parsing errors+>      2. report bad nestings, e.g., 'uniq(store(A,B));'+>      3. report unknown commands, ignoring them+> +>    Additionally, the command hquery reports SciDB/shim server+>    query exceptions without terminating the process.+> +>    The command hquery accepts Haskell sytle comments and accepts+>    the setting of the following following global variables:+> +>      -- Number of lines to fetch+>      n=Integer;+>      -- Format of the output+>      format={'csv'|'csv+'|'dcsv'|'dense'|'sparse'|'opaque'+>             |'store'|'text'|'tsv'|'tsv+'};+>      -- True to fetch data, false to not fetch data+>      fetch={true|false};+>      -- True to read lines, false to read bytes+>      readinglines={true|false};+>      -- Prefix to execute before a query by shim, e.g.,+>      prefix='a_query(\'a_string\');'+> +>    Prefix is an optional, semi-colon separated, AFL statements+>    to precede a query in the same SciDB connection context.+>    It is mainly used for SciDB namespace and role  setting.+>    There is no terminating semi-colon so trailing semi-colons+>    are removed otherwise the prefix is sent to  shim unverified+>    and unaltered via the variable 'prefix'.+> +>    The command 'quit;' or 'exit;' ends the interactive session+>    with exit status 0.  The command "vars;" displays the interpreter+>    variables and values, and the command "funs;" displays the+>    currently defined interpreter functions and definitions: exit,+>    funs, quit, upload, and vars.+> +>    The upload command takes one argument, a local file path+>    string, and returns a shim server-side file path.  It is used+>    in queries such as load, input, load_module that take a shim+>    server-side file path. Examples are+> +>      load(m4x4_missing,+>        upload('/home/scidb/scidb/m4x4_missing.scidb'));+> +>      input(m4x4_missing,+>        upload('/home/scidb/scidb/m4x4_missing.scidb'));+> +>      load_module(upload('/home/scidb/scidb/module_1.txt'));+> +>      join(input(m4x4,upload('/tmp/a\\'y\\'b.txt')),+>        input(m4x4,upload('/tmp/z.txt')));+> +>    All of the above is case insensitive and terminated with a+>    semi-colon (;).+> +> INTERACTIVE SESSION+>    Multi-line queries are supported interactively as they+>    are in non-interactive execution.  Ctrl-D at a new prompt+>    ends the interactive session.  Ctrl-C returns to the+>    interactive prompt, used to end input, especially+>    multi-line input.+> +>    The default prompt is 'True/dcsv/23?', for example,+> +>      True/dcsv/23? list('arrays');+> +>    which displays up to 23 lines of arrays, that is,+> +>      Fetch/Format/NumberOfLines?+> +>    You can change the global variables 'n', 'format', 'fetch',+>    'readinglines', and 'prefix' during execution which changes+>    the prompt:+> +>      True/dcsv/23? n=200;              -- Fetch 200 lines+>      True/dcsv/200? n=0;               -- Fetch all lines+>      True/dcsv/0? format='csv';        -- Set format to csv+>      True/csv/0? fetch=false;          -- Fetch no lines regardless+>                                        -- the value of n+>      False/csv/0? fetch=true;format=dcsv;n=23;+>      True/dcsv/23? readinglines=false; -- Fetch all bytes regardless+>                                        -- the value of n+>      Bytes/dcsv/23? prefix='set_namespace(\'sensor_data\');';+>      Bytes/dcsv/23p list('arrays');    -- List sensor_data arrays+>      Bytes/dcsv/23p quit;+> +>    In other words, the prompt indicates the default behaviour for+>    the next query executed.+> +> OPTIONS+>    The following options are supported:+> +>    -a True|false, true to read lines, false to read bytes+>       (--reading-lines).  If false, the number of lines to+>       fetch (-b) is ignored and the entire output buffer is+>       downloaded.  This follows the recommendataion of the+>       shim documentation.+> +>    -b Number, number of lines to fetch (--number).+> +>    -c Certificate store file, a certificate store to load and use+>       for SSL/TLS connections (--certificate-store). The insecure+>       option (-n) over-rides the certificate store (-c).+> +>    -d Use basic digest access authorization, used by either the+>       http and https protocols (--digest-authorization).  Digest+>       authorization (-d) over-rides SciDB authorization (-s).+> +>    -e True|false, true to fetch lines, false to not fetch lines+>       (--fetch).+> +>    -f Query file, a readable file of queries.  Multi-line queries+>       are supported in a file (--file).  If stdin is non-empty,+>       it is executed before the file of queries.  If operands are+>       present, they are executed after the file of queries.+> +>    -g Get and display the SciDB version via shim and then exit+>       (--scidb-version).  This performs a simple check for shim +>       and SciDB availability.+> +>    -h Display a short hquery summary (--help).+> +>    -i IP address or hostname, default localhost (--host).+> +>    -l Display the hquery license terms (--license).+> +>    -m Display this internal manual page (--manual).+> +>    -n Do not use certificate validation, insecure because+>       of potential man-in-the-middle attacks (--insecure).+>       The insecure option (-n) over-rides the certificate+>       store (-c).+> +>    -o Format, ouput format such as dcsv, csv, csv+, tsv, tsv+,+>       etc (--format).+> +>    -p Port number, default 8080 for protocol (-r) http and default+>       8083 for protocol (-r) https (--port).+> +>    -r Protocol, e.g., http or https, default http (--protocol).+>       If the protocol is http, the certificate store (-c) and+>       insecure (-n) options are disabled.+> +>    -s Use SciDB access authorization, requires the https protocol+>       (--scidb-authorization).  This option sets the https protocol+>       except when digest authorization (-d) over-rides SciDB+>       authorization (-s).+> +>    -t History file, defualt ~/.hquery_history or /tmp/.hquery_history+>       if ~ does not exist (--history).+> +>    -u Username, defualt null (--username).  Used by the digest or+>       SciDB authorization option (-d or -s).  Displays an error+>       and exits if neither is used with digest or SciDB+>       authorization.+> +>    -v The version of hquery (--version).+> +>    -w Password, default null (--password).  Used by the digest or+>       SciDB authorization option (-d or -s).  Displays an error+>       and exits if neither is used with digest or SciDB+>       authorization.+> +>    -y A synopsis of the internal manual page (--synopsis).+> +>    -x Prefix, a prefix to execute before a query by shim+>       (--prefix).  Note that the prefix on the command line+>       is verified before being sent to shim.  Prefix is a+>       semi-colon separated set of statements.  It is mainly+>       used for SciDB namespace and role setting.  There is no+>       terminating semi-colon so trailing semi-colons are removed.+> +>    -V Same as -V1 (--verbose).+>   -V0 Quiet.  No information is sent to stderr (--verbose=0).+>   -V1 Shows some HTTP exceptions and trace information (--verbose=1).+>   -V2 Shows additional URL information (--verbose=2).+> +> OPERANDS+>    SciDB AFL queries.+> +> USAGE NOTES+>    The development of the utility hquery began with SciDB community+>    edition 13 and continued with 14, 15, 16, 18, and 19.+> +>    This version of hquery has been lightly tested with ghc+>    version 8.2.2 and 8.6.5 and SciDB 18.1 and 19.3 community edition.+>    Currently the command hquery has never been tested on a SciDB+>    enterprise >    edition, and thus it is not known if SciDB+>    authorization (-s) or prefix (-x) actually works.+> +> EXAMPLES+>    To list all currently defined arrays with SciDB authorization required,+>    use+> +>      hquery -i coordinator -s -u ScidB -w SciDBPassword \+>          "n=0; list('arrays');"+> +>    To list up to 100 lines of functions with digest authorization required,+>    use+> +>      hquery -i coordinator -d -u Digest -w DigestPassword \+>          "n=100; list('arrays');"+> +>    To list up to 23 lines of operators, 23 being the default, use+> +>      hquery -i coordinator "list('operators');"+> +>    To list all functions by reading bytes instead of lines, use+> +>      hquery -i coordinator -a false "list('functions');"+> +>   To create an array A, use+> +>      hquery -i coordinator "create array A <x:double> [i=0:99:0:10];"+> +>    To execute the file of queries HQTests.qy with no authorization required+>    via a TLS connection, use+> +>      hquery -c ssl_cert.pem  -r https -i coordinator -f HQTest.qy+> +>    To execute the file of queries HQTests.qy with digest authorization+>    required via a TLS connection insecurely, use+> +>      hquery -n -r https -i coordinator -d -u Digest -w DigestPassword \+>          -f HQTests.qy+> +>    To list all arrays in the sensor_data namespace, use+> +>      hquery -i coordinator -b 0 -x "set_namespace('sensor_data');" \+>          "list('arrays');"+> +>    To display a synopsis of this internal manual page, use+> +>      hquery -y+> +>    To display a summary of usage, use+> +>      hquery -h+> +>    To display this internal manual page, use+> +>      hquery -m+> +> ENVIRONMENT VARIABLES+>    HOME   Home directory for the history file, by defualt+>           ~/.hquery_history.+> +>    PAGER  Page the internal manual page or license terms+>           using "${PAGER}", otherwise print it.+> +> EXIT STATUS+>    An exit status of 0 is returned if successful, otherwise non-zero+>    is returned.+> +>      EXIT CODE    MEANING+>          1        Unknown error.+>          2        No authorization specified (-s|-d) with username/password.+>          3        Invalid protocol, hostname, port, or history file option.+>          4        Cannot connect to hostname:port.+>          5        Unreadable query file.+>          6        Unreadable certicate store file.+>          7        Invalid certificate store.+>          8        Network/certificate manager initialization error.+>          9        Empty, bad or no digest authentication.+>         10        Unauthorized access.+>         11        Could not connect to SciDB.+>         12        Input syntax error for a SciDB query.+>         13        Fetch (-e) or reading-lines (-a) not true or false.+>         14        Bad command-line prefix (-x).+>    15..255        Unknown error.+> +> FILES+>    ~/.hquery_history+> +> SEE ALSO+>    SciDB, SciDB iquery, SciDB shim at https://www.paradigm4.com/ +>    and https://www.paradigm4.com/forum for more information.+> +> NOTES+>    Please send bug reports to https://github.com/mdgabriel/scidb-hquery/issues.+> +> BUGS+>    No known bugs to date.+-}+main :: IO ()+main =+  do cmdLine  <- getArgs+     progName <- getProgName+     case getOpt (argOrder config) options cmdLine of+       (opts, args, []) -> runCmd $ foldl updateEnvField env opts+           where env = defaultEnv{command=takeFileName progName,operands=args}+       (_, _, errs) -> error $ concat errs ++ usageInfo (header progName) options+++-- Section: summary, help, version+{- |+Given the programe name, returns the program name and the release+version.+-}+versionHeader :: String -> String+versionHeader progName = takeFileName progName ++ " release " ++ release config++{- |+Given the program name, returns a synopis of options.+-}+header :: String -> String+header progName = versionHeader (takeFileName progName) +++                  "\nUsage: " ++ takeFileName progName ++ flagsOps config++{- |+Puts the program name and its version.+-}+putVersion :: IO ()+putVersion = do progName <- getProgName+                putStrLn (versionHeader progName)+                exitSuccess++{- |+Puts the program name and the synopsis of options to handle (stdout or+stderr) with the supplied the exit code.+-}+putSynopsis :: Handle -> String -> ExitCode -> IO ()+putSynopsis h s e = do progName <- getProgName+                       hPutStrLn h (takeFileName progName ++ ": " ++ s ++ header progName)+                       exitWith e++{- |+Puts the program name and a short summary.+-}+putSummary :: IO ()+putSummary = do progName <- getProgName+                putStrLn (usageInfo (header progName) options)+                exitSuccess+++-- Section: configuration+{- |+Configuration information is initial, constant information, that is,+not needing updates.+-}+data Configuration =+    Config {+            argOrder       :: ArgOrder Flag,+            release        :: String,+            flagsOps       :: String+           }++{- |+To be configured once with the versions number and synopsis.  Other+items may of course be added to the configuration as needed.+-}+config :: Configuration+config =+    Config {+            argOrder       = RequireOrder,+            -- Update revision number: TOGGLE CASE+            release        = "2.8.0.432",+            flagsOps       = " [[-g|-h|-l|-m|-v|-y] |"+++                             "\n                 [-V n] [-t hstfile] [-c certstore] [-n]"+++                             "\n                   [-r http[s]] [-i host] [-p port] [-a true|false]"+++                             "\n                     [-e true|false] [-o fmt] [-b num] [-d|-s] [-u usr] [-w pw]"+++                             "\n                       [-f qyfile] [query...]"+++                             "\n              ]"+           }+    where+    revision =+        let num = flip elem ['0'..'9']+        in  reverse.dropWhile (not.num).reverse.dropWhile (not.num)+++-- Section: options+{- |+Flags set as a function of the command line options supplied.+-}+data Flag = Help | License | Manual | Synopsis | Version | Verbose Verbosity+          | Host String | Port String | Protocol String | File FilePath+          | History String | Username String | Password String+          | Fetch String | Format String | Number String | VersionSciDb+          | DigestAuth | SciDbAuth | CertStore String | Insecure+          | ReadingLines String | Prefix String++{- |+Options that can be given on the command line.+-}+options :: [OptDescr Flag]+options =+    [ Option "a" ["reading-lines"](ReqArg ReadingLines "TRUE|FALSE") "Reading lines: true lines or false bytes."+    , Option "b" ["number"]   (ReqArg Number "NUMBER")     "Number of lines to fetch when possible."+    , Option "c" ["certificate-store"] (ReqArg CertStore "CERTSTORE") "Load and use certificate store."+    , Option "d" ["digest-authorization"] (NoArg DigestAuth) "Use basic digest authorization."+    , Option "e" ["fetch"]    (ReqArg Fetch "TRUE|FALSE")  "Fetch lines: true or false."+    , Option "f" ["file"]     (ReqArg File "FILE")         "File of queries FILE."+    , Option "g" ["scidb-version"] (NoArg VersionSciDb)    "Get and display the SciDB version via shim."+    , Option "h" ["help"]     (NoArg Help)                 "Help summary."+    , Option "i" ["host"]     (ReqArg Host "HOSTNAME")     "Hostname or IP address HOSTNAME."+    , Option "l" ["license"]  (NoArg License)              "License terms."+    , Option "m" ["manual"]   (NoArg Manual)               "Manual page."+    , Option "n" ["insecure"] (NoArg Insecure)             "Do not use certificate validation (\"insecure\")."+    , Option "o" ["format"]   (ReqArg Format "FORMAT")     "Format dcsv, csv, csv+, tsv, tsv+, etc."+    , Option "p" ["port"]     (ReqArg Port "PORT")         "Port number PORT."+    , Option "r" ["protocol"] (ReqArg Protocol "PROTOCOL") "Protocol HTTP or HTTPS."+    , Option "s" ["scidb-authorization"] (NoArg SciDbAuth) "Use SciDB authorization."+    , Option "t" ["history"]  (ReqArg History "HISTORY")   "History file HISTORY."+    , Option "u" ["username"] (ReqArg Username "USERNAME") "Username USERNAME."+    , Option "v" ["version"]  (NoArg Version)              "Version of this command."+    , Option "w" ["password"] (ReqArg Password "PASSWORD") "Password PASWORD."+    , Option "y" ["synopsis"] (NoArg Synopsis)             "Help synopsis."+    , Option "x" ["prefix"]   (ReqArg Prefix "PREFIX")     "Prefix to execute before a query by shim."+    , Option "V" ["verbose"]  (OptArg inpver "012")        "Verbose information to stderr."+    ]+    where inpver :: Maybe String -> Flag+          inpver ms = Verbose $ case (fromMaybe (-1) . readMay . fromMaybe "1") ms of+                                  0 -> Verbose0+                                  1 -> Verbose1+                                  2 -> Verbose2+                                  _ -> VerboseDef++-- Section: updating a field in the environment+{- |+Every option, and only an option, must be able to be updated here.+-}+updateEnvField :: Environment -> Flag -> Environment+updateEnvField env opt =+    case opt of+      Host s     -> env{host      =      s}+      Port s     -> env{port      = Just s}+      Protocol s -> env{protocol  =      s}+      CertStore s-> env{certStore =      s}+      Insecure   -> env{insecure  =   True}+      DigestAuth -> env{digestAuth=   True}+      SciDbAuth  -> env{scidbAuth =   True}+      Fetch s    -> env{defFetch  = tOrF s}+      ReadingLines s->env{defReadingLines=tOrF s}+      Prefix s   -> env{defPrefix =xsemi s}+      Format s   -> env{defFormat =      s}+      Number s   -> env{defNumber =      s}+      Username s -> env{username  =      s}+      Password s -> env{password  =      s}+      History s  -> env{history   =      s}+      File s     -> env{file      =      s}+      Help       -> env{help      =   True}+      License    -> env{license   =   True}+      Manual     -> env{manual    =   True}+      Synopsis   -> env{synopsis  =   True}+      Version    -> env{version   =   True}+      VersionSciDb->env{versionSciDb= True}+      Verbose v  -> env{verbose   =      v}+    where tOrF s = case fmap toLower s of+                     "true"  -> Just True+                     "false" -> Just False+                     _       -> Nothing+          xsemi  = stripUsing (==';') +--    _          -> error (command env ++ ": updateEnvField: unknown error")++-- Section: running the command given the environment+{- |+Update the environment with updateEnv, verify the environment with+verifyEnv, resolve option conflicts with resolveEnv, and run the+command given the environemnt with runWith which does the actual work,+usually imported from a module.+-}+runCmd :: Environment -> IO ()+runCmd env+    | synopsis env = putSynopsis stdout "\r" ExitSuccess+    | help    env  = putSummary+    | version env  = putVersion+    | manual  env  = putManual+    | license env  = putLicense+    | otherwise    =+      do env'  <- fmap resolveEnv (updateEnv0 env)+         verifyEnv0 env'+         env'' <- updateEnv1 env'+         verifyEnv1 env''+         when (versionSciDb env'') (putStrLn ("SciDB version "++sciDbVersion env'') >> exitSuccess)+         runWith env''++{- |+'updateEnv' updates the environment ('Environment') from the universe,+the external environment.+-}+updateEnv0, updateEnv1 :: Environment -> IO Environment+-- Usage order is important in runCmd, so please do not change it without study+updateEnv0 env= do let b_ = digestAuth env || scidbAuth env+                   when ((not.null.username) env || (not.null.password) env) $+                        unless b_ (putSynopsis stderr+                                   "\rNo authorization (-s|-d) specified with a username/password.\n"+                                   (ExitFailure 2)+                                  )+                   cd    <- getCurrentDirectory+                   es    <- getEnvironment+                   let pd = lookup "PWD" es+                   let hm = lookup "HOME" es+                   let e1 = maybe env{pwd =  cd} (\pd -> env{pwd  = pd}) pd+                   let e2 = maybe e1 (\hm ->  e1{home = hm}) hm+                   return e2++updateEnv1 env =+    do env' <- try (updateEnv1' env) :: IO (Either HttpException Environment)+       case env' of+         Left e      -> do case e of+                             HttpExceptionRequest _ ct -> putSynopsis stderr ("\r"++mk show ct++"\n") (ExitFailure 8)+                             InvalidUrlException s1 s2 -> putSynopsis stderr ("\r"++mk id ("Invalid URL: "++s1++": "++s2++"\n")) (ExitFailure 8)+                           undefined -- this point is never reached+         Right env'' -> fetchUsernamePassword env''+    where+      mk f s = intercalate "\n" $ wrap 80 $ cleanDoubleQuotes $ f s+      updateEnv1' env = do menv <- mkGlobalManagerEnv env+                           maybe (do hPutStrLn stderr ("Invalid certificate store: " ++ certStore env)+                                     putSynopsis stderr "\r" (ExitFailure 7)+                                     undefined+                                 ) return menv++{- | Given the 'Environment' from the command line, fetch from the user+the username and/or password interactively when required.+-}+fetchUsernamePassword :: Environment -> IO Environment+fetchUsernamePassword e = if digestAuth e || scidbAuth e+                          then do un <- fetch username (fetchUsername "")+                                  pw <- encode <$> fetch password (fetchPassword Nothing "")+                                  return e{username = un, password = pw}+                          else return e+    where fetch f g = if null (f e) then g else return (f e)+          encode = if scidbAuth e && checkMajorVersion (18>=) (sciDbVersion e)+                   then base64Sha512Hash else id++{- |+'verifyEnv' verifies the environment created from the command line+options and the supplied operands.+-}+verifyEnv0, verifyEnv1 :: Environment -> IO ()+verifyEnv0 env = do b0 <- valid HOSTNAME (host      env)+                    b1 <- valid PORT     (maybePort env)+                    b2 <- valid PROTOCOL (protocol  env)+                    b3 <- valid HISTORY  (history   env)+                    unless (b0 && b1 && b2 && b3) (putSynopsis stderr "\r" (ExitFailure 3))+                    b4 <- isConnectable (host env) (maybePort env)+                    unless b4 (putSynopsis stderr "\r" (ExitFailure 4))+                    b5 <- if null (file env) then return True else valid READABLE (file env)+                    unless b5 (putSynopsis stderr "\r" (ExitFailure 5))+                    b6 <-if null (certStore env) then return True else valid READABLE (certStore env)+                    unless b6 (putSynopsis stderr "\r" (ExitFailure 6))+                    let b_ = isJust (defFetch env) && isJust (defReadingLines env)+                    unless b_ (putSynopsis stderr "\r" (ExitFailure 13))+                    b' <- valid PREFIX (defPrefix env)+                    unless b' (putSynopsis stderr "\r" (ExitFailure 14))++verifyEnv1 env =+    do let b7 = (not . null) (digestHeaders env)+       when (digestAuth env) $+            unless b7 (putSynopsis stderr+                       "\rEmpty, bad or no digest authentication\n"+                       (ExitFailure 9)+                      )++{- |+'resolveEnv' resolves the environment created from the command line+options and the supplied operands, e.g., if an option over-rides+another, 'resolveEnv' takes this into account.+-}+resolveEnv :: Environment -> Environment+resolveEnv = resolveEnv5.resolveEnv4.resolveEnv3.resolveEnv2.resolveEnv1.resolveEnv0+    -- Order is important, so please do not change it without study+    where+      resolveEnv0 env = if digestAuth env then env{scidbAuth=False} else env+      resolveEnv1 env = if digestAuth env || scidbAuth env+                         then env else env{username = "", password = ""}+      resolveEnv2 env = if scidbAuth env then env{protocol="https"} else env+      resolveEnv3 env = if insecure env then env{certStore = ""} else env+      resolveEnv4 env = if protocol env == "http" then env{certStore = "",insecure=False} else env+      resolveEnv5 env = if history env == "" then env{history = history_file env} else env+          where history_file env = home env ++ [pathSeparator] ++ dot ++ command env ++ "_history"++{- |+'runWith' this environment.  'runWith' is the interface between the command+line options plus operands and the real work. 'runWith' is 'hquery'.+-}+runWith :: Environment -> IO ()+runWith = hquery
+ src/Manual.hs view
@@ -0,0 +1,335 @@+module Manual(putManual) where++import System.Exit (exitWith)+import UtilsUnsafe (putOrPageStrLn)++-- | Display the internal manual.++putManual :: IO ()+putManual = putOrPageStrLn internalManual >>= exitWith++-- | Internal manual.  The definitive source of the internal manual is+-- the description section of the module Main.++internalManual :: String+internalManual =+    "hquery(1)                    User Command                   hquery(1)\n"+++    "\n"+++    "NAME\n"+++    "   hquery - Haskell query for SciDB via shim\n"+++    "\n"+++    "SYNOPSIS\n"+++    "   hquery [-V n] [-t hstfile] [-c certstore] [-n]\n"+++    "             [-r http[s]] [-i host] [-p port] [-a true|false]\n"+++    "               [-e true|false] [-o fmt] [-b num] [-d|-s] [-u usr] [-w pw]\n"+++    "                 [-f qyfile] [query...]\n"+++    "   hquery -g\n"+++    "   hquery -h\n"+++    "   hquery -l\n"+++    "   hquery -m\n"+++    "   hquery -v\n"+++    "   hquery -y\n"+++    "\n"+++    "AVAILABILITY\n"+++    "   Marcus D. Gabriel.  All rights reserved 2014-19(c).\n"+++    "\n"+++    "   marcus@gabriel.name\n"+++    "\n"+++    "   License terms: GNU GPL version 3 (hquery -l)\n"+++    "\n"+++    "DESCRIPTION\n"+++    "   The command hquery with no operands and no options will begin an\n"+++    "   interacitve session with a SciDB server using SciDB's shim\n"+++    "   protocol at http://localhost:8080.\n"+++    "\n"+++    "   With operands, each string will be executed as a SciDB AFL (Array\n"+++    "   Functional Language) query returning a result in SciDB DCSV\n"+++    "   format and fetching only 23 lines per query by default.  If\n"+++    "   stdin is non-empty, it will be execute before the operands.\n"+++    "   SciDB AFL queries are case insensitive and terminated by\n"+++    "   semi-colons (;).\n"+++    "\n"+++    "   Before submitting a query to the shim server, the command\n"+++    "   hquery will\n"+++    "     1. return syntax and parsing errors\n"+++    "     2. report bad nestings, e.g., 'uniq(store(A,B));'\n"+++    "     3. report unknown commands, ignoring them\n"+++    "\n"+++    "   Additionally, the command hquery reports SciDB/shim server\n"+++    "   query exceptions without terminating the process.\n"+++    "\n"+++    "   The command hquery accepts Haskell sytle comments and accepts\n"+++    "   the setting of the following following global variables:\n"+++    "\n"+++    "     -- Number of lines to fetch\n"+++    "     n=Integer;\n"+++    "     -- Format of the output\n"+++    "     format={'csv'|'csv+'|'dcsv'|'dense'|'sparse'|'opaque'\n"+++    "            |'store'|'text'|'tsv'|'tsv+'};\n"+++    "     -- True to fetch data, false to not fetch data\n"+++    "     fetch={true|false};\n"+++    "     -- True to read lines, false to read bytes\n"+++    "     readinglines={true|false};\n"+++    "     -- Prefix to execute before a query by shim, e.g.,\n"+++    "     prefix='a_query(\\'a_string\\');'\n"+++    "\n"+++    "   Prefix is an optional, semi-colon separated, AFL statements\n"+++    "   to precede a query in the same SciDB connection context.\n"+++    "   It is mainly used for SciDB namespace and role  setting.\n"+++    "   There is no terminating semi-colon so trailing semi-colons\n"+++    "   are removed otherwise the prefix is sent to  shim unverified\n"+++    "   and unaltered via the variable 'prefix'.\n"+++    "\n"+++    "   The command 'quit;' or 'exit;' ends the interactive session\n"+++    "   with exit status 0.  The command \"vars;\" displays the interpreter\n"+++    "   variables and values, and the command \"funs;\" displays the\n"+++    "   currently defined interpreter functions and definitions: exit,\n"+++    "   funs, quit, upload, and vars.\n"+++    "\n"+++    "   The upload command takes one argument, a local file path\n"+++    "   string, and returns a shim server-side file path.  It is used\n"+++    "   in queries such as load, input, load_module that take a shim\n"+++    "   server-side file path. Examples are\n"+++    "\n"+++    "     load(m4x4_missing,\n"+++    "       upload('/home/scidb/scidb/m4x4_missing.scidb'));\n"+++    "\n"+++    "     input(m4x4_missing,\n"+++    "       upload('/home/scidb/scidb/m4x4_missing.scidb'));\n"+++    "\n"+++    "     load_module(upload('/home/scidb/scidb/module_1.txt'));\n"+++    "\n"+++    "     join(input(m4x4,upload('/tmp/a\\\\'y\\\\'b.txt')),\n"+++    "       input(m4x4,upload('/tmp/z.txt')));\n"+++    "\n"+++    "   All of the above is case insensitive and terminated with a\n"+++    "   semi-colon (;).\n"+++    "\n"+++    "INTERACTIVE SESSION\n"+++    "   Multi-line queries are supported interactively as they\n"+++    "   are in non-interactive execution.  Ctrl-D at a new prompt\n"+++    "   ends the interactive session.  Ctrl-C returns to the\n"+++    "   interactive prompt, used to end input, especially\n"+++    "   multi-line input.\n"+++    "\n"+++    "   The default prompt is 'True/dcsv/23?', for example,\n"+++    "\n"+++    "     True/dcsv/23? list('arrays');\n"+++    "\n"+++    "   which displays up to 23 lines of arrays, that is,\n"+++    "\n"+++    "     Fetch/Format/NumberOfLines?\n"+++    "\n"+++    "   You can change the global variables 'n', 'format', 'fetch',\n"+++    "   'readinglines', and 'prefix' during execution which changes\n"+++    "   the prompt:\n"+++    "\n"+++    "     True/dcsv/23? n=200;              -- Fetch 200 lines\n"+++    "     True/dcsv/200? n=0;               -- Fetch all lines\n"+++    "     True/dcsv/0? format='csv';        -- Set format to csv\n"+++    "     True/csv/0? fetch=false;          -- Fetch no lines regardless\n"+++    "                                       -- the value of n\n"+++    "     False/csv/0? fetch=true;format=dcsv;n=23;\n"+++    "     True/dcsv/23? readinglines=false; -- Fetch all bytes regardless\n"+++    "                                       -- the value of n\n"+++    "     Bytes/dcsv/23? prefix='set_namespace(\\'sensor_data\\');';\n"+++    "     Bytes/dcsv/23p list('arrays');    -- List sensor_data arrays\n"+++    "     Bytes/dcsv/23p quit;\n"+++    "\n"+++    "   In other words, the prompt indicates the default behaviour for\n"+++    "   the next query executed.\n"+++    "\n"+++    "OPTIONS\n"+++    "   The following options are supported:\n"+++    "\n"+++    "   -a True|false, true to read lines, false to read bytes\n"+++    "      (--reading-lines).  If false, the number of lines to\n"+++    "      fetch (-b) is ignored and the entire output buffer is\n"+++    "      downloaded.  This follows the recommendataion of the\n"+++    "      shim documentation.\n"+++    "\n"+++    "   -b Number, number of lines to fetch (--number).\n"+++    "\n"+++    "   -c Certificate store file, a certificate store to load and use\n"+++    "      for SSL/TLS connections (--certificate-store). The insecure\n"+++    "      option (-n) over-rides the certificate store (-c).\n"+++    "\n"+++    "   -d Use basic digest access authorization, used by either the\n"+++    "      http and https protocols (--digest-authorization).  Digest\n"+++    "      authorization (-d) over-rides SciDB authorization (-s).\n"+++    "\n"+++    "   -e True|false, true to fetch lines, false to not fetch lines\n"+++    "      (--fetch).\n"+++    "\n"+++    "   -f Query file, a readable file of queries.  Multi-line queries\n"+++    "      are supported in a file (--file).  If stdin is non-empty,\n"+++    "      it is executed before the file of queries.  If operands are\n"+++    "      present, they are executed after the file of queries.\n"+++    "\n"+++    "   -g Get and display the SciDB version via shim and then exit\n"+++    "      (--scidb-version).  This performs a simple check for shim \n"+++    "      and SciDB availability.\n"+++    "\n"+++    "   -h Display a short hquery summary (--help).\n"+++    "\n"+++    "   -i IP address or hostname, default localhost (--host).\n"+++    "\n"+++    "   -l Display the hquery license terms (--license).\n"+++    "\n"+++    "   -m Display this internal manual page (--manual).\n"+++    "\n"+++    "   -n Do not use certificate validation, insecure because\n"+++    "      of potential man-in-the-middle attacks (--insecure).\n"+++    "      The insecure option (-n) over-rides the certificate\n"+++    "      store (-c).\n"+++    "\n"+++    "   -o Format, ouput format such as dcsv, csv, csv+, tsv, tsv+,\n"+++    "      etc (--format).\n"+++    "\n"+++    "   -p Port number, default 8080 for protocol (-r) http and default\n"+++    "      8083 for protocol (-r) https (--port).\n"+++    "\n"+++    "   -r Protocol, e.g., http or https, default http (--protocol).\n"+++    "      If the protocol is http, the certificate store (-c) and\n"+++    "      insecure (-n) options are disabled.\n"+++    "\n"+++    "   -s Use SciDB access authorization, requires the https protocol\n"+++    "      (--scidb-authorization).  This option sets the https protocol\n"+++    "      except when digest authorization (-d) over-rides SciDB\n"+++    "      authorization (-s).\n"+++    "\n"+++    "   -t History file, defualt ~/.hquery_history or /tmp/.hquery_history\n"+++    "      if ~ does not exist (--history).\n"+++    "\n"+++    "   -u Username, defualt null (--username).  Used by the digest or\n"+++    "      SciDB authorization option (-d or -s).  Displays an error\n"+++    "      and exits if neither is used with digest or SciDB\n"+++    "      authorization.\n"+++    "\n"+++    "   -v The version of hquery (--version).\n"+++    "\n"+++    "   -w Password, default null (--password).  Used by the digest or\n"+++    "      SciDB authorization option (-d or -s).  Displays an error\n"+++    "      and exits if neither is used with digest or SciDB\n"+++    "      authorization.\n"+++    "\n"+++    "   -y A synopsis of the internal manual page (--synopsis).\n"+++    "\n"+++    "   -x Prefix, a prefix to execute before a query by shim\n"+++    "      (--prefix).  Note that the prefix on the command line\n"+++    "      is verified before being sent to shim.  Prefix is a\n"+++    "      semi-colon separated set of statements.  It is mainly\n"+++    "      used for SciDB namespace and role setting.  There is no\n"+++    "      terminating semi-colon so trailing semi-colons are removed.\n"+++    "\n"+++    "   -V Same as -V1 (--verbose).\n"+++    "  -V0 Quiet.  No information is sent to stderr (--verbose=0).\n"+++    "  -V1 Shows some HTTP exceptions and trace information (--verbose=1).\n"+++    "  -V2 Shows additional URL information (--verbose=2).\n"+++    "\n"+++    "OPERANDS\n"+++    "   SciDB AFL queries.\n"+++    "\n"+++    "USAGE NOTES\n"+++    "   The development of the utility hquery began with SciDB community\n"+++    "   edition 13 and continued with 14, 15, 16, 18, and 19.\n"+++    "\n"+++    "   This version of hquery has been lightly tested with ghc\n"+++    "   version 8.2.2 and 8.6.5 and SciDB 18.1 and 19.3 community edition.\n"+++    "   Currently the command hquery has never been tested on a SciDB\n"+++    "   enterprise edition, and thus it is not known if SciDB\n"+++    "   authorization (-s) or prefix (-x) actually works.\n"+++    "\n"+++    "EXAMPLES\n"+++    "   To list all currently defined arrays with SciDB authorization required,\n"+++    "   use\n"+++    "\n"+++    "     hquery -i coordinator -s -u ScidB -w SciDBPassword \\\n"+++    "         \"n=0; list('arrays');\"\n"+++    "\n"+++    "   To list up to 100 lines of functions with digest authorization required,\n"+++    "   use\n"+++    "\n"+++    "     hquery -i coordinator -d -u Digest -w DigestPassword \\\n"+++    "         \"n=100; list('arrays');\"\n"+++    "\n"+++    "   To list up to 23 lines of operators, 23 being the default, use\n"+++    "\n"+++    "     hquery -i coordinator \"list('operators');\"\n"+++    "\n"+++    "   To list all functions by reading bytes instead of lines, use\n"+++    "\n"+++    "     hquery -i coordinator -a false \"list('functions');\"\n"+++    "\n"+++    "  To create an array A, use\n"+++    "\n"+++    "     hquery -i coordinator \"create array A <x:double> [i=0:99:0:10];\"\n"+++    "\n"+++    "   To execute the file of queries HQTests.qy with no authorization required\n"+++    "   via a TLS connection, use\n"+++    "\n"+++    "     hquery -c ssl_cert.pem  -r https -i coordinator -f HQTest.qy\n"+++    "\n"+++    "   To execute the file of queries HQTests.qy with digest authorization\n"+++    "   required via a TLS connection insecurely, use\n"+++    "\n"+++    "     hquery -n -r https -i coordinator -d -u Digest -w DigestPassword \\\n"+++    "         -f HQTests.qy\n"+++    "\n"+++    "   To list all arrays in the sensor_data namespace, use\n"+++    "\n"+++    "     hquery -i coordinator -b 0 -x \"set_namespace('sensor_data');\" \\\n"+++    "         \"list('arrays');\"\n"+++    "\n"+++    "   To display a synopsis of this internal manual page, use\n"+++    "\n"+++    "     hquery -y\n"+++    "\n"+++    "   To display a summary of usage, use\n"+++    "\n"+++    "     hquery -h\n"+++    "\n"+++    "   To display this internal manual page, use\n"+++    "\n"+++    "     hquery -m\n"+++    "\n"+++    "ENVIRONMENT VARIABLES\n"+++    "   HOME   Home directory for the history file, by defualt\n"+++    "          ~/.hquery_history.\n"+++    "\n"+++    "   PAGER  Page the internal manual page or license terms\n"+++    "          using \"${PAGER}\", otherwise print it.\n"+++    "\n"+++    "EXIT STATUS\n"+++    "   An exit status of 0 is returned if successful, otherwise non-zero\n"+++    "   is returned.\n"+++    "\n"+++    "     EXIT CODE    MEANING\n"+++    "         1        Unknown error.\n"+++    "         2        No authorization specified (-s|-d) with username/password.\n"+++    "         3        Invalid protocol, hostname, port, or history file option.\n"+++    "         4        Cannot connect to hostname:port.\n"+++    "         5        Unreadable query file.\n"+++    "         6        Unreadable certicate store file.\n"+++    "         7        Invalid certificate store.\n"+++    "         8        Network/certificate manager initialization error.\n"+++    "         9        Empty, bad or no digest authentication.\n"+++    "        10        Unauthorized access.\n"+++    "        11        Could not connect to SciDB.\n"+++    "        12        Input syntax error for a SciDB query.\n"+++    "        13        Fetch (-e) or reading-lines (-a) not true or false.\n"+++    "        14        Bad command-line prefix (-x).\n"+++    "   15..255        Unknown error.\n"+++    "\n"+++    "FILES\n"+++    "   ~/.hquery_history\n"+++    "\n"+++    "SEE ALSO\n"+++    "   SciDB, SciDB iquery, SciDB shim at https://www.paradigm4.com/ \n"+++    "   and https://www.paradigm4.com/forum for more information.\n"+++    "\n"+++    "NOTES\n"+++    "   Please send bug reports to https://github.com/mdgabriel/scidb-hquery/issues.\n"+++    "\n"+++    "BUGS\n"+++    "   No known bugs to date.\n"
+ src/SciDbAFL.cf view
@@ -0,0 +1,120 @@+-- SciDB AFL queries++entrypoints AFL ;++comment "--"      ;+comment "{-" "-}" ;++-- SciDB reserves certain keywords that you cannot use as identifiers+-- (such as array names, dimension names, or attribute names). The+-- lists are language-dependent.+--+-- The following words are reserved when using AFL:+--   and          array    as+--   asc          between  case+--   compression  create   default+--   desc         else     empty+--   end          false    if+--   is           not      null+--   or           reserve  temp+--   then         true     using+--   when+token ResAnd         ["Aa"]["Nn"]["Dd"]                                                 ;+token ResArray       ["Aa"]["Rr"]["Rr"]["Aa"]["Yy"]                                     ;+token ResAs          ["Aa"]["Ss"]                                                       ;+token ResAsc         ["Aa"]["Ss"]["Cc"]                                                 ;+--ken ResBetween     ["Bb"]["Ee"]["Tt"]["Ww"]["Ee"]["Ee"]["Nn"]                         ; -- Not used here+--ken ResCase        ["Cc"]["Aa"]["Ss"]["Ee"]                                           ; -- Not used here+token ResCompression ["Cc"]["Oo"]["Mm"]["Pp"]["Rr"]["Ee"]["Ss"]["Ss"]["Ii"]["Oo"]["Nn"] ;+token ResCreate      ["Cc"]["Rr"]["Ee"]["Aa"]["Tt"]["Ee"]                               ;+token ResDefault     ["Dd"]["Ee"]["Ff"]["Aa"]["Uu"]["Ll"]["Tt"]                         ;+token ResDesc        ["Dd"]["Ee"]["Ss"]["Cc"]                                           ;+--ken ResElse        ["Ee"]["Ll"]["Ss"]["Ee"]                                           ; -- Not used here+--ken ResEmpty       ["Ee"]["Mm"]["Pp"]["Tt"]["Yy"]                                     ; -- Not used here+--ken ResEnd         ["Ee"]["Nn"]["Dd"]                                                 ; -- Not used here+token ResFalse       ["Ff"]["Aa"]["Ll"]["Ss"]["Ee"]                                     ;+--ken ResIf          ["Ii"]["Ff"]                                                       ; -- Not used here+--ken ResIs          ["Ii"]["Ss"]                                                       ; -- Not used here+token ResNot         ["Nn"]["Oo"]["Tt"]                                                 ;+token ResNull        ["Nn"]["Uu"]["Ll"]["Ll"]                                           ;+token ResOr          ["Oo"]["Rr"]                                                       ;+--ken ResReserve     ["Rr"]["Ee"]["Ss"]["Ee"]["Rr"]["Vv"]["Ee"]                         ; -- Not used here+token ResTemp        ["Tt"]["Ee"]["Mm"]["Pp"]                                           ;+--ken ResThen        ["Tt"]["Hh"]["Ee"]["Nn"]                                           ; -- Not used here+token ResTrue        ["Tt"]["Rr"]["Uu"]["Ee"]                                           ;+--ken ResUsing       ["Uu"]["Ss"]["Ii"]["Nn"]["Gg"]                                     ; -- Not used here+--ken ResWhen        ["Ww"]["Hh"]["Ee"]["Nn"]                                           ; -- Not used here++-- SciDb expressions (Precedence follows C language conventions)+Eor              . Exp  ::= Exp  ResOr  Exp1                    ;+Eand             . Exp1 ::= Exp1 ResAnd Exp2                    ;+Eeq              . Exp2 ::= Exp2 "="    Exp3                    ;+Ene              . Exp2 ::= Exp2 "<>"   Exp3                    ;+Elt              . Exp3 ::= Exp3 "<"    Exp4                    ;+Egt              . Exp3 ::= Exp3 ">"    Exp4                    ;+Ele              . Exp3 ::= Exp3 "<="   Exp4                    ;+Ege              . Exp3 ::= Exp3 ">="   Exp4                    ;+EAdd             . Exp4 ::= Exp4 "+"    Exp5                    ;+ESub             . Exp4 ::= Exp4 "-"    Exp5                    ;+EMul             . Exp5 ::= Exp5 "*"    Exp6                    ;+EDiv             . Exp5 ::= Exp5 "/"    Exp6                    ;+EMod             . Exp5 ::= Exp5 "%"    Exp6                    ;+ENeg             . Exp7 ::=      "-"    Exp6                    ;+EFunc            . Exp8 ::= Id "(" [Exp] ")"                    ;+separator          Exp      ","                                 ;+EVersion         . Exp8 ::= Id "@" Integer                      ;+EArrayVar        . Exp8 ::= Id "." Id                           ;+EOption          . Exp8 ::= Id ":" Exp                          ; -- shift/reduce conflicts: +42+EAsId            . Exp9 ::= Exp8 ResAs Id                       ;+EAsc             . Exp9 ::= Exp8 ResAsc                         ;+EDesc            . Exp9 ::= Exp8 ResDesc                        ;+EVar             . Exp10::= Id                                  ;+EScheme          . Exp10::= Schema                              ;+EString          . Exp10 ::= AString                            ;+EFalse           . Exp10 ::= ResFalse                           ;+ETrue            . Exp10 ::= ResTrue                            ;+ENull            . Exp10 ::= ResNull                            ;+EInt             . Exp10 ::= Integer                            ;+EDouble          . Exp10 ::= ADouble                            ;+EWildcard        . Exp10 ::= "*"                                ;+EDefault         . Exp10 ::= "?"                                ;+coercions          Exp      10                                  ;+token ADouble digit+ (('.' digit+ (["Ee"] '-'? digit+)?)+                      |(["Ee"] '-'? digit+)+                     )                                          ;+token AString ('\'' ((char - ["'\\"] ) | ('\\' ["'\\"]))* '\'') ;++-- AFL+Queries    . AFL   ::= [Query]                              ;+terminator Query       ";"                                  ;+QueryNil   . Query ::=                                      ;+QueryExp   . Query ::= Exp                                  ;+QueryArray . Query ::= ResCreate         ResArray Id Schema ;+QueryTemp  . Query ::= ResCreate ResTemp ResArray Id Schema ;++Scheme . Schema              ::= "<" [Attribute] ">" "[" Dimensions "]" ;+separator nonempty Attribute     ","                                    ;++Attrib . Attribute ::= Id ":" Id NullableOption DefaultOption CompressionOption ;++NullabeOff     . NullableOption    ::=                        ;+NullableOn     . NullableOption    ::= ResNull                ;+NullableNot    . NullableOption    ::= ResNot ResNull         ;+DefaultOff     . DefaultOption     ::=                        ;+DefaultOn      . DefaultOption     ::= ResDefault Exp6        ;+CompressionOff . CompressionOption ::=                        ;+CompressionOn  . CompressionOption ::= ResCompression AString ;++Dim            . Dimensions ::= Dimension                          ;+DimSemicolon   . Dimensions ::= Dimension ";" Dimensions           ;+DimComma       . Dimensions ::= Dimension "," Dimensions           ; -- shift/reduce conflicts: +1+DimId          . Dimension  ::= Id                                 ;+DimLoHi        . Dimension  ::= Id "=" Exp ":" Exp                 ;+DimLoHiOverlap . Dimension  ::= Id "=" Exp ":" Exp ":" Exp         ;+DimAll         . Dimension  ::= Id "=" Exp ":" Exp ":" Exp ":" Exp ;+DimDeprecated  . Dimension  ::= Id "=" Exp ":" Exp "," Exp "," Exp ;++--------------------------------------------------------------------------------++-- Identifier (Id) is last as a catch all+token Id letter (letter | digit | '_')* ;
+ src/Utils.hs view
@@ -0,0 +1,101 @@+{-# LANGUAGE Safe #-}+module Utils (checkMajorVersion+             ,cleanDoubleQuotes+             ,deEscapeSingleQuotes+             ,dot+             ,escapeSingleQuotes+             ,nolines+             ,replace+             ,strip+             ,stripUsing+             ,toDoubleQuotedStr+             ,toSingleQuotedStr+             ,wrap+             ,wrapUsing+             )+where++import Data.Char                (isSpace)+import Data.List                (findIndices,intercalate)+import Data.List.Split          (splitOn)+import Data.Maybe               (fromMaybe)+import Safe                     (lastDef,readMay)++-- | Given a comparison and a string return true or false:+--+-- > *Utils> checkMajorVersion (18>=) "18.1.0"+-- > True+-- > *Utils> checkMajorVersion (18>=) "19.3"+-- > False+-- > *Utils> checkMajorVersion (>=19) "19.3"+-- > True+-- > *Utils> checkMajorVersion (>=19) "18.1.0"+-- > False+--+checkMajorVersion :: (Int -> t) -> String -> t+checkMajorVersion f s = f (fromMaybe 0 (readMay (takeWhile (/='.') s) :: Maybe Int))++-- | 'strip' away leading and trailing space.+strip :: String -> String+strip = stripUsing isSpace++-- | If at all possible, 'wrap' a string @s@ into strings of length less+-- than or equal to @l@ breaking with 'isSpace'.+wrap :: Int -> String -> [String]+wrap = wrapUsing isSpace++-- | 'stripUsing' predicate @p@ leading and trailing @p x@ true.+stripUsing :: (a -> Bool) -> [a] -> [a]+stripUsing p = dropWhile p . reverse . dropWhile p . reverse++-- | 'wrapUsing' predicate @p@ a list @xs@ into lists of length less+-- than or equal to @l@ breaking on @p x@ true.+wrapUsing :: (a -> Bool) -> Int -> [a] -> [[a]]+wrapUsing p l s =+           if length s' < l || null is+           then [s']+           else hd:wrapUsing p l tl+    where s'       = stripUsing p s+          is       = findIndices p s'+          (hd, tl) = splitAt i s'+          i        = (lastDef (head is) . takeWhile (<=l)) is++-- | 'dot' = \".\"+dot    :: FilePath+dot     = "."++-- | Make a double quoted string from a single quoted string, a SciDB+-- string.++toDoubleQuotedStr :: String -> String+toDoubleQuotedStr = replace "\"" "'" . stripUsing (=='\'') . replace "\\'" "\""++-- | Make a single quoted string which is a SciDB string.++toSingleQuotedStr :: String -> String+toSingleQuotedStr s = "'" ++ escapeSingleQuotes s ++ "'"++-- | De-Escape single quotes.+deEscapeSingleQuotes :: String -> String+deEscapeSingleQuotes = replace "\\'" "'"++-- | Escape single quotes.+escapeSingleQuotes :: String -> String+escapeSingleQuotes = replace "'" "\\'" ++-- | Replaces newlines (\\n) with a space ( ).++nolines :: String -> String+nolines = replace "\n" " "++-- | Replace needle in a haystack with replacement.++replace :: Eq a => [a] -> [a] -> [a] -> [a]+replace needle replacement haystack =+    intercalate replacement (splitOn needle haystack)++-- | Replace escaped double quotes (\") by single quotes (')+-- and remove double qoutes (").++cleanDoubleQuotes :: String -> String+cleanDoubleQuotes = replace "\"" "" . replace "\\\"" "'"
+ src/UtilsUnsafe.hs view
@@ -0,0 +1,175 @@+{-# LANGUAGE LambdaCase #-}+module UtilsUnsafe+               (base64Sha512Hash+               ,fetchPassword+               ,fetchUsername+               ,isConnectable+               ,managerSettings+               ,putOrPageStrLn+               ,VALID(..)+               ,valid+               )+where++import qualified Data.ByteString       as B (empty)+import qualified Data.ByteString.Char8 as C (pack)++import Control.Monad            (unless)+import Crypto.Hash              --()+import Data.Char                (toLower)+import Data.Default.Class       (def)+import Data.Maybe               (fromMaybe,fromJust,isNothing)+import Data.X509.CertificateStore (CertificateStore)+import Network.Connection       (TLSSettings(..))+import Network.HTTP.Client      (ManagerSettings)+import Network.HTTP.Client.TLS  (mkManagerSettings)+import Network.Socket           (addrAddress,addrFamily,addrProtocol,addrSocketType,close,connect,getAddrInfo,socket)+import Network.TLS              (Shared(..),ClientParams(..),Supported(..),defaultParamsClient)+import Network.TLS.Extra.Cipher (ciphersuite_default)+import Safe                     (readMay)+import System.Console.Haskeline (Settings,autoAddHistory,defaultSettings,getInputLine,getPassword,runInputT)+import System.Environment       (getEnvironment)+import System.Exit              (ExitCode(..))+import System.IO                (IOMode(..),openFile,hFlush,hClose,hPutStr,hPutStrLn,stderr)+import System.IO.Error          (ioeGetErrorString,tryIOError)+import System.Process           (createProcess,shell,CreateProcess(..),StdStream(..),waitForProcess)+import Text.Hostname            (validHostname)++import ErrM                     (Err(..))+import Interpreter              (Results(..),interpret)+import Utils                    (toSingleQuotedStr)++import Crypto.Hash              (hashWith, SHA512 (..))+import Data.ByteString          (ByteString)+import Data.ByteArray.Encoding  (convertToBase, Base (Base64))+import Data.Text                (pack)+import Data.Text.Encoding       (encodeUtf8)++-- | Given a string, return a Base64, SHA512 hash.+base64Sha512Hash s =+    let bs     = encodeUtf8 $ pack s+        digest = convertToBase Base64 (hashWith SHA512 bs)+    in show (digest :: ByteString)++-- | Put a string or page it if the environmental variable PAGER is set.+putOrPageStrLn :: String -> IO ExitCode+putOrPageStrLn str+    | null str  = return ExitSuccess+    | otherwise =+    do pager <- fmap (lookup "PAGER") getEnvironment+       if isNothing pager+           then putStrLn str >> return ExitSuccess+           else do (inh, _, _, pid) <- createProcess (shell $ fromJust pager){std_in = CreatePipe}+                   unless (isNothing inh) $ do hPutStr (fromJust inh) str+                                               hFlush (fromJust inh)+                                               hClose (fromJust inh)+                   waitForProcess pid++data VALID = HOSTNAME | PORT | PROTOCOL | HISTORY | READABLE | PREFIX++-- | Is the string a valid 'VALID'?+--+-- >   valid HOSTNAME "localhost"+-- >   valid PORT "8080"+-- >   valid PROTOCOL "http"+-- >   valid READABLE "/path_to_query_file/file"+-- >   -- Terminating semi-colon (;) optional+-- >   valid PREFIX "set_namespace('sensor_data');"+-- >   valid HISTORY "HOME/.hquery_history"+--+-- where HOME is replaced by the home directory of the user if it+-- exists, otherwise /tmp.++valid :: VALID -> String -> IO Bool+valid HOSTNAME s = if (validHostname . C.pack) (fmap toLower s)+                   then return True+                   else do hPutStrLn stderr ("Bad hostname '" ++ s ++ "'")+                           return False++valid PORT     s = if maybe False (\i -> 0 < i && i < 65536) (readMay s :: Maybe Int)+                   then return True+                   else do hPutStrLn stderr ("Bad port number '" ++ s ++ "'")+                           return False++valid PROTOCOL s = let t = fmap toLower s+                   in if t == "http" || t == "https"+                      then return True+                      else do hPutStrLn stderr ("Bad protocol '" ++ s ++ "'")+                              return False++valid HISTORY  s = do result <- tryIOError (openFile s AppendMode)+                      either (\ioe -> do {putIOE "Bad history file" s ioe; return False})+                             (\h -> do {hClose h; return True})+                             result++valid READABLE s = do result <- tryIOError (openFile s ReadMode)+                      either (\ioe -> do {putIOE "Unreadable file" s ioe; return False})+                             (\h -> do {hClose h; return True})+                             result++valid PREFIX s = let s'  = s ++ ";"+                     err = interpret s'+                 in do b <- case err of+                              Bad m -> do hPutStrLn stderr ("Input " ++ m)+                                          return False+                              Ok rs -> return $ all (\case+                                                     Yes _     -> True+                                                     No _      -> True+                                                     Unknown _ ->  True+                                                     _         ->  False+                                                    ) rs+                       if null s || b then return True+                       else do hPutStrLn stderr ("Bad prefix " ++ toSingleQuotedStr s')+                               return False++-- | Return true if one can connect to hostname @h@ and port @p@,+-- otherwise false with a message sent to stderr.+isConnectable :: String -> String -> IO Bool+isConnectable h p =+    do addrs' <- tryIOError (getAddrInfo Nothing (Just h) (Just p))+       either (\ioe -> do {putIOE "Bad hostname:port" (h++":"++p) ioe; return False})+              (\addrs -> do let addr = head addrs+                            sock <- socket (addrFamily addr) (addrSocketType addr) (addrProtocol addr)+                            result <- tryIOError (connect sock (addrAddress addr))+                            either (\ioe -> do {putIOE "Cannot connect:" (h++":"++p) ioe; return False})+                                   (\_ -> do {close sock; return True})+                                   result+              )+              addrs'++putIOE :: String -> String -> IOError -> IO ()+putIOE p s ioe = hPutStrLn stderr (p ++ " '" ++ s ++ "' (" ++ ioeGetErrorString ioe ++ ")")++-- | Fetch the user name with prompt @Username@ or prompt string @s@.+fetchUsername :: String -> IO String+fetchUsername s = let s' = if null s then "Username: " else s ++ ": "+                  in fromMaybe "" <$> runInputT safeSettings (getInputLine s')++-- | Fetch the password with prompt @Password@ or prompt string @s@ and+-- masking character @c@ otherwise @*@.++fetchPassword :: Maybe Char -> String -> IO String+fetchPassword m s = let s' = if null s then "Password: " else s ++ ": "+                        c  = fromMaybe '*' m+                    in do s <- fromMaybe "" <$> runInputT safeSettings (getPassword (Just c) s')+                          putStrLn ""+                          return s++safeSettings :: Settings IO+safeSettings = defaultSettings{autoAddHistory = False}++-- | Given a certificate store, create manager settings for SSL/TLS+-- connections.++managerSettings :: CertificateStore -> ManagerSettings+managerSettings store = mkManagerSettings settings Nothing+  where settings = TLSSettings params+        params   = (defaultParamsClient "" B.empty) {+                       clientUseServerNameIndication = True+                     , clientShared = def {+                           sharedCAStore = store+                       }+                     , clientSupported = def {+                           supportedCiphers = ciphersuite_default+                       }+                   }