A .build.yml => .build.yml +26 -0
@@ 0,0 1,26 @@
+image: nixos/latest
+sources:
+ - https://git.sr.ht/~jack/misc
+tasks:
+ - bunkplan: |
+ cd bunkplan
+ nix-build --no-out-link
+ - bunkplan-ml: |
+ cd bunkplan-ml
+ nix-build --no-out-link
+ - cabinsheets: |
+ cd cabinsheets
+ nix-build --no-out-link
+ - codeworld-raycaster: |
+ cd codeworld-raycaster
+ nix-build --no-out-link
+ - metscrape: |
+ cd metscrape
+ nix-build --no-out-link
+ - metscrape2: |
+ cd metscrape2
+ nix-build --no-out-link
+triggers:
+ - condition: failure
+ action: email
+ to: jack@jackkelly.name
A COPYING => COPYING +661 -0
@@ 0,0 1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are 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.
+
+ 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.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ 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 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 work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ 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 AGPL, see
+<https://www.gnu.org/licenses/>.
M README.md => README.md +9 -1
@@ 1,11 1,19 @@
# Miscellaneous Code
+[](https://builds.sr.ht/~jack/misc?)
+
Here's where I store code that's not worth spinning out into
-full-fledged projects. Most of it is GPLv3-or-later but I might
+full-fledged projects. Most of it is AGPLv3-or-later but I might
licence it under something else if you ask nicely.
## Index of Projects
All paths are relative to repository root.
+* `bunkplan` - Generate a HTML bunkplan from a CSV (Haskell).
+* `bunkplan-ml` - Generate a HTML bunkplan from a CSV (old O'Caml version).
+* `cabinsheets` - Make HTML sheets to print & hang outside each cabin on a ship.
* `codeworld-raycaster` - Draw a blocky labyrinth like it's 1992.
+* `metscrape` - Batch-download wind forecasts from MetVUW (broken, unmaintained).
+* `metscrape2` - Batch-download marine weather forecasts.
+* `photoscripts` - Some shell scripts I use to manage my photos.
A WTFPL => WTFPL +14 -0
@@ 0,0 1,14 @@
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ Version 2, December 2004
+
+ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
+
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
+
A bunkplan-ml/Makefile => bunkplan-ml/Makefile +5 -0
@@ 0,0 1,5 @@
+bunkplan: bunkplan.ml
+ ocamlfind ocamlopt -package csv -package extlib -linkpkg -o $@ $^
+
+clean:
+ -rm -f *.html *.o *.cmi *.cmx bunkplan
A bunkplan-ml/README => bunkplan-ml/README +7 -0
@@ 0,0 1,7 @@
+This reads in a CSV file defining a watchbill and generates a nice
+HTML (4.01 transitional, yech) watchbill for printing. It also makes
+sheets to stick at the front of each cabin.
+
+Requires ocaml, findlib, extlib and csv.
+
+Sample CSV included.
A bunkplan-ml/bunkplan.ml => bunkplan-ml/bunkplan.ml +326 -0
@@ 0,0 1,326 @@
+(* bunkplan.ml - Generate (crappy) HTML bunkplans from CSV *)
+(* Copyright (C) 2012 Jack Kelly *)
+(* *)
+(* This program is free software: you can redistribute it and/or modify *)
+(* it under the terms of the GNU Affero 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 Affero General Public License for more details. *)
+(* *)
+(* You should have received a copy of the GNU Affero General Public *)
+(* License along with this program. If not, see *)
+(* <https://www.gnu.org/licenses/>. *)
+
+open ExtList;;
+open ExtString;;
+
+module IntMap = Map.Make (struct type t = int let compare = compare end);;
+module StringMap = Map.Make (String);;
+
+type crew_type =
+ CO
+ | Chef
+ | Mate of int
+ | Passenger
+ | Watch_Assistant
+ | Watch_Leader;;
+
+type watch = Red | White | Blue;;
+let watch_to_string w =
+ match w with
+ Red -> "RED"
+ | White -> "WHITE"
+ | Blue -> "BLUE"
+let watch_to_string_color w =
+ match w with
+ Red -> "<font color=\"red\">RED</font>"
+ | White -> "WHITE"
+ | Blue -> "<font color=\"blue\">BLUE</font>"
+
+type sex = Male | Female;;
+type bunk_definition = {
+ number: int;
+ cabin: string;
+ bunk_name: string;
+ };;
+type bunk_assignment = {
+ muster_number: int;
+ crew_type: crew_type;
+ watch: watch;
+ name: string;
+ sex: sex;
+ bunk_number: int;
+ liferaft: string;
+ emergency_station: string;
+ };;
+type bunkplan = {
+ assignment: bunk_assignment list;
+ bunks: bunk_definition list;
+ };;
+
+(* Split the rows of the CSV file into the bunkplan, bunks and
+ excludes sections. *)
+let split rows =
+ let chunk list mark =
+ let not_mark row = List.hd row <> mark
+ and not_hash row = (List.hd row).[0] <> '#' in
+ List.takewhile not_hash (List.tl (List.dropwhile not_mark list))
+ in
+ let assignments = chunk rows "#BUNKPLAN"
+ and bunks = chunk rows "#BUNKS"
+ and excludes = chunk rows "#EXCLUDE"
+ in
+ assignments, bunks, excludes;;
+
+(* Parse the watchbill *)
+let parse_assignments assignments =
+ let rec iter assignments acc =
+ match assignments with
+ [] -> List.rev acc
+ | [num;crew_type;watch;name;sex;bunk;liferaft;emergency_station]::tl ->
+ iter tl ({ muster_number=int_of_string num;
+ crew_type=(match crew_type with
+ "CO" -> CO
+ | "CH" -> Chef
+ | "M1" -> Mate 1
+ | "M2" -> Mate 2
+ | "M3" -> Mate 3
+ | "WA" -> Watch_Assistant
+ | "WL" -> Watch_Leader
+ | "" -> Passenger
+ | _ -> failwith "Invalid passenger type.");
+ watch=(match watch with
+ "R" -> Red
+ | "W" -> White
+ | "B" -> Blue
+ | _ -> failwith "Invalid watch.");
+ name=name;
+ sex=(match sex with
+ "M" -> Male
+ | "F" -> Female
+ | _ -> failwith "Invalid sex.");
+ bunk_number=int_of_string bunk;
+ liferaft=liferaft;
+ emergency_station=emergency_station }::acc)
+ | _ -> failwith "Format error in watchbill." in
+ iter assignments [];;
+
+(* Parse bunk definitions *)
+let parse_bunks bunks =
+ let rec iter bunks acc =
+ match bunks with
+ [] -> List.rev acc
+ | [num;cabin;name]::tl -> iter tl ({ number=int_of_string num;
+ cabin=cabin;
+ bunk_name=name }::acc)
+ | _ -> failwith "Format error in bunk definition."
+ in iter bunks [];;
+
+(* Turn a filename into a watchbill and bunk definitions *)
+let read_bunkplan filename =
+ let tidy = List.map (List.map (fun s -> String.uppercase (String.strip s)))
+ and csv = List.filter (fun x -> x <> []) (Csv.trim (Csv.load filename)) in
+ let assignments, bunks, excludes = split (tidy csv) in
+ let watchbill = parse_assignments assignments
+ and bunk_def = parse_bunks bunks
+ and excludes = List.concat excludes in
+ watchbill, bunk_def, excludes;;
+
+let doctype = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n";;
+
+(* Print one cabin plan *)
+let print_cabin template_filename bunks_by_number name cabin =
+ if cabin = [] then () else
+ let size = List.length cabin
+ and filename = (Filename.chop_extension
+ template_filename) ^ "-" ^ name ^ ".html" in
+ let chan = open_out filename in
+ let out = output_string chan
+ and printf = Printf.fprintf chan in
+ let cell = printf "<td><center>%s</center></td>" in
+ let heading = printf "<td><center><font color=\"darkblue\"><u>%s</u></font></center></td>" in
+ out doctype;
+ out "<html>\n";
+ out "<head>\n";
+ printf "<title>BUNK PLAN %s</title>\n" name;
+ out "</head>";
+ out "<body>\n";
+ if size <= 4 then out "<br /><br /><br /><br /><br /><br />";
+ printf "<h1 align=\"center\">BUNK PLAN %s</h1>\n" name;
+ out "<center>\n";
+ if size > 4 then
+ out "<font size=\"5\">"
+ else
+ out "<font size=\"6\">";
+ out"<b>\n";
+ out "<table cellpadding=\"5\" cellspacing=\"40\">\n";
+ out "<tr>";
+ heading "BUNK";
+ heading "WATCH";
+ heading "NAME";
+ out "</tr>\n";
+ List.iter (fun p ->
+ out "<tr>";
+ cell ((IntMap.find p.bunk_number bunks_by_number).bunk_name);
+ cell (watch_to_string_color p.watch);
+ cell p.name;
+ out "</tr>\n") (List.sort ~cmp:(fun a b ->
+ compare a.bunk_number b.bunk_number) cabin);
+ out "</table>\n";
+ out "</b></font>\n";
+ out "</center>\n";
+ out "</body>\n";
+ out "</html>\n";
+ close_out chan;;
+
+(* Print the watchbill *)
+let print_watchbill template_filename bunks_by_number watchbill =
+ let filename = (Filename.chop_extension
+ template_filename) ^ "-WATCHBILL.html" in
+ let chan = open_out filename in
+ let out = output_string chan
+ and printf = Printf.fprintf chan in
+ let red = printf "<font color=\"red\">%s</font>" in
+ out doctype;
+ out "<html>\n";
+ out "<head>\n";
+ out "<title>WATCH AND STATION BILL</title>\n";
+ out "</head>\n";
+ out "<body>\n";
+ out "<center><font face=\"sans\">\n";
+ out "<table border=\"2\" rules=\"all\">\n";
+ out "<tr><td colspan=\"7\">";
+ out "<center>WINDEWARD BOUND<br />WATCH AND STATION BILL</center>";
+ out "</td></tr>\n";
+ let watch_head watch =
+ out "<tr style=\"border:solid 2px\"><td><center>";
+ red "NO.";
+ out "</center></td><td><center>";
+ red ((watch_to_string watch) ^ " WATCH");
+ out "</center></td><td><center>";
+ red "BUNK";
+ out "</center></td><td><center>";
+ red "GEAR";
+ out "</center></td><td><center>";
+ red "CABIN";
+ out "</center></td><td><center>";
+ red "LIFERAFT";
+ out "</center></td><td><center>";
+ red "EMERGENCY STATION";
+ out "</center></td></tr>\n"; in
+ let name_cell entry =
+ let bgcell label =
+ "<td bgcolor=\"#6666ff\">" ^ label ^ "</td>"
+ and nth n =
+ match n with
+ 1 -> "1st"
+ | 2 -> "2nd"
+ | 3 -> "3rd"
+ | _ -> failwith "Unexpected number"
+ and passenger_cell sex name =
+ let color = match sex with Male -> "blue" | Female -> "red" in
+ "<td><font color=\"" ^ color ^ "\">" ^ name ^ "</font></td>"
+ in
+ match entry.crew_type with
+ CO -> bgcell ("CAPTAIN - " ^ entry.name)
+ | Chef -> bgcell ("COOK - " ^ entry.name)
+ | Mate n -> bgcell ((nth n) ^ " MATE " ^ entry.name)
+ | Passenger -> passenger_cell entry.sex entry.name
+ | Watch_Assistant -> "<td>" ^ entry.name ^ "</td>"
+ | Watch_Leader -> bgcell ("LEADER - " ^ entry.name) in
+ let watch_line entry =
+ out "<tr><td>";
+ red ("<center>" ^ (string_of_int entry.muster_number) ^ "</center>");
+ out "</td>";
+ out (name_cell entry);
+ out ("<td><center>" ^ (string_of_int entry.bunk_number) ^ "</center></td>");
+ out "<td></td>";
+ out "<td><center>";
+ out (IntMap.find entry.bunk_number bunks_by_number).cabin;
+ out "</center></td>";
+ printf "<td><center>%s</center></td>" entry.liferaft;
+ printf "<td><center>%s</center></td></tr>\n" entry.emergency_station in
+ watch_head Red;
+ let rec iter watchbill watch =
+ match watchbill with
+ [] -> ()
+ | hd::tl ->
+ if hd.watch <> watch then watch_head hd.watch;
+ watch_line hd;
+ iter tl hd.watch
+ in
+ iter (List.sort
+ ~cmp:(fun a b -> compare a.muster_number b.muster_number)
+ watchbill) Red;
+ out "</table>\n";
+ out "</font></center>\n";
+ out "</body>\n";
+ out "</html>\n";
+ close_out chan;;
+
+(* Build and print the cabin plans *)
+let make_cabins filename watchbill bunks excludes =
+ (* Build a map of the watchbill, by bunk *)
+ let wb_by_bunk =
+ let rec iter watchbill map =
+ match watchbill with
+ [] -> map
+ | hd::tl -> iter tl (IntMap.add hd.bunk_number hd map)
+ in iter watchbill IntMap.empty in
+
+ (* And a map of the bunks, by bunk number *)
+ let bunks_by_number =
+ let rec iter bunks map =
+ match bunks with
+ [] -> map
+ | hd::tl -> iter tl (IntMap.add hd.number hd map)
+ in iter bunks IntMap.empty in
+
+ (* And a map of the cabins, by their cabin name *)
+ let bunks_by_cabin =
+ let rec iter cabins map =
+ match cabins with
+ [] -> StringMap.map List.rev map
+ | hd::tl -> try
+ let cabin = StringMap.find hd.cabin map in
+ iter tl (StringMap.add hd.cabin (hd::cabin) map)
+ with Not_found -> iter tl (StringMap.add hd.cabin [hd] map)
+ in iter bunks StringMap.empty in
+
+ (* And now a map of the people in the cabin *)
+ let cabins = StringMap.map (fun cabin ->
+ List.filter_map (fun bunk ->
+ try
+ Some (IntMap.find bunk.number wb_by_bunk)
+ with Not_found -> None) cabin) bunks_by_cabin in
+
+ (* Filter out the excluded cabins. StringMap.filter is not yet in my
+ version of ocaml. *)
+ let cabins = ref cabins in
+ List.iter (fun cabin ->
+ cabins := StringMap.remove cabin !cabins)
+ excludes;
+ let cabins = !cabins in
+
+ (* Now print the cabin definitions! *)
+ StringMap.iter (print_cabin filename bunks_by_number) cabins;
+ print_watchbill filename bunks_by_number watchbill;;
+
+let make_bunkplan filename =
+ let watchbill, bunk_def, excludes = read_bunkplan filename in
+ make_cabins filename watchbill bunk_def excludes;;
+
+let main () =
+ let nargs = Array.length Sys.argv in
+ if nargs = 2 then
+ make_bunkplan Sys.argv.(1)
+ else begin
+ print_endline "Must have a single filename argument.";
+ exit 1
+ end;;
+
+main ();;
A bunkplan-ml/bunkplan.nix => bunkplan-ml/bunkplan.nix +18 -0
@@ 0,0 1,18 @@
+{ stdenv, ocaml, csv, findlib, ocaml_extlib }:
+
+stdenv.mkDerivation {
+ name = "bunkplan";
+ src = ./.;
+
+ buildInputs = [ ocaml csv findlib ocaml_extlib ];
+
+ installPhase = "install -D -m 755 bunkplan $out/bin/bunkplan";
+
+ meta = with stdenv.lib; {
+ homepage = https://git.sr.ht/~jack/misc;
+ description = "Generate a bunkplan from a CSV";
+ license = licenses.agpl3Plus;
+ maintainers = [ maintainers.endgame ];
+ platforms = platforms.all;
+ };
+}
A bunkplan-ml/default.nix => bunkplan-ml/default.nix +6 -0
@@ 0,0 1,6 @@
+{ nixpkgs ? import ../nix/nixpkgs.nix }:
+
+with nixpkgs;
+callPackage (import ./bunkplan.nix) {
+ inherit (ocamlPackages) csv findlib ocaml_extlib;
+}
A bunkplan-ml/sample.csv => bunkplan-ml/sample.csv +77 -0
@@ 0,0 1,77 @@
+Types:,
+CO,Captain
+CH,Chef
+M1,First Mate
+M2,Second Mate
+M3,Third Mate
+WA,Watch Assistant
+WL,Watch Leader
+(Leave blank for trainees/passengers.)
+
+Number,Type,Watch (R/W/B),Name,Sex (M/F),Bunk (1-30),Liferaft,Emergency Station
+#BUNKPLAN,<- Do not edit this line
+1,WL,R,Red Leader,F,9,Fwd,Quarterdeck
+2,WA,R,Red Assistant,M,3,Fwd,Quarterdeck
+3,,R,Red Crew 1,F,20,Fwd,Quarterdeck
+4,,R,Red Crew 2,F,21,Fwd,Quarterdeck
+5,,R,Red Crew 3,M,25,Fwd,Quarterdeck
+6,,R,Red Crew 4,M,24,Fwd,Quarterdeck
+7,,R,Red Crew 5,M,1,Fwd,Quarterdeck
+8,,R,Red Crew 6,M,2,Fwd,Quarterdeck
+9,CH,R,The Cook,F,10,Fwd,Quarterdeck
+10,CO,R,The Captain,F,29,Fwd,Quarterdeck
+11,WL,W,White Leader,M,23,Aft 1,Quarterdeck
+12,WA,W,White Assistant,F,11,Aft 1,Quarterdeck
+13,,W,White Crew 1,F,12,Aft 1,Quarterdeck
+14,,W,White Crew 2,F,14,Aft 1,Quarterdeck
+15,,W,White Crew 3,M,16,Aft 1,Quarterdeck
+16,,W,White Crew 4,M,17,Aft 1,Quarterdeck
+17,,W,White Crew 5,M,18,Aft 1,Quarterdeck
+18,,W,White Crew 6,M,15,Aft 1,Quarterdeck
+19,M1,W,The First Mate,M,28,Aft 1,Quarterdeck
+20,WL,B,Blue Leader,M,22,Aft 1,Quarterdeck
+21,,B,Blue Assistant,M,4,Aft 1,Quarterdeck
+22,,B,Blue Crew 1,F,13,Aft 1,Quarterdeck
+23,,B,Blue Crew 2,F,19,Aft 1,Quarterdeck
+24,,B,Blue Crew 3,M,8,Aft 1,Quarterdeck
+25,,B,Blue Crew 4,M,7,Aft 1,Quarterdeck
+26,,B,Blue Crew 5,M,5,Aft 2,Quarterdeck
+27,,B,Blue Crew 6,M,6,Aft 2,Quarterdeck
+28,M2,B,The Second Mate,M,27,Aft 2,Quarterdeck
+
+#BUNKS,<- Do not edit this line
+1,FOCS'L,Port Upper
+2,FOCS'L,Port Mid
+3,FOCS'L,Port Lower
+4,FOCS'L,Port Cross
+5,FOCS'L,Stbd Cross
+6,FOCS'L,Stbd Lower
+7,FOCS'L,Stbd Mid
+8,FOCS'L,Stbd Upper
+9,Port Fwd,Upper
+10,Port Fwd,Lower
+11,Port Fwd,Cross
+12,Stbd Fwd,Cross
+13,Stbd Fwd,Lower
+14,Stbd Fwd,Upper
+15,Port Mid,Upper
+16,Port Mid,Mid
+17,Port Mid,Lower
+18,Port Mid,Cross
+19,Stbd Aft,Lower
+20,Stbd Aft,Mid
+21,Stbd Aft,Upper
+22,Port Aft,Lower
+23,Port Aft,Mid
+24,Port Aft,Upper
+25,Port Aft,Cross
+26,Drystore,Bunk
+27,Mates,Upper
+28,Mates,Lower
+29,Aft,Port
+30,Aft,Stbd
+
+#EXCLUDE,"<- Do not edit this line"
+Mates
+Aft
+Drystore
A bunkplan/Bunkplan.hs => bunkplan/Bunkplan.hs +262 -0
@@ 0,0 1,262 @@
+-- bunkplan.ml - Generate (crappy) HTML bunkplans from CSV
+-- Copyright (C) 2012 Jack Kelly
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+{-# LANGUAGE LambdaCase #-}
+
+import Data.Char
+import Data.Foldable (traverse_)
+import Data.Function
+import Data.List
+import qualified Data.Map as Map
+import Data.Maybe
+import System.Exit
+import System.FilePath
+import System.Environment
+import Text.CSV hiding (csv)
+import Text.Html (Html, (!), (<<), (+++))
+import qualified Text.Html as Html
+import Text.ParserCombinators.Parsec.Error
+import Text.Printf
+
+data Crew = Captain
+ | Chef
+ | Mate Int
+ | Passenger
+ | WatchAssistant
+ | WatchLeader deriving Show
+
+data Watch = Red | White | Blue deriving Show
+
+watchLabel :: Watch -> Html
+watchLabel = Html.toHtml . map toUpper . show
+
+watchLabelColor :: Watch -> Html
+watchLabelColor w = colorize $ watchLabel w where
+ colorize = case w of
+ Red -> (! [Html.color Html.red]) . Html.font
+ White -> id
+ Blue -> (! [Html.color Html.blue]) . Html.font
+
+data Sex = Male | Female deriving Show
+
+data BunkDefinition = BunkDefinition {
+ _number :: String, -- Yes, string, to handle bunk 9A and so on.
+ _cabin :: String,
+ _bunkName :: String
+ } deriving Show
+
+data BunkAssignment = BunkAssignment {
+ _musterNumber :: Int,
+ _crewType :: Crew,
+ _watch :: Watch,
+ _name :: String,
+ _sex :: Sex,
+ _bunkNumber :: String,
+ _liferaft :: String,
+ _emergencyStation :: String
+ } deriving Show
+
+data BunkPlan = BunkPlan {
+ _assignment :: [BunkAssignment],
+ _bunks :: [BunkDefinition]
+ } deriving Show
+
+-- Split up the csv into assignments, bunks and excluded cabins (no parsing).
+split :: CSV -> ([Record], [Record], [Record])
+split rows = (assignments, bunks, excludes) where
+ assignments = chunk rows "#BUNKPLAN"
+ bunks = chunk rows "#BUNKS"
+ excludes = chunk rows "#EXCLUDE"
+ chunk list mark = takeWhile notHash $ tail $ dropWhile notMark list where
+ notHash = (/= '#') . head . head
+ notMark = (/= mark) . head
+
+-- Parsing Functions.
+parseCrew :: String -> Crew
+parseCrew "CO" = Captain
+parseCrew "CH" = Chef
+parseCrew "M1" = Mate 1
+parseCrew "M2" = Mate 2
+parseCrew "M3" = Mate 3
+parseCrew "WA" = WatchAssistant
+parseCrew "WL" = WatchLeader
+parseCrew "" = Passenger
+parseCrew _ = error "Invalid passenger type."
+
+parseWatch :: String -> Watch
+parseWatch "R" = Red
+parseWatch "W" = White
+parseWatch "B" = Blue
+parseWatch _ = error "Invalid Watch."
+
+parseSex :: String -> Sex
+parseSex "M" = Male
+parseSex "F" = Female
+parseSex _ = error "Invalid Sex."
+
+parseAssignments :: [Record] -> [BunkAssignment]
+parseAssignments = iter [] where
+ iter acc [] = reverse acc
+ iter acc ([num,
+ crew,
+ watch,
+ name,
+ sex,
+ bunk,
+ liferaft,
+ emergencyStation]:rs) = iter (assign:acc) rs where
+ assign = BunkAssignment {
+ _musterNumber = read num,
+ _crewType = parseCrew crew,
+ _watch = parseWatch watch,
+ _name = name,
+ _sex = parseSex sex,
+ _bunkNumber = bunk,
+ _liferaft = liferaft,
+ _emergencyStation = emergencyStation
+ }
+ iter _ _ = error "Format error in watchbill."
+
+parseDefinitions :: [Record] -> [BunkDefinition]
+parseDefinitions = iter [] where
+ iter acc [] = reverse acc
+ iter acc ([num, cabin, name]:rs) = iter (def:acc) rs where
+ def = BunkDefinition {
+ _number = num,
+ _cabin = cabin,
+ _bunkName = name
+ }
+ iter _ _ = error "Format error in bunk definition."
+
+-- Trim a CSV file: remove empty columns on the left, empty rows at
+-- top or bottom and empty cells at the end of the row.
+
+trimCSV :: CSV -> CSV
+trimCSV = trimRight . trimLeft . trimBottom . trimTop where
+ trimRight = map $ reverse . dropWhile (== "") . reverse
+ trimLeft csv =
+ let margin = minimum $ map (length . takeWhile (== "")) csv
+ in map (drop margin) csv
+ trimTop = dropWhile (all (== ""))
+ trimBottom = reverse . trimTop . reverse
+
+-- Non-structural fixups on the CSV.
+tidy :: CSV -> CSV
+tidy = upper . trimCells where
+ upper = map $ map $ map toUpper
+ trimCells = map . map $ (reverse . dropWhile isSpace . reverse)
+
+-- Read the CSV, parse everything.
+readBunkPlan :: FilePath -> IO ([BunkAssignment], [BunkDefinition], [String])
+readBunkPlan f =
+ parseCSVFromFile f >>= \case
+ Left err -> error $ concatMap messageString $ errorMessages err
+ Right records -> do
+ let records' = filter (not . null) $ trimCSV records
+ (assignments, bunks, excludes) = split $ tidy records'
+ watchbill = parseAssignments assignments
+ bunkDefs = parseDefinitions bunks
+ excludes' = concat excludes
+ return (watchbill, bunkDefs, excludes')
+
+-- Turn the input filename into an output filename.
+makeFileName :: FilePath -> String -> FilePath
+makeFileName template inName = dropExtension template ++ "-" ++ inName ++ ".html"
+
+-- Print one cabin plan
+printCabin :: FilePath
+ -> Map.Map String BunkDefinition
+ -> String
+ -> [BunkAssignment]
+ -> IO ()
+printCabin template bunks name cabin =
+ if null cabin
+ then return ()
+ else do
+ let doctype = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
+ filename = makeFileName template name
+ size = length cabin
+ smallCabin = size <= 5
+ fontSize = if smallCabin then "6" else "5"
+
+ title = printf "BUNK PLAN %s" name :: String
+ theHead = Html.header << Html.thetitle << title
+ theH1 = (Html.h1 << title) ! [Html.align "center"]
+
+ headingCell label = Html.th
+ << Html.center
+ << (Html.font << Html.underline << label) ! [Html.color Html.navy]
+ headingRow = foldl1 (+++) $ map headingCell ["BUNK", "WATCH", "NAME"]
+ cell label = Html.td << Html.center << label
+ bunk assign = _bunkName $ bunks Map.! _bunkNumber assign
+ row assign = Html.tr << (cell (bunk assign)
+ +++ cell (watchLabelColor $ _watch assign)
+ +++ cell (_name assign))
+ theRows = map row $ sortBy (compare `on` _bunkNumber) cabin
+ theTable = (Html.table << (headingRow +++ theRows)) !
+ [Html.cellpadding 5, Html.cellspacing 40]
+ content = Html.center << ((Html.font << Html.bold << theTable)
+ ! [Html.size fontSize])
+ theBody = Html.body << (theH1 +++ content)
+ writeFile filename $
+ doctype ++ Html.prettyHtml (Html.thehtml << (theHead +++ theBody))
+
+-- Build the cabin structures and print plans.
+makeCabins :: FilePath
+ -> ([BunkAssignment], [BunkDefinition], [String])
+ -> IO ()
+makeCabins filename (watchbill, bunks, excludes) = do
+ -- Build a map of the watchbill, by bunk.
+ let watchbillByBunk =
+ foldl (\m assign ->
+ Map.insert (_bunkNumber assign) assign m)
+ Map.empty watchbill
+
+ -- And a map of the bunks by bunk number.
+ let bunksByNumber =
+ foldl (\m def ->
+ Map.insert (_number def) def m) Map.empty bunks
+
+ -- And a map of the cabins, by cabin name.
+ let bunksByCabin =
+ Map.map reverse $
+ foldl (\m def -> Map.insertWith (++) (_cabin def) [def] m)
+ Map.empty bunks
+
+ -- And now a map of the people in each cabin, except the excludes
+ let cabins =
+ Map.filterWithKey (\cabin _ -> cabin `notElem` excludes) $
+ Map.map (mapMaybe
+ (\bunk -> Map.lookup (_number bunk) watchbillByBunk))
+ bunksByCabin
+
+ -- Now print everything!
+ traverse_ (uncurry $ printCabin filename bunksByNumber) $
+ Map.toList cabins
+
+-- Parse and print everything.
+makeBunkPlan :: FilePath -> IO ()
+makeBunkPlan fileName = readBunkPlan fileName >>= makeCabins fileName
+
+-- Let's go!
+main :: IO ()
+main = do
+ args <- getArgs
+ if length args /= 1
+ then do
+ putStrLn "Must have a single filename argument."
+ exitFailure
+ else makeBunkPlan $ head args
A bunkplan/CHANGELOG.md => bunkplan/CHANGELOG.md +5 -0
@@ 0,0 1,5 @@
+# Revision history for bunkplan
+
+## 0.1.0.0 -- YYYY-mm-dd
+
+* First version. Released on an unsuspecting world.
A bunkplan/COPYING => bunkplan/COPYING +661 -0
@@ 0,0 1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are 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.
+
+ 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.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ 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 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 work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ 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 AGPL, see
+<https://www.gnu.org/licenses/>.
A bunkplan/Setup.hs => bunkplan/Setup.hs +2 -0
@@ 0,0 1,2 @@
+import Distribution.Simple
+main = defaultMain
A bunkplan/TODO => bunkplan/TODO +4 -0
@@ 0,0 1,4 @@
+- Watchbill
+ - Font sizing on long names
+ - Lighten colour on "important person" highlight
+- Font sizing on large cabins?
A bunkplan/bunkplan.cabal => bunkplan/bunkplan.cabal +25 -0
@@ 0,0 1,25 @@
+cabal-version: >=1.10
+
+name: bunkplan
+version: 0.1.0.0
+synopsis: Generate a HTML bunkplan from a CSV
+description: Generate a HTML bunkplan from a CSV.
+license: AGPL-3-or-later
+license-file: COPYING
+author: Jack Kelly
+maintainer: jack@jackkelly.name
+copyright: Copyright (C) 2012 Jack Kelly
+category: Application
+build-type: Simple
+extra-source-files: CHANGELOG.md
+
+executable bunkplan
+ main-is: Bunkplan.hs
+ build-depends: base >= 4.12 && < 4.13
+ , containers >= 0.6.0.1 && < 0.7
+ , csv >= 0.1.2 && < 0.2
+ , filepath >= 1.4.2.1 && < 1.5
+ , html >= 1.0.1.2 && < 1.1
+ , parsec >= 3.1.13.0 && < 3.2
+ default-language: Haskell2010
+ ghc-options: -Wall -threaded
A bunkplan/bunkplan.nix => bunkplan/bunkplan.nix +15 -0
@@ 0,0 1,15 @@
+{ mkDerivation, base, containers, csv, filepath, html, parsec
+, stdenv
+}:
+mkDerivation {
+ pname = "bunkplan";
+ version = "0.1.0.0";
+ src = ./.;
+ isLibrary = false;
+ isExecutable = true;
+ executableHaskellDepends = [
+ base containers csv filepath html parsec
+ ];
+ description = "Generate a HTML bunkplan from a CSV";
+ license = stdenv.lib.licenses.agpl3Plus;
+}
A bunkplan/default.nix => bunkplan/default.nix +15 -0
@@ 0,0 1,15 @@
+{ nixpkgs ? import ../nix/nixpkgs.nix
+, compiler ? "default"
+, doBenchmark ? false
+}:
+
+let
+ inherit (nixpkgs) pkgs;
+
+ haskellPackages = if compiler == "default"
+ then pkgs.haskellPackages
+ else pkgs.haskell.packages.${compiler};
+
+ variant = if doBenchmark then pkgs.haskell.lib.doBenchmark else pkgs.lib.id;
+in
+ variant (haskellPackages.callPackage ./bunkplan.nix {})
A bunkplan/sample.csv => bunkplan/sample.csv +80 -0
@@ 0,0 1,80 @@
+Types:,
+CO,Captain
+CH,Chef
+M1,First Mate
+M2,Second Mate
+M3,Third Mate
+WA,Watch Assistant
+WL,Watch Leader
+(Leave blank for trainees/passengers.)
+
+Number,Type,Watch (R/W/B),Name,Sex (M/F),Bunk (1-30),Liferaft,Emergency Station
+#BUNKPLAN,<- Do not edit this line
+1,WL,R,Red Leader,F,9,Fwd,Quarterdeck
+2,WA,R,Red Assistant,M,3,Fwd,Quarterdeck
+3,,R,Red Crew 1,F,20,Fwd,Quarterdeck
+4,,R,Red Crew 2,F,21,Fwd,Quarterdeck
+5,,R,Red Crew 3,M,25,Fwd,Quarterdeck
+6,,R,Red Crew 4,M,24,Fwd,Quarterdeck
+7,,R,Red Crew 5,M,1,Fwd,Quarterdeck
+8,,R,Red Crew 6,M,2,Fwd,Quarterdeck
+9,CH,R,The Cook,F,10,Fwd,Quarterdeck
+10,CO,R,The Captain,F,29,Fwd,Quarterdeck
+11,WL,W,White Leader,M,23,Aft 1,Quarterdeck
+12,WA,W,White Assistant,F,11,Aft 1,Quarterdeck
+13,,W,White Crew 1,F,12,Aft 1,Quarterdeck
+14,,W,White Crew 2,F,14,Aft 1,Quarterdeck
+15,,W,White Crew 3,M,16,Aft 1,Quarterdeck
+16,,W,White Crew 4,M,17,Aft 1,Quarterdeck
+17,,W,White Crew 5,M,18,Aft 1,Quarterdeck
+18,,W,White Crew 6,M,15,Aft 1,Quarterdeck
+19,M1,W,The First Mate,M,28,Aft 1,Quarterdeck
+20,WL,B,Blue Leader,M,22,Aft 1,Quarterdeck
+21,,B,Blue Assistant,M,4,Aft 1,Quarterdeck
+22,,B,Blue Crew 1,F,13,Aft 1,Quarterdeck
+23,,B,Blue Crew 2,F,19,Aft 1,Quarterdeck
+24,,B,Blue Crew 3,M,8,Aft 1,Quarterdeck
+25,,B,Blue Crew 4,M,7,Aft 1,Quarterdeck
+26,,B,Blue Crew 5,M,5,Aft 2,Quarterdeck
+27,,B,Blue Crew 6,M,6,Aft 2,Quarterdeck
+28,M2,B,The Second Mate,M,27,Aft 2,Quarterdeck
+
+#BUNKS,<- Do not edit this line
+1,FOCS'L,Port Upper
+2,FOCS'L,Port Mid
+3,FOCS'L,Port Lower
+4,FOCS'L,Port Cross
+5,FOCS'L,Stbd Cross
+6,FOCS'L,Stbd Lower
+7,FOCS'L,Stbd Mid
+8,FOCS'L,Stbd Upper
+9A,Port Fwd,Upper
+9,Port Fwd,Mid
+10,Port Fwd,Lower
+11,Port Fwd,Cross
+12,Stbd Fwd,Upper Cross
+13,Stbd Fwd,Lower
+13A,Stbd Fwd,Lower Cross
+14A,Stbd Fwd,Upper
+14,Stbd Fwd,Mid
+15,Port Mid,Upper
+16,Port Mid,Mid
+17,Port Mid,Lower
+18,Port Mid,Cross
+19,Stbd Aft,Lower
+20,Stbd Aft,Mid
+21,Stbd Aft,Upper
+22,Port Aft,Lower
+23,Port Aft,Mid
+24,Port Aft,Upper
+25,Port Aft,Cross
+26,Drystore,Bunk
+27,Mates,Upper
+28,Mates,Lower
+29,Aft,Port
+30,Aft,Stbd
+
+#EXCLUDE,"<- Do not edit this line"
+Mates
+Aft
+Drystore
A bunkplan/shell.nix => bunkplan/shell.nix +13 -0
@@ 0,0 1,13 @@
+{ nixpkgs ? import ../nix/nixpkgs.nix
+, compiler ? "default"
+, doBenchmark ? false
+}:
+let
+ inherit (nixpkgs) pkgs;
+ env = (import ./. { inherit nixpkgs compiler doBenchmark; }).env;
+in
+ env.overrideAttrs (oldAttrs: {
+ buildInputs = with pkgs.haskellPackages; oldAttrs.buildInputs ++ [
+ cabal-install cabal2nix ghcid
+ ];
+ })
A cabinsheets/Cabinsheets.hs => cabinsheets/Cabinsheets.hs +138 -0
@@ 0,0 1,138 @@
+-- cabinsheet.ml - Generate (crappy) HTML cabin sheets from CSV
+-- Copyright (C) 2012 Jack Kelly
+--
+-- 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/>.
+
+import Control.Monad
+import Data.Char
+import qualified Data.Map as Map
+import System.Environment
+import System.Exit
+import System.FilePath
+import System.IO
+import Text.CSV
+import Text.Html
+import Text.ParserCombinators.Parsec.Error
+import Text.Printf
+
+-- Cabinsheets are a lot simpler than bunkplans: it's just a series of
+-- records of the form (Cabin, Bunk, Watch, Name). Watch names get
+-- colorized, and the string "HOT BUNK" is rendered in purple.
+data CabinEntry = CabinEntry {
+ bunk :: String,
+ watch :: String,
+ name :: String
+}
+
+type CabinPlan = Map.Map String [CabinEntry]
+
+-- Trim a CSV file: remove empty columns on the left, empty rows at
+-- top or bottom and empty cells at the end of the row.
+trimCSV :: CSV -> CSV
+trimCSV = noEmpty . trimRight . trimLeft where
+ noEmpty = filter (/= [])
+ trimRight = map $ reverse . (dropWhile (== "")) . reverse
+ trimLeft csv = let margin = minimum
+ $ map length
+ $ map (takeWhile (== "")) csv in
+ map (drop margin) csv
+
+-- Non-structural fixups on the CSV.
+tidy :: CSV -> CSV
+tidy = upper . trimCells where
+ upper = map $ map $ map toUpper
+ trimCells = map $ map $ (reverse . (dropWhile isSpace) . reverse)
+
+-- Read the cabin plan into something useful.
+parseCabinPlan :: CSV -> CabinPlan
+parseCabinPlan = foldr addEntry Map.empty where
+ addEntry [cabin, bunk, watch, name] =
+ Map.insertWith (++) cabin [CabinEntry {
+ bunk = bunk,
+ watch = watch,
+ Main.name = name
+ }]
+ addEntry _ = error "Malformed line in CSV"
+
+readCabinPlan :: FilePath -> IO CabinPlan
+readCabinPlan file = do
+ csv <- parseCSVFromFile file
+ case csv of
+ Left err -> error $ concatMap messageString $ errorMessages err
+ Right records -> return $ parseCabinPlan $ tidy $ trimCSV records
+
+-- Generate cabin sheet.
+colorize :: String -> Html
+colorize "RED" = (font << "RED") ! [color "red"]
+colorize "BLUE" = (font << "BLUE") ! [color "blue"]
+colorize "GREEN" = (font << "GREEN") ! [color "green"]
+colorize "HOT BUNK" = (font << "HOT BUNK") ! [color "purple"]
+colorize other = toHtml other
+
+makeCabinSheet :: String -> [CabinEntry] -> String
+makeCabinSheet cabin entries =
+ doctype ++ (prettyHtml $ thehtml << (theHead +++ theBody)) where
+ doctype = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n"
+ size = length entries
+ smallCabin = size <= 5
+ bigNames = any ((>= 15) . length . Main.name) entries
+ fontSize
+ | smallCabin = "6"
+ | bigNames = "5"
+ | otherwise = "4"
+
+ title = (printf "BUNK PLAN %s" cabin) :: String
+ theHead = header << thetitle << title
+ theH1 = (h1 << title) ! [align "center"]
+
+ spacer = if smallCabin then iterate (br +++) br !! 3 else noHtml
+
+ headingCell label = th
+ << center
+ << (font << underline << label) ! [color navy]
+ headingRow = foldl1 (+++) $ map headingCell ["BUNK", "WATCH", "NAME"]
+ cell label = td << center << label
+ row entry = tr << ((cell $ bunk entry)
+ +++ (cell $ colorize $ watch entry)
+ +++ (cell $ Main.name entry))
+ theRows = map row entries
+ theTable = (table << (headingRow +++ theRows)) ! [cellpadding 5,
+ cellspacing 40]
+ content = center << ((font << bold << theTable)
+ ! [Text.Html.size fontSize])
+ theBody = body << (theH1 +++ content)
+
+-- Turn the input filename into an output filename.
+makeFileName :: FilePath -> String -> FilePath
+makeFileName template name = (dropExtension template) ++ "-" ++ name ++ ".html"
+
+printCabinSheet :: FilePath -> String -> [CabinEntry] -> IO ()
+printCabinSheet template cabin entries =
+ writeFile (makeFileName template cabin) (makeCabinSheet cabin entries)
+
+printCabinSheets :: FilePath -> CabinPlan -> IO ()
+printCabinSheets template cabins =
+ mapM_ (uncurry $ printCabinSheet template) $ Map.toList cabins
+
+main :: IO ()
+main = do
+ args <- getArgs
+ case args of
+ [file] -> do
+ plan <- readCabinPlan file
+ printCabinSheets file plan
+ exitSuccess
+ _ -> do
+ putStrLn "Must have a single filename argument."
+ exitFailure
A cabinsheets/Makefile => cabinsheets/Makefile +5 -0
@@ 0,0 1,5 @@
+Cabinsheets: Cabinsheets.hs
+ ghc --make Cabinsheets.hs
+
+clean:
+ -rm -f *.html Cabinsheets Cabinsheets.o Cabinsheets.hi
A cabinsheets/README => cabinsheets/README +4 -0
@@ 0,0 1,4 @@
+The cabin sheets are all generated from a single CSV file. Each row of
+the CSV has four columns: the cabin, the bunk, the watch and the name
+of the person in that bunk. Copy and alter sample.csv, that's the
+easiest way.
A cabinsheets/sample.csv => cabinsheets/sample.csv +33 -0
@@ 0,0 1,33 @@
+FOCS'L,Port Upper,Red,Person 1
+FOCS'L,Port Mid,Red,Person 2
+FOCS'L,Port Lower,Red,Person 3
+FOCS'L,Port Cross,Red,Person 4
+FOCS'L,Stbd Cross,Red,Person 5
+FOCS'L,Stbd Lower,Red,Person 6
+FOCS'L,Stbd Mid,Red,Person 7
+FOCS'L,Stbd Upper,Red,Person 8
+
+Port Fwd,Lower,White,Person 9
+Port Fwd,Mid,White,Person 10
+Port Fwd,Upper,White,Person 11
+Port Fwd,Cross,White,Person 12
+
+Stbd Fwd,Lower,White,Person 13
+Stbd Fwd,Mid,White,Person 14
+Stbd Fwd,Upper,White,Person 15
+Stbd Fwd,Lower Cross,White,Person 16
+Stbd Fwd,Upper Cross,White,Person 17
+
+Port Mid,Lower,Blue,Person 18
+Port Mid,Mid,Blue,Person 19
+Port Mid,Upper,Blue,Person 20
+Port Mid,Cross,Blue,Person 21
+
+Stbd Aft,Lower,Blue,Person 22
+Stbd Aft,Mid,Blue,Person 23
+Stbd Aft,Upper,Blue,Person 24
+
+Port Aft,Lower,Blue,Person 25
+Port Aft,Mid,Blue,Person 26
+Port Aft,Upper,Blue,Person 27
+Port Aft,Cross,Blue,Person 28
M codeworld-raycaster/app/Main.hs => codeworld-raycaster/app/Main.hs +16 -2
@@ 1,4 1,18 @@
-{-# LANGUAGE StaticPointers #-}
+-- codeworld-raycaster - draw a blocky labyrinth like it's 1992.
+-- Copyright (C) 2018 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
module Main where
@@ 12,4 26,4 @@ main
= interactionOf initialState handleTime handleEvent draw
where
handleTime _ s = s
- draw s = render s & coordinatePlane>
\ No newline at end of file
+ draw s = render s & coordinatePlane
A codeworld-raycaster/codeworld-api-0.3.1-blank-canvas-jailbreak.patch => codeworld-raycaster/codeworld-api-0.3.1-blank-canvas-jailbreak.patch +12 -0
@@ 0,0 1,12 @@
+diff -uar a/codeworld-api-0.3.1/codeworld-api.cabal b/codeworld-api-0.3.1/codeworld-api.cabal
+--- a/codeworld-api.cabal 2019-02-28 02:15:42.000000000 +1000
++++ b/codeworld-api.cabal 2019-11-02 19:15:58.972474817 +1000
+@@ -51,7 +51,7 @@
+ ghcjs-dom >= 0.8 && < 0.9,
+ transformers
+ else
+- Build-depends: blank-canvas >= 0.6 && < 0.7,
++ Build-depends: blank-canvas,
+ time >= 1.6.0 && < 1.9
+
+ Exposed: True
D codeworld-raycaster/codeworld-api-0.3.1.nix => codeworld-raycaster/codeworld-api-0.3.1.nix +0 -15
@@ 1,15 0,0 @@
-{ mkDerivation, base, blank-canvas, cereal, cereal-text, containers
-, ghc-prim, hashable, mtl, random, random-shuffle, stdenv, text
-, time
-}:
-mkDerivation {
- pname = "codeworld-api";
- version = "0.3.1";
- sha256 = "6f017882e65353e27077551af9bb5f6d427f967e9fc69bd88073c353617e6f8e";
- libraryHaskellDepends = [
- base blank-canvas cereal cereal-text containers ghc-prim hashable
- mtl random random-shuffle text time
- ];
- description = "Graphics library for CodeWorld";
- license = stdenv.lib.licenses.asl20;
-}
M codeworld-raycaster/codeworld-raycaster.cabal => codeworld-raycaster/codeworld-raycaster.cabal +2 -1
@@ 3,7 3,7 @@ cabal-version: >= 2.0
name: codeworld-raycaster
version: 0.1.0.0
synopsis: Simple raycaster
-license: GPL-3.0-or-later
+license: AGPL-3.0-or-later
license-file: LICENSE
author: Jack Kelly
maintainer: jack@jackkelly.name
@@ 11,6 11,7 @@ copyright: (c) 2019 Jack Kelly
category: Game Engine
build-type: Simple
extra-source-files: CHANGELOG.md, README.md
+homepage: https://git.sr.ht/~jack/misc
library
exposed-modules: Controller
M codeworld-raycaster/codeworld-raycaster.nix => codeworld-raycaster/codeworld-raycaster.nix +3 -1
@@ 7,5 7,7 @@ mkDerivation {
isExecutable = true;
libraryHaskellDepends = [ array base codeworld-api text ];
executableHaskellDepends = [ base codeworld-api ];
- license = stdenv.lib.licenses.gpl3;
+ homepage = "https://git.sr.ht/~jack/misc";
+ description = "Simple raycaster";
+ license = stdenv.lib.licenses.agpl3Plus;
}
M codeworld-raycaster/default.nix => codeworld-raycaster/default.nix +7 -3
@@ 1,4 1,7 @@
-{ nixpkgs ? import ./nixpkgs-pin.nix {}, compiler ? "default", doBenchmark ? false }:
+{ nixpkgs ? import ../nix/nixpkgs.nix
+, compiler ? "default"
+, doBenchmark ? false
+}:
let
inherit (nixpkgs) pkgs;
@@ 8,8 11,9 @@ let
else pkgs.haskell.packages.${compiler};
myHaskellPackages = haskellPackages.override {
- overrides = self: super: {
- codeworld-api = super.callPackage ./codeworld-api-0.3.1.nix {};
+ overrides = self: super: with pkgs.haskell.lib; {
+ codeworld-api = appendPatch (unmarkBroken super.codeworld-api)
+ ./codeworld-api-0.3.1-blank-canvas-jailbreak.patch;
};
};
M codeworld-raycaster/shell.nix => codeworld-raycaster/shell.nix +3 -3
@@ 1,13 1,13 @@
-{ nixpkgs ? import ./nixpkgs-pin.nix {}
+{ nixpkgs ? import ../nix/nixpkgs.nix
, compiler ? "default"
, doBenchmark ? false
}:
let
inherit (nixpkgs) pkgs;
- env = (import ./default.nix { inherit nixpkgs compiler doBenchmark; }).env;
+ env = (import ./. { inherit nixpkgs compiler doBenchmark; }).env;
in
env.overrideAttrs (oldAttrs: {
buildInputs = with pkgs.haskellPackages; oldAttrs.buildInputs ++ [
- cabal-install ghcid
+ cabal-install cabal2nix ghcid
];
})
M codeworld-raycaster/src/Controller.hs => codeworld-raycaster/src/Controller.hs +17 -1
@@ 1,3 1,19 @@
+-- codeworld-raycaster - draw a blocky labyrinth like it's 1992.
+-- Copyright (C) 2018 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
{-# LANGUAGE OverloadedStrings #-}
module Controller where
@@ 13,7 29,7 @@ handleEvent (KeyPress k) s
| k == "Up" = adjustPosition (forward 0.1) s
| k == "Down" = adjustPosition (forward (-0.1)) s
| k == "Left" = adjustFacing (normalize . (+ turnAngle)) s
- | k == "Right" = adjustFacing (normalize . (subtract turnAngle)) s
+ | k == "Right" = adjustFacing (normalize . subtract turnAngle) s
where
forward d (px, py) = (px + d * cos theta, py + d * sin theta) where
M codeworld-raycaster/src/Renderer.hs => codeworld-raycaster/src/Renderer.hs +16 -0
@@ 1,3 1,19 @@
+-- codeworld-raycaster - draw a blocky labyrinth like it's 1992.
+-- Copyright (C) 2018 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
module Renderer (render, normalize) where
import CodeWorld
M codeworld-raycaster/src/State.hs => codeworld-raycaster/src/State.hs +16 -0
@@ 1,3 1,19 @@
+-- codeworld-raycaster - draw a blocky labyrinth like it's 1992.
+-- Copyright (C) 2018 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
module State where
import Data.Array (Array, (!), bounds, array)
A metscrape/Makefile => metscrape/Makefile +13 -0
@@ 0,0 1,13 @@
+PKGS := libcurl libxml-2.0
+CFLAGS := -std=gnu99 -Wall -Wextra $(shell pkg-config --cflags $(PKGS))
+LIBS := $(shell pkg-config --libs $(PKGS))
+
+all: metscrape
+
+metscrape: metscrape.c
+ gcc $(CFLAGS) -o $@ $< $(LIBS)
+
+clean:
+ -rm -f metscrape *.gif
+
+.PHONY: all clean
A metscrape/README => metscrape/README +8 -0
@@ 0,0 1,8 @@
+This is no longer maintained, and MetVUW have redone their website, so
+it doesn't work any more. Might still be useful as a reference.
+
+A simple C program to pull down a set of MetVUW weather
+images. Everything's hardcoded: it always pulls the "seaussie" set, and
+pulls down every image in the set.
+
+Requires libxml2 and libcurl.
A metscrape/default.nix => metscrape/default.nix +2 -0
@@ 0,0 1,2 @@
+{ nixpkgs ? import ../nix/nixpkgs.nix }:
+nixpkgs.callPackage (import ./metscrape.nix) {}
A metscrape/metscrape.c => metscrape/metscrape.c +141 -0
@@ 0,0 1,141 @@
+/*
+ * metscrape - dumb scraper to pull down MetVUW weather images
+ * Copyright (C) 2012 Jack Kelly <jack@jackkelly.name>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <curl/curl.h>
+#include <libxml/HTMLparser.h>
+#include <libxml/xpath.h>
+
+#define FORECAST_URL ("http://www.metvuw.com/forecast/forecast1.php" \
+ "?type=rain®ion=seaussie&tim=06")
+#define FORECAST_IMG_URL_PATTERN ("http://www.metvuw.com/forecast/%1$s/" \
+ "rain-seaussie-%1$s-%2$02d.gif")
+#define FORECAST_IMG_FILE_PATTERN "rain-seaussie-%1$s-%2$03d.gif"
+#define BUFSIZE 1024
+
+/* Fetch options */
+#define START 6
+#define STEP 6
+#define LAST 180
+
+/* Fetch ALL THE IMAGES! */
+static void fetch_images(const char* base) {
+ puts("Fetching images...");
+
+ char buf[BUFSIZE];
+ CURL* curl = curl_easy_init();
+ if (curl == NULL) {
+ puts(" - Error");
+ return;
+ }
+
+ size_t write_cb(void* p, size_t sz, size_t nmemb, void* ud) {
+ FILE* fp = ud;
+ size_t written = fwrite(p, sz, nmemb, fp);
+ return sz * written;
+ }
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
+
+ for (int i = START; i <= LAST; i += STEP) {
+ snprintf(buf, BUFSIZE, FORECAST_IMG_URL_PATTERN, base, i);
+ curl_easy_setopt(curl, CURLOPT_URL, buf);
+ snprintf(buf, BUFSIZE, FORECAST_IMG_FILE_PATTERN, base, i);
+ FILE* fp = fopen(buf, "w");
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
+ printf(" - %s...", buf);
+ fflush(stdout);
+
+ CURLcode status = curl_easy_perform(curl);
+ fclose(fp);
+ if (status == 0) {
+ puts(" OK");
+ } else {
+ puts(" FAIL");
+ unlink(buf);
+ }
+ }
+ curl_easy_cleanup(curl);
+}
+
+/* Forecast URLs take the form
+ http://www.metvuw.com/forecast/2012031712/rain-seaussie-2012031712-06.gif
+ This fetches a sample page and finds the base (here 20120031712).
+ Free the result with free().
+ Return NULL if it gets confused. */
+static char* get_forecast_base(void) {
+ char* result = NULL;
+ htmlParserCtxtPtr ctx = htmlNewParserCtxt();
+ if (ctx == NULL) goto err0;
+ htmlDocPtr doc = htmlCtxtReadFile(ctx,
+ FORECAST_URL,
+ NULL,
+ (HTML_PARSE_RECOVER
+ | XML_PARSE_NOERROR
+ | XML_PARSE_NOWARNING));
+ if (doc == NULL) goto err1;
+
+ xmlXPathContextPtr xpath = xmlXPathNewContext(doc);
+ if (xpath == NULL) goto err2;
+
+ xmlXPathObjectPtr obj = xmlXPathEvalExpression((const xmlChar*)"//img", xpath);
+ if (obj == NULL) goto err3;
+
+ for (int i = 0; i < obj->nodesetval->nodeNr; i++) {
+ xmlChar* prop = xmlGetProp(obj->nodesetval->nodeTab[i], (const xmlChar*)"src");
+ if (prop != NULL) {
+ if (strstr((const char*)prop, "rain-") != NULL) {
+ free(result);
+ result = strndup((const char*)prop + 2, 10);
+ }
+ }
+ xmlFree(prop);
+ }
+
+ xmlFreeDoc(doc);
+ err3:
+ xmlXPathFreeObject(obj);
+ err2:
+ xmlXPathFreeContext(xpath);
+ err1:
+ xmlFreeParserCtxt(ctx);
+ err0:
+ return result;
+}
+
+int main(int argc, char *argv[]) {
+ (void)argc;
+ (void)argv;
+ curl_global_init(CURL_GLOBAL_ALL);
+ xmlInitParser();
+ printf("Finding the forecast base... ");
+ fflush(stdout);
+ char* base = get_forecast_base();
+ if (base != NULL) {
+ printf("%s\n", base);
+ fetch_images(base);
+ free(base);
+ } else {
+ printf("error\n");
+ }
+ xmlCleanupParser();
+ curl_global_cleanup();
+ return 0;
+}
A metscrape/metscrape.nix => metscrape/metscrape.nix +19 -0
@@ 0,0 1,19 @@
+{ stdenv, curl, libxml2, pkgconfig }:
+
+stdenv.mkDerivation {
+ name = "metscrape";
+ src = ./.;
+
+ buildInputs = [ curl.dev libxml2.dev ];
+ nativeBuildInputs = [ pkgconfig ];
+
+ installPhase = "install -D -m 755 metscrape $out/bin/metscrape";
+
+ meta = with stdenv.lib; {
+ homepage = https://git.sr.ht/~jack/misc;
+ description = "Batch-download MetVUW forecasts";
+ license = licenses.agpl3Plus;
+ maintainers = [ maintainers.endgame ];
+ platforms = platforms.all;
+ };
+}
A metscrape2/COPYING => metscrape2/COPYING +661 -0
@@ 0,0 1,661 @@
+ GNU AFFERO GENERAL PUBLIC LICENSE
+ Version 3, 19 November 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+our General Public Licenses are 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.
+
+ 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.
+
+ Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+ A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate. Many developers of free software are heartened and
+encouraged by the resulting cooperation. However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+ The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community. It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server. Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+ An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals. This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+ 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 Affero 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. Remote Network Interaction; Use with the GNU General Public License.
+
+ Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software. This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+ 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 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 work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source. For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code. There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+ 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 AGPL, see
+<https://www.gnu.org/licenses/>.
A metscrape2/README => metscrape2/README +2 -0
@@ 0,0 1,2 @@
+An expansion of metscrape, written in haskell, that supports most of
+the forecasts that I'm interested in.
A metscrape2/Setup.hs => metscrape2/Setup.hs +18 -0
@@ 0,0 1,18 @@
+-- metscrape - bulk-download weather forecasts.
+-- Copyright (C) 2012 Jack Kelly <jack@jackkelly.name>
+--
+-- 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/>.
+
+import Distribution.Simple
+main = defaultMain
A metscrape2/default.nix => metscrape2/default.nix +15 -0
@@ 0,0 1,15 @@
+{ nixpkgs ? import ../nix/nixpkgs.nix
+, compiler ? "default"
+, doBenchmark ? false
+}:
+
+let
+ inherit (nixpkgs) pkgs;
+
+ haskellPackages = if compiler == "default"
+ then pkgs.haskellPackages
+ else pkgs.haskell.packages.${compiler};
+
+ variant = if doBenchmark then pkgs.haskell.lib.doBenchmark else pkgs.lib.id;
+in
+ variant (haskellPackages.callPackage ./metscrape.nix {})
A metscrape2/metscrape.cabal => metscrape2/metscrape.cabal +71 -0
@@ 0,0 1,71 @@
+Cabal-Version: >= 1.10
+
+Name: metscrape
+Version: 0.1.0.0
+Synopsis: Batch-download marine weather forecasts
+Description: Batch-download marine weather forecasts.
+Category: Application
+License: AGPL-3-or-later
+License-File: COPYING
+Author: Jack Kelly
+Maintainer: jack@jackkelly.name
+Build-Type: Simple
+Homepage: https://git.sr.ht/~jack/misc
+
+Library
+ Build-Depends: base >= 4.12.0.0 && < 4.13,
+ bytestring >= 0.10.8.2 && < 0.11,
+ containers >= 0.6.0.1 && < 0.7,
+ directory >= 1.3.3.0 && < 1.4,
+ filepath >= 1.4.2.1 && < 1.5,
+ HTTP >= 4000.3.14 && < 4000.4,
+ hxt >= 9.3.1.18 && < 9.4,
+ hxt-http >= 9.1.5.2 && < 9.2,
+ network >= 2.8.0.1 && < 2.9,
+ network-uri >= 2.6.1.0 && < 2.7
+
+ Exposed-Modules: Menu,
+ Scraper,
+ Scrapers.BOM,
+ Scrapers.BOMText,
+ Scrapers.MetVUW,
+ Text
+
+ HS-Source-Dirs: src/lib
+ Default-Language: Haskell2010
+ GHC-Options: -Wall
+
+Executable MetscrapeAUS
+ Build-Depends: base, metscrape
+ HS-Source-Dirs: src/bin
+ Main-Is: MetscrapeAUS.hs
+ Default-Language: Haskell2010
+ GHC-Options: -Wall -threaded
+
+Executable MetscrapeNSW
+ Build-Depends: base, metscrape
+ HS-Source-Dirs: src/bin
+ Main-Is: MetscrapeNSW.hs
+ Default-Language: Haskell2010
+ GHC-Options: -Wall -threaded
+
+Executable MetscrapeVIC
+ Build-Depends: base, metscrape
+ HS-Source-Dirs: src/bin
+ Main-Is: MetscrapeVIC.hs
+ Default-Language: Haskell2010
+ GHC-Options: -Wall -threaded
+
+Executable MetscrapeTAS
+ Build-Depends: base, metscrape
+ HS-Source-Dirs: src/bin
+ Main-Is: MetscrapeTAS.hs
+ Default-Language: Haskell2010
+ GHC-Options: -Wall -threaded
+
+Executable MetscrapeNZ
+ Build-Depends: base, metscrape
+ HS-Source-Dirs: src/bin
+ Main-Is: MetscrapeNZ.hs
+ Default-Language: Haskell2010
+ GHC-Options: -Wall -threaded
A metscrape2/metscrape.nix => metscrape2/metscrape.nix +18 -0
@@ 0,0 1,18 @@
+{ mkDerivation, base, bytestring, containers, directory, filepath
+, HTTP, hxt, hxt-http, network, network-uri, stdenv
+}:
+mkDerivation {
+ pname = "metscrape";
+ version = "0.1.0.0";
+ src = ./.;
+ isLibrary = true;
+ isExecutable = true;
+ libraryHaskellDepends = [
+ base bytestring containers directory filepath HTTP hxt hxt-http
+ network network-uri
+ ];
+ executableHaskellDepends = [ base ];
+ homepage = "https://git.sr.ht/~jack/misc";
+ description = "Batch-download marine weather forecasts";
+ license = stdenv.lib.licenses.agpl3Plus;
+}
A metscrape2/shell.nix => metscrape2/shell.nix +13 -0
@@ 0,0 1,13 @@
+{ nixpkgs ? import ../nix/nixpkgs.nix
+, compiler ? "default"
+, doBenchmark ? false
+}:
+let
+ inherit (nixpkgs) pkgs;
+ env = (import ./. { inherit nixpkgs compiler doBenchmark; }).env;
+in
+ env.overrideAttrs (oldAttrs: {
+ buildInputs = with pkgs.haskellPackages; oldAttrs.buildInputs ++ [
+ cabal-install cabal2nix ghcid
+ ];
+ })
A metscrape2/src/bin/MetscrapeAUS.hs => metscrape2/src/bin/MetscrapeAUS.hs +30 -0
@@ 0,0 1,30 @@
+-- metscrape - bulk-download weather forecasts.
+-- Copyright (C) 2013 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+import Menu
+import Scrapers.BOM as BOM
+import Scrapers.MetVUW as MetVUW
+
+main :: IO ()
+main = run [
+ ("[BOM] Mean Sea Level Pressure", BOM.scrapeMSLPP),
+ ("[BOM] Surface Pressure/Rainfall", BOM.scrapeSurfacePressureRainfall),
+ ("[MetVUW] SE Australia Winds",
+ MetVUW.scrapeMetVUW "seaussie" "Weather/MetVUW/SEAUS/Wind-%03d.gif"),
+ ("[BOM] SE Australia Sea And Swell",
+ scrapeInteractiveWeather "IDY30223" "sigWaveHgt"
+ "Weather/SeaAndSwell%03d.png")
+ ]
A metscrape2/src/bin/MetscrapeNSW.hs => metscrape2/src/bin/MetscrapeNSW.hs +65 -0
@@ 0,0 1,65 @@
+-- metscrape - bulk-download weather forecasts.
+-- Copyright (C) 2013 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+import Menu
+import Scraper
+import Scrapers.BOM
+import Scrapers.BOMText
+
+to :: String -> FilePath -> Scraper
+url `to` path = Munge url transformXml $ "Weather/NSW/" ++ path
+
+main :: IO ()
+main = run [
+ ("[BOM] NSW Winds",
+ scrapeMarineWind "nsw" "Weather/NSW/Wind%02d.png"),
+
+ ("[BOMText] Byron Coast",
+ "http://www.bom.gov.au/nsw/forecasts/byroncoast.shtml"
+ `to` "ByronCoast.txt"),
+
+ ("[BOMText] Coffs Coast",
+ "http://www.bom.gov.au/nsw/forecasts/coffscoast.shtml"
+ `to` "CoffsCoast.txt"),
+
+ ("[BOMText] Macquarie Coast",
+ "http://www.bom.gov.au/nsw/forecasts/macquariecoast.shtml"
+ `to` "MacquarieCoast.txt"),
+
+ ("[BOMText] Hunter Coast",
+ "http://www.bom.gov.au/nsw/forecasts/huntercoast.shtml"
+ `to` "HunterCoast.txt"),
+
+ ("[BOMText] Sydney Coast",
+ "http://www.bom.gov.au/nsw/forecasts/sydneycoast.shtml"
+ `to` "SydneyCoast.txt"),
+
+ ("[BOMText] Sydney Closed Waters",
+ "http://www.bom.gov.au/nsw/forecasts/sydneywaters.shtml"
+ `to` "SydneyClosedWaters.txt"),
+
+ ("[BOMText] Illawarra Coast",
+ "http://www.bom.gov.au/nsw/forecasts/illawarracoast.shtml"
+ `to` "IllawarraCoast.txt"),
+
+ ("[BOMText] Batemans Coast",
+ "http://www.bom.gov.au/nsw/forecasts/batemanscoast.shtml"
+ `to` "BatemansCoast.txt"),
+
+ ("[BOMText] Eden Coast",
+ "http://www.bom.gov.au/nsw/forecasts/edencoast.shtml"
+ `to` "EdenCoast.txt")
+ ]
A metscrape2/src/bin/MetscrapeNZ.hs => metscrape2/src/bin/MetscrapeNZ.hs +30 -0
@@ 0,0 1,30 @@
+-- metscrape - bulk-download weather forecasts.
+-- Copyright (C) 2013 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+import Menu
+import Scrapers.MetVUW as MetVUW
+
+main :: IO ()
+main = run [
+ ("[MetVUW] New Zealand Winds",
+ MetVUW.scrapeMetVUW "nz" "Weather/MetVUW/NZ/Wind-%03d.gif"),
+ ("[MetVUW] NZ North Island Winds",
+ MetVUW.scrapeMetVUW "nzni" "Weather/MetVUW/NZNorth/Wind-%03d.gif"),
+ ("[MetVUW] NZ South Island Winds",
+ MetVUW.scrapeMetVUW "nzsi" "Weather/MetVUW/NZSouth/Wind-%03d.gif"),
+ ("[MetVUW] Southwest Pacific MSLPP",
+ MetVUW.scrapeMetVUW "swp" "Weather/MetVUW/SWPacific/MSLP-%03d.gif")
+ ]
A metscrape2/src/bin/MetscrapeTAS.hs => metscrape2/src/bin/MetscrapeTAS.hs +81 -0
@@ 0,0 1,81 @@
+-- metscrape - bulk-download weather forecasts.
+-- Copyright (C) 2013 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+import Menu
+import Scraper
+import Scrapers.BOM
+import Scrapers.BOMText
+
+to :: String -> FilePath -> Scraper
+url `to` path = Munge url transformXml $ "Weather/Tas/" ++ path
+
+main :: IO ()
+main = run [
+ ("[BOM] Tasmania Winds",
+ scrapeMarineWind "tas" "Weather/Tas/Wind%02d.png"),
+
+ ("[BOM] Bass Straight Sea and Swell",
+ scrapeInteractiveWeather "IDY30205" "sigWaveHgt"
+ "Weather/Tas/BassStrait%03d.png"),
+
+ ("[BOMText] Banks Strait",
+ "http://www.bom.gov.au/tas/forecasts/banksstrait.shtml"
+ `to` "BanksStrait.txt"),
+
+ ("[BOMText] Derwent Estuary",
+ "http://www.bom.gov.au/tas/forecasts/derwent.shtml"
+ `to` "Derwent.txt"),
+
+ ("[BOMText] D'Entrecasteaux Channel",
+ "http://www.bom.gov.au/tas/forecasts/channel.shtml"
+ `to` "Channel.txt"),
+
+ ("[BOMText] East of Flinders Island",
+ "http://www.bom.gov.au/tas/forecasts/eastflindersisland.shtml"
+ `to` "EastFlindersIsland.txt"),
+
+ ("[BOMText] Central North Coast",
+ "http://www.bom.gov.au/tas/forecasts/centralnorthcoast.shtml"
+ `to` "CentralNorthCoast.txt"),
+
+ ("[BOMText] Central West Coast",
+ "http://www.bom.gov.au/tas/forecasts/centralwestcoast.shtml"
+ `to` "CentralWestCoast.txt"),
+
+ ("[BOMText] Far North West Coast",
+ "http://www.bom.gov.au/tas/forecasts/farnorthwestcoast.shtml"
+ `to` "FarNorthWestCoast.txt"),
+
+ ("[BOMText] Lower East Coast",
+ "http://www.bom.gov.au/tas/forecasts/lowereastcoast.shtml"
+ `to` "LowerEastCoast.txt"),
+
+ ("[BOMText] Southeast Coast",
+ "http://www.bom.gov.au/tas/forecasts/southeastcoast.shtml"
+ `to` "SoutheastCoast.txt"),
+
+ ("[BOMText] Storm Bay",
+ "http://www.bom.gov.au/tas/forecasts/stormbay.shtml"
+ `to` "StormBay.txt"),
+
+ ("[BOMText] Southwest Coast",
+ "http://www.bom.gov.au/tas/forecasts/southwestcoast.shtml"
+ `to` "SouthwestCoast.txt"),
+
+ ("[BOMText] Upper East Coast",
+ "http://www.bom.gov.au/tas/forecasts/uppereastcoast.shtml"
+ `to` "UpperEastCoast.txt")
+ ]
A metscrape2/src/bin/MetscrapeVIC.hs => metscrape2/src/bin/MetscrapeVIC.hs +49 -0
@@ 0,0 1,49 @@
+-- metscrape - bulk-download weather forecasts.
+-- Copyright (C) 2013 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+import Menu
+import Scraper
+import Scrapers.BOM
+import Scrapers.BOMText
+
+to :: String -> FilePath -> Scraper
+url `to` path = Munge url transformXml $ "Weather/Vic/" ++ path
+
+main :: IO ()
+main = run [
+ ("[BOM] Victorian Winds",
+ scrapeMarineWind "vic" "Weather/Vic/Wind%02d.png"),
+
+ ("[BOMText] Central Coast",
+ "http://www.bom.gov.au/vic/forecasts/centralcoast.shtml"
+ `to` "CentralCoast.txt"),
+
+ ("[BOMText] Central Gippsland Coast",
+ "http://www.bom.gov.au/vic/forecasts/centralgippslandcoast.shtml"
+ `to` "CentralGippslandCoast.txt"),
+
+ ("[BOMText] East Gippsland Coast",
+ "http://www.bom.gov.au/vic/forecasts/eastgippslandcoast.shtml"
+ `to` "EastGippslandCoast.txt"),
+
+ ("[BOMText] Port Phillip",
+ "http://www.bom.gov.au/vic/forecasts/portphillip.shtml"
+ `to` "PortPhillip.txt"),
+
+ ("[BOMText] West Coast",
+ "http://www.bom.gov.au/vic/forecasts/westcoast.shtml"
+ `to` "WestCoast.txt")
+ ]
A => +65 -0
@@ 0,0 1,65 @@
-- metscrape - bulk-download weather forecasts.
-- Copyright (C) 2013 Jack Kelly <jack@jackkelly.name>
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
--
-- You should have received a copy of the GNU Affero General Public License
-- along with this program. If not, see <https://www.gnu.org/licenses/>.
module Menu (Menu, run) where
import Data.Char
import qualified Data.Map as Map
import Scraper
import System.IO
import Text.Printf
type Menu = [(String, Scraper)]
printItems :: Menu -> IO ()
printItems items =
let labels = zipWith (printf "%c) %s") ['A'..'Z'] (map fst items) in
mapM_ putStrLn labels
-- Return the menu entries that are actually selected.
menu :: Menu -> IO Menu
menu items = do
printItems items
putStr "\nEnter the options to grab, or * for all: "
hFlush stdout
line <- fmap (\str -> [ toUpper c | c <- str, c == '*' || isAlpha c ]) getLine
if '*' `elem` line
then return items
else do
let table = Map.fromList $ zip ['A' .. 'Z'] items
selected = filter (/= '*') line
return $ map (table Map.!) selected
fetch :: (String, Scraper) -> IO ()
fetch (label, scraper) = do
let line = replicate (length label) '='
putStrLn $ line
putStrLn $ label
putStrLn $ line
scrape scraper
copyright :: IO ()
copyright =
putStrLn "metscrape Copyright (C) 2013 Jack Kelly <jack@jackkelly.name>\n\
\This program comes with ABSOLUTELY NO WARRANTY.\n\
\This is free software, and you are welcome to redistribute it\n\
\under certain conditions; see the GNU Affero GPL version 3\n\
\(or later) for details.\n"
run :: Menu -> IO ()
run choices = do
copyright
menu choices >>= mapM_ fetch
A metscrape2/src/lib/Scraper.hs => metscrape2/src/lib/Scraper.hs +56 -0
@@ 0,0 1,56 @@
+-- metscrape - bulk-download weather forecasts.
+-- Copyright (C) 2013 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+module Scraper (Scraper(..), scrape) where
+
+import Control.Exception
+import qualified Data.ByteString as BS
+import Data.Maybe (fromMaybe)
+import Network.HTTP
+import Network.URI (parseURI)
+import System.Directory
+import System.FilePath
+import System.IO
+
+data Scraper = WGet [(String, FilePath)]
+ | IOWGet (IO [(String, FilePath)])
+ | Munge String (String -> IO String) FilePath
+
+scrape :: Scraper -> IO ()
+scrape (WGet files) = mapM_ scrapeOne files where
+ scrapeOne (url, path) = do
+ createDirectoryIfMissing True $ dropFileName path
+ putStrLn $ url ++ " -> " ++ path
+ get url >>= BS.writeFile path
+ get url = let uri = fromMaybe (error $ "Invalid URI: " ++ url) (parseURI url)
+ in
+ catch (simpleHTTP (defaultGETRequest_ uri) >>= getResponseBody)
+ (\e -> do
+ let msg = show (e :: IOException)
+ hPutStrLn stderr ("Warning: " ++ msg)
+ get url)
+scrape (IOWGet f) = f >>= (scrape . WGet)
+scrape (Munge url f path) = do
+ createDirectoryIfMissing True $ dropFileName path
+ putStrLn $ url ++ " -> " ++ path
+ let grabit = simpleHTTP (getRequest url)
+ >>= getResponseBody
+ >>= f
+ >>= writeFile path
+ let get = catch grabit (\e -> do let msg = show (e :: IOException)
+ hPutStrLn stderr ("Warning: " ++ msg)
+ get)
+ get
A metscrape2/src/lib/Scrapers/BOM.hs => metscrape2/src/lib/Scrapers/BOM.hs +81 -0
@@ 0,0 1,81 @@
+-- metscrape - bulk-download weather forecasts.
+-- Copyright (C) 2013 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+module Scrapers.BOM (scrapeInteractiveWeather,
+ scrapeMarineWind,
+ scrapeMSLPP,
+ scrapeSurfacePressureRainfall) where
+
+import Data.List
+import Data.Maybe (fromMaybe)
+import Network.HTTP
+import Network.URI (parseURI)
+import Text.Printf
+import Scraper
+
+-- From the BOM's Interactive Weather and Wave maps tool. productCode
+-- is something like "IDY30223" and productName is something like
+-- "sigWaveHgt".
+scrapeInteractiveWeather :: String -> String -> String -> Scraper
+scrapeInteractiveWeather code name pat
+ = WGet [ ( printf urlPattern n
+ , printf pat n
+ )
+ | n <- [0, 3..72] :: [Int]
+ ] where
+ urlPattern = "http://www.bom.gov.au/charts_data/" ++ code ++
+ "/current/" ++ munge name ++ "/" ++ code ++ "." ++ name ++
+ ".%03d.png"
+ munge str = [ if s == '-' then '/' else s | s <- str ]
+
+scrapeMSLPP :: Scraper
+scrapeMSLPP = WGet [( "http://www.bom.gov.au/fwo/IDG00074.gif"
+ , "Weather/BOM_MSLPP.gif"
+ )
+ ]
+
+scrapeMarineWind :: String -> String -> Scraper
+scrapeMarineWind loc pat = IOWGet $ do
+ let url = "http://www.bom.gov.au/marine/wind.shtml?"
+ ++ "unit=p0&location=" ++ loc ++ "&tz=AEDT"
+ let uri = fromMaybe
+ (error $ "Invalid URI: " ++ url) (parseURI url)
+
+ -- Hacky, but it works. For now.
+ text <- simpleHTTP (defaultGETRequest_ uri)
+ >>= getResponseBody
+ let urls = [ ("http://www.bom.gov.au" ++)
+ $ takeWhile (/= '"')
+ $ tail
+ $ dropWhile (/= '"') line | line <- lines text
+ , "url: \"" `isInfixOf` line]
+
+ let files = (printf
+ <$> [pat]
+ <*> ([1..] :: [Int])) :: [FilePath]
+ return $ zip urls files
+
+scrapeSurfacePressureRainfall :: Scraper
+scrapeSurfacePressureRainfall = WGet $ first ++ second where
+ first = [ (printf firstUrl n,
+ printf path n) | n <- [6, 12..72] :: [Int] ]
+ firstUrl = "http://www.bom.gov.au/charts_data/IDY20301/\
+ \current/mslp-precip/IDY20301.mslp-precip.%03d.png"
+ second = [ (printf secondUrl n,
+ printf path n)| n <- [78, 84..156] :: [Int] ]
+ secondUrl = "http://www.bom.gov.au/charts_data/IDY20002/\
+ \current/mslp-precip/IDY20002.mslp-precip.%03d.png"
+ path = "Weather/SurfacePressureRainfall%03d.png"
A metscrape2/src/lib/Scrapers/BOMText.hs => metscrape2/src/lib/Scrapers/BOMText.hs +71 -0
@@ 0,0 1,71 @@
+-- metscrape - bulk-download weather forecasts.
+-- Copyright (C) 2013 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+module Scrapers.BOMText (transformXml) where
+
+import Data.Tree.NTree.TypeDefs
+import Text
+import Text.XML.HXT.Core
+
+underline :: Char -> String -> String
+underline ch text = text ++ "\n" ++ replicate (length text) ch
+
+title :: IOSLA (XIOState ()) XmlTree (NTree XNode) -> IO String
+title doc = fmap ((++ "\n") . underline '=' . head) $ runX $
+ doc //> hasName "title" /> getText
+
+date :: IOSLA (XIOState ()) XmlTree (NTree XNode) -> IO String
+date doc = fmap ((++ "\n\n") . head) $ runX $
+ doc //> hasAttrValue "class" (== "date") //> getText
+
+synopsis :: IOSLA (XIOState ()) XmlTree (NTree XNode) -> IO String
+synopsis doc = fmap unlines $ runX $
+ doc //> hasAttrValue "class" (== "synopsis")
+ /> ((hasName "h2"
+ >>> processChildren (changeText $ underline '-'))
+ <+> (hasName "p"
+ >>> processChildren (changeText trim)))
+ /> getText
+
+days :: IOSLA (XIOState ()) XmlTree (NTree XNode) -> IO String
+days doc = fmap unlines $ runX $
+ doc //> hasAttrValue "class" (== "day")
+ /> ((hasName "h2"
+ >>> processChildren
+ (changeText $ ("\n" ++) . underline '-') /> getText)
+ <+> (hasAttrValue "class" (== "marine warning")
+ /> getText)
+ <+> ((getChildren
+ >>> ((hasName "dt" /> getText)
+ <+> (hasName "dd"
+ /> hasName "span"
+ /> getText))
+ >>> arr trim)
+ >>. merge)) where
+ merge [] = []
+ merge [s] = [s]
+ merge (s1:s2:ss) = (s1 ++ ": " ++ s2):merge ss
+
+warning :: IOSLA (XIOState ()) XmlTree (NTree XNode) -> IO String
+warning doc = fmap (("\n\n" ++) . concat) $ runX $
+ doc //> hasAttrValue "class" (== "preamble")
+ /> ((hasName "strong" /> changeText (++ ": ")) <+> isText)
+ >>> getText
+
+transformXml :: String -> IO String
+transformXml xml =
+ let doc = readString [ withParseHTML yes, withWarnings no ] xml
+ in concat <$> sequence [ f doc | f <- [title, date, synopsis, days, warning] ]
A metscrape2/src/lib/Scrapers/MetVUW.hs => metscrape2/src/lib/Scrapers/MetVUW.hs +65 -0
@@ 0,0 1,65 @@
+-- metscrape - bulk-download weather forecasts.
+-- Copyright (C) 2013 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+module Scrapers.MetVUW (scrapeMetVUW) where
+
+import Control.Exception
+import Data.List
+import Data.Maybe
+import Scraper
+import System.IO
+import Text.Printf
+import Text.XML.HXT.Core
+import Text.XML.HXT.HTTP
+
+forecastURL :: String -> String
+forecastURL region = "http://www.metvuw.com/forecast/forecast1.php"
+ ++ "?type=rain®ion=" ++ region ++ "&tim=06"
+
+forecastImageURL :: String -> String -> Int -> String
+forecastImageURL region date =
+ printf "http://www.metvuw.com/forecast/%s/rain-%s-%s-%02d.gif"
+ date region date
+
+-- Look for the image that's the actual weather forecast.
+imageDate :: [String] -> Maybe String
+imageDate images = listToMaybe [ x | x <- images, "rain-" `isInfixOf` x ]
+
+scrapeBase :: String -> IO (Maybe String)
+scrapeBase region = do
+ let url = forecastURL region
+ let grabit = runX (readDocument [ withHTTP [],
+ withParseHTML yes,
+ withWarnings no ] url
+ //>
+ hasName "img"
+ >>>
+ getAttrValue "src")
+ let get = catch grabit (\e -> do let msg = show (e :: IOException)
+ hPutStrLn stderr ("Warning: " ++ msg)
+ get)
+ images <- get
+ case imageDate images of
+ Nothing -> return Nothing
+ Just image -> return . Just . take 10 $ drop 2 image
+
+scrapeMetVUW :: String -> String -> Scraper
+scrapeMetVUW region pat = IOWGet $ do
+ maybeBase <- scrapeBase region
+ return $ case maybeBase of
+ Nothing -> []
+ Just base -> [ (forecastImageURL region base n,
+ printf pat n) | n <- [6, 12..180] ]
A metscrape2/src/lib/Text.hs => metscrape2/src/lib/Text.hs +22 -0
@@ 0,0 1,22 @@
+-- metscrape - bulk-download weather forecasts.
+-- Copyright (C) 2013 Jack Kelly <jack@jackkelly.name>
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU Affero 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 Affero General Public License for more details.
+--
+-- You should have received a copy of the GNU Affero General Public License
+-- along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+module Text where
+
+import Data.Char
+
+trim :: String -> String
+trim = f . f where f = reverse . (dropWhile isSpace)
A nix/nixpkgs.json => nix/nixpkgs.json +7 -0
@@ 0,0 1,7 @@
+{
+ "url": "https://github.com/NixOS/nixpkgs",
+ "rev": "47bd85469fbd507c12d8ec7f9650ab6dcbd8c274",
+ "date": "2019-11-02T09:20:40+01:00",
+ "sha256": "13vdwrjyp290z949769cjkfzy2dls00zqg3zyzbhz8y5xhhsq4wn",
+ "fetchSubmodules": false
+}
A nix/nixpkgs.nix => nix/nixpkgs.nix +8 -0
@@ 0,0 1,8 @@
+let
+ nixpkgsJson = builtins.fromJSON (builtins.readFile ./nixpkgs.json);
+ nixpkgsFunc = import (builtins.fetchTarball (with nixpkgsJson; {
+ url = "${url}/archive/${rev}.tar.gz";
+ inherit sha256;
+ }));
+in
+ nixpkgsFunc {}
A nix/update.bash => nix/update.bash +4 -0
@@ 0,0 1,4 @@
+#!/usr/bin/env nix-shell
+#!nix-shell -i bash -p nix-prefetch-git
+
+nix-prefetch-git https://github.com/NixOS/nixpkgs > nixpkgs.json
A photoscripts/README => photoscripts/README +2 -0
@@ 0,0 1,2 @@
+A few scripts I use to manage my photos. Everything in this directory
+is under WTFPL.
A photoscripts/downcase-all => photoscripts/downcase-all +4 -0
@@ 0,0 1,4 @@
+#!/bin/sh
+for f in *; do
+ mv $f `echo $f | tr '[A-Z]' '[a-z]'`
+done
A photoscripts/make-img-tags => photoscripts/make-img-tags +5 -0
@@ 0,0 1,5 @@
+#!/bin/sh
+dir=`basename $PWD`
+for f in *.jpg; do
+ echo "<img src=\"/blog/images/$dir/$f\" alt=\"\" />"
+done
A photoscripts/rename-all => photoscripts/rename-all +6 -0