commit be38c68b85ae02bf2f3facceda7325a483f2dbe4 Author: FliegendeWurst <2012gdwu+github@posteo.de> Date: Wed Sep 27 11:14:27 2023 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c24f4d3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +sensors*.db +x.csv \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..83c3240 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,140 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashlink" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d452c155cb93fecdfb02a73dd57b5d8e442c2063bd7aac72f1bc5e4263a43086" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "libsqlite3-sys" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f0455f2c1bc9a7caa792907026e469c1d91761fb0ea37cbb16427c77280cf35" +dependencies = [ + "pkg-config", + "vcpkg", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "pkg-config" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df8c4ec4b0627e53bdf214615ad287367e482558cf84b109250b37464dc03ae" + +[[package]] +name = "rusqlite" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01e213bc3ecb39ac32e81e51ebe31fd888a940515173e3a18a35f8c6e896422a" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + +[[package]] +name = "sensor-dashboard" +version = "1.0.0" +dependencies = [ + "rusqlite", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..2ab5df4 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "sensor-dashboard" +version = "1.0.0" +edition = "2018" +authors = ["Arne Keller "] +license = "AGPL-3.0-or-later" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rusqlite = "0.28.0" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..be3f7b2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + 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. + + + Copyright (C) + + 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 . + +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 +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..517b55e --- /dev/null +++ b/README.md @@ -0,0 +1,29 @@ +# sensor-dashboard + +Simple webpage to display gathered temperature and humidity data. + +## License + +### papaparse.js + +Source: https://github.com/mholt/PapaParse +License: MIT + +### uPlot + +Source: https://github.com/leeoniya/uPlot +License: MIT + +### This project + +Copyright © 2023 Arne Keller + +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. \ No newline at end of file diff --git a/base.js b/base.js new file mode 100644 index 0000000..00c8373 --- /dev/null +++ b/base.js @@ -0,0 +1,179 @@ +"use strict"; +let dataX = []; +let dataY = []; +let dataY2 = []; +let dataY3 = []; +let xMin = Number.MAX_SAFE_INTEGER; +let xMax = 0; + +function buttonsPlugin(opts) { + return { + hooks: { + ready: u => { + function zoomRange(seconds) { + u.setScale('x', { + min: xMax - seconds, + max: xMax + }); + } + + const day = document.getElementById("day"); + day.addEventListener("click", e => { + zoomRange(60 * 60 * 24); + }); + const week = document.getElementById("week"); + week.addEventListener("click", e => { + zoomRange(60 * 60 * 24 * 7); + }); + document.getElementById("all").addEventListener("click", e => { + u.setScale('x', { + min: xMin, + max: xMax + }); + }) + } + } + }; +} + +function processCSV() { + let plotData = [dataX, dataY, dataY2]; + let opts = { + title: "Temperature and humidity stats", + id: "chart1", + class: "my-chart", + width: document.getElementById("plot").clientWidth, + height: 600, + plugins: [ + buttonsPlugin({}) + ], + scales: { + x: { + time: true, + range: (u, dataMin, dataMax) => { + if ((dataMax - dataMin) % (60 * 60 * 24) === 0) { + return [dataMin, dataMax]; + } else { + return [dataMin, Math.ceil(dataMax / (24 * 60 * 60)) * 24 * 60 * 60]; + } + } + }, + y: { + auto: true, + // always show zero + // https://github.com/leeoniya/uPlot/issues/143#issuecomment-595251878 + /* + range: (u, dataMin, dataMax) => { + let [min, max] = uPlot.rangeNum(dataMin, dataMax, 0.2, true); + return [ + Math.min(0, min), + Math.max(0, max), + ]; + } + */ + }, + "%": { + //range: [0, 100] + auto: true, + }, + }, + series: [ + { + label: "t", + value: "{YYYY}-{MM}-{DD} {HH}:{mm}", + class: "monospace" + }, + { + label: "temperature", + class: "monospace", + width: 1, + stroke: `rgba(230, 180, 0, 100%)`, + drawStyle: 0, // line + lineInterpolation: 0, // linear + spanGaps: true, + //paths + }, + { + label: "relative humidity", + scale: "%", + class: "monospace", + width: 1, + stroke: `rgba(35, 50, 255, 100%)`, + drawStyle: 0, // line + lineInterpolation: 0, // linear + spanGaps: true, + //paths + }, + /* + { + label: "absolute humidity", + scale: "grams/m³", + class: "monospace", + width: 2, + stroke: `rgb(85, 100, 255)`, + drawStyle: 0, // line + lineInterpolation: 0, // linear + spanGaps: true, + //paths + } + */ + ], + axes: [ + { + //label: "Zeit", + labelSize: 20, + values: [[3600 * 24, "{D}.{M}.{YY}\n{H}:{mm}", null, null ]] + }, + { + space: 50, + scale: "%", + label: "RH", + }, + { + space: 50, + side: 1, + label: "°C", + }, + ], + }; + + document.getElementById("plot").innerHTML = ""; + let uplot = new uPlot(opts, plotData, document.getElementById("plot")); + uplot.setCursor({left: 10000, top: 0}); // show latest values instantly + uplot.cursor.lock = true; + let legendEl = document.querySelector(".u-legend"); + legendEl.classList.remove("u-inline"); + + document.getElementById("buttons").style.display = ""; + + // mobile view: activate 24h initially + setTimeout(() => { + const vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0) + const vh = Math.max(document.documentElement.clientHeight || 0, window.innerHeight || 0) + if (vh > vw) { + document.getElementById("day").click(); + } + }, 500); +} +Papa.parse('./x.csv', { + delimiter: ",", + header: true, + download: true, + step: function(row) { + if (row.errors.length > 0) { + return; + } + const t = Number(row.data["time"]); + dataX.push(t); + if (t > xMax) { + xMax = t; + } + if (t < xMin) { + xMin = t; + } + dataY.push(Number(row.data["celsius"]) / 10.0); + dataY2.push(Number(row.data["humidity"]) / 10.0); + //dataY3.push(Number(row.data["abs_humidity"])); + }, + complete: processCSV, +}); \ No newline at end of file diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..326ed10 Binary files /dev/null and b/favicon.ico differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..65c9e2d --- /dev/null +++ b/index.html @@ -0,0 +1,40 @@ + + + + + Sensor dashboard + + + + + + + +
+ + + + + + diff --git a/papaparse.js b/papaparse.js new file mode 100644 index 0000000..a92afc1 --- /dev/null +++ b/papaparse.js @@ -0,0 +1,7 @@ +/* @license +Papa Parse +v5.3.0 +https://github.com/mholt/PapaParse +License: MIT +*/ +!function(e,t){"function"==typeof define&&define.amd?define([],t):"object"==typeof module&&"undefined"!=typeof exports?module.exports=t():e.Papa=t()}(this,function s(){"use strict";var f="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==f?f:{};var n=!f.document&&!!f.postMessage,o=n&&/blob:/i.test((f.location||{}).protocol),a={},h=0,b={parse:function(e,t){var i=(t=t||{}).dynamicTyping||!1;U(i)&&(t.dynamicTypingFunction=i,i={});if(t.dynamicTyping=i,t.transform=!!U(t.transform)&&t.transform,t.worker&&b.WORKERS_SUPPORTED){var r=function(){if(!b.WORKERS_SUPPORTED)return!1;var e=(i=f.URL||f.webkitURL||null,r=s.toString(),b.BLOB_URL||(b.BLOB_URL=i.createObjectURL(new Blob(["(",r,")();"],{type:"text/javascript"})))),t=new f.Worker(e);var i,r;return t.onmessage=m,t.id=h++,a[t.id]=t}();return r.userStep=t.step,r.userChunk=t.chunk,r.userComplete=t.complete,r.userError=t.error,t.step=U(t.step),t.chunk=U(t.chunk),t.complete=U(t.complete),t.error=U(t.error),delete t.worker,void r.postMessage({input:e,config:t,workerId:r.id})}var n=null;b.NODE_STREAM_INPUT,"string"==typeof e?n=t.download?new l(t):new p(t):!0===e.readable&&U(e.read)&&U(e.on)?n=new g(t):(f.File&&e instanceof File||e instanceof Object)&&(n=new c(t));return n.stream(e)},unparse:function(e,t){var n=!1,m=!0,_=",",v="\r\n",s='"',a=s+s,i=!1,r=null,o=!1;!function(){if("object"!=typeof t)return;"string"!=typeof t.delimiter||b.BAD_DELIMITERS.filter(function(e){return-1!==t.delimiter.indexOf(e)}).length||(_=t.delimiter);("boolean"==typeof t.quotes||"function"==typeof t.quotes||Array.isArray(t.quotes))&&(n=t.quotes);"boolean"!=typeof t.skipEmptyLines&&"string"!=typeof t.skipEmptyLines||(i=t.skipEmptyLines);"string"==typeof t.newline&&(v=t.newline);"string"==typeof t.quoteChar&&(s=t.quoteChar);"boolean"==typeof t.header&&(m=t.header);if(Array.isArray(t.columns)){if(0===t.columns.length)throw new Error("Option columns is empty");r=t.columns}void 0!==t.escapeChar&&(a=t.escapeChar+s);"boolean"==typeof t.escapeFormulae&&(o=t.escapeFormulae)}();var h=new RegExp(q(s),"g");"string"==typeof e&&(e=JSON.parse(e));if(Array.isArray(e)){if(!e.length||Array.isArray(e[0]))return f(null,e,i);if("object"==typeof e[0])return f(r||u(e[0]),e,i)}else if("object"==typeof e)return"string"==typeof e.data&&(e.data=JSON.parse(e.data)),Array.isArray(e.data)&&(e.fields||(e.fields=e.meta&&e.meta.fields),e.fields||(e.fields=Array.isArray(e.data[0])?e.fields:u(e.data[0])),Array.isArray(e.data[0])||"object"==typeof e.data[0]||(e.data=[e.data])),f(e.fields||[],e.data||[],i);throw new Error("Unable to serialize unrecognized input");function u(e){if("object"!=typeof e)return[];var t=[];for(var i in e)t.push(i);return t}function f(e,t,i){var r="";"string"==typeof e&&(e=JSON.parse(e)),"string"==typeof t&&(t=JSON.parse(t));var n=Array.isArray(e)&&0=this._config.preview;if(o)f.postMessage({results:n,workerId:b.WORKER_ID,finished:a});else if(U(this._config.chunk)&&!t){if(this._config.chunk(n,this._handle),this._handle.paused()||this._handle.aborted())return void(this._halted=!0);n=void 0,this._completeResults=void 0}return this._config.step||this._config.chunk||(this._completeResults.data=this._completeResults.data.concat(n.data),this._completeResults.errors=this._completeResults.errors.concat(n.errors),this._completeResults.meta=n.meta),this._completed||!a||!U(this._config.complete)||n&&n.meta.aborted||(this._config.complete(this._completeResults,this._input),this._completed=!0),a||n&&n.meta.paused||this._nextChunk(),n}this._halted=!0},this._sendError=function(e){U(this._config.error)?this._config.error(e):o&&this._config.error&&f.postMessage({workerId:b.WORKER_ID,error:e,finished:!1})}}function l(e){var r;(e=e||{}).chunkSize||(e.chunkSize=b.RemoteChunkSize),u.call(this,e),this._nextChunk=n?function(){this._readChunk(),this._chunkLoaded()}:function(){this._readChunk()},this.stream=function(e){this._input=e,this._nextChunk()},this._readChunk=function(){if(this._finished)this._chunkLoaded();else{if(r=new XMLHttpRequest,this._config.withCredentials&&(r.withCredentials=this._config.withCredentials),n||(r.onload=y(this._chunkLoaded,this),r.onerror=y(this._chunkError,this)),r.open(this._config.downloadRequestBody?"POST":"GET",this._input,!n),this._config.downloadRequestHeaders){var e=this._config.downloadRequestHeaders;for(var t in e)r.setRequestHeader(t,e[t])}if(this._config.chunkSize){var i=this._start+this._config.chunkSize-1;r.setRequestHeader("Range","bytes="+this._start+"-"+i)}try{r.send(this._config.downloadRequestBody)}catch(e){this._chunkError(e.message)}n&&0===r.status&&this._chunkError()}},this._chunkLoaded=function(){4===r.readyState&&(r.status<200||400<=r.status?this._chunkError():(this._start+=this._config.chunkSize?this._config.chunkSize:r.responseText.length,this._finished=!this._config.chunkSize||this._start>=function(e){var t=e.getResponseHeader("Content-Range");if(null===t)return-1;return parseInt(t.substring(t.lastIndexOf("/")+1))}(r),this.parseChunk(r.responseText)))},this._chunkError=function(e){var t=r.statusText||e;this._sendError(new Error(t))}}function c(e){var r,n;(e=e||{}).chunkSize||(e.chunkSize=b.LocalChunkSize),u.call(this,e);var s="undefined"!=typeof FileReader;this.stream=function(e){this._input=e,n=e.slice||e.webkitSlice||e.mozSlice,s?((r=new FileReader).onload=y(this._chunkLoaded,this),r.onerror=y(this._chunkError,this)):r=new FileReaderSync,this._nextChunk()},this._nextChunk=function(){this._finished||this._config.preview&&!(this._rowCount=this._input.size,this.parseChunk(e.target.result)},this._chunkError=function(){this._sendError(r.error)}}function p(e){var i;u.call(this,e=e||{}),this.stream=function(e){return i=e,this._nextChunk()},this._nextChunk=function(){if(!this._finished){var e,t=this._config.chunkSize;return t?(e=i.substring(0,t),i=i.substring(t)):(e=i,i=""),this._finished=!i,this.parseChunk(e)}}}function g(e){u.call(this,e=e||{});var t=[],i=!0,r=!1;this.pause=function(){u.prototype.pause.apply(this,arguments),this._input.pause()},this.resume=function(){u.prototype.resume.apply(this,arguments),this._input.resume()},this.stream=function(e){this._input=e,this._input.on("data",this._streamData),this._input.on("end",this._streamEnd),this._input.on("error",this._streamError)},this._checkIsFinished=function(){r&&1===t.length&&(this._finished=!0)},this._nextChunk=function(){this._checkIsFinished(),t.length?this.parseChunk(t.shift()):i=!0},this._streamData=y(function(e){try{t.push("string"==typeof e?e:e.toString(this._config.encoding)),i&&(i=!1,this._checkIsFinished(),this.parseChunk(t.shift()))}catch(e){this._streamError(e)}},this),this._streamError=y(function(e){this._streamCleanUp(),this._sendError(e)},this),this._streamEnd=y(function(){this._streamCleanUp(),r=!0,this._streamData("")},this),this._streamCleanUp=y(function(){this._input.removeListener("data",this._streamData),this._input.removeListener("end",this._streamEnd),this._input.removeListener("error",this._streamError)},this)}function i(_){var a,o,h,r=Math.pow(2,53),n=-r,s=/^\s*-?(\d+\.?|\.\d+|\d+\.\d+)(e[-+]?\d+)?\s*$/,u=/(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))/,t=this,i=0,f=0,d=!1,e=!1,l=[],c={data:[],errors:[],meta:{}};if(U(_.step)){var p=_.step;_.step=function(e){if(c=e,m())g();else{if(g(),0===c.data.length)return;i+=e.data.length,_.preview&&i>_.preview?o.abort():(c.data=c.data[0],p(c,t))}}}function v(e){return"greedy"===_.skipEmptyLines?""===e.join("").trim():1===e.length&&0===e[0].length}function g(){if(c&&h&&(k("Delimiter","UndetectableDelimiter","Unable to auto-detect delimiting character; defaulted to '"+b.DefaultDelimiter+"'"),h=!1),_.skipEmptyLines)for(var e=0;e=l.length?"__parsed_extra":l[i]),_.transform&&(s=_.transform(s,n)),s=y(n,s),"__parsed_extra"===n?(r[n]=r[n]||[],r[n].push(s)):r[n]=s}return _.header&&(i>l.length?k("FieldMismatch","TooManyFields","Too many fields: expected "+l.length+" fields but parsed "+i,f+t):i=r.length/2?"\r\n":"\r"}(e,r)),h=!1,_.delimiter)U(_.delimiter)&&(_.delimiter=_.delimiter(e),c.meta.delimiter=_.delimiter);else{var n=function(e,t,i,r,n){var s,a,o,h;n=n||[",","\t","|",";",b.RECORD_SEP,b.UNIT_SEP];for(var u=0;u=L)return R(!0)}else for(_=M,M++;;){if(-1===(_=a.indexOf(O,_+1)))return i||u.push({type:"Quotes",code:"MissingQuotes",message:"Quoted field unterminated",row:h.length,index:M}),E();if(_===r-1)return E(a.substring(M,_).replace(m,O));if(O!==z||a[_+1]!==z){if(O===z||0===_||a[_-1]!==z){-1!==p&&p<_+1&&(p=a.indexOf(D,_+1)),-1!==g&&g<_+1&&(g=a.indexOf(I,_+1));var y=w(-1===g?p:Math.min(p,g));if(a[_+1+y]===D){f.push(a.substring(M,_).replace(m,O)),a[M=_+1+y+e]!==O&&(_=a.indexOf(O,M)),p=a.indexOf(D,M),g=a.indexOf(I,M);break}var k=w(g);if(a.substring(_+1+k,_+1+k+n)===I){if(f.push(a.substring(M,_).replace(m,O)),C(_+1+k+n),p=a.indexOf(D,M),_=a.indexOf(O,M),o&&(S(),j))return R();if(L&&h.length>=L)return R(!0);break}u.push({type:"Quotes",code:"InvalidQuotes",message:"Trailing quote on quoted field is malformed",row:h.length,index:M}),_++}}else _++}return E();function b(e){h.push(e),d=M}function w(e){var t=0;if(-1!==e){var i=a.substring(_+1,e);i&&""===i.trim()&&(t=i.length)}return t}function E(e){return i||(void 0===e&&(e=a.substring(M)),f.push(e),M=r,b(f),o&&S()),R()}function C(e){M=e,b(f),f=[],g=a.indexOf(I,M)}function R(e){return{data:h,errors:u,meta:{delimiter:D,linebreak:I,aborted:j,truncated:!!e,cursor:d+(t||0)}}}function S(){A(R()),h=[],u=[]}function x(e,t,i){var r={nextDelim:void 0,quoteSearch:void 0},n=a.indexOf(O,t+1);if(t /run/user/pi/x.csv'])) + super().do_GET() + +# derived from: https://github.com/python/cpython/blob/3.11/Lib/http/server.py +if __name__ == '__main__': + import contextlib + + handler_class = RefreshingHandler + directory = os.getcwd() + + # ensure dual-stack is not disabled; ref #38907 + class DualStackServer(http.server.ThreadingHTTPServer): + + def server_bind(self): + # suppress exception when protocol is IPv4 + with contextlib.suppress(Exception): + self.socket.setsockopt( + socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0) + return super().server_bind() + + def finish_request(self, request, client_address): + self.RequestHandlerClass(request, client_address, self, + directory=directory) + + http.server.test( + HandlerClass=handler_class, + ServerClass=DualStackServer, + port=24473, + bind=None, + protocol="HTTP/1.1", + ) diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..1dea627 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,58 @@ +use rusqlite::Connection; + +fn main() { + let db = Connection::open("sensors.db").unwrap(); + let mut get_values = db.prepare("SELECT time,celsius,humidity FROM sensor_readings ORDER BY time ASC").unwrap(); + let mut values = get_values + .query_map([], |row| Ok((row.get(0).unwrap(), row.get(1).unwrap(), row.get(2).unwrap(), true))) + .unwrap() + .map(Result::unwrap) + .collect::>(); + values[0].3 = false; + // exclude clearly wrong values + let window_size = 8; + for i in window_size..values.len() { + let avg = values[i-window_size..i].iter().map(|x| x.1).sum::() / window_size as i64; + if avg.abs_diff(values[i].1) >= 40 && (i == 0 || values[i].0 - values[i-1].0 < 5000000) && i < values.len() - 5 { + values[i].3 = false; + } + } + // exclude outliers (> X °C diff and not between consecutive values) + // remember, measurements are done once every 10 minutes + // it is unlikely the temp. will sway by 2.4 ° C in that timeframe + windows_mut_each(&mut values, 3, |vars| { + if vars[1].0 - vars[0].0 >= 5000000 { + return; + } + if vars[1].1.abs_diff(vars[0].1) >= 19 && vars[1].1 > vars[0].1 && vars[1].1 > vars[2].1 { + vars[1].3 = false; + } + // spike down + if vars[1].1.abs_diff(vars[0].1) >= 19 && vars[1].1 < vars[0].1 && vars[1].1 < vars[2].1 { + vars[1].3 = false; + } + // check for humidity too + if vars[1].2.abs_diff(vars[0].2) >= 30 && vars[1].2.abs_diff(vars[2].2) >= 30 { + vars[1].3 = false; + } + }); + println!("time,humidity,celsius"); // ,abs_humidity + for (time, celsius, rh, keep) in values { + if keep { + //let t = celsius as f64 / 10.0; + //let ah = (6.112 * E.powf((17.67 * t)/(t + 243.5)) * (rh as f64 * 10.0) * 2.1674) / (273.15 + t); + println!("{},{},{}", time, rh, celsius);//, ah); + } + } +} + +// https://users.rust-lang.org/t/iterator-over-mutable-windows-of-slice/17110/6 +fn windows_mut_each(v: &mut [T], n: usize, mut f: impl FnMut(&mut [T])) { + let mut start = 0; + let mut end = n; + while end <= v.len() { + f(&mut v[start..end]); + start += 1; + end += 1; + } +} \ No newline at end of file diff --git a/uPlot.iife.min.js b/uPlot.iife.min.js new file mode 100644 index 0000000..ee4ea40 --- /dev/null +++ b/uPlot.iife.min.js @@ -0,0 +1,2 @@ +/*! https://github.com/leeoniya/uPlot (v1.6.22) */ +var uPlot=function(){"use strict";const e="u-off",t="u-label",l="width",n="height",i="top",o="bottom",s="left",r="right",u="#000",a="mousemove",f="mousedown",c="mouseup",h="mouseenter",d="mouseleave",p="dblclick",m="change",g="dppxchange",x="undefined"!=typeof window,w=x?document:null,_=x?window:null,b=x?navigator:null;let k,v;function y(e,t){if(null!=t){let l=e.classList;!l.contains(t)&&l.add(t)}}function M(e,t){let l=e.classList;l.contains(t)&&l.remove(t)}function S(e,t,l){e.style[t]=l+"px"}function E(e,t,l,n){let i=w.createElement(e);return null!=t&&y(i,t),null!=l&&l.insertBefore(i,n),i}function D(e,t){return E("div",e,t)}const z=new WeakMap;function T(t,l,n,i,o){let s="translate("+l+"px,"+n+"px)";s!=z.get(t)&&(t.style.transform=s,z.set(t,s),0>l||0>n||l>i||n>o?y(t,e):M(t,e))}const P=new WeakMap;function A(e,t,l){let n=t+l;n!=P.get(e)&&(P.set(e,n),e.style.background=t,e.style.borderColor=l)}const W=new WeakMap;function Y(e,t,l,n){let i=t+""+l;i!=W.get(e)&&(W.set(e,i),e.style.height=l+"px",e.style.width=t+"px",e.style.marginLeft=n?-t/2+"px":0,e.style.marginTop=n?-l/2+"px":0)}const C={passive:!0},F={...C,capture:!0};function H(e,t,l,n){t.addEventListener(e,l,n?F:C)}function R(e,t,l,n){t.removeEventListener(e,l,n?F:C)}function G(e,t,l,n){let i;l=l||0;let o=2147483647>=(n=n||t.length-1);for(;n-l>1;)i=o?l+n>>1:te((l+n)/2),e>t[i]?l=i:n=i;return e-t[l]>t[n]-e?n:l}function L(e,t,l,n){for(let i=1==n?t:l;i>=t&&l>=i;i+=n)if(null!=e[i])return i;return-1}x&&function e(){let t=devicePixelRatio;k!=t&&(k=t,v&&R(m,v,e),v=matchMedia(`(min-resolution: ${k-.001}dppx) and (max-resolution: ${k+.001}dppx)`),H(m,v,e),_.dispatchEvent(new CustomEvent(g)))}();const O=[0,0];function I(e,t,l,n){return O[0]=0>l?ye(e,-l):e,O[1]=0>n?ye(t,-n):t,O}function j(e,t,l,n){let i,o,s,r=re(e),u=10==l?ue:ae;return e==t&&(-1==r?(e*=l,t/=l):(e/=l,t*=l)),n?(i=te(u(e)),o=ne(u(t)),s=I(se(l,i),se(l,o),i,o),e=s[0],t=s[1]):(i=te(u(ee(e))),o=te(u(ee(t))),s=I(se(l,i),se(l,o),i,o),e=ve(e,s[0]),t=ke(t,s[1])),[e,t]}function N(e,t,l,n){let i=j(e,t,l,n);return 0==e&&(i[0]=0),0==t&&(i[1]=0),i}const U={mode:3,pad:.1},B={pad:0,soft:null,mode:0},V={min:B,max:B};function J(e,t,l,n){return We(l)?K(e,t,l):(B.pad=l,B.soft=n?0:null,B.mode=n?3:0,K(e,t,V))}function q(e,t){return null==e?t:e}function K(e,t,l){let n=l.min,i=l.max,o=q(n.pad,0),s=q(i.pad,0),r=q(n.hard,-ce),u=q(i.hard,ce),a=q(n.soft,ce),f=q(i.soft,-ce),c=q(n.mode,0),h=q(i.mode,0),d=t-e;1e-9>d&&(d=0,0!=e&&0!=t||(d=1e-9,2==c&&a!=ce&&(o=0),2==h&&f!=-ce&&(s=0)));let p=d||ee(t)||1e3,m=ue(p),g=se(10,te(m)),x=ye(ve(e-p*(0==d?0==e?.1:1:o),g/10),9),w=a>e||1!=c&&(3!=c||x>a)&&(2!=c||a>x)?ce:a,_=oe(r,w>x&&e>=w?w:ie(w,x)),b=ye(ke(t+p*(0==d?0==t?.1:1:s),g/10),9),k=t>f||1!=h&&(3!=h||f>b)&&(2!=h||b>f)?-ce:f,v=ie(u,b>k&&k>=t?k:oe(k,b));return _==v&&0==_&&(v=100),[_,v]}const Z=new Intl.NumberFormat(x?b.language:"en-US"),$=e=>Z.format(e),X=Math,Q=X.PI,ee=X.abs,te=X.floor,le=X.round,ne=X.ceil,ie=X.min,oe=X.max,se=X.pow,re=X.sign,ue=X.log10,ae=X.log2,fe=(e,t=1)=>X.asinh(e/t),ce=1/0;function he(e){return 1+(0|ue((e^e>>31)-(e>>31)))}function de(e,t){return le(e/t)*t}function pe(e,t,l){return ie(oe(e,t),l)}function me(e){return"function"==typeof e?e:()=>e}const ge=e=>e,xe=(e,t)=>t,we=()=>null,_e=()=>!0,be=(e,t)=>e==t;function ke(e,t){return ne(e/t)*t}function ve(e,t){return te(e/t)*t}function ye(e,t){return le(e*(t=10**t))/t}const Me=new Map;function Se(e){return((""+e).split(".")[1]||"").length}function Ee(e,t,l,n){let i=[],o=n.map(Se);for(let s=t;l>s;s++){let t=ee(s),l=ye(se(e,s),t);for(let e=0;n.length>e;e++){let r=n[e]*l,u=(0>r||0>s?t:0)+(o[e]>s?o[e]:0),a=ye(r,u);i.push(a),Me.set(a,u)}}return i}const De={},ze=[],Te=[null,null],Pe=Array.isArray;function Ae(e){return"string"==typeof e}function We(e){let t=!1;if(null!=e){let l=e.constructor;t=null==l||l==Object}return t}function Ye(e){return null!=e&&"object"==typeof e}const Ce=Object.getPrototypeOf(Uint8Array);function Fe(e,t=We){let l;if(Pe(e)){let n=e.find((e=>null!=e));if(Pe(n)||t(n)){l=Array(e.length);for(let n=0;e.length>n;n++)l[n]=Fe(e[n],t)}else l=e.slice()}else if(e instanceof Ce)l=e.slice();else if(t(e)){l={};for(let n in e)l[n]=Fe(e[n],t)}else l=e;return l}function He(e){let t=arguments;for(let l=1;t.length>l;l++){let n=t[l];for(let t in n)We(e[t])?He(e[t],Fe(n[t])):e[t]=Fe(n[t])}return e}function Re(e,t,l){for(let n,i=0,o=-1;t.length>i;i++){let s=t[i];if(s>o){for(n=s-1;n>=0&&null==e[n];)e[n--]=null;for(n=s+1;l>n&&null==e[n];)e[o=n++]=null}}}const Ge="undefined"==typeof queueMicrotask?e=>Promise.resolve().then(e):queueMicrotask,Le=["January","February","March","April","May","June","July","August","September","October","November","December"],Oe=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];function Ie(e){return e.slice(0,3)}const je=Oe.map(Ie),Ne=Le.map(Ie),Ue={MMMM:Le,MMM:Ne,WWWW:Oe,WWW:je};function Be(e){return(10>e?"0":"")+e}const Ve={YYYY:e=>e.getFullYear(),YY:e=>(e.getFullYear()+"").slice(2),MMMM:(e,t)=>t.MMMM[e.getMonth()],MMM:(e,t)=>t.MMM[e.getMonth()],MM:e=>Be(e.getMonth()+1),M:e=>e.getMonth()+1,DD:e=>Be(e.getDate()),D:e=>e.getDate(),WWWW:(e,t)=>t.WWWW[e.getDay()],WWW:(e,t)=>t.WWW[e.getDay()],HH:e=>Be(e.getHours()),H:e=>e.getHours(),h:e=>{let t=e.getHours();return 0==t?12:t>12?t-12:t},AA:e=>12>e.getHours()?"AM":"PM",aa:e=>12>e.getHours()?"am":"pm",a:e=>12>e.getHours()?"a":"p",mm:e=>Be(e.getMinutes()),m:e=>e.getMinutes(),ss:e=>Be(e.getSeconds()),s:e=>e.getSeconds(),fff:e=>function(e){return(10>e?"00":100>e?"0":"")+e}(e.getMilliseconds())};function Je(e,t){t=t||Ue;let l,n=[],i=/\{([a-z]+)\}|[^{]+/gi;for(;l=i.exec(e);)n.push("{"==l[0][0]?Ve[l[1]]:l[0]);return e=>{let l="";for(let i=0;n.length>i;i++)l+="string"==typeof n[i]?n[i]:n[i](e,t);return l}}const qe=(new Intl.DateTimeFormat).resolvedOptions().timeZone,Ke=e=>e%1==0,Ze=[1,2,2.5,5],$e=Ee(10,-16,0,Ze),Xe=Ee(10,0,16,Ze),Qe=Xe.filter(Ke),et=$e.concat(Xe),tt="{YYYY}",lt="\n"+tt,nt="{M}/{D}",it="\n"+nt,ot=it+"/{YY}",st="{aa}",rt="{h}:{mm}"+st,ut="\n"+rt,at=":{ss}",ft=null;function ct(e){let t=1e3*e,l=60*t,n=60*l,i=24*n,o=30*i,s=365*i;return[(1==e?Ee(10,0,3,Ze).filter(Ke):Ee(10,-3,0,Ze)).concat([t,5*t,10*t,15*t,30*t,l,5*l,10*l,15*l,30*l,n,2*n,3*n,4*n,6*n,8*n,12*n,i,2*i,3*i,4*i,5*i,6*i,7*i,8*i,9*i,10*i,15*i,o,2*o,3*o,4*o,6*o,s,2*s,5*s,10*s,25*s,50*s,100*s]),[[s,tt,ft,ft,ft,ft,ft,ft,1],[28*i,"{MMM}",lt,ft,ft,ft,ft,ft,1],[i,nt,lt,ft,ft,ft,ft,ft,1],[n,"{h}"+st,ot,ft,it,ft,ft,ft,1],[l,rt,ot,ft,it,ft,ft,ft,1],[t,at,ot+" "+rt,ft,it+" "+rt,ft,ut,ft,1],[e,at+".{fff}",ot+" "+rt,ft,it+" "+rt,ft,ut,ft,1]],function(t){return(r,u,a,f,c,h)=>{let d=[],p=c>=s,m=c>=o&&s>c,g=t(a),x=ye(g*e,3),w=bt(g.getFullYear(),p?0:g.getMonth(),m||p?1:g.getDate()),_=ye(w*e,3);if(m||p){let l=m?c/o:0,n=p?c/s:0,i=x==_?x:ye(bt(w.getFullYear()+n,w.getMonth()+l,1)*e,3),r=new Date(le(i/e)),u=r.getFullYear(),a=r.getMonth();for(let o=0;f>=i;o++){let s=bt(u+n*o,a+l*o,1),r=s-t(ye(s*e,3));i=ye((+s+r)*e,3),i>f||d.push(i)}}else{let o=i>c?c:i,s=_+(te(a)-te(x))+ke(x-_,o);d.push(s);let p=t(s),m=p.getHours()+p.getMinutes()/l+p.getSeconds()/n,g=c/n,w=h/r.axes[u]._space;for(;s=ye(s+c,1==e?0:3),f>=s;)if(g>1){let e=te(ye(m+g,6))%24,l=t(s).getHours()-e;l>1&&(l=-1),s-=l*n,m=(m+g)%24,.7>ye((s-d[d.length-1])/c,3)*w||d.push(s)}else d.push(s)}return d}}]}const[ht,dt,pt]=ct(1),[mt,gt,xt]=ct(.001);function wt(e,t){return e.map((e=>e.map(((l,n)=>0==n||8==n||null==l?l:t(1==n||0==e[8]?l:e[1]+l)))))}function _t(e,t){return(l,n,i,o,s)=>{let r,u,a,f,c,h,d=t.find((e=>s>=e[0]))||t[t.length-1];return n.map((t=>{let l=e(t),n=l.getFullYear(),i=l.getMonth(),o=l.getDate(),s=l.getHours(),p=l.getMinutes(),m=l.getSeconds(),g=n!=r&&d[2]||i!=u&&d[3]||o!=a&&d[4]||s!=f&&d[5]||p!=c&&d[6]||m!=h&&d[7]||d[1];return r=n,u=i,a=o,f=s,c=p,h=m,g(l)}))}}function bt(e,t,l){return new Date(e,t,l)}function kt(e,t){return t(e)}function vt(e,t){return(l,n)=>t(e(n))}Ee(2,-53,53,[1]);const yt={show:!0,live:!0,isolate:!1,markers:{show:!0,width:2,stroke:function(e,t){let l=e.series[t];return l.width?l.stroke(e,t):l.points.width?l.points.stroke(e,t):null},fill:function(e,t){return e.series[t].fill(e,t)},dash:"solid"},idx:null,idxs:null,values:[]},Mt=[0,0];function St(e,t,l){return e=>{0==e.button&&l(e)}}function Et(e,t,l){return l}const Dt={show:!0,x:!0,y:!0,lock:!1,move:function(e,t,l){return Mt[0]=t,Mt[1]=l,Mt},points:{show:function(e,t){let i=e.cursor.points,o=D(),s=i.size(e,t);S(o,l,s),S(o,n,s);let r=s/-2;S(o,"marginLeft",r),S(o,"marginTop",r);let u=i.width(e,t,s);return u&&S(o,"borderWidth",u),o},size:function(e,t){return Jt(e.series[t].points.width,1)},width:0,stroke:function(e,t){let l=e.series[t].points;return l._stroke||l._fill},fill:function(e,t){let l=e.series[t].points;return l._fill||l._stroke}},bind:{mousedown:St,mouseup:St,click:St,dblclick:St,mousemove:Et,mouseleave:Et,mouseenter:Et},drag:{setScale:!0,x:!0,y:!1,dist:0,uni:null,_x:!1,_y:!1},focus:{prox:-1},left:-10,top:-10,idx:null,dataIdx:function(e,t,l){return l},idxs:null},zt={show:!0,stroke:"rgba(0,0,0,0.07)",width:2},Tt=He({},zt,{filter:xe}),Pt=He({},Tt,{size:10}),At=He({},zt,{show:!1}),Wt='12px system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',Yt="bold "+Wt,Ct={show:!0,scale:"x",stroke:u,space:50,gap:5,size:50,labelGap:0,labelSize:30,labelFont:Yt,side:2,grid:Tt,ticks:Pt,border:At,font:Wt,rotate:0},Ft={show:!0,scale:"x",auto:!1,sorted:1,min:ce,max:-ce,idxs:[]};function Ht(e,t){return t.map((e=>null==e?"":$(e)))}function Rt(e,t,l,n,i,o,s){let r=[],u=Me.get(i)||0;for(let e=l=s?l:ye(ke(l,i),u);n>=e;e=ye(e+i,u))r.push(Object.is(e,-0)?0:e);return r}function Gt(e,t,l,n,i){const o=[],s=e.scales[e.axes[t].scale].log,r=te((10==s?ue:ae)(l));i=se(s,r),0>r&&(i=ye(i,-r));let u=l;do{o.push(u),u=ye(u+i,Me.get(i)),i*s>u||(i=u)}while(n>=u);return o}function Lt(e,t,l,n,i){let o=e.scales[e.axes[t].scale].asinh,s=n>o?Gt(e,t,oe(o,l),n,i):[o],r=0>n||l>0?[]:[0];return(-o>l?Gt(e,t,oe(o,-n),-l,i):[o]).reverse().map((e=>-e)).concat(r,s)}const Ot=/./,It=/[12357]/,jt=/[125]/,Nt=/1/;function Ut(e,t,l){let n=e.axes[l],i=n.scale,o=e.scales[i];if(3==o.distr&&2==o.log)return t;let s=e.valToPos,r=n._space,u=s(10,i),a=s(9,i)-u4==o.distr&&0==e||a.test(e)?e:null))}function Bt(e,t){return null==t?"":$(t)}const Vt={show:!0,scale:"y",stroke:u,space:30,gap:5,size:50,labelGap:0,labelSize:30,labelFont:Yt,side:3,grid:Tt,ticks:Pt,border:At,font:Wt,rotate:0};function Jt(e,t){return ye((3+2*(e||1))*t,3)}const qt={scale:null,auto:!0,sorted:0,min:ce,max:-ce},Kt={show:!0,auto:!0,sorted:0,alpha:1,facets:[He({},qt,{scale:"x"}),He({},qt,{scale:"y"})]},Zt={scale:"y",auto:!0,sorted:0,show:!0,spanGaps:!1,gaps:(e,t,l,n,i)=>i,alpha:1,points:{show:function(e,t){let{scale:l,idxs:n}=e.series[0],i=e._data[0],o=e.valToPos(i[n[0]],l,!0),s=e.valToPos(i[n[1]],l,!0);return ee(s-o)/(e.series[t].points.space*k)>=n[1]-n[0]},filter:null},values:null,min:ce,max:-ce,idxs:[],path:null,clip:null};function $t(e,t,l){return l/10}const Xt={time:!0,auto:!0,distr:1,log:10,asinh:1,min:null,max:null,dir:1,ori:0},Qt=He({},Xt,{time:!1,ori:1}),el={};function tl(e){let t=el[e];return t||(t={key:e,plots:[],sub(e){t.plots.push(e)},unsub(e){t.plots=t.plots.filter((t=>t!=e))},pub(e,l,n,i,o,s,r){for(let u=0;t.plots.length>u;u++)t.plots[u]!=l&&t.plots[u].pub(e,l,n,i,o,s,r)}},null!=e&&(el[e]=t)),t}function ll(e,t,l){const n=e.series[t],i=e.scales,o=e.bbox;let s=e._data[0],r=e._data[t],u=2==e.mode?i[n.facets[0].scale]:i[e.series[0].scale],a=2==e.mode?i[n.facets[1].scale]:i[n.scale],f=o.left,c=o.top,h=o.width,d=o.height,p=e.valToPosH,m=e.valToPosV;return 0==u.ori?l(n,s,r,u,a,p,m,f,c,h,d,fl,hl,pl,gl,wl):l(n,s,r,u,a,m,p,c,f,d,h,cl,dl,ml,xl,_l)}function nl(e,t){let l=0,n=0,i=q(e.bands,ze);for(let e=0;i.length>e;e++){let o=i[e];o.series[0]==t?l=o.dir:o.series[1]==t&&(n|=1==o.dir?1:2)}return[l,1==n?-1:2==n?1:3==n?2:0]}function il(e,t,l,n,i){let o=e.scales[e.series[t].scale];return-1==i?o.min:1==i?o.max:3==o.distr?1==o.dir?o.min:o.max:0}function ol(e,t,l,n,i,o){return ll(e,t,((e,t,s,r,u,a,f,c,h,d,p)=>{let m=e.pxRound;const g=0==r.ori?hl:dl;let x,w;1==r.dir*(0==r.ori?1:-1)?(x=l,w=n):(x=n,w=l);let _=m(a(t[x],r,d,c)),b=m(f(s[x],u,p,h)),k=m(a(t[w],r,d,c)),v=m(f(1==o?u.max:u.min,u,p,h)),y=new Path2D(i);return g(y,k,v),g(y,_,v),g(y,_,b),y}))}function sl(e,t,l,n,i,o){let s=null;if(e.length>0){s=new Path2D;const r=0==t?pl:ml;let u=l;for(let t=0;e.length>t;t++){let l=e[t];if(l[1]>l[0]){let e=l[0]-u;e>0&&r(s,u,n,e,n+o),u=l[1]}}let a=l+i-u;a>0&&r(s,u,n,a,n+o)}return s}function rl(e,t,l,n,i,o,s){let r=[];for(let u=1==i?l:n;u>=l&&n>=u;u+=i)if(null===t[u]){let a=u,f=u;if(1==i)for(;++u<=n&&null===t[u];)f=u;else for(;--u>=l&&null===t[u];)f=u;let c=o(e[a]),h=f==a?c:o(e[f]);c=s>0?c:o(e[a-i]),h=0>s?h:o(e[f+i]),c>h||r.push([c,h])}return r}function ul(e){return 0==e?ge:1==e?le:t=>de(t,e)}function al(e){let t=0==e?fl:cl,l=0==e?(e,t,l,n,i,o)=>{e.arcTo(t,l,n,i,o)}:(e,t,l,n,i,o)=>{e.arcTo(l,t,i,n,o)},n=0==e?(e,t,l,n,i)=>{e.rect(t,l,n,i)}:(e,t,l,n,i)=>{e.rect(l,t,i,n)};return(e,i,o,s,r,u=0)=>{0==u?n(e,i,o,s,r):(u=ie(u,s/2,r/2),t(e,i+u,o),l(e,i+s,o,i+s,o+r,u),l(e,i+s,o+r,i,o+r,u),l(e,i,o+r,i,o,u),l(e,i,o,i+s,o,u),e.closePath())}}const fl=(e,t,l)=>{e.moveTo(t,l)},cl=(e,t,l)=>{e.moveTo(l,t)},hl=(e,t,l)=>{e.lineTo(t,l)},dl=(e,t,l)=>{e.lineTo(l,t)},pl=al(0),ml=al(1),gl=(e,t,l,n,i,o)=>{e.arc(t,l,n,i,o)},xl=(e,t,l,n,i,o)=>{e.arc(l,t,n,i,o)},wl=(e,t,l,n,i,o,s)=>{e.bezierCurveTo(t,l,n,i,o,s)},_l=(e,t,l,n,i,o,s)=>{e.bezierCurveTo(l,t,i,n,s,o)};function bl(){return(e,t,l,n,i)=>ll(e,t,((t,o,s,r,u,a,f,c,h,d,p)=>{let m,g,{pxRound:x,points:w}=t;0==r.ori?(m=fl,g=gl):(m=cl,g=xl);const _=ye(w.width*k,3);let b=(w.size-w.width)/2*k,v=ye(2*b,3),y=new Path2D,M=new Path2D,{left:S,top:E,width:D,height:z}=e.bbox;pl(M,S-v,E-v,D+2*v,z+2*v);const T=e=>{if(null!=s[e]){let t=x(a(o[e],r,d,c)),l=x(f(s[e],u,p,h));m(y,t+b,l),g(y,t,l,b,0,2*Q)}};if(i)i.forEach(T);else for(let e=l;n>=e;e++)T(e);return{stroke:_>0?y:null,fill:y,clip:M,flags:3}}))}function kl(e){return(t,l,n,i,o,s)=>{n!=i&&(o!=n&&s!=n&&e(t,l,n),o!=i&&s!=i&&e(t,l,i),e(t,l,s))}}const vl=kl(hl),yl=kl(dl);function Ml(e){const t=q(e?.alignGaps,0);return(e,l,n,i)=>ll(e,l,((o,s,r,u,a,f,c,h,d,p,m)=>{let g,x,w=o.pxRound,_=e=>w(f(e,u,p,h)),b=e=>w(c(e,a,m,d));0==u.ori?(g=hl,x=vl):(g=dl,x=yl);const k=u.dir*(0==u.ori?1:-1),v={stroke:new Path2D,fill:null,clip:null,band:null,gaps:null,flags:1},y=v.stroke;let M,S,E,D=ce,z=-ce,T=_(s[1==k?n:i]),P=L(r,n,i,1*k),A=L(r,n,i,-1*k),W=_(s[P]),Y=_(s[A]);for(let e=1==k?n:i;e>=n&&i>=e;e+=k){let t=_(s[e]);t==T?null!=r[e]&&(S=b(r[e]),D==ce&&(g(y,t,S),M=S),D=ie(S,D),z=oe(S,z)):(D!=ce&&(x(y,T,D,z,M,S),E=T),null!=r[e]?(S=b(r[e]),g(y,t,S),D=z=M=S):(D=ce,z=-ce),T=t)}D!=ce&&D!=z&&E!=T&&x(y,T,D,z,M,S);let[C,F]=nl(e,l);if(null!=o.fill||0!=C){let t=v.fill=new Path2D(y),n=b(o.fillTo(e,l,o.min,o.max,C));g(t,Y,n),g(t,W,n)}if(!o.spanGaps){let a=[];a.push(...rl(s,r,n,i,k,_,t)),v.gaps=a=o.gaps(e,l,n,i,a),v.clip=sl(a,u.ori,h,d,p,m)}return 0!=F&&(v.band=2==F?[ol(e,l,n,i,y,-1),ol(e,l,n,i,y,1)]:ol(e,l,n,i,y,F)),v}))}function Sl(e,t,l,n,i){const o=e.length;if(2>o)return null;const s=new Path2D;if(l(s,e[0],t[0]),2==o)n(s,e[1],t[1]);else{let l=Array(o),n=Array(o-1),r=Array(o-1),u=Array(o-1);for(let l=0;o-1>l;l++)r[l]=t[l+1]-t[l],u[l]=e[l+1]-e[l],n[l]=r[l]/u[l];l[0]=n[0];for(let e=1;o-1>e;e++)0===n[e]||0===n[e-1]||n[e-1]>0!=n[e]>0?l[e]=0:(l[e]=3*(u[e-1]+u[e])/((2*u[e]+u[e-1])/n[e-1]+(u[e]+2*u[e-1])/n[e]),isFinite(l[e])||(l[e]=0));l[o-1]=n[o-2];for(let n=0;o-1>n;n++)i(s,e[n]+u[n]/3,t[n]+l[n]*u[n]/3,e[n+1]-u[n]/3,t[n+1]-l[n+1]*u[n]/3,e[n+1],t[n+1])}return s}const El=new Set;function Dl(){El.forEach((e=>{e.syncRect(!0)}))}x&&(H("resize",_,Dl),H("scroll",_,Dl,!0),H(g,_,(()=>{jl.pxRatio=k})));const zl=Ml(),Tl=bl();function Pl(e,t,l,n){return(n?[e[0],e[1]].concat(e.slice(2)):[e[0]].concat(e.slice(1))).map(((e,n)=>Al(e,n,t,l)))}function Al(e,t,l,n){return He({},0==t?l:n,e)}function Wl(e,t,l){return null==t?Te:[t,l]}const Yl=Wl;function Cl(e,t,l){return null==t?Te:J(t,l,.1,!0)}function Fl(e,t,l,n){return null==t?Te:j(t,l,e.scales[n].log,!1)}const Hl=Fl;function Rl(e,t,l,n){return null==t?Te:N(t,l,e.scales[n].log,!1)}const Gl=Rl;function Ll(e,t,l,n,i){let o=oe(he(e),he(t)),s=t-e,r=G(i/n*s,l);do{let e=l[r],t=n*e/s;if(t>=i&&17>=o+(5>e?Me.get(e):0))return[e,t]}while(++r(t=le((l=+n)*k))+"px")),t,l]}function Il(e){e.show&&[e.font,e.labelFont].forEach((e=>{let t=ye(e[2]*k,1);e[0]=e[0].replace(/[0-9.]+px/,t+"px"),e[1]=t}))}function jl(u,m,x){const b={mode:q(u.mode,1)},v=b.mode;function z(e,t){return((3==t.distr?ue(e>0?e:t.clamp(b,e,t.min,t.max,t.key)):4==t.distr?fe(e,t.asinh):e)-t._min)/(t._max-t._min)}function P(e,t,l,n){let i=z(e,t);return n+l*(-1==t.dir?1-i:i)}function W(e,t,l,n){let i=z(e,t);return n+l*(-1==t.dir?i:1-i)}function C(e,t,l,n){return 0==t.ori?P(e,t,l,n):W(e,t,l,n)}b.valToPosH=P,b.valToPosV=W;let F=!1;b.status=0;const L=b.root=D("uplot");null!=u.id&&(L.id=u.id),y(L,u.class),u.title&&(D("u-title",L).textContent=u.title);const O=E("canvas"),I=b.ctx=O.getContext("2d"),B=D("u-wrap",L),V=b.under=D("u-under",B);B.appendChild(O);const K=b.over=D("u-over",B),Z=+q((u=Fe(u)).pxAlign,1),$=ul(Z);(u.plugins||[]).forEach((e=>{e.opts&&(u=e.opts(b,u)||u)}));const te=u.ms||.001,re=b.series=1==v?Pl(u.series||[],Ft,Zt,!1):function(e,t){return e.map(((e,l)=>0==l?null:He({},t,e)))}(u.series||[null],Kt),ae=b.axes=Pl(u.axes||[],Ct,Vt,!0),he=b.scales={},ge=b.bands=u.bands||[];ge.forEach((e=>{e.fill=me(e.fill||null),e.dir=q(e.dir,-1)}));const ve=2==v?re[1].facets[0].scale:re[0].scale,Me={axes:function(){for(let e=0;ae.length>e;e++){let t=ae[e];if(!t.show||!t._show)continue;let l,n,u=t.side,a=u%2,f=t.stroke(b,e),c=0==u||3==u?-1:1;if(t.label){let e=le((t._lpos+t.labelGap*c)*k);ql(t.labelFont[0],f,"center",2==u?i:o),I.save(),1==a?(l=n=0,I.translate(e,le(At+Yt/2)),I.rotate((3==u?-Q:Q)/2)):(l=le(Pt+Wt/2),n=e),I.fillText(t.label,l,n),I.restore()}let[h,d]=t._found;if(0==d)continue;let p=he[t.scale],m=0==a?Wt:Yt,g=0==a?Pt:At,x=le(t.gap*k),w=t._splits,_=2==p.distr?w.map((e=>Nl[e])):w,v=2==p.distr?Nl[w[1]]-Nl[w[0]]:h,y=t.ticks,M=t.border,S=y.show?le(y.size*k):0,E=t._rotate*-Q/180,D=$(t._pos*k),z=D+(S+x)*c;n=0==a?z:0,l=1==a?z:0,ql(t.font[0],f,1==t.align?s:2==t.align?r:E>0?s:0>E?r:0==a?"center":3==u?r:s,E||1==a?"middle":2==u?i:o);let T=1.5*t.font[1],P=w.map((e=>$(C(e,p,m,g)))),A=t._values;for(let e=0;A.length>e;e++){let t=A[e];if(null!=t){0==a?l=P[e]:n=P[e],t=""+t;let i=-1==t.indexOf("\n")?[t]:t.split(/\n/gm);for(let e=0;i.length>e;e++){let t=i[e];E?(I.save(),I.translate(l,n+e*T),I.rotate(E),I.fillText(t,0,0),I.restore()):I.fillText(t,l,n+e*T)}}}y.show&&tn(P,y.filter(b,_,e,d,v),a,u,D,S,ye(y.width*k,3),y.stroke(b,e),y.dash,y.cap);let W=t.grid;W.show&&tn(P,W.filter(b,_,e,d,v),a,0==a?2:1,0==a?At:Pt,0==a?Yt:Wt,ye(W.width*k,3),W.stroke(b,e),W.dash,W.cap),M.show&&tn([D],[1],0==a?1:0,0==a?1:2,1==a?At:Pt,1==a?Yt:Wt,ye(M.width*k,3),M.stroke(b,e),M.dash,M.cap)}ti("drawAxes")},series:function(){pl>0&&(re.forEach(((e,t)=>{if(t>0&&e.show&&null==e._paths){let l=function(e){let t=pe(ml-1,0,pl-1),l=pe(gl+1,0,pl-1);for(;null==e[t]&&t>0;)t--;for(;null==e[l]&&pl-1>l;)l++;return[t,l]}(m[t]);e._paths=e.paths(b,t,l[0],l[1])}})),re.forEach(((e,t)=>{if(t>0&&e.show){jl!=e.alpha&&(I.globalAlpha=jl=e.alpha),Zl(t,!1),e._paths&&$l(t,!1);{Zl(t,!0);let l=e.points.show(b,t,ml,gl),n=e.points.filter(b,t,l,e._paths?e._paths.gaps:null);(l||n)&&(e.points._paths=e.points.paths(b,t,ml,gl,n),$l(t,!0))}1!=jl&&(I.globalAlpha=jl=1),ti("drawSeries",t)}})))}},Se=(u.drawOrder||["axes","series"]).map((e=>Me[e]));function Ee(e){let t=he[e];if(null==t){let l=(u.scales||De)[e]||De;if(null!=l.from)Ee(l.from),he[e]=He({},he[l.from],l,{key:e});else{t=he[e]=He({},e==ve?Xt:Qt,l),t.key=e;let n=t.time,i=t.range,o=Pe(i);if((e!=ve||2==v&&!n)&&(!o||null!=i[0]&&null!=i[1]||(i={min:null==i[0]?U:{mode:1,hard:i[0],soft:i[0]},max:null==i[1]?U:{mode:1,hard:i[1],soft:i[1]}},o=!1),!o&&We(i))){let e=i;i=(t,l,n)=>null==l?Te:J(l,n,e)}t.range=me(i||(n?Yl:e==ve?3==t.distr?Hl:4==t.distr?Gl:Wl:3==t.distr?Fl:4==t.distr?Rl:Cl)),t.auto=me(!o&&t.auto),t.clamp=me(t.clamp||$t),t._min=t._max=null}}}Ee("x"),Ee("y"),1==v&&re.forEach((e=>{Ee(e.scale)})),ae.forEach((e=>{Ee(e.scale)}));for(let e in u.scales)Ee(e);const Ce=he[ve],Re=Ce.distr;let Le,Oe;0==Ce.ori?(y(L,"u-hz"),Le=P,Oe=W):(y(L,"u-vt"),Le=W,Oe=P);const Ie={};for(let e in he){let t=he[e];null==t.min&&null==t.max||(Ie[e]={min:t.min,max:t.max},t.min=t.max=null)}const je=u.tzDate||(e=>new Date(le(e/te))),Ne=u.fmtDate||Je,Ue=1==te?pt(je):xt(je),Be=_t(je,wt(1==te?dt:gt,Ne)),Ve=vt(je,kt("{YYYY}-{MM}-{DD} {h}:{mm}{aa}",Ne)),qe=[],Ke=b.legend=He({},yt,u.legend),Ze=Ke.show,$e=Ke.markers;let Xe;Ke.idxs=qe,$e.width=me($e.width),$e.dash=me($e.dash),$e.stroke=me($e.stroke),$e.fill=me($e.fill);let tt,lt=[],nt=[],it=!1,ot={};if(Ke.live){const e=re[1]?re[1].values:null;it=null!=e,tt=it?e(b,1,0):{_:0};for(let e in tt)ot[e]="--"}if(Ze)if(Xe=E("table","u-legend",L),it){let e=E("tr","u-thead",Xe);for(var st in E("th",null,e),tt)E("th",t,e).textContent=st}else y(Xe,"u-inline"),Ke.live&&y(Xe,"u-live");const rt={show:!0},ut={show:!1},at=new Map;function ft(e,t,l){const n=at.get(t)||{},i=nl.bind[e](b,t,l);i&&(H(e,t,n[e]=i),at.set(t,n))}function ct(e,t){const l=at.get(t)||{};for(let n in l)null!=e&&n!=e||(R(n,t,l[n]),delete l[n]);null==e&&at.delete(t)}let bt=0,Mt=0,St=0,Et=0,zt=0,Tt=0,Pt=0,At=0,Wt=0,Yt=0;b.bbox={};let Ot=!1,It=!1,jt=!1,Nt=!1,qt=!1;function el(e,t,l){(l||e!=b.width||t!=b.height)&&ll(e,t),on(!1),jt=!0,It=!0,Nt=qt=nl.left>=0,_n()}function ll(e,t){b.width=bt=St=e,b.height=Mt=Et=t,zt=Tt=0,function(){let e=!1,t=!1,l=!1,n=!1;ae.forEach((i=>{if(i.show&&i._show){let{side:o,_size:s}=i,r=o%2,u=s+(null!=i.label?i.labelSize:0);u>0&&(r?(St-=u,3==o?(zt+=u,n=!0):l=!0):(Et-=u,0==o?(Tt+=u,e=!0):t=!0))}})),fl[0]=e,fl[1]=l,fl[2]=t,fl[3]=n,St-=dl[1]+dl[3],zt+=dl[3],Et-=dl[2]+dl[0],Tt+=dl[0]}(),function(){let e=zt+St,t=Tt+Et,l=zt,n=Tt;function i(i,o){switch(i){case 1:return e+=o,e-o;case 2:return t+=o,t-o;case 3:return l-=o,l+o;case 0:return n-=o,n+o}}ae.forEach((e=>{if(e.show&&e._show){let t=e.side;e._pos=i(t,e._size),null!=e.label&&(e._lpos=i(t,e.labelSize))}}))}();let l=b.bbox;Pt=l.left=de(zt*k,.5),At=l.top=de(Tt*k,.5),Wt=l.width=de(St*k,.5),Yt=l.height=de(Et*k,.5)}b.setSize=function({width:e,height:t}){el(e,t)};const nl=b.cursor=He({},Dt,{drag:{y:2==v}},u.cursor);{nl.idxs=qe,nl._lock=!1;let e=nl.points;e.show=me(e.show),e.size=me(e.size),e.stroke=me(e.stroke),e.width=me(e.width),e.fill=me(e.fill)}const ol=b.focus=He({},u.focus||{alpha:.3},nl.focus),sl=ol.prox>=0;let rl=[null];function al(l,n){if(1==v||n>0){let e=1==v&&he[l.scale].time,t=l.value;l.value=e?Ae(t)?vt(je,kt(t,Ne)):t||Ve:t||Bt,l.label=l.label||(e?"Time":"Value")}if(n>0){l.width=null==l.width?1:l.width,l.paths=l.paths||zl||we,l.fillTo=me(l.fillTo||il),l.pxAlign=+q(l.pxAlign,Z),l.pxRound=ul(l.pxAlign),l.stroke=me(l.stroke||null),l.fill=me(l.fill||null),l._stroke=l._fill=l._paths=l._focus=null;let e=Jt(l.width,1),t=l.points=He({},{size:e,width:oe(1,.2*e),stroke:l.stroke,space:2*e,paths:Tl,_stroke:null,_fill:null},l.points);t.show=me(t.show),t.filter=me(t.filter),t.fill=me(t.fill),t.stroke=me(t.stroke),t.paths=me(t.paths),t.pxAlign=l.pxAlign}if(Ze){let i=function(l,n){if(0==n&&(it||!Ke.live||2==v))return Te;let i=[],o=E("tr","u-series",Xe,Xe.childNodes[n]);y(o,l.class),l.show||y(o,e);let s=E("th",null,o);if($e.show){let e=D("u-marker",s);if(n>0){let t=$e.width(b,n);t&&(e.style.border=t+"px "+$e.dash(b,n)+" "+$e.stroke(b,n)),e.style.background=$e.fill(b,n)}}let r=D(t,s);for(var u in r.textContent=l.label,n>0&&($e.show||(r.style.color=l.width>0?$e.stroke(b,n):$e.fill(b,n)),ft("click",s,(e=>{if(nl._lock)return;let t=re.indexOf(l);if((e.ctrlKey||e.metaKey)!=Ke.isolate){let e=re.some(((e,l)=>l>0&&l!=t&&e.show));re.forEach(((l,n)=>{n>0&&Pn(n,e?n==t?rt:ut:rt,!0,li.setSeries)}))}else Pn(t,{show:!l.show},!0,li.setSeries)})),sl&&ft(h,s,(()=>{nl._lock||Pn(re.indexOf(l),Cn,!0,li.setSeries)}))),tt){let e=E("td","u-value",o);e.textContent="--",i.push(e)}return[o,i]}(l,n);lt.splice(n,0,i[0]),nt.splice(n,0,i[1]),Ke.values.push(null)}if(nl.show){qe.splice(n,0,null);let e=function(e,t){if(t>0){let l=nl.points.show(b,t);if(l)return y(l,"u-cursor-pt"),y(l,e.class),T(l,-10,-10,St,Et),K.insertBefore(l,rl[t]),l}}(l,n);e&&rl.splice(n,0,e)}ti("addSeries",n)}b.addSeries=function(e,t){e=Al(e,t=null==t?re.length:t,Ft,Zt),re.splice(t,0,e),al(re[t],t)},b.delSeries=function(e){if(re.splice(e,1),Ze){Ke.values.splice(e,1),nt.splice(e,1);let t=lt.splice(e,1)[0];ct(null,t.firstChild),t.remove()}nl.show&&(qe.splice(e,1),rl.length>1&&rl.splice(e,1)[0].remove()),ti("delSeries",e)};const fl=[!1,!1,!1,!1];function cl(e,t,l){let[n,i,o,s]=l,r=t%2,u=0;return 0==r&&(s||i)&&(u=0==t&&!n||2==t&&!o?le(Ct.size/3):0),1==r&&(n||o)&&(u=1==t&&!i||3==t&&!s?le(Vt.size/2):0),u}const hl=b.padding=(u.padding||[cl,cl,cl,cl]).map((e=>me(q(e,cl)))),dl=b._padding=hl.map(((e,t)=>e(b,t,fl,0)));let pl,ml=null,gl=null;const xl=1==v?re[0].idxs:null;let wl,_l,bl,kl,vl,yl,Ml,Sl,Dl,jl,Nl=null,Ul=!1;function Bl(e,t){if(m=null==e?[]:Fe(e,Ye),2==v){pl=0;for(let e=1;re.length>e;e++)pl+=m[e][0].length;b.data=m=e}else if(null==m[0]&&(m[0]=[]),b.data=m.slice(),Nl=m[0],pl=Nl.length,2==Re){m[0]=Array(pl);for(let e=0;pl>e;e++)m[0][e]=e}if(b._data=m,on(!0),ti("setData"),2==Re&&(jt=!0),!1!==t){let e=Ce;e.auto(b,Ul)?Vl():Tn(ve,e.min,e.max),Nt=nl.left>=0,qt=!0,_n()}}function Vl(){let e,t;Ul=!0,1==v&&(pl>0?(ml=xl[0]=0,gl=xl[1]=pl-1,e=m[0][ml],t=m[0][gl],2==Re?(e=ml,t=gl):1==pl&&(3==Re?[e,t]=j(e,e,Ce.log,!1):4==Re?[e,t]=N(e,e,Ce.log,!1):Ce.time?t=e+le(86400/te):[e,t]=J(e,t,.1,!0))):(ml=xl[0]=e=null,gl=xl[1]=t=null)),Tn(ve,e,t)}function Jl(e="#0000",t,l=ze,n="butt",i="#0000",o="round"){e!=wl&&(I.strokeStyle=wl=e),i!=_l&&(I.fillStyle=_l=i),t!=bl&&(I.lineWidth=bl=t),o!=vl&&(I.lineJoin=vl=o),n!=yl&&(I.lineCap=yl=n),l!=kl&&I.setLineDash(kl=l)}function ql(e,t,l,n){t!=_l&&(I.fillStyle=_l=t),e!=Ml&&(I.font=Ml=e),l!=Sl&&(I.textAlign=Sl=l),n!=Dl&&(I.textBaseline=Dl=n)}function Kl(e,t,l,n,i=0){if(n.length>0&&e.auto(b,Ul)&&(null==t||null==t.min)){let t=q(ml,0),o=q(gl,n.length-1),s=null==l.min?3==e.distr?function(e,t,l){let n=ce,i=-ce;for(let o=t;l>=o;o++)e[o]>0&&(n=ie(n,e[o]),i=oe(i,e[o]));return[n==ce?1:n,i==-ce?10:i]}(n,t,o):function(e,t,l,n){let i=ce,o=-ce;if(1==n)i=e[t],o=e[l];else if(-1==n)i=e[l],o=e[t];else for(let n=t;l>=n;n++)null!=e[n]&&(i=ie(i,e[n]),o=oe(o,e[n]));return[i,o]}(n,t,o,i):[l.min,l.max];e.min=ie(e.min,l.min=s[0]),e.max=oe(e.max,l.max=s[1])}}function Zl(e,t){let l=t?re[e].points:re[e];l._stroke=l.stroke(b,e),l._fill=l.fill(b,e)}function $l(e,t){let l=t?re[e].points:re[e],n=l._stroke,i=l._fill,{stroke:o,fill:s,clip:r,flags:u}=l._paths,a=null,f=ye(l.width*k,3),c=f%2/2;t&&null==i&&(i=f>0?"#fff":n);let h=1==l.pxAlign;if(h&&I.translate(c,c),!t){let e=Pt,t=At,n=Wt,i=Yt,o=f*k/2;0==l.min&&(i+=o),0==l.max&&(t-=o,i+=o),a=new Path2D,a.rect(e,t,n,i)}t?Xl(n,f,l.dash,l.cap,i,o,s,u,r):function(e,t,l,n,i,o,s,r,u,a,f){let c=!1;ge.forEach(((h,d)=>{if(h.series[0]==e){let e,p=re[h.series[1]],g=m[h.series[1]],x=(p._paths||De).band;Pe(x)&&(x=1==h.dir?x[0]:x[1]);let w=null;p.show&&x&&function(e,t,l){for(t=q(t,0),l=q(l,e.length-1);l>=t;){if(null!=e[t])return!0;t++}return!1}(g,ml,gl)?(w=h.fill(b,d)||o,e=p._paths.clip):x=null,Xl(t,l,n,i,w,s,r,u,a,f,e,x),c=!0}})),c||Xl(t,l,n,i,o,s,r,u,a,f)}(e,n,f,l.dash,l.cap,i,o,s,u,a,r),h&&I.translate(-c,-c)}function Xl(e,t,l,n,i,o,s,r,u,a,f,c){Jl(e,t,l,n,i),(u||a||c)&&(I.save(),u&&I.clip(u),a&&I.clip(a)),c?3==(3&r)?(I.clip(c),f&&I.clip(f),en(i,s),Ql(e,o,t)):2&r?(en(i,s),I.clip(c),Ql(e,o,t)):1&r&&(I.save(),I.clip(c),f&&I.clip(f),en(i,s),I.restore(),Ql(e,o,t)):(en(i,s),Ql(e,o,t)),(u||a||c)&&I.restore()}function Ql(e,t,l){l>0&&(t instanceof Map?t.forEach(((e,t)=>{I.strokeStyle=wl=t,I.stroke(e)})):null!=t&&e&&I.stroke(t))}function en(e,t){t instanceof Map?t.forEach(((e,t)=>{I.fillStyle=_l=t,I.fill(e)})):null!=t&&e&&I.fill(t)}function tn(e,t,l,n,i,o,s,r,u,a){let f=s%2/2;1==Z&&I.translate(f,f),Jl(r,s,u,a,r),I.beginPath();let c,h,d,p,m=i+(0==n||3==n?-o:o);0==l?(h=i,p=m):(c=i,d=m);for(let n=0;e.length>n;n++)null!=t[n]&&(0==l?c=d=e[n]:h=p=e[n],I.moveTo(c,h),I.lineTo(d,p));I.stroke(),1==Z&&I.translate(-f,-f)}function ln(e){let t=!0;return ae.forEach(((l,n)=>{if(!l.show)return;let i=he[l.scale];if(null==i.min)return void(l._show&&(t=!1,l._show=!1,on(!1)));l._show||(t=!1,l._show=!0,on(!1));let o=l.side,s=o%2,{min:r,max:u}=i,[a,f]=function(e,t,l,n){let i,o=ae[e];if(n>0){let s=o._space=o.space(b,e,t,l,n);i=Ll(t,l,o._incrs=o.incrs(b,e,t,l,n,s),n,s)}else i=[0,0];return o._found=i}(n,r,u,0==s?St:Et);if(0==f)return;let c=l._splits=l.splits(b,n,r,u,a,f,2==i.distr),h=2==i.distr?c.map((e=>Nl[e])):c,d=2==i.distr?Nl[c[1]]-Nl[c[0]]:a,p=l._values=l.values(b,l.filter(b,h,n,f,d),n,f,d);l._rotate=2==o?l.rotate(b,p,n,f):0;let m=l._size;l._size=ne(l.size(b,p,n,e)),null!=m&&l._size!=m&&(t=!1)})),t}function nn(e){let t=!0;return hl.forEach(((l,n)=>{let i=l(b,n,fl,e);i!=dl[n]&&(t=!1),dl[n]=i})),t}function on(e){re.forEach(((t,l)=>{l>0&&(t._paths=null,e&&(1==v?(t.min=null,t.max=null):t.facets.forEach((e=>{e.min=null,e.max=null}))))}))}b.setData=Bl;let sn,rn,un,an,fn,cn,hn,dn,pn,mn,gn,xn,wn=!1;function _n(){wn||(Ge(bn),wn=!0)}function bn(){Ot&&(function(){let e=Fe(he,Ye);for(let t in e){let l=e[t],n=Ie[t];if(null!=n&&null!=n.min)He(l,n),t==ve&&on(!0);else if(t!=ve||2==v)if(0==pl&&null==l.from){let e=l.range(b,null,null,t);l.min=e[0],l.max=e[1]}else l.min=ce,l.max=-ce}if(pl>0){re.forEach(((t,l)=>{if(1==v){let n=t.scale,i=e[n],o=Ie[n];if(0==l){let e=i.range(b,i.min,i.max,n);i.min=e[0],i.max=e[1],ml=G(i.min,m[0]),gl=G(i.max,m[0]),i.min>m[0][ml]&&ml++,m[0][gl]>i.max&&gl--,t.min=Nl[ml],t.max=Nl[gl]}else t.show&&t.auto&&Kl(i,o,t,m[l],t.sorted);t.idxs[0]=ml,t.idxs[1]=gl}else if(l>0&&t.show&&t.auto){let[n,i]=t.facets,o=n.scale,s=i.scale,[r,u]=m[l];Kl(e[o],Ie[o],n,r,n.sorted),Kl(e[s],Ie[s],i,u,i.sorted),t.min=i.min,t.max=i.max}}));for(let t in e){let l=e[t],n=Ie[t];if(null==l.from&&(null==n||null==n.min)){let e=l.range(b,l.min==ce?null:l.min,l.max==-ce?null:l.max,t);l.min=e[0],l.max=e[1]}}}for(let t in e){let l=e[t];if(null!=l.from){let n=e[l.from];if(null==n.min)l.min=l.max=null;else{let e=l.range(b,n.min,n.max,t);l.min=e[0],l.max=e[1]}}}let t={},l=!1;for(let n in e){let i=e[n],o=he[n];if(o.min!=i.min||o.max!=i.max){o.min=i.min,o.max=i.max;let e=o.distr;o._min=3==e?ue(o.min):4==e?fe(o.min,o.asinh):o.min,o._max=3==e?ue(o.max):4==e?fe(o.max,o.asinh):o.max,t[n]=l=!0}}if(l){re.forEach(((e,l)=>{2==v?l>0&&t.y&&(e._paths=null):t[e.scale]&&(e._paths=null)}));for(let e in t)jt=!0,ti("setScale",e);nl.show&&(Nt=qt=nl.left>=0)}for(let e in Ie)Ie[e]=null}(),Ot=!1),jt&&(function(){let e=!1,t=0;for(;!e;){t++;let l=ln(t),n=nn(t);e=3==t||l&&n,e||(ll(b.width,b.height),It=!0)}}(),jt=!1),It&&(S(V,s,zt),S(V,i,Tt),S(V,l,St),S(V,n,Et),S(K,s,zt),S(K,i,Tt),S(K,l,St),S(K,n,Et),S(B,l,bt),S(B,n,Mt),O.width=le(bt*k),O.height=le(Mt*k),ae.forEach((({_el:t,_show:l,_size:n,_pos:i,side:o})=>{if(null!=t)if(l){let l=o%2==1;S(t,l?"left":"top",i-(3===o||0===o?n:0)),S(t,l?"width":"height",n),S(t,l?"top":"left",l?Tt:zt),S(t,l?"height":"width",l?Et:St),M(t,e)}else y(t,e)})),wl=_l=bl=vl=yl=Ml=Sl=Dl=kl=null,jl=1,Un(!0),ti("setSize"),It=!1),bt>0&&Mt>0&&(I.clearRect(0,0,O.width,O.height),ti("drawClear"),Se.forEach((e=>e())),ti("draw")),nl.show&&Nt&&(jn(null,!0,!1),Nt=!1),F||(F=!0,b.status=1,ti("ready")),Ul=!1,wn=!1}function kn(e,t){let l=he[e];if(null==l.from){if(0==pl){let n=l.range(b,t.min,t.max,e);t.min=n[0],t.max=n[1]}if(t.min>t.max){let e=t.min;t.min=t.max,t.max=e}if(pl>1&&null!=t.min&&null!=t.max&&1e-16>t.max-t.min)return;e==ve&&2==l.distr&&pl>0&&(t.min=G(t.min,m[0]),t.max=G(t.max,m[0]),t.min==t.max&&t.max++),Ie[e]=t,Ot=!0,_n()}}b.redraw=(e,t)=>{jt=t||!1,!1!==e?Tn(ve,Ce.min,Ce.max):_n()},b.setScale=kn;let vn=!1;const yn=nl.drag;let Mn=yn.x,Sn=yn.y;nl.show&&(nl.x&&(sn=D("u-cursor-x",K)),nl.y&&(rn=D("u-cursor-y",K)),0==Ce.ori?(un=sn,an=rn):(un=rn,an=sn),gn=nl.left,xn=nl.top);const En=b.select=He({show:!0,over:!0,left:0,width:0,top:0,height:0},u.select),Dn=En.show?D("u-select",En.over?K:V):null;function zn(e,t){if(En.show){for(let t in e)S(Dn,t,En[t]=e[t]);!1!==t&&ti("setSelect")}}function Tn(e,t,l){kn(e,{min:t,max:l})}function Pn(t,l,n,i){null!=l.focus&&function(e){if(e!=Yn){let t=null==e,l=1!=ol.alpha;re.forEach(((n,i)=>{let o=t||0==i||i==e;n._focus=t?null:o,l&&function(e,t){re[e].alpha=t,nl.show&&rl[e]&&(rl[e].style.opacity=t),Ze&<[e]&&(lt[e].style.opacity=t)}(i,o?1:ol.alpha)})),Yn=e,l&&_n()}}(t),null!=l.show&&re.forEach(((n,i)=>{0>=i||t!=i&&null!=t||(n.show=l.show,function(t){let l=Ze?lt[t]:null;re[t].show?l&&M(l,e):(l&&y(l,e),rl.length>1&&T(rl[t],-10,-10,St,Et))}(i),Tn(2==v?n.facets[1].scale:n.scale,null,null),_n())})),!1!==n&&ti("setSeries",t,l),i&&oi("setSeries",b,t,l)}let An,Wn,Yn;b.setSelect=zn,b.setSeries=Pn,b.addBand=function(e,t){e.fill=me(e.fill||null),e.dir=q(e.dir,-1),ge.splice(t=null==t?ge.length:t,0,e)},b.setBand=function(e,t){He(ge[e],t)},b.delBand=function(e){null==e?ge.length=0:ge.splice(e,1)};const Cn={focus:!0};function Fn(e,t,l){let n=he[t];l&&(e=e/k-(1==n.ori?Tt:zt));let i=St;1==n.ori&&(i=Et,e=i-e),-1==n.dir&&(e=i-e);let o=n._min,s=o+e/i*(n._max-o),r=n.distr;return 3==r?se(10,s):4==r?((e,t=1)=>X.sinh(e)*t)(s,n.asinh):s}function Hn(e,t){S(Dn,s,En.left=e),S(Dn,l,En.width=t)}function Rn(e,t){S(Dn,i,En.top=e),S(Dn,n,En.height=t)}Ze&&sl&&H(d,Xe,(()=>{nl._lock||null!=Yn&&Pn(null,Cn,!0,li.setSeries)})),b.valToIdx=e=>G(e,m[0]),b.posToIdx=function(e,t){return G(Fn(e,ve,t),m[0],ml,gl)},b.posToVal=Fn,b.valToPos=(e,t,l)=>0==he[t].ori?P(e,he[t],l?Wt:St,l?Pt:0):W(e,he[t],l?Yt:Et,l?At:0),b.batch=function(e){e(b),_n()},b.setCursor=(e,t,l)=>{gn=e.left,xn=e.top,jn(null,t,l)};let Gn=0==Ce.ori?Hn:Rn,Ln=1==Ce.ori?Hn:Rn;function On(e,t){if(null!=e){let t=e.idx;Ke.idx=t,re.forEach(((e,l)=>{(l>0||!it)&&In(l,t)}))}Ze&&Ke.live&&function(){if(Ze&&Ke.live)for(let e=2==v?1:0;re.length>e;e++){if(0==e&&it)continue;let t=Ke.values[e],l=0;for(let n in t)nt[e][l++].firstChild.nodeValue=t[n]}}(),qt=!1,!1!==t&&ti("setLegend")}function In(e,t){let l;if(null==t)l=ot;else{let n=re[e],i=0==e&&2==Re?Nl:m[e];l=it?n.values(b,e,t):{_:n.value(b,i[t],e,t)}}Ke.values[e]=l}function jn(e,t,l){let n;pn=gn,mn=xn,[gn,xn]=nl.move(b,gn,xn),nl.show&&(un&&T(un,le(gn),0,St,Et),an&&T(an,0,le(xn),St,Et)),An=ce;let i=0==Ce.ori?St:Et,o=1==Ce.ori?St:Et;if(0>gn||0==pl||ml>gl){n=null;for(let e=0;re.length>e;e++)e>0&&rl.length>1&&T(rl[e],-10,-10,St,Et);if(sl&&Pn(null,Cn,!0,null==e&&li.setSeries),Ke.live){qe.fill(null),qt=!0;for(let e=0;re.length>e;e++)Ke.values[e]=ot}}else{let e,t,l;1==v&&(e=0==Ce.ori?gn:xn,t=Fn(e,ve),n=G(t,m[0],ml,gl),l=ke(Le(m[0][n],Ce,i,0),.5));for(let e=2==v?1:0;re.length>e;e++){let s=re[e],r=qe[e],u=1==v?m[e][r]:m[e][1][r],a=nl.dataIdx(b,e,n,t),f=1==v?m[e][a]:m[e][1][a];qt=qt||f!=u||a!=r,qe[e]=a;let c=a==n?l:ke(Le(1==v?m[0][a]:m[e][0][a],Ce,i,0),.5);if(e>0&&s.show){let t,l,n=null==f?-10:ke(Oe(f,1==v?he[s.scale]:he[s.facets[1].scale],o,0),.5);if(n>0&&1==v){let t=ee(n-xn);t>An||(An=t,Wn=e)}if(0==Ce.ori?(t=c,l=n):(t=n,l=c),qt&&rl.length>1){A(rl[e],nl.points.fill(b,e),nl.points.stroke(b,e));let n,i,o,s,r=!0,u=nl.points.bbox;if(null!=u){r=!1;let t=u(b,e);o=t.left,s=t.top,n=t.width,i=t.height}else o=t,s=l,n=i=nl.points.size(b,e);Y(rl[e],n,i,r),T(rl[e],o,s,St,Et)}}if(Ke.live){if(!qt||0==e&&it)continue;In(e,a)}}}if(nl.idx=n,nl.left=gn,nl.top=xn,qt&&(Ke.idx=n,On()),En.show&&vn)if(null!=e){let[t,l]=li.scales,[n,s]=li.match,[r,u]=e.cursor.sync.scales,a=e.cursor.drag;if(Mn=a._x,Sn=a._y,Mn||Sn){let a,f,c,h,d,{left:p,top:m,width:g,height:x}=e.select,w=e.scales[t].ori,_=e.posToVal,b=null!=t&&n(t,r),k=null!=l&&s(l,u);b&&Mn?(0==w?(a=p,f=g):(a=m,f=x),c=he[t],h=Le(_(a,r),c,i,0),d=Le(_(a+f,r),c,i,0),Gn(ie(h,d),ee(d-h))):Gn(0,i),k&&Sn?(1==w?(a=p,f=g):(a=m,f=x),c=he[l],h=Oe(_(a,u),c,o,0),d=Oe(_(a+f,u),c,o,0),Ln(ie(h,d),ee(d-h))):Ln(0,o)}else qn()}else{let e=ee(pn-fn),t=ee(mn-cn);if(1==Ce.ori){let l=e;e=t,t=l}Mn=yn.x&&e>=yn.dist,Sn=yn.y&&t>=yn.dist;let l,n,s=yn.uni;null!=s?Mn&&Sn&&(Mn=e>=s,Sn=t>=s,Mn||Sn||(t>e?Sn=!0:Mn=!0)):yn.x&&yn.y&&(Mn||Sn)&&(Mn=Sn=!0),Mn&&(0==Ce.ori?(l=hn,n=gn):(l=dn,n=xn),Gn(ie(l,n),ee(n-l)),Sn||Ln(0,o)),Sn&&(1==Ce.ori?(l=hn,n=gn):(l=dn,n=xn),Ln(ie(l,n),ee(n-l)),Mn||Gn(0,i)),Mn||Sn||(Gn(0,0),Ln(0,0))}if(yn._x=Mn,yn._y=Sn,null==e){if(l){if(null!=ni){let[e,t]=li.scales;li.values[0]=null!=e?Fn(0==Ce.ori?gn:xn,e):null,li.values[1]=null!=t?Fn(1==Ce.ori?gn:xn,t):null}oi(a,b,gn,xn,St,Et,n)}if(sl){let e=l&&li.setSeries,t=ol.prox;null==Yn?An>t||Pn(Wn,Cn,!0,e):An>t?Pn(null,Cn,!0,e):Wn!=Yn&&Pn(Wn,Cn,!0,e)}}F&&!1!==t&&ti("setCursor")}b.setLegend=On;let Nn=null;function Un(e){!0===e?Nn=null:(Nn=K.getBoundingClientRect(),ti("syncRect",Nn))}function Bn(e,t,l,n,i,o){nl._lock||(Vn(e,t,l,n,i,o,0,!1,null!=e),null!=e?jn(null,!0,!0):jn(t,!0,!1))}function Vn(e,t,l,n,i,o,s,r,u){if(null==Nn&&Un(!1),null!=e)l=e.clientX-Nn.left,n=e.clientY-Nn.top;else{if(0>l||0>n)return gn=-10,void(xn=-10);let[e,s]=li.scales,r=t.cursor.sync,[u,a]=r.values,[f,c]=r.scales,[h,d]=li.match,p=t.axes[0].side%2==1,m=0==Ce.ori?St:Et,g=1==Ce.ori?St:Et,x=p?o:i,w=p?i:o,_=p?n:l,b=p?l:n;if(l=null!=f?h(e,f)?C(u,he[e],m,0):-10:m*(_/x),n=null!=c?d(s,c)?C(a,he[s],g,0):-10:g*(b/w),1==Ce.ori){let e=l;l=n,n=e}}u&&(l>1&&St-1>l||(l=de(l,St)),n>1&&Et-1>n||(n=de(n,Et))),r?(fn=l,cn=n,[hn,dn]=nl.move(b,l,n)):(gn=l,xn=n)}const Jn={width:0,height:0};function qn(){zn(Jn,!1)}function Kn(e,t,l,n,i,o){vn=!0,Mn=Sn=yn._x=yn._y=!1,Vn(e,t,l,n,i,o,0,!0,!1),null!=e&&(ft(c,w,Zn),oi(f,b,hn,dn,St,Et,null))}function Zn(e,t,l,n,i,o){vn=yn._x=yn._y=!1,Vn(e,t,l,n,i,o,0,!1,!0);let{left:s,top:r,width:u,height:a}=En,f=u>0||a>0;if(f&&zn(En),yn.setScale&&f){let e=s,t=u,l=r,n=a;if(1==Ce.ori&&(e=r,t=a,l=s,n=u),Mn&&Tn(ve,Fn(e,ve),Fn(e+t,ve)),Sn)for(let e in he){let t=he[e];e!=ve&&null==t.from&&t.min!=ce&&Tn(e,Fn(l+n,e),Fn(l,e))}qn()}else nl.lock&&(nl._lock=!nl._lock,nl._lock||jn(null,!0,!1));null!=e&&(ct(c,w),oi(c,b,gn,xn,St,Et,null))}function $n(e){Vl(),qn(),null!=e&&oi(p,b,gn,xn,St,Et,null)}function Xn(){ae.forEach(Il),el(b.width,b.height,!0)}H(g,_,Xn);const Qn={};Qn.mousedown=Kn,Qn.mousemove=Bn,Qn.mouseup=Zn,Qn.dblclick=$n,Qn.setSeries=(e,t,l,n)=>{Pn(l,n,!0,!1)},nl.show&&(ft(f,K,Kn),ft(a,K,Bn),ft(h,K,Un),ft(d,K,(function(){if(!nl._lock){let e=vn;if(vn){let e,t,l=!0,n=!0,i=10;0==Ce.ori?(e=Mn,t=Sn):(e=Sn,t=Mn),e&&t&&(l=i>=gn||gn>=St-i,n=i>=xn||xn>=Et-i),e&&l&&(gn=hn>gn?0:St),t&&n&&(xn=dn>xn?0:Et),jn(null,!0,!0),vn=!1}gn=-10,xn=-10,jn(null,!0,!0),e&&(vn=e)}})),ft(p,K,$n),El.add(b),b.syncRect=Un);const ei=b.hooks=u.hooks||{};function ti(e,t,l){e in ei&&ei[e].forEach((e=>{e.call(null,b,t,l)}))}(u.plugins||[]).forEach((e=>{for(let t in e.hooks)ei[t]=(ei[t]||[]).concat(e.hooks[t])}));const li=He({key:null,setSeries:!1,filters:{pub:_e,sub:_e},scales:[ve,re[1]?re[1].scale:null],match:[be,be],values:[null,null]},nl.sync);nl.sync=li;const ni=li.key,ii=tl(ni);function oi(e,t,l,n,i,o,s){li.filters.pub(e,t,l,n,i,o,s)&&ii.pub(e,t,l,n,i,o,s)}function si(){ti("init",u,m),Bl(m||u.data,!1),Ie[ve]?kn(ve,Ie[ve]):Vl(),el(u.width,u.height),jn(null,!0,!1),zn(En,!1)}return ii.sub(b),b.pub=function(e,t,l,n,i,o,s){li.filters.sub(e,t,l,n,i,o,s)&&Qn[e](null,t,l,n,i,o,s)},b.destroy=function(){ii.unsub(b),El.delete(b),at.clear(),R(g,_,Xn),L.remove(),ti("destroy")},re.forEach(al),ae.forEach((function(e,t){if(e._show=e.show,e.show){let l=e.side%2,n=he[e.scale];null==n&&(e.scale=l?re[1].scale:ve,n=he[e.scale]);let i=n.time;e.size=me(e.size),e.space=me(e.space),e.rotate=me(e.rotate),e.incrs=me(e.incrs||(2==n.distr?Qe:i?1==te?ht:mt:et)),e.splits=me(e.splits||(i&&1==n.distr?Ue:3==n.distr?Gt:4==n.distr?Lt:Rt)),e.stroke=me(e.stroke),e.grid.stroke=me(e.grid.stroke),e.ticks.stroke=me(e.ticks.stroke),e.border.stroke=me(e.border.stroke);let o=e.values;e.values=Pe(o)&&!Pe(o[0])?me(o):i?Pe(o)?_t(je,wt(o,Ne)):Ae(o)?function(e,t){let l=Je(t);return(t,n)=>n.map((t=>l(e(t))))}(je,o):o||Be:o||Ht,e.filter=me(e.filter||(3>n.distr?xe:Ut)),e.font=Ol(e.font),e.labelFont=Ol(e.labelFont),e._size=e.size(b,null,t,0),e._space=e._rotate=e._incrs=e._found=e._splits=e._values=null,e._size>0&&(fl[t]=!0,e._el=D("u-axis",B))}})),x?x instanceof HTMLElement?(x.appendChild(L),si()):x(b,si):si(),b}jl.assign=He,jl.fmtNum=$,jl.rangeNum=J,jl.rangeLog=j,jl.rangeAsinh=N,jl.orient=ll,jl.pxRatio=k,jl.join=function(e,t){let l=new Set;for(let t=0;e.length>t;t++){let n=e[t][0],i=n.length;for(let e=0;i>e;e++)l.add(n[e])}let n=[Array.from(l).sort(((e,t)=>e-t))],i=n[0].length,o=new Map;for(let e=0;i>e;e++)o.set(n[0][e],e);for(let l=0;e.length>l;l++){let s=e[l],r=s[0];for(let e=1;s.length>e;e++){let u=s[e],a=Array(i).fill(void 0),f=t?t[l][e]:1,c=[];for(let e=0;u.length>e;e++){let t=u[e],l=o.get(r[e]);null===t?0!=f&&(a[l]=t,2==f&&c.push(l)):a[l]=t}Re(a,c,i),n.push(a)}}return n},jl.fmtDate=Je,jl.tzDate=function(e,t){let l;return"UTC"==t||"Etc/UTC"==t?l=new Date(+e+6e4*e.getTimezoneOffset()):t==qe?l=e:(l=new Date(e.toLocaleString("en-US",{timeZone:t})),l.setMilliseconds(e.getMilliseconds())),l},jl.sync=tl;{jl.addGap=function(e,t,l){let n=e[e.length-1];n&&n[0]==t?n[1]=l:e.push([t,l])},jl.clipGaps=sl;let e=jl.paths={points:bl};e.linear=Ml,e.stepped=function(e){const t=q(e.align,1),l=q(e.ascDesc,!1),n=q(e.alignGaps,0);return(e,i,o,s)=>ll(e,i,((r,u,a,f,c,h,d,p,m,g,x)=>{let w=r.pxRound,_=e=>w(h(e,f,g,p)),b=e=>w(d(e,c,x,m)),v=0==f.ori?hl:dl;const y={stroke:new Path2D,fill:null,clip:null,band:null,gaps:null,flags:1},M=y.stroke,S=f.dir*(0==f.ori?1:-1);o=L(a,o,s,1),s=L(a,o,s,-1);let E=b(a[1==S?o:s]),D=_(u[1==S?o:s]),z=D;v(M,D,E);for(let e=1==S?o:s;e>=o&&s>=e;e+=S){let l=a[e];if(null==l)continue;let n=_(u[e]),i=b(l);1==t?v(M,n,E):v(M,z,i),v(M,n,i),E=i,z=n}let[T,P]=nl(e,i);if(null!=r.fill||0!=T){let t=y.fill=new Path2D(M),l=b(r.fillTo(e,i,r.min,r.max,T));v(t,z,l),v(t,D,l)}if(!r.spanGaps){let c=[];c.push(...rl(u,a,o,s,S,_,n));let h=r.width*k/2,d=l||1==t?h:-h,w=l||-1==t?-h:h;c.forEach((e=>{e[0]+=d,e[1]+=w})),y.gaps=c=r.gaps(e,i,o,s,c),y.clip=sl(c,f.ori,p,m,g,x)}return 0!=P&&(y.band=2==P?[ol(e,i,o,s,M,-1),ol(e,i,o,s,M,1)]:ol(e,i,o,s,M,P)),y}))},e.bars=function(e){const t=q((e=e||De).size,[.6,ce,1]),l=e.align||0,n=(e.gap||0)*k,i=q(e.radius,0),o=1-t[0],s=q(t[1],ce)*k,r=q(t[2],1)*k,u=q(e.disp,De),a=q(e.each,(()=>{})),{fill:f,stroke:c}=u;return(e,t,h,d)=>ll(e,t,((p,m,g,x,w,_,b,v,y,M,S)=>{let E=p.pxRound;const D=x.dir*(0==x.ori?1:-1),z=w.dir*(1==w.ori?1:-1);let T,P,A=0==x.ori?pl:ml,W=0==x.ori?a:(e,t,l,n,i,o,s)=>{a(e,t,l,i,n,s,o)},[Y,C]=nl(e,t),F=3==w.distr?1==Y?w.max:w.min:0,H=b(F,w,S,y),R=E(p.width*k),G=!1,L=null,O=null,I=null,j=null;null==f||0!=R&&null==c||(G=!0,L=f.values(e,t,h,d),O=new Map,new Set(L).forEach((e=>{null!=e&&O.set(e,new Path2D)})),R>0&&(I=c.values(e,t,h,d),j=new Map,new Set(I).forEach((e=>{null!=e&&j.set(e,new Path2D)}))));let{x0:N,size:U}=u;if(null!=N&&null!=U){m=N.values(e,t,h,d),2==N.unit&&(m=m.map((t=>e.posToVal(v+t*M,x.key,!0))));let l=U.values(e,t,h,d);P=2==U.unit?l[0]*M:_(l[0],x,M,v)-_(0,x,M,v),P=E(P-R),T=1==D?-R/2:P+R/2}else{let e=M;if(m.length>1){let t=null;for(let l=0,n=1/0;m.length>l;l++)if(void 0!==g[l]){if(null!=t){let i=ee(m[l]-m[t]);n>i&&(n=i,e=ee(_(m[l],x,M,v)-_(m[t],x,M,v)))}t=l}}P=E(ie(s,oe(r,e-e*o))-R-n),T=(0==l?P/2:l==D?0:P)-l*D*n/2}const B={stroke:null,fill:null,clip:null,band:null,gaps:null,flags:3};let V;0!=C&&(B.band=new Path2D,V=E(b(1==C?w.max:w.min,w,S,y)));const J=G?null:new Path2D,K=B.band;let{y0:Z,y1:$}=u,X=null;null!=Z&&null!=$&&(g=$.values(e,t,h,d),X=Z.values(e,t,h,d));for(let l=1==D?h:d;l>=h&&d>=l;l+=D){let n=g[l];if(void 0===n)continue;let o=_(2!=x.distr||null!=u?m[l]:l,x,M,v),s=b(q(n,F),w,S,y);null!=X&&null!=n&&(H=b(X[l],w,S,y));let r=E(o-T),a=E(oe(s,H)),f=E(ie(s,H)),c=a-f,h=i*P;null!=n&&(G?(R>0&&null!=I[l]&&A(j.get(I[l]),r,f+te(R/2),P,oe(0,c-R),h),null!=L[l]&&A(O.get(L[l]),r,f+te(R/2),P,oe(0,c-R),h)):A(J,r,f+te(R/2),P,oe(0,c-R),h),W(e,t,l,r-R/2,f,P+R,c)),0!=C&&(z*C==1?(a=f,f=V):(f=a,a=V),c=a-f,A(K,r-R/2,f,P+R,oe(0,c),0))}return R>0&&(B.stroke=G?j:J),B.fill=G?O:J,B}))},e.spline=function(e){return function(e,t){const l=q(t?.alignGaps,0);return(t,n,i,o)=>ll(t,n,((s,r,u,a,f,c,h,d,p,m,g)=>{let x,w,_,b=s.pxRound,k=e=>b(c(e,a,m,d)),v=e=>b(h(e,f,g,p));0==a.ori?(x=fl,_=hl,w=wl):(x=cl,_=dl,w=_l);const y=a.dir*(0==a.ori?1:-1);i=L(u,i,o,1),o=L(u,i,o,-1);let M=k(r[1==y?i:o]),S=M,E=[],D=[];for(let e=1==y?i:o;e>=i&&o>=e;e+=y)if(null!=u[e]){let t=k(r[e]);E.push(S=t),D.push(v(u[e]))}const z={stroke:e(E,D,x,_,w,b),fill:null,clip:null,band:null,gaps:null,flags:1},T=z.stroke;let[P,A]=nl(t,n);if(null!=s.fill||0!=P){let e=z.fill=new Path2D(T),l=v(s.fillTo(t,n,s.min,s.max,P));_(e,S,l),_(e,M,l)}if(!s.spanGaps){let e=[];e.push(...rl(r,u,i,o,y,k,l)),z.gaps=e=s.gaps(t,n,i,o,e),z.clip=sl(e,a.ori,d,p,m,g)}return 0!=A&&(z.band=2==A?[ol(t,n,i,o,T,-1),ol(t,n,i,o,T,1)]:ol(t,n,i,o,T,A)),z}))}(Sl,e)}}return jl}(); diff --git a/uPlot.min.css b/uPlot.min.css new file mode 100644 index 0000000..c54627d --- /dev/null +++ b/uPlot.min.css @@ -0,0 +1 @@ +.uplot, .uplot *, .uplot *::before, .uplot *::after {box-sizing: border-box;}.uplot {font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";line-height: 1.5;width: min-content;}.u-title {text-align: center;font-size: 18px;font-weight: bold;}.u-wrap {position: relative;user-select: none;}.u-over, .u-under {position: absolute;}.u-under {overflow: hidden;}.uplot canvas {display: block;position: relative;width: 100%;height: 100%;}.u-axis {position: absolute;}.u-legend {font-size: 14px;margin: auto;text-align: center;}.u-inline {display: block;}.u-inline * {display: inline-block;}.u-inline tr {margin-right: 16px;}.u-legend th {font-weight: 600;}.u-legend th > * {vertical-align: middle;display: inline-block;}.u-legend .u-marker {width: 1em;height: 1em;margin-right: 4px;background-clip: padding-box !important;}.u-inline.u-live th::after {content: ":";vertical-align: middle;}.u-inline:not(.u-live) .u-value {display: none;}.u-series > * {padding: 4px;}.u-series th {cursor: pointer;}.u-legend .u-off > * {opacity: 0.3;}.u-select {background: rgba(0,0,0,0.07);position: absolute;pointer-events: none;}.u-cursor-x, .u-cursor-y {position: absolute;left: 0;top: 0;pointer-events: none;will-change: transform;z-index: 100;}.u-hz .u-cursor-x, .u-vt .u-cursor-y {height: 100%;border-right: 1px dashed #607D8B;}.u-hz .u-cursor-y, .u-vt .u-cursor-x {width: 100%;border-bottom: 1px dashed #607D8B;}.u-cursor-pt {position: absolute;top: 0;left: 0;border-radius: 50%;border: 0 solid;pointer-events: none;will-change: transform;z-index: 100;/*this has to be !important since we set inline "background" shorthand */background-clip: padding-box !important;}.u-axis.u-off, .u-select.u-off, .u-cursor-x.u-off, .u-cursor-y.u-off, .u-cursor-pt.u-off {display: none;} \ No newline at end of file