commit 6c066b47542cbdff7fc5082d780b1300c35d2c9a Author: Aadi Desai <21363892+supleed2@users.noreply.github.com> Date: Thu Feb 10 23:15:22 2022 +0000 Initialize hlp22-project diff --git a/.env.development b/.env.development new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/.env.development @@ -0,0 +1 @@ + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6de5b8c --- /dev/null +++ b/.gitignore @@ -0,0 +1,245 @@ +# Output folder +app/*.eot +app/*.svg +app/*.woff +app/*.woff2 +app/*.ttf +app/main.js* +app/renderer.js* + + +public/bundle.js* +electron/Content/app/main.js* +electron/Content/app/renderer.js* + +# Distribution. +dist/ + +# Diagrams +*.dprj + +# Node +node_modules/ + +# Ionide +.ionide + +# Paket +/.paket/ +/paket-files/* + +.config/ +.vscode/ + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Xamarin Studio / monodevelop user-specific +*.userprefs +*.dll.mdb +*.exe.mdb + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +[Bb]in/ +[Oo]bj/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Other Visual Studio data +.vs/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +#[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml + +# Enable nuget.exe in the .nuget folder (though normally executables are not tracked) +!.nuget/NuGet.exe + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +sql/ +*.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + + +#LightSwitch generated files +GeneratedArtifacts/ +_Pvt_Extensions/ +ModelManifest.xml + +# ========================= +# Windows detritus +# ========================= + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac desktop service store files +.DS_Store + +# =================================================== +# Exclude F# project specific directories and files +# =================================================== + +# NuGet Packages Directory +packages/ + +# Generated documentation folder +docs/output/ + +# Temp folder used for publishing docs +temp*/ + +# Test results produced by build +TestResults.xml +TestResult.xml + +# Nuget outputs +*.nupkg +release.cmd +release.sh +localpackages/ + +*.orig +docs/content/license.md +docs/content/release-notes.md +docs/tools/FSharp.Formatting.svclog + +.ionide.debug +*.bak +project.lock.json + +# Exclude doc generation and logs +docsrc/content/license.md +docsrc/content/release-notes.md +docsrc/tools/FSharp.Formatting.svclog + + + +# FAKE build cache +.fake/ + +/bin/ +/dist/ +!/docsrc/tools +!/docsrc/tools/templates +!/docsrc/tools/templates/* + +# Fable 3 Output +*.fs.js +*.fs.js.map + diff --git a/CountLines.cmd b/CountLines.cmd new file mode 100644 index 0000000..4227415 --- /dev/null +++ b/CountLines.cmd @@ -0,0 +1,5 @@ +@echo on +cls +scc --by-file --large-line-count=2000 --no-large -w --include-ext fs src\renderer\common src\renderer\drawblock src\renderer\ui src\renderer\interface src\renderer\simulator + + \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e72bfdd --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 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 General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..e72bfdd --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 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 General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/Nuget.Config b/Nuget.Config new file mode 100644 index 0000000..8ef9d53 --- /dev/null +++ b/Nuget.Config @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/README.md b/README.md new file mode 100644 index 0000000..d7fedcc --- /dev/null +++ b/README.md @@ -0,0 +1,221 @@ +# Issie - an Interactive Schematic Simulator with Integrated Editor + +Issie (Interactive Schematic Simulator with Integrated Editor) is an application for digital circuit design and simulation. It is targeted at students and hobbyists that want to get a grasp of Digital Electronics concepts in a simple and fun way. Issie is designed to be beginner-friendly and guide the users toward their goals via clear error messages and visual clues. Issie is developed and actively used in teaching at Imperial College London. + +* If you are just interested in using the application, jump to the [Getting Started](#getting-started) section. +* If you want user documentation and news go to the [web pages](https://tomcl.github.io/issie/). + +For more technical info about the project, read on. This documentation is partly based on the excellent [VisUAL2](https://github.com/ImperialCollegeLondon/Visual2) documentation, given the similarity in the technology stack used. + +## Introduction + +For the Issie website go [here](https://tomcl.github.io/issie/). + +The application is mostly written in F#, which gets transpiled to JavaScript via the [Fable](https://fable.io/) compiler. [Electron](https://www.electronjs.org/) is then used to convert the developed web-app to a cross-platform application. [Electron](electronjs.org) provides access to platform-level APIs (such as access to the file system) which would not be available to vanilla browser web-apps. + +[Webpack 4](https://webpack.js.org/) is the module bundler responsible for the JavaScript concatenation and automated building process: the electron-webpack build +is automated with the all-in-one electron-webpack package. + +The drawing capabilities are provided (now) by a custom schemetic editor library implemented in F# and specialised for digital components. + +The choice of F# as main programming language for the app has been dictated by a few factors: + +* The success of the [VisUAL2](https://github.com/ImperialCollegeLondon/Visual2), which uses a similar technology stack; +* Strongly typed functional code tends to be easy to maintain and test, as the type-checker massively helps you; +* Imperial College EEE/EIE students learn such language in the 3rd year High-Level-Programming course, hence can maintain the app in the future; +* F# can be used with the powerful [Elmish](https://elmish.github.io/elmish/) framework to develop User Interfaces in a [Functional Reactive Programming](https://en.wikipedia.org/wiki/Functional_reactive_programming) fashion. + +## Project Structure + +Electron bundles Chromium (View) and node.js (Engine), therefore as in every node.js project, the `package.json` file specifies the (Node) module dependencies. + +* dependencies: node libraries that the executable code (and development code) needs +* dev-dependencies: node libraries only needed by development tools + +Additionally, the section `"scripts"`: +``` + "scripts": { + "compile": "dotnet fable src/main && dotnet fable src/renderer", + "dev": "cd src/main && dotnet fable watch . --run npm run devrenderer", + "devmain": "cd src/main && dotnet fable watch . --run npm run webpackdev", + "devrenderer": "cd src/renderer && dotnet fable watch . --run npm run webpackdev", + "webpackdev": "electron-webpack dev", + "webpack": "electron-webpack", + "dist": "npm run compile && npm run webpack && electron-builder", + } +``` +Defines the in-project shortcut commands as a set of ` : ` it is equivalent to calling ``. +For example, in the root of the project, running in the terminal `npm run dev` is equivalent to the command line: + +``` +cd src/main && dotnet fable watch . --run npm run devrenderer +``` + +This runs fable 3 to transpile the main process, then (`--run` is an option of fable to run another command) runs script `devrenderer` to transpile to javascript and watch the F# files in the renderer process. After the renderer transpilation is finished +`electron-webpack dev` will be run. This invokes `webpack` to pack and lauch the javascript code, under electron, and also watches for changes in the javascript code, and *hot loads* these on the running application + +As result of this, at any time saving an edited F# renderer project file causes (nearly) immediate: + +* fable transpile to from F# to javascript file (dependent F# files may also be transpiled) +* webpack hot load of any changed javascript files to the running electron application + +The build system depends on a `Fake` file `build.fsx`. Fake is a DSL written in F# that is specialised to automate build tasks. Build.fsx has targets representing build tasks, and normally these are run via `build.cmd` or `build.sh`, instead of using `dotnet fake` directly: + +* `build ` ==> `dotnet fake build -t ` + +## Code Structure + +The source code consists of two distinct sections transpiled separately to Javascript to make a complete Electron application. + +* The electron main process runs the Electron parent process under the desktop native OS, it starts the app process and provides desktop access services to it. +* The electron client (app) process runs under Chromium in a simulated browser environment (isolated from the native OS). + +Electron thus allows code written for a browser (HTML + CSS + JavaScript) to be run as a desktop app with the additional capability of desktop filesystem access via communication between the two processes. + +Both processes run Javascript under Node. + +The `src/Main/Main.fs` source configures electron start-up and is boilerplate. It is transpiled to the root project directory so it can be automatically picked up by Electron. + +The remaining app code is arranged in four different sections, each being a separate F# project. This separation allows all the non-web-based code (which can equally be run and tested under .Net) to be run and tested under F# directly in addition to being transpiled and run under Electron. + +The project relies on the draw2d JavaScript (node) library, which is extended to support digital electronics components. The extensions are in the `draw2d` sub-folder of the renderer project source files. + +The code that turns the F# project source into `renderer.js` is the FABLE compiler followed by the Node Webpack bundler that combines multiple Javascript files into a single `renderer.js`. + +The compile process is controlled by the `.fsproj` files (defining the F# source) and `webpack.additions.main.js`, `webpack.additions.renderer.js` +which define how Webpack combines F# outputs for both electron main and electron app processes and where the executable code is put. +This is boilerplate which you do not need to change; normally the F# project files are all that needs to be modified. + +## File Structure + +### `src` folder + +| Subfolder | Description | +|:------------:|:--------------------------------------------------------------------------------------------------:| +| `main/` | Code for the main electron process that sets everything up - not normally changed | +| `Common/` | Provides some common types and utilities used by all other sections, including the WidthInferer | +| `Simulator/` | Contains the logic to analyse and simulate a diagram. | +| `Renderer/` | Contains the UI logic, the wrapper to the JavaScript drawing library and a set of utility function to write/read/parse diagram files. This amd `main` are the only projects that cannot run under .Net, as they contain JavaScript related functionalities. | + +### `Tests` folder + +Contains numerous tests for the WidthInferer and Simulator. Based on F# Expecto testing library. + + +### `Static` folder + +Contains static files used in the application. + +### `Docs` folder + +Contains source information copied (or compiled) into the `docs` directory that controls the project +[Github Pages](https://pages.github.com/) website, with url [https://tomcl.github.io/issie/](https://tomcl.github.io/issie/). + +## Project versus File in the Issie application + +Issie allows the users to create projects and files within those projects. A Issie project is simply a folder named `` that contains an empty file named `.dprj` (dprj stands for diagram project). The project folder any non-zero number of design files, each named `.dgm` (dgm stands for diagram). each deisgn file represents one design sheet of a hierarchical hardware design, sheets can contain, as components, other sheets. + +When opening a project, Issie will initially search the given repository for `.dgm` files, parse and load their content, and allow the user to open them in Issie or use them as components in other designs. + +## Build Magic + +This project uses modern F# / dotnet cross-platform build. The build process does not normally concern a developer, but here is an overview for if it needs to be adjusted. + +* Before anything can be built Dotnet & Node.js are manually be (globally) installed. Dotnet includes the `paket` tool which will manage other dotnet-related dependencies. Node.js includes `npm` which will do the same for Node-related dependencies. NB - there are other popular packet managers for Node, e.g. Yarn. They do not mix with npm, so make sure you do not use them. Confusingly, they will sort-of work, but cause install incompatibilities. + * Dotnet dependencies are executable programs or libraries that run under dotnet and are written in C#'. F#, etc. + * Node dependencies are (always) Javascript modules which run under node. +* Initially (the first time `build.cmd` is run) the build tools categorised in `dotnet-tools.json` are installed by `dotnet tool restore`. + * fake (with the F# compiler) + * fable +* Next all the project Dotnet dependencies (`paket.dependencies` for the whole project, selected from by the `paket.references` in each project directory, are loaded by the `paket` packet manager. +* Finally fake runs `build.fsx` (this is platform-independent) which uses `npm` to install all the node (Javascript) dependencies listed in `package.json`. That includes tools like webpack and electron, which run under node, as well as the node libraries that will be used by needed by the running electron app, including electron itself. These are all loaded by the `npm` packet manager. + +## Getting Started + +If you just want to run the app go to the [releases page](https://github.com/tomcl/issie/releases) and +download and run the latest prebuilt binary for your platform (Windows or Macos). Issie will require in total about 200M of disk space. + +* Windows: unzip \*.zip anywhere and double-click the top-level `Issie.exe` application in the unzipped files. +* Macos: Double click the dmg file and run the application inside the folder, or drag and drop this to install. + * The binaries are not signed. You will need to [perform a one-off security bypass](https://www.wikihow.com/Install-Software-from-Unsigned-Developers-on-a-Mac). + +### + +Issie installs and runs without making system changes - all of its code is inside the directory you download. You can delete this and replace it by a later version of Issie. Each design sheet is stored in a similarly named file under the porject directory. The subdirectory `backup` there contains a large numbers of backup snapshots for design recovery. These are not needed for Issie operation so you can delete them - or even the whole `backup` directory, if you wish. + +## Getting Started as Developer + +If you want to get started as a developer, follow these steps. + +### Development Install Prerequisites + +Download and install (if you already have these tools installed just check the version constraints). + + +* [.Net 6 SDK](https://dotnet.microsoft.com/download/dotnet/5.0). Version >= 6.0 +* [Node.js v14](https://nodejs.org/dist/latest-v14.x/). **Version 12 or (preferably) v14 - NOT latest 16** + * Node.js includes the `npm` package manager, so this does not need to be installed separately. + * The lastest LTS version of Node is now v16. That will currently NOT work. + * If you are using a different version of Node for developmnet on oytehr projects, global install + (the default) may interfere with this. You will need to do a more complex local node install. +* (recommended) Visual Studio 2022 which includes F# 6.0 +* (recommended) install [hyper.js](https://hyper.is/) to have a good command line interface - anything else you like will do. + +### Issie Development + +1. Download & unzip the [Issie repo](https://github.com/tomcl/ISSIE), or if contributing clone it locally, or fork it on github and then clone it locally. Make sure you are contributing to the Issie repo - not the Issie parent repo, if cloning (Github desktop gives you this option when you clone). + +3. Navigate to the project root directory (which contains this README) in a command-line interpreter. For Windows usage make sure if possible for convenience +that you have a _tabbed_ command-line interpreter that can be started direct from file explorer within a specific directory (by right-clicking on the explorer directory view). +That makes things a lot more pleasant. The new [Windows Terminal](https://github.com/microsoft/terminal) works well. + +4. Run `build.cmd` under Windows or `build.sh` under linux or macos. This will download and install all dependencies then launch the application with HMR. + + * HMR: the application will automatically recompile and update while running if you save updated source files + * To initialise and reload: `File -> reload page` + * To exit: after you exit the application the auto-compile script will terminate after about 15s + * To recompile the application `npm run dev` or `npm run devfast` (devfast switches off some debugging to make simulation run a lot faster). + * To generate distributable binaries for dev host system `npm run dist`. + * If you have changed node modules use `build dev`. Note that this project uses npm, not yarn. If npm gets stuck use `build cleannode` and try again. + * From time to time run `build killzombies` to terminate orphan node and dotnet processes which accumulate using this dev chain. (Not sure if this is still needed) + +#### Development on Macos + +In theory the build should work equally well on macos. Practically that is now (10/2021) the case. Having installed the normal prerequisites, and Visual Studio for Mac, which itself has the F# compiler, the one-off setup can be done manually from the various build steps needed: + +* git clone to local project directory as normal (with github desktop or command line git - one off) +* dotnet tool restore (build tools - one off) +* dotnet paket install (install dotnet packages one off) +* npm install (install node packages - one off) +* npm run dev (run the dev envt) + + +One unresolved issue that can occur on Macs is file permission problems. Best practice is for all installation and dev to run under the current (non-admin) user. If any part of the necessary downloaded development files gets written as root then subsequent development commands that modify it will need to be executed using sudo. + +``` +sudo npm run devfast +``` + +If possible, try to avoid this, but if necessary it can be done. Probably the better solution is to investigate properly which install steps introduce these root owner files, change the file ownership back to current user with `chown -R `. Please document any progress made with mac builds (detailing which mac OS) on an issue. + + +## Reinstalling Compiler and Libraries + +To reinstall the build environment (without changing project code) rerun `build.cmd` (Windows) or `build.sh` (Linux and MacOS). You may need first to +run `build killzombies` to remove orphan processes that lock build files. + +## Creating binaries + +`npm run dist` will generate the correct binaries for your system under `/dist`. + +* There is a very rare bug in the code that downloads electron binaries that is sensitive to fast internet access: +going through a VPN makes it go away. It is one-off since the binaries are cached once downloaded. If this hits you +the workaround is to run the build script again using Imperial College VPN. Having downloaded the binaries once +the porblem will go away. + +## TODO + + +* Should Node be upgraded to v14? +* Clean up Paket dependencies + diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md new file mode 100644 index 0000000..5a79631 --- /dev/null +++ b/RELEASE_NOTES.md @@ -0,0 +1,20 @@ +### v0.5.0 - Issie 1st release + +* Change name to Issie - Interative Simulation and Schematic Integrated Editor. +* Mend build system - now HMR works. +* Breaking change - alter size of NOT gates => any old sheet with the NOT gates will crash the software on load. + +### v0.4.0 - DECAD 1st release + +* Major update to build system. +* Upgrade all packages to latest. +* Mend bug in loading of exact wire and bus positions. +* Change name to DECAD. + +### 0.2 - March, 2020 + +* End of FYP Release + +### v0.1-beta + +* User feedback release diff --git a/Tests/CanvasStates.fs b/Tests/CanvasStates.fs new file mode 100644 index 0000000..accabc8 --- /dev/null +++ b/Tests/CanvasStates.fs @@ -0,0 +1,738 @@ +module CanvasStates + +open CommonTypes + +// Guidelines to create states: +// - draw the diagram you want to test in the actual application, then log its +// state state. Use logStateToFSharp.py to transform the log output into +// a (almost) valid FSharp data structure. +// - write it from scratch. Remember: +// --> each component Id must be unique +// --> each connection Id must be unique +// --> each port Id must be unique + +let makeCustomComponent (dep:LoadedComponent) = { + Name = dep.Name + InputLabels = dep.InputLabels + OutputLabels = dep.OutputLabels +} + +/// Just a single input node. No conections. +let state1 : CanvasState = + [ + { + Id = "input-node0"; + Type = Input 1; + Label = "input-node0-label"; + InputPorts = []; + OutputPorts = [{ + Id = "out-port0"; + PortNumber = Some 0; + PortType = PortType.Output; + HostId = "input-node0" + }]; + X = 169; + Y = 175 + H=50; + W=40; + } + ], + [] + +/// State1 loaded as a dependency. +let state1Dependency : LoadedComponent = { + Name = "broken-one-input" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + FilePath = "" + CanvasState = state1 + InputLabels = ["input-node0", 1] + OutputLabels = [] +} + +/// State1 custom component. +let state1CustomComponent : CustomComponentType = + makeCustomComponent state1Dependency + +/// Two unconnected input nodes. No conections. +let state2 : CanvasState = + [ + { H=50; W=40; Id = "input-node0"; Type = Input 1; Label = "input-node0-label"; InputPorts = []; OutputPorts = [{Id = "input-node0-out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "input-node1"; Type = Input 1; Label = "input-node1-label"; InputPorts = []; OutputPorts = [{Id = "input-node1-out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "input-node1"}]; X = 169; Y = 175} + ], + [] + +/// Simple circuit with one input connected to one output. +let state3 : CanvasState = + [ + { H=50; W=40; Id = "input-node0"; Type = Input 1; Label = "input-node0-label"; InputPorts = []; OutputPorts = [{Id = "out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "output-node0"; Type = Output 1; Label = "output-node0-label"; InputPorts = [{Id = "inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output-node0"}]; OutputPorts = []; X = 364; Y = 175} + ], + [ + { Id = "conn0"; Source = {Id = "out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "input-node0"}; Target = {Id = "inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "output-node0"}; Vertices = []} + ] + +/// State3 loaded as a dependency. +let state3Dependency : LoadedComponent = { + Name = "input-output" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + FilePath = "" + CanvasState = state3 + InputLabels = ["input-node0-label", 1] + OutputLabels = ["output-node0-label", 1] +} + +/// State3 custom component. +let state3CustomComponent : CustomComponentType = + makeCustomComponent state3Dependency + +/// Simple circuit with one input connected to two outputs. +let state4 : CanvasState = + [ + { H=50; W=40; Id = "input-node0"; Type = Input 1; Label = "input-node0-label"; InputPorts = []; OutputPorts = [{Id = "out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "output-node0"; Type = Output 1; Label = "output-node0-label"; InputPorts = [{Id = "output-node0-inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output-node0"}]; OutputPorts = []; X = 364; Y = 175} + { H=50; W=40; Id = "output-node1"; Type = Output 1; Label = "output-node1-label"; InputPorts = [{Id = "output-node1-inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output-node1"}]; OutputPorts = []; X = 364; Y = 175} + ], + [ + { Id = "conn0"; Source = {Id = "out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "input-node0"}; Target = {Id = "output-node0-inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "output-node0"}; Vertices = []} + { Id = "conn1"; Source = {Id = "out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "input-node0"}; Target = {Id = "output-node1-inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "output-node1"}; Vertices = []} + ] + +/// Two inputs connected to the same output. +let state5 : CanvasState = + [ + { H=50; W=40; Id = "input-node0"; Type = Input 1; Label = "input-node0-label"; InputPorts = []; OutputPorts = [{Id = "input-node0-out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "input-node1"; Type = Input 1; Label = "input-node1-label"; InputPorts = []; OutputPorts = [{Id = "input-node1-out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "input-node1"}]; X = 169; Y = 175} + { H=50; W=40; Id = "output-node0"; Type = Output 1; Label = "output-node0-label"; InputPorts = [{Id = "inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output-node0"}]; OutputPorts = []; X = 364; Y = 175} + ], + [ + { Id = "conn0"; Source = {Id = "input-node0-out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "input-node0"}; Target = {Id = "inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "output-node0"}; Vertices = []} + { Id = "conn1"; Source = {Id = "input-node1-out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "input-node1"}; Target = {Id = "inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "output-node0"}; Vertices = []} + ] + +/// Two inputs; one And; one output. +let state6 : CanvasState = + [ + { H=50; W=40; Id = "top-input"; Type = Input 1; Label = "input-node0-label"; InputPorts = []; OutputPorts = [{Id = "top-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "top-input"}]; X = 326; Y = 440} + { H=50; W=40; Id = "bottom-input"; Type = Input 1; Label = "input-node1-label"; InputPorts = []; OutputPorts = [{Id = "bottom-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "bottom-input"}]; X = 321; Y = 492} + { H=50; W=40; Id = "and"; Type = And; Label = ""; InputPorts = [{Id = "and-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and"}; {Id = "and-in1"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and"}]; OutputPorts = [{Id = "and-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and"}]; X = 428; Y = 459} + { H=50; W=40; Id = "output"; Type = Output 1; Label = "output-node0-label"; InputPorts = [{Id = "output-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output"}]; OutputPorts = []; X = 610; Y = 469} + ], + [ + {Id = "conn0"; Source = {Id = "top-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "top-input"}; Target = {Id = "and-in0"; PortNumber = None; PortType = PortType.Input; HostId = "and"}; Vertices = []} + {Id = "conn1"; Source = {Id = "bottom-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "bottom-input"}; Target = {Id = "and-in1"; PortNumber = None; PortType = PortType.Input; HostId = "and"}; Vertices = []} + {Id = "conn2"; Source = {Id = "and-out0"; PortNumber = None; PortType = PortType.Output; HostId = "and"}; Target = {Id = "output-in0"; PortNumber = None; PortType = PortType.Input; HostId = "output"}; Vertices = []} + ] + +/// Two inputs; one And; one output; with extra connection input to output. +let state7 : CanvasState = + [ + { H=50; W=40; Id = "top-input"; Type = Input 1; Label = "input-node0-label"; InputPorts = []; OutputPorts = [{Id = "top-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "top-input"}]; X = 326; Y = 440} + { H=50; W=40; Id = "bottom-input"; Type = Input 1; Label = "input-node1-label"; InputPorts = []; OutputPorts = [{Id = "bottom-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "bottom-input"}]; X = 321; Y = 492} + { H=50; W=40; Id = "and"; Type = And; Label = ""; InputPorts = [{Id = "and-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and"}; {Id = "and-in1"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and"}]; OutputPorts = [{Id = "and-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and"}]; X = 428; Y = 459} + { H=50; W=40; Id = "output"; Type = Output 1; Label = "output-node0-label"; InputPorts = [{Id = "output-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output"}]; OutputPorts = []; X = 610; Y = 469} + ], + [ + {Id = "conn0"; Source = {Id = "top-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "top-input"}; Target = {Id = "and-in0"; PortNumber = None; PortType = PortType.Input; HostId = "and"}; Vertices = []} + {Id = "conn1"; Source = {Id = "bottom-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "bottom-input"}; Target = {Id = "and-in1"; PortNumber = None; PortType = PortType.Input; HostId = "and"}; Vertices = []} + {Id = "conn2"; Source = {Id = "and-out0"; PortNumber = None; PortType = PortType.Output; HostId = "and"}; Target = {Id = "output-in0"; PortNumber = None; PortType = PortType.Input; HostId = "output"}; Vertices = []} + {Id = "conn3"; Source = {Id = "bottom-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "bottom-input"}; Target = {Id = "output-in0"; PortNumber = None; PortType = PortType.Input; HostId = "output"}; Vertices = []} + ] + +/// Two inputs; one And; one output; with extra connections inputs to and. +let state8 : CanvasState = + [ + { H=50; W=40; Id = "top-input"; Type = Input 1; Label = "input-node0-label"; InputPorts = []; OutputPorts = [{Id = "top-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "top-input"}]; X = 326; Y = 440} + { H=50; W=40; Id = "bottom-input"; Type = Input 1; Label = "input-node1-label"; InputPorts = []; OutputPorts = [{Id = "bottom-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "bottom-input"}]; X = 321; Y = 492} + { H=50; W=40; Id = "and"; Type = And; Label = ""; InputPorts = [{Id = "and-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and"}; {Id = "and-in1"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and"}]; OutputPorts = [{Id = "and-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and"}]; X = 428; Y = 459} + { H=50; W=40; Id = "output"; Type = Output 1; Label = "output-node0-label"; InputPorts = [{Id = "output-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output"}]; OutputPorts = []; X = 610; Y = 469} + ], + [ + {Id = "conn0"; Source = {Id = "top-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "top-input"}; Target = {Id = "and-in0"; PortNumber = None; PortType = PortType.Input; HostId = "and"}; Vertices = []} + {Id = "conn1"; Source = {Id = "bottom-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "bottom-input"}; Target = {Id = "and-in1"; PortNumber = None; PortType = PortType.Input; HostId = "and"}; Vertices = []} + {Id = "conn2"; Source = {Id = "and-out0"; PortNumber = None; PortType = PortType.Output; HostId = "and"}; Target = {Id = "output-in0"; PortNumber = None; PortType = PortType.Input; HostId = "output"}; Vertices = []} + {Id = "conn3"; Source = {Id = "top-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "top-input"}; Target = {Id = "and-in1"; PortNumber = None; PortType = PortType.Input; HostId = "and"}; Vertices = []} + {Id = "conn4"; Source = {Id = "bottom-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "bottom-input"}; Target = {Id = "and-in0"; PortNumber = None; PortType = PortType.Input; HostId = "and"}; Vertices = []} + ] + +/// Mux2 with only two connected ports. +let state9 : CanvasState = + [ + { H=50; W=40; Id = "top-input"; Type = Input 1; Label = "input-node0-label"; InputPorts = []; OutputPorts = [{Id = "top-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "top-input"}]; X = 326; Y = 440} + { H=50; W=40; Id = "bottom-input"; Type = Input 1; Label = "input-node1-label"; InputPorts = []; OutputPorts = [{Id = "bottom-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "bottom-input"}]; X = 321; Y = 492} + { H=50; W=40; Id = "mux"; Type = Mux2; Label = ""; InputPorts = [{Id = "mux-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "mux"}; {Id = "mux-in1"; PortNumber = Some 1; PortType = PortType.Input; HostId = "mux"}; {Id = "mux-in2"; PortNumber = Some 2; PortType = PortType.Input; HostId = "mux"};]; OutputPorts = [{Id = "mux-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "mux"}]; X = 428; Y = 459} + { H=50; W=40; Id = "output"; Type = Output 1; Label = "output-node0-label"; InputPorts = [{Id = "output-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output"}]; OutputPorts = []; X = 610; Y = 469} + ], + [ + {Id = "conn0"; Source = {Id = "top-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "top-input"}; Target = {Id = "mux-in0"; PortNumber = None; PortType = PortType.Input; HostId = "mux"}; Vertices = []} + {Id = "conn1"; Source = {Id = "bottom-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "bottom-input"}; Target = {Id = "mux-in1"; PortNumber = None; PortType = PortType.Input; HostId = "mux"}; Vertices = []} + {Id = "conn2"; Source = {Id = "mux-out0"; PortNumber = None; PortType = PortType.Output; HostId = "mux"}; Target = {Id = "output-in0"; PortNumber = None; PortType = PortType.Input; HostId = "output"}; Vertices = []} + ] + +/// Complex diagram with 3 Ands; one input; one output and 2 cycles (yet all +/// ports are connected prpoerly). +let state10 : CanvasState = + [ + { H=50; W=40; Id = "and0"; Type = And; Label = ""; InputPorts = [{Id = "8e8b684e-664f-5758-15c9-79c84c8fc81a"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and0"}; {Id = "d9b40581-2587-506d-1868-8201d3802913"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and0"}]; OutputPorts = [{Id = "edb944e4-1fe8-e9e2-eaf2-e5278277b29d"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and0"}]; X = 392; Y = 79} + { H=50; W=40; Id = "and1"; Type = And; Label = ""; InputPorts = [{Id = "23f32198-bf52-0456-6be2-1fbe92b36bbf"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and1"}; {Id = "9697ec8d-b6d3-9f2a-aaaf-0907fd087e05"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and1"}]; OutputPorts = [{Id = "41d15996-0838-6a41-e974-ee330fd13607"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and1"}]; X = 593; Y = 86} + { H=50; W=40; Id = "output"; Type = Output 1; Label = "output"; InputPorts = [{Id = "25886b76-feee-6892-6637-cc2378fe6094"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output"}]; OutputPorts = []; X = 770; Y = 187} + { H=50; W=40; Id = "input"; Type = Input 1; Label = "input"; InputPorts = []; OutputPorts = [{Id = "14344e8e-9448-4933-9004-85756859c64d"; PortNumber = Some 0; PortType = PortType.Output; HostId = "input"}]; X = 492; Y = 245} + { H=50; W=40; Id = "and2"; Type = And; Label = ""; InputPorts = [{Id = "aefefef8-61ea-a3cf-49f9-11b858342504"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and2"}; {Id = "5c4d25e1-c067-79d3-adc7-7e141f5a7905"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and2"}]; OutputPorts = [{Id = "26de501f-4e60-9f61-fce0-6e5fdb131f87"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and2"}]; X = 268; Y = 261} + ], + [ + {Id = "conn0"; Source = {Id = "41d15996-0838-6a41-e974-ee330fd13607"; PortNumber = None; PortType = PortType.Output; HostId = "and1"}; Target = {Id = "25886b76-feee-6892-6637-cc2378fe6094"; PortNumber = None; PortType = PortType.Input; HostId = "output"}; Vertices = []} + {Id = "conn1"; Source = {Id = "41d15996-0838-6a41-e974-ee330fd13607"; PortNumber = None; PortType = PortType.Output; HostId = "and1"}; Target = {Id = "5c4d25e1-c067-79d3-adc7-7e141f5a7905"; PortNumber = None; PortType = PortType.Input; HostId = "and2"}; Vertices = []} + {Id = "conn2"; Source = {Id = "14344e8e-9448-4933-9004-85756859c64d"; PortNumber = None; PortType = PortType.Output; HostId = "input"}; Target = {Id = "9697ec8d-b6d3-9f2a-aaaf-0907fd087e05"; PortNumber = None; PortType = PortType.Input; HostId = "and1"}; Vertices = []} + {Id = "conn3"; Source = {Id = "edb944e4-1fe8-e9e2-eaf2-e5278277b29d"; PortNumber = None; PortType = PortType.Output; HostId = "and0"}; Target = {Id = "23f32198-bf52-0456-6be2-1fbe92b36bbf"; PortNumber = None; PortType = PortType.Input; HostId = "and1"}; Vertices = []} + {Id = "conn4"; Source = {Id = "edb944e4-1fe8-e9e2-eaf2-e5278277b29d"; PortNumber = None; PortType = PortType.Output; HostId = "and0"}; Target = {Id = "aefefef8-61ea-a3cf-49f9-11b858342504"; PortNumber = None; PortType = PortType.Input; HostId = "and2"}; Vertices = []} + {Id = "conn5"; Source = {Id = "26de501f-4e60-9f61-fce0-6e5fdb131f87"; PortNumber = None; PortType = PortType.Output; HostId = "and2"}; Target = {Id = "8e8b684e-664f-5758-15c9-79c84c8fc81a"; PortNumber = None; PortType = PortType.Input; HostId = "and0"}; Vertices = []} + {Id = "conn6"; Source = {Id = "26de501f-4e60-9f61-fce0-6e5fdb131f87"; PortNumber = None; PortType = PortType.Output; HostId = "and2"}; Target = {Id = "d9b40581-2587-506d-1868-8201d3802913"; PortNumber = None; PortType = PortType.Input; HostId = "and0"}; Vertices = []} + ] + +/// Complex diagram with 3 Ands; one input; one output and 1 cycles with three +/// components (yet all ports are connected prpoerly). +let state11 : CanvasState = + [ + { H=50; W=40; Id = "and0"; Type = And; Label = ""; InputPorts = [{Id = "8e8b684e-664f-5758-15c9-79c84c8fc81a"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and0"}; {Id = "d9b40581-2587-506d-1868-8201d3802913"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and0"}]; OutputPorts = [{Id = "edb944e4-1fe8-e9e2-eaf2-e5278277b29d"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and0"}]; X = 392; Y = 79} + { H=50; W=40; Id = "and1"; Type = And; Label = ""; InputPorts = [{Id = "23f32198-bf52-0456-6be2-1fbe92b36bbf"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and1"}; {Id = "9697ec8d-b6d3-9f2a-aaaf-0907fd087e05"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and1"}]; OutputPorts = [{Id = "41d15996-0838-6a41-e974-ee330fd13607"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and1"}]; X = 593; Y = 86} + { H=50; W=40; Id = "output"; Type = Output 1; Label = "output"; InputPorts = [{Id = "25886b76-feee-6892-6637-cc2378fe6094"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output"}]; OutputPorts = []; X = 770; Y = 187} + { H=50; W=40; Id = "input"; Type = Input 1; Label = "input"; InputPorts = []; OutputPorts = [{Id = "14344e8e-9448-4933-9004-85756859c64d"; PortNumber = Some 0; PortType = PortType.Output; HostId = "input"}]; X = 492; Y = 245} + { H=50; W=40; Id = "and2"; Type = And; Label = ""; InputPorts = [{Id = "aefefef8-61ea-a3cf-49f9-11b858342504"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and2"}; {Id = "5c4d25e1-c067-79d3-adc7-7e141f5a7905"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and2"}]; OutputPorts = [{Id = "26de501f-4e60-9f61-fce0-6e5fdb131f87"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and2"}]; X = 268; Y = 261} + ], + [ + {Id = "conn0"; Source = {Id = "41d15996-0838-6a41-e974-ee330fd13607"; PortNumber = None; PortType = PortType.Output; HostId = "and1"}; Target = {Id = "25886b76-feee-6892-6637-cc2378fe6094"; PortNumber = None; PortType = PortType.Input; HostId = "output"}; Vertices = []} + {Id = "conn1"; Source = {Id = "41d15996-0838-6a41-e974-ee330fd13607"; PortNumber = None; PortType = PortType.Output; HostId = "and1"}; Target = {Id = "5c4d25e1-c067-79d3-adc7-7e141f5a7905"; PortNumber = None; PortType = PortType.Input; HostId = "and2"}; Vertices = []} + {Id = "conn2"; Source = {Id = "14344e8e-9448-4933-9004-85756859c64d"; PortNumber = None; PortType = PortType.Output; HostId = "input"}; Target = {Id = "9697ec8d-b6d3-9f2a-aaaf-0907fd087e05"; PortNumber = None; PortType = PortType.Input; HostId = "and1"}; Vertices = []} + {Id = "conn3"; Source = {Id = "edb944e4-1fe8-e9e2-eaf2-e5278277b29d"; PortNumber = None; PortType = PortType.Output; HostId = "and0"}; Target = {Id = "23f32198-bf52-0456-6be2-1fbe92b36bbf"; PortNumber = None; PortType = PortType.Input; HostId = "and1"}; Vertices = []} + {Id = "conn4"; Source = {Id = "41d15996-0838-6a41-e974-ee330fd13607"; PortNumber = None; PortType = PortType.Output; HostId = "and1"}; Target = {Id = "aefefef8-61ea-a3cf-49f9-11b858342504"; PortNumber = None; PortType = PortType.Input; HostId = "and2"}; Vertices = []} + {Id = "conn5"; Source = {Id = "26de501f-4e60-9f61-fce0-6e5fdb131f87"; PortNumber = None; PortType = PortType.Output; HostId = "and2"}; Target = {Id = "8e8b684e-664f-5758-15c9-79c84c8fc81a"; PortNumber = None; PortType = PortType.Input; HostId = "and0"}; Vertices = []} + {Id = "conn6"; Source = {Id = "26de501f-4e60-9f61-fce0-6e5fdb131f87"; PortNumber = None; PortType = PortType.Output; HostId = "and2"}; Target = {Id = "d9b40581-2587-506d-1868-8201d3802913"; PortNumber = None; PortType = PortType.Input; HostId = "and0"}; Vertices = []} + ] + +/// Complex diagram with 3 Ands; one input; one output and no cycles. +let state12 : CanvasState = + [ + { H=50; W=40; Id = "and0"; Type = And; Label = ""; InputPorts = [{Id = "8e8b684e-664f-5758-15c9-79c84c8fc81a"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and0"}; {Id = "d9b40581-2587-506d-1868-8201d3802913"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and0"}]; OutputPorts = [{Id = "edb944e4-1fe8-e9e2-eaf2-e5278277b29d"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and0"}]; X = 392; Y = 79} + { H=50; W=40; Id = "and1"; Type = And; Label = ""; InputPorts = [{Id = "23f32198-bf52-0456-6be2-1fbe92b36bbf"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and1"}; {Id = "9697ec8d-b6d3-9f2a-aaaf-0907fd087e05"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and1"}]; OutputPorts = [{Id = "41d15996-0838-6a41-e974-ee330fd13607"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and1"}]; X = 593; Y = 86} + { H=50; W=40; Id = "output"; Type = Output 1; Label = "output"; InputPorts = [{Id = "25886b76-feee-6892-6637-cc2378fe6094"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output"}]; OutputPorts = []; X = 770; Y = 187} + { H=50; W=40; Id = "input"; Type = Input 1; Label = "input"; InputPorts = []; OutputPorts = [{Id = "14344e8e-9448-4933-9004-85756859c64d"; PortNumber = Some 0; PortType = PortType.Output; HostId = "input"}]; X = 492; Y = 245} + { H=50; W=40; Id = "and2"; Type = And; Label = ""; InputPorts = [{Id = "aefefef8-61ea-a3cf-49f9-11b858342504"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and2"}; {Id = "5c4d25e1-c067-79d3-adc7-7e141f5a7905"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and2"}]; OutputPorts = [{Id = "26de501f-4e60-9f61-fce0-6e5fdb131f87"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and2"}]; X = 268; Y = 261} + ], + [ + {Id = "conn0"; Source = {Id = "41d15996-0838-6a41-e974-ee330fd13607"; PortNumber = None; PortType = PortType.Output; HostId = "and1"}; Target = {Id = "25886b76-feee-6892-6637-cc2378fe6094"; PortNumber = None; PortType = PortType.Input; HostId = "output"}; Vertices = []} + {Id = "conn1"; Source = {Id = "14344e8e-9448-4933-9004-85756859c64d"; PortNumber = None; PortType = PortType.Output; HostId = "input"}; Target = {Id = "5c4d25e1-c067-79d3-adc7-7e141f5a7905"; PortNumber = None; PortType = PortType.Input; HostId = "and2"}; Vertices = []} + {Id = "conn2"; Source = {Id = "14344e8e-9448-4933-9004-85756859c64d"; PortNumber = None; PortType = PortType.Output; HostId = "input"}; Target = {Id = "9697ec8d-b6d3-9f2a-aaaf-0907fd087e05"; PortNumber = None; PortType = PortType.Input; HostId = "and1"}; Vertices = []} + {Id = "conn3"; Source = {Id = "edb944e4-1fe8-e9e2-eaf2-e5278277b29d"; PortNumber = None; PortType = PortType.Output; HostId = "and0"}; Target = {Id = "23f32198-bf52-0456-6be2-1fbe92b36bbf"; PortNumber = None; PortType = PortType.Input; HostId = "and1"}; Vertices = []} + {Id = "conn4"; Source = {Id = "14344e8e-9448-4933-9004-85756859c64d"; PortNumber = None; PortType = PortType.Output; HostId = "input"}; Target = {Id = "aefefef8-61ea-a3cf-49f9-11b858342504"; PortNumber = None; PortType = PortType.Input; HostId = "and2"}; Vertices = []} + {Id = "conn5"; Source = {Id = "26de501f-4e60-9f61-fce0-6e5fdb131f87"; PortNumber = None; PortType = PortType.Output; HostId = "and2"}; Target = {Id = "8e8b684e-664f-5758-15c9-79c84c8fc81a"; PortNumber = None; PortType = PortType.Input; HostId = "and0"}; Vertices = []} + {Id = "conn6"; Source = {Id = "26de501f-4e60-9f61-fce0-6e5fdb131f87"; PortNumber = None; PortType = PortType.Output; HostId = "and2"}; Target = {Id = "d9b40581-2587-506d-1868-8201d3802913"; PortNumber = None; PortType = PortType.Input; HostId = "and0"}; Vertices = []} + ] + +/// One bit adder. +let state13 : CanvasState = + [ + { H=50; W=40; Id="2953603d-44e4-5c1f-3fb1-698f7863b6b5";Type=Input 1;Label="A";InputPorts=[];OutputPorts=[{Id="336aab97-a7bd-9a37-9062-56753b57c268";PortNumber= Some 0;PortType=PortType.Output;HostId="2953603d-44e4-5c1f-3fb1-698f7863b6b5"}];X=97;Y=111} + { H=50; W=40; Id="170e69f4-b3d7-d9e0-9f1d-6a564ba62062";Type=Input 1;Label="B";InputPorts=[];OutputPorts=[{Id="1ee439f3-8d23-c049-ff9e-cd8f1b4d3d9d";PortNumber= Some 0;PortType=PortType.Output;HostId="170e69f4-b3d7-d9e0-9f1d-6a564ba62062"}];X=54;Y=203} + { H=50; W=40; Id="253e21f0-b062-4858-c315-5a5315cadf45";Type=And;Label="";InputPorts=[{Id="1b2c73d1-b38e-64e6-5b19-e4e7f690a692";PortNumber= Some 0;PortType=PortType.Input;HostId="253e21f0-b062-4858-c315-5a5315cadf45"}; {Id="9fdb22f6-f8eb-829f-68b3-87b9c8577299";PortNumber= Some 1;PortType=PortType.Input;HostId="253e21f0-b062-4858-c315-5a5315cadf45"}];OutputPorts=[{Id="95a03834-e494-92b2-b8d4-a148e3c0763b";PortNumber= Some 0;PortType=PortType.Output;HostId="253e21f0-b062-4858-c315-5a5315cadf45"}];X=498;Y=208} + { H=50; W=40; Id="6b7bac71-eec5-4979-834a-c1bfe40d77b9";Type=Xor;Label="";InputPorts=[{Id="6a468f2c-4db4-d3ae-402f-a617885884e7";PortNumber= Some 0;PortType=PortType.Input;HostId="6b7bac71-eec5-4979-834a-c1bfe40d77b9"}; {Id="9826a9b5-cd62-51ec-6368-93c4967745f9";PortNumber= Some 1;PortType=PortType.Input;HostId="6b7bac71-eec5-4979-834a-c1bfe40d77b9"}];OutputPorts=[{Id="7cb01ee2-49d4-00b5-7523-14e4de3c5489";PortNumber= Some 0;PortType=PortType.Output;HostId="6b7bac71-eec5-4979-834a-c1bfe40d77b9"}];X=501;Y=108} + { H=50; W=40; Id="9aaf18a9-b3ac-bf51-1ed3-625baa1ff6a9";Type=Output 1;Label="Sum";InputPorts=[{Id="14b23a60-21ae-374f-d083-41aa2510eeab";PortNumber= Some 0;PortType=PortType.Input;HostId="9aaf18a9-b3ac-bf51-1ed3-625baa1ff6a9"}];OutputPorts=[];X=691;Y=122} + { H=50; W=40; Id="94da6dd7-a263-a3ec-ec76-bfa07b0b0f34";Type=Output 1;Label="Carry";InputPorts=[{Id="b9d457f7-dcef-89a1-aa76-b9ba7f9ca3f4";PortNumber= Some 0;PortType=PortType.Input;HostId="94da6dd7-a263-a3ec-ec76-bfa07b0b0f34"}];OutputPorts=[];X=692;Y=223} + ], + [ + {Id="79df6e40-7ad2-b1d2-cb98-ea5d649ef1cc";Source={Id="7cb01ee2-49d4-00b5-7523-14e4de3c5489";PortNumber=None;PortType=PortType.Output;HostId="6b7bac71-eec5-4979-834a-c1bfe40d77b9"};Target={Id="14b23a60-21ae-374f-d083-41aa2510eeab";PortNumber=None;PortType=PortType.Input;HostId="9aaf18a9-b3ac-bf51-1ed3-625baa1ff6a9"}; Vertices = []} + {Id="6b066c26-750b-6eb3-2516-bc122899f846";Source={Id="1ee439f3-8d23-c049-ff9e-cd8f1b4d3d9d";PortNumber=None;PortType=PortType.Output;HostId="170e69f4-b3d7-d9e0-9f1d-6a564ba62062"};Target={Id="9fdb22f6-f8eb-829f-68b3-87b9c8577299";PortNumber=None;PortType=PortType.Input;HostId="253e21f0-b062-4858-c315-5a5315cadf45"}; Vertices = []} + {Id="5f7c6896-8fbd-bfaf-ee0f-a677f7804283";Source={Id="1ee439f3-8d23-c049-ff9e-cd8f1b4d3d9d";PortNumber=None;PortType=PortType.Output;HostId="170e69f4-b3d7-d9e0-9f1d-6a564ba62062"};Target={Id="9826a9b5-cd62-51ec-6368-93c4967745f9";PortNumber=None;PortType=PortType.Input;HostId="6b7bac71-eec5-4979-834a-c1bfe40d77b9"}; Vertices = []} + {Id="8ed22d89-b542-a182-fef9-1a67170da60e";Source={Id="336aab97-a7bd-9a37-9062-56753b57c268";PortNumber=None;PortType=PortType.Output;HostId="2953603d-44e4-5c1f-3fb1-698f7863b6b5"};Target={Id="1b2c73d1-b38e-64e6-5b19-e4e7f690a692";PortNumber=None;PortType=PortType.Input;HostId="253e21f0-b062-4858-c315-5a5315cadf45"}; Vertices = []} + {Id="0cd3f109-22ee-3543-7247-db2b4ffe5fc8";Source={Id="336aab97-a7bd-9a37-9062-56753b57c268";PortNumber=None;PortType=PortType.Output;HostId="2953603d-44e4-5c1f-3fb1-698f7863b6b5"};Target={Id="6a468f2c-4db4-d3ae-402f-a617885884e7";PortNumber=None;PortType=PortType.Input;HostId="6b7bac71-eec5-4979-834a-c1bfe40d77b9"}; Vertices = []} + {Id="3230b338-cdd4-7632-e441-9d2f50df013a";Source={Id="95a03834-e494-92b2-b8d4-a148e3c0763b";PortNumber=None;PortType=PortType.Output;HostId="253e21f0-b062-4858-c315-5a5315cadf45"};Target={Id="b9d457f7-dcef-89a1-aa76-b9ba7f9ca3f4";PortNumber=None;PortType=PortType.Input;HostId="94da6dd7-a263-a3ec-ec76-bfa07b0b0f34"}; Vertices = []} + ] + +/// Similar to state4, but output nodes have the same label. +let state14 : CanvasState = + [ + { H=50; W=40; Id = "input-node0"; Type = Input 1; Label = "input-node0-label"; InputPorts = []; OutputPorts = [{Id = "out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "output-node0"; Type = Output 1; Label = "output-duplicate-label"; InputPorts = [{Id = "output-node0-inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output-node0"}]; OutputPorts = []; X = 364; Y = 175} + { H=50; W=40; Id = "output-node1"; Type = Output 1; Label = "output-duplicate-label"; InputPorts = [{Id = "output-node1-inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output-node1"}]; OutputPorts = []; X = 364; Y = 175} + ], + [ + {Id = "conn0"; Source = {Id = "out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "input-node0"}; Target = {Id = "output-node0-inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "output-node0"}; Vertices = []} + {Id = "conn1"; Source = {Id = "out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "input-node0"}; Target = {Id = "output-node1-inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "output-node1"}; Vertices = []} + ] + +/// Similar to state6, but input nodes have the same label. +let state15 : CanvasState = + [ + { H=50; W=40; Id = "top-input"; Type = Input 1; Label = "input-duplicate-label"; InputPorts = []; OutputPorts = [{Id = "top-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "top-input"}]; X = 326; Y = 440} + { H=50; W=40; Id = "bottom-input"; Type = Input 1; Label = "input-duplicate-label"; InputPorts = []; OutputPorts = [{Id = "bottom-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "bottom-input"}]; X = 321; Y = 492} + { H=50; W=40; Id = "and"; Type = And; Label = ""; InputPorts = [{Id = "and-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and"}; {Id = "and-in1"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and"}]; OutputPorts = [{Id = "and-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and"}]; X = 428; Y = 459} + { H=50; W=40; Id = "output"; Type = Output 1; Label = "output-node0-label"; InputPorts = [{Id = "output-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output"}]; OutputPorts = []; X = 610; Y = 469} + ], + [ + {Id = "conn0"; Source = {Id = "top-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "top-input"}; Target = {Id = "and-in0"; PortNumber = None; PortType = PortType.Input; HostId = "and"}; Vertices = []} + {Id = "conn1"; Source = {Id = "bottom-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "bottom-input"}; Target = {Id = "and-in1"; PortNumber = None; PortType = PortType.Input; HostId = "and"}; Vertices = []} + {Id = "conn2"; Source = {Id = "and-out0"; PortNumber = None; PortType = PortType.Output; HostId = "and"}; Target = {Id = "output-in0"; PortNumber = None; PortType = PortType.Input; HostId = "output"}; Vertices = []} + ] + +/// One input and one output, connected to the state3CustomComponent. +let state16 : CanvasState = + [ + { H=50; W=40; Id = "outer-input-node0"; Type = Input 1; Label = "outer-input-node0-label"; InputPorts = []; OutputPorts = [{Id = "outer-out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "outer-input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "outer-output-node0"; Type = Output 1; Label = "outer-output-node0-label"; InputPorts = [{Id = "outer-inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "outer-output-node0"}]; OutputPorts = []; X = 364; Y = 175} + { + H=50; W=40; Id = "inp-out-component"; Type = Custom state3CustomComponent; Label = "inp-out-component-label"; + InputPorts = [{Id = "inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "inp-out-component"}]; + OutputPorts = [{Id = "out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "inp-out-component"}]; + X = 169; Y = 175 + } + ], + [ + { + Id = "conn0"; + Source = {Id = "outer-out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "outer-input-node0"}; + Target = {Id = "inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "inp-out-component"}; + Vertices = [] + } + { + Id = "conn1"; + Source = {Id = "out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "inp-out-component"}; + Target = {Id = "outer-inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "outer-output-node0"}; + Vertices = [] + } + ] + +/// State16 loaded as a dependency. +let state16Dependency : LoadedComponent = { + Name = "nested-input-output" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + FilePath = "" + CanvasState = state16 + InputLabels = ["outer-input-node0-label", 1] + OutputLabels = ["outer-output-node0-label", 1] +} + +/// State16 custom component. +let state16CustomComponent : CustomComponentType = + makeCustomComponent state16Dependency + +/// One input and one output, connected to the state16CustomComponent, which +/// contains the state3CustomComponent. +let state17 : CanvasState = + [ + { H=50; W=40; Id = "outer-outer-input-node0"; Type = Input 1; Label = "outer-outer-input-node0-label"; InputPorts = []; OutputPorts = [{Id = "outer-outer-out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "outer-outer-input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "outer-outer-output-node0"; Type = Output 1; Label = "outer-outer-output-node0-label"; InputPorts = [{Id = "outer-outer-inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "outer-outer-output-node0"}]; OutputPorts = []; X = 364; Y = 175} + { + H=50; W=40; Id = "wrapped-inp-out-component"; Type = Custom state3CustomComponent; Label = "wrapped-inp-out-component-label"; + InputPorts = [{Id = "inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "wrapped-inp-out-component"}]; + OutputPorts = [{Id = "out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "wrapped-inp-out-component"}]; + X = 169; Y = 175 + } + ], + [ + { + Id = "conn0"; + Source = {Id = "outer-outer-out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "outer-outer-input-node0"}; + Target = {Id = "inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "wrapped-inp-out-component"}; + Vertices = [] + } + { + Id = "conn1"; + Source = {Id = "out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "wrapped-inp-out-component"}; + Target = {Id = "outer-outer-inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "outer-outer-output-node0"}; + Vertices = [] + } + ] + +/// State17 loaded as a dependency. +let state17Dependency : LoadedComponent = { + Name = "doubly-nested-input-output" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + FilePath = "" + CanvasState = state17 + InputLabels = ["outer-outer-input-node0-label", 1] + OutputLabels = ["outer-outer-output-node0-label", 1] +} + +/// State17 custom component. +let state17CustomComponent : CustomComponentType = + makeCustomComponent state17Dependency + +/// One input and one output, connected to the state17CustomComponent, which +/// contains state16CustomComponent, which contains the state3CustomComponent. +let state18 : CanvasState = + [ + { H=50; W=40; Id = "outer-outer-outer-input-node0"; Type = Input 1; Label = "outer-outer-outer-input-node0-label"; InputPorts = []; OutputPorts = [{Id = "outer-outer-outer-out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "outer-outer-outer-input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "outer-outer-outer-output-node0"; Type = Output 1; Label = "outer-outer-outer-output-node0-label"; InputPorts = [{Id = "outer-outer-outer-inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "outer-outer-outer-output-node0"}]; OutputPorts = []; X = 364; Y = 175} + { + H=50; W=40; Id = "doubly-wrapped-inp-out-component"; Type = Custom state3CustomComponent; Label = "doubly-wrapped-inp-out-component-label"; + InputPorts = [{Id = "inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "doubly-wrapped-inp-out-component"}]; + OutputPorts = [{Id = "out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "doubly-wrapped-inp-out-component"}]; + X = 169; Y = 175 + } + ], + [ + { + Id = "conn0"; + Source = {Id = "outer-outer-outer-out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "outer-outer-outer-input-node0"}; + Target = {Id = "inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "doubly-wrapped-inp-out-component"}; + Vertices = [] + } + { + Id = "conn1"; + Source = {Id = "out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "doubly-wrapped-inp-out-component"}; + Target = {Id = "outer-outer-outer-inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "outer-outer-outer-output-node0"}; + Vertices = [] + } + ] + +/// One input connected to a broken dependency. +let state19 : CanvasState = + [ + { H=50; W=40; Id = "outer-input-node0"; Type = Input 1; Label = "outer-input-node0-label"; InputPorts = []; OutputPorts = [{Id = "outer-out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "outer-input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "broken-input"; Type = Custom state1CustomComponent; Label = "broken-input-label"; InputPorts = [{Id = "broken-input-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "broken-input"}]; OutputPorts = []; X = 169; Y = 175} + ], + [ + { + Id = "conn0" + Source = {Id = "outer-out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "outer-input-node0"} + Target = {Id = "broken-input-port0"; PortNumber = None; PortType = PortType.Input; HostId = "broken-input"} + Vertices = [] + } + ] + +/// Similar to state16, but uses state16CustomComponent instead of +/// state3CustomComponent to create a cycle. +let state20 : CanvasState = + [ + { H=50; W=40; Id = "outer-input-node0"; Type = Input 1; Label = "outer-input-node0-label"; InputPorts = []; OutputPorts = [{Id = "outer-out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "outer-input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "outer-output-node0"; Type = Output 1; Label = "outer-output-node0-label"; InputPorts = [{Id = "outer-inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "outer-output-node0"}]; OutputPorts = []; X = 364; Y = 175} + { + H=50; W=40; Id = "inp-out-component"; Type = Custom state16CustomComponent; Label = "inp-out-component-label"; + InputPorts = [{Id = "inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "inp-out-component"}]; + OutputPorts = [{Id = "out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "inp-out-component"}]; + X = 169; Y = 175 + } + ], + [ + { + Id = "conn0"; + Source = {Id = "outer-out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "outer-input-node0"}; + Target = {Id = "inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "inp-out-component"}; + Vertices = [] + } + { + Id = "conn1"; + Source = {Id = "out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "inp-out-component"}; + Target = {Id = "outer-inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "outer-output-node0"}; + Vertices = [] + } + ] + +// Test a long dependecy cycle. +// state21 --> state22 --> state23 --> state21 + +let state21CustomComponent : CustomComponentType = { + Name = "21-custom-component" + InputLabels = ["21-inp", 1] + OutputLabels = ["21-out", 1] +} + +let state22CustomComponent : CustomComponentType = { + Name = "22-custom-component" + InputLabels = ["22-inp", 1] + OutputLabels = ["22-out", 1] +} + +let state23CustomComponent : CustomComponentType = { + Name = "23-custom-component" + InputLabels = ["23-inp", 1] + OutputLabels = ["23-out", 1] +} + +/// Simple input-output component that uses state22. +let state21 : CanvasState = + [ + { H=50; W=40; Id = "outer-input-node0"; Type = Input 1; Label = "21-inp"; InputPorts = []; OutputPorts = [{Id = "outer-out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "outer-input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "outer-output-node0"; Type = Output 1; Label = "21-out"; InputPorts = [{Id = "outer-inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "outer-output-node0"}]; OutputPorts = []; X = 364; Y = 175} + { + H=50; W=40; Id = "inp-out-component"; Type = Custom state22CustomComponent; Label = "inp-out-component-label"; + InputPorts = [{Id = "inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "inp-out-component"}]; + OutputPorts = [{Id = "out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "inp-out-component"}]; + X = 169; Y = 175 + } + ], + [ + { + Id = "conn0"; + Source = {Id = "outer-out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "outer-input-node0"}; + Target = {Id = "inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "inp-out-component"}; + Vertices = [] + } + { + Id = "conn1"; + Source = {Id = "out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "inp-out-component"}; + Target = {Id = "outer-inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "outer-output-node0"}; + Vertices = [] + } + ] + +/// Simple input-output component that uses state23. +let state22 : CanvasState = + [ + { H=50; W=40; Id = "outer-input-node0"; Type = Input 1; Label = "22-inp"; InputPorts = []; OutputPorts = [{Id = "outer-out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "outer-input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "outer-output-node0"; Type = Output 1; Label = "22-out"; InputPorts = [{Id = "outer-inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "outer-output-node0"}]; OutputPorts = []; X = 364; Y = 175} + { + H=50; W=40; Id = "inp-out-component"; Type = Custom state23CustomComponent; Label = "inp-out-component-label"; + InputPorts = [{Id = "inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "inp-out-component"}]; + OutputPorts = [{Id = "out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "inp-out-component"}]; + X = 169; Y = 175 + } + ], + [ + { + Id = "conn0"; + Source = {Id = "outer-out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "outer-input-node0"}; + Target = {Id = "inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "inp-out-component"}; + Vertices = [] + } + { + Id = "conn1"; + Source = {Id = "out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "inp-out-component"}; + Target = {Id = "outer-inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "outer-output-node0"}; + Vertices = [] + } + ] + +/// Simple input-output component that uses state21. +let state23 : CanvasState = + [ + { H=50; W=40; Id = "outer-input-node0"; Type = Input 1; Label = "23-inp"; InputPorts = []; OutputPorts = [{Id = "outer-out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "outer-input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "outer-output-node0"; Type = Output 1; Label = "23-out"; InputPorts = [{Id = "outer-inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "outer-output-node0"}]; OutputPorts = []; X = 364; Y = 175} + { + H=50; W=40; Id = "inp-out-component"; Type = Custom state21CustomComponent; Label = "inp-out-component-label"; + InputPorts = [{Id = "inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "inp-out-component"}]; + OutputPorts = [{Id = "out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "inp-out-component"}]; + X = 169; Y = 175 + } + ], + [ + { + Id = "conn0"; + Source = {Id = "outer-out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "outer-input-node0"}; + Target = {Id = "inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "inp-out-component"}; + Vertices = [] + } + { + Id = "conn1"; + Source = {Id = "out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "inp-out-component"}; + Target = {Id = "outer-inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "outer-output-node0"}; + Vertices = [] + } + ] + +let state21Dependency : LoadedComponent = { + Name = "21-custom-component" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + FilePath = "" + CanvasState = state21 + InputLabels = ["21-inp", 1] + OutputLabels = ["21-out", 1] +} + +let state22Dependency : LoadedComponent = { + Name = "22-custom-component" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + FilePath = "" + CanvasState = state22 + InputLabels = ["22-inp", 1] + OutputLabels = ["22-out", 1] +} + +let state23Dependency : LoadedComponent = { + Name = "23-custom-component" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + FilePath = "" + CanvasState = state23 + InputLabels = ["23-inp", 1] + OutputLabels = ["23-out", 1] +} + +/// Simple input-output component that uses state23. +let state24 : CanvasState = + [ + { H=50; W=40; Id = "outer-input-node0"; Type = Input 1; Label = "24-inp"; InputPorts = []; OutputPorts = [{Id = "outer-out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "outer-input-node0"}]; X = 169; Y = 175} + { H=50; W=40; Id = "outer-output-node0"; Type = Output 1; Label = "24-out"; InputPorts = [{Id = "outer-inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "outer-output-node0"}]; OutputPorts = []; X = 364; Y = 175} + { + H=50; W=40; Id = "inp-out-component"; Type = Custom state23CustomComponent; Label = "inp-out-component-label"; + InputPorts = [{Id = "inp-port0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "inp-out-component"}]; + OutputPorts = [{Id = "out-port0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "inp-out-component"}]; + X = 169; Y = 175 + } + ], + [ + { + Id = "conn0"; + Source = {Id = "outer-out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "outer-input-node0"}; + Target = {Id = "inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "inp-out-component"}; + Vertices = [] + } + { + Id = "conn1"; + Source = {Id = "out-port0"; PortNumber = None; PortType = PortType.Output; HostId = "inp-out-component"}; + Target = {Id = "outer-inp-port0"; PortNumber = None; PortType = PortType.Input; HostId = "outer-output-node0"}; + Vertices = [] + } + ] + +/// Similar to state6, but with a missing connection from bottom input to and. +let state25 : CanvasState = + [ + {H=50; W=40; Id = "top-input"; Type = Input 1; Label = "input-node0-label"; InputPorts = []; OutputPorts = [{Id = "top-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "top-input"}]; X = 326; Y = 440} + {H=50; W=40; Id = "bottom-input"; Type = Input 1; Label = "input-node1-label"; InputPorts = []; OutputPorts = [{Id = "bottom-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "bottom-input"}]; X = 321; Y = 492} + {H=50; W=40; Id = "and"; Type = And; Label = ""; InputPorts = [{Id = "and-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and"}; {Id = "and-in1"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and"}]; OutputPorts = [{Id = "and-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and"}]; X = 428; Y = 459} + {H=50; W=40; Id = "output"; Type = Output 1; Label = "output-node0-label"; InputPorts = [{Id = "output-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output"}]; OutputPorts = []; X = 610; Y = 469} + ], + [ + {Id = "conn0"; Source = {Id = "top-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "top-input"}; Target = {Id = "and-in0"; PortNumber = None; PortType = PortType.Input; HostId = "and"}; Vertices = []} + {Id = "conn2"; Source = {Id = "and-out0"; PortNumber = None; PortType = PortType.Output; HostId = "and"}; Target = {Id = "output-in0"; PortNumber = None; PortType = PortType.Input; HostId = "output"}; Vertices = []} + ] + +/// Similar to state6, but with a missing connection from and to output. +let state26 : CanvasState = + [ + {H=50; W=40; Id = "top-input"; Type = Input 1; Label = "input-node0-label"; InputPorts = []; OutputPorts = [{Id = "top-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "top-input"}]; X = 326; Y = 440} + {H=50; W=40; Id = "bottom-input"; Type = Input 1; Label = "input-node1-label"; InputPorts = []; OutputPorts = [{Id = "bottom-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "bottom-input"}]; X = 321; Y = 492} + {H=50; W=40; Id = "and"; Type = And; Label = ""; InputPorts = [{Id = "and-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and"}; {Id = "and-in1"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and"}]; OutputPorts = [{Id = "and-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and"}]; X = 428; Y = 459} + {H=50; W=40; Id = "output"; Type = Output 1; Label = "output-node0-label"; InputPorts = [{Id = "output-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output"}]; OutputPorts = []; X = 610; Y = 469} + ], + [ + {Id = "conn0"; Source = {Id = "top-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "top-input"}; Target = {Id = "and-in0"; PortNumber = None; PortType = PortType.Input; HostId = "and"}; Vertices = []} + {Id = "conn1"; Source = {Id = "bottom-input-out0"; PortNumber = None; PortType = PortType.Output; HostId = "bottom-input"}; Target = {Id = "and-in1"; PortNumber = None; PortType = PortType.Input; HostId = "and"}; Vertices = []} + ] + +/// Similar to state6, but with both inputs unconnected. +let state27 : CanvasState = + [ + {H=50; W=40; Id = "top-input"; Type = Input 1; Label = "input-node0-label"; InputPorts = []; OutputPorts = [{Id = "top-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "top-input"}]; X = 326; Y = 440} + {H=50; W=40; Id = "bottom-input"; Type = Input 1; Label = "input-node1-label"; InputPorts = []; OutputPorts = [{Id = "bottom-input-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "bottom-input"}]; X = 321; Y = 492} + {H=50; W=40; Id = "and"; Type = And; Label = ""; InputPorts = [{Id = "and-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "and"}; {Id = "and-in1"; PortNumber = Some 1; PortType = PortType.Input; HostId = "and"}]; OutputPorts = [{Id = "and-out0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "and"}]; X = 428; Y = 459} + {H=50; W=40; Id = "output"; Type = Output 1; Label = "output-node0-label"; InputPorts = [{Id = "output-in0"; PortNumber = Some 0; PortType = PortType.Input; HostId = "output"}]; OutputPorts = []; X = 610; Y = 469} + ], + [ + {Id = "conn2"; Source = {Id = "and-out0"; PortNumber = None; PortType = PortType.Output; HostId = "and"}; Target = {Id = "output-in0"; PortNumber = None; PortType = PortType.Input; HostId = "output"}; Vertices = []} + ] + +// Half adder. + +let halfAdderState : CanvasState = + [ + { H=50; W=40; Id = "50151b16-a5e1-76ca-93d2-c4446a6a6c60"; Type = Input 1; Label = "B"; InputPorts = []; OutputPorts = [{Id = "0ca8918f-28b0-0892-4335-3a375c35ef15"; PortNumber = Some 0; PortType = PortType.Output; HostId = "50151b16-a5e1-76ca-93d2-c4446a6a6c60"}]; X = 100; Y = 195} + { H=50; W=40; Id = "36c5c713-b731-21d0-c2f9-9e9bf4c79048"; Type = Input 1; Label = "A"; InputPorts = []; OutputPorts = [{Id = "23fcb523-bd9d-0ca1-cb84-6a37779f2dce"; PortNumber = Some 0; PortType = PortType.Output; HostId = "36c5c713-b731-21d0-c2f9-9e9bf4c79048"}]; X = 100; Y = 100} + { H=50; W=40; Id = "7227d00f-d329-af58-b769-0bf42ee6f2ef"; Type = And; Label = ""; InputPorts = [{Id = "49c3e9ab-4ad5-0c6c-cda9-987a820ad1c5"; PortNumber = Some 0; PortType = PortType.Input; HostId = "7227d00f-d329-af58-b769-0bf42ee6f2ef"}; {Id = "7d121026-401b-72e5-2051-3497b65d99b3"; PortNumber = Some 1; PortType = PortType.Input; HostId = "7227d00f-d329-af58-b769-0bf42ee6f2ef"}]; OutputPorts = [{Id = "45d7d345-38f8-0933-a86c-16159674e4a0"; PortNumber = Some 0; PortType = PortType.Output; HostId = "7227d00f-d329-af58-b769-0bf42ee6f2ef"}]; X = 267; Y = 179} + { H=50; W=40; Id = "5ea2bff6-ee86-e729-5c14-a52b302af517"; Type = Xor; Label = ""; InputPorts = [{Id = "1e8be0a9-1c87-e877-3e7b-a6335f5ddad4"; PortNumber = Some 0; PortType = PortType.Input; HostId = "5ea2bff6-ee86-e729-5c14-a52b302af517"}; {Id = "77dfc4b4-6616-6768-7c35-8c3c1c26acbd"; PortNumber = Some 1; PortType = PortType.Input; HostId = "5ea2bff6-ee86-e729-5c14-a52b302af517"}]; OutputPorts = [{Id = "27537cac-d2b0-dd3d-e0ee-a6f27d2e793e"; PortNumber = Some 0; PortType = PortType.Output; HostId = "5ea2bff6-ee86-e729-5c14-a52b302af517"}]; X = 267; Y = 97} + { H=50; W=40; Id = "0be5c1d8-c5a8-5fad-6e4b-e74e873ce728"; Type = Output 1; Label = "Sum"; InputPorts = [{Id = "26723054-cb13-f8b2-3a5d-ae8224d532e1"; PortNumber = Some 0; PortType = PortType.Input; HostId = "0be5c1d8-c5a8-5fad-6e4b-e74e873ce728"}]; OutputPorts = []; X = 420; Y = 107} + { H=50; W=40; Id = "56dd9000-1a54-8040-3e90-33e44ce390b9"; Type = Output 1; Label = "Cout"; InputPorts = [{Id = "617c8ca8-d4b3-182f-b8d1-ce7f4b6a5359"; PortNumber = Some 0; PortType = PortType.Input; HostId = "56dd9000-1a54-8040-3e90-33e44ce390b9"}]; OutputPorts = []; X = 420; Y = 189} + ], + [ + {Id = "5751a3dc-26e0-2df2-d797-af37b357f7bd"; Source = {Id = "27537cac-d2b0-dd3d-e0ee-a6f27d2e793e"; PortNumber = None; PortType = PortType.Output; HostId = "5ea2bff6-ee86-e729-5c14-a52b302af517"}; Target = {Id = "26723054-cb13-f8b2-3a5d-ae8224d532e1"; PortNumber = None; PortType = PortType.Input; HostId = "0be5c1d8-c5a8-5fad-6e4b-e74e873ce728"}; Vertices = [307.0,117.0; 420.0,117.0]} + {Id = "4d823d53-2991-68a4-a72b-7c3aec1e6b75"; Source = {Id = "0ca8918f-28b0-0892-4335-3a375c35ef15"; PortNumber = None; PortType = PortType.Output; HostId = "50151b16-a5e1-76ca-93d2-c4446a6a6c60"}; Target = {Id = "7d121026-401b-72e5-2051-3497b65d99b3"; PortNumber = None; PortType = PortType.Input; HostId = "7227d00f-d329-af58-b769-0bf42ee6f2ef"}; Vertices = [130.0,205.0; 198.5,205.0; 198.5,205.66666666666666; 267.0,205.66666666666666]} + {Id = "3491b238-ea58-d04a-8d55-78b630507094"; Source = {Id = "23fcb523-bd9d-0ca1-cb84-6a37779f2dce"; PortNumber = None; PortType = PortType.Output; HostId = "36c5c713-b731-21d0-c2f9-9e9bf4c79048"}; Target = {Id = "49c3e9ab-4ad5-0c6c-cda9-987a820ad1c5"; PortNumber = None; PortType = PortType.Input; HostId = "7227d00f-d329-af58-b769-0bf42ee6f2ef"}; Vertices = [130.0,110.0; 170.5,110.0; 170.5,192.33333333333334; 267.0,192.33333333333334]} + {Id = "9c7f868c-0411-eeaf-eefe-9923ae6a66bd"; Source = {Id = "23fcb523-bd9d-0ca1-cb84-6a37779f2dce"; PortNumber = None; PortType = PortType.Output; HostId = "36c5c713-b731-21d0-c2f9-9e9bf4c79048"}; Target = {Id = "1e8be0a9-1c87-e877-3e7b-a6335f5ddad4"; PortNumber = None; PortType = PortType.Input; HostId = "5ea2bff6-ee86-e729-5c14-a52b302af517"}; Vertices = [130.0,110.0; 198.5,110.0; 198.5,110.33333333333333; 267.0,110.33333333333333]} + {Id = "c5c8d60b-712d-b182-aaf1-b902c1eb4b7b"; Source = {Id = "0ca8918f-28b0-0892-4335-3a375c35ef15"; PortNumber = None; PortType = PortType.Output; HostId = "50151b16-a5e1-76ca-93d2-c4446a6a6c60"}; Target = {Id = "77dfc4b4-6616-6768-7c35-8c3c1c26acbd"; PortNumber = None; PortType = PortType.Input; HostId = "5ea2bff6-ee86-e729-5c14-a52b302af517"}; Vertices = [130.0,205.0; 198.5,205.0; 198.5,123.66666666666667; 267.0,123.66666666666667]} + {Id = "712471ca-270a-0410-a9e5-a7894a6c2df4"; Source = {Id = "45d7d345-38f8-0933-a86c-16159674e4a0"; PortNumber = None; PortType = PortType.Output; HostId = "7227d00f-d329-af58-b769-0bf42ee6f2ef"}; Target = {Id = "617c8ca8-d4b3-182f-b8d1-ce7f4b6a5359"; PortNumber = None; PortType = PortType.Input; HostId = "56dd9000-1a54-8040-3e90-33e44ce390b9"}; Vertices = [307.0,199.0; 420.0,199.0]} + ] + +let halfAdderDependency : LoadedComponent = { + Name = "half-adder" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + FilePath = "" + CanvasState = halfAdderState + InputLabels = ["A", 1; "B", 1] + OutputLabels = ["Cout", 1; "Sum", 1] +} + +let halfAdderCustom : CustomComponentType = + makeCustomComponent halfAdderDependency + +// Full adder: uses half adder. + +let fullAdderState : CanvasState = + [ + { H=50; W=40; Id = "6d47f06e-e8ac-1554-9304-e549a85eb9f3"; Type = Custom {Name = "half-adder"; InputLabels = ["A", 1; "B", 1]; OutputLabels = ["Cout", 1; "Sum", 1]}; Label = "half-adder"; InputPorts = [{Id = "bab6da29-c4fe-adae-c94b-ada53dc9b948"; PortNumber = Some 0; PortType = PortType.Input; HostId = "6d47f06e-e8ac-1554-9304-e549a85eb9f3"}; {Id = "6ff179d8-a703-eed2-c948-a214c0aff3a9"; PortNumber = Some 1; PortType = PortType.Input; HostId = "6d47f06e-e8ac-1554-9304-e549a85eb9f3"}]; OutputPorts = [{Id = "0b68efeb-91be-da25-c7c5-dfa1b76b105b"; PortNumber = Some 0; PortType = PortType.Output; HostId = "6d47f06e-e8ac-1554-9304-e549a85eb9f3"}; {Id = "60b550b8-37d9-a0b8-c55c-cfc0044ef147"; PortNumber = Some 1; PortType = PortType.Output; HostId = "6d47f06e-e8ac-1554-9304-e549a85eb9f3"}]; X = 187; Y = 200} + { H=50; W=40; Id = "2c610c78-72b7-2816-fec5-a53d2fa54742"; Type = Input 1; Label = "A"; InputPorts = []; OutputPorts = [{Id = "51e83d48-e73b-0961-3ebe-f488e7f89326"; PortNumber = Some 0; PortType = PortType.Output; HostId = "2c610c78-72b7-2816-fec5-a53d2fa54742"}]; X = 95; Y = 171} + { H=50; W=40; Id = "7e461ed2-53f6-c225-e184-91d24532ef33"; Type = Input 1; Label = "B"; InputPorts = []; OutputPorts = [{Id = "1eaa9bb4-0fa1-4fb3-0792-fe36b5d94886"; PortNumber = Some 0; PortType = PortType.Output; HostId = "7e461ed2-53f6-c225-e184-91d24532ef33"}]; X = 95; Y = 265} + { H=50; W=40; Id = "9aacd9e5-45c1-dfdd-5cc2-f464dd3983ec"; Type = Custom {Name = "half-adder"; InputLabels = ["A", 1; "B", 1]; OutputLabels = ["Cout", 1; "Sum", 1]}; Label = "half-adder"; InputPorts = [{Id = "15575f10-2ec6-6033-cd3a-3ddabda8dbf3"; PortNumber = Some 0; PortType = PortType.Input; HostId = "9aacd9e5-45c1-dfdd-5cc2-f464dd3983ec"}; {Id = "7cdb3ebb-cfa1-6892-9d35-de8f15cb87ac"; PortNumber = Some 1; PortType = PortType.Input; HostId = "9aacd9e5-45c1-dfdd-5cc2-f464dd3983ec"}]; OutputPorts = [{Id = "093b66de-366d-40fc-a3b5-2c2d396d7fb5"; PortNumber = Some 0; PortType = PortType.Output; HostId = "9aacd9e5-45c1-dfdd-5cc2-f464dd3983ec"}; {Id = "8cbfb956-5d53-aa0f-2546-ff32426901d1"; PortNumber = Some 1; PortType = PortType.Output; HostId = "9aacd9e5-45c1-dfdd-5cc2-f464dd3983ec"}]; X = 323; Y = 108} + { H=50; W=40; Id = "eddfd0f6-f06d-5190-3af9-540371a13391"; Type = Input 1; Label = "Cin"; InputPorts = []; OutputPorts = [{Id = "042a92cb-f8d7-3cca-7519-a0bae85fdb6b"; PortNumber = Some 0; PortType = PortType.Output; HostId = "eddfd0f6-f06d-5190-3af9-540371a13391"}]; X = 100; Y = 70} + { H=50; W=40; Id = "d8087733-5924-4af4-e67a-2c9630173608"; Type = Or; Label = ""; InputPorts = [{Id = "f812e552-daab-73d0-cfa0-de0190279c8d"; PortNumber = Some 0; PortType = PortType.Input; HostId = "d8087733-5924-4af4-e67a-2c9630173608"}; {Id = "d25307aa-412f-d108-0f70-335b4e331f52"; PortNumber = Some 1; PortType = PortType.Input; HostId = "d8087733-5924-4af4-e67a-2c9630173608"}]; OutputPorts = [{Id = "93f988ff-3b92-1904-2dcb-17ec5e88178f"; PortNumber = Some 0; PortType = PortType.Output; HostId = "d8087733-5924-4af4-e67a-2c9630173608"}]; X = 481; Y = 196} + { H=50; W=40; Id = "9bf01350-53a9-bb16-1f02-0df29cb60b0f"; Type = Output 1; Label = "Cout"; InputPorts = [{Id = "17f9e9e2-3040-65ba-9578-b4ea6a8f8b28"; PortNumber = Some 0; PortType = PortType.Input; HostId = "9bf01350-53a9-bb16-1f02-0df29cb60b0f"}]; OutputPorts = []; X = 567; Y = 206} + { H=50; W=40; Id = "434a7ce9-942f-0939-94eb-8dd7162ad916"; Type = Output 1; Label = "Sum"; InputPorts = [{Id = "f7ed4610-faf3-e0cb-d985-86f6da5fa148"; PortNumber = Some 0; PortType = PortType.Input; HostId = "434a7ce9-942f-0939-94eb-8dd7162ad916"}]; OutputPorts = []; X = 567; Y = 138} + ], + [ + {Id = "67479e2e-468f-ebe6-7fa8-fe4e7e25efac"; Source = {Id = "51e83d48-e73b-0961-3ebe-f488e7f89326"; PortNumber = None; PortType = PortType.Output; HostId = "2c610c78-72b7-2816-fec5-a53d2fa54742"}; Target = {Id = "bab6da29-c4fe-adae-c94b-ada53dc9b948"; PortNumber = None; PortType = PortType.Input; HostId = "6d47f06e-e8ac-1554-9304-e549a85eb9f3"}; Vertices = [125.0,181.0; 156.0,181.0; 156.0,220.0; 187.0,220.0]} + {Id = "b658d7c4-7b6a-4c9d-7cbc-19f6b25d3631"; Source = {Id = "1eaa9bb4-0fa1-4fb3-0792-fe36b5d94886"; PortNumber = None; PortType = PortType.Output; HostId = "7e461ed2-53f6-c225-e184-91d24532ef33"}; Target = {Id = "6ff179d8-a703-eed2-c948-a214c0aff3a9"; PortNumber = None; PortType = PortType.Input; HostId = "6d47f06e-e8ac-1554-9304-e549a85eb9f3"}; Vertices = [125.0,275.0; 156.0,275.0; 156.0,240.0; 187.0,240.0]} + {Id = "c7cf8ab2-7521-b09c-e4f8-4d09f0913d4f"; Source = {Id = "0b68efeb-91be-da25-c7c5-dfa1b76b105b"; PortNumber = None; PortType = PortType.Output; HostId = "6d47f06e-e8ac-1554-9304-e549a85eb9f3"}; Target = {Id = "d25307aa-412f-d108-0f70-335b4e331f52"; PortNumber = None; PortType = PortType.Input; HostId = "d8087733-5924-4af4-e67a-2c9630173608"}; Vertices = [247.0,220.0; 364.0,220.0; 364.0,222.66666666666666; 481.0,222.66666666666666]} + {Id = "3330546c-fe28-33c1-5f7a-fb71ba73249b"; Source = {Id = "093b66de-366d-40fc-a3b5-2c2d396d7fb5"; PortNumber = None; PortType = PortType.Output; HostId = "9aacd9e5-45c1-dfdd-5cc2-f464dd3983ec"}; Target = {Id = "f812e552-daab-73d0-cfa0-de0190279c8d"; PortNumber = None; PortType = PortType.Input; HostId = "d8087733-5924-4af4-e67a-2c9630173608"}; Vertices = [383.0,128.0; 432.0,128.0; 432.0,209.33333333333334; 481.0,209.33333333333334]} + {Id = "18bf5873-fe65-59d4-9c42-4b578bac5dc6"; Source = {Id = "8cbfb956-5d53-aa0f-2546-ff32426901d1"; PortNumber = None; PortType = PortType.Output; HostId = "9aacd9e5-45c1-dfdd-5cc2-f464dd3983ec"}; Target = {Id = "f7ed4610-faf3-e0cb-d985-86f6da5fa148"; PortNumber = None; PortType = PortType.Input; HostId = "434a7ce9-942f-0939-94eb-8dd7162ad916"}; Vertices = [383.0,148.0; 567.0,148.0]} + {Id = "026d76ef-92b3-91ae-6873-e2cc505ccb8d"; Source = {Id = "60b550b8-37d9-a0b8-c55c-cfc0044ef147"; PortNumber = None; PortType = PortType.Output; HostId = "6d47f06e-e8ac-1554-9304-e549a85eb9f3"}; Target = {Id = "7cdb3ebb-cfa1-6892-9d35-de8f15cb87ac"; PortNumber = None; PortType = PortType.Input; HostId = "9aacd9e5-45c1-dfdd-5cc2-f464dd3983ec"}; Vertices = [247.0,240.0; 285.0,240.0; 285.0,148.0; 323.0,148.0]} + {Id = "3c37db26-e552-d5fb-10f5-57227c4ec6f5"; Source = {Id = "93f988ff-3b92-1904-2dcb-17ec5e88178f"; PortNumber = None; PortType = PortType.Output; HostId = "d8087733-5924-4af4-e67a-2c9630173608"}; Target = {Id = "17f9e9e2-3040-65ba-9578-b4ea6a8f8b28"; PortNumber = None; PortType = PortType.Input; HostId = "9bf01350-53a9-bb16-1f02-0df29cb60b0f"}; Vertices = [521.0,216.0; 567.0,216.0]} + {Id = "e1f27e7e-d0ae-e207-db0e-59c9a872255d"; Source = {Id = "042a92cb-f8d7-3cca-7519-a0bae85fdb6b"; PortNumber = None; PortType = PortType.Output; HostId = "eddfd0f6-f06d-5190-3af9-540371a13391"}; Target = {Id = "15575f10-2ec6-6033-cd3a-3ddabda8dbf3"; PortNumber = None; PortType = PortType.Input; HostId = "9aacd9e5-45c1-dfdd-5cc2-f464dd3983ec"}; Vertices = [130.0,80.0; 226.5,80.0; 226.5,128.0; 323.0,128.0]} + ] + +let fullAdderDependency : LoadedComponent = { + Name = "full-adder" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + FilePath = "" + CanvasState = fullAdderState + InputLabels = ["Cin", 1; "B", 1; "A", 1] + OutputLabels = ["Sum", 1; "Cout", 1] +} + +let fullAdderCustom : CustomComponentType = + makeCustomComponent fullAdderDependency + +// 2 bit adder: uses full adder. + +let twoBitAdderState : CanvasState = + [ + { H=50; W=40; Id = "57604fee-25b0-9498-06f1-3a065d046515"; Type = Custom {Name = "full-adder"; InputLabels = ["Cin", 1; "B", 1; "A", 1]; OutputLabels = ["Sum", 1; "Cout", 1]}; Label = "full-adder"; InputPorts = [{Id = "6a5725f2-f181-d678-371f-7add822462ea"; PortNumber = Some 0; PortType = PortType.Input; HostId = "57604fee-25b0-9498-06f1-3a065d046515"}; {Id = "13f98ff8-2e41-2aef-cbc8-1ed636c8c8c7"; PortNumber = Some 1; PortType = PortType.Input; HostId = "57604fee-25b0-9498-06f1-3a065d046515"}; {Id = "025e36fe-41f2-7f7c-08e2-7b1bb047b798"; PortNumber = Some 2; PortType = PortType.Input; HostId = "57604fee-25b0-9498-06f1-3a065d046515"}]; OutputPorts = [{Id = "c14929a9-b56c-2414-38e6-6fab3127203f"; PortNumber = Some 0; PortType = PortType.Output; HostId = "57604fee-25b0-9498-06f1-3a065d046515"}; {Id = "0cb60845-f6b7-4e88-53bc-18e6c06364ca"; PortNumber = Some 1; PortType = PortType.Output; HostId = "57604fee-25b0-9498-06f1-3a065d046515"}]; X = 298; Y = 129} + { H=50; W=40; Id = "b2842635-e4ec-3113-9130-d827d48e2875"; Type = Custom {Name = "full-adder"; InputLabels = ["Cin", 1; "B", 1; "A", 1]; OutputLabels = ["Sum", 1; "Cout", 1]}; Label = "full-adder"; InputPorts = [{Id = "ce42647b-a5db-5fa1-9a94-baaeec7416cd"; PortNumber = Some 0; PortType = PortType.Input; HostId = "b2842635-e4ec-3113-9130-d827d48e2875"}; {Id = "3496a30f-e2bf-2b12-576d-cf28201850ff"; PortNumber = Some 1; PortType = PortType.Input; HostId = "b2842635-e4ec-3113-9130-d827d48e2875"}; {Id = "9c0d3115-bf93-6c1c-b5bb-784cd7ca7896"; PortNumber = Some 2; PortType = PortType.Input; HostId = "b2842635-e4ec-3113-9130-d827d48e2875"}]; OutputPorts = [{Id = "f6da6a43-076e-1171-53de-6bef710bcaf8"; PortNumber = Some 0; PortType = PortType.Output; HostId = "b2842635-e4ec-3113-9130-d827d48e2875"}; {Id = "04744361-bbe8-ac74-8643-fae2126ed686"; PortNumber = Some 1; PortType = PortType.Output; HostId = "b2842635-e4ec-3113-9130-d827d48e2875"}]; X = 298; Y = 298} + { H=50; W=40; Id = "78795182-35c4-1c50-2190-6fc944a2adea"; Type = Input 1; Label = "Zero"; InputPorts = []; OutputPorts = [{Id = "8b0b16ed-3a4e-2ade-6e4b-6285b0d7d2c8"; PortNumber = Some 0; PortType = PortType.Output; HostId = "78795182-35c4-1c50-2190-6fc944a2adea"}]; X = 155; Y = 72} + { H=50; W=40; Id = "69a6ad2a-af19-369f-0483-0e09e6841da3"; Type = Input 1; Label = "B0"; InputPorts = []; OutputPorts = [{Id = "0b74f567-0740-9667-a7e9-3042aeb7ef8f"; PortNumber = Some 0; PortType = PortType.Output; HostId = "69a6ad2a-af19-369f-0483-0e09e6841da3"}]; X = 83; Y = 150} + { H=50; W=40; Id = "82a03f0b-ae31-b487-ed1b-335e235adeb7"; Type = Input 1; Label = "A1"; InputPorts = []; OutputPorts = [{Id = "e3b566b6-abf4-1446-7267-37d2ad1deed7"; PortNumber = Some 0; PortType = PortType.Output; HostId = "82a03f0b-ae31-b487-ed1b-335e235adeb7"}]; X = 84; Y = 389} + { H=50; W=40; Id = "a63fe5a2-9f4d-e70f-131b-ed35d3f3a9e1"; Type = Input 1; Label = "B1"; InputPorts = []; OutputPorts = [{Id = "d59e003b-088b-cf84-0f93-83c2235b5942"; PortNumber = Some 0; PortType = PortType.Output; HostId = "a63fe5a2-9f4d-e70f-131b-ed35d3f3a9e1"}]; X = 84; Y = 324} + { H=50; W=40; Id = "86372781-c2f4-09f2-406f-f385ee7a47a9"; Type = Input 1; Label = "A0"; InputPorts = []; OutputPorts = [{Id = "0d00e79c-1a98-3744-be2f-b9eb78a1cf5b"; PortNumber = Some 0; PortType = PortType.Output; HostId = "86372781-c2f4-09f2-406f-f385ee7a47a9"}]; X = 83; Y = 200} + { H=50; W=40; Id = "dbb1f55a-edf3-bde2-4c69-43a02560e17d"; Type = Output 1; Label = "Sum1"; InputPorts = [{Id = "8dcbc0d6-ab44-c2e2-9e26-90ee31fa2e35"; PortNumber = Some 0; PortType = PortType.Input; HostId = "dbb1f55a-edf3-bde2-4c69-43a02560e17d"}]; OutputPorts = []; X = 514; Y = 321} + { H=50; W=40; Id = "8f5bded5-f46d-722d-6108-03dda4236c01"; Type = Output 1; Label = "Sum0"; InputPorts = [{Id = "3a537f37-4c6d-3c85-48a7-040d6263bebe"; PortNumber = Some 0; PortType = PortType.Input; HostId = "8f5bded5-f46d-722d-6108-03dda4236c01"}]; OutputPorts = []; X = 514; Y = 150} + { H=50; W=40; Id = "7d948312-376d-1d4b-cf02-90872026be16"; Type = Output 1; Label = "Cout"; InputPorts = [{Id = "bb868347-969a-38d2-2389-2d4ae7b63ce8"; PortNumber = Some 0; PortType = PortType.Input; HostId = "7d948312-376d-1d4b-cf02-90872026be16"}]; OutputPorts = []; X = 514; Y = 389} + ], + [ + {Id = "9a089fef-870a-53d8-00a0-e954963ac8e1"; Source = {Id = "0cb60845-f6b7-4e88-53bc-18e6c06364ca"; PortNumber = None; PortType = PortType.Output; HostId = "57604fee-25b0-9498-06f1-3a065d046515"}; Target = {Id = "ce42647b-a5db-5fa1-9a94-baaeec7416cd"; PortNumber = None; PortType = PortType.Input; HostId = "b2842635-e4ec-3113-9130-d827d48e2875"}; Vertices = [370.0,189.0; 399.0,189.0; 399.0,255.75; 278.0,255.75; 278.0,320.5; 298.0,320.5]} + {Id = "77ab7f29-5375-44b2-d66f-b7c21d412c7f"; Source = {Id = "0b74f567-0740-9667-a7e9-3042aeb7ef8f"; PortNumber = None; PortType = PortType.Output; HostId = "69a6ad2a-af19-369f-0483-0e09e6841da3"}; Target = {Id = "13f98ff8-2e41-2aef-cbc8-1ed636c8c8c7"; PortNumber = None; PortType = PortType.Input; HostId = "57604fee-25b0-9498-06f1-3a065d046515"}; Vertices = [113.0,160.0; 214.5,160.0; 214.5,174.0; 298.0,174.0]} + {Id = "dba98b52-cddf-04d3-648a-fa7b915d4f87"; Source = {Id = "d59e003b-088b-cf84-0f93-83c2235b5942"; PortNumber = None; PortType = PortType.Output; HostId = "a63fe5a2-9f4d-e70f-131b-ed35d3f3a9e1"}; Target = {Id = "3496a30f-e2bf-2b12-576d-cf28201850ff"; PortNumber = None; PortType = PortType.Input; HostId = "b2842635-e4ec-3113-9130-d827d48e2875"}; Vertices = [114.0,334.0; 215.0,334.0; 215.0,343.0; 298.0,343.0]} + {Id = "c7ce0fcc-c122-4ce6-3779-0f548cbfab38"; Source = {Id = "f6da6a43-076e-1171-53de-6bef710bcaf8"; PortNumber = None; PortType = PortType.Output; HostId = "b2842635-e4ec-3113-9130-d827d48e2875"}; Target = {Id = "8dcbc0d6-ab44-c2e2-9e26-90ee31fa2e35"; PortNumber = None; PortType = PortType.Input; HostId = "dbb1f55a-edf3-bde2-4c69-43a02560e17d"}; Vertices = [370.0,328.0; 446.5,328.0; 446.5,331.0; 514.0,331.0]} + {Id = "abc884ae-3a1a-5a35-6f6f-5695d4898759"; Source = {Id = "04744361-bbe8-ac74-8643-fae2126ed686"; PortNumber = None; PortType = PortType.Output; HostId = "b2842635-e4ec-3113-9130-d827d48e2875"}; Target = {Id = "bb868347-969a-38d2-2389-2d4ae7b63ce8"; PortNumber = None; PortType = PortType.Input; HostId = "7d948312-376d-1d4b-cf02-90872026be16"}; Vertices = [370.0,358.0; 446.5,358.0; 446.5,399.0; 514.0,399.0]} + {Id = "3c7b523c-71d3-9378-176c-7c45cfc516cf"; Source = {Id = "c14929a9-b56c-2414-38e6-6fab3127203f"; PortNumber = None; PortType = PortType.Output; HostId = "57604fee-25b0-9498-06f1-3a065d046515"}; Target = {Id = "3a537f37-4c6d-3c85-48a7-040d6263bebe"; PortNumber = None; PortType = PortType.Input; HostId = "8f5bded5-f46d-722d-6108-03dda4236c01"}; Vertices = [370.0,159.0; 446.5,159.0; 446.5,160.0; 514.0,160.0]} + {Id = "ccb35ae8-54b6-4072-6680-3cc05bb00f95"; Source = {Id = "0d00e79c-1a98-3744-be2f-b9eb78a1cf5b"; PortNumber = None; PortType = PortType.Output; HostId = "86372781-c2f4-09f2-406f-f385ee7a47a9"}; Target = {Id = "025e36fe-41f2-7f7c-08e2-7b1bb047b798"; PortNumber = None; PortType = PortType.Input; HostId = "57604fee-25b0-9498-06f1-3a065d046515"}; Vertices = [113.0,210.0; 214.5,210.0; 214.5,196.5; 298.0,196.5]} + {Id = "11759cef-e928-32c1-e6ec-b44b198d1a2e"; Source = {Id = "e3b566b6-abf4-1446-7267-37d2ad1deed7"; PortNumber = None; PortType = PortType.Output; HostId = "82a03f0b-ae31-b487-ed1b-335e235adeb7"}; Target = {Id = "9c0d3115-bf93-6c1c-b5bb-784cd7ca7896"; PortNumber = None; PortType = PortType.Input; HostId = "b2842635-e4ec-3113-9130-d827d48e2875"}; Vertices = [114.0,399.0; 215.0,399.0; 215.0,365.5; 298.0,365.5]} + {Id = "2ae1f296-5dfb-986e-2c4c-3e3435d750b9"; Source = {Id = "8b0b16ed-3a4e-2ade-6e4b-6285b0d7d2c8"; PortNumber = None; PortType = PortType.Output; HostId = "78795182-35c4-1c50-2190-6fc944a2adea"}; Target = {Id = "6a5725f2-f181-d678-371f-7add822462ea"; PortNumber = None; PortType = PortType.Input; HostId = "57604fee-25b0-9498-06f1-3a065d046515"}; Vertices = [185.0,82.0; 250.5,82.0; 250.5,151.5; 298.0,151.5]} + ] + +let twoBitAdderDependency : LoadedComponent = { + Name = "2-bit-adder" + FilePath = "" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + CanvasState = twoBitAdderState + InputLabels = ["A0", 1; "B1", 1; "A1", 1; "B0", 1; "Zero", 1] + OutputLabels = ["Cout", 1; "Sum0", 1; "Sum1", 1] +} + +let twoBitAdderCustom : CustomComponentType = + makeCustomComponent twoBitAdderDependency diff --git a/Tests/CanvasStatesMemories.fs b/Tests/CanvasStatesMemories.fs new file mode 100644 index 0000000..0d9ba39 --- /dev/null +++ b/Tests/CanvasStatesMemories.fs @@ -0,0 +1,69 @@ +module CanvasStatesMemories + +open CommonTypes +open Helpers + +let makeData (lst: int list) = + lst + |> List.indexed + |> List.map (fun (a,d) -> int64 a, int64 d) + |> Map + +let mem1 = { + AddressWidth = 2 + WordWidth = 4 + Data = [0; 1; 4; 15] |> makeData +} + +/// Synchronous ROM connected to address and output. +let stateMem1 : CanvasState = + [ + {H=50;W=40; Id = "322715aa-a1d4-b314-91c7-670d33bca00a";Type = ROM mem1;Label = "";InputPorts = [{Id = "3ff66cbf-7662-f666-2823-6459005239f2";PortNumber = Some 0;PortType = PortType.Input;HostId = "322715aa-a1d4-b314-91c7-670d33bca00a"}];OutputPorts = [{Id = "81f27eec-4619-cb35-ce9a-ac7149a52da8";PortNumber = Some 0;PortType = PortType.Output;HostId = "322715aa-a1d4-b314-91c7-670d33bca00a"}];X = 252;Y = 240}; + {H=50;W=40; Id = "4f65afe9-f03c-2b97-fde9-c657ca32f246";Type = Input 2;Label = "addr";InputPorts = [];OutputPorts = [{Id = "453dbdf9-8a50-792d-c6a9-27396ef5b036";PortNumber = Some 0;PortType = PortType.Output;HostId = "4f65afe9-f03c-2b97-fde9-c657ca32f246"}];X = 88;Y = 280}; + {H=50;W=40; Id = "fbb5aa79-a471-ac24-4201-56ae39d537c6";Type = Output 4;Label = "data";InputPorts = [{Id = "d3339319-afbc-c196-6a23-475704cff3ae";PortNumber = Some 0;PortType = PortType.Input;HostId = "fbb5aa79-a471-ac24-4201-56ae39d537c6"}];OutputPorts = [];X = 467;Y = 280} + ], + [ + {Id = "b5675376-6921-1909-5838-b43891f88fee";Source = {Id = "453dbdf9-8a50-792d-c6a9-27396ef5b036";PortNumber = None;PortType = PortType.Output;HostId = "4f65afe9-f03c-2b97-fde9-c657ca32f246"};Target = {Id = "3ff66cbf-7662-f666-2823-6459005239f2";PortNumber = None;PortType = PortType.Input;HostId = "322715aa-a1d4-b314-91c7-670d33bca00a"};Vertices = [118.0,290.0; 252.0,290.0]}; + {Id = "4720848e-5a2e-7203-d4ac-22f9d9d74af3";Source = {Id = "81f27eec-4619-cb35-ce9a-ac7149a52da8";PortNumber = None;PortType = PortType.Output;HostId = "322715aa-a1d4-b314-91c7-670d33bca00a"};Target = {Id = "d3339319-afbc-c196-6a23-475704cff3ae";PortNumber = None;PortType = PortType.Input;HostId = "fbb5aa79-a471-ac24-4201-56ae39d537c6"};Vertices = [332.0,290.0; 467.0,290.0]} + ] + +/// Numbers from 0 to 255. +let mem2 = { + AddressWidth = 8 + WordWidth = 8 + Data = [0..pow2(8)-1] |> makeData +} + +/// Synchronous ROM connected to address and output. ROM is big. +let stateMem2 : CanvasState = + [ + {H=50;W=40; Id = "322715aa-a1d4-b314-91c7-670d33bca00a";Type = ROM mem2;Label = "";InputPorts = [{Id = "3ff66cbf-7662-f666-2823-6459005239f2";PortNumber = Some 0;PortType = PortType.Input;HostId = "322715aa-a1d4-b314-91c7-670d33bca00a"}];OutputPorts = [{Id = "81f27eec-4619-cb35-ce9a-ac7149a52da8";PortNumber = Some 0;PortType = PortType.Output;HostId = "322715aa-a1d4-b314-91c7-670d33bca00a"}];X = 252;Y = 240}; + {H=50;W=40; Id = "4f65afe9-f03c-2b97-fde9-c657ca32f246";Type = Input 8;Label = "addr";InputPorts = [];OutputPorts = [{Id = "453dbdf9-8a50-792d-c6a9-27396ef5b036";PortNumber = Some 0;PortType = PortType.Output;HostId = "4f65afe9-f03c-2b97-fde9-c657ca32f246"}];X = 88;Y = 280}; + {H=50;W=40; Id = "fbb5aa79-a471-ac24-4201-56ae39d537c6";Type = Output 8;Label = "data";InputPorts = [{Id = "d3339319-afbc-c196-6a23-475704cff3ae";PortNumber = Some 0;PortType = PortType.Input;HostId = "fbb5aa79-a471-ac24-4201-56ae39d537c6"}];OutputPorts = [];X = 467;Y = 280} + ], + [ + {Id = "b5675376-6921-1909-5838-b43891f88fee";Source = {Id = "453dbdf9-8a50-792d-c6a9-27396ef5b036";PortNumber = None;PortType = PortType.Output;HostId = "4f65afe9-f03c-2b97-fde9-c657ca32f246"};Target = {Id = "3ff66cbf-7662-f666-2823-6459005239f2";PortNumber = None;PortType = PortType.Input;HostId = "322715aa-a1d4-b314-91c7-670d33bca00a"};Vertices = [118.0,290.0; 252.0,290.0]}; + {Id = "4720848e-5a2e-7203-d4ac-22f9d9d74af3";Source = {Id = "81f27eec-4619-cb35-ce9a-ac7149a52da8";PortNumber = None;PortType = PortType.Output;HostId = "322715aa-a1d4-b314-91c7-670d33bca00a"};Target = {Id = "d3339319-afbc-c196-6a23-475704cff3ae";PortNumber = None;PortType = PortType.Input;HostId = "fbb5aa79-a471-ac24-4201-56ae39d537c6"};Vertices = [332.0,290.0; 467.0,290.0]} + ] + +let mem3 = { + AddressWidth = 3 + WordWidth = 4 + Data = [0; 0; 0; 0; 0; 0; 0; 0] |> makeData +} + +/// Fully connected RAM. +let stateMem3 : CanvasState = + [ + {H=50;W=40; Id = "33d42057-a42d-3fc5-5b6c-a9f31e18bb60";Type = RAM mem3;Label = "";InputPorts = [{Id = "83ff4d8a-a28e-ebc8-8311-77def91ca935";PortNumber = Some 0;PortType = PortType.Input;HostId = "33d42057-a42d-3fc5-5b6c-a9f31e18bb60"}; {Id = "0c116a9b-78cd-79a5-c080-dfdc1445334d";PortNumber = Some 1;PortType = PortType.Input;HostId = "33d42057-a42d-3fc5-5b6c-a9f31e18bb60"}; {Id = "86e5f7cf-657c-9383-54b3-65c156fdf867";PortNumber = Some 2;PortType = PortType.Input;HostId = "33d42057-a42d-3fc5-5b6c-a9f31e18bb60"}];OutputPorts = [{Id = "c9e983ab-b832-156a-36fd-9ce1d03810d7";PortNumber = Some 0;PortType = PortType.Output;HostId = "33d42057-a42d-3fc5-5b6c-a9f31e18bb60"}];X = 318;Y = 190}; + {H=50;W=40; Id = "1f9704f9-88fc-124c-3ff8-21c36cfb7328";Type = Output 4;Label = "data-out";InputPorts = [{Id = "0af79035-101f-b683-f39c-68a36a7dc33f";PortNumber = Some 0;PortType = PortType.Input;HostId = "1f9704f9-88fc-124c-3ff8-21c36cfb7328"}];OutputPorts = [];X = 647;Y = 230}; + {H=50;W=40; Id = "266d8763-6fbf-37c2-6825-d3487153053b";Type = Input 4;Label = "data-in";InputPorts = [];OutputPorts = [{Id = "b155889c-3d6d-8ebf-2b3b-771f1ada3578";PortNumber = Some 0;PortType = PortType.Output;HostId = "266d8763-6fbf-37c2-6825-d3487153053b"}];X = 116;Y = 230}; + {H=50;W=40; Id = "81030fc6-2471-a568-160f-922709edeb2e";Type = Input 3;Label = "addr";InputPorts = [];OutputPorts = [{Id = "ceb4382f-d670-912f-87c2-755315a89c87";PortNumber = Some 0;PortType = PortType.Output;HostId = "81030fc6-2471-a568-160f-922709edeb2e"}];X = 116;Y = 138}; + {H=50;W=40; Id = "f0769200-24e3-5c7b-3591-c5c3711d9336";Type = Input 1;Label = "write";InputPorts = [];OutputPorts = [{Id = "b8286beb-9cc1-1128-cc1e-813388ca16fc";PortNumber = Some 0;PortType = PortType.Output;HostId = "f0769200-24e3-5c7b-3591-c5c3711d9336"}];X = 116;Y = 322} + ], + [ + {Id = "04957b14-81b7-83c0-7669-c9c6fc363e00";Source = {Id = "b155889c-3d6d-8ebf-2b3b-771f1ada3578";PortNumber = None;PortType = PortType.Output;HostId = "266d8763-6fbf-37c2-6825-d3487153053b"};Target = {Id = "0c116a9b-78cd-79a5-c080-dfdc1445334d";PortNumber = None;PortType = PortType.Input;HostId = "33d42057-a42d-3fc5-5b6c-a9f31e18bb60"};Vertices = [146.0,240.0; 318.0,240.0]}; + {Id = "d24c03fd-7b01-e68f-0d6f-8ff153791809";Source = {Id = "c9e983ab-b832-156a-36fd-9ce1d03810d7";PortNumber = None;PortType = PortType.Output;HostId = "33d42057-a42d-3fc5-5b6c-a9f31e18bb60"};Target = {Id = "0af79035-101f-b683-f39c-68a36a7dc33f";PortNumber = None;PortType = PortType.Input;HostId = "1f9704f9-88fc-124c-3ff8-21c36cfb7328"};Vertices = [448.0,240.0; 647.0,240.0]}; + {Id = "63851c98-6945-0718-29c9-94f738246fd3";Source = {Id = "b8286beb-9cc1-1128-cc1e-813388ca16fc";PortNumber = None;PortType = PortType.Output;HostId = "f0769200-24e3-5c7b-3591-c5c3711d9336"};Target = {Id = "86e5f7cf-657c-9383-54b3-65c156fdf867";PortNumber = None;PortType = PortType.Input;HostId = "33d42057-a42d-3fc5-5b6c-a9f31e18bb60"};Vertices = [146.0,332.0; 232.0,332.0; 232.0,265.0; 318.0,265.0]}; + {Id = "69b302c0-11e5-bb4d-291c-077318321d91";Source = {Id = "ceb4382f-d670-912f-87c2-755315a89c87";PortNumber = None;PortType = PortType.Output;HostId = "81030fc6-2471-a568-160f-922709edeb2e"};Target = {Id = "83ff4d8a-a28e-ebc8-8311-77def91ca935";PortNumber = None;PortType = PortType.Input;HostId = "33d42057-a42d-3fc5-5b6c-a9f31e18bb60"};Vertices = [146.0,148.0; 232.0,148.0; 232.0,215.0; 318.0,215.0]} + ] diff --git a/Tests/CanvasStatesSync.fs b/Tests/CanvasStatesSync.fs new file mode 100644 index 0000000..f816758 --- /dev/null +++ b/Tests/CanvasStatesSync.fs @@ -0,0 +1,233 @@ +module CanvasStatesSync + +open CommonTypes + +/// Simple DFF connected to an input and an output. +let stateSync1 : CanvasState = + [ + {H=50; W=40;Id = "067434c0-3bf4-f4c4-551b-1001d73b024f";Type = DFF;Label = "";InputPorts = [{Id = "b595ca8e-027e-0024-2855-1169330c53f4";PortNumber = Some 0;PortType = PortType.Input;HostId = "067434c0-3bf4-f4c4-551b-1001d73b024f"}];OutputPorts = [{Id = "547be6ee-118d-5bd6-2b3c-37ed3250302f";PortNumber = Some 0;PortType = PortType.Output;HostId = "067434c0-3bf4-f4c4-551b-1001d73b024f"}];X = 409;Y = 232}; + {H=50; W=40;Id = "6e7a2000-439c-108e-df6d-93cff7a41266";Type = Input 1;Label = "in";InputPorts = [];OutputPorts = [{Id = "62496e2e-fa0d-3e2b-46f2-9ee99a141de6";PortNumber = Some 0;PortType = PortType.Output;HostId = "6e7a2000-439c-108e-df6d-93cff7a41266"}];X = 171;Y = 247}; + {H=50; W=40;Id = "a5d52bcd-0a6d-d123-7313-61d0b8b367fd";Type = Output 1;Label = "out";InputPorts = [{Id = "5fd06e1a-90ba-64e8-24bf-d69f190a6b2f";PortNumber = Some 0;PortType = PortType.Input;HostId = "a5d52bcd-0a6d-d123-7313-61d0b8b367fd"}];OutputPorts = [];X = 671;Y = 247} + ], + [ + {Id = "fe93a564-b9be-2ce5-61a0-89a57d1f4c30";Source = {Id = "547be6ee-118d-5bd6-2b3c-37ed3250302f";PortNumber = None;PortType = PortType.Output;HostId = "067434c0-3bf4-f4c4-551b-1001d73b024f"};Target = {Id = "5fd06e1a-90ba-64e8-24bf-d69f190a6b2f";PortNumber = None;PortType = PortType.Input;HostId = "a5d52bcd-0a6d-d123-7313-61d0b8b367fd"};Vertices = [459.0,257.0; 671.0,257.0]}; + {Id = "e1da6926-1493-ffb0-c85b-c58b00506cd6";Source = {Id = "62496e2e-fa0d-3e2b-46f2-9ee99a141de6";PortNumber = None;PortType = PortType.Output;HostId = "6e7a2000-439c-108e-df6d-93cff7a41266"};Target = {Id = "b595ca8e-027e-0024-2855-1169330c53f4";PortNumber = None;PortType = PortType.Input;HostId = "067434c0-3bf4-f4c4-551b-1001d73b024f"};Vertices = [201.0,257.0; 409.0,257.0]} + ] + +/// stateSync1 loaded as a dependency. +let stateSync1Dependency : LoadedComponent = { + Name = "single-dff" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + FilePath = "" + CanvasState = stateSync1 + InputLabels = ["in", 1] + OutputLabels = ["out", 1] +} + +/// stateSync1 custom component. +let stateSync1CustomComponent : CustomComponentType = + CanvasStates.makeCustomComponent stateSync1Dependency + +/// Two DFF connected in series. +let stateSync2 : CanvasState = + [ + {H=50; W=40;Id = "067434c0-3bf4-f4c4-551b-1001d73b024f";Type = DFF;Label = "";InputPorts = [{Id = "b595ca8e-027e-0024-2855-1169330c53f4";PortNumber = Some 0;PortType = PortType.Input;HostId = "067434c0-3bf4-f4c4-551b-1001d73b024f"}];OutputPorts = [{Id = "547be6ee-118d-5bd6-2b3c-37ed3250302f";PortNumber = Some 0;PortType = PortType.Output;HostId = "067434c0-3bf4-f4c4-551b-1001d73b024f"}];X = 351;Y = 185}; + {H=50; W=40;Id = "a5d52bcd-0a6d-d123-7313-61d0b8b367fd";Type = Output 1;Label = "out";InputPorts = [{Id = "5fd06e1a-90ba-64e8-24bf-d69f190a6b2f";PortNumber = Some 0;PortType = PortType.Input;HostId = "a5d52bcd-0a6d-d123-7313-61d0b8b367fd"}];OutputPorts = [];X = 752;Y = 200}; + {H=50; W=40;Id = "3739e54a-fd21-bf60-8fc2-a3d10108c947";Type = Input 1;Label = "in";InputPorts = [];OutputPorts = [{Id = "5c467246-0f2a-0da7-6e92-9f041d1a9fd8";PortNumber = Some 0;PortType = PortType.Output;HostId = "3739e54a-fd21-bf60-8fc2-a3d10108c947"}];X = 200;Y = 200}; + {H=50; W=40;Id = "edda6ee1-8b6f-8f37-8177-4c073299a362";Type = DFF;Label = "";InputPorts = [{Id = "7888376e-2242-39ac-9299-aef7e30f4465";PortNumber = Some 0;PortType = PortType.Input;HostId = "edda6ee1-8b6f-8f37-8177-4c073299a362"}];OutputPorts = [{Id = "272e61d9-786c-f609-274c-9990997892cf";PortNumber = Some 0;PortType = PortType.Output;HostId = "edda6ee1-8b6f-8f37-8177-4c073299a362"}];X = 574;Y = 185} + ], + [ + {Id = "9e2ded72-08fd-c5d2-5bd7-f191c02f0d4d";Source = {Id = "272e61d9-786c-f609-274c-9990997892cf";PortNumber = None;PortType = PortType.Output;HostId = "edda6ee1-8b6f-8f37-8177-4c073299a362"};Target = {Id = "5fd06e1a-90ba-64e8-24bf-d69f190a6b2f";PortNumber = None;PortType = PortType.Input;HostId = "a5d52bcd-0a6d-d123-7313-61d0b8b367fd"};Vertices = [624.0,210.0; 752.0,210.0]}; + {Id = "bc1e6ca7-6f71-697d-c81e-53598fcd5b4e";Source = {Id = "547be6ee-118d-5bd6-2b3c-37ed3250302f";PortNumber = None;PortType = PortType.Output;HostId = "067434c0-3bf4-f4c4-551b-1001d73b024f"};Target = {Id = "7888376e-2242-39ac-9299-aef7e30f4465";PortNumber = None;PortType = PortType.Input;HostId = "edda6ee1-8b6f-8f37-8177-4c073299a362"};Vertices = [401.0,210.0; 574.0,210.0]}; + {Id = "9b5af8de-2de5-3a95-7347-316c3f9cfa8d";Source = {Id = "5c467246-0f2a-0da7-6e92-9f041d1a9fd8";PortNumber = None;PortType = PortType.Output;HostId = "3739e54a-fd21-bf60-8fc2-a3d10108c947"};Target = {Id = "b595ca8e-027e-0024-2855-1169330c53f4";PortNumber = None;PortType = PortType.Input;HostId = "067434c0-3bf4-f4c4-551b-1001d73b024f"};Vertices = [230.0,210.0; 351.0,210.0]} + ] + +/// Three DFF connected in series. +let stateSync3 : CanvasState = + [ + {H=50; W=40;Id = "067434c0-3bf4-f4c4-551b-1001d73b024f";Type = DFF;Label = "";InputPorts = [{Id = "b595ca8e-027e-0024-2855-1169330c53f4";PortNumber = Some 0;PortType = PortType.Input;HostId = "067434c0-3bf4-f4c4-551b-1001d73b024f"}];OutputPorts = [{Id = "547be6ee-118d-5bd6-2b3c-37ed3250302f";PortNumber = Some 0;PortType = PortType.Output;HostId = "067434c0-3bf4-f4c4-551b-1001d73b024f"}];X = 351;Y = 185}; + {H=50; W=40;Id = "a5d52bcd-0a6d-d123-7313-61d0b8b367fd";Type = Output 1;Label = "out";InputPorts = [{Id = "5fd06e1a-90ba-64e8-24bf-d69f190a6b2f";PortNumber = Some 0;PortType = PortType.Input;HostId = "a5d52bcd-0a6d-d123-7313-61d0b8b367fd"}];OutputPorts = [];X = 752;Y = 200}; + {H=50; W=40;Id = "3739e54a-fd21-bf60-8fc2-a3d10108c947";Type = Input 1;Label = "in";InputPorts = [];OutputPorts = [{Id = "5c467246-0f2a-0da7-6e92-9f041d1a9fd8";PortNumber = Some 0;PortType = PortType.Output;HostId = "3739e54a-fd21-bf60-8fc2-a3d10108c947"}];X = 200;Y = 200}; + {H=50; W=40;Id = "edda6ee1-8b6f-8f37-8177-4c073299a362";Type = DFF;Label = "";InputPorts = [{Id = "7888376e-2242-39ac-9299-aef7e30f4465";PortNumber = Some 0;PortType = PortType.Input;HostId = "edda6ee1-8b6f-8f37-8177-4c073299a362"}];OutputPorts = [{Id = "272e61d9-786c-f609-274c-9990997892cf";PortNumber = Some 0;PortType = PortType.Output;HostId = "edda6ee1-8b6f-8f37-8177-4c073299a362"}];X = 489;Y = 185}; + {H=50; W=40;Id = "36fd5a8f-ca4c-eb7e-e0f4-3b89109ad650";Type = DFF;Label = "";InputPorts = [{Id = "2e1f0297-f4c6-c266-7dbb-d56fc63e386a";PortNumber = Some 0;PortType = PortType.Input;HostId = "36fd5a8f-ca4c-eb7e-e0f4-3b89109ad650"}];OutputPorts = [{Id = "e0df158f-e186-c205-8693-9fa92c62d154";PortNumber = Some 0;PortType = PortType.Output;HostId = "36fd5a8f-ca4c-eb7e-e0f4-3b89109ad650"}];X = 613;Y = 185} + ], + [ + {Id = "9e2ded72-08fd-c5d2-5bd7-f191c02f0d4d";Source = {Id = "272e61d9-786c-f609-274c-9990997892cf";PortNumber = None;PortType = PortType.Output;HostId = "edda6ee1-8b6f-8f37-8177-4c073299a362"};Target = {Id = "2e1f0297-f4c6-c266-7dbb-d56fc63e386a";PortNumber = None;PortType = PortType.Input;HostId = "36fd5a8f-ca4c-eb7e-e0f4-3b89109ad650"};Vertices = [539.0,210.0; 613.0,210.0]}; + {Id = "9b5af8de-2de5-3a95-7347-316c3f9cfa8d";Source = {Id = "5c467246-0f2a-0da7-6e92-9f041d1a9fd8";PortNumber = None;PortType = PortType.Output;HostId = "3739e54a-fd21-bf60-8fc2-a3d10108c947"};Target = {Id = "b595ca8e-027e-0024-2855-1169330c53f4";PortNumber = None;PortType = PortType.Input;HostId = "067434c0-3bf4-f4c4-551b-1001d73b024f"};Vertices = [230.0,210.0; 351.0,210.0]}; + {Id = "bc1e6ca7-6f71-697d-c81e-53598fcd5b4e";Source = {Id = "547be6ee-118d-5bd6-2b3c-37ed3250302f";PortNumber = None;PortType = PortType.Output;HostId = "067434c0-3bf4-f4c4-551b-1001d73b024f"};Target = {Id = "7888376e-2242-39ac-9299-aef7e30f4465";PortNumber = None;PortType = PortType.Input;HostId = "edda6ee1-8b6f-8f37-8177-4c073299a362"};Vertices = [401.0,210.0; 489.0,210.0]}; + {Id = "56b29fa5-a6e0-45d1-d2c0-4d3f4d82d94c";Source = {Id = "e0df158f-e186-c205-8693-9fa92c62d154";PortNumber = None;PortType = PortType.Output;HostId = "36fd5a8f-ca4c-eb7e-e0f4-3b89109ad650"};Target = {Id = "5fd06e1a-90ba-64e8-24bf-d69f190a6b2f";PortNumber = None;PortType = PortType.Input;HostId = "a5d52bcd-0a6d-d123-7313-61d0b8b367fd"};Vertices = [663.0,210.0; 752.0,210.0]} + ] + +/// StateSync1 custom component followed by a DFF. +let stateSync4 : CanvasState = + [ + {H=50; W=40;Id = "03e4c81a-4703-d9f5-dfaf-301de006610f";Type = Input 1;Label = "a";InputPorts = [];OutputPorts = [{Id = "0caf419c-354b-78b8-a12b-e5fa450d4fc0";PortNumber = Some 0;PortType = PortType.Output;HostId = "03e4c81a-4703-d9f5-dfaf-301de006610f"}];X = 100;Y = 100}; + {H=50; W=40;Id = "781e7d9d-b18c-d614-dbc0-23bac9e617b7";Type = Output 1;Label = "b";InputPorts = [{Id = "a8e8da74-7bd2-f3a8-9ee5-9e8caa1ee0e5";PortNumber = Some 0;PortType = PortType.Input;HostId = "781e7d9d-b18c-d614-dbc0-23bac9e617b7"}];OutputPorts = [];X = 749;Y = 100}; + {H=50; W=40;Id = "547051c6-38f6-27ec-7c33-9c3bbee47e6e";Type = DFF;Label = "";InputPorts = [{Id = "7ec9e434-b066-daf3-3308-0a13a97c8880";PortNumber = Some 0;PortType = PortType.Input;HostId = "547051c6-38f6-27ec-7c33-9c3bbee47e6e"}];OutputPorts = [{Id = "252c237c-1323-a291-eccb-f94392a37743";PortNumber = Some 0;PortType = PortType.Output;HostId = "547051c6-38f6-27ec-7c33-9c3bbee47e6e"}];X = 500;Y = 85}; + {H=50; W=40;Id = "423bb75b-e791-14f9-ecc2-1ac1c73fc55b";Type = Custom stateSync1CustomComponent;Label = "main";InputPorts = [{Id = "4c5a5a1a-e7e3-f53b-8059-0dfd34d796b1";PortNumber = Some 0;PortType = PortType.Input;HostId = "423bb75b-e791-14f9-ecc2-1ac1c73fc55b"}];OutputPorts = [{Id = "05578981-7a96-a101-b726-df761e234abb";PortNumber = Some 0;PortType = PortType.Output;HostId = "423bb75b-e791-14f9-ecc2-1ac1c73fc55b"}];X = 285;Y = 95} + ], + [ + {Id = "75474538-c7cb-de96-9fd2-5f55af7af631";Source = {Id = "0caf419c-354b-78b8-a12b-e5fa450d4fc0";PortNumber = None;PortType = PortType.Output;HostId = "03e4c81a-4703-d9f5-dfaf-301de006610f"};Target = {Id = "4c5a5a1a-e7e3-f53b-8059-0dfd34d796b1";PortNumber = None;PortType = PortType.Input;HostId = "423bb75b-e791-14f9-ecc2-1ac1c73fc55b"};Vertices = [130.0,110.0; 285.0,110.0]}; + {Id = "4c146e97-db61-4848-5073-01c3785d2571";Source = {Id = "252c237c-1323-a291-eccb-f94392a37743";PortNumber = None;PortType = PortType.Output;HostId = "547051c6-38f6-27ec-7c33-9c3bbee47e6e"};Target = {Id = "a8e8da74-7bd2-f3a8-9ee5-9e8caa1ee0e5";PortNumber = None;PortType = PortType.Input;HostId = "781e7d9d-b18c-d614-dbc0-23bac9e617b7"};Vertices = [550.0,110.0; 749.0,110.0]}; + {Id = "50982a96-2ea6-7db7-2eda-6c38456697c4";Source = {Id = "05578981-7a96-a101-b726-df761e234abb";PortNumber = None;PortType = PortType.Output;HostId = "423bb75b-e791-14f9-ecc2-1ac1c73fc55b"};Target = {Id = "7ec9e434-b066-daf3-3308-0a13a97c8880";PortNumber = None;PortType = PortType.Input;HostId = "547051c6-38f6-27ec-7c33-9c3bbee47e6e"};Vertices = [345.0,110.0; 500.0,110.0]} + ] + +/// A DFF looping to itself via a Not gate. Two output nodes to probe the wires +/// before and after the Not gate. No inputs. +let stateSync5 : CanvasState = + [ + {H=50; W=40;Id = "62a3108e-1198-502b-e338-e677815aead3";Type = Output 1;Label = "out1";InputPorts = [{Id = "3a7fdd4d-59d0-60cf-9eaf-cd2c7fd16264";PortNumber = Some 0;PortType = PortType.Input;HostId = "62a3108e-1198-502b-e338-e677815aead3"}];OutputPorts = [];X = 417;Y = 117}; + {H=50; W=40;Id = "fc72c05a-5174-0334-aa74-be3ce27c3657";Type = Not;Label = "";InputPorts = [{Id = "add99bad-5b00-ab97-4f13-2903a14b2f4e";PortNumber = Some 0;PortType = PortType.Input;HostId = "fc72c05a-5174-0334-aa74-be3ce27c3657"}];OutputPorts = [{Id = "63ca8512-31ee-88e6-9d25-8fdc727d2418";PortNumber = Some 0;PortType = PortType.Output;HostId = "fc72c05a-5174-0334-aa74-be3ce27c3657"}];X = 169;Y = 184}; + {H=50; W=40;Id = "023094a0-9787-47ce-26af-03086cdc4b15";Type = Output 1;Label = "out2";InputPorts = [{Id = "0ed71ded-67ad-cd1b-0ff0-a1e167900051";PortNumber = Some 0;PortType = PortType.Input;HostId = "023094a0-9787-47ce-26af-03086cdc4b15"}];OutputPorts = [];X = 229;Y = 138}; + {H=50; W=40;Id = "1a772449-853d-2171-1e47-fb9783b99556";Type = DFF;Label = "";InputPorts = [{Id = "8b78d961-4203-c0ae-3229-c3a02c42065a";PortNumber = Some 0;PortType = PortType.Input;HostId = "1a772449-853d-2171-1e47-fb9783b99556"}];OutputPorts = [{Id = "abd2d9ec-a752-cb9d-b97e-afd7e2eea26d";PortNumber = Some 0;PortType = PortType.Output;HostId = "1a772449-853d-2171-1e47-fb9783b99556"}];X = 273;Y = 343} + ], + [ + {Id = "5f42f1e8-0ccd-24e1-04a2-635d957c991b";Source = {Id = "63ca8512-31ee-88e6-9d25-8fdc727d2418";PortNumber = None;PortType = PortType.Output;HostId = "fc72c05a-5174-0334-aa74-be3ce27c3657"};Target = {Id = "0ed71ded-67ad-cd1b-0ff0-a1e167900051";PortNumber = None;PortType = PortType.Input;HostId = "023094a0-9787-47ce-26af-03086cdc4b15"};Vertices = [199.0,199.0; 214.0,199.0; 214.0,148.0; 229.0,148.0]}; + {Id = "dc4cbb8e-e7a8-a008-97a8-0200f8720a81";Source = {Id = "63ca8512-31ee-88e6-9d25-8fdc727d2418";PortNumber = None;PortType = PortType.Output;HostId = "fc72c05a-5174-0334-aa74-be3ce27c3657"};Target = {Id = "8b78d961-4203-c0ae-3229-c3a02c42065a";PortNumber = None;PortType = PortType.Input;HostId = "1a772449-853d-2171-1e47-fb9783b99556"};Vertices = [199.0,199.0; 236.0,199.0; 236.0,368.0; 273.0,368.0]}; + {Id = "4810ec6b-a9f9-a562-58cf-82f9071755ad";Source = {Id = "abd2d9ec-a752-cb9d-b97e-afd7e2eea26d";PortNumber = None;PortType = PortType.Output;HostId = "1a772449-853d-2171-1e47-fb9783b99556"};Target = {Id = "add99bad-5b00-ab97-4f13-2903a14b2f4e";PortNumber = None;PortType = PortType.Input;HostId = "fc72c05a-5174-0334-aa74-be3ce27c3657"};Vertices = [323.0,368.0; 343.0,368.0; 343.0,283.5; 149.0,283.5; 149.0,199.0; 169.0,199.0]}; + {Id = "3831ffa7-549f-da3b-ab73-20c72e69b5b8";Source = {Id = "abd2d9ec-a752-cb9d-b97e-afd7e2eea26d";PortNumber = None;PortType = PortType.Output;HostId = "1a772449-853d-2171-1e47-fb9783b99556"};Target = {Id = "3a7fdd4d-59d0-60cf-9eaf-cd2c7fd16264";PortNumber = None;PortType = PortType.Input;HostId = "62a3108e-1198-502b-e338-e677815aead3"};Vertices = [323.0,368.0; 370.0,368.0; 370.0,127.0; 417.0,127.0]} + ] + + +/// Similar to stateSync5, but with a stateSync1 custom component instead of a +/// DFF. Loop with a synchronous custom component. +let stateSync6 : CanvasState = + [ + {H=50; W=40;Id = "62a3108e-1198-502b-e338-e677815aead3";Type = Output 1;Label = "out1";InputPorts = [{Id = "3a7fdd4d-59d0-60cf-9eaf-cd2c7fd16264";PortNumber = Some 0;PortType = PortType.Input;HostId = "62a3108e-1198-502b-e338-e677815aead3"}];OutputPorts = [];X = 417;Y = 117}; + {H=50; W=40;Id = "fc72c05a-5174-0334-aa74-be3ce27c3657";Type = Not;Label = "";InputPorts = [{Id = "add99bad-5b00-ab97-4f13-2903a14b2f4e";PortNumber = Some 0;PortType = PortType.Input;HostId = "fc72c05a-5174-0334-aa74-be3ce27c3657"}];OutputPorts = [{Id = "63ca8512-31ee-88e6-9d25-8fdc727d2418";PortNumber = Some 0;PortType = PortType.Output;HostId = "fc72c05a-5174-0334-aa74-be3ce27c3657"}];X = 169;Y = 184}; + {H=50; W=40;Id = "023094a0-9787-47ce-26af-03086cdc4b15";Type = Output 1;Label = "out2";InputPorts = [{Id = "0ed71ded-67ad-cd1b-0ff0-a1e167900051";PortNumber = Some 0;PortType = PortType.Input;HostId = "023094a0-9787-47ce-26af-03086cdc4b15"}];OutputPorts = [];X = 229;Y = 138}; + {H=50; W=40;Id = "1a772449-853d-2171-1e47-fb9783b99556";Type = Custom stateSync1CustomComponent;Label = "";InputPorts = [{Id = "8b78d961-4203-c0ae-3229-c3a02c42065a";PortNumber = Some 0;PortType = PortType.Input;HostId = "1a772449-853d-2171-1e47-fb9783b99556"}];OutputPorts = [{Id = "abd2d9ec-a752-cb9d-b97e-afd7e2eea26d";PortNumber = Some 0;PortType = PortType.Output;HostId = "1a772449-853d-2171-1e47-fb9783b99556"}];X = 273;Y = 343} + ], + [ + {Id = "5f42f1e8-0ccd-24e1-04a2-635d957c991b";Source = {Id = "63ca8512-31ee-88e6-9d25-8fdc727d2418";PortNumber = None;PortType = PortType.Output;HostId = "fc72c05a-5174-0334-aa74-be3ce27c3657"};Target = {Id = "0ed71ded-67ad-cd1b-0ff0-a1e167900051";PortNumber = None;PortType = PortType.Input;HostId = "023094a0-9787-47ce-26af-03086cdc4b15"};Vertices = [199.0,199.0; 214.0,199.0; 214.0,148.0; 229.0,148.0]}; + {Id = "dc4cbb8e-e7a8-a008-97a8-0200f8720a81";Source = {Id = "63ca8512-31ee-88e6-9d25-8fdc727d2418";PortNumber = None;PortType = PortType.Output;HostId = "fc72c05a-5174-0334-aa74-be3ce27c3657"};Target = {Id = "8b78d961-4203-c0ae-3229-c3a02c42065a";PortNumber = None;PortType = PortType.Input;HostId = "1a772449-853d-2171-1e47-fb9783b99556"};Vertices = [199.0,199.0; 236.0,199.0; 236.0,368.0; 273.0,368.0]}; + {Id = "4810ec6b-a9f9-a562-58cf-82f9071755ad";Source = {Id = "abd2d9ec-a752-cb9d-b97e-afd7e2eea26d";PortNumber = None;PortType = PortType.Output;HostId = "1a772449-853d-2171-1e47-fb9783b99556"};Target = {Id = "add99bad-5b00-ab97-4f13-2903a14b2f4e";PortNumber = None;PortType = PortType.Input;HostId = "fc72c05a-5174-0334-aa74-be3ce27c3657"};Vertices = [323.0,368.0; 343.0,368.0; 343.0,283.5; 149.0,283.5; 149.0,199.0; 169.0,199.0]}; + {Id = "3831ffa7-549f-da3b-ab73-20c72e69b5b8";Source = {Id = "abd2d9ec-a752-cb9d-b97e-afd7e2eea26d";PortNumber = None;PortType = PortType.Output;HostId = "1a772449-853d-2171-1e47-fb9783b99556"};Target = {Id = "3a7fdd4d-59d0-60cf-9eaf-cd2c7fd16264";PortNumber = None;PortType = PortType.Input;HostId = "62a3108e-1198-502b-e338-e677815aead3"};Vertices = [323.0,368.0; 370.0,368.0; 370.0,127.0; 417.0,127.0]} + ] + +/// Input connected to two outputs. One of the two paths has a DFF in between. +/// Therefore, A to B-Comb is combinatorial path. A to B-Sync is a synchronous +/// path. +let stateSync7 : CanvasState = + [ + {H=50; W=40;Id = "ff10125a-601f-e1d5-e379-7eb7c65eb91f";Type = Input 1;Label = "A";InputPorts = [];OutputPorts = [{Id = "32b40ca6-c21f-5b84-ca05-38d88b35b567";PortNumber = Some 0;PortType = PortType.Output;HostId = "ff10125a-601f-e1d5-e379-7eb7c65eb91f"}];X = 150;Y = 150}; + {H=50; W=40;Id = "2947473e-2eef-864c-217a-dd5c1daaae44";Type = DFF;Label = "";InputPorts = [{Id = "45a6e6f6-ed52-8de9-2fed-9f7a0bbb86dc";PortNumber = Some 0;PortType = PortType.Input;HostId = "2947473e-2eef-864c-217a-dd5c1daaae44"}];OutputPorts = [{Id = "25dc0c5b-e047-090b-5c2a-7ac216d80122";PortNumber = Some 0;PortType = PortType.Output;HostId = "2947473e-2eef-864c-217a-dd5c1daaae44"}];X = 230;Y = 210}; + {H=50; W=40;Id = "794d5154-6969-3f4e-9c8b-4bc17927c28f";Type = Output 1;Label = "B-Comb";InputPorts = [{Id = "dbdd44c2-14e4-449c-4d69-6dd78af61e2c";PortNumber = Some 0;PortType = PortType.Input;HostId = "794d5154-6969-3f4e-9c8b-4bc17927c28f"}];OutputPorts = [];X = 328;Y = 150}; + {H=50; W=40;Id = "95452292-b507-ab43-f082-85152d3e4cf2";Type = Output 1;Label = "B-Sync";InputPorts = [{Id = "05a19e53-570c-f02f-0af2-7ba35c4a4b71";PortNumber = Some 0;PortType = PortType.Input;HostId = "95452292-b507-ab43-f082-85152d3e4cf2"}];OutputPorts = [];X = 328;Y = 225} + ], + [ + {Id = "79418b3f-7ee3-997a-a433-32a9fbb49f18";Source = {Id = "32b40ca6-c21f-5b84-ca05-38d88b35b567";PortNumber = None;PortType = PortType.Output;HostId = "ff10125a-601f-e1d5-e379-7eb7c65eb91f"};Target = {Id = "dbdd44c2-14e4-449c-4d69-6dd78af61e2c";PortNumber = None;PortType = PortType.Input;HostId = "794d5154-6969-3f4e-9c8b-4bc17927c28f"};Vertices = [180.0,160.0; 328.0,160.0]}; + {Id = "51efab13-f633-205b-8cd4-c3c858ae25d8";Source = {Id = "32b40ca6-c21f-5b84-ca05-38d88b35b567";PortNumber = None;PortType = PortType.Output;HostId = "ff10125a-601f-e1d5-e379-7eb7c65eb91f"};Target = {Id = "45a6e6f6-ed52-8de9-2fed-9f7a0bbb86dc";PortNumber = None;PortType = PortType.Input;HostId = "2947473e-2eef-864c-217a-dd5c1daaae44"};Vertices = [180.0,160.0; 205.0,160.0; 205.0,235.0; 230.0,235.0]}; + {Id = "10c6a066-34dd-e0e2-d53d-32c34fcddde6";Source = {Id = "25dc0c5b-e047-090b-5c2a-7ac216d80122";PortNumber = None;PortType = PortType.Output;HostId = "2947473e-2eef-864c-217a-dd5c1daaae44"};Target = {Id = "05a19e53-570c-f02f-0af2-7ba35c4a4b71";PortNumber = None;PortType = PortType.Input;HostId = "95452292-b507-ab43-f082-85152d3e4cf2"};Vertices = [280.0,235.0; 328.0,235.0]} + ] + +/// stateSync7 loaded as a dependency. +let stateSync7Dependency : LoadedComponent = { + Name = "combinatorial-sync" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + FilePath = "" + CanvasState = stateSync7 + InputLabels = ["A", 1] + OutputLabels = ["B-Comb", 1; "B-Sync", 1] +} + +/// stateSync7 custom component. +let stateSync7CustomComponent : CustomComponentType = + CanvasStates.makeCustomComponent stateSync7Dependency + +/// stateSync7 Not-ed self looped in the synchronous branch. This is a +/// legitimate synchronous circuit and should pass. It is the same showed in +/// the report for the examples about combinatorial loops detection. +let stateSync8 : CanvasState = + [ + {H=50; W=40;Id = "eb5353fd-fac6-3b2a-4de8-8949046671d2";Type = Custom stateSync7CustomComponent;Label = "";InputPorts = [{Id = "04f9c8fe-06c2-b485-e181-73aa36617622";PortNumber = Some 0;PortType = PortType.Input;HostId = "eb5353fd-fac6-3b2a-4de8-8949046671d2"}];OutputPorts = [{Id = "b9f547be-e285-cb90-1803-b8d3a4c0d351";PortNumber = Some 0;PortType = PortType.Output;HostId = "eb5353fd-fac6-3b2a-4de8-8949046671d2"}; {Id = "9935af7b-9671-60a2-a76a-f00d3a372d6c";PortNumber = Some 1;PortType = PortType.Output;HostId = "eb5353fd-fac6-3b2a-4de8-8949046671d2"}];X = 302;Y = 256}; + {H=50; W=40;Id = "66030e1a-4a97-244a-f0bb-d9e5fd25627f";Type = Output 1;Label = "B";InputPorts = [{Id = "8bfcfe42-be19-e2fa-42ae-25e929cab003";PortNumber = Some 0;PortType = PortType.Input;HostId = "66030e1a-4a97-244a-f0bb-d9e5fd25627f"}];OutputPorts = [];X = 488;Y = 266}; + {H=50; W=40;Id = "825b172a-9355-8bf1-10fc-b18f06d4e76b";Type = Not;Label = "";InputPorts = [{Id = "69688e66-1a74-e959-f58a-6085a5ae5c57";PortNumber = Some 0;PortType = PortType.Input;HostId = "825b172a-9355-8bf1-10fc-b18f06d4e76b"}];OutputPorts = [{Id = "7f763373-0473-16b8-75da-f80541b220ec";PortNumber = Some 0;PortType = PortType.Output;HostId = "825b172a-9355-8bf1-10fc-b18f06d4e76b"}];X = 536;Y = 281} + ], + [ + {Id = "c1ba620c-e715-5f47-d05b-1a6937750f13";Source = {Id = "7f763373-0473-16b8-75da-f80541b220ec";PortNumber = None;PortType = PortType.Output;HostId = "825b172a-9355-8bf1-10fc-b18f06d4e76b"};Target = {Id = "04f9c8fe-06c2-b485-e181-73aa36617622";PortNumber = None;PortType = PortType.Input;HostId = "eb5353fd-fac6-3b2a-4de8-8949046671d2"};Vertices = [566.0,296.0; 586.0,296.0; 586.0,395.0; 282.0,395.0; 282.0,286.0; 302.0,286.0]}; + {Id = "b1a62f29-11d6-957d-da22-f780a247ad24";Source = {Id = "9935af7b-9671-60a2-a76a-f00d3a372d6c";PortNumber = None;PortType = PortType.Output;HostId = "eb5353fd-fac6-3b2a-4de8-8949046671d2"};Target = {Id = "69688e66-1a74-e959-f58a-6085a5ae5c57";PortNumber = None;PortType = PortType.Input;HostId = "825b172a-9355-8bf1-10fc-b18f06d4e76b"};Vertices = [374.0,296.0; 536.0,296.0]}; + {Id = "ee6ffc42-4a79-edff-3eb2-7008eec7a649";Source = {Id = "b9f547be-e285-cb90-1803-b8d3a4c0d351";PortNumber = None;PortType = PortType.Output;HostId = "eb5353fd-fac6-3b2a-4de8-8949046671d2"};Target = {Id = "8bfcfe42-be19-e2fa-42ae-25e929cab003";PortNumber = None;PortType = PortType.Input;HostId = "66030e1a-4a97-244a-f0bb-d9e5fd25627f"};Vertices = [374.0,276.0; 488.0,276.0]} + ] + +/// stateSync8 loaded as a dependency. +let stateSync8Dependency : LoadedComponent = { + Name = "fake-combinatorial-loop" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + FilePath = "" + CanvasState = stateSync8 + InputLabels = [] + OutputLabels = ["B", 1;] +} + +/// stateSync8 custom component. +let stateSync8CustomComponent : CustomComponentType = + CanvasStates.makeCustomComponent stateSync8Dependency + +/// StateSync8 connected to an output. Legitmate ciruit that behaves precisely +/// like stateSync8. +let stateSync9 : CanvasState = + [ + {H=50; W=40;Id = "16e7b03d-6504-a148-e207-ce99634ee5c5";Type = Custom stateSync8CustomComponent;Label = "loop2";InputPorts = [];OutputPorts = [{Id = "1db2fde2-c823-9ac8-1b7f-5187166934e9";PortNumber = Some 0;PortType = PortType.Output;HostId = "16e7b03d-6504-a148-e207-ce99634ee5c5"}];X = 568;Y = 310}; + {H=50; W=40;Id = "a100bada-b27f-15ca-accb-153e717a31f1";Type = Output 1;Label = "B";InputPorts = [{Id = "b2c8d4ef-bb50-3b2b-259b-e6381ca798a4";PortNumber = Some 0;PortType = PortType.Input;HostId = "a100bada-b27f-15ca-accb-153e717a31f1"}];OutputPorts = [];X = 715;Y = 315} + ], + [ + {Id = "2b617de7-dfcc-0287-1d9e-0f6a3b40de5b";Source = {Id = "1db2fde2-c823-9ac8-1b7f-5187166934e9";PortNumber = None;PortType = PortType.Output;HostId = "16e7b03d-6504-a148-e207-ce99634ee5c5"};Target = {Id = "b2c8d4ef-bb50-3b2b-259b-e6381ca798a4";PortNumber = None;PortType = PortType.Input;HostId = "a100bada-b27f-15ca-accb-153e717a31f1"};Vertices = [618.0,325.0; 715.0,325.0]} + ] + +/// A fully connected DFFE. +let stateSync10 : CanvasState = + [ + {H=50; W=40;Id = "5916f1cf-408e-4186-a839-c80926bfddf0";Type = Input 1;Label = "in";InputPorts = [];OutputPorts = [{Id = "e894fb40-804a-36d1-b2e8-6033afb61dfa";PortNumber = Some 0;PortType = PortType.Output;HostId = "5916f1cf-408e-4186-a839-c80926bfddf0"}];X = 109;Y = 95}; + {H=50; W=40;Id = "4f90dab4-e43d-3c75-cd2e-27a5ef66ccaf";Type = DFFE;Label = "";InputPorts = [{Id = "c766cb8d-a762-04b9-f021-4a9175fdbc01";PortNumber = Some 0;PortType = PortType.Input;HostId = "4f90dab4-e43d-3c75-cd2e-27a5ef66ccaf"}; {Id = "2b80cebe-c0af-4905-d443-fd99796ec8df";PortNumber = Some 1;PortType = PortType.Input;HostId = "4f90dab4-e43d-3c75-cd2e-27a5ef66ccaf"}];OutputPorts = [{Id = "ecee9ad7-925f-c0b9-26d5-4cf8b96a9be1";PortNumber = Some 0;PortType = PortType.Output;HostId = "4f90dab4-e43d-3c75-cd2e-27a5ef66ccaf"}];X = 273;Y = 80}; + {H=50; W=40;Id = "cab54371-5e07-9586-eb9b-be8cc417e610";Type = Input 1;Label = "en";InputPorts = [];OutputPorts = [{Id = "4c83ef6d-7267-2732-d828-c508fff7f889";PortNumber = Some 0;PortType = PortType.Output;HostId = "cab54371-5e07-9586-eb9b-be8cc417e610"}];X = 109;Y = 270}; + {H=50; W=40;Id = "a2c874bb-eaeb-d62d-8a72-5eeae48db694";Type = Output 1;Label = "out";InputPorts = [{Id = "df5f625f-43c4-28bb-c931-eae047edaa14";PortNumber = Some 0;PortType = PortType.Input;HostId = "a2c874bb-eaeb-d62d-8a72-5eeae48db694"}];OutputPorts = [];X = 495;Y = 95} + ], + [ + {Id = "7ab86f0a-1b2c-7901-0a12-cbe447f1f06d";Source = {Id = "e894fb40-804a-36d1-b2e8-6033afb61dfa";PortNumber = None;PortType = PortType.Output;HostId = "5916f1cf-408e-4186-a839-c80926bfddf0"};Target = {Id = "c766cb8d-a762-04b9-f021-4a9175fdbc01";PortNumber = None;PortType = PortType.Input;HostId = "4f90dab4-e43d-3c75-cd2e-27a5ef66ccaf"};Vertices = [139.0,105.0; 273.0,105.0]}; + {Id = "04bb7d64-1899-a4f3-6c50-f53ccd84cd49";Source = {Id = "ecee9ad7-925f-c0b9-26d5-4cf8b96a9be1";PortNumber = None;PortType = PortType.Output;HostId = "4f90dab4-e43d-3c75-cd2e-27a5ef66ccaf"};Target = {Id = "df5f625f-43c4-28bb-c931-eae047edaa14";PortNumber = None;PortType = PortType.Input;HostId = "a2c874bb-eaeb-d62d-8a72-5eeae48db694"};Vertices = [353.0,105.0; 495.0,105.0]}; + {Id = "de4f03d1-580c-eabb-7439-38b664b89aba";Source = {Id = "4c83ef6d-7267-2732-d828-c508fff7f889";PortNumber = None;PortType = PortType.Output;HostId = "cab54371-5e07-9586-eb9b-be8cc417e610"};Target = {Id = "2b80cebe-c0af-4905-d443-fd99796ec8df";PortNumber = None;PortType = PortType.Input;HostId = "4f90dab4-e43d-3c75-cd2e-27a5ef66ccaf"};Vertices = [139.0,280.938; 313.0,280.938; 313.0,130.0]} + ] + +/// stateSync7 Not-ed self looped in the combinatorial branch. This is NOT a +/// legitimate circuit, has combinatorial cycle. Similar to stateSync8 but loops +/// with the other output of the custom component. +let stateSync11 : CanvasState = + [ + {H=50; W=40;Id = "c9d9659a-4476-de3a-a838-eeab15496c99";Type = Custom stateSync7CustomComponent;Label = "loop1";InputPorts = [{Id = "c52782db-1ac3-f0d5-28ca-02c8410eb78d";PortNumber = Some 0;PortType = PortType.Input;HostId = "c9d9659a-4476-de3a-a838-eeab15496c99"}];OutputPorts = [{Id = "eda8e4f2-f21b-12fc-b209-ad315b99a851";PortNumber = Some 0;PortType = PortType.Output;HostId = "c9d9659a-4476-de3a-a838-eeab15496c99"}; {Id = "627b5ddf-e4ef-5629-70d4-af674cf37b96";PortNumber = Some 1;PortType = PortType.Output;HostId = "c9d9659a-4476-de3a-a838-eeab15496c99"}];X = 508;Y = 245}; + {H=50; W=40;Id = "5c24921a-88e9-7bc2-ee89-97fefb694902";Type = Not;Label = "";InputPorts = [{Id = "e16cf7e3-d01f-29e5-8d0d-921194f2f909";PortNumber = Some 0;PortType = PortType.Input;HostId = "5c24921a-88e9-7bc2-ee89-97fefb694902"}];OutputPorts = [{Id = "50f7aed7-49de-5472-defa-cbf07c2c4f56";PortNumber = Some 0;PortType = PortType.Output;HostId = "5c24921a-88e9-7bc2-ee89-97fefb694902"}];X = 664;Y = 245}; + {H=50; W=40;Id = "68bfdbd5-b91f-9f34-0a32-2f8730856d49";Type = Output 1;Label = "B-Sync";InputPorts = [{Id = "ce17f39f-f79e-d9c5-78dd-379d4be0d3a4";PortNumber = Some 0;PortType = PortType.Input;HostId = "68bfdbd5-b91f-9f34-0a32-2f8730856d49"}];OutputPorts = [];X = 701;Y = 273} + ], + [ + {Id = "24e0a9c6-5a3a-e5e9-5034-0f831dcbe0f9";Source = {Id = "627b5ddf-e4ef-5629-70d4-af674cf37b96";PortNumber = None;PortType = PortType.Output;HostId = "c9d9659a-4476-de3a-a838-eeab15496c99"};Target = {Id = "ce17f39f-f79e-d9c5-78dd-379d4be0d3a4";PortNumber = None;PortType = PortType.Input;HostId = "68bfdbd5-b91f-9f34-0a32-2f8730856d49"};Vertices = [580.0,285.0; 640.5,285.0; 640.5,283.0; 701.0,283.0]}; + {Id = "bc1f9a51-5ca8-1aa0-b4bd-b86bc9646c20";Source = {Id = "eda8e4f2-f21b-12fc-b209-ad315b99a851";PortNumber = None;PortType = PortType.Output;HostId = "c9d9659a-4476-de3a-a838-eeab15496c99"};Target = {Id = "e16cf7e3-d01f-29e5-8d0d-921194f2f909";PortNumber = None;PortType = PortType.Input;HostId = "5c24921a-88e9-7bc2-ee89-97fefb694902"};Vertices = [580.0,265.0; 622.0,265.0; 622.0,260.0; 664.0,260.0]}; + {Id = "cc7a9da2-f78a-f3e1-1c2f-7323f2b43d15";Source = {Id = "50f7aed7-49de-5472-defa-cbf07c2c4f56";PortNumber = None;PortType = PortType.Output;HostId = "5c24921a-88e9-7bc2-ee89-97fefb694902"};Target = {Id = "c52782db-1ac3-f0d5-28ca-02c8410eb78d";PortNumber = None;PortType = PortType.Input;HostId = "c9d9659a-4476-de3a-a838-eeab15496c99"};Vertices = [694.0,260.0; 714.0,260.0; 714.0,195.5; 488.0,195.5; 488.0,275.0; 508.0,275.0]} + ] + +/// stateSync11 loaded as a dependency. +let stateSync11Dependency : LoadedComponent = { + Name = "combinatorial-loop" + TimeStamp = System.DateTime.MinValue + WaveInfo = None + FilePath = "" + CanvasState = stateSync11 + InputLabels = [] + OutputLabels = ["B-Sync", 1;] +} + +/// stateSync11 custom component. +let stateSync11CustomComponent : CustomComponentType = + CanvasStates.makeCustomComponent stateSync11Dependency + +/// StateSync11 connected to an output. Should spot cycle in the dependency. +let stateSync12 : CanvasState = + [ + {H=50; W=40;Id = "eab95b08-cf95-15b7-ad8f-4eaffcefff6f";Type = Custom stateSync11CustomComponent;Label = "loop2-comb";InputPorts = [];OutputPorts = [{Id = "685a78e3-c891-d0c3-f973-1814b01edd28";PortNumber = Some 0;PortType = PortType.Output;HostId = "eab95b08-cf95-15b7-ad8f-4eaffcefff6f"}];X = 354;Y = 215}; + {H=50; W=40;Id = "638304a8-99e8-fe4f-4503-b50c64f45756";Type = Output 1;Label = "B-Comb";InputPorts = [{Id = "3b0171fa-dffe-f4c5-5f8c-e365112bae2f";PortNumber = Some 0;PortType = PortType.Input;HostId = "638304a8-99e8-fe4f-4503-b50c64f45756"}];OutputPorts = [];X = 532;Y = 220} + ], + [ + {Id = "f7c55a63-955e-6edd-0db6-fe320dc02c02";Source = {Id = "685a78e3-c891-d0c3-f973-1814b01edd28";PortNumber = None;PortType = PortType.Output;HostId = "eab95b08-cf95-15b7-ad8f-4eaffcefff6f"};Target = {Id = "3b0171fa-dffe-f4c5-5f8c-e365112bae2f";PortNumber = None;PortType = PortType.Input;HostId = "638304a8-99e8-fe4f-4503-b50c64f45756"};Vertices = [420.0,230.0; 532.0,230.0]} + ] diff --git a/Tests/CanvasStatesWithBuses.fs b/Tests/CanvasStatesWithBuses.fs new file mode 100644 index 0000000..8afa48a --- /dev/null +++ b/Tests/CanvasStatesWithBuses.fs @@ -0,0 +1,278 @@ +module CanvasStatesWithBuses + +open CommonTypes +open CanvasStates + +/// Two inputs connected to a MergeWires component. No other connections. +let stateBus1 : CanvasState = + [ + {H=50;W=40; Id = "08de9671-756c-44e0-905c-cde5b9a98aa9";Type = Input 1;Label = "a";InputPorts = [];OutputPorts = [{Id = "528c3ccc-9554-6a5b-129f-c88e55478ae2";PortNumber = Some 0;PortType = PortType.Output;HostId = "08de9671-756c-44e0-905c-cde5b9a98aa9"}];X = 100;Y = 100}; + {H=50;W=40; Id = "0b7b0ae5-dcca-f0af-3ba6-68231fdf80fc";Type = Input 1;Label = "b";InputPorts = [];OutputPorts = [{Id = "9de10edf-96be-beb0-2926-45f98b5dccb2";PortNumber = Some 0;PortType = PortType.Output;HostId = "0b7b0ae5-dcca-f0af-3ba6-68231fdf80fc"}];X = 100;Y = 169}; + {H=50;W=40; Id = "8caa65e2-97eb-ed9c-cd34-220b1fde3add";Type = MergeWires;Label = "";InputPorts = [{Id = "6d525499-76f1-001b-3cca-726c4aa9b2ee";PortNumber = Some 0;PortType = PortType.Input;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"}; {Id = "0d6f9b2f-d511-c08b-3b72-4c23975adeda";PortNumber = Some 1;PortType = PortType.Input;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"}];OutputPorts = [{Id = "f8a73708-ed54-cc87-d4d5-0a72745e82c7";PortNumber = Some 0;PortType = PortType.Output;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"}];X = 230;Y = 138} + ], + [ + {Id = "conn0";Source = {Id = "528c3ccc-9554-6a5b-129f-c88e55478ae2";PortNumber = None;PortType = PortType.Output;HostId = "08de9671-756c-44e0-905c-cde5b9a98aa9"};Target = {Id = "6d525499-76f1-001b-3cca-726c4aa9b2ee";PortNumber = None;PortType = PortType.Input;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"};Vertices = [130.0,110.0; 180.0,110.0; 180.0,138.0; 230.0,138.0]}; + {Id = "conn1";Source = {Id = "9de10edf-96be-beb0-2926-45f98b5dccb2";PortNumber = None;PortType = PortType.Output;HostId = "0b7b0ae5-dcca-f0af-3ba6-68231fdf80fc"};Target = {Id = "0d6f9b2f-d511-c08b-3b72-4c23975adeda";PortNumber = None;PortType = PortType.Input;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"};Vertices = [130.0,179.0; 180.0,179.0; 180.0,158.0; 230.0,158.0]} + ] + +/// A MergeWires connected to a SplitWire 1. +let stateBus2 : CanvasState = + [ + {H=50;W=40; Id = "8caa65e2-97eb-ed9c-cd34-220b1fde3add";Type = MergeWires;Label = "";InputPorts = [{Id = "6d525499-76f1-001b-3cca-726c4aa9b2ee";PortNumber = Some 0;PortType = PortType.Input;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"}; {Id = "0d6f9b2f-d511-c08b-3b72-4c23975adeda";PortNumber = Some 1;PortType = PortType.Input;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"}];OutputPorts = [{Id = "f8a73708-ed54-cc87-d4d5-0a72745e82c7";PortNumber = Some 0;PortType = PortType.Output;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"}];X = 230;Y = 138}; + {H=50;W=40; Id = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2";Type = SplitWire 1;Label = "";InputPorts = [{Id = "ba539631-cbee-1c40-e2ad-755e3c4893ab";PortNumber = Some 0;PortType = PortType.Input;HostId = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2"}];OutputPorts = [{Id = "9f93cb8f-ad50-a556-57fb-3f1ec4cbdaba";PortNumber = Some 0;PortType = PortType.Output;HostId = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2"}; {Id = "58dc5768-a64d-e6d6-36cc-fecdd57b57d7";PortNumber = Some 1;PortType = PortType.Output;HostId = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2"}];X = 336;Y = 138} + ], + [ + {Id = "conn0";Source = {Id = "f8a73708-ed54-cc87-d4d5-0a72745e82c7";PortNumber = None;PortType = PortType.Output;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"};Target = {Id = "ba539631-cbee-1c40-e2ad-755e3c4893ab";PortNumber = None;PortType = PortType.Input;HostId = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2"};Vertices = [270.0,148.0; 336.0,148.0]} + ] + +/// A MergeWires connected to a SplitWire 1 and a single-bit output node. +let stateBus3 : CanvasState = + [ + {H=50;W=40; Id = "8caa65e2-97eb-ed9c-cd34-220b1fde3add";Type = MergeWires;Label = "";InputPorts = [{Id = "6d525499-76f1-001b-3cca-726c4aa9b2ee";PortNumber = Some 0;PortType = PortType.Input;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"}; {Id = "0d6f9b2f-d511-c08b-3b72-4c23975adeda";PortNumber = Some 1;PortType = PortType.Input;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"}];OutputPorts = [{Id = "f8a73708-ed54-cc87-d4d5-0a72745e82c7";PortNumber = Some 0;PortType = PortType.Output;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"}];X = 230;Y = 138}; + {H=50;W=40; Id = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2";Type = SplitWire 1;Label = "";InputPorts = [{Id = "ba539631-cbee-1c40-e2ad-755e3c4893ab";PortNumber = Some 0;PortType = PortType.Input;HostId = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2"}];OutputPorts = [{Id = "9f93cb8f-ad50-a556-57fb-3f1ec4cbdaba";PortNumber = Some 0;PortType = PortType.Output;HostId = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2"}; {Id = "58dc5768-a64d-e6d6-36cc-fecdd57b57d7";PortNumber = Some 1;PortType = PortType.Output;HostId = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2"}];X = 336;Y = 138} + {H=50;W=40; Id = "7af6a475-990d-015f-e9e0-4a680cc84173";Type = Output 1;Label = "a";InputPorts = [{Id = "cefbb411-481e-d04d-c5a0-02f3921e423f";PortNumber = Some 0;PortType = PortType.Input;HostId = "7af6a475-990d-015f-e9e0-4a680cc84173"}];OutputPorts = [];X = 346;Y = 63} + ], + [ + {Id = "conn0";Source = {Id = "f8a73708-ed54-cc87-d4d5-0a72745e82c7";PortNumber = None;PortType = PortType.Output;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"};Target = {Id = "ba539631-cbee-1c40-e2ad-755e3c4893ab";PortNumber = None;PortType = PortType.Input;HostId = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2"};Vertices = [270.0,148.0; 336.0,148.0]} + {Id = "conn1";Source = {Id = "f8a73708-ed54-cc87-d4d5-0a72745e82c7";PortNumber = None;PortType = PortType.Output;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"};Target = {Id = "cefbb411-481e-d04d-c5a0-02f3921e423f";PortNumber = None;PortType = PortType.Input;HostId = "7af6a475-990d-015f-e9e0-4a680cc84173"};Vertices = [270.0,148.0; 308.0,148.0; 308.0,73.0; 346.0,73.0]} + ] + +/// Like stateBus2 but with a loop. +let stateBus4 : CanvasState = + [ + {H=50;W=40; Id = "8caa65e2-97eb-ed9c-cd34-220b1fde3add";Type = MergeWires;Label = "";InputPorts = [{Id = "6d525499-76f1-001b-3cca-726c4aa9b2ee";PortNumber = Some 0;PortType = PortType.Input;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"}; {Id = "0d6f9b2f-d511-c08b-3b72-4c23975adeda";PortNumber = Some 1;PortType = PortType.Input;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"}];OutputPorts = [{Id = "f8a73708-ed54-cc87-d4d5-0a72745e82c7";PortNumber = Some 0;PortType = PortType.Output;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"}];X = 230;Y = 138}; + {H=50;W=40; Id = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2";Type = SplitWire 1;Label = "";InputPorts = [{Id = "ba539631-cbee-1c40-e2ad-755e3c4893ab";PortNumber = Some 0;PortType = PortType.Input;HostId = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2"}];OutputPorts = [{Id = "9f93cb8f-ad50-a556-57fb-3f1ec4cbdaba";PortNumber = Some 0;PortType = PortType.Output;HostId = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2"}; {Id = "58dc5768-a64d-e6d6-36cc-fecdd57b57d7";PortNumber = Some 1;PortType = PortType.Output;HostId = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2"}];X = 336;Y = 138} + ], + [ + {Id = "conn0";Source = {Id = "f8a73708-ed54-cc87-d4d5-0a72745e82c7";PortNumber = None;PortType = PortType.Output;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"};Target = {Id = "ba539631-cbee-1c40-e2ad-755e3c4893ab";PortNumber = None;PortType = PortType.Input;HostId = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2"};Vertices = [270.0,148.0; 336.0,148.0]} + {Id = "conn1";Source = {Id = "9f93cb8f-ad50-a556-57fb-3f1ec4cbdaba";PortNumber = None;PortType = PortType.Output;HostId = "6060cff2-0e4f-d3ac-a8f2-40557eca62b2"};Target = {Id = "6d525499-76f1-001b-3cca-726c4aa9b2ee";PortNumber = None;PortType = PortType.Input;HostId = "8caa65e2-97eb-ed9c-cd34-220b1fde3add"};Vertices = [376.0,138.0; 396.0,138.0; 396.0,138.0; 210.0,138.0; 210.0,138.0; 230.0,138.0]} + ] + +/// All the bus components in series, properly connected. No other components. +let stateBus6 : CanvasState = + [ + {H=50;W=40; Id = "52a4b421-c919-6177-c66c-ec2a77379373";Type = SplitWire 1;Label = "";InputPorts = [{Id = "07e65ee3-58a7-a5e0-724a-0f56f2e528c5";PortNumber = Some 0;PortType = PortType.Input;HostId = "52a4b421-c919-6177-c66c-ec2a77379373"}];OutputPorts = [{Id = "8e27936c-75e6-5ad1-777e-6aa111b2d584";PortNumber = Some 0;PortType = PortType.Output;HostId = "52a4b421-c919-6177-c66c-ec2a77379373"}; {Id = "1385e5ca-c8e7-b209-402f-b85c42023bdb";PortNumber = Some 1;PortType = PortType.Output;HostId = "52a4b421-c919-6177-c66c-ec2a77379373"}];X = 614;Y = 258}; + {H=50;W=40; Id = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d";Type = MergeWires;Label = "";InputPorts = [{Id = "94d62be4-60ae-4e5f-add7-3715341617aa";PortNumber = Some 0;PortType = PortType.Input;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"}; {Id = "c8e1b3ee-d1c7-e576-6e8e-eca93bb33fce";PortNumber = Some 1;PortType = PortType.Input;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"}];OutputPorts = [{Id = "cabe29d9-74ea-06b9-8421-8547090727f9";PortNumber = Some 0;PortType = PortType.Output;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"}];X = 241;Y = 248}; + {H=50;W=40; Id = "66dd284a-9199-fda1-867b-4e6b837a7ae5";Type = MergeWires;Label = "";InputPorts = [{Id = "2ee75313-e4e3-4ab8-9e36-a5089e49278d";PortNumber = Some 0;PortType = PortType.Input;HostId = "66dd284a-9199-fda1-867b-4e6b837a7ae5"}; {Id = "a5d69516-6a23-a363-e86f-2fe2a062e722";PortNumber = Some 1;PortType = PortType.Input;HostId = "66dd284a-9199-fda1-867b-4e6b837a7ae5"}];OutputPorts = [{Id = "caf8086a-b657-bc0a-5684-a25556b95845";PortNumber = Some 0;PortType = PortType.Output;HostId = "66dd284a-9199-fda1-867b-4e6b837a7ae5"}];X = 153;Y = 258}; + {H=50;W=40; Id = "02e33421-bea8-657b-1e17-6e0df31696d5";Type = SplitWire 2;Label = "";InputPorts = [{Id = "ed9727f2-373b-9f23-9293-dacea5a5476b";PortNumber = Some 0;PortType = PortType.Input;HostId = "02e33421-bea8-657b-1e17-6e0df31696d5"}];OutputPorts = [{Id = "7beda885-b4f4-f5be-ada5-476643c2cec3";PortNumber = Some 0;PortType = PortType.Output;HostId = "02e33421-bea8-657b-1e17-6e0df31696d5"}; {Id = "853f0e05-b301-db44-d437-d50abef0065b";PortNumber = Some 1;PortType = PortType.Output;HostId = "02e33421-bea8-657b-1e17-6e0df31696d5"}];X = 531;Y = 248}; + {H=50;W=40; Id = "eb13d9a8-162b-3ffc-a1d8-e6666edf7a67";Type = MergeWires;Label = "";InputPorts = [{Id = "b87776d8-4588-4dc1-3251-342683ee4ba8";PortNumber = Some 0;PortType = PortType.Input;HostId = "eb13d9a8-162b-3ffc-a1d8-e6666edf7a67"}; {Id = "b26122bb-0ce1-8e3e-1021-a9aec7c4c0ca";PortNumber = Some 1;PortType = PortType.Input;HostId = "eb13d9a8-162b-3ffc-a1d8-e6666edf7a67"}];OutputPorts = [{Id = "211fd204-86fe-e959-b4fa-129d1b4accb4";PortNumber = Some 0;PortType = PortType.Output;HostId = "eb13d9a8-162b-3ffc-a1d8-e6666edf7a67"}];X = 329;Y = 258}; + {H=50;W=40; Id = "a7db69d3-5a34-e5d2-46d1-19fe8879b625";Type = SplitWire 1;Label = "";InputPorts = [{Id = "075ab754-bff4-ce21-0384-1f46f1ae986a";PortNumber = Some 0;PortType = PortType.Input;HostId = "a7db69d3-5a34-e5d2-46d1-19fe8879b625"}];OutputPorts = [{Id = "673c4ac0-9c68-6f3c-dfd4-6b129b956357";PortNumber = Some 0;PortType = PortType.Output;HostId = "a7db69d3-5a34-e5d2-46d1-19fe8879b625"}; {Id = "3a314510-a373-0c2c-50c1-ac3ce9d5f4f7";PortNumber = Some 1;PortType = PortType.Output;HostId = "a7db69d3-5a34-e5d2-46d1-19fe8879b625"}];X = 438;Y = 258} + ], + [ + {Id = "conn0";Source = {Id = "caf8086a-b657-bc0a-5684-a25556b95845";PortNumber = None;PortType = PortType.Output;HostId = "66dd284a-9199-fda1-867b-4e6b837a7ae5"};Target = {Id = "c8e1b3ee-d1c7-e576-6e8e-eca93bb33fce";PortNumber = None;PortType = PortType.Input;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"};Vertices = [193.0,268.0; 230.0,268.0; 230.0,268.0; 241.0,268.0]}; + {Id = "conn1";Source = {Id = "cabe29d9-74ea-06b9-8421-8547090727f9";PortNumber = None;PortType = PortType.Output;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"};Target = {Id = "b87776d8-4588-4dc1-3251-342683ee4ba8";PortNumber = None;PortType = PortType.Input;HostId = "eb13d9a8-162b-3ffc-a1d8-e6666edf7a67"};Vertices = [281.0,258.0; 329.0,258.0]} + {Id = "conn2";Source = {Id = "211fd204-86fe-e959-b4fa-129d1b4accb4";PortNumber = None;PortType = PortType.Output;HostId = "eb13d9a8-162b-3ffc-a1d8-e6666edf7a67"};Target = {Id = "075ab754-bff4-ce21-0384-1f46f1ae986a";PortNumber = None;PortType = PortType.Input;HostId = "a7db69d3-5a34-e5d2-46d1-19fe8879b625"};Vertices = [369.0,268.0; 438.0,268.0]}; + {Id = "conn3";Source = {Id = "673c4ac0-9c68-6f3c-dfd4-6b129b956357";PortNumber = None;PortType = PortType.Output;HostId = "a7db69d3-5a34-e5d2-46d1-19fe8879b625"};Target = {Id = "ed9727f2-373b-9f23-9293-dacea5a5476b";PortNumber = None;PortType = PortType.Input;HostId = "02e33421-bea8-657b-1e17-6e0df31696d5"};Vertices = [478.0,258.0; 531.0,258.0]}; + {Id = "conn4";Source = {Id = "853f0e05-b301-db44-d437-d50abef0065b";PortNumber = None;PortType = PortType.Output;HostId = "02e33421-bea8-657b-1e17-6e0df31696d5"};Target = {Id = "07e65ee3-58a7-a5e0-724a-0f56f2e528c5";PortNumber = None;PortType = PortType.Input;HostId = "52a4b421-c919-6177-c66c-ec2a77379373"};Vertices = [571.0,268.0; 614.0,268.0]}; + ] + +/// Non-inferrable loop: MergeWires connected to MergeWires and loop back. +let stateBus7 : CanvasState = + [ + {H=50;W=40; Id = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d";Type = MergeWires;Label = "";InputPorts = [{Id = "94d62be4-60ae-4e5f-add7-3715341617aa";PortNumber = Some 0;PortType = PortType.Input;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"}; {Id = "c8e1b3ee-d1c7-e576-6e8e-eca93bb33fce";PortNumber = Some 1;PortType = PortType.Input;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"}];OutputPorts = [{Id = "cabe29d9-74ea-06b9-8421-8547090727f9";PortNumber = Some 0;PortType = PortType.Output;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"}];X = 241;Y = 248}; + {H=50;W=40; Id = "eb13d9a8-162b-3ffc-a1d8-e6666edf7a67";Type = MergeWires;Label = "";InputPorts = [{Id = "b87776d8-4588-4dc1-3251-342683ee4ba8";PortNumber = Some 0;PortType = PortType.Input;HostId = "eb13d9a8-162b-3ffc-a1d8-e6666edf7a67"}; {Id = "b26122bb-0ce1-8e3e-1021-a9aec7c4c0ca";PortNumber = Some 1;PortType = PortType.Input;HostId = "eb13d9a8-162b-3ffc-a1d8-e6666edf7a67"}];OutputPorts = [{Id = "211fd204-86fe-e959-b4fa-129d1b4accb4";PortNumber = Some 0;PortType = PortType.Output;HostId = "eb13d9a8-162b-3ffc-a1d8-e6666edf7a67"}];X = 325;Y = 258} + ], + [ + {Id = "conn0";Source = {Id = "211fd204-86fe-e959-b4fa-129d1b4accb4";PortNumber = None;PortType = PortType.Output;HostId = "eb13d9a8-162b-3ffc-a1d8-e6666edf7a67"};Target = {Id = "c8e1b3ee-d1c7-e576-6e8e-eca93bb33fce";PortNumber = None;PortType = PortType.Input;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"};Vertices = [365.0,268.0; 385.0,268.0; 385.0,307.0; 221.0,307.0; 221.0,268.0; 241.0,268.0]}; + {Id = "conn1";Source = {Id = "cabe29d9-74ea-06b9-8421-8547090727f9";PortNumber = None;PortType = PortType.Output;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"};Target = {Id = "b87776d8-4588-4dc1-3251-342683ee4ba8";PortNumber = None;PortType = PortType.Input;HostId = "eb13d9a8-162b-3ffc-a1d8-e6666edf7a67"};Vertices = [281.0,258.0; 325.0,258.0]} + ] + +/// Mux connected to two PushBusFirst. Width not inferrable. +let stateBus8 : CanvasState = + [ + {H=50;W=40; Id = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d";Type = MergeWires;Label = "";InputPorts = [{Id = "94d62be4-60ae-4e5f-add7-3715341617aa";PortNumber = Some 0;PortType = PortType.Input;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"}; {Id = "c8e1b3ee-d1c7-e576-6e8e-eca93bb33fce";PortNumber = Some 1;PortType = PortType.Input;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"}];OutputPorts = [{Id = "cabe29d9-74ea-06b9-8421-8547090727f9";PortNumber = Some 0;PortType = PortType.Output;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"}];X = 241;Y = 248}; + {H=50;W=40; Id = "3875f58b-8744-291d-1f4f-bca5b1a1eda5";Type = Mux2;Label = "mux2";InputPorts = [{Id = "6758d0e5-2618-afe4-473b-43c5002abf74";PortNumber = Some 0;PortType = PortType.Input;HostId = "3875f58b-8744-291d-1f4f-bca5b1a1eda5"}; {Id = "401a0856-683d-6ed2-c193-53d1761ad7a4";PortNumber = Some 1;PortType = PortType.Input;HostId = "3875f58b-8744-291d-1f4f-bca5b1a1eda5"}; {Id = "cf514335-b50d-eb19-c6f5-18303cda0b13";PortNumber = Some 2;PortType = PortType.Input;HostId = "3875f58b-8744-291d-1f4f-bca5b1a1eda5"}];OutputPorts = [{Id = "6bf59da3-ea8a-30c3-163d-37dbefd821bc";PortNumber = Some 0;PortType = PortType.Output;HostId = "3875f58b-8744-291d-1f4f-bca5b1a1eda5"}];X = 145;Y = 190}; + {H=50;W=40; Id = "536f5ede-5b98-ce3f-db3e-e96de247a89b";Type = MergeWires;Label = "";InputPorts = [{Id = "b871e19d-2bec-0cc1-8c71-0fbee278bf51";PortNumber = Some 0;PortType = PortType.Input;HostId = "536f5ede-5b98-ce3f-db3e-e96de247a89b"}; {Id = "69b5caec-1da0-9ecb-d7fc-fbd9af66fc23";PortNumber = Some 1;PortType = PortType.Input;HostId = "536f5ede-5b98-ce3f-db3e-e96de247a89b"}];OutputPorts = [{Id = "6b2d64d3-7697-a97f-ed51-f0991d77b6b9";PortNumber = Some 0;PortType = PortType.Output;HostId = "536f5ede-5b98-ce3f-db3e-e96de247a89b"}];X = 336;Y = 237} + ], + [ + {Id = "conn0";Source = {Id = "6bf59da3-ea8a-30c3-163d-37dbefd821bc";PortNumber = None;PortType = PortType.Output;HostId = "3875f58b-8744-291d-1f4f-bca5b1a1eda5"};Target = {Id = "94d62be4-60ae-4e5f-add7-3715341617aa";PortNumber = None;PortType = PortType.Input;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"};Vertices = [175.0,215.0; 208.0,215.0; 208.0,248.0; 241.0,248.0]}; + {Id = "conn1";Source = {Id = "cabe29d9-74ea-06b9-8421-8547090727f9";PortNumber = None;PortType = PortType.Output;HostId = "37dd0853-0d7e-ab38-82e7-4e5d6d43ee9d"};Target = {Id = "69b5caec-1da0-9ecb-d7fc-fbd9af66fc23";PortNumber = None;PortType = PortType.Input;HostId = "536f5ede-5b98-ce3f-db3e-e96de247a89b"};Vertices = [281.0,258.0; 308.5,258.0; 308.5,257.0; 336.0,257.0]} + ] + +/// And connected to a SplitWire 1. +let stateBus9 : CanvasState = + [ + {H=50;W=40; Id = "3875f58b-8744-291d-1f4f-bca5b1a1eda5";Type = And;Label = "and";InputPorts = [{Id = "6758d0e5-2618-afe4-473b-43c5002abf74";PortNumber = Some 0;PortType = PortType.Input;HostId = "3875f58b-8744-291d-1f4f-bca5b1a1eda5"}; {Id = "401a0856-683d-6ed2-c193-53d1761ad7a4";PortNumber = Some 1;PortType = PortType.Input;HostId = "3875f58b-8744-291d-1f4f-bca5b1a1eda5"}];OutputPorts = [{Id = "6bf59da3-ea8a-30c3-163d-37dbefd821bc";PortNumber = Some 0;PortType = PortType.Output;HostId = "3875f58b-8744-291d-1f4f-bca5b1a1eda5"}];X = 145;Y = 190}; + {H=50;W=40; Id = "772307ab-2941-3343-28a2-faacaa0efc96";Type = SplitWire 1;Label = "";InputPorts = [{Id = "2332109c-b48a-be65-70fd-662fc00cd0c7";PortNumber = Some 0;PortType = PortType.Input;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"}];OutputPorts = [{Id = "6df8212b-0639-3d53-61cd-297e74d6bbad";PortNumber = Some 0;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"}; {Id = "5a95b665-510e-848c-c178-e0356b48940a";PortNumber = Some 1;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"}];X = 262;Y = 205} + ], + [ + {Id = "conn0";Source = {Id = "6bf59da3-ea8a-30c3-163d-37dbefd821bc";PortNumber = None;PortType = PortType.Output;HostId = "3875f58b-8744-291d-1f4f-bca5b1a1eda5"};Target = {Id = "2332109c-b48a-be65-70fd-662fc00cd0c7";PortNumber = None;PortType = PortType.Input;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"};Vertices = [175.0,215.0; 262.0,215.0]} + ] + +/// Two inputs, packed into a bus, unpacked into two outputs. +let stateBus10 : CanvasState = + [ + {H=50;W=40; Id = "772307ab-2941-3343-28a2-faacaa0efc96";Type = SplitWire 1;Label = "";InputPorts = [{Id = "2332109c-b48a-be65-70fd-662fc00cd0c7";PortNumber = Some 0;PortType = PortType.Input;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"}];OutputPorts = [{Id = "6df8212b-0639-3d53-61cd-297e74d6bbad";PortNumber = Some 0;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"}; {Id = "5a95b665-510e-848c-c178-e0356b48940a";PortNumber = Some 1;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"}];X = 336;Y = 205}; + {H=50;W=40; Id = "74dcc790-927f-ae61-fd63-577c3387de0e";Type = MergeWires;Label = "";InputPorts = [{Id = "f4b2f416-0af3-8345-185a-d01b69fdda46";PortNumber = Some 0;PortType = PortType.Input;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"}; {Id = "edd76daa-336d-7c68-8d94-7bbe30539724";PortNumber = Some 1;PortType = PortType.Input;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"}];OutputPorts = [{Id = "6e7f6dfb-770b-1451-a569-1d20cc0785b6";PortNumber = Some 0;PortType = PortType.Output;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"}];X = 235;Y = 205}; + {H=50;W=40; Id = "a91be585-2d3b-d872-be0f-b416c8eb03d2";Type = Input 1;Label = "a";InputPorts = [];OutputPorts = [{Id = "7a9bee0a-7ecc-13b6-ed3e-942f32d3c5fb";PortNumber = Some 0;PortType = PortType.Output;HostId = "a91be585-2d3b-d872-be0f-b416c8eb03d2"}];X = 110;Y = 175}; + {H=50;W=40; Id = "9985ebc6-1cd5-8863-1341-1d543d236d38";Type = Input 1;Label = "b";InputPorts = [];OutputPorts = [{Id = "3d87edd9-9572-df33-f8f8-9b77fbdd6bc5";PortNumber = Some 0;PortType = PortType.Output;HostId = "9985ebc6-1cd5-8863-1341-1d543d236d38"}];X = 110;Y = 245}; + {H=50;W=40; Id = "8a9392fc-493b-7e96-72ec-b6f5f11ded8a";Type = Output 1;Label = "a-out";InputPorts = [{Id = "ee1bc94e-a726-8868-f25a-25b5fc44b60a";PortNumber = Some 0;PortType = PortType.Input;HostId = "8a9392fc-493b-7e96-72ec-b6f5f11ded8a"}];OutputPorts = [];X = 449;Y = 178}; + {H=50;W=40; Id = "dfcf6cff-fbac-e54f-7a9d-7059d17e3a0b"; Type = Output 1; Label = "b-out"; InputPorts = [{Id = "a0194620-020c-8897-0207-9d7e9ee2a538"; PortNumber = Some 0; PortType = PortType.Input; HostId = "dfcf6cff-fbac-e54f-7a9d-7059d17e3a0b"}]; OutputPorts = []; X = 443; Y = 234} + ], + [ + {Id = "cfaa960d-99c2-0f40-4ac7-335f6a238e2b";Source = {Id = "7a9bee0a-7ecc-13b6-ed3e-942f32d3c5fb";PortNumber = None;PortType = PortType.Output;HostId = "a91be585-2d3b-d872-be0f-b416c8eb03d2"};Target = {Id = "f4b2f416-0af3-8345-185a-d01b69fdda46";PortNumber = None;PortType = PortType.Input;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"};Vertices = [140.0,185.0; 187.5,185.0; 187.5,205.0; 235.0,205.0]}; + {Id = "78ceafbf-cfb8-4442-a6bb-62ed6a1893cd";Source = {Id = "5a95b665-510e-848c-c178-e0356b48940a";PortNumber = None;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"};Target = {Id = "a0194620-020c-8897-0207-9d7e9ee2a538";PortNumber = None;PortType = PortType.Input;HostId = "dfcf6cff-fbac-e54f-7a9d-7059d17e3a0b"};Vertices = [376.0,225.0; 409.5,225.0; 409.5,244.0; 443.0,244.0]}; + {Id = "221f1ae2-9beb-5099-bc4c-a3f6c86214d4";Source = {Id = "6df8212b-0639-3d53-61cd-297e74d6bbad";PortNumber = None;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"};Target = {Id = "ee1bc94e-a726-8868-f25a-25b5fc44b60a";PortNumber = None;PortType = PortType.Input;HostId = "8a9392fc-493b-7e96-72ec-b6f5f11ded8a"};Vertices = [376.0,205.0; 412.5,205.0; 412.5,188.0; 449.0,188.0]}; + {Id = "1287faef-e07d-cca5-83c7-3aa3b1265cd8";Source = {Id = "3d87edd9-9572-df33-f8f8-9b77fbdd6bc5";PortNumber = None;PortType = PortType.Output;HostId = "9985ebc6-1cd5-8863-1341-1d543d236d38"};Target = {Id = "edd76daa-336d-7c68-8d94-7bbe30539724";PortNumber = None;PortType = PortType.Input;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"};Vertices = [140.0,255.0; 187.5,255.0; 187.5,225.0; 235.0,225.0]}; + {Id = "35d2c879-dda4-f719-836f-f6daf9803c85";Source = {Id = "6e7f6dfb-770b-1451-a569-1d20cc0785b6";PortNumber = None;PortType = PortType.Output;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"};Target = {Id = "2332109c-b48a-be65-70fd-662fc00cd0c7";PortNumber = None;PortType = PortType.Input;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"};Vertices = [275.0,215.0; 336.0,215.0]} + ] + +/// Two inputs make a bus2, then Push input a to bus, then try to split into 2 single bits (fail). +let stateBus11 : CanvasState = + [ + {H=50;W=40; Id = "772307ab-2941-3343-28a2-faacaa0efc96";Type = SplitWire 1;Label = "";InputPorts = [{Id = "2332109c-b48a-be65-70fd-662fc00cd0c7";PortNumber = Some 0;PortType = PortType.Input;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"}];OutputPorts = [{Id = "6df8212b-0639-3d53-61cd-297e74d6bbad";PortNumber = Some 0;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"}; {Id = "5a95b665-510e-848c-c178-e0356b48940a";PortNumber = Some 1;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"}];X = 410;Y = 200}; + {H=50;W=40; Id = "74dcc790-927f-ae61-fd63-577c3387de0e";Type = MergeWires;Label = "";InputPorts = [{Id = "f4b2f416-0af3-8345-185a-d01b69fdda46";PortNumber = Some 0;PortType = PortType.Input;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"}; {Id = "edd76daa-336d-7c68-8d94-7bbe30539724";PortNumber = Some 1;PortType = PortType.Input;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"}];OutputPorts = [{Id = "6e7f6dfb-770b-1451-a569-1d20cc0785b6";PortNumber = Some 0;PortType = PortType.Output;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"}];X = 235;Y = 205}; + {H=50;W=40; Id = "a91be585-2d3b-d872-be0f-b416c8eb03d2";Type = Input 1;Label = "a";InputPorts = [];OutputPorts = [{Id = "7a9bee0a-7ecc-13b6-ed3e-942f32d3c5fb";PortNumber = Some 0;PortType = PortType.Output;HostId = "a91be585-2d3b-d872-be0f-b416c8eb03d2"}];X = 110;Y = 175}; + {H=50;W=40; Id = "9985ebc6-1cd5-8863-1341-1d543d236d38";Type = Input 1;Label = "b";InputPorts = [];OutputPorts = [{Id = "3d87edd9-9572-df33-f8f8-9b77fbdd6bc5";PortNumber = Some 0;PortType = PortType.Output;HostId = "9985ebc6-1cd5-8863-1341-1d543d236d38"}];X = 110;Y = 245}; + {H=50;W=40; Id = "8a9392fc-493b-7e96-72ec-b6f5f11ded8a";Type = Output 1;Label = "a-out";InputPorts = [{Id = "ee1bc94e-a726-8868-f25a-25b5fc44b60a";PortNumber = Some 0;PortType = PortType.Input;HostId = "8a9392fc-493b-7e96-72ec-b6f5f11ded8a"}];OutputPorts = [];X = 523;Y = 173}; + {H=50;W=40; Id = "dfcf6cff-fbac-e54f-7a9d-7059d17e3a0b";Type = Output 1;Label = "b-out";InputPorts = [{Id = "a0194620-020c-8897-0207-9d7e9ee2a538";PortNumber = Some 0;PortType = PortType.Input;HostId = "dfcf6cff-fbac-e54f-7a9d-7059d17e3a0b"}];OutputPorts = [];X = 517;Y = 229}; + {H=50;W=40; Id = "94efe8d3-413b-9390-b627-be7bc91ae2d1";Type = MergeWires;Label = "";InputPorts = [{Id = "4a1da488-0834-1835-9649-6f4d5c172579";PortNumber = Some 0;PortType = PortType.Input;HostId = "94efe8d3-413b-9390-b627-be7bc91ae2d1"}; {Id = "4f58042b-383e-7557-fa72-8b149ba177a2";PortNumber = Some 1;PortType = PortType.Input;HostId = "94efe8d3-413b-9390-b627-be7bc91ae2d1"}];OutputPorts = [{Id = "3fbb97a2-aab1-b94d-c4cf-d52f8421f3b8";PortNumber = Some 0;PortType = PortType.Output;HostId = "94efe8d3-413b-9390-b627-be7bc91ae2d1"}];X = 317;Y = 196} + ], + [ + {Id = "conn";Source = {Id = "5a95b665-510e-848c-c178-e0356b48940a";PortNumber = None;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"};Target = {Id = "a0194620-020c-8897-0207-9d7e9ee2a538";PortNumber = None;PortType = PortType.Input;HostId = "dfcf6cff-fbac-e54f-7a9d-7059d17e3a0b"};Vertices = [450.0,220.0; 483.5,220.0; 483.5,239.0; 517.0,239.0]}; + {Id = "221f1ae2-9beb-5099-bc4c-a3f6c86214d4";Source = {Id = "6df8212b-0639-3d53-61cd-297e74d6bbad";PortNumber = None;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"};Target = {Id = "ee1bc94e-a726-8868-f25a-25b5fc44b60a";PortNumber = None;PortType = PortType.Input;HostId = "8a9392fc-493b-7e96-72ec-b6f5f11ded8a"};Vertices = [450.0,200.0; 503.0,200.0; 503.0,183.0; 523.0,183.0]}; + {Id = "conn1";Source = {Id = "3fbb97a2-aab1-b94d-c4cf-d52f8421f3b8";PortNumber = None;PortType = PortType.Output;HostId = "94efe8d3-413b-9390-b627-be7bc91ae2d1"};Target = {Id = "2332109c-b48a-be65-70fd-662fc00cd0c7";PortNumber = None;PortType = PortType.Input;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"};Vertices = [357.0,206.0; 383.5,206.0; 383.5,210.0; 410.0,210.0]}; + {Id = "1287faef-e07d-cca5-83c7-3aa3b1265cd8";Source = {Id = "3d87edd9-9572-df33-f8f8-9b77fbdd6bc5";PortNumber = None;PortType = PortType.Output;HostId = "9985ebc6-1cd5-8863-1341-1d543d236d38"};Target = {Id = "edd76daa-336d-7c68-8d94-7bbe30539724";PortNumber = None;PortType = PortType.Input;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"};Vertices = [140.0,255.0; 187.5,255.0; 187.5,225.0; 235.0,225.0]}; + {Id = "3fd09a23-18c1-0edd-b7cb-a70a4b8d42ef";Source = {Id = "6e7f6dfb-770b-1451-a569-1d20cc0785b6";PortNumber = None;PortType = PortType.Output;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"};Target = {Id = "4f58042b-383e-7557-fa72-8b149ba177a2";PortNumber = None;PortType = PortType.Input;HostId = "94efe8d3-413b-9390-b627-be7bc91ae2d1"};Vertices = [275.0,215.0; 296.0,215.0; 296.0,216.0; 317.0,216.0]}; + {Id = "d429c2f2-d60c-0dc9-2279-7022dc127783";Source = {Id = "7a9bee0a-7ecc-13b6-ed3e-942f32d3c5fb";PortNumber = None;PortType = PortType.Output;HostId = "a91be585-2d3b-d872-be0f-b416c8eb03d2"};Target = {Id = "4a1da488-0834-1835-9649-6f4d5c172579";PortNumber = None;PortType = PortType.Input;HostId = "94efe8d3-413b-9390-b627-be7bc91ae2d1"};Vertices = [140.0,185.0; 187.5,185.0; 187.5,196.0; 317.0,196.0]}; + {Id = "cfaa960d-99c2-0f40-4ac7-335f6a238e2b";Source = {Id = "7a9bee0a-7ecc-13b6-ed3e-942f32d3c5fb";PortNumber = None;PortType = PortType.Output;HostId = "a91be585-2d3b-d872-be0f-b416c8eb03d2"};Target = {Id = "f4b2f416-0af3-8345-185a-d01b69fdda46";PortNumber = None;PortType = PortType.Input;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"};Vertices = [140.0,185.0; 187.5,185.0; 187.5,205.0; 235.0,205.0]} + ] + +/// Pack 4 bits into a bus, then extract them. +let stateBus12 : CanvasState = + [ + {H=50;W=40; Id = "772307ab-2941-3343-28a2-faacaa0efc96";Type = SplitWire 1;Label = "";InputPorts = [{Id = "2332109c-b48a-be65-70fd-662fc00cd0c7";PortNumber = Some 0;PortType = PortType.Input;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"}];OutputPorts = [{Id = "6df8212b-0639-3d53-61cd-297e74d6bbad";PortNumber = Some 0;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"}; {Id = "5a95b665-510e-848c-c178-e0356b48940a";PortNumber = Some 1;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"}];X = 627;Y = 205}; + {H=50;W=40; Id = "74dcc790-927f-ae61-fd63-577c3387de0e";Type = MergeWires;Label = "";InputPorts = [{Id = "f4b2f416-0af3-8345-185a-d01b69fdda46";PortNumber = Some 0;PortType = PortType.Input;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"}; {Id = "edd76daa-336d-7c68-8d94-7bbe30539724";PortNumber = Some 1;PortType = PortType.Input;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"}];OutputPorts = [{Id = "6e7f6dfb-770b-1451-a569-1d20cc0785b6";PortNumber = Some 0;PortType = PortType.Output;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"}];X = 235;Y = 205}; + {H=50;W=40; Id = "94efe8d3-413b-9390-b627-be7bc91ae2d1";Type = MergeWires;Label = "";InputPorts = [{Id = "4a1da488-0834-1835-9649-6f4d5c172579";PortNumber = Some 0;PortType = PortType.Input;HostId = "94efe8d3-413b-9390-b627-be7bc91ae2d1"}; {Id = "4f58042b-383e-7557-fa72-8b149ba177a2";PortNumber = Some 1;PortType = PortType.Input;HostId = "94efe8d3-413b-9390-b627-be7bc91ae2d1"}];OutputPorts = [{Id = "3fbb97a2-aab1-b94d-c4cf-d52f8421f3b8";PortNumber = Some 0;PortType = PortType.Output;HostId = "94efe8d3-413b-9390-b627-be7bc91ae2d1"}];X = 299;Y = 195}; + {H=50;W=40; Id = "76de964a-124b-5c16-6de1-6158626344ac";Type = Input 1;Label = "a";InputPorts = [];OutputPorts = [{Id = "9dc8cfaa-c989-276a-6703-11196c5c7974";PortNumber = Some 0;PortType = PortType.Output;HostId = "76de964a-124b-5c16-6de1-6158626344ac"}];X = 110;Y = 111}; + {H=50;W=40; Id = "a91be585-2d3b-d872-be0f-b416c8eb03d2";Type = Input 1;Label = "b";InputPorts = [];OutputPorts = [{Id = "7a9bee0a-7ecc-13b6-ed3e-942f32d3c5fb";PortNumber = Some 0;PortType = PortType.Output;HostId = "a91be585-2d3b-d872-be0f-b416c8eb03d2"}];X = 110;Y = 175}; + {H=50;W=40; Id = "9985ebc6-1cd5-8863-1341-1d543d236d38";Type = Input 1;Label = "c";InputPorts = [];OutputPorts = [{Id = "3d87edd9-9572-df33-f8f8-9b77fbdd6bc5";PortNumber = Some 0;PortType = PortType.Output;HostId = "9985ebc6-1cd5-8863-1341-1d543d236d38"}];X = 110;Y = 245}; + {H=50;W=40; Id = "9824ceb8-e999-8e48-9a56-7a4349e495b1";Type = Input 1;Label = "d";InputPorts = [];OutputPorts = [{Id = "712999dd-e970-51b3-f38f-aee70ff42d2d";PortNumber = Some 0;PortType = PortType.Output;HostId = "9824ceb8-e999-8e48-9a56-7a4349e495b1"}];X = 110;Y = 326}; + {H=50;W=40; Id = "c16668ed-ec17-3a14-8a4b-dec6c40335b5";Type = MergeWires;Label = "";InputPorts = [{Id = "38d99b30-a219-c37e-df55-04b7240a599e";PortNumber = Some 0;PortType = PortType.Input;HostId = "c16668ed-ec17-3a14-8a4b-dec6c40335b5"}; {Id = "2f0c6067-124f-233b-1077-db88900c31cc";PortNumber = Some 1;PortType = PortType.Input;HostId = "c16668ed-ec17-3a14-8a4b-dec6c40335b5"}];OutputPorts = [{Id = "6c5a63af-db72-1ece-495d-7a04c88fd1f0";PortNumber = Some 0;PortType = PortType.Output;HostId = "c16668ed-ec17-3a14-8a4b-dec6c40335b5"}];X = 364;Y = 205}; + {H=50;W=40; Id = "59b45f9c-192c-98ce-da25-a94db45a5790";Type = Output 1;Label = "a-out";InputPorts = [{Id = "e62e040a-bcd2-58f6-39d5-24548811b784";PortNumber = Some 0;PortType = PortType.Input;HostId = "59b45f9c-192c-98ce-da25-a94db45a5790"}];OutputPorts = [];X = 746;Y = 111}; + {H=50;W=40; Id = "8a9392fc-493b-7e96-72ec-b6f5f11ded8a";Type = Output 1;Label = "b-out";InputPorts = [{Id = "ee1bc94e-a726-8868-f25a-25b5fc44b60a";PortNumber = Some 0;PortType = PortType.Input;HostId = "8a9392fc-493b-7e96-72ec-b6f5f11ded8a"}];OutputPorts = [];X = 743;Y = 174}; + {H=50;W=40; Id = "dfcf6cff-fbac-e54f-7a9d-7059d17e3a0b";Type = Output 1;Label = "c-out";InputPorts = [{Id = "a0194620-020c-8897-0207-9d7e9ee2a538";PortNumber = Some 0;PortType = PortType.Input;HostId = "dfcf6cff-fbac-e54f-7a9d-7059d17e3a0b"}];OutputPorts = [];X = 743;Y = 230}; + {H=50;W=40; Id = "214620f0-51f6-59fe-1558-ed47fd2c680a";Type = Output 1;Label = "d-out";InputPorts = [{Id = "b6e25648-a9a1-9c9c-935d-5f50a26c6c2b";PortNumber = Some 0;PortType = PortType.Input;HostId = "214620f0-51f6-59fe-1558-ed47fd2c680a"}];OutputPorts = [];X = 743;Y = 315}; + {H=50;W=40; Id = "a3b6ec22-f265-2ec6-fad0-a4259ec4b3cf";Type = SplitWire 1;Label = "";InputPorts = [{Id = "2a6d1069-81da-f185-ad82-3c524819f56a";PortNumber = Some 0;PortType = PortType.Input;HostId = "a3b6ec22-f265-2ec6-fad0-a4259ec4b3cf"}];OutputPorts = [{Id = "f72513fe-f696-dbae-133b-6c864c7075a2";PortNumber = Some 0;PortType = PortType.Output;HostId = "a3b6ec22-f265-2ec6-fad0-a4259ec4b3cf"}; {Id = "8333c9b0-911e-aab3-b7fd-026d97b4a412";PortNumber = Some 1;PortType = PortType.Output;HostId = "a3b6ec22-f265-2ec6-fad0-a4259ec4b3cf"}];X = 546;Y = 195}; + {H=50;W=40; Id = "156b43f1-5e54-b058-c716-c5623c5f6e37";Type = SplitWire 3;Label = "";InputPorts = [{Id = "67424fbf-f200-6690-a8e6-450e951d9411";PortNumber = Some 0;PortType = PortType.Input;HostId = "156b43f1-5e54-b058-c716-c5623c5f6e37"}];OutputPorts = [{Id = "58405846-6427-732c-c901-f72f1162b36e";PortNumber = Some 0;PortType = PortType.Output;HostId = "156b43f1-5e54-b058-c716-c5623c5f6e37"}; {Id = "d40a1df5-6b29-5b4d-486f-925a2d16a615";PortNumber = Some 1;PortType = PortType.Output;HostId = "156b43f1-5e54-b058-c716-c5623c5f6e37"}];X = 442;Y = 205} + ], + [ + {Id = "5a9d111c-acec-3973-01ea-d0590e547b89";Source = {Id = "d40a1df5-6b29-5b4d-486f-925a2d16a615";PortNumber = None;PortType = PortType.Output;HostId = "156b43f1-5e54-b058-c716-c5623c5f6e37"};Target = {Id = "b6e25648-a9a1-9c9c-935d-5f50a26c6c2b";PortNumber = None;PortType = PortType.Input;HostId = "214620f0-51f6-59fe-1558-ed47fd2c680a"};Vertices = [482.0,225.0; 510.5,225.0; 510.5,325.0; 743.0,325.0]}; + {Id = "8f3205ca-5911-5a36-68da-4e8ca384c4a2";Source = {Id = "f72513fe-f696-dbae-133b-6c864c7075a2";PortNumber = None;PortType = PortType.Output;HostId = "a3b6ec22-f265-2ec6-fad0-a4259ec4b3cf"};Target = {Id = "e62e040a-bcd2-58f6-39d5-24548811b784";PortNumber = None;PortType = PortType.Input;HostId = "59b45f9c-192c-98ce-da25-a94db45a5790"};Vertices = [586.0,195.0; 666.0,195.0; 666.0,121.0; 746.0,121.0]}; + {Id = "1287faef-e07d-cca5-83c7-3aa3b1265cd8";Source = {Id = "3d87edd9-9572-df33-f8f8-9b77fbdd6bc5";PortNumber = None;PortType = PortType.Output;HostId = "9985ebc6-1cd5-8863-1341-1d543d236d38"};Target = {Id = "edd76daa-336d-7c68-8d94-7bbe30539724";PortNumber = None;PortType = PortType.Input;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"};Vertices = [140.0,255.0; 187.5,255.0; 187.5,225.0; 235.0,225.0]}; + {Id = "cfaa960d-99c2-0f40-4ac7-335f6a238e2b";Source = {Id = "7a9bee0a-7ecc-13b6-ed3e-942f32d3c5fb";PortNumber = None;PortType = PortType.Output;HostId = "a91be585-2d3b-d872-be0f-b416c8eb03d2"};Target = {Id = "f4b2f416-0af3-8345-185a-d01b69fdda46";PortNumber = None;PortType = PortType.Input;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"};Vertices = [140.0,185.0; 187.5,185.0; 187.5,205.0; 235.0,205.0]}; + {Id = "56e8c89b-bcbf-e674-a49d-72d06c20a563";Source = {Id = "712999dd-e970-51b3-f38f-aee70ff42d2d";PortNumber = None;PortType = PortType.Output;HostId = "9824ceb8-e999-8e48-9a56-7a4349e495b1"};Target = {Id = "2f0c6067-124f-233b-1077-db88900c31cc";PortNumber = None;PortType = PortType.Input;HostId = "c16668ed-ec17-3a14-8a4b-dec6c40335b5"};Vertices = [140.0,336.0; 344.0,336.0; 344.0,225.0; 364.0,225.0]}; + {Id = "221f1ae2-9beb-5099-bc4c-a3f6c86214d4";Source = {Id = "6df8212b-0639-3d53-61cd-297e74d6bbad";PortNumber = None;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"};Target = {Id = "ee1bc94e-a726-8868-f25a-25b5fc44b60a";PortNumber = None;PortType = PortType.Input;HostId = "8a9392fc-493b-7e96-72ec-b6f5f11ded8a"};Vertices = [667.0,205.0; 723.0,205.0; 723.0,184.0; 743.0,184.0]}; + {Id = "78ceafbf-cfb8-4442-a6bb-62ed6a1893cd";Source = {Id = "5a95b665-510e-848c-c178-e0356b48940a";PortNumber = None;PortType = PortType.Output;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"};Target = {Id = "a0194620-020c-8897-0207-9d7e9ee2a538";PortNumber = None;PortType = PortType.Input;HostId = "dfcf6cff-fbac-e54f-7a9d-7059d17e3a0b"};Vertices = [667.0,225.0; 703.5,225.0; 703.5,240.0; 743.0,240.0]}; + {Id = "edc53e8b-8c1e-340f-aaec-7eecf337a9a8";Source = {Id = "9dc8cfaa-c989-276a-6703-11196c5c7974";PortNumber = None;PortType = PortType.Output;HostId = "76de964a-124b-5c16-6de1-6158626344ac"};Target = {Id = "4a1da488-0834-1835-9649-6f4d5c172579";PortNumber = None;PortType = PortType.Input;HostId = "94efe8d3-413b-9390-b627-be7bc91ae2d1"};Vertices = [140.0,121.0; 279.5,121.0; 279.5,195.0; 299.5,195.0]}; + {Id = "3fd09a23-18c1-0edd-b7cb-a70a4b8d42ef";Source = {Id = "6e7f6dfb-770b-1451-a569-1d20cc0785b6";PortNumber = None;PortType = PortType.Output;HostId = "74dcc790-927f-ae61-fd63-577c3387de0e"};Target = {Id = "4f58042b-383e-7557-fa72-8b149ba177a2";PortNumber = None;PortType = PortType.Input;HostId = "94efe8d3-413b-9390-b627-be7bc91ae2d1"};Vertices = [275.0,215.0; 299.5,215.0]}; + {Id = "7aaafe2c-9648-bb9d-95cb-7ed8c8309150";Source = {Id = "3fbb97a2-aab1-b94d-c4cf-d52f8421f3b8";PortNumber = None;PortType = PortType.Output;HostId = "94efe8d3-413b-9390-b627-be7bc91ae2d1"};Target = {Id = "38d99b30-a219-c37e-df55-04b7240a599e";PortNumber = None;PortType = PortType.Input;HostId = "c16668ed-ec17-3a14-8a4b-dec6c40335b5"};Vertices = [339.5,205.0; 364.0,205.0]}; + {Id = "4852ec1c-5960-6696-b8c1-650b9517cb56";Source = {Id = "8333c9b0-911e-aab3-b7fd-026d97b4a412";PortNumber = None;PortType = PortType.Output;HostId = "a3b6ec22-f265-2ec6-fad0-a4259ec4b3cf"};Target = {Id = "2332109c-b48a-be65-70fd-662fc00cd0c7";PortNumber = None;PortType = PortType.Input;HostId = "772307ab-2941-3343-28a2-faacaa0efc96"};Vertices = [586.0,215.0; 627.0,215.0]}; + {Id = "960e38bd-dd14-5109-ac25-8c701249f48b";Source = {Id = "6c5a63af-db72-1ece-495d-7a04c88fd1f0";PortNumber = None;PortType = PortType.Output;HostId = "c16668ed-ec17-3a14-8a4b-dec6c40335b5"};Target = {Id = "67424fbf-f200-6690-a8e6-450e951d9411";PortNumber = None;PortType = PortType.Input;HostId = "156b43f1-5e54-b058-c716-c5623c5f6e37"};Vertices = [404.0,215.0; 442.0,215.0]}; + {Id = "6d0843df-f606-4fb5-0349-ae90260e6c28";Source = {Id = "58405846-6427-732c-c901-f72f1162b36e";PortNumber = None;PortType = PortType.Output;HostId = "156b43f1-5e54-b058-c716-c5623c5f6e37"};Target = {Id = "2a6d1069-81da-f185-ad82-3c524819f56a";PortNumber = None;PortType = PortType.Input;HostId = "a3b6ec22-f265-2ec6-fad0-a4259ec4b3cf"};Vertices = [482.0,205.0; 546.0,205.0]} + ] + +/// A 4 bit input connected to a 4 bit output. +let stateBus13 : CanvasState = + [ + {H=50;W=40; Id = "9bcba47e-deae-0b3f-2079-a1b124526b00";Type = Input 4;Label = "a";InputPorts = [];OutputPorts = [{Id = "f9f6284f-1663-ec81-5c5c-0a6660d1d524";PortNumber = Some 0;PortType = PortType.Output;HostId = "9bcba47e-deae-0b3f-2079-a1b124526b00"}];X = 100;Y = 100}; + {H=50;W=40; Id = "ad2ef0c3-537e-9d2e-0064-ac6b952e4b97";Type = Output 4;Label = "b";InputPorts = [{Id = "ba682a02-30db-a03f-db83-8f3ab1afc6e0";PortNumber = Some 0;PortType = PortType.Input;HostId = "ad2ef0c3-537e-9d2e-0064-ac6b952e4b97"}];OutputPorts = [];X = 193;Y = 100} + ], + [ + {Id = "conn";Source = {Id = "f9f6284f-1663-ec81-5c5c-0a6660d1d524";PortNumber = None;PortType = PortType.Output;HostId = "9bcba47e-deae-0b3f-2079-a1b124526b00"};Target = {Id = "ba682a02-30db-a03f-db83-8f3ab1afc6e0";PortNumber = None;PortType = PortType.Input;HostId = "ad2ef0c3-537e-9d2e-0064-ac6b952e4b97"};Vertices = [130.0,110.0; 193.0,110.0]} + ] + +/// A 4 bit input connected to a 3 bit output. +let stateBus14 : CanvasState = + [ + {H=50;W=40; Id = "9bcba47e-deae-0b3f-2079-a1b124526b00";Type = Input 4;Label = "a";InputPorts = [];OutputPorts = [{Id = "f9f6284f-1663-ec81-5c5c-0a6660d1d524";PortNumber = Some 0;PortType = PortType.Output;HostId = "9bcba47e-deae-0b3f-2079-a1b124526b00"}];X = 100;Y = 100}; + {H=50;W=40; Id = "ad2ef0c3-537e-9d2e-0064-ac6b952e4b97";Type = Output 3;Label = "b";InputPorts = [{Id = "ba682a02-30db-a03f-db83-8f3ab1afc6e0";PortNumber = Some 0;PortType = PortType.Input;HostId = "ad2ef0c3-537e-9d2e-0064-ac6b952e4b97"}];OutputPorts = [];X = 193;Y = 100} + ], + [ + {Id = "conn";Source = {Id = "f9f6284f-1663-ec81-5c5c-0a6660d1d524";PortNumber = None;PortType = PortType.Output;HostId = "9bcba47e-deae-0b3f-2079-a1b124526b00"};Target = {Id = "ba682a02-30db-a03f-db83-8f3ab1afc6e0";PortNumber = None;PortType = PortType.Input;HostId = "ad2ef0c3-537e-9d2e-0064-ac6b952e4b97"};Vertices = [130.0,110.0; 193.0,110.0]} + ] + +/// A 3 bit input connected to a 4 bit output. +let stateBus15 : CanvasState = + [ + {H=50;W=40; Id = "9bcba47e-deae-0b3f-2079-a1b124526b00";Type = Input 3;Label = "a";InputPorts = [];OutputPorts = [{Id = "f9f6284f-1663-ec81-5c5c-0a6660d1d524";PortNumber = Some 0;PortType = PortType.Output;HostId = "9bcba47e-deae-0b3f-2079-a1b124526b00"}];X = 100;Y = 100}; + {H=50;W=40; Id = "ad2ef0c3-537e-9d2e-0064-ac6b952e4b97";Type = Output 4;Label = "b";InputPorts = [{Id = "ba682a02-30db-a03f-db83-8f3ab1afc6e0";PortNumber = Some 0;PortType = PortType.Input;HostId = "ad2ef0c3-537e-9d2e-0064-ac6b952e4b97"}];OutputPorts = [];X = 193;Y = 100} + ], + [ + {Id = "conn";Source = {Id = "f9f6284f-1663-ec81-5c5c-0a6660d1d524";PortNumber = None;PortType = PortType.Output;HostId = "9bcba47e-deae-0b3f-2079-a1b124526b00"};Target = {Id = "ba682a02-30db-a03f-db83-8f3ab1afc6e0";PortNumber = None;PortType = PortType.Input;HostId = "ad2ef0c3-537e-9d2e-0064-ac6b952e4b97"};Vertices = [130.0,110.0; 193.0,110.0]} + ] + +/// A 2 bit input split into 2 single bit outputs. +let stateBus16 : CanvasState = + [ + {H=50;W=40; Id = "96b167b2-2c40-34e7-d4fc-4a7016c7ddf5";Type = SplitWire 1;Label = "";InputPorts = [{Id = "a5977d59-b944-6651-bf91-3f3700bca60b";PortNumber = Some 0;PortType = PortType.Input;HostId = "96b167b2-2c40-34e7-d4fc-4a7016c7ddf5"}];OutputPorts = [{Id = "de1e9d70-4ce1-c6d9-cb87-30f632c9e1d1";PortNumber = Some 0;PortType = PortType.Output;HostId = "96b167b2-2c40-34e7-d4fc-4a7016c7ddf5"}; {Id = "dc05cdf8-5ef7-c605-6c5b-bb8842c49089";PortNumber = Some 1;PortType = PortType.Output;HostId = "96b167b2-2c40-34e7-d4fc-4a7016c7ddf5"}];X = 202;Y = 112}; + {H=50;W=40; Id = "c6f000db-310f-d8ad-ff5e-938d7c2aaa7c";Type = Input 2;Label = "a";InputPorts = [];OutputPorts = [{Id = "28047c34-2af2-867e-9130-6eb128769eef";PortNumber = Some 0;PortType = PortType.Output;HostId = "c6f000db-310f-d8ad-ff5e-938d7c2aaa7c"}];X = 102;Y = 112}; + {H=50;W=40; Id = "60e2df66-bb8c-53f1-832d-e154c30cf9dd";Type = Output 1;Label = "b";InputPorts = [{Id = "24e75289-91d1-30e7-0ec5-409eb73f9ad3";PortNumber = Some 0;PortType = PortType.Input;HostId = "60e2df66-bb8c-53f1-832d-e154c30cf9dd"}];OutputPorts = [];X = 324;Y = 88}; + {H=50;W=40; Id = "85e19389-c087-8b30-6c0a-02f7cc753695";Type = Output 1;Label = "c";InputPorts = [{Id = "99c1d8ae-5e85-fbbf-892d-48acb0fdff82";PortNumber = Some 0;PortType = PortType.Input;HostId = "85e19389-c087-8b30-6c0a-02f7cc753695"}];OutputPorts = [];X = 324;Y = 152} + ], + [ + {Id = "conn0";Source = {Id = "28047c34-2af2-867e-9130-6eb128769eef";PortNumber = None;PortType = PortType.Output;HostId = "c6f000db-310f-d8ad-ff5e-938d7c2aaa7c"};Target = {Id = "a5977d59-b944-6651-bf91-3f3700bca60b";PortNumber = None;PortType = PortType.Input;HostId = "96b167b2-2c40-34e7-d4fc-4a7016c7ddf5"};Vertices = [132.0,122.0; 202.0,122.0]}; + {Id = "conn1";Source = {Id = "dc05cdf8-5ef7-c605-6c5b-bb8842c49089";PortNumber = None;PortType = PortType.Output;HostId = "96b167b2-2c40-34e7-d4fc-4a7016c7ddf5"};Target = {Id = "99c1d8ae-5e85-fbbf-892d-48acb0fdff82";PortNumber = None;PortType = PortType.Input;HostId = "85e19389-c087-8b30-6c0a-02f7cc753695"};Vertices = [242.0,132.0; 283.0,132.0; 283.0,162.0; 324.0,162.0]}; + {Id = "conn2";Source = {Id = "de1e9d70-4ce1-c6d9-cb87-30f632c9e1d1";PortNumber = None;PortType = PortType.Output;HostId = "96b167b2-2c40-34e7-d4fc-4a7016c7ddf5"};Target = {Id = "24e75289-91d1-30e7-0ec5-409eb73f9ad3";PortNumber = None;PortType = PortType.Input;HostId = "60e2df66-bb8c-53f1-832d-e154c30cf9dd"};Vertices = [242.0,112.0; 283.0,112.0; 283.0,98.0; 324.0,98.0]} + ] + +/// 3 bit input merged with 4 bit input, then split in the same way. +let stateBus17 : CanvasState = + [ + {H=50;W=40; Id = "6bcdc74a-9d71-3304-537d-1a17f02924eb";Type = Input 3;Label = "in3";InputPorts = [];OutputPorts = [{Id = "9e8b16ba-d450-c228-e64c-d5323cd4ca0a";PortNumber = Some 0;PortType = PortType.Output;HostId = "6bcdc74a-9d71-3304-537d-1a17f02924eb"}];X = 100;Y = 100}; + {H=50;W=40; Id = "97c4b56d-4f8c-2b00-fb61-a08cdd01dd76";Type = Input 4;Label = "in4";InputPorts = [];OutputPorts = [{Id = "2cf62d71-2b34-ab11-9007-19409fe13b77";PortNumber = Some 0;PortType = PortType.Output;HostId = "97c4b56d-4f8c-2b00-fb61-a08cdd01dd76"}];X = 100;Y = 183}; + {H=50;W=40; Id = "71d66801-50d5-4316-eb79-9e99a43cdfe4";Type = MergeWires;Label = "";InputPorts = [{Id = "6714352e-6a15-a388-3f3f-27c7cb0e6fc7";PortNumber = Some 0;PortType = PortType.Input;HostId = "71d66801-50d5-4316-eb79-9e99a43cdfe4"}; {Id = "32c34b03-b0f0-16f5-345a-fca3626f16c3";PortNumber = Some 1;PortType = PortType.Input;HostId = "71d66801-50d5-4316-eb79-9e99a43cdfe4"}];OutputPorts = [{Id = "85cc42dd-5ea8-0f62-a421-74d844f4de83";PortNumber = Some 0;PortType = PortType.Output;HostId = "71d66801-50d5-4316-eb79-9e99a43cdfe4"}];X = 190;Y = 138}; + {H=50;W=40; Id = "1a6e1bb4-cfe0-77f9-a207-f409168ef210";Type = Output 3;Label = "out3";InputPorts = [{Id = "ca111545-dbcd-e812-b81d-af6e51769f0e";PortNumber = Some 0;PortType = PortType.Input;HostId = "1a6e1bb4-cfe0-77f9-a207-f409168ef210"}];OutputPorts = [];X = 375;Y = 89}; + {H=50;W=40; Id = "d2676492-2302-24d9-52eb-6e69e7971339";Type = Output 4;Label = "out4";InputPorts = [{Id = "819cf4ff-57a7-4743-075b-0c07a983a866";PortNumber = Some 0;PortType = PortType.Input;HostId = "d2676492-2302-24d9-52eb-6e69e7971339"}];OutputPorts = [];X = 369;Y = 216}; + {H=50;W=40; Id = "bb51f8c6-2c82-5206-eb25-492e15849e81";Type = SplitWire 3;Label = "";InputPorts = [{Id = "4a440c75-75c5-1a5c-93d9-97ca3993683f";PortNumber = Some 0;PortType = PortType.Input;HostId = "bb51f8c6-2c82-5206-eb25-492e15849e81"}];OutputPorts = [{Id = "68ca1398-18c8-cea1-c6c2-61393fb33e08";PortNumber = Some 0;PortType = PortType.Output;HostId = "bb51f8c6-2c82-5206-eb25-492e15849e81"}; {Id = "be6c9827-eba7-6c19-ca75-7fcb1ac30dc9";PortNumber = Some 1;PortType = PortType.Output;HostId = "bb51f8c6-2c82-5206-eb25-492e15849e81"}];X = 254;Y = 138} + ], + [ + {Id = "9df32195-00b4-9795-3dc1-78fb70d453f2";Source = {Id = "68ca1398-18c8-cea1-c6c2-61393fb33e08";PortNumber = None;PortType = PortType.Output;HostId = "bb51f8c6-2c82-5206-eb25-492e15849e81"};Target = {Id = "ca111545-dbcd-e812-b81d-af6e51769f0e";PortNumber = None;PortType = PortType.Input;HostId = "1a6e1bb4-cfe0-77f9-a207-f409168ef210"};Vertices = [294.0,138.0; 334.5,138.0; 334.5,99.0; 375.0,99.0]}; + {Id = "82cc4ce9-7b15-40ac-0226-98a7f8e2fb9a";Source = {Id = "be6c9827-eba7-6c19-ca75-7fcb1ac30dc9";PortNumber = None;PortType = PortType.Output;HostId = "bb51f8c6-2c82-5206-eb25-492e15849e81"};Target = {Id = "819cf4ff-57a7-4743-075b-0c07a983a866";PortNumber = None;PortType = PortType.Input;HostId = "d2676492-2302-24d9-52eb-6e69e7971339"};Vertices = [294.0,158.0; 331.5,158.0; 331.5,226.0; 369.0,226.0]}; + {Id = "cd13c70f-6037-0cf4-1295-5795e92d745c";Source = {Id = "9e8b16ba-d450-c228-e64c-d5323cd4ca0a";PortNumber = None;PortType = PortType.Output;HostId = "6bcdc74a-9d71-3304-537d-1a17f02924eb"};Target = {Id = "6714352e-6a15-a388-3f3f-27c7cb0e6fc7";PortNumber = None;PortType = PortType.Input;HostId = "71d66801-50d5-4316-eb79-9e99a43cdfe4"};Vertices = [130.0,110.0; 160.0,110.0; 160.0,138.0; 190.0,138.0]}; + {Id = "7438de0c-bbaf-c1f6-0307-42ece66c6c00";Source = {Id = "2cf62d71-2b34-ab11-9007-19409fe13b77";PortNumber = None;PortType = PortType.Output;HostId = "97c4b56d-4f8c-2b00-fb61-a08cdd01dd76"};Target = {Id = "32c34b03-b0f0-16f5-345a-fca3626f16c3";PortNumber = None;PortType = PortType.Input;HostId = "71d66801-50d5-4316-eb79-9e99a43cdfe4"};Vertices = [130.0,193.0; 160.0,193.0; 160.0,158.0; 190.0,158.0]}; + {Id = "678ffa07-0ed7-7b6f-ba9b-b14839c08a71";Source = {Id = "85cc42dd-5ea8-0f62-a421-74d844f4de83";PortNumber = None;PortType = PortType.Output;HostId = "71d66801-50d5-4316-eb79-9e99a43cdfe4"};Target = {Id = "4a440c75-75c5-1a5c-93d9-97ca3993683f";PortNumber = None;PortType = PortType.Input;HostId = "bb51f8c6-2c82-5206-eb25-492e15849e81"};Vertices = [230.0,148.0; 254.0,148.0]} +] + +/// Partially connected Mux2. Top input (2 bits), select (1 bit) anc connection +/// to output (2 bits). +let stateBus18 : CanvasState = + [ + {H=50;W=40; Id = "8078a917-236f-5a40-18a6-8e2d6a1458f5";Type = Input 2;Label = "a";InputPorts = [];OutputPorts = [{Id = "cc7c6510-d49b-28d9-e0bc-d5350a2c76a8";PortNumber = Some 0;PortType = PortType.Output;HostId = "8078a917-236f-5a40-18a6-8e2d6a1458f5"}];X = 122;Y = 125}; + {H=50;W=40; Id = "ed12b5d8-556b-515a-cc9d-873960690380";Type = Input 1;Label = "b";InputPorts = [];OutputPorts = [{Id = "a6010bcb-ba2b-e57f-ca50-39f3d094e3b8";PortNumber = Some 0;PortType = PortType.Output;HostId = "ed12b5d8-556b-515a-cc9d-873960690380"}];X = 122;Y = 204}; + {H=50;W=40; Id = "d7028a8f-83be-0d81-6f0f-19b384caddae";Type = Mux2;Label = "";InputPorts = [{Id = "108ea909-b27f-24ba-22ea-2faeb061a926";PortNumber = Some 0;PortType = PortType.Input;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"}; {Id = "38c8c934-d55e-2aff-e61b-5fbf7d7eed91";PortNumber = Some 1;PortType = PortType.Input;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"}; {Id = "f283db84-a1f0-d006-be39-f17be6f8490c";PortNumber = Some 2;PortType = PortType.Input;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"}];OutputPorts = [{Id = "5b651087-9b95-3a80-4f99-014f85f0dfdd";PortNumber = Some 0;PortType = PortType.Output;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"}];X = 244;Y = 156}; + {H=50;W=40; Id = "00661085-7d05-4185-09ef-4138ac918ad2";Type = Output 2;Label = "aa";InputPorts = [{Id = "7bbfa7d3-4718-e6fe-e7e9-8c00e5257f45";PortNumber = Some 0;PortType = PortType.Input;HostId = "00661085-7d05-4185-09ef-4138ac918ad2"}];OutputPorts = [];X = 373;Y = 171} + ], + [ + {Id = "conn-sel";Source = {Id = "a6010bcb-ba2b-e57f-ca50-39f3d094e3b8";PortNumber = None;PortType = PortType.Output;HostId = "ed12b5d8-556b-515a-cc9d-873960690380"};Target = {Id = "f283db84-a1f0-d006-be39-f17be6f8490c";PortNumber = None;PortType = PortType.Input;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"};Vertices = [152.0,214.0; 259.0,214.0; 259.0,201.0]}; + {Id = "conn-top-input";Source = {Id = "cc7c6510-d49b-28d9-e0bc-d5350a2c76a8";PortNumber = None;PortType = PortType.Output;HostId = "8078a917-236f-5a40-18a6-8e2d6a1458f5"};Target = {Id = "108ea909-b27f-24ba-22ea-2faeb061a926";PortNumber = None;PortType = PortType.Input;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"};Vertices = [152.0,135.0; 198.0,135.0; 198.0,172.0; 244.0,172.6]}; + {Id = "conn-to-output";Source = {Id = "5b651087-9b95-3a80-4f99-014f85f0dfdd";PortNumber = None;PortType = PortType.Output;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"};Target = {Id = "7bbfa7d3-4718-e6fe-e7e9-8c00e5257f45";PortNumber = None;PortType = PortType.Input;HostId = "00661085-7d05-4185-09ef-4138ac918ad2"};Vertices = [274.0,181.0; 373.0,181.0]} + ] + +/// Fully connected Mux, but two inputs have different widths. Similar to +/// stateBus18. +let stateBus19 : CanvasState = + [ + {H=50;W=40; Id = "8078a917-236f-5a40-18a6-8e2d6a1458f5";Type = Input 2;Label = "a";InputPorts = [];OutputPorts = [{Id = "cc7c6510-d49b-28d9-e0bc-d5350a2c76a8";PortNumber = Some 0;PortType = PortType.Output;HostId = "8078a917-236f-5a40-18a6-8e2d6a1458f5"}];X = 122;Y = 125}; + {H=50;W=40; Id = "ed12b5d8-556b-515a-cc9d-873960690380";Type = Input 1;Label = "b";InputPorts = [];OutputPorts = [{Id = "a6010bcb-ba2b-e57f-ca50-39f3d094e3b8";PortNumber = Some 0;PortType = PortType.Output;HostId = "ed12b5d8-556b-515a-cc9d-873960690380"}];X = 122;Y = 204}; + {H=50;W=40; Id = "d7028a8f-83be-0d81-6f0f-19b384caddae";Type = Mux2;Label = "";InputPorts = [{Id = "108ea909-b27f-24ba-22ea-2faeb061a926";PortNumber = Some 0;PortType = PortType.Input;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"}; {Id = "38c8c934-d55e-2aff-e61b-5fbf7d7eed91";PortNumber = Some 1;PortType = PortType.Input;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"}; {Id = "f283db84-a1f0-d006-be39-f17be6f8490c";PortNumber = Some 2;PortType = PortType.Input;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"}];OutputPorts = [{Id = "5b651087-9b95-3a80-4f99-014f85f0dfdd";PortNumber = Some 0;PortType = PortType.Output;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"}];X = 244;Y = 156}; + {H=50;W=40; Id = "00661085-7d05-4185-09ef-4138ac918ad2";Type = Output 2;Label = "aa";InputPorts = [{Id = "7bbfa7d3-4718-e6fe-e7e9-8c00e5257f45";PortNumber = Some 0;PortType = PortType.Input;HostId = "00661085-7d05-4185-09ef-4138ac918ad2"}];OutputPorts = [];X = 373;Y = 171} + ], + [ + {Id = "conn-sel";Source = {Id = "a6010bcb-ba2b-e57f-ca50-39f3d094e3b8";PortNumber = None;PortType = PortType.Output;HostId = "ed12b5d8-556b-515a-cc9d-873960690380"};Target = {Id = "f283db84-a1f0-d006-be39-f17be6f8490c";PortNumber = None;PortType = PortType.Input;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"};Vertices = [152.0,214.0; 259.0,214.0; 259.0,201.0]}; + {Id = "conn-top-input";Source = {Id = "cc7c6510-d49b-28d9-e0bc-d5350a2c76a8";PortNumber = None;PortType = PortType.Output;HostId = "8078a917-236f-5a40-18a6-8e2d6a1458f5"};Target = {Id = "108ea909-b27f-24ba-22ea-2faeb061a926";PortNumber = None;PortType = PortType.Input;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"};Vertices = [152.0,135.0; 198.0,135.0; 198.0,172.0; 244.0,172.6]}; + {Id = "conn-to-output";Source = {Id = "5b651087-9b95-3a80-4f99-014f85f0dfdd";PortNumber = None;PortType = PortType.Output;HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"};Target = {Id = "7bbfa7d3-4718-e6fe-e7e9-8c00e5257f45";PortNumber = None;PortType = PortType.Input;HostId = "00661085-7d05-4185-09ef-4138ac918ad2"};Vertices = [274.0,181.0; 373.0,181.0]} + {Id = "conn-bottom-input"; Source = {Id = "a6010bcb-ba2b-e57f-ca50-39f3d094e3b8"; PortNumber = None; PortType = PortType.Output; HostId = "ed12b5d8-556b-515a-cc9d-873960690380"}; Target = {Id = "38c8c934-d55e-2aff-e61b-5fbf7d7eed91"; PortNumber = None; PortType = PortType.Input; HostId = "d7028a8f-83be-0d81-6f0f-19b384caddae"}; Vertices = [152.0,258.0; 198.0,258.0; 198.0,189.33333333333334; 244.0,189.33333333333334]} + ] + +/// Partially connected Demux. A 2-bit input, Mux, a 2-bit output. +let stateBus20 : CanvasState = + [ + {H=50;W=40; Id = "8078a917-236f-5a40-18a6-8e2d6a1458f5";Type = Input 2;Label = "a";InputPorts = [];OutputPorts = [{Id = "cc7c6510-d49b-28d9-e0bc-d5350a2c76a8";PortNumber = Some 0;PortType = PortType.Output;HostId = "8078a917-236f-5a40-18a6-8e2d6a1458f5"}];X = 122;Y = 125}; + {H=50;W=40; Id = "fbfb4202-9816-f214-0401-da18caddeb0f";Type = Demux2;Label = "";InputPorts = [{Id = "2b224026-609a-5eae-6885-ff9820dbae5f";PortNumber = Some 0;PortType = PortType.Input;HostId = "fbfb4202-9816-f214-0401-da18caddeb0f"}; {Id = "68043f9b-47e7-793f-fed2-943a7d7336dc";PortNumber = Some 1;PortType = PortType.Input;HostId = "fbfb4202-9816-f214-0401-da18caddeb0f"}];OutputPorts = [{Id = "57070484-347e-4701-8c36-f510c2ef150c";PortNumber = Some 0;PortType = PortType.Output;HostId = "fbfb4202-9816-f214-0401-da18caddeb0f"}; {Id = "123463bf-7868-9a87-6fb1-36627a3c9bad";PortNumber = Some 1;PortType = PortType.Output;HostId = "fbfb4202-9816-f214-0401-da18caddeb0f"}];X = 254;Y = 110}; + {H=50;W=40; Id = "00661085-7d05-4185-09ef-4138ac918ad2";Type = Output 2;Label = "aa";InputPorts = [{Id = "7bbfa7d3-4718-e6fe-e7e9-8c00e5257f45";PortNumber = Some 0;PortType = PortType.Input;HostId = "00661085-7d05-4185-09ef-4138ac918ad2"}];OutputPorts = [];X = 401;Y = 117} + ], + [ + {Id = "conn-to-output";Source = {Id = "57070484-347e-4701-8c36-f510c2ef150c";PortNumber = None;PortType = PortType.Output;HostId = "fbfb4202-9816-f214-0401-da18caddeb0f"};Target = {Id = "7bbfa7d3-4718-e6fe-e7e9-8c00e5257f45";PortNumber = None;PortType = PortType.Input;HostId = "00661085-7d05-4185-09ef-4138ac918ad2"};Vertices = [284.0,126.66666666666667; 343.5,126.66666666666667; 343.5,127.0; 401.0,127.0]}; + {Id = "conn-to-input";Source = {Id = "cc7c6510-d49b-28d9-e0bc-d5350a2c76a8";PortNumber = None;PortType = PortType.Output;HostId = "8078a917-236f-5a40-18a6-8e2d6a1458f5"};Target = {Id = "2b224026-609a-5eae-6885-ff9820dbae5f";PortNumber = None;PortType = PortType.Input;HostId = "fbfb4202-9816-f214-0401-da18caddeb0f"};Vertices = [152.0,135.0; 254.0,135.0]} + ] diff --git a/Tests/SimulatorMemoriesTests.fs b/Tests/SimulatorMemoriesTests.fs new file mode 100644 index 0000000..5183b17 --- /dev/null +++ b/Tests/SimulatorMemoriesTests.fs @@ -0,0 +1,101 @@ +module SimulatorMemoriesTests + +open CommonTypes +open SimulatorTypes +open CanvasStatesMemories +open NumberHelpers +open Helpers + +/// Tuple with: (diagramName, state, loadedComponents, number of clock ticks, inputss). +/// Note that the inputss is a list of inputs. I.e. inputss provides an inputs +/// for every time step. The first set of inputs will be fed before the first +/// clock tick, then second after the second clock tick and so on. If no inputs +/// are provided for a certain iteration, none will fed. +type private TestCaseInput = string * CanvasState * LoadedComponent list * int * ((ComponentId * WireData) list) list +type private IterationOutput = (SimulationIO * WireData) list // Output after every clock tick. +type private TestCaseOutput = Result +type private TestCase = string * TestCaseInput * TestCaseOutput + +let private toWD num w = convertIntToWireData w (int64 num) + +let private makeStateMem3Input addr dataIn write = + [ (ComponentId "81030fc6-2471-a568-160f-922709edeb2e", toWD addr 3) + (ComponentId "266d8763-6fbf-37c2-6825-d3487153053b", toWD dataIn 4) + (ComponentId "f0769200-24e3-5c7b-3591-c5c3711d9336", toWD write 1) ] + +let private makeStateMem3Output dataOut = + [ (ComponentId "1f9704f9-88fc-124c-3ff8-21c36cfb7328", ComponentLabel "data-out", 4), toWD dataOut 4 ] + +let testCasesSimulatorMemories : TestCase list = [ + "Synchronous ROM connected to address and output", + ("main", stateMem1, [], 6, [ + [ (ComponentId "4f65afe9-f03c-2b97-fde9-c657ca32f246", toWD 0 2) ] + [ (ComponentId "4f65afe9-f03c-2b97-fde9-c657ca32f246", toWD 1 2) ] + [ (ComponentId "4f65afe9-f03c-2b97-fde9-c657ca32f246", toWD 2 2) ] + [ (ComponentId "4f65afe9-f03c-2b97-fde9-c657ca32f246", toWD 3 2) ] + ]), + Ok [ + [ (ComponentId "fbb5aa79-a471-ac24-4201-56ae39d537c6", ComponentLabel "data", 4), toWD 0 4 ] // Mem[0] + [ (ComponentId "fbb5aa79-a471-ac24-4201-56ae39d537c6", ComponentLabel "data", 4), toWD 0 4 ] // Mem[0] + [ (ComponentId "fbb5aa79-a471-ac24-4201-56ae39d537c6", ComponentLabel "data", 4), toWD 1 4 ] // Mem[1] + [ (ComponentId "fbb5aa79-a471-ac24-4201-56ae39d537c6", ComponentLabel "data", 4), toWD 4 4 ] // Mem[2] + [ (ComponentId "fbb5aa79-a471-ac24-4201-56ae39d537c6", ComponentLabel "data", 4), toWD 15 4 ] // Mem[3] + [ (ComponentId "fbb5aa79-a471-ac24-4201-56ae39d537c6", ComponentLabel "data", 4), toWD 15 4 ] // Mem[3] + ] + + "Synchronous ROM connected to address and output. ROM is big.", + ("main", stateMem2, [], pow2(8)+1, ( + [0..pow2(8)-1] |> List.map (fun i -> + [ (ComponentId "4f65afe9-f03c-2b97-fde9-c657ca32f246", toWD i 8) ] + ) + )), + Ok ( + [ [ (ComponentId "fbb5aa79-a471-ac24-4201-56ae39d537c6", ComponentLabel "data", 8), toWD 0 8 ] ] // Mem[0] + @ + ( + [0..pow2(8)-1] |> List.map (fun i -> + [ (ComponentId "fbb5aa79-a471-ac24-4201-56ae39d537c6", ComponentLabel "data", 8), toWD i 8 ] + ) + ) + ) + + "RAM only writes if write flag is set", + ("main", stateMem3, [], 10, [ + makeStateMem3Input 0 1 0 + makeStateMem3Input 0 1 0 + makeStateMem3Input 0 1 1 // Turn on write flag. Set to one. + makeStateMem3Input 0 0 1 // Set to zero. + makeStateMem3Input 0 1 1 // Set to one. + makeStateMem3Input 0 0 0 // Turn off write flag. Stays at one. + makeStateMem3Input 0 0 0 + makeStateMem3Input 0 0 0 + makeStateMem3Input 0 0 0 + makeStateMem3Input 0 0 0 + ]), + Ok [ + makeStateMem3Output 0 // Mem[0], unchanged + makeStateMem3Output 0 // Mem[0], unchanged + makeStateMem3Output 0 // Mem[0], unchanged + makeStateMem3Output 1 // Mem[0], set to 1 + makeStateMem3Output 0 // Mem[0], set to 0 + makeStateMem3Output 1 // Mem[0], set to 1 + makeStateMem3Output 1 // Mem[0], stays 1 + makeStateMem3Output 1 // Mem[0], stays 1 + makeStateMem3Output 1 // Mem[0], stays 1 + makeStateMem3Output 1 // Mem[0], stays 1 + ] + + "RAM writes and reads all locations.", + ("main", stateMem3, [], 17, + ( [0..pow2(3)-1] |> List.map(fun i -> makeStateMem3Input i (i+1) 1) ) // Write all locations. + @ + ( [0..pow2(3)-1] |> List.map(fun i -> makeStateMem3Input i 0 0) ) // Read all locations. + ), + Ok ( + [ makeStateMem3Output 0 ] + @ + ( [0..pow2(3)-1] |> List.map(fun i -> makeStateMem3Output <| i+1) ) + @ + ( [0..pow2(3)-1] |> List.map(fun i -> makeStateMem3Output <| i+1) ) + ) +] diff --git a/Tests/SimulatorSyncTests.fs b/Tests/SimulatorSyncTests.fs new file mode 100644 index 0000000..df2e429 --- /dev/null +++ b/Tests/SimulatorSyncTests.fs @@ -0,0 +1,214 @@ +module SimulatorSyncTests + +open CommonTypes +open SimulatorTypes +open CanvasStatesSync + +/// Tuple with: (diagramName, state, loadedComponents, number of clock ticks, inputss). +/// Note that the inputss is a list of inputs. I.e. inputss provides an inputs +/// for every time step. The first set of inputs will be fed before the first +/// clock tick, then second after the second clock tick and so on. If no inputs +/// are provided for a certain iteration, none will fed. +type private TestCaseInput = string * CanvasState * LoadedComponent list * int * ((ComponentId * WireData) list) list +type private IterationOutput = (SimulationIO * WireData) list // Output after every clock tick. +type private TestCaseOutput = Result +type private TestCase = string * TestCaseInput * TestCaseOutput + +let testCasesSimulatorSync : TestCase list = [ + "Simple D-flip-flop, one input, one output (zero)", + ("main", stateSync1, [], 5, [ + [ (ComponentId "6e7a2000-439c-108e-df6d-93cff7a41266", [Zero]) ] + ]), + Ok ( + // Check it is zero for 5 ticks. + [(ComponentId "a5d52bcd-0a6d-d123-7313-61d0b8b367fd", ComponentLabel "out", 1), [Zero]] + |> List.replicate 5 + ) + + "Simple D-flip-flop, one input, one output (one)", + ("main", stateSync1, [], 5, [ + [ (ComponentId "6e7a2000-439c-108e-df6d-93cff7a41266", [One]) ] + ]), + Ok ( + // Tick 0, out is zero. + [[(ComponentId "a5d52bcd-0a6d-d123-7313-61d0b8b367fd", ComponentLabel "out", 1), [Zero]]] + @ + // Then out is 1 four times. + ([(ComponentId "a5d52bcd-0a6d-d123-7313-61d0b8b367fd", ComponentLabel "out", 1), [One]] + |> List.replicate 4) + ) + + "Two D-flip-flop connected in series, one input, one output (one)", + ("main", stateSync2, [], 5, [ + [ (ComponentId "3739e54a-fd21-bf60-8fc2-a3d10108c947", [One]) ] + ]), + Ok ( + // Tick 0 and 1, out is zero. + ([(ComponentId "a5d52bcd-0a6d-d123-7313-61d0b8b367fd", ComponentLabel "out", 1), [Zero]] + |> List.replicate 2) + @ + // Then out is 1 three times. + ([(ComponentId "a5d52bcd-0a6d-d123-7313-61d0b8b367fd", ComponentLabel "out", 1), [One]] + |> List.replicate 3) + ) + + "Three D-flip-flop connected in series, one input, one output (one)", + ("main", stateSync3, [], 5, [ + [ (ComponentId "3739e54a-fd21-bf60-8fc2-a3d10108c947", [One]) ] + ]), + Ok ( + // Tick 0,1 and 2, out is zero. + ([(ComponentId "a5d52bcd-0a6d-d123-7313-61d0b8b367fd", ComponentLabel "out", 1), [Zero]] + |> List.replicate 3) + @ + // Then out is 1 two times. + ([(ComponentId "a5d52bcd-0a6d-d123-7313-61d0b8b367fd", ComponentLabel "out", 1), [One]] + |> List.replicate 2) + ) + + "StateSync1 custom component followed by a DFF (one)", + ("main", stateSync4, [stateSync1Dependency], 5, [ + [ (ComponentId "03e4c81a-4703-d9f5-dfaf-301de006610f", [One]) ] + ]), + Ok ( + // Tick 0 and 1, out is zero. + ([(ComponentId "781e7d9d-b18c-d614-dbc0-23bac9e617b7", ComponentLabel "b", 1), [Zero]] + |> List.replicate 2) + @ + // Then out is 1 three times. + ([(ComponentId "781e7d9d-b18c-d614-dbc0-23bac9e617b7", ComponentLabel "b", 1), [One]] + |> List.replicate 3) + ) + + "StateSync1 custom component followed by a DFF, time varying inputs", + ("main", stateSync4, [stateSync1Dependency], 10, [ + [ (ComponentId "03e4c81a-4703-d9f5-dfaf-301de006610f", [One]) ] + [ (ComponentId "03e4c81a-4703-d9f5-dfaf-301de006610f", [Zero]) ] + [ (ComponentId "03e4c81a-4703-d9f5-dfaf-301de006610f", [One]) ] + ]), + Ok [ + [ (ComponentId "781e7d9d-b18c-d614-dbc0-23bac9e617b7", ComponentLabel "b", 1), [Zero] ] + [ (ComponentId "781e7d9d-b18c-d614-dbc0-23bac9e617b7", ComponentLabel "b", 1), [Zero] ] + [ (ComponentId "781e7d9d-b18c-d614-dbc0-23bac9e617b7", ComponentLabel "b", 1), [One] ] // After 2 timesteps, the One arrives. + [ (ComponentId "781e7d9d-b18c-d614-dbc0-23bac9e617b7", ComponentLabel "b", 1), [Zero] ] // Back to Zero. + [ (ComponentId "781e7d9d-b18c-d614-dbc0-23bac9e617b7", ComponentLabel "b", 1), [One] ] // Back to One. + [ (ComponentId "781e7d9d-b18c-d614-dbc0-23bac9e617b7", ComponentLabel "b", 1), [One] ] // And statys one... + [ (ComponentId "781e7d9d-b18c-d614-dbc0-23bac9e617b7", ComponentLabel "b", 1), [One] ] + [ (ComponentId "781e7d9d-b18c-d614-dbc0-23bac9e617b7", ComponentLabel "b", 1), [One] ] + [ (ComponentId "781e7d9d-b18c-d614-dbc0-23bac9e617b7", ComponentLabel "b", 1), [One] ] + [ (ComponentId "781e7d9d-b18c-d614-dbc0-23bac9e617b7", ComponentLabel "b", 1), [One] ] + ] + + "A DFF looping to itself via a Not gate. Two output nodes to probe the wires before and after the Not gate.", + ("main", stateSync5, [], 4, []), + Ok [ + [ (ComponentId "62a3108e-1198-502b-e338-e677815aead3", ComponentLabel "out1", 1), [Zero] + (ComponentId "023094a0-9787-47ce-26af-03086cdc4b15", ComponentLabel "out2", 1), [One] ] + + [ (ComponentId "62a3108e-1198-502b-e338-e677815aead3", ComponentLabel "out1", 1), [One] + (ComponentId "023094a0-9787-47ce-26af-03086cdc4b15", ComponentLabel "out2", 1), [Zero] ] + + [ (ComponentId "62a3108e-1198-502b-e338-e677815aead3", ComponentLabel "out1", 1), [Zero] + (ComponentId "023094a0-9787-47ce-26af-03086cdc4b15", ComponentLabel "out2", 1), [One] ] + + [ (ComponentId "62a3108e-1198-502b-e338-e677815aead3", ComponentLabel "out1", 1), [One] + (ComponentId "023094a0-9787-47ce-26af-03086cdc4b15", ComponentLabel "out2", 1), [Zero] ] + ] + + "Similar to stateSync5, but with a stateSync1 custom component instead of a DFF.", + ("main", stateSync6, [stateSync1Dependency], 4, []), + Ok [ + [ (ComponentId "62a3108e-1198-502b-e338-e677815aead3", ComponentLabel "out1", 1), [Zero] + (ComponentId "023094a0-9787-47ce-26af-03086cdc4b15", ComponentLabel "out2", 1), [One] ] + + [ (ComponentId "62a3108e-1198-502b-e338-e677815aead3", ComponentLabel "out1", 1), [One] + (ComponentId "023094a0-9787-47ce-26af-03086cdc4b15", ComponentLabel "out2", 1), [Zero] ] + + [ (ComponentId "62a3108e-1198-502b-e338-e677815aead3", ComponentLabel "out1", 1), [Zero] + (ComponentId "023094a0-9787-47ce-26af-03086cdc4b15", ComponentLabel "out2", 1), [One] ] + + [ (ComponentId "62a3108e-1198-502b-e338-e677815aead3", ComponentLabel "out1", 1), [One] + (ComponentId "023094a0-9787-47ce-26af-03086cdc4b15", ComponentLabel "out2", 1), [Zero] ] + ] + + "A connected to output via both sync and comb paths.", + ("main", stateSync7, [], 4, [ + [(ComponentId "ff10125a-601f-e1d5-e379-7eb7c65eb91f", [One])] + [(ComponentId "ff10125a-601f-e1d5-e379-7eb7c65eb91f", [Zero])] + ]), + Ok [ + [ (ComponentId "794d5154-6969-3f4e-9c8b-4bc17927c28f", ComponentLabel "B-Comb", 1), [One] + (ComponentId "95452292-b507-ab43-f082-85152d3e4cf2", ComponentLabel "B-Sync", 1), [Zero] ] + + [ (ComponentId "794d5154-6969-3f4e-9c8b-4bc17927c28f", ComponentLabel "B-Comb", 1), [Zero] + (ComponentId "95452292-b507-ab43-f082-85152d3e4cf2", ComponentLabel "B-Sync", 1), [One] ] + + [ (ComponentId "794d5154-6969-3f4e-9c8b-4bc17927c28f", ComponentLabel "B-Comb", 1), [Zero] + (ComponentId "95452292-b507-ab43-f082-85152d3e4cf2", ComponentLabel "B-Sync", 1), [Zero] ] + + [ (ComponentId "794d5154-6969-3f4e-9c8b-4bc17927c28f", ComponentLabel "B-Comb", 1), [Zero] + (ComponentId "95452292-b507-ab43-f082-85152d3e4cf2", ComponentLabel "B-Sync", 1), [Zero] ] + ] + + "stateSync7 Not-ed self looped in the synchronous branch.", + ("main", stateSync8, [stateSync7Dependency], 4, []), + Ok [ + [ (ComponentId "66030e1a-4a97-244a-f0bb-d9e5fd25627f", ComponentLabel "B", 1), [One] ] + [ (ComponentId "66030e1a-4a97-244a-f0bb-d9e5fd25627f", ComponentLabel "B", 1), [Zero] ] + [ (ComponentId "66030e1a-4a97-244a-f0bb-d9e5fd25627f", ComponentLabel "B", 1), [One] ] + [ (ComponentId "66030e1a-4a97-244a-f0bb-d9e5fd25627f", ComponentLabel "B", 1), [Zero] ] + ] + + "stateSync8 wrapped", + ("main", stateSync9, [stateSync8Dependency; stateSync7Dependency], 4, []), + Ok [ + [ (ComponentId "a100bada-b27f-15ca-accb-153e717a31f1", ComponentLabel "B", 1), [One] ] + [ (ComponentId "a100bada-b27f-15ca-accb-153e717a31f1", ComponentLabel "B", 1), [Zero] ] + [ (ComponentId "a100bada-b27f-15ca-accb-153e717a31f1", ComponentLabel "B", 1), [One] ] + [ (ComponentId "a100bada-b27f-15ca-accb-153e717a31f1", ComponentLabel "B", 1), [Zero] ] + ] + + "A fully connected DFFE.", + ("main", stateSync10, [], 8, [ + [ (ComponentId "5916f1cf-408e-4186-a839-c80926bfddf0", [Zero]) // in + (ComponentId "cab54371-5e07-9586-eb9b-be8cc417e610", [Zero]) ] // enable + [ (ComponentId "5916f1cf-408e-4186-a839-c80926bfddf0", [Zero]) + (ComponentId "cab54371-5e07-9586-eb9b-be8cc417e610", [One]) ] // turn on enable + [ (ComponentId "5916f1cf-408e-4186-a839-c80926bfddf0", [One]) + (ComponentId "cab54371-5e07-9586-eb9b-be8cc417e610", [One]) ] // turn on enable + [ (ComponentId "5916f1cf-408e-4186-a839-c80926bfddf0", [Zero]) + (ComponentId "cab54371-5e07-9586-eb9b-be8cc417e610", [Zero]) ] // turn off enable + [ (ComponentId "5916f1cf-408e-4186-a839-c80926bfddf0", [One]) + (ComponentId "cab54371-5e07-9586-eb9b-be8cc417e610", [One]) ] // turn on enable again + [ (ComponentId "5916f1cf-408e-4186-a839-c80926bfddf0", [Zero]) + (ComponentId "cab54371-5e07-9586-eb9b-be8cc417e610", [One]) ] // set to zero + ]), + Ok [ + [ (ComponentId "a2c874bb-eaeb-d62d-8a72-5eeae48db694", ComponentLabel "out", 1), [Zero] ] + [ (ComponentId "a2c874bb-eaeb-d62d-8a72-5eeae48db694", ComponentLabel "out", 1), [Zero] ] + [ (ComponentId "a2c874bb-eaeb-d62d-8a72-5eeae48db694", ComponentLabel "out", 1), [Zero] ] // enabled but zero + [ (ComponentId "a2c874bb-eaeb-d62d-8a72-5eeae48db694", ComponentLabel "out", 1), [One] ] // set to one + [ (ComponentId "a2c874bb-eaeb-d62d-8a72-5eeae48db694", ComponentLabel "out", 1), [One] ] // enable is off + [ (ComponentId "a2c874bb-eaeb-d62d-8a72-5eeae48db694", ComponentLabel "out", 1), [One] ] // enable is on again + [ (ComponentId "a2c874bb-eaeb-d62d-8a72-5eeae48db694", ComponentLabel "out", 1), [Zero] ] // set to zero + [ (ComponentId "a2c874bb-eaeb-d62d-8a72-5eeae48db694", ComponentLabel "out", 1), [Zero] ] // set to zero + ] + + "StateSync7 Not-ed self looped in the combinatorial branch.", + ("main", stateSync11, [stateSync7Dependency], 4, []), + Error { + Msg = "Cycle detected in combinatorial logic." + InDependency = None + ComponentsAffected = ["c9d9659a-4476-de3a-a838-eeab15496c99"; "5c24921a-88e9-7bc2-ee89-97fefb694902"] |> List.map ComponentId + ConnectionsAffected = ["bc1f9a51-5ca8-1aa0-b4bd-b86bc9646c20"; "cc7a9da2-f78a-f3e1-1c2f-7323f2b43d15"] |> List.map ConnectionId + } + + "StateSync11 connected to an output. Should spot cycle in the dependency.", + ("main", stateSync12, [stateSync11Dependency; stateSync7Dependency], 4, []), + Error { + Msg = "Cycle detected in combinatorial logic." + InDependency = Some "combinatorial-loop" + ComponentsAffected = ["c9d9659a-4476-de3a-a838-eeab15496c99"; "5c24921a-88e9-7bc2-ee89-97fefb694902"] |> List.map ComponentId + ConnectionsAffected = [] // Connections are not inferred in dependencies. + } +] diff --git a/Tests/SimulatorTests.fs b/Tests/SimulatorTests.fs new file mode 100644 index 0000000..e404433 --- /dev/null +++ b/Tests/SimulatorTests.fs @@ -0,0 +1,457 @@ +module SimulatorTests + +open CommonTypes +open SimulatorTypes +open CanvasStates +open CanvasStatesWithBuses +open Simulator + +/// Tuple with: (diagramName, state, loadedComponents, inputs). +type private SimulatorTestCaseInput = string * CanvasState * LoadedComponent list * (ComponentId * WireData) list +type private SimulatorTestCaseOutput = Result<(SimulationIO * WireData) list, SimulationError> +type private SimulatorTestCase = string * SimulatorTestCaseInput * SimulatorTestCaseOutput + +let private makeError msg deps comps conns = + Error { + Msg = msg + InDependency = deps + ComponentsAffected = comps |> List.map ComponentId + ConnectionsAffected = conns |> List.map ConnectionId + } + +/// Given a list of N generic elements, associate each element with a bit and +/// return 2^N lists with all the possible bit combinations. +/// A bit is simply a bus with width 1. +let makeAllBitCombinations (lst : 'a list) : (('a * WireData) list) list = + let rec allCombinations lst result stack = + match lst with + | [] -> List.rev stack :: result + | el :: lst' -> + let result = allCombinations lst' result ((el,[Zero]) :: stack) + allCombinations lst' result ((el,[One]) :: stack) + List.rev <| allCombinations lst [] [] + +/// Auto generate all the testcases for a CanvasState (i.e. a full thruth +/// table). The thruth table considers ALL inputs to be single bit inputs, +/// please do not use this function if not all inputs are like that. +let private createAllTestCases + (title : string) + (diagramName : string) + (state : CanvasState) + (dependencies : LoadedComponent list) + (inputLabels : ComponentId list) + (expectedResults : ((SimulationIO * WireData) list) list) + : SimulatorTestCase list = + let allInputCombinations = makeAllBitCombinations inputLabels + assert(List.length allInputCombinations = List.length expectedResults) + (allInputCombinations, expectedResults) + ||> List.map2 (fun inputs outputs -> + sprintf "%s: %A" title inputs, + (diagramName, state, dependencies, inputs), + Ok outputs + ) + +// The input to a test case is formed by: +// - a CanvasState, +// - a list of loaded dependencies, +// - a list of input values that will be applied to the simulation graph. + +// The dependency list and the inputs do not matter since the test has to fail +// in the earlier checks. +let private testCasesSimulatorPortError : SimulatorTestCase list = [ + "Unconnected input node", + ("", state1, [], []), + makeError + "All ports must have at least one connection." + None + ["input-node0"] + [] + + "Two unconnected input nodes", + ("", state2, [], []), + makeError + "All ports must have at least one connection." + None + ["input-node0"] + [] + + "Two inputs and one output", + ("", state5, [], []), + makeError + "A wire must have precisely one driving component, but 2 were found. If you want to merge wires together use a MergeWires component." + None + ["output-node0"] + [] + + "Two inputs, one And, one output, with extra connection input to output", + ("", state7, [], []), + makeError + "A wire must have precisely one driving component, but 2 were found. If you want to merge wires together use a MergeWires component." + None + ["output"] + [] + + "Two inputs, one And, one output, with extra connections inputs to and", + ("", state8, [], []), + makeError + "A wire must have precisely one driving component, but 2 were found. If you want to merge wires together use a MergeWires component." + None + ["and"] + [] + + "Mux2 with only two connected ports", + ("", state9, [], []), + makeError + "All ports must have at least one connection." + None + ["mux"] + [] +] + +let private testCasesSimulatorDuplicatIOError : SimulatorTestCase list = [ + "Simple circuit with duplicated output label", + ("", state14, [], []), + makeError + "Two Output components cannot have the same label: output-duplicate-label." + None + ["output-node0"; "output-node1"] + [] + + "Simple And circuit with duplicated input label", + ("", state15, [], []), + makeError + "Two Input components cannot have the same label: input-duplicate-label." + None + ["top-input"; "bottom-input"] + [] +] + +let private testCasesSimulatorCycleError : SimulatorTestCase list = [ + "Complex diagram with three Ands and two cycles", + ("", state10, [], []), + makeError + "Cycle detected in combinatorial logic." + None + ["and2"; "and0"] + ["conn5"; "conn4"] + + "Complex diagram with three Ands and one long cycle", + ("", state11, [], []), + makeError + "Cycle detected in combinatorial logic." + None + ["and1"; "and2"; "and0"] + ["conn1"; "conn5"; "conn3"] +] + +// In the next tests, we have no dependencies. +// The inputs are set since the simulation graph should be fine. +let private testCasesSimulatorOkNoDependencies : SimulatorTestCase list = + createAllTestCases + "Simple circuit with one input and one output" + "main" state3 [] [ComponentId "input-node0"] + [ + [(ComponentId "output-node0", ComponentLabel "output-node0-label", 1), [Zero]] + [(ComponentId "output-node0", ComponentLabel "output-node0-label", 1), [One]] + ] + @ + createAllTestCases + "Simple circuit with one input connected to two outputs" + "main" state4 [] [ComponentId "input-node0"] + [ + [ + (ComponentId "output-node0", ComponentLabel "output-node0-label", 1), [Zero] + (ComponentId "output-node1", ComponentLabel "output-node1-label", 1), [Zero] + ] + [ + (ComponentId "output-node0", ComponentLabel "output-node0-label", 1), [One] + (ComponentId "output-node1", ComponentLabel "output-node1-label", 1), [One] + ] + ] + @ + createAllTestCases + "Two inputs; one And; one output" + "main" state6 [] [ComponentId "top-input"; ComponentId "bottom-input"] + [ + [(ComponentId "output", ComponentLabel "output-node0-label", 1), [Zero]] + [(ComponentId "output", ComponentLabel "output-node0-label", 1), [Zero]] + [(ComponentId "output", ComponentLabel "output-node0-label", 1), [Zero]] + [(ComponentId "output", ComponentLabel "output-node0-label", 1), [One]] + ] + @ + createAllTestCases + "Weird diagram with a series of and gates" + "main" state12 [] [ComponentId "input"] + [ + [(ComponentId "output", ComponentLabel "output", 1), [Zero]] + [(ComponentId "output", ComponentLabel "output", 1), [One]] + ] + @ + createAllTestCases + "One bit adder (Zero, Zero)" + "main" state13 [] [ + ComponentId "2953603d-44e4-5c1f-3fb1-698f7863b6b5" + ComponentId "170e69f4-b3d7-d9e0-9f1d-6a564ba62062" + ] + [ + [ + (ComponentId "9aaf18a9-b3ac-bf51-1ed3-625baa1ff6a9", ComponentLabel "Sum", 1), [Zero] + (ComponentId "94da6dd7-a263-a3ec-ec76-bfa07b0b0f34", ComponentLabel "Carry", 1), [Zero] + ] + [ + (ComponentId "9aaf18a9-b3ac-bf51-1ed3-625baa1ff6a9", ComponentLabel "Sum", 1), [One] + (ComponentId "94da6dd7-a263-a3ec-ec76-bfa07b0b0f34", ComponentLabel "Carry", 1), [Zero] + ] + [ + (ComponentId "9aaf18a9-b3ac-bf51-1ed3-625baa1ff6a9", ComponentLabel "Sum", 1), [One] + (ComponentId "94da6dd7-a263-a3ec-ec76-bfa07b0b0f34", ComponentLabel "Carry", 1), [Zero] + ] + [ + (ComponentId "9aaf18a9-b3ac-bf51-1ed3-625baa1ff6a9", ComponentLabel "Sum", 1), [Zero] + (ComponentId "94da6dd7-a263-a3ec-ec76-bfa07b0b0f34", ComponentLabel "Carry", 1), [One] + ] + ] + +let testCasesSimulatorDependencyError : SimulatorTestCase list = + createAllTestCases + "Broken unused dependency." // Since the dependency is unused the test should pass. + "main" state3 [state1Dependency] [ComponentId "input-node0"] + [ + [(ComponentId "output-node0", ComponentLabel "output-node0-label", 1), [Zero]] + [(ComponentId "output-node0", ComponentLabel "output-node0-label", 1), [One]] + ] + @ + [ + // Broken dependencies. + + "Input connected to broken depdendency.", + ("main", state19, [state1Dependency], []), + makeError + "All ports must have at least one connection." + (Some "broken-one-input") [] [] + + // Dependency cycle. + + "Component using itself.", + (state16Dependency.Name, state20, [state16Dependency], []), + makeError + (sprintf "Found a cycle in dependencies: \"%s\" --> \"%s\"." state16Dependency.Name state16Dependency.Name) + None [] [] + + "Long cycle starting at root.", + (state23Dependency.Name, state23, [state21Dependency; state22Dependency], []), + makeError + (sprintf "Found a cycle in dependencies: \"%s\" --> \"%s\" --> \"%s\" --> \"%s\"." state23Dependency.Name state21Dependency.Name state22Dependency.Name state23Dependency.Name) + None [] [] + + "Long cycle.", + ("main", state24, [state21Dependency; state22Dependency; state23Dependency], []), + makeError + (sprintf "Found a cycle in dependencies: \"%s\" --> \"%s\" --> \"%s\" --> \"%s\"." state23Dependency.Name state21Dependency.Name state22Dependency.Name state23Dependency.Name) + None [] [] + + // Missing dependencies. + + "2 bit full adder missing dependencies", + ("2-bit-adder", twoBitAdderState, [], []), + makeError + "Could not resolve dependency: \"full-adder\". Make sure a dependency with such name exists in the current project." + (Some "2-bit-adder") [] [] + + "2 bit full adder missing half adder dependency", + ("2-bit-adder", twoBitAdderState, [fullAdderDependency], []), + makeError + "Could not resolve dependency: \"half-adder\". Make sure a dependency with such name exists in the current project." + (Some "full-adder") [] [] + + "2 bit full adder missing full adder dependency", + ("2-bit-adder", twoBitAdderState, [halfAdderDependency], []), + makeError + "Could not resolve dependency: \"full-adder\". Make sure a dependency with such name exists in the current project." + (Some "2-bit-adder") [] [] + ] + +// Outputs fot the 2bit adder test. + +let private zero = [ + (ComponentId "dbb1f55a-edf3-bde2-4c69-43a02560e17d", ComponentLabel "Sum1", 1), [Zero] + (ComponentId "8f5bded5-f46d-722d-6108-03dda4236c01", ComponentLabel "Sum0", 1), [Zero] + (ComponentId "7d948312-376d-1d4b-cf02-90872026be16", ComponentLabel "Cout", 1), [Zero] + ] +let private one = [ + (ComponentId "dbb1f55a-edf3-bde2-4c69-43a02560e17d", ComponentLabel "Sum1", 1), [Zero] + (ComponentId "8f5bded5-f46d-722d-6108-03dda4236c01", ComponentLabel "Sum0", 1), [One] + (ComponentId "7d948312-376d-1d4b-cf02-90872026be16", ComponentLabel "Cout", 1), [Zero] + ] +let private two = [ + (ComponentId "dbb1f55a-edf3-bde2-4c69-43a02560e17d", ComponentLabel "Sum1", 1), [One] + (ComponentId "8f5bded5-f46d-722d-6108-03dda4236c01", ComponentLabel "Sum0", 1), [Zero] + (ComponentId "7d948312-376d-1d4b-cf02-90872026be16", ComponentLabel "Cout", 1), [Zero] + ] +let private three = [ + (ComponentId "dbb1f55a-edf3-bde2-4c69-43a02560e17d", ComponentLabel "Sum1", 1), [One] + (ComponentId "8f5bded5-f46d-722d-6108-03dda4236c01", ComponentLabel "Sum0", 1), [One] + (ComponentId "7d948312-376d-1d4b-cf02-90872026be16", ComponentLabel "Cout", 1), [Zero] + ] +let private four = [ + (ComponentId "dbb1f55a-edf3-bde2-4c69-43a02560e17d", ComponentLabel "Sum1", 1), [Zero] + (ComponentId "8f5bded5-f46d-722d-6108-03dda4236c01", ComponentLabel "Sum0", 1), [Zero] + (ComponentId "7d948312-376d-1d4b-cf02-90872026be16", ComponentLabel "Cout", 1), [One] + ] +let private five = [ + (ComponentId "dbb1f55a-edf3-bde2-4c69-43a02560e17d", ComponentLabel "Sum1", 1), [Zero] + (ComponentId "8f5bded5-f46d-722d-6108-03dda4236c01", ComponentLabel "Sum0", 1), [One] + (ComponentId "7d948312-376d-1d4b-cf02-90872026be16", ComponentLabel "Cout", 1), [One] + ] +let private six = [ + (ComponentId "dbb1f55a-edf3-bde2-4c69-43a02560e17d", ComponentLabel "Sum1", 1), [One] + (ComponentId "8f5bded5-f46d-722d-6108-03dda4236c01", ComponentLabel "Sum0", 1), [Zero] + (ComponentId "7d948312-376d-1d4b-cf02-90872026be16", ComponentLabel "Cout", 1), [One] + ] +let private seven = [ + (ComponentId "dbb1f55a-edf3-bde2-4c69-43a02560e17d", ComponentLabel "Sum1", 1), [One] + (ComponentId "8f5bded5-f46d-722d-6108-03dda4236c01", ComponentLabel "Sum0", 1), [One] + (ComponentId "7d948312-376d-1d4b-cf02-90872026be16", ComponentLabel "Cout", 1), [One] + ] + +let testCasesSimulatorOkWithDependencies : SimulatorTestCase list = + createAllTestCases + "Simple input-output dependency" "main" + state16 [state3Dependency] [ComponentId "outer-input-node0"] + [ + [(ComponentId "outer-output-node0", ComponentLabel "outer-output-node0-label", 1), [Zero]] + [(ComponentId "outer-output-node0", ComponentLabel "outer-output-node0-label", 1), [One]] + ] + @ + createAllTestCases + "Nested input-output dependency" "main" + state17 [state16Dependency; state3Dependency] [ComponentId "outer-outer-input-node0"] + [ + [(ComponentId "outer-outer-output-node0", ComponentLabel "outer-outer-output-node0-label", 1), [Zero]] + [(ComponentId "outer-outer-output-node0", ComponentLabel "outer-outer-output-node0-label", 1), [One]] + ] + @ + createAllTestCases + "Doubly nested input-output dependency" "main" + state18 [state17Dependency; state16Dependency; state3Dependency] [ComponentId "outer-outer-outer-input-node0"] + [ + [(ComponentId "outer-outer-outer-output-node0", ComponentLabel "outer-outer-outer-output-node0-label", 1), [Zero]] + [(ComponentId "outer-outer-outer-output-node0", ComponentLabel "outer-outer-outer-output-node0-label", 1), [One]] + ] + @ + createAllTestCases + "2 bit adder" "2-bit-adder" + twoBitAdderState [fullAdderDependency; halfAdderDependency] [ + ComponentId "78795182-35c4-1c50-2190-6fc944a2adea" // Cin + ComponentId "a63fe5a2-9f4d-e70f-131b-ed35d3f3a9e1" // B1 + ComponentId "69a6ad2a-af19-369f-0483-0e09e6841da3" // B0 + ComponentId "82a03f0b-ae31-b487-ed1b-335e235adeb7" // A1 + ComponentId "86372781-c2f4-09f2-406f-f385ee7a47a9" // A0 + ] + [ + zero;one;two;three; + one;two;three;four; + two;three;four;five; + three;four;five;six; + one;two;three;four; + two;three;four;five; + three;four;five;six; + four;five;six;seven + ] + +let private testCasesSimulatorBusesError : SimulatorTestCase list = [ + "Two inputs make a bus2, then Push input a to bus, then try to split into 2 single bits (fail)", + ("main", stateBus11, [], []), + makeError "Wrong wire width. Target port expects a 1 bit(s) signal, but source port produces a 2 bit(s) signal." None [] ["conn"] + + "A 4 bit input connected to a 3 bit output", + ("main", stateBus14, [], []), + makeError "Wrong wire width. Target port expects a 3 bit(s) signal, but source port produces a 4 bit(s) signal." None [] ["conn"] + + "A 3 bit input connected to a 4 bit output", + ("main", stateBus15, [], []), + makeError "Wrong wire width. Target port expects a 4 bit(s) signal, but source port produces a 3 bit(s) signal." None [] ["conn"] +] + +let private testCasesSimulatorOkWithBuses : SimulatorTestCase list = + createAllTestCases + "Two inputs, packed into a bus, unpacked into two outputs" "main" + stateBus10 [] [ + ComponentId "a91be585-2d3b-d872-be0f-b416c8eb03d2" // a + ComponentId "9985ebc6-1cd5-8863-1341-1d543d236d38" // b + ] + (makeAllBitCombinations [ + (ComponentId "8a9392fc-493b-7e96-72ec-b6f5f11ded8a", ComponentLabel "a-out", 1) + (ComponentId "dfcf6cff-fbac-e54f-7a9d-7059d17e3a0b", ComponentLabel "b-out", 1) + ]) + @ + createAllTestCases + "Four inputs, packed into a bus, unpacked into four outputs" "main" + stateBus12 [] [ + ComponentId "76de964a-124b-5c16-6de1-6158626344ac" // a + ComponentId "a91be585-2d3b-d872-be0f-b416c8eb03d2" // b + ComponentId "9985ebc6-1cd5-8863-1341-1d543d236d38" // c + ComponentId "9824ceb8-e999-8e48-9a56-7a4349e495b1" // d + ] + (makeAllBitCombinations [ + (ComponentId "59b45f9c-192c-98ce-da25-a94db45a5790", ComponentLabel "a-out", 1) + (ComponentId "8a9392fc-493b-7e96-72ec-b6f5f11ded8a", ComponentLabel "b-out", 1) + (ComponentId "dfcf6cff-fbac-e54f-7a9d-7059d17e3a0b", ComponentLabel "c-out", 1) + (ComponentId "214620f0-51f6-59fe-1558-ed47fd2c680a", ComponentLabel "d-out", 1) + ]) + @ + [ + "A 4 bit input connected to a four bit output (1)", + ("main", stateBus13, [], [ + ComponentId "9bcba47e-deae-0b3f-2079-a1b124526b00", [One; One; One; One] + ]), + [ + (ComponentId "ad2ef0c3-537e-9d2e-0064-ac6b952e4b97", ComponentLabel "b", 4), [One; One; One; One] + ] |> Ok + + "A 4 bit input connected to a four bit output (2)", + ("main", stateBus13, [], [ + ComponentId "9bcba47e-deae-0b3f-2079-a1b124526b00", [Zero; One; Zero; One] + ]), + [ + (ComponentId "ad2ef0c3-537e-9d2e-0064-ac6b952e4b97", ComponentLabel "b", 4), [Zero; One; Zero; One] + ] |> Ok + + "A 2 bit input split into 2 single bit outputs (1)", + ("main", stateBus16, [], [ + ComponentId "c6f000db-310f-d8ad-ff5e-938d7c2aaa7c", [One; Zero] + ]), + [ + (ComponentId "60e2df66-bb8c-53f1-832d-e154c30cf9dd", ComponentLabel "b", 1), [One] + (ComponentId "85e19389-c087-8b30-6c0a-02f7cc753695", ComponentLabel "c", 1), [Zero] + ] |> Ok + + "A 2 bit input split into 2 single bit outputs (2)", + ("main", stateBus16, [], [ + ComponentId "c6f000db-310f-d8ad-ff5e-938d7c2aaa7c", [Zero; One] + ]), + [ + (ComponentId "60e2df66-bb8c-53f1-832d-e154c30cf9dd", ComponentLabel "b", 1), [Zero] + (ComponentId "85e19389-c087-8b30-6c0a-02f7cc753695", ComponentLabel "c", 1), [One] + ] |> Ok + + "3 bit input merged with 4 bit input, then split in the same way", + ("main", stateBus17, [], [ + ComponentId "6bcdc74a-9d71-3304-537d-1a17f02924eb", [One; Zero; One] // 3 bits. + ComponentId "97c4b56d-4f8c-2b00-fb61-a08cdd01dd76", [Zero; One; Zero; One] // 4 bits. + ]), + [ + (ComponentId "1a6e1bb4-cfe0-77f9-a207-f409168ef210", ComponentLabel "out3", 3), [One; Zero; One] + (ComponentId "d2676492-2302-24d9-52eb-6e69e7971339", ComponentLabel "out4", 4), [Zero; One; Zero; One] + ] |> Ok + ] + +let testCasesSimulator = + testCasesSimulatorPortError @ + testCasesSimulatorCycleError @ + testCasesSimulatorDuplicatIOError @ + testCasesSimulatorOkNoDependencies @ + testCasesSimulatorDependencyError @ + testCasesSimulatorOkWithDependencies @ + testCasesSimulatorBusesError @ + testCasesSimulatorOkWithBuses diff --git a/Tests/TestLib.fs b/Tests/TestLib.fs new file mode 100644 index 0000000..542edbe --- /dev/null +++ b/Tests/TestLib.fs @@ -0,0 +1,18 @@ +module TestLib + +open Expecto + +/// Create a testcase for unit testing a function. +let testFunction f testData = + let descr, inp, expectedOut = testData + testCase descr <| fun () -> + let actual = f inp + Expect.equal actual expectedOut "" + +/// Create an expecto testList from a list of testCases. +let createTestList descr f testCases = + testList descr <| List.map (testFunction f) testCases + +/// Run all the previously defined tests. +let runTests () = + runTestsInAssembly defaultConfig [||] |> ignore diff --git a/Tests/Tests.fs b/Tests/Tests.fs new file mode 100644 index 0000000..aff5f21 --- /dev/null +++ b/Tests/Tests.fs @@ -0,0 +1,84 @@ +open TestLib +open Expecto +open Simulator +open BusWidthInferer +open SimulatorTests +open SimulatorSyncTests +open SimulatorMemoriesTests +open WidthInfererTests +open EEExtensions + +let runSimulatorTest (diagramName, state, loadedComponents, inputs) = + // Build simulation graph. + match prepareSimulation diagramName state loadedComponents with + | Error e -> Error e + | Ok simData -> + // Feed all the inputs and extract the outputs. + (simData.Graph, inputs) + ||> List.fold (fun graph (inputId, bit) -> feedSimulationInput graph inputId bit) + |> extractSimulationIOs simData.Outputs + |> Ok + +let safeListItem lst idx = + if idx >= List.length lst then [] else List.item idx lst + +let runSimulatorSyncTest (diagramName, state, loadedComponents, ticks, inputss) = + // Build simulation graph. + match prepareSimulation diagramName state loadedComponents with + | Error e -> Error e + | Ok simData -> + let results, graph = + (simData.Graph, [0..ticks-1]) + ||> List.mapFold (fun graph i -> + // Feed the inputs for this time iteration before the clock + // tick. + let inputs = safeListItem inputss i + let graph = + (graph, inputs) + ||> List.fold (fun graph (inputId, bit) -> + feedSimulationInput graph inputId bit) + // Extract output, then feed a new clock tick. + extractSimulationIOs simData.Outputs graph, feedClockTick graph + ) + Ok results + +[] +let simulatorTests = + createTestList "simulator" runSimulatorTest testCasesSimulator +[] +let simulatorSyncTests = + createTestList "simulatorSync" runSimulatorSyncTest testCasesSimulatorSync +[] +let simulatorMemoriesTests = + createTestList "simulatorMemories" runSimulatorSyncTest testCasesSimulatorMemories +[] +let widthInfererTests = + createTestList "widthInferer" inferConnectionsWidth testCasesWidthInferer + +let mutable Watches: Map = Map.empty + + +/// dotnet core timer function +let stopTimer s = + let timer = Map.tryFind s Watches + match timer with + | None -> failwithf "error: Timer '%s' has been stopped before it was started. timers: %A" s (Map.keys Watches) + | Some stopWatch -> + stopWatch.Stop() + printfn "%s: %.4fms" s stopWatch.Elapsed.TotalMilliseconds + +/// dotnet core timer function +let startTimer s = + Watches <- Map.add s (System.Diagnostics.Stopwatch.StartNew()) Watches + +/// measure various dotnet core performance stats +/// m = structure size. +/// n = number of iterations. +let displayPerformance m n = Helpers.checkPerformance m n startTimer stopTimer + + +[] +let main argv = + displayPerformance 100 1000000 + //TestLib.runTests () + 0 diff --git a/Tests/Tests.fsproj b/Tests/Tests.fsproj new file mode 100644 index 0000000..d8fc510 --- /dev/null +++ b/Tests/Tests.fsproj @@ -0,0 +1,24 @@ + + + + Exe + netcoreapp3.1 + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Tests/WidthInfererTests.fs b/Tests/WidthInfererTests.fs new file mode 100644 index 0000000..be93df0 --- /dev/null +++ b/Tests/WidthInfererTests.fs @@ -0,0 +1,184 @@ +module WidthInfererTests + +open CommonTypes +open CanvasStates +open CanvasStatesWithBuses + +type private WidthInfererTestCaseInput = CanvasState +type private WidthInfererTestCaseOutput = Result +type private WidhtInfererTestCase = string * WidthInfererTestCaseInput * WidthInfererTestCaseOutput + +let private testCasesWidthInfererSimple : WidhtInfererTestCase list = [ + "Two unconnected input nodes. No conections", state2, + Ok Map.empty + + "Simple circuit with one input connected to one output", state3, + [ + ConnectionId "conn0", Some 1 + ] |> Map.ofList |> Ok + + "Simple circuit with one input connected to two outputs", state4, + [ + ConnectionId "conn0", Some 1 + ConnectionId "conn1", Some 1 + ] |> Map.ofList |> Ok + + "Two inputs; one And; one output", state6, + [ + ConnectionId "conn0", Some 1 + ConnectionId "conn1", Some 1 + ConnectionId "conn2", Some 1 + ] |> Map.ofList |> Ok + + "Partially connected and: missing bottom connections", state25, + [ + ConnectionId "conn0", Some 1 + ConnectionId "conn2", Some 1 + ] |> Map.ofList |> Ok + + "Partially connected and: missing connection to output", state26, + [ + ConnectionId "conn0", Some 1 + ConnectionId "conn1", Some 1 + ] |> Map.ofList |> Ok + + "Partially connected and: missing both input connections", state27, + [ + ConnectionId "conn2", Some 1 + ] |> Map.ofList |> Ok + + "One input and one output, connected to the state3CustomComponent", state16, + [ + ConnectionId "conn0", Some 1 + ConnectionId "conn1", Some 1 + ] |> Map.ofList |> Ok + + "Nested custom components", state18, + [ + ConnectionId "conn0", Some 1 + ConnectionId "conn1", Some 1 + ] |> Map.ofList |> Ok +] + +let private testCasesWidthInfererBuses : WidhtInfererTestCase list = [ + "Two inputs connected to a MergeWires component. No other connections", stateBus1, + [ + ConnectionId "conn0", Some 1 + ConnectionId "conn1", Some 1 + ] |> Map.ofList |> Ok + + "A MergeWires connected to a SplitWire 1.", stateBus2, + [ + ConnectionId "conn0", None + ] |> Map.ofList |> Ok + + "A MergeWires connected to a SplitWire 1 and a single-bit output node", stateBus3, + [ + ConnectionId "conn0", None + ConnectionId "conn1", None + ] |> Map.ofList |> Ok + + "A MergeWires connected to a SplitWire 1, with loop", stateBus4, + [ + ConnectionId "conn0", None + ConnectionId "conn1", None + ] |> Map.ofList |> Ok + + "All the bus components in series, properly connected. No other components", stateBus6, + [ + ConnectionId "conn0", None + ConnectionId "conn1", None + ConnectionId "conn2", None + ConnectionId "conn3", None + ConnectionId "conn4", None + ] |> Map.ofList |> Ok + + "Non-inferrable loop", stateBus7, + [ + ConnectionId "conn0", None + ConnectionId "conn1", None + ] |> Map.ofList |> Ok + + "Mux connected to two MergeWires. Width not inferrable", stateBus8, + [ + ConnectionId "conn0", None + ConnectionId "conn1", None + ] |> Map.ofList |> Ok + + "A 4 bit input connected to a four bit output", stateBus13, + [ + ConnectionId "conn", Some 4 + ] |> Map.ofList |> Ok + + "A 2 bit input split into 2 single bit outputs", stateBus16, + [ + ConnectionId "conn0", Some 2 + ConnectionId "conn1", Some 1 + ConnectionId "conn2", Some 1 + ] |> Map.ofList |> Ok + + "3 bit input merged with 4 bit input, then split in the same way", stateBus17, + [ + ConnectionId "678ffa07-0ed7-7b6f-ba9b-b14839c08a71", Some 7 + ConnectionId "7438de0c-bbaf-c1f6-0307-42ece66c6c00", Some 4 + ConnectionId "82cc4ce9-7b15-40ac-0226-98a7f8e2fb9a", Some 4 + ConnectionId "9df32195-00b4-9795-3dc1-78fb70d453f2", Some 3 + ConnectionId "cd13c70f-6037-0cf4-1295-5795e92d745c", Some 3 + ] |> Map.ofList |> Ok + + "Partially connected Mux2", stateBus18, + [ + ConnectionId "conn-sel", Some 1 + ConnectionId "conn-top-input", Some 2 + ConnectionId "conn-to-output", Some 2 + ] |> Map.ofList |> Ok + + "Partially connected Demux2", stateBus20, + [ + ConnectionId "conn-to-input", Some 2 + ConnectionId "conn-to-output", Some 2 + ] |> Map.ofList |> Ok +] + +let private testCasesWidthInfererError : WidhtInfererTestCase list = [ + "Two inputs connected to the same output", state5, + Error { + Msg = "A wire must have precisely one driving component. If you want to merge two wires together, use a MergeWires component." + ConnectionsAffected = ["conn1"; "conn0"] |> List.map ConnectionId + } + + "Two inputs; one And; one output; with extra connection input to output", state7, + Error { + Msg = "A wire must have precisely one driving component. If you want to merge two wires together, use a MergeWires component." + ConnectionsAffected = ["conn3"; "conn2"] |> List.map ConnectionId + } + + "And connected to a SplitWire 1", stateBus9, + Error { + Msg = "Wrong wire width. Target port expects a signal with at least 2 bits, but source port produces a 1 bit(s) signal." + ConnectionsAffected = ["conn0"] |> List.map ConnectionId + } + + "A 4 bit input connected to a 3 bit output", stateBus14, + Error { + Msg = "Wrong wire width. Target port expects a 3 bit(s) signal, but source port produces a 4 bit(s) signal." + ConnectionsAffected = ["conn"] |> List.map ConnectionId + } + + "A 3 bit input connected to a 4 bit output", stateBus15, + Error { + Msg = "Wrong wire width. Target port expects a 4 bit(s) signal, but source port produces a 3 bit(s) signal." + ConnectionsAffected = ["conn"] |> List.map ConnectionId + } + + "Fully connected Mux, but two inputs have different widths", stateBus19, + Error { + Msg = "Wrong wire width. The two inputs to a multiplexer are expected to have the same width, but top input has 2 bits and bottom input has 1 bits." + ConnectionsAffected = ["conn-top-input"; "conn-bottom-input"] |> List.map ConnectionId + } +] + +let testCasesWidthInferer : WidhtInfererTestCase list = + testCasesWidthInfererSimple @ + testCasesWidthInfererBuses @ + testCasesWidthInfererError diff --git a/Tests/logStateToFSharp.py b/Tests/logStateToFSharp.py new file mode 100644 index 0000000..c5a0180 --- /dev/null +++ b/Tests/logStateToFSharp.py @@ -0,0 +1,59 @@ +# Python script that helps transforming the result of logging a file back into +# an f# data structure. +# Useful when writing the CanvasStates for the tests. + +import re + +state = """ +[ + {Id = 8078a917-236f-5a40-18a6-8e2d6a1458f5;Type = Input 2;Label = a;InputPorts = [];OutputPorts = [{Id = cc7c6510-d49b-28d9-e0bc-d5350a2c76a8;PortNumber = 0;PortType = Output;HostId = 8078a917-236f-5a40-18a6-8e2d6a1458f5}];X = 122;Y = 125}; + {Id = fbfb4202-9816-f214-0401-da18caddeb0f;Type = Demux2;Label = ;InputPorts = [{Id = 2b224026-609a-5eae-6885-ff9820dbae5f;PortNumber = 0;PortType = Input;HostId = fbfb4202-9816-f214-0401-da18caddeb0f}; {Id = 68043f9b-47e7-793f-fed2-943a7d7336dc;PortNumber = 1;PortType = Input;HostId = fbfb4202-9816-f214-0401-da18caddeb0f}];OutputPorts = [{Id = 57070484-347e-4701-8c36-f510c2ef150c;PortNumber = 0;PortType = Output;HostId = fbfb4202-9816-f214-0401-da18caddeb0f}; {Id = 123463bf-7868-9a87-6fb1-36627a3c9bad;PortNumber = 1;PortType = Output;HostId = fbfb4202-9816-f214-0401-da18caddeb0f}];X = 254;Y = 110}; + {Id = 00661085-7d05-4185-09ef-4138ac918ad2;Type = Output 2;Label = aa;InputPorts = [{Id = 7bbfa7d3-4718-e6fe-e7e9-8c00e5257f45;PortNumber = 0;PortType = Input;HostId = 00661085-7d05-4185-09ef-4138ac918ad2}];OutputPorts = [];X = 401;Y = 117} +], +[ + {Id = 1ef71074-fa16-a068-84a0-18d324e3ada6;Source = {Id = 57070484-347e-4701-8c36-f510c2ef150c;PortNumber = null;PortType = Output;HostId = fbfb4202-9816-f214-0401-da18caddeb0f};Target = {Id = 7bbfa7d3-4718-e6fe-e7e9-8c00e5257f45;PortNumber = null;PortType = Input;HostId = 00661085-7d05-4185-09ef-4138ac918ad2};Vertices = [284,126.66666666666667; 343.5,126.66666666666667; 343.5,127; 401,127]}; + {Id = f326a7a3-79d5-4ace-f0cf-606657fc2c42;Source = {Id = cc7c6510-d49b-28d9-e0bc-d5350a2c76a8;PortNumber = null;PortType = Output;HostId = 8078a917-236f-5a40-18a6-8e2d6a1458f5};Target = {Id = 2b224026-609a-5eae-6885-ff9820dbae5f;PortNumber = null;PortType = Input;HostId = fbfb4202-9816-f214-0401-da18caddeb0f};Vertices = [152,135; 254,135]} +] +""" + +def applyAll(functions, init): + res = init + for f in functions: + res = f(res) + return res + +def addQuotesId(str): + return re.sub(r'Id = ([0-9a-z\-]*)', r'Id = "\1"', str) + +def addQuotesLabel(str): + return re.sub(r'Label = ([0-9a-zA-Z\-]*)', r'Label = "\1"', str) + +def addPortTypeDot(str): + return re.sub(r'PortType = (Input|Output)', r'PortType = PortType.\1', str) + +def replaceNull(str): + return re.sub(r'PortNumber = null;', r'PortNumber = None;', str) + +def replacePortNumberSome(str): + return re.sub(r'PortNumber = (\d);', r'PortNumber = Some \1;', str) + +def replaceCustomName(str): + return re.sub(r'Name = ([0-9a-zA-Z\-]*)', r'Name = "\1"', str) + +def replaceLabels(str): + return re.sub(r'InputLabels = [([0-9a-zA-Z\-]*); ]', r'Label = "\1"', str) + +def replaceFloat(str): + return re.sub(r'(\d\d+)(,|;|])', r'\1.0\2', str) + +functions = [ + addQuotesId, + addQuotesLabel, + addPortTypeDot, + replaceNull, + replacePortNumberSome, + replaceCustomName, + replaceFloat, +] + +print(applyAll(functions, state)) diff --git a/Tests/paket.references b/Tests/paket.references new file mode 100644 index 0000000..5709242 --- /dev/null +++ b/Tests/paket.references @@ -0,0 +1,13 @@ +group Electron + Fable.Core + Fable.Browser.Dom + Fable.Electron + Fable.Elmish + Fable.Elmish.React + Fable.Elmish.Debugger + Fable.Elmish.HMR + Fable.Node + Fable.Promise + Fable.React + Fulma + Fable.SimpleJson diff --git a/build.cmd b/build.cmd new file mode 100644 index 0000000..0927384 --- /dev/null +++ b/build.cmd @@ -0,0 +1,6 @@ +@echo off +cls +dotnet tool restore +dotnet paket install +:: dotnet restore build.proj +dotnet fake build -t %* \ No newline at end of file diff --git a/build.fsx b/build.fsx new file mode 100644 index 0000000..f9eaf0e --- /dev/null +++ b/build.fsx @@ -0,0 +1,99 @@ +#r "paket: groupref FakeBuild //" +#load ".fake/build.fsx/intellisense.fsx" + +#if !FAKE +#r "netstandard" +#r "Facades/netstandard" // https://github.com/ionide/ionide-vscode-fsharp/issues/839#issuecomment-396296095 +#endif + +open System +open Fake.Core +open Fake.Core.TargetOperators +open Fake.DotNet +open Fake.IO +open Fake.IO.Globbing.Operators +open Fake.IO.FileSystemOperators +open Fake.JavaScript + +Target.create "CleanDev" (fun _ -> + !! "src/**/bin" + ++ "src/**/obj" + ++ "dist" + ++ ".fable" + |> Shell.cleanDirs +) + +Target.create "Clean" (fun _ -> + !! "src/**/bin" + ++ "src/**/obj" + ++ "dist" + ++ ".fable" + |> Shell.cleanDirs + Target.run 1 "KillZombies" [] +) + +Target.create "CleanFableJS" <| fun _ -> + !! (__SOURCE_DIRECTORY__ @@ "src/**/*.fs.js") + ++ (__SOURCE_DIRECTORY__ @@ "src/**/*.map") + |> Seq.toList + |> File.deleteAll + +Target.create "CleanNode" <| fun _ -> + Shell.cleanDir (__SOURCE_DIRECTORY__ @@ "node_modules") + File.delete (__SOURCE_DIRECTORY__ @@ "package-lock.json") + +Target.create "DotnetRestore" (fun _ -> + Shell.Exec("dotnet","restore issie.sln") |> ignore) + +Target.create "NpmInstall" (fun _ -> + Npm.install id +) + +Target.create "Build" (fun _ -> + Npm.run "compile" id +) + +Target.create "Dev" (fun _ -> + Npm.run "dev" id +) + +Target.create "Dist" (fun _ -> + Npm.run "dist" id +) + +Target.create "DistDir" (fun _ -> + Npm.run "dist:dir" id +) + +Target.create "KillZombies" <| fun _ -> + Fake.Core.Process.killAllByName "issie.exe" + Fake.Core.Process.killAllByName "node" + Fake.Core.Process.killAllByName "dotnet" + +// Build order + +"CleanFableJS" + ==> "Clean" + +"CleanFableJS" + ==> "CleanDev" + +"CleanDev" + ==> "DotnetRestore" + ==> "NpmInstall" + ==> "Build" + +"NpmInstall" + ==> "Dev" + +"NpmInstall" + ==> "Dist" + +"NpmInstall" + ==> "DistDir" + +"CleanFableJS" + ==> "dev" + +// start build +Target.runOrDefaultWithArguments "Dev" diff --git a/build.fsx.lock b/build.fsx.lock new file mode 100644 index 0000000..42d6cd2 --- /dev/null +++ b/build.fsx.lock @@ -0,0 +1,5 @@ +STORAGE: NONE +RESTRICTION: || (== net6.0) (== netstandard2.0) +NUGET + remote: https://api.nuget.org/v3/index.json + FSharp.Core (6.0.1) diff --git a/build.old.fsx b/build.old.fsx new file mode 100644 index 0000000..ff593de --- /dev/null +++ b/build.old.fsx @@ -0,0 +1,785 @@ +// -------------------------------------------------------------------------------------- +// FAKE build script +// -------------------------------------------------------------------------------------- +#nowarn "0213" +#r "paket: groupref FakeBuild //" +#load "./tools/FSharpLint.fs" +#load "./tools/ElectronTools.fs" +#load "./tools/Updating.fs" +#load "./.fake/build.fsx/intellisense.fsx" + +open BlackFox.CommandLine +open Fake.Core +open Fake.Core.TargetOperators +open Fake.DotNet +open Fake.JavaScript +open Fake.IO +open Fake.IO.FileSystemOperators +open Fake.IO.Globbing.Operators +open Fake.Net.Http +open Fake.Tools +open Fantomas.FakeHelpers +open Fantomas.FormatConfig +open Tools.Electron +open Tools.Linting +open Tools.Updating +open System +open System.IO + +// The name of the project +// (used by attributes in AssemblyInfo, name of a NuGet package and directory in 'src') +let project = "issie" + +// Short summary of the project +// (used as description in AssemblyInfo and as a short summary for NuGet package) +let summary = "Schematic editor and Simulator" + +// Author(s) of the project +let author = "tomcl" + +// File system information +let solutionFile = "issie.sln" + +// Build docs website root +let website = "https://tomcl.github.io/issie/docs" + +// Github repository +let repo = @"https://github.com/tomcl/issie" + +// Web or JS related fs projects +// Projects that have bindings to other languages where name linting needs to be more relaxed. +let relaxedNameLinting = + [ (__SOURCE_DIRECTORY__ @@ "src/Electron/**/*.fs") ] + +let netCoreVersions = [ "netcoreapp3.1" ] + +// OS runtime targets +let runTimes = ["win-x64";"linux-x64"] + +// Read additional information from the release notes document +let release = ReleaseNotes.load (__SOURCE_DIRECTORY__ @@ "RELEASE_NOTES.md") + +// Helper active pattern for project types +let (|Fsproj|Csproj|Vbproj|Shproj|) (projFileName:string) = + match projFileName with + | f when f.EndsWith("fsproj") -> Fsproj + | f when f.EndsWith("csproj") -> Csproj + | f when f.EndsWith("vbproj") -> Vbproj + | f when f.EndsWith("shproj") -> Shproj + | _ -> failwith (sprintf "Project file %s not supported. Unknown project type." projFileName) + +let tools = __SOURCE_DIRECTORY__ @@ "tools" +let srcGlob = __SOURCE_DIRECTORY__ @@ "src/**/*.??proj" +let fsSrcGlob = __SOURCE_DIRECTORY__ @@ "src/**/*.fs" +let fsTestGlob = __SOURCE_DIRECTORY__ @@ "tests/**/*.fs" +let bin = __SOURCE_DIRECTORY__ @@ "bin" +let temp = __SOURCE_DIRECTORY__ @@ "temp" +let objFolder = __SOURCE_DIRECTORY__ @@ "obj" +let dist = __SOURCE_DIRECTORY__ @@ "dist" +let fable = __SOURCE_DIRECTORY__ @@ ".fable" +let fsProjGlob = + !! (__SOURCE_DIRECTORY__ @@ "src/**/*.fsproj") + ++ (__SOURCE_DIRECTORY__ @@ "tests/**/*.fsproj") + +let foldExcludeGlobs (g: IGlobbingPattern) (d: string) = g -- d +let foldIncludeGlobs (g: IGlobbingPattern) (d: string) = g ++ d + +let fsSrcAndTest = + !! fsSrcGlob + ++ fsTestGlob + -- (__SOURCE_DIRECTORY__ @@ "src/**/obj/**") + -- (__SOURCE_DIRECTORY__ @@ "tests/**/obj/**") + -- (__SOURCE_DIRECTORY__ @@ "src/**/AssemblyInfo.*") + -- (__SOURCE_DIRECTORY__ @@ "src/**/**/AssemblyInfo.*") + +let fsRelaxedNameLinting = + let baseGlob s = + !! s + -- (__SOURCE_DIRECTORY__ @@ "src/**/AssemblyInfo.*") + -- (__SOURCE_DIRECTORY__ @@ "src/**/obj/**") + -- (__SOURCE_DIRECTORY__ @@ "tests/**/obj/**") + match relaxedNameLinting with + | [h] when relaxedNameLinting.Length = 1 -> baseGlob h |> Some + | h::t -> List.fold foldIncludeGlobs (baseGlob h) t |> Some + | _ -> None + +let failOnBadExitAndPrint (p : ProcessResult) = + if p.ExitCode <> 0 then + p.Errors |> Seq.iter Trace.traceError + failwithf "failed with exitcode %d" p.ExitCode + +module dotnet = + let tool optionConfig command args = + DotNet.exec (fun p -> { p with WorkingDirectory = tools} |> optionConfig ) (sprintf "%s" command) args + |> failOnBadExitAndPrint + + let femto optionConfig args = + tool optionConfig (!!(__SOURCE_DIRECTORY__ @@ "packages/tooling/Femto/tools/**/**/Femto.dll") |> Seq.head) args + +let setCmd f args = + match Environment.isWindows with + | true -> Command.RawCommand(f, Arguments.OfArgs args) + | false -> Command.RawCommand("mono", Arguments.OfArgs (f::args)) + +let configuration() = + FakeVar.getOrDefault "configuration" "Release" + +let getEnvFromAllOrNone (s: string) = + let envOpt (envVar: string) = + if String.isNullOrEmpty envVar then None + else Some(envVar) + + let procVar = Environment.GetEnvironmentVariable(s) |> envOpt + let userVar = Environment.GetEnvironmentVariable(s, EnvironmentVariableTarget.User) |> envOpt + let machVar = Environment.GetEnvironmentVariable(s, EnvironmentVariableTarget.Machine) |> envOpt + + match procVar,userVar,machVar with + | Some(v), _, _ + | _, Some(v), _ + | _, _, Some(v) + -> Some(v) + | _ -> None + + +// -------------------------------------------------------------------------------------- +// Initialisation and fixup actions + +Target.create "Init" <| fun _ -> + Fake.IO.File.delete (__SOURCE_DIRECTORY__ @@ ".paket/Paket.Restore.Targets") + Fake.IO.Directory.delete (__SOURCE_DIRECTORY__ @@ "packet_files") + +Target.create "KillCreated" <| fun _ -> + Fake.Core.Process.killAllCreatedProcesses() + +Target.create "KillZombies" <| fun _ -> + Fake.Core.Process.killAllByName "issie.exe" + Fake.Core.Process.killAllByName "node" + Fake.Core.Process.killAllByName "dotnet" + + + +// -------------------------------------------------------------------------------------- +// Set configuration mode based on target + +Target.create "ConfigDebug" <| fun _ -> + FakeVar.set "configuration" "Debug" + +Target.create "ConfigRelease" <| fun _ -> + FakeVar.set "configuration" "Release" + +// -------------------------------------------------------------------------------------- +// Generate assembly info files with the right version & up-to-date information + +Target.create "AssemblyInfo" <| fun _ -> + let getAssemblyInfoAttributes projectName = + [ AssemblyInfo.Title (projectName) + AssemblyInfo.Product project + AssemblyInfo.Description summary + AssemblyInfo.Version release.AssemblyVersion + AssemblyInfo.FileVersion release.AssemblyVersion + AssemblyInfo.Configuration <| configuration() + AssemblyInfo.InternalsVisibleTo (sprintf "%s.Tests" projectName) ] + + let getProjectDetails projectPath = + let projectName = Path.GetFileNameWithoutExtension(projectPath) + ( projectPath, + projectName, + Path.GetDirectoryName(projectPath), + (getAssemblyInfoAttributes projectName) + ) + + !! srcGlob + |> Seq.map getProjectDetails + |> Seq.iter (fun (projFileName, _, folderName, attributes) -> + match projFileName with + | Fsproj -> AssemblyInfoFile.createFSharp (folderName "AssemblyInfo.fs") attributes + | Csproj -> AssemblyInfoFile.createCSharp ((folderName "Properties") "AssemblyInfo.cs") attributes + | Vbproj -> AssemblyInfoFile.createVisualBasic ((folderName "My Project") "AssemblyInfo.vb") attributes + | Shproj -> () ) + +// -------------------------------------------------------------------------------------- +// Update package.json version & name + +Target.create "PackageJson" <| fun _ -> + let setValues (current: Json.JsonPackage) = + { current with + Name = Str.toKebabCase project |> Some + Description = summary |> Some + Version = release.NugetVersion |> Some + Repository = + match current.Repository with + | Some(r) -> + { r with + Json.RepositoryValue.Type = "git" |> Some + Json.RepositoryValue.Url = repo + ".git" |> Some } + | _ -> + { Json.RepositoryValue.Type = "git" |> Some + Json.RepositoryValue.Url = repo + ".git" |> Some + Json.RepositoryValue.Directory = None } + |> Some + Author = author |> Some + License = (File.readLine(__SOURCE_DIRECTORY__ @@ "LICENSE.md").Split(' ')) |> Array.head |> Some + Bugs = { Json.BugsValue.Url = (repo + "/issues" |> Some) } |> Some + Homepage = repo |> Some } + + Json.setJsonPkg setValues + +// -------------------------------------------------------------------------------------- +// Copies binaries from default VS location to expected bin folder +// But keeps a subdirectory structure for each project in the +// src folder to support multiple project outputs + +Target.create "CopyBinaries" <| fun _ -> + !! srcGlob + -- (__SOURCE_DIRECTORY__ @@ "src/**/*.shproj") + -- (__SOURCE_DIRECTORY__ @@ "src/**/Electron.Fable.fsproj") + |> Seq.map (fun f -> ((Path.getDirectory f) @@ "bin" @@ configuration(), "bin" @@ (Path.GetFileNameWithoutExtension f))) + |> Seq.iter (fun (fromDir, toDir) -> Shell.copyDir toDir fromDir (fun _ -> true)) + +// -------------------------------------------------------------------------------------- +// Clean tasks + +Target.create "Clean" <| fun _ -> + let clean() = + !! (__SOURCE_DIRECTORY__ @@ "tests/**/bin") + ++ (__SOURCE_DIRECTORY__ @@ "tests/**/obj") + ++ (__SOURCE_DIRECTORY__ @@ "tools/bin") + ++ (__SOURCE_DIRECTORY__ @@ "tools/obj") + ++ (__SOURCE_DIRECTORY__ @@ "src/**/bin") + ++ (__SOURCE_DIRECTORY__ @@ "src/**/obj") + |> Seq.toList + |> List.append [bin; temp; objFolder; dist; fable] + |> Shell.cleanDirs + TaskRunner.runWithRetries clean 99 + +Target.create "CleanDocs" <| fun _ -> + let clean() = + Shell.cleanDirs ["docs"] + TaskRunner.runWithRetries clean 99 + +Target.create "PostBuildClean" <| fun _ -> + let clean() = + !! srcGlob + -- (__SOURCE_DIRECTORY__ @@ "src/**/*.shproj") + |> Seq.map ( + (fun f -> (Path.getDirectory f) @@ "bin" @@ configuration()) + >> (fun f -> Directory.EnumerateDirectories(f) |> Seq.toList ) + >> (fun fL -> fL |> List.map (fun f -> Directory.EnumerateDirectories(f) |> Seq.toList))) + |> (Seq.concat >> Seq.concat) + |> Seq.iter Directory.delete + TaskRunner.runWithRetries clean 99 + +Target.create "PostPublishClean" <| fun _ -> + let clean() = + !! (__SOURCE_DIRECTORY__ @@ "src/**/bin" @@ configuration() @@ "/**/publish") + |> Seq.iter Directory.delete + TaskRunner.runWithRetries clean 99 + +Target.create "CleanElectronBin" <| fun _ -> + let netCores = + netCoreVersions + |> List.map (fun s -> __SOURCE_DIRECTORY__ @@ "bin/Core" @@ s) + + let clean() = + !! (__SOURCE_DIRECTORY__ @@ "bin/Main") + ++ (__SOURCE_DIRECTORY__ @@ "bin/Renderer") + ++ (__SOURCE_DIRECTORY__ @@ "bin/Common") + ++ (__SOURCE_DIRECTORY__ @@ "bin/Simulator") + ++ (__SOURCE_DIRECTORY__ @@ "bin/WidthInferer") + |> List.ofSeq + |> Shell.deleteDirs + + let runtimeDirs = + runTimes + |> List.map (fun s -> + netCores + |> List.map (fun coreVer -> coreVer @@ s @@ "**")) + |> List.concat + + match netCores |> List.tryHead with + | Some(h) -> + !! (h @@ "**") + |> (fun src -> List.fold foldIncludeGlobs src netCores.Tail) + |> (fun src -> List.fold foldExcludeGlobs src runtimeDirs) + |> Seq.iter Shell.rm + | _ -> () + TaskRunner.runWithRetries clean 99 + +// -------------------------------------------------------------------------------------- +// Restore tasks + +let restoreSolution () = + solutionFile + |> DotNet.restore id + +Target.create "Restore" <| fun _ -> + TaskRunner.runWithRetries restoreSolution 5 + +// Add task to make Node.js cli ready +Target.create "YarnInstall" <| fun _ -> + let setParams (defaults:Yarn.YarnParams) = + if Environment.isLinux then + defaults + else + { defaults with + Yarn.YarnParams.YarnFilePath = (__SOURCE_DIRECTORY__ @@ "packages/tooling/Yarnpkg.Yarn/content/bin/yarn.cmd") + } + Yarn.install setParams + +// Build Key.json if necessary from GD_KEY env variable +Target.create "BuildKeys" <| fun _ -> + let jsonPath = + __SOURCE_DIRECTORY__ @@ "src/Core/Key.json" + |> FileInfo.ofPath + let key = + let insertKey s = sprintf "{ \"key\": \"%s\" }" s + + getEnvFromAllOrNone "GD_KEY" + |> Option.map (insertKey) + |> defaultArg <| "" + TraceSecrets.register "" key + + if key <> "" && jsonPath.Exists |> not then + File.writeString false jsonPath.FullName key + else () + +// -------------------------------------------------------------------------------------- +// Build tasks + +Target.create "Build" <| fun _ -> + let setParams (defaults:MSBuildParams) = + { defaults with + Verbosity = Some(Quiet) + Targets = ["Build"] + Properties = + [ + "Optimize", "True" + "DebugSymbols", "True" + "Configuration", configuration() + "Version", release.AssemblyVersion + "GenerateDocumentationFile", "true" + "DependsOnNETStandard", "true" + ] + } + restoreSolution() + MSBuild.build setParams solutionFile + +Target.create "BuildElectron" <| fun _ -> + Npm.exec "rebuild node-sass" id + Yarn.exec "compile" id + +// Run Dev mode +Target.create "Dev" <| fun _ -> + Yarn.exec "dev" id + +// Build artifacts +Target.create "DistWin" <| fun _ -> + Yarn.exec "distwin" id + +// Build artifacts +Target.create "DistMac" <| fun _ -> + Yarn.exec "distmac" id + +// Gets latest docker image to build for linux +Target.create "PullDockerImage" <| fun _ -> + CmdLine.Empty + |> CmdLine.append "pull" + |> CmdLine.append "electronuserland/builder" + |> CmdLine.toString + |> CreateProcess.fromRawCommandLine "docker" + |> CreateProcess.ensureExitCodeWithMessage "Pulling electronuserland/builder docker container failed." + |> Proc.run + |> ignore + +// Build artifacts +Target.create "DistLinux" <| fun _ -> + let sandboxPath = @"./node_modules/electron/dist/chrome-sandbox" + + CmdLine.Empty + |> CmdLine.append "run" + |> CmdLine.append "--rm" + |> CmdLine.appendRaw (sprintf "-v %s:/project" __SOURCE_DIRECTORY__) + |> CmdLine.appendRaw "-v electron:/root/.cache/electron" + |> CmdLine.appendRaw "-v electron-builder:/root/.cache/electron-builder electronuserland/builder" + |> CmdLine.appendRaw (sprintf "/bin/bash -c \"chown -R root %s && chmod 4755 %s && yarn --link-duplicates --pure-lockfile && yarn distLinux\"" sandboxPath sandboxPath) + |> CmdLine.toString + |> CreateProcess.fromRawCommandLine "docker" + |> CreateProcess.ensureExitCodeWithMessage "Failed to build linux image." + |> Proc.run + |> ignore + +// -------------------------------------------------------------------------------------- +// Create differentials for updating + +Target.create "CreateDiffs" <| fun _ -> + let latestTag = (Git.CommandHelper.runSimpleGitCommand __SOURCE_DIRECTORY__ "describe --tag").Split('-').[0] + let latestRelease = + if Version(release.NugetVersion) <= Version(latestTag.Substring(1)) then + failwith "Cannot create diff of older version" + else + sprintf "https://github.com/Shmew/MordhauBuddy/releases/download/%s" latestTag + + let downloadSignature (fi: FileInfo) = + let file = + match fi.Extension with + | ext when ext = ".exe" -> sprintf "MordhauBuddy.Setup.%s%s.sig" (latestTag.Substring(1)) ext + | ext when ext = ".AppImage" -> sprintf "MordhauBuddy-%s%s.sig" (latestTag.Substring(1)) ext + | _ -> failwith "Invalid file extention for generating delta" + + sprintf "%s/%s" latestRelease file + |> downloadFile (fi.Directory.FullName @@ file) + + !! (__SOURCE_DIRECTORY__ @@ "dist/linux-x64/*.AppImage") + ++ (__SOURCE_DIRECTORY__ @@ "dist/win-x64/*.exe") + |> List.ofSeq + |> List.distinct + |> List.iter (fun f -> + let fi = FileInfo.ofPath(f) + genSigNew (sprintf "%s.sig" fi.Name) fi + + downloadSignature fi + |> FileInfo.ofPath + |> genDelta fi) + +// -------------------------------------------------------------------------------------- +// Publish net core applications + +Target.create "PublishDotNet" <| fun _ -> + let runPublish (project: string) (framework: string) = + let buildWithRunTime (rt: string) = + let setParams (defaults:MSBuildParams) = + { defaults with + Verbosity = Some(Quiet) + Targets = ["Publish"] + Properties = + [ + "Optimize", "True" + "DebugSymbols", "True" + "Configuration", configuration() + "Version", release.AssemblyVersion + "GenerateDocumentationFile", "true" + "TargetFramework", framework + "SelfContained", "true" + "RuntimeIdentifier", rt + ] + } + MSBuild.build setParams project + runTimes |> List.iter buildWithRunTime + + !! srcGlob + -- (__SOURCE_DIRECTORY__ @@ "src/**/*.shproj") + -- (__SOURCE_DIRECTORY__ @@ "src/**/*.vbproj") + |> Seq.map + ((fun f -> (((Path.getDirectory f) @@ "bin" @@ configuration()), f) ) + >> + (fun f -> + Directory.EnumerateDirectories(fst f) + |> Seq.filter (fun frFolder -> frFolder.Contains("netcoreapp")) + |> Seq.map (fun frFolder -> DirectoryInfo(frFolder).Name), snd f)) + |> Seq.iter (fun (l,p) -> l |> Seq.iter (runPublish p)) + +// -------------------------------------------------------------------------------------- +// Lint and format source code to ensure consistency + +Target.create "Format" <| fun _ -> + let config = + { FormatConfig.Default with + PageWidth = 120 + SpaceBeforeColon = false } + + fsSrcAndTest + |> List.ofSeq + |> formatCode config + |> Async.RunSynchronously + |> printfn "Formatted files: %A" + +Target.create "Lint" <| fun _ -> + fsSrcAndTest + -- (__SOURCE_DIRECTORY__ @@ "src/**/AssemblyInfo.*") + |> (fun src -> List.fold foldExcludeGlobs src relaxedNameLinting) + |> (fun fGlob -> + match fsRelaxedNameLinting with + | Some(glob) -> + [(false, fGlob); (true, glob)] + | None -> [(false, fGlob)]) + |> Seq.map (fun (b,glob) -> (b,glob |> List.ofSeq)) + |> List.ofSeq + |> FSharpLinter.lintFiles (__SOURCE_DIRECTORY__ @@ "bin/LintResults.xml") + +// -------------------------------------------------------------------------------------- +// Validate JavaScript dependencies + +Target.create "ValidateJSPackages" <| fun _ -> + let validate () = + fsProjGlob + |> Seq.iter (fun file -> + dotnet.femto id + (sprintf "--resolve %s" file)) + TaskRunner.runWithRetries validate 5 + +// -------------------------------------------------------------------------------------- +// Run the unit test binaries + +Target.create "RunTests" <| fun _ -> + !! ("tests/**/bin" @@ configuration() @@ "**" @@ "*Tests.exe") + |> Seq.iter (fun f -> + CreateProcess.fromCommand(setCmd f []) + |> CreateProcess.withTimeout (TimeSpan.MaxValue) + |> CreateProcess.ensureExitCodeWithMessage "Tests failed." + |> Proc.run + |> ignore) + +// -------------------------------------------------------------------------------------- +// Generate Paket load scripts +Target.create "LoadScripts" <| fun _ -> + let frameworks = + __SOURCE_DIRECTORY__ @@ "bin" + |> Directory.EnumerateDirectories + |> Seq.map (fun d -> + Directory.EnumerateDirectories d + |> Seq.map (fun f -> DirectoryInfo(f).Name) + |> List.ofSeq) + |> List.ofSeq + |> List.reduce List.append + |> List.distinct + |> List.reduce (fun acc elem -> sprintf "%s --framework %s" elem acc) + |> function + | e when e.Length > 0 -> + Some (sprintf "--framework %s" e) + | _ -> None + + let arguments = + [Some("generate-load-scripts"); frameworks] + |> List.choose id + |> List.reduce (fun acc elem -> sprintf "%s %s" acc elem) + + arguments + |> CreateProcess.fromRawCommandLine ((__SOURCE_DIRECTORY__ @@ ".paket") @@ "paket.exe") + |> CreateProcess.withTimeout (TimeSpan.MaxValue) + |> CreateProcess.ensureExitCodeWithMessage "Failed to generate paket load scripts." + |> Proc.run + |> ignore + +// -------------------------------------------------------------------------------------- +// Generate the documentation + + +// Paths with template/source/output locations +let content = __SOURCE_DIRECTORY__ @@ "docsrc/content" +let output = __SOURCE_DIRECTORY__ @@ "docs" +let files = __SOURCE_DIRECTORY__ @@ "docsrc/files" +let templates = __SOURCE_DIRECTORY__ @@ "docsrc/tools/templates" +let formatting = __SOURCE_DIRECTORY__ @@ "packages/formatting/FSharp.Formatting" +let toolPath = __SOURCE_DIRECTORY__ @@ "packages/formatting/FSharp.Formatting.CommandTool/tools/fsformatting.exe" +let docTemplate = "docpage.cshtml" + +Target.create "LocalDocs" <| fun _ -> + FakeVar.set "Website" website // for now we never generate local docs +Target.create "ReleaseDocs" <| fun _ -> + FakeVar.set "Website" website + +// Specify more information about your project +let info () = + [ "project-name", project + "project-author", author + "project-summary", summary + "project-repo", repo + "root", FakeVar.getOrDefault "Website" website ] + +let referenceBinaries = [] + +let layoutRootsAll = new Collections.Generic.Dictionary() +layoutRootsAll.Add("en",[ templates; + formatting @@ "templates" + formatting @@ "templates/reference" ]) + +Target.create "ReferenceDocs" <| fun _ -> + Directory.ensure (output @@ "reference") + + let lDirs = + DirectoryInfo.getSubDirectories <| DirectoryInfo bin + |> Array.map DirectoryInfo.getSubDirectories + |> Array.reduce Array.append + |> Array.map (fun x -> x.FullName.ToLower()) + |> List.ofArray + printfn "lDirs=%A" lDirs + let binaries () = + let manuallyAdded = + referenceBinaries + |> List.map (fun b -> bin @@ b) + + let conventionBased = + DirectoryInfo.getSubDirectories <| DirectoryInfo bin + |> Array.collect (fun d -> + let name, dInfo = + let netFrameworkBin = + DirectoryInfo.getSubDirectories d |> Array.filter(fun x -> x.FullName.ToLower().Contains("net4")) + let netCoreBin = + DirectoryInfo.getSubDirectories d |> Array.filter(fun x -> x.FullName.ToLower().Contains("netcoreapp")) + + match netFrameworkBin.Length > 0 with + | true -> + d.Name, netFrameworkBin |> Array.head + | false -> + d.Name, netCoreBin |> Array.head + + dInfo.GetFiles() + |> Array.filter (fun x -> + x.Name.ToLower() = (sprintf "%s.dll" name).ToLower() + || x.Name.ToLower() = (sprintf "%s.exe" name).ToLower()) + |> Array.map (fun x -> x.FullName)) + |> List.ofArray + + conventionBased @ manuallyAdded + printfn "Binaries=%A" (binaries()) + binaries() + |> FSFormatting.createDocsForDlls (fun args -> + { args with + OutputDirectory = output @@ "reference" + LayoutRoots = layoutRootsAll.["en"] + ProjectParameters = info() + LibDirs = lDirs + ToolPath = toolPath + SourceRepository = repo @@ "tree/master" }) + +let copyFiles () = + Shell.copyRecursive files output true + |> Trace.logItems "Copying file: " + Directory.ensure (output @@ "content") + Shell.copyRecursive (formatting @@ "styles") (output @@ "content") true + |> Trace.logItems "Copying styles and scripts: " + +Target.create "Docs" <| fun _ -> + File.delete "docsrc/content/release-notes.md" + Shell.copyFile "docsrc/content/" "RELEASE_NOTES.md" + Shell.rename "docsrc/content/release-notes.md" "docsrc/content/RELEASE_NOTES.md" + + DirectoryInfo.getSubDirectories (DirectoryInfo.ofPath templates) + |> Seq.iter (fun d -> + let name = d.Name + if name.Length = 2 || name.Length = 3 then + layoutRootsAll.Add( + name, [templates @@ name + formatting @@ "templates" + formatting @@ "templates/reference" ])) + copyFiles () + + for dir in [ content ] do + let langSpecificPath(lang, path:string) = + path.Split([|'/'; '\\'|], StringSplitOptions.RemoveEmptyEntries) + |> Array.exists(fun i -> i = lang) + let layoutRoots = + let key = layoutRootsAll.Keys |> Seq.tryFind (fun i -> langSpecificPath(i, dir)) + match key with + | Some lang -> layoutRootsAll.[lang] + | None -> layoutRootsAll.["en"] // "en" is the default language + + FSFormatting.createDocs (fun args -> + { args with + Source = content + OutputDirectory = output + LayoutRoots = layoutRoots + ProjectParameters = info() + Template = docTemplate }) + +Target.create "GenerateDocs" ignore + +// -------------------------------------------------------------------------------------- +// Release Scripts + +Target.create "GitPush" <| fun p -> + let msg = + p.Context.Arguments + |> List.choose (fun s -> + match s.StartsWith("--Msg=") with + | true -> Some(s.Substring 6) + | false -> None) + |> List.tryHead + |> function + | Some(s) -> s + | None -> (sprintf "Bump version to %s" release.NugetVersion) + + Git.Staging.stageAll "" + Git.Commit.exec "" msg + Git.Branches.push "" + +Target.create "GitTag" <| fun _ -> + Git.Branches.tag "" release.NugetVersion + Git.Branches.pushTag "" "origin" release.NugetVersion + +// -------------------------------------------------------------------------------------- +// Run all targets by default. Invoke 'build -t ' to override + +Target.create "All" ignore +Target.create "Release" ignore +Target.create "UpdateDocs" ignore +Target.create "AllDev" ignore +Target.create "QDev" <| fun _ -> + Yarn.exec "dev" id + +"Clean" + ==> "AssemblyInfo" + ==> "Restore" + ==> "YarnInstall" + ==> "Build" + ==> "BuildElectron" + ==> "PostBuildClean" + ==> "CopyBinaries" + +"Build" ==> "RunTests" + +"Build" + ==> "PostBuildClean" + ==> "PublishDotNet" + ==> "PostPublishClean" + ==> "CopyBinaries" + +"Restore" ==> "Lint" +"Restore" ==> "Format" + +"Lint" + ?=> "Build" + ?=> "RunTests" + ?=> "CleanDocs" + +"CopyBinaries" + ==> "CleanDocs" + ==> "Docs" + ==> "ReferenceDocs" + ==> "GenerateDocs" + ?=> "CleanElectronBin" + +"Clean" + ==> "GitPush" + ?=> "GitTag" + +"All" <== [ "CleanElectronBin"] + +"AllDev" <== ["CleanElectronBin"] + +"All" ?=> "Release" + +"LocalDocs" ?=> "All" +"ReleaseDocs" ?=> "All" + +"ConfigDebug" ?=> "Clean" +"ConfigRelease" ?=> "Clean" + +"PullDockerImage" + ==> "DistLinux" + + +"YarnInstall" + ==> "DistWin" + + +"DistWin" ?=> "DistLinux" + +"Dev" <== ["All"; "LocalDocs"; "ConfigDebug"] + +"DistWin" <== ["All"; "ConfigRelease"] +"DistLinux" <== ["All"; "ConfigRelease"] +"Release" <== ["All"; "ConfigRelease"; "DistWin"; "DistLinux"] +"UpdateDocs" <== ["All"; "ReleaseDocs"; "ConfigRelease"] + +Target.runOrDefaultWithArguments "Dev" diff --git a/build.proj b/build.proj new file mode 100644 index 0000000..b677fc3 --- /dev/null +++ b/build.proj @@ -0,0 +1,25 @@ + + + + + netstandard2.0 + true + + + + $([System.IO.Path]::GetFullPath("$(MSBuildThisFileDirectory)")) + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..1d539a8 --- /dev/null +++ b/build.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +# to properly set Travis permissions: https://stackoverflow.com/questions/33820638/travis-yml-gradlew-permission-denied +# git update-index --chmod=+x fake.sh +# git commit -m "permission access for travis" + +set -eu +set -o pipefail + +dotnet tool restore +dotnet paket install +# dotnet restore build.proj + +if [ ! -f build.fsx ]; then + dotnet fake run init.fsx +fi + +dotnet fake build $@ \ No newline at end of file diff --git a/build/icon.png b/build/icon.png new file mode 100644 index 0000000..076ee0e Binary files /dev/null and b/build/icon.png differ diff --git a/docs/Contact.html b/docs/Contact.html new file mode 100644 index 0000000..42ccd3c --- /dev/null +++ b/docs/Contact.html @@ -0,0 +1,48 @@ + + + + + + Contact + + + + + + + + + + + + + + + + + + + +
+ +

+ If you encounter any problems using or downloading the software, please see the Gihub Issue page, or create a new issue on the ISSIE GitHub repository. + Any feedback and suggestions are also welcome! +


+ +
+ + + + diff --git a/docs/DeveloperInfo.html b/docs/DeveloperInfo.html new file mode 100644 index 0000000..427e272 --- /dev/null +++ b/docs/DeveloperInfo.html @@ -0,0 +1,64 @@ + + + + + + Developer Info + + + + + + + + + + + + + + + + + + + +
+ +

+ Marco's Dissertation or his Poster. +


+ + +
    +
  • Issie is designed to be usable without needing a User Manual. Developer information can be found in the + Github README. +
  • +

+ + + +

+ The project is hosted on Github where you can report issues, fork the project and submit pull + requests. Please take a look at the contribution guidelines for more information. Contact Tom Clarke + for more information about development. +


+ + + +
+ + + + diff --git a/docs/Download.html b/docs/Download.html new file mode 100644 index 0000000..afb1686 --- /dev/null +++ b/docs/Download.html @@ -0,0 +1,62 @@ + + + + + + Download + + + + + + + + + + + + + + + + + + + +
+ +

+ Latest stable release: Click here for the latest GitHub release page, where the latest .zip and .tar file can be found. +

+ Possibly unstable: Download latest master .zip +


+ + +

+ Currently no known incompatibilities. Linux users can run the windows .zip file under WINE. + See Getting Started for information about how to run the binaries. +


+ + +

+ All releases: Click here +
+
+ Latest release notes: Click here +

+
+ + + + diff --git a/docs/UserGuide.html b/docs/UserGuide.html new file mode 100644 index 0000000..3d52944 --- /dev/null +++ b/docs/UserGuide.html @@ -0,0 +1,85 @@ + + + + + + User Guide + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/blog.md b/docs/blog.md new file mode 100644 index 0000000..99a8091 --- /dev/null +++ b/docs/blog.md @@ -0,0 +1,2 @@ + + diff --git a/docs/community.html b/docs/community.html new file mode 100644 index 0000000..cdc8329 --- /dev/null +++ b/docs/community.html @@ -0,0 +1,62 @@ + + + + + Community + + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ +

Community

+

This presently just has the Announcements page, but more may be added in the future.

+

Announcements

+

*

+ + +
+
+ +
+
+
+ + diff --git a/docs/content/github-blue.png b/docs/content/github-blue.png new file mode 100644 index 0000000..57432a0 Binary files /dev/null and b/docs/content/github-blue.png differ diff --git a/docs/content/github.png b/docs/content/github.png new file mode 100644 index 0000000..5d48d83 Binary files /dev/null and b/docs/content/github.png differ diff --git a/docs/content/img/circuit.png b/docs/content/img/circuit.png new file mode 100644 index 0000000..fc18445 Binary files /dev/null and b/docs/content/img/circuit.png differ diff --git a/docs/content/img/circuit/RAMviewer.png b/docs/content/img/circuit/RAMviewer.png new file mode 100644 index 0000000..cb0cbc8 Binary files /dev/null and b/docs/content/img/circuit/RAMviewer.png differ diff --git a/docs/content/img/circuit/catalog.png b/docs/content/img/circuit/catalog.png new file mode 100644 index 0000000..a29ba19 Binary files /dev/null and b/docs/content/img/circuit/catalog.png differ diff --git a/docs/content/img/circuit/circuitcropped.png b/docs/content/img/circuit/circuitcropped.png new file mode 100644 index 0000000..e3d5607 Binary files /dev/null and b/docs/content/img/circuit/circuitcropped.png differ diff --git a/docs/content/img/circuit/dragindicator.png b/docs/content/img/circuit/dragindicator.png new file mode 100644 index 0000000..98f0414 Binary files /dev/null and b/docs/content/img/circuit/dragindicator.png differ diff --git a/docs/content/img/circuit/initialcanvas.png b/docs/content/img/circuit/initialcanvas.png new file mode 100644 index 0000000..01b8ec1 Binary files /dev/null and b/docs/content/img/circuit/initialcanvas.png differ diff --git a/docs/content/img/circuit/memoryeditor.png b/docs/content/img/circuit/memoryeditor.png new file mode 100644 index 0000000..d5b6b1b Binary files /dev/null and b/docs/content/img/circuit/memoryeditor.png differ diff --git a/docs/content/img/circuit/propertiesram.png b/docs/content/img/circuit/propertiesram.png new file mode 100644 index 0000000..058ae9d Binary files /dev/null and b/docs/content/img/circuit/propertiesram.png differ diff --git a/docs/content/img/circuit/propertiestab.png b/docs/content/img/circuit/propertiestab.png new file mode 100644 index 0000000..5f3131e Binary files /dev/null and b/docs/content/img/circuit/propertiestab.png differ diff --git a/docs/content/img/circuit/randomcircuit.png b/docs/content/img/circuit/randomcircuit.png new file mode 100644 index 0000000..44302f4 Binary files /dev/null and b/docs/content/img/circuit/randomcircuit.png differ diff --git a/docs/content/img/circuit/savebutton.png b/docs/content/img/circuit/savebutton.png new file mode 100644 index 0000000..ee48d05 Binary files /dev/null and b/docs/content/img/circuit/savebutton.png differ diff --git a/docs/content/img/circuit/simulation tab.png b/docs/content/img/circuit/simulation tab.png new file mode 100644 index 0000000..d20db85 Binary files /dev/null and b/docs/content/img/circuit/simulation tab.png differ diff --git a/docs/content/img/circuit/stepsimulation.png b/docs/content/img/circuit/stepsimulation.png new file mode 100644 index 0000000..1e32d03 Binary files /dev/null and b/docs/content/img/circuit/stepsimulation.png differ diff --git a/docs/content/img/circuit/waveformsimulation.png b/docs/content/img/circuit/waveformsimulation.png new file mode 100644 index 0000000..b659696 Binary files /dev/null and b/docs/content/img/circuit/waveformsimulation.png differ diff --git a/docs/content/img/circuit/wavesim.png b/docs/content/img/circuit/wavesim.png new file mode 100644 index 0000000..8f226f0 Binary files /dev/null and b/docs/content/img/circuit/wavesim.png differ diff --git a/docs/content/img/circuit/wavesimorder.png b/docs/content/img/circuit/wavesimorder.png new file mode 100644 index 0000000..83c48b8 Binary files /dev/null and b/docs/content/img/circuit/wavesimorder.png differ diff --git a/docs/content/img/circuit/wavesimramview.png b/docs/content/img/circuit/wavesimramview.png new file mode 100644 index 0000000..9e1853d Binary files /dev/null and b/docs/content/img/circuit/wavesimramview.png differ diff --git a/docs/content/img/circuit/wireerror.png b/docs/content/img/circuit/wireerror.png new file mode 100644 index 0000000..b70bada Binary files /dev/null and b/docs/content/img/circuit/wireerror.png differ diff --git a/docs/content/img/github-blue.png b/docs/content/img/github-blue.png new file mode 100644 index 0000000..57432a0 Binary files /dev/null and b/docs/content/img/github-blue.png differ diff --git a/docs/content/img/github.png b/docs/content/img/github.png new file mode 100644 index 0000000..5d48d83 Binary files /dev/null and b/docs/content/img/github.png differ diff --git a/docs/content/img/icon.ico b/docs/content/img/icon.ico new file mode 100644 index 0000000..498c5d6 Binary files /dev/null and b/docs/content/img/icon.ico differ diff --git a/docs/content/style.css b/docs/content/style.css new file mode 100644 index 0000000..a117fb1 --- /dev/null +++ b/docs/content/style.css @@ -0,0 +1,394 @@ +@import url(https://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans+Mono|Open+Sans:400,600,700); +@import url('https://fonts.googleapis.com/css2?family=Inconsolata:wght@200;300;400;500;600;700;800;900&display=swap'); +/* COLOUR THEME */ +/* + Backround (white): #FBFFFE + Highlight/secondary background (yellow): #FAA916 + Highlight (blue): #01ABAA + TextColour (off black): #272838 +*/ +/*-------------------------------------------------------------------------- + Formatting for F# code snippets +/*--------------------------------------------------------------------------*/ +/* strings --- and stlyes for other string related formats */ +span.s { + color: #E0E268; +} +/* printf formatters */ +span.pf { color:#E0C57F; } +/* escaped chars */ +span.e { color:#EA8675; } + +/* identifiers --- and styles for more specific identifier types */ +span.id { color:#d1d1d1; } +/* module */ +span.m { color:#43AEC6; } +/* reference type */ +span.rt { color:#43AEC6; } +/* value type */ +span.vt { color:#43AEC6; } +/* interface */ +span.if{ color:#43AEC6; } +/* type argument */ +span.ta { color:#43AEC6; } +/* disposable */ +span.d { color:#43AEC6; } +/* property */ +span.prop { color:#43AEC6; } +/* punctuation */ +span.p { color:#43AEC6; } +/* function */ +span.f { color:#e1e1e1; } +/* active pattern */ +span.pat { color:#4ec9b0; } +/* union case */ +span.u { color:#4ec9b0; } +/* enumeration */ +span.e { color:#4ec9b0; } +/* keywords */ +span.k { color:#FAB11D; } +/* comment */ +span.c { color:#808080; } +/* operators */ +span.o { color:#af75c1; } +/* numbers */ +span.n { color:#96C71D; } +/* line number */ +span.l { color:#80b0b0; } +/* mutable var or ref cell */ +span.v { color:#d1d1d1; font-weight: bold; } +/* inactive code */ +span.inactive { color:#808080; } +/* preprocessor */ +span.prep { color:#af75c1; } +/* fsi output */ +span.fsi { color:#808080; } + +/* omitted */ +span.omitted { + background:#3c4e52; + border-radius:5px; + color:#808080; + padding:0px 0px 1px 0px; +} +/* tool tip */ +div.tip { + background:#475b5f; + border-radius:4px; + font:11pt 'Droid Sans', arial, sans-serif; + padding:6px 8px 6px 8px; + display:none; + color:#d1d1d1; + pointer-events:none; +} +table.pre pre { + padding:0px; + margin:0px; + border:none; +} +table.pre, pre.fssnip, pre { + line-height:13pt; + border:1px solid #d8d8d8; + border-collapse:separate; + white-space:pre; + font: 9pt 'Droid Sans Mono',consolas,monospace; + width:90%; + margin:10px 20px 20px 20px; + background-color:#212d30; + padding:10px; + border-radius:5px; + color:#d1d1d1; + max-width: none; +} +pre.fssnip code { + font: 9pt 'Droid Sans Mono',consolas,monospace; +} +table.pre pre { + padding:0px; + margin:0px; + border-radius:0px; + width: 100%; +} +table.pre td { + padding:0px; + white-space:normal; + margin:0px; +} +table.pre td.lines { + width:30px; +} + +/*-------------------------------------------------------------------------- + Formatting for page & standard document content +/*--------------------------------------------------------------------------*/ + +body { + font-family: 'Inconsolata', 'Helvetica'; + margin: 0; + padding-top: 0px; + padding-bottom: 40px; +} + +pre { + word-wrap: inherit; +} + +/* Format the heading - nicer spacing etc. */ +.masthead { + overflow: hidden; +} +.masthead .muted a { + text-decoration:none; + color:#999999; +} +.masthead ul, .masthead li { + margin-bottom:0px; +} +.masthead .nav li { + margin-top: 15px; + font-size:110%; +} +.masthead h3 { + margin-bottom:5px; + font-size:170%; +} +hr { + margin:0px 0px 20px 0px; +} + +/* Make table headings and td.title bold */ +td.title, thead { + font-weight:bold; +} + +/* Format the right-side menu */ +#menu { + margin-top:50px; + font-size:11pt; + padding-left:20px; +} + +#menu .nav-header { + font-size:12pt; + color:#606060; + margin-top:20px; +} + +#menu li { + line-height:25px; +} + +/* -------- NAVIGATION BAR STYLE ---------- */ + +/* Add a black background color to the top navigation */ +.topnav { + background-color: #FAA916; + overflow: hidden; + line-height: 20px; + vertical-align: middle; + font-weight: 600; + flex-direction: column; +} + +/* Style the links inside the navigation bar */ +.topnav a { + float: left; + margin: 0.5%; + padding: 0.75%; + color: #272838; + text-align: center; + text-decoration: none; + font-size: 18px; + +} + +/* Change the color of links on hover */ +.topnav a:hover { + border-radius: 5px; + background-color: #FBFFFE; + color: #272838; +} + +/* Right-aligned section inside the top navigation */ +.topnav-right { + flex-direction: column; + overflow: hidden; + vertical-align: middle; +} + +.topnav-right a { + float: right; + margin: 0.5%; + padding: 0.75%; + color: #FBFFFE; + background-color: #01ABAA; + border: 1px solid #FBFFFE; + border-radius: 5px; +} + +/* -------- PANNEL STYLE ------- */ + +.IntroBackground { + margin-top: 0.5%; + background: url('../content/img/circuit/circuitcropped.png'); + clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 70%); +} + +.IntroLayer { + margin-top: 0.5%; + background-color: rgba(250, 169, 22, 0.8); + clip-path: polygon(0% 0%, 100% 0%, 100% 100%, 0% 70%); +} + +/* ------- GENERAL TEXT PARAGRAPH STYLE ------ */ +.GeneralText { + margin: 5%; + color: #272838; +} + + +/* -------- TABLE OF CONTENTS STYLE ------- */ + +#toc_container { + background: rgba(250, 169, 22, 0.65) none repeat scroll 0 0; + border: 3px solid #FAA916; + display: table; + margin-bottom: 1em; + padding: 20px; + width: auto; +} + +.toc_title { + font-weight: 700; + text-align: left; + color: #272838 +} + +#toc_container li, #toc_container ul, #toc_container ul li { + list-style: outside none none !important; + margin-bottom: 5px; +} + + +/* ------ GENERIC IMAGE FORMATTING -------- */ + +img { + max-width: 100%; + height: auto; + text-align: center; + width: 50%; + margin-left: auto; + margin-right: auto; + display: block; +} + + +/* ------- CLASSES TO ADD LINES BETWEEN SECTIONS -------- */ + +.section { + border-bottom: 1px solid #FAA916; +} + +#halfwidth { + width: 50%; +} + + +/* -------- List formatting --------- */ + +li{ + margin: 10px 0; +} + +/* Responsive layout - when the screen is less than 700px wide, make the two columns stack on top of each other instead of next to each other */ +@media screen and (max-width: 700px) { + .topnav { + flex-direction: column; + } + .topnav-right { + flex-direction: column; + } +} + +/* Responsive layout - when the screen is less than 400px wide, make the navigation links stack on top of each other instead of next to each other */ +@media screen and (max-width: 400px) { + .topnav-right { + float: none; + width: 100%; + } +} + +/* Change font sizes for headings etc. */ +#main h1 { font-size: 26pt; margin:10px 0px 15px 0px; font-weight:400; border: 1px solid #272838; border-width: 0 1px;} +#main h2 { font-size: 20pt; margin:20px 0px 0px 0px; font-weight:400; border-bottom: 1px solid #272838; } +#main h3 { font-size: 14pt; margin:15px 0px 0px 0px; font-weight:600; } +#main p { font-size: 11pt; margin:5px 0px 15px 0px; } +#main ul { font-size: 11pt; margin-top:10px; } +#main li { font-size: 11pt; margin: 5px 0px 5px 0px; } +#main strong { font-weight:700; } + + + +/*-------------------------------------------------------------------------- + Formatting for API reference +/*--------------------------------------------------------------------------*/ + +.type-list .type-name, .module-list .module-name { + width:25%; + font-weight:bold; +} +.member-list .member-name { + width:35%; +} +#main .xmldoc h2 { + font-size:14pt; + margin:10px 0px 0px 0px; +} +#main .xmldoc h3 { + font-size:12pt; + margin:10px 0px 0px 0px; +} +.github-link { + float:right; + text-decoration:none; +} +.github-link img { + border-style:none; + margin-left:10px; +} +.github-link .hover { display:none; } +.github-link:hover .hover { display:block; } +.github-link .normal { display: block; } +.github-link:hover .normal { display: none; } + +/*-------------------------------------------------------------------------- + Links +/*--------------------------------------------------------------------------*/ + +h1 a, h1 a:hover, h1 a:focus, +h2 a, h2 a:hover, h2 a:focus, +h3 a, h3 a:hover, h3 a:focus, +h4 a, h4 a:hover, h4 a:focus, +h5 a, h5 a:hover, h5 a:focus, +h6 a, h6 a:hover, h6 a:focus { color : inherit; text-decoration : inherit; outline:none } + +/*-------------------------------------------------------------------------- + Additional formatting for the homepage +/*--------------------------------------------------------------------------*/ + +#nuget { + margin-top:20px; + font-size: 11pt; + padding:20px; +} + +#nuget pre { + font-size:11pt; + -moz-border-radius: 0px; + -webkit-border-radius: 0px; + border-radius: 0px; + background: #404040; + border-style:none; + color: #e0e0e0; + margin-top:15px; +} diff --git a/docs/content/style_light.css b/docs/content/style_light.css new file mode 100644 index 0000000..0685b48 --- /dev/null +++ b/docs/content/style_light.css @@ -0,0 +1,227 @@ +@import url(https://fonts.googleapis.com/css?family=Droid+Sans|Droid+Sans+Mono|Open+Sans:400,600,700); + +/*-------------------------------------------------------------------------- + Formatting for F# code snippets +/*--------------------------------------------------------------------------*/ + +/* identifier */ +span.i { color:#000000; } +/* string */ +span.s { color:#a31515; } +/* keywords */ +span.k { color:#0000ff; } +/* comment */ +span.c { color:#008000; } +/* operators */ +span.o { color:#000000; } +/* numbers */ +span.n { color:#000000; } +/* line number */ +span.l { color:#96c2cd; } +/* type or module */ +span.t { color:#2b91af; } +/* function */ +span.f { color:#0000a0; } +/* DU case or active pattern */ +span.p { color:#800080; } +/* mutable var or ref cell */ +span.v { color:#000000; font-weight: bold; } +/* printf formatters */ +span.pf { color:#2b91af; } +/* escaped chars */ +span.e { color:#ff0080; } +/* mutable var or ref cell */ + + +/* inactive code */ +span.inactive { color:#808080; } +/* preprocessor */ +span.prep { color:#0000ff; } +/* fsi output */ +span.fsi { color:#808080; } + +/* omitted */ +span.omitted { + background:#3c4e52; + border-radius:5px; + color:#808080; + padding:0px 0px 1px 0px; +} +/* tool tip */ +div.tip { + background:#e5e5e5; + border-radius:4px; + font:9pt 'Droid Sans', arial, sans-serif; + padding:6px 8px 6px 8px; + display:none; + color:#000000; + pointer-events:none; +} +table.pre pre { + padding:0px; + margin:0px; + border:none; +} +table.pre, pre.fssnip, pre { + line-height:13pt; + border:1px solid #d8d8d8; + border-collapse:separate; + white-space:pre; + font: 10pt consolas,monospace; + width:90%; + margin:10px 20px 20px 20px; + background-color:#fdfdfd; + padding:10px; + border-radius:5px; + color:#000000; + max-width: none; +} +pre.fssnip code { + font: 9pt 'Droid Sans Mono',consolas,monospace; +} +table.pre pre { + padding:0px; + margin:0px; + border-radius:0px; + width: 100%; +} +table.pre td { + padding:0px; + white-space:normal; + margin:0px; +} +table.pre td.lines { + width:30px; +} + +/*-------------------------------------------------------------------------- + Formatting for page & standard document content +/*--------------------------------------------------------------------------*/ + +body { + font-family: 'Open Sans', serif; + padding-top: 0px; + padding-bottom: 40px; +} + +pre { + word-wrap: inherit; +} + +/* Format the heading - nicer spacing etc. */ +.masthead { + overflow: hidden; +} +.masthead .muted a { + text-decoration:none; + color:#999999; +} +.masthead ul, .masthead li { + margin-bottom:0px; +} +.masthead .nav li { + margin-top: 15px; + font-size:110%; +} +.masthead h3 { + margin-bottom:5px; + font-size:170%; +} +hr { + margin:0px 0px 20px 0px; +} + +/* Make table headings and td.title bold */ +td.title, thead { + font-weight:bold; +} + +/* Format the right-side menu */ +#menu { + margin-top:50px; + font-size:11pt; + padding-left:20px; +} + +#menu .nav-header { + font-size:12pt; + color:#606060; + margin-top:20px; +} + +#menu li { + line-height:25px; +} + +/* Change font sizes for headings etc. */ +#main h1 { font-size: 26pt; margin:10px 0px 15px 0px; font-weight:400; } +#main h2 { font-size: 20pt; margin:20px 0px 0px 0px; font-weight:400; } +#main h3 { font-size: 14pt; margin:15px 0px 0px 0px; font-weight:600; } +#main p { font-size: 11pt; margin:5px 0px 15px 0px; } +#main ul { font-size: 11pt; margin-top:10px; } +#main li { font-size: 11pt; margin: 5px 0px 5px 0px; } +#main strong { font-weight:700; } + +/*-------------------------------------------------------------------------- + Formatting for API reference +/*--------------------------------------------------------------------------*/ + +.type-list .type-name, .module-list .module-name { + width:25%; + font-weight:bold; +} +.member-list .member-name { + width:35%; +} +#main .xmldoc h2 { + font-size:14pt; + margin:10px 0px 0px 0px; +} +#main .xmldoc h3 { + font-size:12pt; + margin:10px 0px 0px 0px; +} +.github-link { + float:right; + text-decoration:none; +} +.github-link img { + border-style:none; + margin-left:10px; +} +.github-link .hover { display:none; } +.github-link:hover .hover { display:block; } +.github-link .normal { display: block; } +.github-link:hover .normal { display: none; } + +/*-------------------------------------------------------------------------- + Links +/*--------------------------------------------------------------------------*/ + +h1 a, h1 a:hover, h1 a:focus, +h2 a, h2 a:hover, h2 a:focus, +h3 a, h3 a:hover, h3 a:focus, +h4 a, h4 a:hover, h4 a:focus, +h5 a, h5 a:hover, h5 a:focus, +h6 a, h6 a:hover, h6 a:focus { color : inherit; text-decoration : inherit; outline:none } + +/*-------------------------------------------------------------------------- + Additional formatting for the homepage +/*--------------------------------------------------------------------------*/ + +#nuget { + margin-top:20px; + font-size: 11pt; + padding:20px; +} + +#nuget pre { + font-size:11pt; + -moz-border-radius: 0px; + -webkit-border-radius: 0px; + border-radius: 0px; + background: #404040; + border-style:none; + color: #e0e0e0; + margin-top:15px; +} diff --git a/docs/content/tips.js b/docs/content/tips.js new file mode 100644 index 0000000..2b125ba --- /dev/null +++ b/docs/content/tips.js @@ -0,0 +1,46 @@ +var currentTip = null; +var currentTipElement = null; + +function hideTip(evt, name, unique) { + var el = document.getElementById(name); + el.style.display = "none"; + currentTip = null; +} + +function findPos(obj) { + // no idea why, but it behaves differently in webbrowser component + if (window.location.search == "?inapp") + return [obj.offsetLeft + 10, obj.offsetTop + 30]; + + var curleft = 0; + var curtop = obj.offsetHeight; + while (obj) { + curleft += obj.offsetLeft; + curtop += obj.offsetTop; + obj = obj.offsetParent; + }; + return [curleft, curtop]; +} + +function hideUsingEsc(e) { + if (!e) { e = event; } + hideTip(e, currentTipElement, currentTip); +} + +function showTip(evt, name, unique, owner) { + document.onkeydown = hideUsingEsc; + if (currentTip == unique) return; + currentTip = unique; + currentTipElement = name; + + var pos = findPos(owner ? owner : (evt.srcElement ? evt.srcElement : evt.target)); + var posx = pos[0]; + var posy = pos[1]; + + var el = document.getElementById(name); + var parent = (document.documentElement == null) ? document.body : document.documentElement; + el.style.position = "absolute"; + el.style.left = posx + "px"; + el.style.top = posy + "px"; + el.style.display = "block"; +} \ No newline at end of file diff --git a/docs/contributing.html b/docs/contributing.html new file mode 100644 index 0000000..33d33a2 --- /dev/null +++ b/docs/contributing.html @@ -0,0 +1,116 @@ + + + + + Contributing + + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ +

Contributing

+

Branching

+
    +
  • Create a feature branch in git.
  • +
  • Fork and clone locally.
  • +
+

Style Guidelines

+ +

Testing

+

Testing is done in the tests libraries using Expecto which is able to load in any +testing framework you may need, but is strongly encouraged to keep things consistent and use Expecto tests and FsCheck +for any property-based testing.

+
    +
  • Add test cases where needed.
  • +
  • Tests are run as part of the build process, please ensure they pass.
  • +
  • Note that pure F# should be tested - GUI cannot easily be tested.
  • +
+

Documentation

+

Documentation is built dynamically from F# script files and markdown files using FSharp.Formatting. +The Reference documentation is dynamically generated, and descriptions specified by using /// rather than // for comments, see the Formatting documentation +for more information.

+
    +
  • Add documentation as necessary, pages can be modified and created in the ./docsrc directory.
  • +
  • Documentation is built during the build process.
  • +
  • Consider adding examples if adding new features.
  • +
  • Markdown Syntax
  • +
+

Building

+
    +
  • Build the solution with Visual Studio, build.cmd or build.sh.
  • +
  • All binaries will be in ./bin after being built.
  • +
  • +When you're ready to commit the code use `build.cmd/sh -t "Release". This will clean up directories, stage, +and build everything for release. Once you've confirmed it looks good, commit to your branch and make your PR. +
  • +
  • Please note in order to build the Linux images you must have Docker installed.
  • +
+

Releasing

+
    +
  • +Create the distributables via the Dist build task, then create the delta and sig files with the CreateDiffs task. Upload all of the files +related to the new version to the release. +
  • +
+
+
+
+ Build process +
+
+

Merging

+
    +
  • Send a pull request and have it reviewed.
  • +
+ + +
+
+ +
+
+
+ + diff --git a/docs/img/communityAnnouncements.png b/docs/img/communityAnnouncements.png new file mode 100644 index 0000000..c662b40 Binary files /dev/null and b/docs/img/communityAnnouncements.png differ diff --git a/docs/img/faceToolsActions.png b/docs/img/faceToolsActions.png new file mode 100644 index 0000000..8b095fc Binary files /dev/null and b/docs/img/faceToolsActions.png differ diff --git a/docs/img/faceToolsProfiles.png b/docs/img/faceToolsProfiles.png new file mode 100644 index 0000000..64dcc4e Binary files /dev/null and b/docs/img/faceToolsProfiles.png differ diff --git a/docs/img/fake.png b/docs/img/fake.png new file mode 100644 index 0000000..8b33cdf Binary files /dev/null and b/docs/img/fake.png differ diff --git a/docs/img/logo-template.pdn b/docs/img/logo-template.pdn new file mode 100644 index 0000000..52606f5 Binary files /dev/null and b/docs/img/logo-template.pdn differ diff --git a/docs/img/logo.png b/docs/img/logo.png new file mode 100644 index 0000000..3b8d6f9 Binary files /dev/null and b/docs/img/logo.png differ diff --git a/docs/img/modAvailable.png b/docs/img/modAvailable.png new file mode 100644 index 0000000..2f8ba0b Binary files /dev/null and b/docs/img/modAvailable.png differ diff --git a/docs/img/modInstalled.png b/docs/img/modInstalled.png new file mode 100644 index 0000000..43afed9 Binary files /dev/null and b/docs/img/modInstalled.png differ diff --git a/docs/img/modInstalling.png b/docs/img/modInstalling.png new file mode 100644 index 0000000..ab9f5b7 Binary files /dev/null and b/docs/img/modInstalling.png differ diff --git a/docs/img/mordhauConfig.png b/docs/img/mordhauConfig.png new file mode 100644 index 0000000..0f47134 Binary files /dev/null and b/docs/img/mordhauConfig.png differ diff --git a/docs/img/settings.png b/docs/img/settings.png new file mode 100644 index 0000000..c211fab Binary files /dev/null and b/docs/img/settings.png differ diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..36e1dbf --- /dev/null +++ b/docs/index.html @@ -0,0 +1,198 @@ + + + + + + ISSIE + + + + + + + + + + + + + + + + + + +
+
+

+


Discover, Learn & Create with the ISSIE circuit schematic editor! +

+ +




+
+
+
+


+ + +

+ Issie (Interactive Schematic Simulator and Integrated Editor) is a very easy to use and capable hierarchical block schematic based digital logic editor and simulator, + originally made for the 1st year undergraduate Digital Electronics and Computer Architecture module at the + Department of Electronic and Electrical Engineering, Imperial College London, by 3rd year students at the same institution. +

+

+ Issie has been well tested on designs with up to 15,000 schematic components. We expect it to be reasonably performant on much larger designs as well. + The simulation speed is approximately 2000 component-clocks per ms. Thus a circuit with 1000 components would run at 2000 clocks per second. Issie + creates fully synchronous circuits with a single clock: logic with asynchronous loops is currently not supported. +

+

+ Issie is coded in F# transpiled to Javascript by FABLE, and uses a pure F# drawing library. +


+ + +
+ + + +

+ ISSIE has an extensive and complete library of components available in the 'Catalogue' menu. + Components include low-level gates and flipflops as + well as larger blocks: RAMs, ROMs, n-bit registers and adders. The lack of HDL-based combinational logic is partly filled by + special components: Bus Select (extracts a bit-field), Bus Compare (decodes a min-term of a bus). Components defined as Verilog + combinational logic are a likely future addition. +


+

+ Viewer components are used to (optionally) view simulation waveforms of nodes on subsheets. Wire label components allow any number of + nodes on one design sheet to be connected without visible wires. +


+
+ Initial circuit and Component tab +

+ + +

+ ISSIE schematic component ports are connected using drag-and-drop: each connection represents a wire or bus. + ISSIE has two methods of routing wires: Auto-routing and Manual-routing. Wires will all start out as Auto-routed, + which means that the wire's path is created automatically by the program. This path will update when moving any connected components. + ISSIE also allows for manual routing, where the user may manipulate segments of the wire as desired to make the circuit more readable. Effort has + been put into making this functionality intuitive, with automatic reversion to auto-routing when wire topology changes, and auto-routing of + endpoints when parts of a wire are manually routed. +


+ + + +

+ Wires will automatically be created the correct width using a width inference algorithm. + Wires connecting two ports of incompatible widths will be highlighted red and an error message shown, as will multiply driven wires. + Additional sanity checks (e.g. for combinational loops, or unconnected ports) are made before simulation with errors highlighted visually. +


+
+ Width Inferer Error Message +

+ + + +

+ ISSIE includes two simulations in order to inspect and test circuit schematics: The step simulator, and waveform simulator. + This allows users to visualise the information in different ways to best suit their needs and understanding. +


+ + + +

+ Step Simulation allows the user to 'step' or cycle through each clock tick, and view the current design sheet's Output and Viewer component information. + It also allows users to view how the state changes in stateful components such as RAM. +


+
+ Step simulator example +

+ + + +

+ Waveform Simulation allows the user to see the values in each selected connected circuit element (Netlist) over time as a waveform. + The waveform simulator allows users to move waveforms up/down in the list to make the simulation more readable. + Users may cycle through the simulator using the arrows to directly go to a specific clock cycle. + Alternatively there is a scrollbar for the Waveform simulator that will automatically lengthen the simulation once the end is reached. + The values in the waveform simulator can be viewed in various formats: binary, hexadecimal, unsigned decimal and signed decimal. + The Waveform Simulator also features a draggable sidebar to partition screen space dynamically between waveforms and circuit. +


+
+ Waveform simulator example +

+ +

+ Waveform Simulation also allows for the simulation and contents viewing of memory components such as RAM. +


+ +
+ Waveform simulator with RAM example +

+ + + + +

+ Users may convert their ISSIE schematic design into a Verilog file using the 'Write design as verilog' option found in the header bar of the application. + This allows great flexibility as ISSIE designs may be used in more complex design tools and other programs that use Verilog; + allowing ISSIE to be used as a top-level design that can be further developed if needed. Verilog output for simulation or synthesis is documented + as part of the Verilog write process, this includes links to a [YoSys](http://bygone.clairexen.net/yosys/download.html) workflow for synthesis on FPGAs. + Imperial College users can download a pre-installed VM for this workflow, the VHDL output is standalone and should work with other synthesis methods. +


+ + +

+ ISSIE allows users to directly edit the contents of Memory components, for more versitility and ease of use. Memory contents can also be exported and imported via .ram files. +


+
+ RAM editor example +

+ + +
+ + +
    +
  • Marco Selvatici for the 8K lines of base code written for his 3rd year BEng FYP
  • +
  • Edoardo Santi for work improving Issie over Summer 2020.
  • +
  • High Level Programming 2020 cohort for providing the base code of the draw block
  • +
  • Jo Merrick for work improving ISSIE for her 3rd year BEng Project
  • +
  • Dr Tom Clarke for his continued work maintaining and improving ISSIE throughout
  • +
  • All 2020/2021 1st year undergraduate students of the EEE department, Imperial College London, for acting as unpaid beta-testers!
  • +
+ +
+ + + + diff --git a/docs/marco-poster.pdf b/docs/marco-poster.pdf new file mode 100644 index 0000000..b49578f Binary files /dev/null and b/docs/marco-poster.pdf differ diff --git a/docs/marco-report.pdf b/docs/marco-report.pdf new file mode 100644 index 0000000..e281d73 Binary files /dev/null and b/docs/marco-report.pdf differ diff --git a/docs/reference/bustypes-componentid.html b/docs/reference/bustypes-componentid.html new file mode 100644 index 0000000..cd921e7 --- /dev/null +++ b/docs/reference/bustypes-componentid.html @@ -0,0 +1,93 @@ + + + + + ComponentId - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

ComponentId

+

+ + Namespace: global
+ Parent Module: BusTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + ComponentId(string) + +
+ Signature: string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/bustypes-connectionid.html b/docs/reference/bustypes-connectionid.html new file mode 100644 index 0000000..5bb3412 --- /dev/null +++ b/docs/reference/bustypes-connectionid.html @@ -0,0 +1,93 @@ + + + + + ConnectionId - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

ConnectionId

+

+ + Namespace: global
+ Parent Module: BusTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + ConnectionId(string) + +
+ Signature: string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/bustypes-connectionswidth.html b/docs/reference/bustypes-connectionswidth.html new file mode 100644 index 0000000..04b3493 --- /dev/null +++ b/docs/reference/bustypes-connectionswidth.html @@ -0,0 +1,120 @@ + + + + + ConnectionsWidth - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

ConnectionsWidth

+

+ + Namespace: global
+ Parent Module: BusTypes
+

+
+
+

Instance members

+ + + + + + + + + + + + + + + + + + +
Instance memberDescription
+ + + x.Count + +
+ Signature: int
+
+
+ +

CompiledName: get_Count

+
+ + + x.IsEmpty + +
+ Signature: bool
+
+
+ +

CompiledName: get_IsEmpty

+
+ + + [key] + +
+ Signature: key:ConnectionId -> int option
+
+
+ +

CompiledName: get_Item

+
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/bustypes-inputportid.html b/docs/reference/bustypes-inputportid.html new file mode 100644 index 0000000..a99e69f --- /dev/null +++ b/docs/reference/bustypes-inputportid.html @@ -0,0 +1,93 @@ + + + + + InputPortId - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

InputPortId

+

+ + Namespace: global
+ Parent Module: BusTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + InputPortId(string) + +
+ Signature: string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/bustypes-inputportnumber.html b/docs/reference/bustypes-inputportnumber.html new file mode 100644 index 0000000..ac368c9 --- /dev/null +++ b/docs/reference/bustypes-inputportnumber.html @@ -0,0 +1,93 @@ + + + + + InputPortNumber - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

InputPortNumber

+

+ + Namespace: global
+ Parent Module: BusTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + InputPortNumber(int) + +
+ Signature: int
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/bustypes-outputportid.html b/docs/reference/bustypes-outputportid.html new file mode 100644 index 0000000..29c9e40 --- /dev/null +++ b/docs/reference/bustypes-outputportid.html @@ -0,0 +1,93 @@ + + + + + OutputPortId - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

OutputPortId

+

+ + Namespace: global
+ Parent Module: BusTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + OutputPortId(string) + +
+ Signature: string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/bustypes-outputportnumber.html b/docs/reference/bustypes-outputportnumber.html new file mode 100644 index 0000000..d9dd58e --- /dev/null +++ b/docs/reference/bustypes-outputportnumber.html @@ -0,0 +1,93 @@ + + + + + OutputPortNumber - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

OutputPortNumber

+

+ + Namespace: global
+ Parent Module: BusTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + OutputPortNumber(int) + +
+ Signature: int
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/bustypes-widthinfererror.html b/docs/reference/bustypes-widthinfererror.html new file mode 100644 index 0000000..f28a0d4 --- /dev/null +++ b/docs/reference/bustypes-widthinfererror.html @@ -0,0 +1,111 @@ + + + + + WidthInferError - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

WidthInferError

+

+ + Namespace: global
+ Parent Module: BusTypes
+

+
+
+

Record Fields

+ + + + + + + + + + + + + + +
Record FieldDescription
+ + + ConnectionsAffected + +
+ Signature: ConnectionId list
+
+
+ + + + + +
+ + + Msg + +
+ Signature: string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/commontypes-canvasstate.html b/docs/reference/commontypes-canvasstate.html new file mode 100644 index 0000000..03a97ee --- /dev/null +++ b/docs/reference/commontypes-canvasstate.html @@ -0,0 +1,105 @@ + + + + + CanvasState - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

CanvasState

+

+ + Namespace: global
+ Parent Module: CommonTypes
+

+
+

F# data describing the contents of a single schematic sheet.

+ +
+

Instance members

+ + + + + + + + + + + + + + +
Instance memberDescription
+ + + x.Item1 + +
+ Signature: Component list
+
+
+ +
+ + + x.Item2 + +
+ Signature: Connection list
+
+
+ +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/commontypes-component.html b/docs/reference/commontypes-component.html new file mode 100644 index 0000000..5b48fa6 --- /dev/null +++ b/docs/reference/commontypes-component.html @@ -0,0 +1,241 @@ + + + + + Component - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Component

+

+ + Namespace: global
+ Parent Module: CommonTypes
+

+
+

JSComponent mapped to F# record. +Id uniquely identifies the component within a sheet and is used by draw2d library. +Label is optional descriptor displayed on schematic.

+ +
+

Record Fields

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + H + +
+ Signature: int
+
+
+ + + + + +
+ + + Id + +
+ Signature: string
+
+
+ + + + + +
+ + + InputPorts + +
+ Signature: Port list
+
+
+ + + + + +
+ + + Label + +
+ Signature: string
+
+
+ + + + + +
+ + + OutputPorts + +
+ Signature: Port list
+
+
+ + + + + +
+ + + Type + +
+ Signature: ComponentType
+
+
+ + + + + +
+ + + W + +
+ Signature: int
+
+
+ + + + + +
+ + + X + +
+ Signature: int
+
+
+ + + + + +
+ + + Y + +
+ Signature: int
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/commontypes-componenttype.html b/docs/reference/commontypes-componenttype.html new file mode 100644 index 0000000..f65be66 --- /dev/null +++ b/docs/reference/commontypes-componenttype.html @@ -0,0 +1,507 @@ + + + + + ComponentType - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

ComponentType

+

+ + Namespace: global
+ Parent Module: CommonTypes
+

+
+
+

Union Cases

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Union CaseDescription
+ + + And + +
+ Signature:
+
+
+ + + + + +
+ + + AsyncROM(Memory) + +
+ Signature: Memory
+
+
+ + + + + +
+ + + BusSelection(OutputWidth,OutputLSBit) + +
+ Signature: int * int
+
+
+ + + + + +
+ + + Custom(CustomComponentType) + +
+ Signature: CustomComponentType
+
+
+ + + + + +
+ + + Demux2 + +
+ Signature:
+
+
+ + + + + +
+ + + DFF + +
+ Signature:
+
+
+ + + + + +
+ + + DFFE + +
+ Signature:
+
+
+ + + + + +
+ + + Input(BusWidth) + +
+ Signature: int
+
+
+ + + + + +
+ + + IOLabel + +
+ Signature:
+
+
+ + + + + +
+ + + MergeWires + +
+ Signature:
+
+
+ + + + + +
+ + + Mux2 + +
+ Signature:
+
+
+ + + + + +
+ + + Nand + +
+ Signature:
+
+
+ + + + + +
+ + + NbitsAdder(BusWidth) + +
+ Signature: int
+
+
+ + + + + +
+ + + Nor + +
+ Signature:
+
+
+ + + + + +
+ + + Not + +
+ Signature:
+
+
+ + + + + +
+ + + Or + +
+ Signature:
+
+
+ + + + + +
+ + + Output(BusWidth) + +
+ Signature: int
+
+
+ + + + + +
+ + + RAM(Memory) + +
+ Signature: Memory
+
+
+ + + + + +
+ + + Register(BusWidth) + +
+ Signature: int
+
+
+ + + + + +
+ + + RegisterE(BusWidth) + +
+ Signature: int
+
+
+ + + + + +
+ + + ROM(Memory) + +
+ Signature: Memory
+
+
+ + + + + +
+ + + SplitWire(BusWidth) + +
+ Signature: int
+
+
+ + + + + +
+ + + Xnor + +
+ Signature:
+
+
+ + + + + +
+ + + Xor + +
+ Signature:
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/commontypes-connection.html b/docs/reference/commontypes-connection.html new file mode 100644 index 0000000..527fb5c --- /dev/null +++ b/docs/reference/commontypes-connection.html @@ -0,0 +1,150 @@ + + + + + Connection - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Connection

+

+ + Namespace: global
+ Parent Module: CommonTypes
+

+
+

JSConnection mapped to F# record. +Id uniquely identifies connection globally and is used by library.

+ +
+

Record Fields

+ + + + + + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + Id + +
+ Signature: string
+
+
+ + + + + +
+ + + Source + +
+ Signature: Port
+
+
+ + + + + +
+ + + Target + +
+ Signature: Port
+
+
+ + + + + +
+ + + Vertices + +
+ Signature: (float * float) list
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/commontypes-customcomponenttype.html b/docs/reference/commontypes-customcomponenttype.html new file mode 100644 index 0000000..10b621d --- /dev/null +++ b/docs/reference/commontypes-customcomponenttype.html @@ -0,0 +1,134 @@ + + + + + CustomComponentType - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

CustomComponentType

+

+ + Namespace: global
+ Parent Module: CommonTypes
+

+
+

Name identified the LoadedComponent used. +The labels define legends on symbol. +Label strings are unique per CustomComponent. +Multiple CustomComponent instances are differentiated by Component data.

+ +
+

Record Fields

+ + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + InputLabels + +
+ Signature: (string * int) list
+
+
+ + + + + +
+ + + Name + +
+ Signature: string
+
+
+ + + + + +
+ + + OutputLabels + +
+ Signature: (string * int) list
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/commontypes-loadedcomponent.html b/docs/reference/commontypes-loadedcomponent.html new file mode 100644 index 0000000..aa263c5 --- /dev/null +++ b/docs/reference/commontypes-loadedcomponent.html @@ -0,0 +1,179 @@ + + + + + LoadedComponent - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

LoadedComponent

+

+ + Namespace: global
+ Parent Module: CommonTypes
+

+
+

Static data describing a schematic sheet loaded as a custom component. +Every sheet is always identified with a file from which it is loaded/saved. +Name is human readable (and is the filename - without extension) and identifies sheet. +File path is the sheet directory and name (with extension). +InputLabels, OutputLabels are the I/O connections. +The I/O connection integers are bus widths. +The I/O connection strings are human readable. The strings are guaranteed +to be unique in the I/O connection list. I.e. An input label may be the same +as an output label, but two input (or output) labels cannot be the same. +The position in the I/O connections list is important as it implicitly +indicates the port number. For example, the first element in the InputLabels +list is related to the Component's Port with PortNumber 0. +Two instances of a loaded component have the same LoadedComponent data.

+ +
+

Record Fields

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + CanvasState + +
+ Signature: CanvasState
+
+
+ + + + + +
+ + + FilePath + +
+ Signature: string
+
+
+ + + + + +
+ + + InputLabels + +
+ Signature: (string * int) list
+
+
+ + + + + +
+ + + Name + +
+ Signature: string
+
+
+ + + + + +
+ + + OutputLabels + +
+ Signature: (string * int) list
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/commontypes-memory.html b/docs/reference/commontypes-memory.html new file mode 100644 index 0000000..e79411f --- /dev/null +++ b/docs/reference/commontypes-memory.html @@ -0,0 +1,129 @@ + + + + + Memory - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Memory

+

+ + Namespace: global
+ Parent Module: CommonTypes
+

+
+
+

Record Fields

+ + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + AddressWidth + +
+ Signature: int
+
+
+ + + + + +
+ + + Data + +
+ Signature: int64 list
+
+
+ + + + + +
+ + + WordWidth + +
+ Signature: int
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/commontypes-numberbase.html b/docs/reference/commontypes-numberbase.html new file mode 100644 index 0000000..20b0e7b --- /dev/null +++ b/docs/reference/commontypes-numberbase.html @@ -0,0 +1,147 @@ + + + + + NumberBase - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

NumberBase

+

+ + Namespace: global
+ Parent Module: CommonTypes
+

+
+
+

Union Cases

+ + + + + + + + + + + + + + + + + + + + + + +
Union CaseDescription
+ + + Bin + +
+ Signature:
+
+
+ + + + + +
+ + + Dec + +
+ Signature:
+
+
+ + + + + +
+ + + Hex + +
+ Signature:
+
+
+ + + + + +
+ + + SDec + +
+ Signature:
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/commontypes-port.html b/docs/reference/commontypes-port.html new file mode 100644 index 0000000..0cf6200 --- /dev/null +++ b/docs/reference/commontypes-port.html @@ -0,0 +1,158 @@ + + + + + Port - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Port

+

+ + Namespace: global
+ Parent Module: CommonTypes
+

+
+

A component I/O. +Id (like any other Id) is a string generated with 32 random hex charactes, +so it is (practically) globally unique. These Ids are used by the draw2d +library to uniquely refer to ports and components. They are generated via: +http://www.draw2d.org/draw2d_touch/jsdoc_6/#!/api/draw2d.util.UUID. +PortNumber is used to identify which port on a component, contiguous from 0 +separately for inputs and outputs. +HostId is the unique Id of the component where the port is. For example, +all three ports on the same And component will have the same HostId.

+ +
+

Record Fields

+ + + + + + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + HostId + +
+ Signature: string
+
+
+ + + + + +
+ + + Id + +
+ Signature: string
+
+
+ + + + + +
+ + + PortNumber + +
+ Signature: int option
+
+
+ + + + + +
+ + + PortType + +
+ Signature: PortType
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/commontypes-porttype.html b/docs/reference/commontypes-porttype.html new file mode 100644 index 0000000..b1d3105 --- /dev/null +++ b/docs/reference/commontypes-porttype.html @@ -0,0 +1,111 @@ + + + + + PortType - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

PortType

+

+ + Namespace: global
+ Parent Module: CommonTypes
+

+
+
+

Union Cases

+ + + + + + + + + + + + + + +
Union CaseDescription
+ + + Input + +
+ Signature:
+
+
+ + + + + +
+ + + Output + +
+ Signature:
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/commontypes-project.html b/docs/reference/commontypes-project.html new file mode 100644 index 0000000..2857022 --- /dev/null +++ b/docs/reference/commontypes-project.html @@ -0,0 +1,134 @@ + + + + + Project - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Project

+

+ + Namespace: global
+ Parent Module: CommonTypes
+

+
+

Type for an open project which represents a complete design. +ProjectPath is directory containing project files. +OpenFileName is name of file from which current schematic sheet is loaded/saved. +LoadedComponents contains the list of schematic sheets, each as a component, one per sheet.

+ +
+

Record Fields

+ + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + LoadedComponents + +
+ Signature: LoadedComponent list
+
+
+ + + + + +
+ + + OpenFileName + +
+ Signature: string
+
+
+ + + + + +
+ + + ProjectPath + +
+ Signature: string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/diagrammessagetype-jsdiagrammsg.html b/docs/reference/diagrammessagetype-jsdiagrammsg.html new file mode 100644 index 0000000..b4fc612 --- /dev/null +++ b/docs/reference/diagrammessagetype-jsdiagrammsg.html @@ -0,0 +1,165 @@ + + + + + JSDiagramMsg - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

JSDiagramMsg

+

+ + Namespace: global
+ Parent Module: DiagramMessageType
+

+
+
+

Union Cases

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Union CaseDescription
+ + + InferWidths(unit) + +
+ Signature: unit
+
+
+ + + + + +
+ + + InitCanvas(JSCanvas) + +
+ Signature: JSCanvas
+
+
+ + + + + +
+ + + SelectComponent(JSComponent) + +
+ Signature: JSComponent
+
+
+ + + + + +
+ + + SetHasUnsavedChanges(bool) + +
+ Signature: bool
+
+
+ + + + + +
+ + + UnselectComponent(unit) + +
+ Signature: unit
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/diagrammessagetype-keyboardshortcutmsg.html b/docs/reference/diagrammessagetype-keyboardshortcutmsg.html new file mode 100644 index 0000000..d3aedfc --- /dev/null +++ b/docs/reference/diagrammessagetype-keyboardshortcutmsg.html @@ -0,0 +1,165 @@ + + + + + KeyboardShortcutMsg - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

KeyboardShortcutMsg

+

+ + Namespace: global
+ Parent Module: DiagramMessageType
+

+
+
+

Union Cases

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Union CaseDescription
+ + + AltC + +
+ Signature:
+
+
+ + + + + +
+ + + AltShiftZ + +
+ Signature:
+
+
+ + + + + +
+ + + AltV + +
+ Signature:
+
+
+ + + + + +
+ + + AltZ + +
+ Signature:
+
+
+ + + + + +
+ + + CtrlS + +
+ Signature:
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/diagrammessagetype-memoryeditordata.html b/docs/reference/diagrammessagetype-memoryeditordata.html new file mode 100644 index 0000000..bdd0968 --- /dev/null +++ b/docs/reference/diagrammessagetype-memoryeditordata.html @@ -0,0 +1,129 @@ + + + + + MemoryEditorData - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

MemoryEditorData

+

+ + Namespace: global
+ Parent Module: DiagramMessageType
+

+
+
+

Record Fields

+ + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + Address + +
+ Signature: int option
+
+
+ + + + + +
+ + + NumberBase + +
+ Signature: NumberBase
+
+
+ + + + + +
+ + + OnlyDiff + +
+ Signature: bool
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/diagrammessagetype-msg.html b/docs/reference/diagrammessagetype-msg.html new file mode 100644 index 0000000..c8774f7 --- /dev/null +++ b/docs/reference/diagrammessagetype-msg.html @@ -0,0 +1,759 @@ + + + + + Msg - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Msg

+

+ + Namespace: global
+ Parent Module: DiagramMessageType
+

+
+
+

Union Cases

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Union CaseDescription
+ + + AddWaveSimFile(string,WaveSimModel) + +
+ Signature: string * WaveSimModel
+
+
+ + + + + +
+ + + ChangeRightTab(RightTab) + +
+ Signature: RightTab
+
+
+ + + + + +
+ + + CloseDiagramNotification + +
+ Signature:
+
+
+ + + + + +
+ + + CloseFilesNotification + +
+ Signature:
+
+
+ + + + + +
+ + + CloseMemoryEditorNotification + +
+ Signature:
+
+
+ + + + + +
+ + + ClosePopup + +
+ Signature:
+
+
+ + + + + +
+ + + CloseProject + +
+ Signature:
+
+
+ + + + + +
+ + + ClosePropertiesNotification + +
+ Signature:
+
+
+ + + + + +
+ + + CloseSimulationNotification + +
+ Signature:
+
+
+ + + + + +
+ + + CloseWaveSimNotification + +
+ Signature:
+
+
+ + + + + +
+ + + EndSimulation + +
+ Signature:
+
+
+ + + + + +
+ + + IncrementSimulationClockTick + +
+ Signature:
+
+
+ + + + + +
+ + + JSDiagramMsg(JSDiagramMsg) + +
+ Signature: JSDiagramMsg
+
+
+ + + + + +
+ + + KeyboardShortcutMsg(KeyboardShortcutMsg) + +
+ Signature: KeyboardShortcutMsg
+
+
+ + + + + +
+ + + MenuAction(MenuCommand,Msg -> unit) + +
+ Signature: MenuCommand * Msg -> unit
+
+
+ + + + + +
+ + + ReloadSelectedComponent(int) + +
+ Signature: int
+
+
+ + + + + +
+ + + SelectionHasChanged + +
+ Signature:
+
+
+ + + + + +
+ + + SetClipboard(CanvasState) + +
+ Signature: CanvasState
+
+
+ + + + + +
+ + + SetCreateComponent(Component) + +
+ Signature: Component
+
+
+ + + + + +
+ + + SetDragMode(DragMode) + +
+ Signature: DragMode
+
+
+ + + + + +
+ + + SetFilesNotification(...) + +
+ Signature: (Msg -> unit) -> (type)
+
+
+ + + + + +
+ + + SetHighlighted(...) + +
+ Signature: ComponentId list * ConnectionId list
+
+
+ + + + + +
+ + + SetMemoryEditorNotification(...) + +
+ Signature: (Msg -> unit) -> (type)
+
+
+ + + + + +
+ + + SetPopupDialogInt(int option) + +
+ Signature: int option
+
+
+ + + + + +
+ + + SetPopupDialogMemorySetup(...) + +
+ Signature: (int * int) option
+
+
+ + + + + +
+ + + SetPopupDialogText(string option) + +
+ Signature: string option
+
+
+ + + + + +
+ + + SetPopupDialogTwoInts(...) + +
+ Signature: int option * IntMode
+
+
+ + + + + +
+ + + SetPopupMemoryEditorData(...) + +
+ Signature: MemoryEditorData option
+
+
+ + + + + +
+ + + SetProject(Project) + +
+ Signature: Project
+
+
+ + + + + +
+ + + SetPropertiesNotification(...) + +
+ Signature: (Msg -> unit) -> (type)
+
+
+ + + + + +
+ + + SetSimulationBase(NumberBase) + +
+ Signature: NumberBase
+
+
+ + + + + +
+ + + SetSimulationGraph(SimulationGraph) + +
+ Signature: SimulationGraph
+
+
+ + + + + +
+ + + SetSimulationNotification(...) + +
+ Signature: (Msg -> unit) -> (type)
+
+
+ + + + + +
+ + + SetTopMenu(TopMenu) + +
+ Signature: TopMenu
+
+
+ + + + + +
+ + + SetViewerWidth(int) + +
+ Signature: int
+
+
+ + + + + +
+ + + ShowPopup(PopupDialogData -> (type)) + +
+ Signature: PopupDialogData -> (type)
+
+
+ + + + + +
+ + + StartSimulation(...) + +
+ Signature: Result<SimulationData,SimulationError>
+
+
+ + + + + +
+ + + StartWaveSim(...) + +
+ Signature: Result<WaveSimModel,SimulationError option>
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/diagrammessagetype-popupdialogdata.html b/docs/reference/diagrammessagetype-popupdialogdata.html new file mode 100644 index 0000000..2f36e52 --- /dev/null +++ b/docs/reference/diagrammessagetype-popupdialogdata.html @@ -0,0 +1,167 @@ + + + + + PopupDialogData - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

PopupDialogData

+

+ + Namespace: global
+ Parent Module: DiagramMessageType
+

+
+

Possible fields that may (or may not) be used in a dialog popup.

+ +
+

Record Fields

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + Int + +
+ Signature: int option
+
+
+ + + + + +
+ + + Int2 + +
+ Signature: int option
+
+
+ + + + + +
+ + + MemoryEditorData + +
+ Signature: MemoryEditorData option
+
+
+ + + + + +
+ + + MemorySetup + +
+ Signature: (int * int) option
+
+
+ + + + + +
+ + + Text + +
+ Signature: string option
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/diagrammessagetype-righttab.html b/docs/reference/diagrammessagetype-righttab.html new file mode 100644 index 0000000..2623365 --- /dev/null +++ b/docs/reference/diagrammessagetype-righttab.html @@ -0,0 +1,147 @@ + + + + + RightTab - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

RightTab

+

+ + Namespace: global
+ Parent Module: DiagramMessageType
+

+
+
+

Union Cases

+ + + + + + + + + + + + + + + + + + + + + + +
Union CaseDescription
+ + + Catalogue + +
+ Signature:
+
+
+ + + + + +
+ + + Properties + +
+ Signature:
+
+
+ + + + + +
+ + + Simulation + +
+ Signature:
+
+
+ + + + + +
+ + + WaveSim + +
+ Signature:
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/diagrammessagetype-topmenu.html b/docs/reference/diagrammessagetype-topmenu.html new file mode 100644 index 0000000..4c6abb6 --- /dev/null +++ b/docs/reference/diagrammessagetype-topmenu.html @@ -0,0 +1,129 @@ + + + + + TopMenu - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

TopMenu

+

+ + Namespace: global
+ Parent Module: DiagramMessageType
+

+
+
+

Union Cases

+ + + + + + + + + + + + + + + + + + +
Union CaseDescription
+ + + Closed + +
+ Signature:
+
+
+ + + + + +
+ + + Files + +
+ Signature:
+
+
+ + + + + +
+ + + Project + +
+ Signature:
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/diagrammessagetype-wavesimmodel.html b/docs/reference/diagrammessagetype-wavesimmodel.html new file mode 100644 index 0000000..2b1c1ec --- /dev/null +++ b/docs/reference/diagrammessagetype-wavesimmodel.html @@ -0,0 +1,273 @@ + + + + + WaveSimModel - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

WaveSimModel

+

+ + Namespace: global
+ Parent Module: DiagramMessageType
+

+
+
+

Record Fields

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + ClkWidth + +
+ Signature: float
+
+
+ + + + + +
+ + + Cursor + +
+ Signature: uint32
+
+
+ + + + + +
+ + + LastCanvasState + +
+ Signature: JSCanvasState option
+
+
+ + + + + +
+ + + LastClk + +
+ Signature: uint32
+
+
+ + + + + +
+ + + Ports + +
+ Signature: WaveSimPort array
+
+
+ + + + + +
+ + + Radix + +
+ Signature: NumberBase
+
+
+ + + + + +
+ + + Selected + +
+ Signature: bool array
+
+
+ + + + + +
+ + + SimData + +
+ Signature: SimulationData array
+
+
+ + + + + +
+ + + WaveAdder + +
+ Signature: WaveAdderModel
+
+
+ + + + + +
+ + + WaveData + +
+ Signature: SimTime array
+
+
+ + + + + +
+ + + WaveNames + +
+ Signature: WaveName array
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/diagrammodeltype-model.html b/docs/reference/diagrammodeltype-model.html new file mode 100644 index 0000000..e7a8ed2 --- /dev/null +++ b/docs/reference/diagrammodeltype-model.html @@ -0,0 +1,417 @@ + + + + + Model - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Model

+

+ + Namespace: global
+ Parent Module: DiagramModelType
+

+
+
+

Record Fields

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + Clipboard + +
+ Signature: CanvasState
+
+
+ + + + + +
+ + + CreateComponent + +
+ Signature: Component option
+
+
+ + + + + +
+ + + CurrentSelected + +
+ Signature: Component list * Connection list
+
+
+ + + + + +
+ + + CurrProject + +
+ Signature: Project option
+
+
+ + + + + +
+ + + Diagram + +
+ Signature: Draw2dWrapper
+
+
+ + + + + +
+ + + DragMode + +
+ Signature: DragMode
+
+
+ + + + + +
+ + + HasUnsavedChanges + +
+ Signature: bool
+
+
+ + + + + +
+ + + Hilighted + +
+ Signature: ComponentId list * ConnectionId list
+
+
+ + + + + +
+ + + LastSelected + +
+ Signature: Component list * Connection list
+
+
+ + + + + +
+ + + LastUsedDialogWidth + +
+ Signature: int
+
+
+ + + + + +
+ + + Notifications + +
+ Signature: Notifications
+
+
+ + + + + +
+ + + Popup + +
+ Signature: (PopupDialogData -> (type)) option
+
+
+ + + + + +
+ + + PopupDialogData + +
+ Signature: PopupDialogData
+
+
+ + + + + +
+ + + RightTab + +
+ Signature: RightTab
+
+
+ + + + + +
+ + + SelectedComponent + +
+ Signature: Component option
+
+
+ + + + + +
+ + + Simulation + +
+ Signature: Result<SimulationData,SimulationError> option
+
+
+ + + + + +
+ + + TopMenu + +
+ Signature: TopMenu
+
+
+ + + + + +
+ + + ViewerWidth + +
+ Signature: int
+
+
+ + + + + +
+ + + WaveSim + +
+ Signature: Map<string,WaveSimModel> * SimulationError option
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/diagrammodeltype-notifications.html b/docs/reference/diagrammodeltype-notifications.html new file mode 100644 index 0000000..7fb34f3 --- /dev/null +++ b/docs/reference/diagrammodeltype-notifications.html @@ -0,0 +1,183 @@ + + + + + Notifications - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Notifications

+

+ + Namespace: global
+ Parent Module: DiagramModelType
+

+
+
+

Record Fields

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + FromDiagram + +
+ Signature: ((Msg -> unit) -> (type)) option
+
+
+ + + + + +
+ + + FromFiles + +
+ Signature: ((Msg -> unit) -> (type)) option
+
+
+ + + + + +
+ + + FromMemoryEditor + +
+ Signature: ((Msg -> unit) -> (type)) option
+
+
+ + + + + +
+ + + FromProperties + +
+ Signature: ((Msg -> unit) -> (type)) option
+
+
+ + + + + +
+ + + FromSimulation + +
+ Signature: ((Msg -> unit) -> (type)) option
+
+
+ + + + + +
+ + + FromWaveSim + +
+ Signature: ((Msg -> unit) -> (type)) option
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/draw2dwrapper-displaymodetype.html b/docs/reference/draw2dwrapper-displaymodetype.html new file mode 100644 index 0000000..fe01b48 --- /dev/null +++ b/docs/reference/draw2dwrapper-displaymodetype.html @@ -0,0 +1,96 @@ + + + + + DisplayModeType - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

DisplayModeType

+

+ + Namespace: global
+ Parent Module: Draw2dWrapper
+

+
+

Determines size of schematic. +ToDo - make this more flexible and expose sizes

+ +
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + DispMode((type)) + +
+ Signature: (type)
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/filesio-jsonhelpers.html b/docs/reference/filesio-jsonhelpers.html new file mode 100644 index 0000000..8d3850a --- /dev/null +++ b/docs/reference/filesio-jsonhelpers.html @@ -0,0 +1,118 @@ + + + + + JsonHelpers - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

JsonHelpers

+

+ Namespace: global
+ Parent Module: FilesIO + + Attributes:
+[<AutoOpen>]
+ +
+

+
+
+ + + +

Functions and values

+ + + + + + + + + + + + + + +
Function or valueDescription
+ + + jsonStringToState(jsonString) + +
+ Signature: jsonString:string -> Result<CanvasState,string>
+
+
+ + + + + +
+ + + stateToJsonString(arg1, arg2) + +
+ Signature: (Component list * Connection list) -> string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-bustypes.html b/docs/reference/global-bustypes.html new file mode 100644 index 0000000..e26c6b9 --- /dev/null +++ b/docs/reference/global-bustypes.html @@ -0,0 +1,143 @@ + + + + + BusTypes - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

BusTypes

+

+ Namespace: global
+

+
+
+ + +

Nested types and modules

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ ComponentId + + +
+ ConnectionId + + +
+ ConnectionsWidth + + +
+ InputPortId + + +
+ InputPortNumber + + +
+ OutputPortId + + +
+ OutputPortNumber + + +
+ WidthInferError + + +
+ +
+ + +
+
+ +
+
+
+ + diff --git a/docs/reference/global-buswidthinferer.html b/docs/reference/global-buswidthinferer.html new file mode 100644 index 0000000..3a36a77 --- /dev/null +++ b/docs/reference/global-buswidthinferer.html @@ -0,0 +1,116 @@ + + + + + BusWidthInferer - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

BusWidthInferer

+

+ Namespace: global
+

+
+
+ + + +

Functions and values

+ + + + + + + + + + + + + + +
Function or valueDescription
+ + + getConnectionWidth(...) + +
+ Signature: connectionsWidth:ConnectionsWidth -> connId:ConnectionId -> int option
+
+
+ + + + +

Lookup the width of a connection in the connectionsWidth map or fail.

+ + +
+ + + inferConnectionsWidth(arg1, arg2) + +
+ Signature: (Component list * Connection list) -> Result<ConnectionsWidth,WidthInferError>
+
+
+ + + + +

Infer width of all connections or return an error

+ + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-canvasstateanalyser.html b/docs/reference/global-canvasstateanalyser.html new file mode 100644 index 0000000..5738a98 --- /dev/null +++ b/docs/reference/global-canvasstateanalyser.html @@ -0,0 +1,118 @@ + + + + + CanvasStateAnalyser - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

CanvasStateAnalyser

+

+ Namespace: global
+

+
+
+ + +

Nested types and modules

+
+ + + + + + + + + + +
TypeDescription
+ MapData + +

Return all the Ids of all input ports across all components. +Return also the ComponentId which may be used in error messages.

+ + +
+ +
+ +

Functions and values

+ + + + + + + + + + +
Function or valueDescription
+ + + analyseState(arg1, arg2) + +
+ Signature: (Component list * Connection list) -> SimulationError option
+
+
+ + + + +

Analyse a CanvasState and return any error (or None).

+ + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-commontypes.html b/docs/reference/global-commontypes.html new file mode 100644 index 0000000..ea4efe4 --- /dev/null +++ b/docs/reference/global-commontypes.html @@ -0,0 +1,268 @@ + + + + + CommonTypes - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

CommonTypes

+

+ Namespace: global
+

+
+
+ + +

Nested types and modules

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ CanvasState + +

F# data describing the contents of a single schematic sheet.

+ + +
+ Component + +

JSComponent mapped to F# record. +Id uniquely identifies the component within a sheet and is used by draw2d library. +Label is optional descriptor displayed on schematic.

+ + +
+ ComponentType + + +
+ Connection + +

JSConnection mapped to F# record. +Id uniquely identifies connection globally and is used by library.

+ + +
+ CustomComponentType + +

Name identified the LoadedComponent used. +The labels define legends on symbol. +Label strings are unique per CustomComponent. +Multiple CustomComponent instances are differentiated by Component data.

+ + +
+ HighLightColor + +

Colors to highlight components +Case name is used (lowercase) as HTML color name +See JSHelpers.getColorString +lots of colors can be added, see https://www.w3schools.com/colors/colors_names.asp

+ + +
+ LoadedComponent + +

Static data describing a schematic sheet loaded as a custom component. +Every sheet is always identified with a file from which it is loaded/saved. +Name is human readable (and is the filename - without extension) and identifies sheet. +File path is the sheet directory and name (with extension). +InputLabels, OutputLabels are the I/O connections. +The I/O connection integers are bus widths. +The I/O connection strings are human readable. The strings are guaranteed +to be unique in the I/O connection list. I.e. An input label may be the same +as an output label, but two input (or output) labels cannot be the same. +The position in the I/O connections list is important as it implicitly +indicates the port number. For example, the first element in the InputLabels +list is related to the Component's Port with PortNumber 0. +Two instances of a loaded component have the same LoadedComponent data.

+ + +
+ Memory + + +
+ NumberBase + + +
+ Port + +

A component I/O. +Id (like any other Id) is a string generated with 32 random hex charactes, +so it is (practically) globally unique. These Ids are used by the draw2d +library to uniquely refer to ports and components. They are generated via: +http://www.draw2d.org/draw2d_touch/jsdoc_6/#!/api/draw2d.util.UUID. +PortNumber is used to identify which port on a component, contiguous from 0 +separately for inputs and outputs. +HostId is the unique Id of the component where the port is. For example, +all three ports on the same And component will have the same HostId.

+ + +
+ PortType + + +
+ Project + +

Type for an open project which represents a complete design. +ProjectPath is directory containing project files. +OpenFileName is name of file from which current schematic sheet is loaded/saved. +LoadedComponents contains the list of schematic sheets, each as a component, one per sheet.

+ + +
+ +
+ +

Functions and values

+ + + + + + + + + + + + + + +
Function or valueDescription
+ + + draw2dCanvasHeight + +
+ Signature: int
+
+
+ + + + + +
+ + + draw2dCanvasWidth + +
+ Signature: int
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-dependencymerger.html b/docs/reference/global-dependencymerger.html new file mode 100644 index 0000000..d112c73 --- /dev/null +++ b/docs/reference/global-dependencymerger.html @@ -0,0 +1,100 @@ + + + + + DependencyMerger - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

DependencyMerger

+

+ Namespace: global
+

+
+
+ + + +

Functions and values

+ + + + + + + + + + +
Function or valueDescription
+ + + mergeDependencies(...) + +
+ Signature: currDiagramName:string -> graph:SimulationGraph -> (Component list * Connection list) -> loadedDependencies:LoadedComponent list -> Result<SimulationGraph,SimulationError>
+
+
+ + + + +

Try to resolve all the dependencies in a graph, and replace the reducer +of the custom components with a simulationgraph. +Return an error if there are problems with the dependencies. +For example, if the graph of an ALU refers to custom component such as +adders, replace them with the actual simulation graph for the adders.

+ + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-diagrammessagetype.html b/docs/reference/global-diagrammessagetype.html new file mode 100644 index 0000000..4f054c4 --- /dev/null +++ b/docs/reference/global-diagrammessagetype.html @@ -0,0 +1,285 @@ + + + + + DiagramMessageType - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

DiagramMessageType

+

+ Namespace: global
+

+
+
+ + +

Nested types and modules

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ DiagEl + + +
+ DragMode + + +
+ IntMode + + +
+ JSDiagramMsg + + +
+ KeyboardShortcutMsg + + +
+ MemoryEditorData + + +
+ MenuCommand + + +
+ Msg + + +
+ PopupDialogData + +

Possible fields that may (or may not) be used in a dialog popup.

+ + +
+ RightTab + + +
+ Sample + + +
+ SimTime + + +
+ StateSample + + +
+ TopMenu + + +
+ WaveAdderModel + + +
+ WaveName + + +
+ WaveSimModel + + +
+ WaveSimPort + + +
+ Waveform + + +
+ Wire + + +
+ +
+ +

Functions and values

+ + + + + + + + + + + + + + +
Function or valueDescription
+ + + initWA + +
+ Signature: WaveAdderModel
+
+
+ + + + + +
+ + + initWS + +
+ Signature: WaveSimModel
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-diagrammodeltype.html b/docs/reference/global-diagrammodeltype.html new file mode 100644 index 0000000..7e07417 --- /dev/null +++ b/docs/reference/global-diagrammodeltype.html @@ -0,0 +1,95 @@ + + + + + DiagramModelType - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

DiagramModelType

+

+ Namespace: global
+

+
+
+ + +

Nested types and modules

+
+ + + + + + + + + + + + + + +
TypeDescription
+ Model + + +
+ Notifications + + +
+ +
+ + +
+
+ +
+
+
+ + diff --git a/docs/reference/global-draw2dwrapper.html b/docs/reference/global-draw2dwrapper.html new file mode 100644 index 0000000..b8037ce --- /dev/null +++ b/docs/reference/global-draw2dwrapper.html @@ -0,0 +1,90 @@ + + + + + Draw2dWrapper - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Draw2dWrapper

+

+ Namespace: global
+

+
+
+ + +

Nested types and modules

+
+ + + + + + + + + + +
TypeDescription
+ DisplayModeType + +

Determines size of schematic. +ToDo - make this more flexible and expose sizes

+ + +
+ +
+ + +
+
+ +
+
+
+ + diff --git a/docs/reference/global-extractor.html b/docs/reference/global-extractor.html new file mode 100644 index 0000000..830821f --- /dev/null +++ b/docs/reference/global-extractor.html @@ -0,0 +1,134 @@ + + + + + Extractor - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Extractor

+

+ Namespace: global
+

+
+
+ + + +

Functions and values

+ + + + + + + + + + + + + + + + + + +
Function or valueDescription
+ + + extractComponent(jsComponent) + +
+ Signature: jsComponent:JSComponent -> Component
+
+
+ + + + +

Transform a JSComponent into an f# data structure.

+ + +
+ + + extractConnection(jsConnection) + +
+ Signature: jsConnection:JSConnection -> Connection
+
+
+ + + + + +
+ + + extractState(arg1, arg2) + +
+ Signature: (JSComponent list * JSConnection list) -> CanvasState
+
+
+ + + + +

Transform the JSCanvasState into an f# data structure.

+ + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-filemenuview.html b/docs/reference/global-filemenuview.html new file mode 100644 index 0000000..30d7245 --- /dev/null +++ b/docs/reference/global-filemenuview.html @@ -0,0 +1,573 @@ + + + + + FileMenuView - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

FileMenuView

+

+ Namespace: global
+

+
+
+ + + +

Functions and values

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Function or valueDescription
+ + + addFileToProject model dispatch + +
+ Signature: model:Model -> dispatch:(Msg -> unit) -> unit
+
+
+ + + + +

Create a new file in this project and open it automatically.

+ + +
+ + + bitNums(a, b) + +
+ Signature: (a:int * b:int) -> string
+
+
+ + + + + +
+ + + clkAdvance(sD) + +
+ Signature: sD:SimulationData -> SimulationData
+
+
+ + + + + +
+ + + compsConns2portLst(...) + +
+ Signature: model:Model -> simData:SimulationData -> diagElLst:DiagEl list -> WaveSimPort []
+
+
+ + + + + +
+ + + currWS(model) + +
+ Signature: model:Model -> WaveSimModel
+
+
+ + + + + +
+ + + driveOut simGraph targetCompId inPortN + +
+ Signature: simGraph:Map<'?8513,SimulationComponent> -> targetCompId:ComponentId -> inPortN:InputPortNumber -> ('?8513 * OutputPortNumber) option
+ Type parameters: '?8513
+
+ + + + +

Returns a tuple option representing the output to which the target input is connected

+ + +
+ + + extractSimData simData nCycles + +
+ Signature: simData:SimulationData -> nCycles:uint32 -> SimulationData []
+
+
+ + + + + +
+ + + extractSimTime model portFunc simData + +
+ Signature: model:'?8528 -> portFunc:('?8528 -> SimulationData -> WaveSimPort []) -> simData:SimulationData -> Sample []
+ Type parameters: '?8528
+
+ + + + + +
+ + + extractWaveData(...) + +
+ Signature: model:'a -> portFunc:('a -> SimulationData -> WaveSimPort []) -> simDataArr:SimulationData [] -> SimTime []
+ Type parameters: 'a
+
+ + + + + +
+ + + extractWaveNames simData model portFunc + +
+ Signature: simData:SimulationData -> model:Model -> portFunc:(Model -> SimulationData -> WaveSimPort []) -> string []
+
+
+ + + + + +
+ + + findName simGraph arg2 + +
+ Signature: simGraph:SimulationGraph -> WaveSimPort -> (string * (int * int)) list
+
+
+ + + + + +
+ + + getCurrFile(model) + +
+ Signature: model:Model -> string
+
+
+ + + + + +
+ + + getSelected(model) + +
+ Signature: model:Model -> DiagEl list
+
+
+ + + + + +
+ + + initFileWS(model) + +
+ Signature: model:Model -> Msg
+
+
+ + + + + +
+ + + limBits(name) + +
+ Signature: name:string -> (int * int) option
+
+
+ + + + + +
+ + + makeSimData(model) + +
+ Signature: model:Model -> Result<SimulationData,SimulationError> option * Result<(Map<string,WaveSimModel> * SimulationError option),'a> option
+ Type parameters: 'a
+
+ + + + + +
+ + + processComp simData cId + +
+ Signature: simData:SimulationData -> cId:ComponentId -> WaveSimPort []
+
+
+ + + + + +
+ + + procIns simData compId inputs + +
+ Signature: simData:SimulationData -> compId:ComponentId -> inputs:InputPortNumber [] -> WaveSimPort []
+
+
+ + + + + +
+ + + reloadablePorts model simData + +
+ Signature: model:Model -> simData:SimulationData -> WaveSimPort []
+
+
+ + + + + +
+ + + remDuplicates(arrWithDup) + +
+ Signature: arrWithDup:WaveSimPort [] -> WaveSimPort []
+
+
+ + + + + +
+ + + saveOpenFileAction(model) + +
+ Signature: model:Model -> unit
+
+
+ + + + +

Save the file currently open.

+ + +
+ + + selected2portLst model simData + +
+ Signature: model:Model -> simData:SimulationData -> WaveSimPort []
+
+
+ + + + + +
+ + + simLst model dispatch portsFunc + +
+ Signature: model:Model -> dispatch:(Msg -> unit) -> portsFunc:(Model -> SimulationData -> WaveSimPort []) -> Msg
+
+
+ + + + + +
+ + + simWireData2Wire(wireData) + +
+ Signature: wireData:Bit list -> bigint
+
+
+ + + + + +
+ + + viewNoProjectMenu model dispatch + +
+ Signature: model:Model -> dispatch:(Msg -> unit) -> (type)
+
+
+ + + + +

Display the initial Open/Create Project menu at the beginning if no project +is open.

+ + +
+ + + viewTopMenu model dispatch + +
+ Signature: model:Model -> dispatch:(Msg -> unit) -> (type)
+
+
+ + + + +

Display top menu.

+ + +
+ + + wSPort2Name simGraph p + +
+ Signature: simGraph:SimulationGraph -> p:WaveSimPort -> string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-filesio.html b/docs/reference/global-filesio.html new file mode 100644 index 0000000..2f46dcb --- /dev/null +++ b/docs/reference/global-filesio.html @@ -0,0 +1,354 @@ + + + + + FilesIO - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

FilesIO

+

+ Namespace: global
+

+
+
+ + +

Nested types and modules

+
+ + + + + + + + + + +
ModuleDescription
+ JsonHelpers + + +
+ +
+ +

Functions and values

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Function or valueDescription
+ + + askForExistingProjectPath() + +
+ Signature: unit -> string option
+
+
+ + + + +

Ask the user to choose a project file, with a dialog window. +Return the folder containing the chosen project file. +Return None if the user exits withouth selecting a path.

+ + +
+ + + askForNewProjectPath() + +
+ Signature: unit -> string option
+
+
+ + + + +

Ask the user a new project path, with a dialog window. +Return None if the user exits withouth selecting a path.

+ + +
+ + + baseName(filePath) + +
+ Signature: filePath:string -> string
+
+
+ + + + + +
+ + + createEmptyDgmFile folderPath baseName + +
+ Signature: folderPath:string -> baseName:string -> unit
+
+
+ + + + +

Create new empty diagram file. Automatically add the .dgm suffix.

+ + +
+ + + dirName(filePath) + +
+ Signature: filePath:string -> string
+
+
+ + + + + +
+ + + pathJoin(args) + +
+ Signature: args:string [] -> string
+
+
+ + + + + +
+ + + removeFile folderPath baseName + +
+ Signature: folderPath:string -> baseName:string -> unit
+
+
+ + + + +

Asyncronously remove file.

+ + +
+ + + savePngFile folderPath baseName png + +
+ Signature: folderPath:string -> baseName:string -> png:'a -> unit
+ Type parameters: 'a
+
+ + + + +

Save a PNG file (encoded base64, as from draw2d) +Overwrite existing file if needed

+ + +
+ + + saveStateToFile(...) + +
+ Signature: folderPath:string -> baseName:string -> (Component list * Connection list) -> unit
+
+
+ + + + +

Save state to file. Automatically add the .dgm suffix.

+ + +
+ + + tryCreateFolder(path) + +
+ Signature: path:string -> Result<unit,string>
+
+
+ + + + + +
+ + + tryLoadComponentsFromPath(folderPath) + +
+ Signature: folderPath:string -> Result<LoadedComponent list,string>
+
+
+ + + + +

Try to load all diagram components from a file path. +Return a string with error if not possible.

+ + +
+ + + writeFile path data + +
+ Signature: path:string -> data:'b -> unit
+ Type parameters: 'b
+
+ + + + +

Write utf8 encoded data to file. +Create file if it does not exist.

+ + +
+ + + writeFileBase64 path data + +
+ Signature: path:string -> data:'?8952 -> unit
+ Type parameters: '?8952
+
+ + + + +

Write base64 encoded data to file. +Create file if it does not exist.

+ + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-helpers.html b/docs/reference/global-helpers.html new file mode 100644 index 0000000..25916a4 --- /dev/null +++ b/docs/reference/global-helpers.html @@ -0,0 +1,198 @@ + + + + + Helpers - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Helpers

+

+ Namespace: global
+

+
+
+ + + +

Functions and values

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Function or valueDescription
+ + + assertThat cond msg + +
+ Signature: cond:bool -> msg:string -> unit
+
+
+ + + + + +
+ + + cropToLength len fromStart str + +
+ Signature: len:int -> fromStart:bool -> str:string -> string
+
+
+ + + + +

Crop a string to the specified length. +fromStart indicates whether you want the first characters or the last + characters.

+ + +
+ + + listSet lst item idx + +
+ Signature: lst:'a list -> item:'a -> idx:int -> 'a list
+ Type parameters: 'a
+
+ + + + +

Set an element of the list at the specified position. +This function is slow: O(n). Do not use unless necessary.

+ + +
+ + + pow2(exponent) + +
+ Signature: exponent:int -> int
+
+
+ + + + +

Return 2^exponent.

+ + +
+ + + pow2int64(exponent) + +
+ Signature: exponent:int -> int64
+
+
+ + + + +

Return 2^exponent, packed into an int64.

+ + +
+ + + tryFindError(lst) + +
+ Signature: lst:Result<'a,'b> list -> Result<'a list,'b>
+ Type parameters: 'a, 'b
+
+ + + + +

Return the first error found in a list of results, or the list of Oks if +there are none.

+ + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-jstypes.html b/docs/reference/global-jstypes.html new file mode 100644 index 0000000..a0fad4e --- /dev/null +++ b/docs/reference/global-jstypes.html @@ -0,0 +1,151 @@ + + + + + JSTypes - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

JSTypes

+

+ Namespace: global
+

+
+
+ + +

Nested types and modules

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ JSCanvas + + +
+ JSCanvasState + + +
+ JSComponent + + +
+ JSComponents + + +
+ JSConnection + + +
+ JSConnections + + +
+ JSPort + + +
+ JSPorts + + +
+ JSVertices + + +
+ +
+ + +
+
+ +
+
+
+ + diff --git a/docs/reference/global-main.html b/docs/reference/global-main.html new file mode 100644 index 0000000..893e4a2 --- /dev/null +++ b/docs/reference/global-main.html @@ -0,0 +1,186 @@ + + + + + Main - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Main

+

+ Namespace: global
+

+
+
+ + + +

Functions and values

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Function or valueDescription
+ + + argFlagIsOn(flags) + +
+ Signature: flags:string list -> bool
+
+
+ + + + +

Returns true if any of flags are present as command line argument.

+ + +
+ + + args + +
+ Signature: string list
+
+
+ + + + + +
+ + + createMainWindow() + +
+ Signature: unit -> unit
+
+
+ + + + + +
+ + + debug + +
+ Signature: bool
+
+
+ + + + + +
+ + + hasDebugArgs() + +
+ Signature: unit -> bool
+
+
+ + + + + +
+ + + mainWindow + +
+ Signature: (type) option
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-numberhelpers.html b/docs/reference/global-numberhelpers.html new file mode 100644 index 0000000..bc83bb1 --- /dev/null +++ b/docs/reference/global-numberhelpers.html @@ -0,0 +1,309 @@ + + + + + NumberHelpers - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

NumberHelpers

+

+ Namespace: global
+

+
+
+ + + +

Functions and values

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Function or valueDescription
+ + + bin(num) + +
+ Signature: num:int -> string
+
+
+ + + + + +
+ + + bin64(num) + +
+ Signature: num:int64 -> string
+
+
+ + + + + +
+ + + bitToString(bit) + +
+ Signature: bit:Bit -> string
+
+
+ + + + +

Convert a bit to string.

+ + +
+ + + convertIntToWireData width num + +
+ Signature: width:int -> num:int64 -> WireData
+
+
+ + + + +

Convert an int into a Bit list with the provided width. The Least +Significant Bits are the one with low index (e.g. LSB is at position 0, MSB +is at position N). Little Endian. +If the number has more bits than width, then more bits will be returned.

+ + +
+ + + convertWireDataToInt(bits) + +
+ Signature: bits:WireData -> int64
+
+
+ + + + +

Convert a list of Bits into an int. The Least Significant Bits are the one +with low index (e.g. LSB is at position 0, MSB is at position N). +Little Endian.

+ + +
+ + + dec(num) + +
+ Signature: num:int -> string
+
+
+ + + + + +
+ + + dec64(num) + +
+ Signature: num:int64 -> string
+
+
+ + + + + +
+ + + hex(num) + +
+ Signature: num:int -> string
+
+
+ + + + + +
+ + + hex64(num) + +
+ Signature: num:int64 -> string
+
+
+ + + + + +
+ + + sDec64(num) + +
+ Signature: num:int64 -> string
+
+
+ + + + + +
+ + + strToInt(str) + +
+ Signature: str:string -> Result<int64,string>
+
+
+ + + + +

Try to convert a string to an int, or return an error message if that was +not possible.

+ + +
+ + + strToIntCheckWidth str width + +
+ Signature: str:string -> width:int -> Result<int64,string>
+
+
+ + + + +

Convert a string to a number making sure that it has no more bits than +specified in width.

+ + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-simulationbuilder.html b/docs/reference/global-simulationbuilder.html new file mode 100644 index 0000000..2b26e14 --- /dev/null +++ b/docs/reference/global-simulationbuilder.html @@ -0,0 +1,114 @@ + + + + + SimulationBuilder - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

SimulationBuilder

+

+ Namespace: global
+

+
+
+ + + +

Functions and values

+ + + + + + + + + + + + + + +
Function or valueDescription
+ + + getLabelConnections comps conns + +
+ Signature: comps:Component list -> conns:Connection list -> Connection list
+
+
+ + + + + +
+ + + runCanvasStateChecksAndBuildGraph(...) + +
+ Signature: (Component list * Connection list) -> Result<SimulationGraph,SimulationError>
+
+
+ + + + +

Validate a diagram and generate its simulation graph.

+ + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-simulationgraphanalyser.html b/docs/reference/global-simulationgraphanalyser.html new file mode 100644 index 0000000..55b6691 --- /dev/null +++ b/docs/reference/global-simulationgraphanalyser.html @@ -0,0 +1,99 @@ + + + + + SimulationGraphAnalyser - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

SimulationGraphAnalyser

+

+ Namespace: global
+

+
+
+ + + +

Functions and values

+ + + + + + + + + + +
Function or valueDescription
+ + + analyseSimulationGraph(...) + +
+ Signature: diagramName:string -> graph:SimulationGraph -> connections:Connection list -> SimulationError option
+
+
+ + + + +

Analyse a SimulationGraph and return any error (or None). +The SimulationGraph should be fully merged with its dependency, so this +function has to be called after the dependency merger has finished. +This function assumes that there are no cyclic dependencies.

+ + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-simulationrunner.html b/docs/reference/global-simulationrunner.html new file mode 100644 index 0000000..068dc65 --- /dev/null +++ b/docs/reference/global-simulationrunner.html @@ -0,0 +1,244 @@ + + + + + SimulationRunner - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

SimulationRunner

+

+ Namespace: global
+

+
+
+ + + +

Functions and values

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Function or valueDescription
+ + + diffReducerInputsOrOutputs newIO oldIO + +
+ Signature: newIO:Map<'a,WireData> -> oldIO:Map<'a,WireData> -> Map<'a,WireData>
+ Type parameters: 'a
+
+ + + + +

Function to determine what reducer inputs or outputs have changed.

+ + +
+ + + extractIncompleteSimulationIOs(...) + +
+ Signature: simulationIOs:SimulationIO list -> graph:SimulationGraph -> (SimulationIO * WireData) list
+
+
+ + + + +

Simlar to extractSimulationIOs, but do not fail if a bit is not set, just +ignore it.

+ + +
+ + + extractSimulationIOs simulationIOs graph + +
+ Signature: simulationIOs:SimulationIO list -> graph:SimulationGraph -> (SimulationIO * WireData) list
+
+
+ + + + +

Given a list of IO nodes (i.e. Inputs or outputs) extract their value. +If they dont all have a value, an error is thrown.

+ + +
+ + + feedClockTick(graph) + +
+ Signature: graph:SimulationGraph -> SimulationGraph
+
+
+ + + + +

Send one global clock tick to all clocked components, and return the updated +simulationGraph.

+ + +
+ + + feedSimulationInput(...) + +
+ Signature: graph:SimulationGraph -> inputId:ComponentId -> wireData:WireData -> SimulationGraph
+
+
+ + + + +

Feed zero to a simulation input. +This function is supposed to be used with Components of type Input.

+ + +
+ + + getSimulationIOs(components) + +
+ Signature: components:Component list -> SimulationIO list * SimulationIO list
+
+
+ + + + +

Get ComponentIds, ComponentLabels and wire widths of all input and output +nodes.

+ + +
+ + + getSimulationIOsFromGraph(graph) + +
+ Signature: graph:SimulationGraph -> SimulationIO list * SimulationIO list
+
+
+ + + + +

Get ComponentIds, ComponentLabels and wire widths of all input and output +nodes in a simulationGraph.

+ + +
+ + + InitialiseGraphWithZeros inputIds graph + +
+ Signature: inputIds:SimulationIO list -> graph:SimulationGraph -> SimulationGraph
+
+
+ + + + +

Feed zeros to all simulation inputs, and feed a single clock tick. +This way all combinational logic has been touched once and had produced its +outputs.

+ + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-simulator.html b/docs/reference/global-simulator.html new file mode 100644 index 0000000..0ce8292 --- /dev/null +++ b/docs/reference/global-simulator.html @@ -0,0 +1,176 @@ + + + + + Simulator - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Simulator

+

+ Namespace: global
+

+
+
+ + + +

Functions and values

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Function or valueDescription
+ + + extractSimulationIOs + +
+ Signature: SimulationIO list -> SimulationGraph -> (SimulationIO * WireData) list
+
+
+ + + + +

Expose the extractSimulationIOs function from SimulationRunner.

+ + +
+ + + extractStatefulComponents(graph) + +
+ Signature: graph:SimulationGraph -> SimulationComponent list
+
+
+ + + + +

Get some info and the state of all stateful components in a graph.

+ + +
+ + + feedClockTick + +
+ Signature: SimulationGraph -> SimulationGraph
+
+
+ + + + +

Expose the feedClockTick function from SimulationRunner.

+ + +
+ + + feedSimulationInput + +
+ Signature: SimulationGraph -> ComponentId -> WireData -> SimulationGraph
+
+
+ + + + +

Expose the feedSimulationInput function from SimulationRunner.

+ + +
+ + + prepareSimulation(...) + +
+ Signature: diagramName:string -> (Component list * Connection list) -> loadedDependencies:LoadedComponent list -> Result<SimulationData,SimulationError>
+
+
+ + + + +

Builds the graph and simulates it with all inputs zeroed.

+ + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/global-simulatortypes.html b/docs/reference/global-simulatortypes.html new file mode 100644 index 0000000..ba2b15a --- /dev/null +++ b/docs/reference/global-simulatortypes.html @@ -0,0 +1,223 @@ + + + + + SimulatorTypes - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

SimulatorTypes

+

+ Namespace: global
+

+
+
+ + +

Nested types and modules

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeDescription
+ Bit + + +
+ ComponentId + + +
+ ComponentLabel + + +
+ ConnectionId + + +
+ InputPortId + + +
+ InputPortNumber + + +
+ IsClockTick + + +
+ OutputPortId + + +
+ OutputPortNumber + + +
+ ReducerInput + + +
+ ReducerOutput + + +
+ SimulationComponent + + +
+ SimulationComponentState + + +
+ SimulationData + + +
+ SimulationError + + +
+ SimulationGraph + + +
+ SimulationIO + + +
+ WireData + + +
+ +
+ + +
+
+ +
+
+
+ + diff --git a/docs/reference/global-synchronousutils.html b/docs/reference/global-synchronousutils.html new file mode 100644 index 0000000..1af757c --- /dev/null +++ b/docs/reference/global-synchronousutils.html @@ -0,0 +1,281 @@ + + + + + SynchronousUtils - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

SynchronousUtils

+

+ Namespace: global
+

+
+
+ + + +

Functions and values

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Function or valueDescription
+ + + calculateCustomComponentsCombinatorialPaths(...) + +
+ Signature: diagramName:string -> graph:SimulationGraph -> CustomCompsCombPaths option
+
+
+ + + + +

For each dependecy in a simulation graph, create a map containing: +- key: name of the custom component. +- value: a map with: +- key: each InputPortNumber +- value: a list of OutputPortNumber combinatorially connected to the +input. +An input is considered combinatorially connected to an output if there is at +least one logic path connecting an input directly with the output. In other +words, there must be at least one route from the input to output that does +not encounter any synchronous component. +Return None if such information cannot be inferred, for example if there is +a circular dependency.

+ + +
+ + + couldBeSynchronousComponent(compType) + +
+ Signature: compType:ComponentType -> bool
+
+
+ + + + +

Tells wether a component is clocked or not. Note that Custom components may +be clocked (cannot tell without recursively analysing them), so they are +considered synchronous.

+ + +
+ + + getCombinatorialOutputs(...) + +
+ Signature: combRoutes:CustomCompsCombPaths -> node:SimulationComponent -> inputPortNumberOpt:InputPortNumber option -> Map<OutputPortNumber,(ComponentId * InputPortNumber) list>
+
+
+ + + + +

Given a map of combinatorial routes from inputs to outputs for every +simulation graph, perform a lookup to find the combinatorial routes from a +given input to the outputs. Then filter the outputs of the custom node to +only point to the combinatorial children (i.e. the ones connected to the +combinatorial outptus).

+ + +
+ + + getCustomComponentType(_arg1) + +
+ Signature: _arg1:ComponentType -> CustomComponentType
+
+
+ + + + + +
+ + + getCustomName(_arg1) + +
+ Signature: _arg1:ComponentType -> string
+
+
+ + + + + +
+ + + getNodeOrFail graph id + +
+ Signature: graph:SimulationGraph -> id:ComponentId -> SimulationComponent
+
+
+ + + + + +
+ + + hasSynchronousComponents(graph) + +
+ Signature: graph:Map<ComponentId,SimulationComponent> -> bool
+
+
+ + + + +

Find out whether a simulation graph has some synchronous components.

+ + +
+ + + isCustom(_arg1) + +
+ Signature: _arg1:ComponentType -> bool
+
+
+ + + + + +
+ + + isInput(_arg1) + +
+ Signature: _arg1:ComponentType -> bool
+
+
+ + + + + +
+ + + isOutput(_arg1) + +
+ Signature: _arg1:ComponentType -> bool
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/index.html b/docs/reference/index.html new file mode 100644 index 0000000..d83dc4b --- /dev/null +++ b/docs/reference/index.html @@ -0,0 +1,239 @@ + + + + + Namespaces - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + +

issie

+ + +

global Namespace

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ModuleDescription
+ CommonTypes + + +
+ Helpers + + +
+ Main + + +
+ DiagramMessageType + + +
+ DiagramModelType + + +
+ Draw2dWrapper + + +
+ Extractor + + +
+ FileMenuView + + +
+ FilesIO + + +
+ JSTypes + + +
+ CanvasStateAnalyser + + +
+ DependencyMerger + + +
+ NumberHelpers + + +
+ SimulationBuilder + + +
+ SimulationGraphAnalyser + + +
+ SimulationRunner + + +
+ Simulator + + +
+ SimulatorTypes + + +
+ SynchronousUtils + + +
+ BusTypes + + +
+ BusWidthInferer + + +
+ +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/jstypes-jscanvas.html b/docs/reference/jstypes-jscanvas.html new file mode 100644 index 0000000..314c321 --- /dev/null +++ b/docs/reference/jstypes-jscanvas.html @@ -0,0 +1,93 @@ + + + + + JSCanvas - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

JSCanvas

+

+ + Namespace: global
+ Parent Module: JSTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + JSCanvas(obj) + +
+ Signature: obj
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/jstypes-jscanvasstate.html b/docs/reference/jstypes-jscanvasstate.html new file mode 100644 index 0000000..a21d41c --- /dev/null +++ b/docs/reference/jstypes-jscanvasstate.html @@ -0,0 +1,103 @@ + + + + + JSCanvasState - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

JSCanvasState

+

+ + Namespace: global
+ Parent Module: JSTypes
+

+
+
+

Instance members

+ + + + + + + + + + + + + + +
Instance memberDescription
+ + + x.Item1 + +
+ Signature: JSComponent list
+
+
+ +
+ + + x.Item2 + +
+ Signature: JSConnection list
+
+
+ +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/jstypes-jscomponent.html b/docs/reference/jstypes-jscomponent.html new file mode 100644 index 0000000..d912d4c --- /dev/null +++ b/docs/reference/jstypes-jscomponent.html @@ -0,0 +1,93 @@ + + + + + JSComponent - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

JSComponent

+

+ + Namespace: global
+ Parent Module: JSTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + JSComponent(obj) + +
+ Signature: obj
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/jstypes-jscomponents.html b/docs/reference/jstypes-jscomponents.html new file mode 100644 index 0000000..8598954 --- /dev/null +++ b/docs/reference/jstypes-jscomponents.html @@ -0,0 +1,93 @@ + + + + + JSComponents - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

JSComponents

+

+ + Namespace: global
+ Parent Module: JSTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + JSComponents(obj) + +
+ Signature: obj
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/jstypes-jsconnection.html b/docs/reference/jstypes-jsconnection.html new file mode 100644 index 0000000..d8261af --- /dev/null +++ b/docs/reference/jstypes-jsconnection.html @@ -0,0 +1,93 @@ + + + + + JSConnection - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

JSConnection

+

+ + Namespace: global
+ Parent Module: JSTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + JSConnection(obj) + +
+ Signature: obj
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/jstypes-jsconnections.html b/docs/reference/jstypes-jsconnections.html new file mode 100644 index 0000000..dd2452f --- /dev/null +++ b/docs/reference/jstypes-jsconnections.html @@ -0,0 +1,93 @@ + + + + + JSConnections - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

JSConnections

+

+ + Namespace: global
+ Parent Module: JSTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + JSConnections(obj) + +
+ Signature: obj
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/jstypes-jsport.html b/docs/reference/jstypes-jsport.html new file mode 100644 index 0000000..3a9edfe --- /dev/null +++ b/docs/reference/jstypes-jsport.html @@ -0,0 +1,93 @@ + + + + + JSPort - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

JSPort

+

+ + Namespace: global
+ Parent Module: JSTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + JSPort(obj) + +
+ Signature: obj
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/jstypes-jsports.html b/docs/reference/jstypes-jsports.html new file mode 100644 index 0000000..ff1efef --- /dev/null +++ b/docs/reference/jstypes-jsports.html @@ -0,0 +1,93 @@ + + + + + JSPorts - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

JSPorts

+

+ + Namespace: global
+ Parent Module: JSTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + JSPorts(obj) + +
+ Signature: obj
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/jstypes-jsvertices.html b/docs/reference/jstypes-jsvertices.html new file mode 100644 index 0000000..c5fa310 --- /dev/null +++ b/docs/reference/jstypes-jsvertices.html @@ -0,0 +1,93 @@ + + + + + JSVertices - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

JSVertices

+

+ + Namespace: global
+ Parent Module: JSTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + JSVertices(obj) + +
+ Signature: obj
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-bit.html b/docs/reference/simulatortypes-bit.html new file mode 100644 index 0000000..487a3f7 --- /dev/null +++ b/docs/reference/simulatortypes-bit.html @@ -0,0 +1,111 @@ + + + + + Bit - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

Bit

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Union Cases

+ + + + + + + + + + + + + + +
Union CaseDescription
+ + + One + +
+ Signature:
+
+
+ + + + + +
+ + + Zero + +
+ Signature:
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-componentid.html b/docs/reference/simulatortypes-componentid.html new file mode 100644 index 0000000..0c72fb1 --- /dev/null +++ b/docs/reference/simulatortypes-componentid.html @@ -0,0 +1,93 @@ + + + + + ComponentId - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

ComponentId

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + ComponentId(string) + +
+ Signature: string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-componentlabel.html b/docs/reference/simulatortypes-componentlabel.html new file mode 100644 index 0000000..7b8d07c --- /dev/null +++ b/docs/reference/simulatortypes-componentlabel.html @@ -0,0 +1,93 @@ + + + + + ComponentLabel - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

ComponentLabel

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + ComponentLabel(string) + +
+ Signature: string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-connectionid.html b/docs/reference/simulatortypes-connectionid.html new file mode 100644 index 0000000..cb62186 --- /dev/null +++ b/docs/reference/simulatortypes-connectionid.html @@ -0,0 +1,93 @@ + + + + + ConnectionId - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

ConnectionId

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + ConnectionId(string) + +
+ Signature: string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-inputportid.html b/docs/reference/simulatortypes-inputportid.html new file mode 100644 index 0000000..8b6a713 --- /dev/null +++ b/docs/reference/simulatortypes-inputportid.html @@ -0,0 +1,93 @@ + + + + + InputPortId - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

InputPortId

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + InputPortId(string) + +
+ Signature: string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-inputportnumber.html b/docs/reference/simulatortypes-inputportnumber.html new file mode 100644 index 0000000..96e8078 --- /dev/null +++ b/docs/reference/simulatortypes-inputportnumber.html @@ -0,0 +1,93 @@ + + + + + InputPortNumber - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

InputPortNumber

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + InputPortNumber(int) + +
+ Signature: int
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-isclocktick.html b/docs/reference/simulatortypes-isclocktick.html new file mode 100644 index 0000000..b486d4e --- /dev/null +++ b/docs/reference/simulatortypes-isclocktick.html @@ -0,0 +1,111 @@ + + + + + IsClockTick - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

IsClockTick

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Union Cases

+ + + + + + + + + + + + + + +
Union CaseDescription
+ + + No + +
+ Signature:
+
+
+ + + + + +
+ + + Yes(SimulationComponentState) + +
+ Signature: SimulationComponentState
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-outputportid.html b/docs/reference/simulatortypes-outputportid.html new file mode 100644 index 0000000..1f0268a --- /dev/null +++ b/docs/reference/simulatortypes-outputportid.html @@ -0,0 +1,93 @@ + + + + + OutputPortId - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

OutputPortId

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + OutputPortId(string) + +
+ Signature: string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-outputportnumber.html b/docs/reference/simulatortypes-outputportnumber.html new file mode 100644 index 0000000..0fd1dfb --- /dev/null +++ b/docs/reference/simulatortypes-outputportnumber.html @@ -0,0 +1,93 @@ + + + + + OutputPortNumber - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

OutputPortNumber

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Union Cases

+ + + + + + + + + + +
Union CaseDescription
+ + + OutputPortNumber(int) + +
+ Signature: int
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-reducerinput.html b/docs/reference/simulatortypes-reducerinput.html new file mode 100644 index 0000000..89ec868 --- /dev/null +++ b/docs/reference/simulatortypes-reducerinput.html @@ -0,0 +1,129 @@ + + + + + ReducerInput - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

ReducerInput

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Record Fields

+ + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + CustomSimulationGraph + +
+ Signature: SimulationGraph option
+
+
+ + + + + +
+ + + Inputs + +
+ Signature: Map<InputPortNumber,WireData>
+
+
+ + + + + +
+ + + IsClockTick + +
+ Signature: IsClockTick
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-reduceroutput.html b/docs/reference/simulatortypes-reduceroutput.html new file mode 100644 index 0000000..d63f0be --- /dev/null +++ b/docs/reference/simulatortypes-reduceroutput.html @@ -0,0 +1,129 @@ + + + + + ReducerOutput - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

ReducerOutput

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Record Fields

+ + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + NewCustomSimulationGraph + +
+ Signature: SimulationGraph option
+
+
+ + + + + +
+ + + NewState + +
+ Signature: SimulationComponentState
+
+
+ + + + + +
+ + + Outputs + +
+ Signature: Map<OutputPortNumber,WireData> option
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-simulationcomponent.html b/docs/reference/simulatortypes-simulationcomponent.html new file mode 100644 index 0000000..0dc06e6 --- /dev/null +++ b/docs/reference/simulatortypes-simulationcomponent.html @@ -0,0 +1,219 @@ + + + + + SimulationComponent - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

SimulationComponent

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Record Fields

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + CustomSimulationGraph + +
+ Signature: SimulationGraph option
+
+
+ + + + + +
+ + + Id + +
+ Signature: ComponentId
+
+
+ + + + + +
+ + + Inputs + +
+ Signature: Map<InputPortNumber,WireData>
+
+
+ + + + + +
+ + + Label + +
+ Signature: ComponentLabel
+
+
+ + + + + +
+ + + Outputs + +
+ Signature: Map<OutputPortNumber,(ComponentId * InputPortNumber) list>
+
+
+ + + + + +
+ + + Reducer + +
+ Signature: ReducerInput -> ReducerOutput
+
+
+ + + + + +
+ + + State + +
+ Signature: SimulationComponentState
+
+
+ + + + + +
+ + + Type + +
+ Signature: ComponentType
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-simulationcomponentstate.html b/docs/reference/simulatortypes-simulationcomponentstate.html new file mode 100644 index 0000000..1d2b39f --- /dev/null +++ b/docs/reference/simulatortypes-simulationcomponentstate.html @@ -0,0 +1,147 @@ + + + + + SimulationComponentState - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

SimulationComponentState

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Union Cases

+ + + + + + + + + + + + + + + + + + + + + + +
Union CaseDescription
+ + + DffState(Bit) + +
+ Signature: Bit
+
+
+ + + + + +
+ + + NoState + +
+ Signature:
+
+
+ + + + + +
+ + + RamState(Memory) + +
+ Signature: Memory
+
+
+ + + + + +
+ + + RegisterState(WireData) + +
+ Signature: WireData
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-simulationdata.html b/docs/reference/simulatortypes-simulationdata.html new file mode 100644 index 0000000..7ec86fc --- /dev/null +++ b/docs/reference/simulatortypes-simulationdata.html @@ -0,0 +1,183 @@ + + + + + SimulationData - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

SimulationData

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Record Fields

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + ClockTickNumber + +
+ Signature: int
+
+
+ + + + + +
+ + + Graph + +
+ Signature: SimulationGraph
+
+
+ + + + + +
+ + + Inputs + +
+ Signature: SimulationIO list
+
+
+ + + + + +
+ + + IsSynchronous + +
+ Signature: bool
+
+
+ + + + + +
+ + + NumberBase + +
+ Signature: NumberBase
+
+
+ + + + + +
+ + + Outputs + +
+ Signature: SimulationIO list
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-simulationerror.html b/docs/reference/simulatortypes-simulationerror.html new file mode 100644 index 0000000..40ff344 --- /dev/null +++ b/docs/reference/simulatortypes-simulationerror.html @@ -0,0 +1,147 @@ + + + + + SimulationError - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

SimulationError

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Record Fields

+ + + + + + + + + + + + + + + + + + + + + + +
Record FieldDescription
+ + + ComponentsAffected + +
+ Signature: ComponentId list
+
+
+ + + + + +
+ + + ConnectionsAffected + +
+ Signature: ConnectionId list
+
+
+ + + + + +
+ + + InDependency + +
+ Signature: string option
+
+
+ + + + + +
+ + + Msg + +
+ Signature: string
+
+
+ + + + + +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-simulationgraph.html b/docs/reference/simulatortypes-simulationgraph.html new file mode 100644 index 0000000..c6c81ea --- /dev/null +++ b/docs/reference/simulatortypes-simulationgraph.html @@ -0,0 +1,120 @@ + + + + + SimulationGraph - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

SimulationGraph

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Instance members

+ + + + + + + + + + + + + + + + + + +
Instance memberDescription
+ + + x.Count + +
+ Signature: int
+
+
+ +

CompiledName: get_Count

+
+ + + x.IsEmpty + +
+ Signature: bool
+
+
+ +

CompiledName: get_IsEmpty

+
+ + + [key] + +
+ Signature: key:ComponentId -> SimulationComponent
+
+
+ +

CompiledName: get_Item

+
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-simulationio.html b/docs/reference/simulatortypes-simulationio.html new file mode 100644 index 0000000..feda715 --- /dev/null +++ b/docs/reference/simulatortypes-simulationio.html @@ -0,0 +1,117 @@ + + + + + SimulationIO - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

SimulationIO

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Instance members

+ + + + + + + + + + + + + + + + + + +
Instance memberDescription
+ + + x.Item1 + +
+ Signature: ComponentId
+
+
+ +
+ + + x.Item2 + +
+ Signature: ComponentLabel
+
+
+ +
+ + + x.Item3 + +
+ Signature: int
+
+
+ +
+ +
+
+ +
+
+
+ + diff --git a/docs/reference/simulatortypes-wiredata.html b/docs/reference/simulatortypes-wiredata.html new file mode 100644 index 0000000..f76815b --- /dev/null +++ b/docs/reference/simulatortypes-wiredata.html @@ -0,0 +1,173 @@ + + + + + WireData - issie + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ + + + +

WireData

+

+ + Namespace: global
+ Parent Module: SimulatorTypes
+

+
+
+

Instance members

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
Instance memberDescription
+ + + x.Head + +
+ Signature: Bit
+
+
+ +

CompiledName: get_Head

+
+ + + x.IsEmpty + +
+ Signature: bool
+
+
+ +

CompiledName: get_IsEmpty

+
+ + + [index] + +
+ Signature: index:int -> Bit
+
+
+ +

CompiledName: get_Item

+
+ + + x.Length + +
+ Signature: int
+
+
+ +

CompiledName: get_Length

+
+ + + x.Tail + +
+ Signature: Bit list
+
+
+ +

CompiledName: get_Tail

+
+

Static members

+ + + + + + + + + + +
Static memberDescription
+ + + List.Empty + +
+ Signature: Bit list
+
+
+ +

CompiledName: get_Empty

+
+ +
+
+ +
+
+
+ + diff --git a/docs/release-notes.html b/docs/release-notes.html new file mode 100644 index 0000000..10770da --- /dev/null +++ b/docs/release-notes.html @@ -0,0 +1,78 @@ + + + + + release-notes + + + + + + + + + + + + + + + +
+
+ +

issie

+
+
+
+
+ +

v0.5.0 - Issie 1st release

+
    +
  • Change name to Issie - Interative Simulation and Schematic Integrated Editor.
  • +
  • Mend build system - now HMR works.
  • +
  • Breaking change - alter size of NOT gates => any old sheet with the NOT gates will crash the software on load.
  • +
+

v0.4.0 - DECAD 1st release

+
    +
  • Major update to build system.
  • +
  • Upgrade all packages to latest.
  • +
  • Mend bug in loading of exact wire and bus positions.
  • +
  • Change name to DECAD.
  • +
+

0.2 - March, 2020

+
    +
  • End of FYP Release
  • +
+

v0.1-beta

+
    +
  • User feedback release
  • +
+ + +
+
+ +
+
+
+ + diff --git a/docsrc/content/community.fsx b/docsrc/content/community.fsx new file mode 100644 index 0000000..f50f70f --- /dev/null +++ b/docsrc/content/community.fsx @@ -0,0 +1,9 @@ +(** +# Community # + +This presently just has the Announcements page, but more may be added in the future. + +## Announcements ## +**) + + diff --git a/docsrc/content/contributing.fsx b/docsrc/content/contributing.fsx new file mode 100644 index 0000000..645e4ac --- /dev/null +++ b/docsrc/content/contributing.fsx @@ -0,0 +1,60 @@ +(** +# Contributing # + +## Branching ## + + - Create a feature branch in git. + - Fork and clone locally. + +## Style Guidelines ## + + - Follow [F# Coding Guidelines](https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/formatting). + - Take into consideration [FSharpLint](https://github.com/fsprojects/FSharpLint) output. + - [Fantomas](https://github.com/fsprojects/fantomas) should be run to ensure formatting is consistent. + +## Testing ## + +Testing is done in the tests libraries using [Expecto](https://github.com/haf/expecto) which is able to load in any +testing framework you may need, but is strongly encouraged to keep things consistent and use Expecto tests and [FsCheck](https://github.com/fscheck/FsCheck) +for any property-based testing. + + - Add test cases where needed. + - Tests are run as part of the build process, please ensure they pass. + - Note that pure F# should be tested - GUI cannot easily be tested. + +## Documentation ## + +Documentation is built dynamically from F# script files and markdown files using [FSharp.Formatting](https://github.com/fsprojects/FSharp.Formatting). +The Reference documentation is dynamically generated, and descriptions specified by using `///` rather than `//` for comments, see the Formatting documentation +for more information. + + - Add documentation as necessary, pages can be modified and created in the `./docsrc` directory. + - Documentation is built during the build process. + - Consider adding examples if adding new features. + - [Markdown Syntax](https://daringfireball.net/projects/markdown/syntax) + +## Building ## + + - Build the solution with Visual Studio, `build.cmd` or `build.sh`. + - All binaries will be in `./bin` after being built. + - When you're ready to commit the code use `build.cmd/sh -t "Release". This will clean up directories, stage, + and build everything for release. Once you've confirmed it looks good, commit to your branch and make your PR. + - Please note in order to build the Linux images you must have `Docker` installed. + +## Releasing ## + + - Create the distributables via the `Dist` build task, then create the delta and sig files with the `CreateDiffs` task. Upload all of the files + related to the new version to the release. + +
+
+
+ Build process +
+
+ +## Merging ## + + - Send a pull request and have it reviewed. + +*) \ No newline at end of file diff --git a/docsrc/content/index.fsx b/docsrc/content/index.fsx new file mode 100644 index 0000000..16cf65e --- /dev/null +++ b/docsrc/content/index.fsx @@ -0,0 +1,68 @@ +(** +# What is Issie? + +Issie (Intuitive Schematic Simulator and Interactive Editor) is a very easy to use and capable block schematic based digital logic editor and simulator, +originally made for the 1st year undergraduate Digital Electronics and Computer Architecture module at the +Department of Electronic and Electrical Engineering, Imperial College London. + +Issie is coded in F# transpiled to Javascript by [FABLE](http://fable.io), and uses the +very capable [Draw2D](https://github.com/freegroup/draw2d) +library. + +## Acknowledgements: + +* Marco Selvatici for the 8K lines of base code written for his 3rd year BEng [FYP](https://github.com/MarcoSelvatici/DEflow) +* An awesome automatic FAKE build system based on Cody Johnson's [MordhausBuddy](https://github.com/Shmew/MordhauBuddy) +* Edoardo Santi for work improving Issie over Summer 2020. + +## Background and Technical Details + +Marco's [Dissertation](https://tomcl.github.com/issie/marco-report.pdf) or his [Poster](https://tomcl.github.com/issie/marco-poster.pdf). + + + + + +## How to get Issie + +Go to the [releases](https://github.com/tomcl/issie/releases) page on the Github repo and download the +package most applicable to your operating system. + +You only need to download the `.exe` for Windows or `.AppImage` for Linux. The other files are for auto-updating +which is handled by the application. (You will see an update button pop up in the top right-hand corner.) + +With Linux: + + - Most distributions are supported, if you have an issue please let me know and I will try to fix it. + - It is distributed in [AppImage](https://appimage.org/) format, which is plug and play for most popular distros. + - You may need to right click and go to properties to give it permissions to execute. + - Some distributions such as Debian will need the start up flag `--no-sandbox` in order to run. + +With Windows: + + - The installer is easy to install, a single click in fact. + + +
+
+
+ +
+
+ +## Documentation ## + + - Functionality - Some example use cases for the application. + - [API Reference](reference/index.html) contains automatically generated documentation for all types, modules + and functions in the library. This includes additional brief samples on using most of the functions. + This is only helpful if you plan on contributing. + +## Contributing ## + +The project is hosted on [Github][gh] where you can [report issues][issues], fork the project and submit pull +requests. Please take a look at the [contribution guidelines](contributing.html) for more information. + + [gh]: https://github.com/tomcl/issie + [issues]: https://github.com/tomcl/issie/issues + +*) diff --git a/docsrc/files/img/communityAnnouncements.png b/docsrc/files/img/communityAnnouncements.png new file mode 100644 index 0000000..c662b40 Binary files /dev/null and b/docsrc/files/img/communityAnnouncements.png differ diff --git a/docsrc/files/img/faceToolsActions.png b/docsrc/files/img/faceToolsActions.png new file mode 100644 index 0000000..8b095fc Binary files /dev/null and b/docsrc/files/img/faceToolsActions.png differ diff --git a/docsrc/files/img/faceToolsProfiles.png b/docsrc/files/img/faceToolsProfiles.png new file mode 100644 index 0000000..64dcc4e Binary files /dev/null and b/docsrc/files/img/faceToolsProfiles.png differ diff --git a/docsrc/files/img/fake.png b/docsrc/files/img/fake.png new file mode 100644 index 0000000..8b33cdf Binary files /dev/null and b/docsrc/files/img/fake.png differ diff --git a/docsrc/files/img/logo-template.pdn b/docsrc/files/img/logo-template.pdn new file mode 100644 index 0000000..52606f5 Binary files /dev/null and b/docsrc/files/img/logo-template.pdn differ diff --git a/docsrc/files/img/logo.png b/docsrc/files/img/logo.png new file mode 100644 index 0000000..3b8d6f9 Binary files /dev/null and b/docsrc/files/img/logo.png differ diff --git a/docsrc/files/img/modAvailable.png b/docsrc/files/img/modAvailable.png new file mode 100644 index 0000000..2f8ba0b Binary files /dev/null and b/docsrc/files/img/modAvailable.png differ diff --git a/docsrc/files/img/modInstalled.png b/docsrc/files/img/modInstalled.png new file mode 100644 index 0000000..43afed9 Binary files /dev/null and b/docsrc/files/img/modInstalled.png differ diff --git a/docsrc/files/img/modInstalling.png b/docsrc/files/img/modInstalling.png new file mode 100644 index 0000000..ab9f5b7 Binary files /dev/null and b/docsrc/files/img/modInstalling.png differ diff --git a/docsrc/files/img/mordhauConfig.png b/docsrc/files/img/mordhauConfig.png new file mode 100644 index 0000000..0f47134 Binary files /dev/null and b/docsrc/files/img/mordhauConfig.png differ diff --git a/docsrc/files/img/settings.png b/docsrc/files/img/settings.png new file mode 100644 index 0000000..c211fab Binary files /dev/null and b/docsrc/files/img/settings.png differ diff --git a/docsrc/files/marco-poster.pdf b/docsrc/files/marco-poster.pdf new file mode 100644 index 0000000..b49578f Binary files /dev/null and b/docsrc/files/marco-poster.pdf differ diff --git a/docsrc/files/marco-report.pdf b/docsrc/files/marco-report.pdf new file mode 100644 index 0000000..e281d73 Binary files /dev/null and b/docsrc/files/marco-report.pdf differ diff --git a/docsrc/tools/templates/template.cshtml b/docsrc/tools/templates/template.cshtml new file mode 100644 index 0000000..bec8515 --- /dev/null +++ b/docsrc/tools/templates/template.cshtml @@ -0,0 +1,55 @@ + + + + + @Title + + + + + + + + + + + + + + + +
+ +
+
+
+ @RenderBody() +
+
+ +
+
+
+ + diff --git a/dotnet-tools.json b/dotnet-tools.json new file mode 100644 index 0000000..ee0abbe --- /dev/null +++ b/dotnet-tools.json @@ -0,0 +1,25 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "fake-cli": { + "version": "5.21.0-alpha003", + "commands": [ + "fake" + ] + }, + "paket": { + "version": "6.2.1", + "commands": [ + "paket" + ] + }, + "fable": { + "version": "3.7.0", + "allowPrerelease": true, + "commands": [ + "fable" + ] + } + } +} \ No newline at end of file diff --git a/issie.sln b/issie.sln new file mode 100644 index 0000000..936ee44 --- /dev/null +++ b/issie.sln @@ -0,0 +1,50 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29009.5 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Main", "src\Main\Main.fsproj", "{AAC1D6D8-2EEB-4BA3-AEAA-CBE06F8D968A}" +EndProject +Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Renderer", "src\Renderer\Renderer.fsproj", "{9F63D5D3-10F5-46F4-BF38-43E75E4FCB2D}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{A2545711-2C3E-4CBF-BB76-AEF8C3665C50}" + ProjectSection(SolutionItems) = preProject + .gitignore = .gitignore + build.fsx = build.fsx + dotnet-tools.json = dotnet-tools.json + LICENSE = LICENSE + Nuget.Config = Nuget.Config + package.json = package.json + paket.dependencies = paket.dependencies + README.md = README.md + webpack.additions.main.js = webpack.additions.main.js + webpack.additions.renderer.js = webpack.additions.renderer.js + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "static", "static", "{EB34148C-70A6-4D00-BA10-87BBDFD4ACBF}" + ProjectSection(SolutionItems) = preProject + static\icon.ico = static\icon.ico + static\index.html = static\index.html + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AAC1D6D8-2EEB-4BA3-AEAA-CBE06F8D968A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AAC1D6D8-2EEB-4BA3-AEAA-CBE06F8D968A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {AAC1D6D8-2EEB-4BA3-AEAA-CBE06F8D968A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {AAC1D6D8-2EEB-4BA3-AEAA-CBE06F8D968A}.Release|Any CPU.Build.0 = Release|Any CPU + {9F63D5D3-10F5-46F4-BF38-43E75E4FCB2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9F63D5D3-10F5-46F4-BF38-43E75E4FCB2D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9F63D5D3-10F5-46F4-BF38-43E75E4FCB2D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9F63D5D3-10F5-46F4-BF38-43E75E4FCB2D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {96DAE6A9-B1CC-4FF7-B08C-D5FBFD55B385} + EndGlobalSection +EndGlobal diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..2cb7b31 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,26901 @@ +{ + "name": "issie", + "version": "2.4.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "issie", + "version": "2.4.0", + "dependencies": { + "@electron/remote": "^2.0.1", + "bulma": "^0.9.2", + "bulma-tooltip": "^3.0.2", + "core-js": "^3.12.1", + "cross-zip": "^3.1.0", + "cross-zip-cli": "^1.0.0", + "font-awesome": "^4.7.0", + "react": "^16.7.0", + "react-dom": "^16.7.0", + "react-tooltip": "^4.2.19", + "source-map-loader": "^1.1.3", + "source-map-support": "0.5.19" + }, + "devDependencies": { + "bufferutil": "^4.0.3", + "electron": "^16", + "electron-builder": "^22", + "electron-webpack": "^2.8.2", + "file-loader": "^3.0.1", + "html-webpack-plugin": "^4.5.2", + "loglevel": "^1.7.1", + "node-sass": "^4.0.0", + "remotedev": "^0.2.9", + "resolve-url-loader": "^3.1.3", + "sass-loader": "^7.3.1", + "url-loader": "^4.1.0", + "utf-8-validate": "^5.0.5", + "webpack": "4.46.0", + "webpack-cli": "^3.3.12" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.7.tgz", + "integrity": "sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw==", + "dev": true + }, + "node_modules/@babel/core": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", + "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.7", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.9", + "@babel/types": "^7.12.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/core/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", + "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/generator/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", + "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "dev": true, + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz", + "integrity": "sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.12.5", + "@babel/helper-validator-option": "^7.12.1", + "browserslist": "^4.14.5", + "semver": "^5.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz", + "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-member-expression-to-functions": "^7.12.1", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-split-export-declaration": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.7.tgz", + "integrity": "sha512-idnutvQPdpbduutvi3JVfEgcVIHooQnhvhx0Nk9isOINOIGYkZea1Pk2JlJRiUnMefrlvr0vkByATBY/mB4vjQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "regexpu-core": "^4.7.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-define-map": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", + "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.10.4", + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz", + "integrity": "sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.1" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", + "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", + "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.7" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.5" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", + "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-simple-access": "^7.12.1", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/helper-validator-identifier": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.1", + "@babel/types": "^7.12.1", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.7.tgz", + "integrity": "sha512-I5xc9oSJ2h59OwyUqjv95HRyzxj53DAubUERgQMrpcCEYQyToeHA+NEcUEsVWB4j53RDeskeBJ0SgRAYHDBckw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.7" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz", + "integrity": "sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-wrap-function": "^7.10.4", + "@babel/types": "^7.12.1" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", + "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.12.1", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", + "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.1" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", + "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.1" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.11.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz", + "integrity": "sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A==", + "dev": true + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.12.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz", + "integrity": "sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helpers": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", + "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" + } + }, + "node_modules/@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz", + "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz", + "integrity": "sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.12.1", + "@babel/plugin-syntax-async-generators": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz", + "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz", + "integrity": "sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz", + "integrity": "sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz", + "integrity": "sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz", + "integrity": "sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz", + "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.7.tgz", + "integrity": "sha512-8c+uy0qmnRTeukiGsjLGy6uVs/TFjJchGXUeBqlG4VWYOdJWkhhVPdQ3uHwbmalfJwv2JsV0qffXP4asRfL2SQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", + "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.12.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz", + "integrity": "sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.7.tgz", + "integrity": "sha512-4ovylXZ0PWmwoOvhU2vhnzVNnm88/Sm9nx7V8BPgMvAzn5zDou3/Awy0EjglyubVHasJj+XCEkr/r1X3P5elCA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz", + "integrity": "sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz", + "integrity": "sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz", + "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz", + "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz", + "integrity": "sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz", + "integrity": "sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.12.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz", + "integrity": "sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz", + "integrity": "sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz", + "integrity": "sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-define-map": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-split-export-declaration": "^7.10.4", + "globals": "^11.1.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz", + "integrity": "sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz", + "integrity": "sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz", + "integrity": "sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz", + "integrity": "sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz", + "integrity": "sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz", + "integrity": "sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz", + "integrity": "sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz", + "integrity": "sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz", + "integrity": "sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz", + "integrity": "sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz", + "integrity": "sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-simple-access": "^7.12.1", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz", + "integrity": "sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.10.4", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-validator-identifier": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz", + "integrity": "sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz", + "integrity": "sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz", + "integrity": "sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz", + "integrity": "sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.12.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz", + "integrity": "sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz", + "integrity": "sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz", + "integrity": "sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng==", + "dev": true, + "dependencies": { + "regenerator-transform": "^0.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz", + "integrity": "sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz", + "integrity": "sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz", + "integrity": "sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.7.tgz", + "integrity": "sha512-VEiqZL5N/QvDbdjfYQBhruN0HYjSPjC4XkeqW4ny/jNtH9gcbgaqBIXYEZCNnESMAGs0/K/R7oFGMhOyu/eIxg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz", + "integrity": "sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.1.tgz", + "integrity": "sha512-EPGgpGy+O5Kg5pJFNDKuxt9RdmTgj5sgrus2XVeMp/ZIbOESadgILUbm50SNpghOh3/6yrbsH+NB5+WJTmsA7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz", + "integrity": "sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz", + "integrity": "sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.7.tgz", + "integrity": "sha512-OnNdfAr1FUQg7ksb7bmbKoby4qFOHw6DKWWUNB9KqnnCldxhxJlP+21dpyaWFmf2h0rTbOkXJtAGevY3XW1eew==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.12.7", + "@babel/helper-compilation-targets": "^7.12.5", + "@babel/helper-module-imports": "^7.12.5", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-validator-option": "^7.12.1", + "@babel/plugin-proposal-async-generator-functions": "^7.12.1", + "@babel/plugin-proposal-class-properties": "^7.12.1", + "@babel/plugin-proposal-dynamic-import": "^7.12.1", + "@babel/plugin-proposal-export-namespace-from": "^7.12.1", + "@babel/plugin-proposal-json-strings": "^7.12.1", + "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", + "@babel/plugin-proposal-numeric-separator": "^7.12.7", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-proposal-optional-catch-binding": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.12.7", + "@babel/plugin-proposal-private-methods": "^7.12.1", + "@babel/plugin-proposal-unicode-property-regex": "^7.12.1", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-class-properties": "^7.12.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.12.1", + "@babel/plugin-transform-arrow-functions": "^7.12.1", + "@babel/plugin-transform-async-to-generator": "^7.12.1", + "@babel/plugin-transform-block-scoped-functions": "^7.12.1", + "@babel/plugin-transform-block-scoping": "^7.12.1", + "@babel/plugin-transform-classes": "^7.12.1", + "@babel/plugin-transform-computed-properties": "^7.12.1", + "@babel/plugin-transform-destructuring": "^7.12.1", + "@babel/plugin-transform-dotall-regex": "^7.12.1", + "@babel/plugin-transform-duplicate-keys": "^7.12.1", + "@babel/plugin-transform-exponentiation-operator": "^7.12.1", + "@babel/plugin-transform-for-of": "^7.12.1", + "@babel/plugin-transform-function-name": "^7.12.1", + "@babel/plugin-transform-literals": "^7.12.1", + "@babel/plugin-transform-member-expression-literals": "^7.12.1", + "@babel/plugin-transform-modules-amd": "^7.12.1", + "@babel/plugin-transform-modules-commonjs": "^7.12.1", + "@babel/plugin-transform-modules-systemjs": "^7.12.1", + "@babel/plugin-transform-modules-umd": "^7.12.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1", + "@babel/plugin-transform-new-target": "^7.12.1", + "@babel/plugin-transform-object-super": "^7.12.1", + "@babel/plugin-transform-parameters": "^7.12.1", + "@babel/plugin-transform-property-literals": "^7.12.1", + "@babel/plugin-transform-regenerator": "^7.12.1", + "@babel/plugin-transform-reserved-words": "^7.12.1", + "@babel/plugin-transform-shorthand-properties": "^7.12.1", + "@babel/plugin-transform-spread": "^7.12.1", + "@babel/plugin-transform-sticky-regex": "^7.12.7", + "@babel/plugin-transform-template-literals": "^7.12.1", + "@babel/plugin-transform-typeof-symbol": "^7.12.1", + "@babel/plugin-transform-unicode-escapes": "^7.12.1", + "@babel/plugin-transform-unicode-regex": "^7.12.1", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.12.7", + "core-js-compat": "^3.7.0", + "semver": "^5.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", + "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", + "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + } + }, + "node_modules/@babel/template": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", + "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.12.7", + "@babel/types": "^7.12.7" + } + }, + "node_modules/@babel/traverse": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz", + "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.12.7", + "@babel/types": "^7.12.7", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/types": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz", + "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@develar/schema-utils": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", + "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", + "dev": true, + "dependencies": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@electron/get": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.13.1.tgz", + "integrity": "sha512-U5vkXDZ9DwXtkPqlB45tfYnnYBN8PePp1z/XDCupnSpdrxT8/ThCv9WCwPLf9oqiSGZTkH6dx2jDUPuoXpjkcA==", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^9.6.0", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=8.6" + }, + "optionalDependencies": { + "global-agent": "^3.0.0", + "global-tunnel-ng": "^2.7.1" + } + }, + "node_modules/@electron/get/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@electron/remote": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@electron/remote/-/remote-2.0.1.tgz", + "integrity": "sha512-bGX4/yB2bPZwXm1DsxgoABgH0Cz7oFtXJgkerB8VrStYdTyvhGAULzNLRn9rVmeAuC3VUDXaXpZIlZAZHpsLIA==", + "peerDependencies": { + "electron": ">= 10.0.0-beta.1" + } + }, + "node_modules/@electron/universal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-1.0.4.tgz", + "integrity": "sha512-ajZoumi4XwqwmZe8YVhu4XGkZBCPyWZsVCQONPTIe9TUlleSN+dic3YpXlaWcilx/HOzTdldTKtabNTeI0gDoA==", + "dev": true, + "dependencies": { + "@malept/cross-spawn-promise": "^1.1.0", + "asar": "^3.0.3", + "debug": "^4.3.1", + "dir-compare": "^2.4.0", + "fs-extra": "^9.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/@electron/universal/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/universal/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/universal/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@malept/cross-spawn-promise": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", + "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@malept/cross-spawn-promise/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@malept/cross-spawn-promise/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@malept/cross-spawn-promise/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@malept/cross-spawn-promise/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@malept/cross-spawn-promise/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@types/anymatch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", + "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", + "dev": true + }, + "node_modules/@types/debug": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", + "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", + "dev": true + }, + "node_modules/@types/fs-extra": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.10.tgz", + "integrity": "sha512-O9T2LLkRDiTlalOBdjEkcnT0MRdT2+wglCl7pJUJ3mkWkR8hX4K+5bg2raQNJcLv4V8zGuTXe7Ud3wSqkTyuyQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==", + "dev": true + }, + "node_modules/@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==" + }, + "node_modules/@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "12.19.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.6.tgz", + "integrity": "sha512-U2VopDdmBoYBmtm8Rz340mvvSz34VgX/K9+XCuckvcLGMkt3rbMX8soqFOikIPlPBc5lmw8By9NUK7bEFSBFlQ==", + "dev": true + }, + "node_modules/@types/plist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.2.tgz", + "integrity": "sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*", + "xmlbuilder": ">=11.0.1" + } + }, + "node_modules/@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true + }, + "node_modules/@types/tapable": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.7.tgz", + "integrity": "sha512-0VBprVqfgFD7Ehb2vd8Lh9TG3jP98gvr8rgehQqzztZNI7o8zS8Ad4jyZneKELphpuE212D8J70LnSNQSyO6bQ==", + "dev": true + }, + "node_modules/@types/uglify-js": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.0.tgz", + "integrity": "sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q==", + "dev": true, + "dependencies": { + "source-map": "^0.6.1" + } + }, + "node_modules/@types/uglify-js/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@types/verror": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.4.tgz", + "integrity": "sha512-OjJdqx6QlbyZw9LShPwRW+Kmiegeg3eWNI41MQQKaG3vjdU2L9SRElntM51HmHBY1cu7izxQJ1lMYioQh3XMBg==", + "dev": true, + "optional": true + }, + "node_modules/@types/webpack": { + "version": "4.41.27", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.27.tgz", + "integrity": "sha512-wK/oi5gcHi72VMTbOaQ70VcDxSQ1uX8S2tukBK9ARuGXrYM/+u4ou73roc7trXDNmCxCoerE8zruQqX/wuHszA==", + "dev": true, + "dependencies": { + "@types/anymatch": "*", + "@types/node": "*", + "@types/tapable": "^1", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "source-map": "^0.6.0" + } + }, + "node_modules/@types/webpack-env": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.16.0.tgz", + "integrity": "sha512-Fx+NpfOO0CpeYX2g9bkvX8O5qh9wrU1sOF4g8sft4Mu7z+qfe387YlyY8w8daDyDsKY5vUxM0yxkAYnbkRbZEw==", + "dev": true + }, + "node_modules/@types/webpack-sources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz", + "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + } + }, + "node_modules/@types/webpack-sources/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@types/webpack/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@types/yargs": { + "version": "15.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", + "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", + "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", + "dev": true + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "dependencies": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==" + }, + "node_modules/@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "dependencies": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "node_modules/@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==" + }, + "node_modules/@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "node_modules/@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/7zip": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/7zip/-/7zip-0.0.6.tgz", + "integrity": "sha1-nK+xca+CMpSQNTtIFvAzR6oVCjA=", + "dev": true, + "bin": { + "7z": "7zip-lite/7z.exe" + } + }, + "node_modules/7zip-bin": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.0.3.tgz", + "integrity": "sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz", + "integrity": "sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/adjust-sourcemap-loader/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "peerDependencies": { + "ajv": ">=5.0.0" + } + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true, + "engines": { + "node": ">=0.4.2" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true, + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "devOptional": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/anymatch/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "devOptional": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/app-builder-bin": { + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.5.12.tgz", + "integrity": "sha512-lQARM2AielmFoBeIo6LZigAe+58Wwe07ZWkt+wVeDxzyieNmeWjlvz/V5dKzinydwdHd+CNswN86sww46yijjA==", + "dev": true + }, + "node_modules/app-builder-lib": { + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.10.5.tgz", + "integrity": "sha512-/W8nlGamJCtKlQtsMWwU9vb+cX4pTNY+rJWCuc7oXUykVSMS50W7LhQusIjCelNfymUQ1XCu6cXEY/ylqhX12A==", + "dev": true, + "dependencies": { + "@develar/schema-utils": "~2.6.5", + "@electron/universal": "1.0.4", + "7zip-bin": "~5.0.3", + "async-exit-hook": "^2.0.1", + "bluebird-lst": "^1.0.9", + "builder-util": "22.10.5", + "builder-util-runtime": "8.7.3", + "chromium-pickle-js": "^0.2.0", + "debug": "^4.3.2", + "ejs": "^3.1.6", + "electron-publish": "22.10.5", + "fs-extra": "^9.1.0", + "hosted-git-info": "^3.0.8", + "is-ci": "^2.0.0", + "istextorbinary": "^5.12.0", + "js-yaml": "^4.0.0", + "lazy-val": "^1.0.4", + "minimatch": "^3.0.4", + "normalize-package-data": "^3.0.0", + "read-config-file": "6.0.0", + "sanitize-filename": "^1.6.3", + "semver": "^7.3.4", + "temp-file": "^3.3.7" + }, + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/app-builder-lib/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/app-builder-lib/node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/app-builder-lib/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/app-builder-lib/node_modules/is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/app-builder-lib/node_modules/js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/app-builder-lib/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/app-builder-lib/node_modules/normalize-package-data": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", + "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "resolve": "^1.20.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/app-builder-lib/node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/app-builder-lib/node_modules/resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "dependencies": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/app-builder-lib/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/app-builder-lib/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "node_modules/are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/argparse/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/arity-n": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz", + "integrity": "sha1-2edrEXM+CFacCEeuezmyhgswt0U=", + "dev": true + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asar": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/asar/-/asar-3.0.3.tgz", + "integrity": "sha512-k7zd+KoR+n8pl71PvgElcoKHrVNiSXtw7odKbyNpmgKe7EGRF9Pnu3uLOukD37EvavKwVFxOUpqXTIZC5B5Pmw==", + "dev": true, + "dependencies": { + "chromium-pickle-js": "^0.2.0", + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "bin": { + "asar": "bin/asar.js" + }, + "engines": { + "node": ">=10.12.0" + }, + "optionalDependencies": { + "@types/glob": "^7.1.1" + } + }, + "node_modules/asar/node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dependencies": { + "object-assign": "^4.1.1", + "util": "0.10.3" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assert/node_modules/inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "node_modules/assert/node_modules/util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dependencies": { + "inherits": "2.0.1" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "dev": true + }, + "node_modules/async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "devOptional": true + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "node_modules/babel-loader": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.2.tgz", + "integrity": "sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g==", + "dev": true, + "dependencies": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^1.4.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "engines": { + "node": ">= 8.9" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "webpack": ">=2" + } + }, + "node_modules/babel-loader/node_modules/find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/babel-loader/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-loader/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-loader/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-loader/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-loader/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-component": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-component/-/babel-plugin-component-1.1.1.tgz", + "integrity": "sha512-WUw887kJf2GH80Ng/ZMctKZ511iamHNqPhd9uKo14yzisvV7Wt1EckIrb8oq/uCz3B3PpAW7Xfl7AkTLDYT6ag==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "7.0.0-beta.35" + } + }, + "node_modules/babel-plugin-component/node_modules/@babel/helper-module-imports": { + "version": "7.0.0-beta.35", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.35.tgz", + "integrity": "sha512-vaC1KyIZSuyWb3Lj277fX0pxivyHwuDU4xZsofqgYAbkDxNieMg2vuhzP5AgMweMY7fCQUMTi+BgPqTLjkxXFg==", + "dev": true, + "dependencies": { + "@babel/types": "7.0.0-beta.35", + "lodash": "^4.2.0" + } + }, + "node_modules/babel-plugin-component/node_modules/@babel/types": { + "version": "7.0.0-beta.35", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.35.tgz", + "integrity": "sha512-y9XT11CozHDgjWcTdxmhSj13rJVXpa5ZXwjjOiTedjaM0ba5ItqdS02t31EhPl7HtOWxsZkYCCUNrSfrOisA6w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=", + "dev": true + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/binaryextensions": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-4.15.0.tgz", + "integrity": "sha512-MkUl3szxXolQ2scI1PM14WOT951KnaTNJ0eMKg7WzOI4kvSxyNo/Cygx4LOBNhwyINhAuSQpJW1rYD9aBSxGaw==", + "dev": true, + "engines": { + "node": ">=0.8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, + "dependencies": { + "inherits": "~2.0.0" + }, + "engines": { + "node": "0.4 || >=0.5.8" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/bluebird-lst": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz", + "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==", + "dev": true, + "dependencies": { + "bluebird": "^3.5.5" + } + }, + "node_modules/bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "dependencies": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "node_modules/boolean": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.4.tgz", + "integrity": "sha512-3hx0kwU3uzG6ReQ3pnaFQPSktpBw6RHN3/ivDKEuU8g1XSfafowyvDnadjv1xp8IZqhtSukxlwv9bF6FhX8m0w==", + "optional": true + }, + "node_modules/boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/camelcase": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", + "integrity": "sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/boxen/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "dependencies": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/browserify-sign/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "dev": true, + "dependencies": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "node_modules/buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "node_modules/bufferutil": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.3.tgz", + "integrity": "sha512-yEYTwGndELGvfXsImMBLop58eaGW+YdONi1fNjTINSY98tmMmFijBG6WXgdkfuLNt4imzQNtIE+eBp1PVpMCSw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.2.0" + } + }, + "node_modules/builder-util": { + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.10.5.tgz", + "integrity": "sha512-/MkLhmyo1gU3xMwXJxccQaRj/9tm5eTd6ZyebTf8SYouY4r3hRser+LxhOm/f8Z9W6oJvfPe0jc9TFsxYfMcsg==", + "dev": true, + "dependencies": { + "@types/debug": "^4.1.5", + "@types/fs-extra": "^9.0.7", + "7zip-bin": "~5.0.3", + "app-builder-bin": "3.5.12", + "bluebird-lst": "^1.0.9", + "builder-util-runtime": "8.7.3", + "chalk": "^4.1.0", + "debug": "^4.3.2", + "fs-extra": "^9.1.0", + "is-ci": "^2.0.0", + "js-yaml": "^4.0.0", + "source-map-support": "^0.5.19", + "stat-mode": "^1.0.0", + "temp-file": "^3.3.7" + } + }, + "node_modules/builder-util-runtime": { + "version": "8.7.3", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.3.tgz", + "integrity": "sha512-1Q2ReBqFblimF5g/TLg2+0M5Xzv0Ih5LxJ/BMWXvEy/e6pQKeeEpbkPMGsN6OiQgkygaZo5VXCXIjOkOQG5EoQ==", + "dev": true, + "dependencies": { + "debug": "^4.3.2", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=8.2.5" + } + }, + "node_modules/builder-util-runtime/node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/builder-util/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/builder-util/node_modules/debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/builder-util/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/builder-util/node_modules/js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/builder-util/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/builder-util/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "node_modules/bulma": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/bulma/-/bulma-0.9.2.tgz", + "integrity": "sha512-e14EF+3VSZ488yL/lJH0tR8mFWiEQVCMi/BQUMi2TGMBOk+zrDg4wryuwm/+dRSHJw0gMawp2tsW7X1JYUCE3A==" + }, + "node_modules/bulma-tooltip": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bulma-tooltip/-/bulma-tooltip-3.0.2.tgz", + "integrity": "sha512-CsT3APjhlZScskFg38n8HYL8oYNUHQtcu4sz6ERarxkUpBRbk9v0h/5KAvXeKapVSn2dp9l7bOGit5SECP8EWQ==" + }, + "node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", + "integrity": "sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w==", + "dev": true, + "dependencies": { + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "minipass": "^3.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "p-map": "^3.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^2.7.1", + "ssri": "^7.0.0", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/cacache/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/cacache/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", + "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camel-case": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz", + "integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.1", + "tslib": "^1.10.0" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "dependencies": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/camelcase-keys/node_modules/camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001242", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001242.tgz", + "integrity": "sha512-KvNuZ/duufelMB3w2xtf9gEWCSxJwUgoxOx5b6ScLXC4kPc9xsczUVCPrQU26j5kOsHM4pSUL54tAZt5THQKug==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "devOptional": true, + "dependencies": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + }, + "optionalDependencies": { + "fsevents": "^1.2.7" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha1-BKEGZywYsIWrd02YPfo+oTjyIgU=", + "dev": true + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dev": true, + "dependencies": { + "source-map": "~0.6.0" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-1.1.0.tgz", + "integrity": "sha512-bAtZo0u82gCfaAGfSNxUdTI9mNyza7D8w4CVCcaOsy7sgwDzvx6ekr6cuWJqY3UGzgnQ1+4wgENup5eIhgxEYA==", + "dev": true, + "optional": true, + "dependencies": { + "slice-ansi": "^1.0.0", + "string-width": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "optional": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "optional": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, + "node_modules/colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "node_modules/compose-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz", + "integrity": "sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8=", + "dev": true, + "dependencies": { + "arity-n": "^1.0.4" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "optional": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "node_modules/copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dependencies": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "node_modules/copy-concurrently/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/core-js": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.12.1.tgz", + "integrity": "sha512-Ne9DKPHTObRuB09Dru5AjwKjY4cJHVGu+y5f7coGn1E9Grkc3p2iBwE9AI/nJzsE29mQF7oq+mhYYRqOMFN1Bw==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.0.tgz", + "integrity": "sha512-o9QKelQSxQMYWHXc/Gc4L8bx/4F7TTraE5rhuN8I7mKBt5dBIUpXpIR3omv70ebr8ST5R3PqbDQr+ZI3+Tt1FQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.14.7", + "semver": "7.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-js-compat/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "optional": true, + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/crc/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/crocket": { + "version": "0.9.11", + "resolved": "https://registry.npmjs.org/crocket/-/crocket-0.9.11.tgz", + "integrity": "sha1-KI/KEe8NPdI5tixIgmXzDI7fsMU=", + "dev": true, + "dependencies": { + "xpipe": "*" + } + }, + "node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/cross-unzip": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/cross-unzip/-/cross-unzip-0.0.2.tgz", + "integrity": "sha1-UYO8R6CVWb78+YzEZXlkmZNZNy8=", + "dev": true + }, + "node_modules/cross-zip": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cross-zip/-/cross-zip-3.1.0.tgz", + "integrity": "sha512-aX02l0SD3KE27pMl69gkxDdDM5D3u9Ic4Je+2b1B2fP0dWnlWWY6ns2Vk5DEgCXJRhL3GasSpicNQRNbDkq0+w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "rimraf": "^3.0.0" + } + }, + "node_modules/cross-zip-cli": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cross-zip-cli/-/cross-zip-cli-1.0.0.tgz", + "integrity": "sha1-loJvgpPo+x6rD1Y9a6ywDc42jPo=", + "dependencies": { + "cross-zip": "^2.1.3", + "minimist": "^1.2.0" + }, + "bin": { + "cross-unzip": "unzip.js", + "cross-zip": "zip.js" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/cross-zip-cli/node_modules/cross-zip": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/cross-zip/-/cross-zip-2.1.6.tgz", + "integrity": "sha512-xLIETNkzRcU6jGRzenJyRFxahbtP4628xEKMTI/Ql0Vu8m4h8M7uRLVi7E5OYHuJ6VQPsG4icJumKAFUvfm0+A==", + "deprecated": "Possible security issue issue found in 2.x. Please update to 3.x", + "dependencies": { + "rimraf": "^3.0.0" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + } + }, + "node_modules/css-hot-loader": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/css-hot-loader/-/css-hot-loader-1.4.4.tgz", + "integrity": "sha512-J/qXHz+r7FOT92qMIJfxUk0LC9fecQNZVr0MswQ4FOpKLyOCBjofVMfc6R268bh/5ktkTShrweMr0wWqerC92g==", + "dev": true, + "dependencies": { + "loader-utils": "^1.1.0", + "lodash": "^4.17.5", + "normalize-url": "^1.9.1" + } + }, + "node_modules/css-hot-loader/node_modules/normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "dependencies": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/css-hot-loader/node_modules/prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/css-loader": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", + "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/css-loader/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/css-select": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", + "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^5.0.0", + "domhandler": "^4.2.0", + "domutils": "^2.6.0", + "nth-check": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-select/node_modules/domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/css-select/node_modules/domhandler": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", + "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/css-select/node_modules/domutils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/css-what": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", + "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "dependencies": { + "array-find-index": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=" + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dev": true, + "dependencies": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dev": true, + "dependencies": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "devOptional": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/del/node_modules/p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/del/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/del/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "devOptional": true + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/dir-compare": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-2.4.0.tgz", + "integrity": "sha512-l9hmu8x/rjVC9Z2zmGzkhOEowZvW7pmYws5CWHutg8u1JgvsKWMx7Q/UODeu4djLZ4FgW5besw5yvMQnBHzuCA==", + "dev": true, + "dependencies": { + "buffer-equal": "1.0.0", + "colors": "1.0.3", + "commander": "2.9.0", + "minimatch": "3.0.4" + }, + "bin": { + "dircompare": "src/cli/dircompare.js" + } + }, + "node_modules/dir-compare/node_modules/commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "dependencies": { + "graceful-readlink": ">= 1.0.0" + }, + "engines": { + "node": ">= 0.6.x" + } + }, + "node_modules/dmg-builder": { + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.10.5.tgz", + "integrity": "sha512-58FEpfH8PEFqjbUNka4bYr52snRT8+LSXrP4gy6EZWOVICbOlmTOYj988pfoLam5C5iXb3odmyUQqwWOxlsEUw==", + "dev": true, + "dependencies": { + "app-builder-lib": "22.10.5", + "builder-util": "22.10.5", + "fs-extra": "^9.1.0", + "iconv-lite": "^0.6.2", + "js-yaml": "^4.0.0", + "sanitize-filename": "^1.6.3" + }, + "optionalDependencies": { + "dmg-license": "^1.0.8" + } + }, + "node_modules/dmg-builder/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/dmg-builder/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/dmg-builder/node_modules/iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dmg-builder/node_modules/js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/dmg-builder/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/dmg-builder/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/dmg-license": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.8.tgz", + "integrity": "sha512-47GOb6b4yVzpovXC34heXElpH++ICg9GuWBeOTaokUNLAoAdWpE4VehudYEEtu96j2jXsgQWYf78nW7r+0Y3eg==", + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "@types/plist": "^3.0.1", + "@types/verror": "^1.10.3", + "ajv": "^6.10.0", + "cli-truncate": "^1.1.0", + "crc": "^3.8.0", + "iconv-corefoundation": "^1.1.5", + "plist": "^3.0.1", + "smart-buffer": "^4.0.2", + "verror": "^1.10.0" + }, + "bin": { + "dmg-license": "bin/dmg-license.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "node_modules/dns-packet": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", + "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", + "dev": true, + "dependencies": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "dependencies": { + "buffer-indexof": "^1.0.0" + } + }, + "node_modules/dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "dependencies": { + "utila": "~0.4" + } + }, + "node_modules/dom-serializer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.1.0.tgz", + "integrity": "sha512-ox7bvGXt2n+uLWtCRLybYx60IrOlWL/aCebWJk1T0d4m3y2tzf4U3ij9wBMUb6YJZpz06HCCYuyCDveE2xXmzQ==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "entities": "^2.0.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "engines": { + "node": ">=0.4", + "npm": ">=1.2" + } + }, + "node_modules/domelementtype": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", + "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.2.tgz", + "integrity": "sha512-NKbgaM8ZJOecTZsIzW5gSuplsX2IWW2mIK7xVr8hTQF2v1CJWTmLZ1HOCh5sH+IzVPAGE5IucooOkvwBRAdowA==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.0.1", + "domhandler": "^3.3.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dot-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz", + "integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==", + "dev": true, + "dependencies": { + "no-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, + "node_modules/dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "node_modules/duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "dependencies": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/editions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.1.0.tgz", + "integrity": "sha512-h6nWEyIocfgho9J3sTSuhU/WoFOu1hTX75rPBebNrbF38Y9QFDjCDizYXdikHTySW7Y3mSxli8bpDz9RAtc7rA==", + "dev": true, + "dependencies": { + "errlop": "^4.0.0", + "version-range": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "node_modules/ejs": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", + "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "dev": true, + "dependencies": { + "jake": "^10.6.1" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-16.0.1.tgz", + "integrity": "sha512-6TSDBcoKGgmKL/+W+LyaXidRVeRl1V4I81ZOWcqsVksdTMfM4AlxTgfaoYdK/nUhqBrUtuPDcqOyJE6Bc4qMpw==", + "hasInstallScript": true, + "dependencies": { + "@electron/get": "^1.13.0", + "@types/node": "^14.6.2", + "extract-zip": "^1.0.3" + }, + "bin": { + "electron": "cli.js" + }, + "engines": { + "node": ">= 8.6" + } + }, + "node_modules/electron-builder": { + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.10.5.tgz", + "integrity": "sha512-0q/289UUJUhRou6lZKDz/wzK6WprIQ6VXMTmaI+w9qXvSNugPC9UA5s2zXInOkjZOvO/xKnjeyiavrVSHYF3tA==", + "dev": true, + "dependencies": { + "@types/yargs": "^15.0.13", + "app-builder-lib": "22.10.5", + "bluebird-lst": "^1.0.9", + "builder-util": "22.10.5", + "builder-util-runtime": "8.7.3", + "chalk": "^4.1.0", + "dmg-builder": "22.10.5", + "fs-extra": "^9.1.0", + "is-ci": "^2.0.0", + "lazy-val": "^1.0.4", + "read-config-file": "6.0.0", + "sanitize-filename": "^1.6.3", + "update-notifier": "^5.1.0", + "yargs": "^16.2.0" + }, + "bin": { + "electron-builder": "out/cli/cli.js", + "install-app-deps": "out/cli/install-app-deps.js" + }, + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/electron-builder/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-builder/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-builder/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-publish": { + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.10.5.tgz", + "integrity": "sha512-dHyuazv3P3j1Xyv7pdwTwAvxWab2pCb0G0Oa6qWQoCc4b1/mRGY00M7AvYW1cPuUijj9zYAf1HmXfM6MifaMlA==", + "dev": true, + "dependencies": { + "@types/fs-extra": "^9.0.7", + "bluebird-lst": "^1.0.9", + "builder-util": "22.10.5", + "builder-util-runtime": "8.7.3", + "chalk": "^4.1.0", + "fs-extra": "^9.1.0", + "lazy-val": "^1.0.4", + "mime": "^2.5.0" + } + }, + "node_modules/electron-publish/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-publish/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-publish/node_modules/mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/electron-publish/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.3.766", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.766.tgz", + "integrity": "sha512-u2quJ862q9reRKh/je3GXis3w38+RoXH1J9N3XjtsS6NzmUAosNsyZgUVFZPN/ZlJ3v6T0rTyZR3q/J5c6Sy5w==", + "dev": true + }, + "node_modules/electron-webpack": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/electron-webpack/-/electron-webpack-2.8.2.tgz", + "integrity": "sha512-rR7hxoOlZIcJf6R08mVl/4TBtFY+HW6sv4Z28TdMWETvcM4ZBIBdGNGylxF0gNwB8gkTgo8UkkDbXGX48K4Vow==", + "dev": true, + "dependencies": { + "@types/webpack-env": "^1.15.1", + "async-exit-hook": "^2.0.1", + "bluebird": "^3.7.2", + "chalk": "^4.0.0", + "crocket": "^0.9.11", + "css-hot-loader": "^1.4.4", + "css-loader": "^3.4.2", + "debug": "^4.1.1", + "dotenv": "^8.2.0", + "dotenv-expand": "^5.1.0", + "electron-devtools-installer": "^2.2.4", + "electron-webpack-js": "~2.4.1", + "file-loader": "^6.0.0", + "fs-extra": "^9.0.0", + "html-loader": "^1.1.0", + "html-webpack-plugin": "^4.0.4", + "lazy-val": "^1.0.4", + "mini-css-extract-plugin": "^0.9.0", + "node-loader": "^0.6.0", + "read-config-file": "~4.0.1", + "semver": "^7.1.3", + "source-map-support": "^0.5.16", + "style-loader": "^1.1.3", + "terser-webpack-plugin": "^2.3.5", + "url-loader": "^4.0.0", + "webpack-cli": "^3.3.11", + "webpack-dev-server": "^3.10.3", + "webpack-merge": "^4.2.2", + "yargs": "^15.3.1" + }, + "bin": { + "electron-webpack": "out/cli.js" + }, + "engines": { + "node": ">=10.0" + }, + "peerDependencies": { + "webpack": "^4.42.1" + } + }, + "node_modules/electron-webpack-js": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/electron-webpack-js/-/electron-webpack-js-2.4.1.tgz", + "integrity": "sha512-NPbcI4nnuclkLEKmwRI8sui2GNe37NKm0pCQR6KZA7YSV3KQdH4I7wOgIZ2AkeCpyeUHrBSMGQY+VqhPD7OtMA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.9.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/preset-env": "^7.9.0", + "babel-loader": "^8.1.0", + "babel-plugin-component": "^1.1.1" + } + }, + "node_modules/electron-webpack/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-webpack/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/electron-webpack/node_modules/electron-devtools-installer": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-2.2.4.tgz", + "integrity": "sha512-b5kcM3hmUqn64+RUcHjjr8ZMpHS2WJ5YO0pnG9+P/RTdx46of/JrEjuciHWux6pE+On6ynWhHJF53j/EDJN0PA==", + "dev": true, + "dependencies": { + "7zip": "0.0.6", + "cross-unzip": "0.0.2", + "rimraf": "^2.5.2", + "semver": "^5.3.0" + } + }, + "node_modules/electron-webpack/node_modules/electron-devtools-installer/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/electron-webpack/node_modules/file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/electron-webpack/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-webpack/node_modules/fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "dev": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/electron-webpack/node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-webpack/node_modules/jsonfile/node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-webpack/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/electron-webpack/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-webpack/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-webpack/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-webpack/node_modules/read-config-file": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-4.0.1.tgz", + "integrity": "sha512-5caED3uo2IAZMPcbh/9hx/O29s2430RLxtnFDdzxpH/epEpawOrQnGBHueotIXUrGPPIgdNQN+S/CIp2WmiSfw==", + "dev": true, + "dependencies": { + "ajv": "^6.10.1", + "ajv-keywords": "^3.4.1", + "dotenv": "^8.0.0", + "dotenv-expand": "^5.1.0", + "fs-extra": "^8.1.0", + "js-yaml": "^3.13.1", + "json5": "^2.1.0", + "lazy-val": "^1.0.4" + }, + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/electron-webpack/node_modules/read-config-file/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/electron-webpack/node_modules/read-config-file/node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-webpack/node_modules/read-config-file/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/electron-webpack/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/electron-webpack/node_modules/schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/electron-webpack/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-webpack/node_modules/universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-webpack/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-webpack/node_modules/y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, + "node_modules/electron-webpack/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/electron-webpack/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/electron/node_modules/@types/node": { + "version": "14.17.34", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.34.tgz", + "integrity": "sha512-USUftMYpmuMzeWobskoPfzDi+vkpe0dvcOBRNOscFrGxVp4jomnRxWuVohgqBow2xyIPC0S3gjxV/5079jhmDg==" + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "devOptional": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", + "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/errlop": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/errlop/-/errlop-4.1.0.tgz", + "integrity": "sha512-vul6gGBuVt0M2TPi1/WrcL86+Hb3Q2Tpu3TME3sbVhZrYf7J1ZMHCodI25RQKCVurh56qTfvgM0p3w5cT4reSQ==", + "dev": true, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "dev": true, + "dependencies": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "dev": true, + "dependencies": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "node_modules/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "optional": true + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dependencies": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/eventsource": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", + "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", + "dev": true, + "dependencies": { + "original": "^1.0.0" + }, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "dependencies": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dev": true, + "dependencies": { + "type": "^2.0.0" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", + "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==", + "dev": true + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extract-zip": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", + "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "dependencies": { + "concat-stream": "^1.6.2", + "debug": "^2.6.9", + "mkdirp": "^0.5.4", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + } + }, + "node_modules/extract-zip/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/extract-zip/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" + }, + "node_modules/file-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", + "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", + "dev": true, + "dependencies": { + "loader-utils": "^1.0.2", + "schema-utils": "^1.0.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/file-loader/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "node_modules/filelist": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", + "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.4" + } + }, + "node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "engines": { + "node": ">=6" + } + }, + "node_modules/find-cache-dir/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "dependencies": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "node_modules/follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + } + }, + "node_modules/font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=", + "engines": { + "node": ">=0.10.3" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dependencies": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + }, + "engines": { + "node": ">= 4.0" + } + }, + "node_modules/fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/fstream/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "dependencies": { + "globule": "^1.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", + "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "devOptional": true, + "dependencies": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + } + }, + "node_modules/glob-parent/node_modules/is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "devOptional": true, + "dependencies": { + "is-extglob": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "dependencies": { + "global-prefix": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-modules/node_modules/global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "dependencies": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-tunnel-ng": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz", + "integrity": "sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==", + "optional": true, + "dependencies": { + "encodeurl": "^1.0.2", + "lodash": "^4.17.10", + "npm-conf": "^1.1.3", + "tunnel": "^0.0.6" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globalthis": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.2.tgz", + "integrity": "sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==", + "optional": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/globby/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/globule": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz", + "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==", + "dev": true, + "dependencies": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "node_modules/graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hosted-git-info": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/html-entities": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz", + "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==", + "dev": true + }, + "node_modules/html-loader": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-1.3.2.tgz", + "integrity": "sha512-DEkUwSd0sijK5PF3kRWspYi56XP7bTNkyg5YWSzBdjaSDmvCufep5c4Vpb3PBf6lUL0YPtLwBfy9fL0t5hBAGA==", + "dev": true, + "dependencies": { + "html-minifier-terser": "^5.1.1", + "htmlparser2": "^4.1.0", + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/html-loader/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/html-loader/node_modules/schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.1", + "clean-css": "^4.2.3", + "commander": "^4.1.1", + "he": "^1.2.0", + "param-case": "^3.0.3", + "relateurl": "^0.2.7", + "terser": "^4.6.3" + }, + "bin": { + "html-minifier-terser": "cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/html-minifier-terser/node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/html-webpack-plugin": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz", + "integrity": "sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==", + "dev": true, + "dependencies": { + "@types/html-minifier-terser": "^5.0.0", + "@types/tapable": "^1.0.5", + "@types/webpack": "^4.41.8", + "html-minifier-terser": "^5.0.1", + "loader-utils": "^1.2.3", + "lodash": "^4.17.20", + "pretty-error": "^2.1.1", + "tapable": "^1.1.3", + "util.promisify": "1.0.0" + }, + "engines": { + "node": ">=6.9" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/http-parser-js": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", + "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "dependencies": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "node_modules/iconv-corefoundation": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.5.tgz", + "integrity": "sha512-hI4m7udfV04OcjleOmDaR4gwXnH4xumxN+ZmywHDiKf2CmAzsT9SVYe7Y4pdnQbyZfXwAQyrElykbE5PrPRfmQ==", + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "cli-truncate": "^1.1.0", + "node-addon-api": "^1.6.3" + }, + "engines": { + "node": "^8.11.2 || >=10" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "dev": true, + "dependencies": { + "postcss": "^7.0.14" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "dependencies": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/in-publish": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz", + "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==", + "dev": true, + "bin": { + "in-install": "in-install.js", + "in-publish": "in-publish.js", + "not-in-install": "not-in-install.js", + "not-in-publish": "not-in-publish.js" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "devOptional": true + }, + "node_modules/internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "dependencies": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "node_modules/ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-bigint": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", + "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "devOptional": true, + "dependencies": { + "binary-extensions": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", + "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", + "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "devOptional": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "dependencies": { + "is-path-inside": "^2.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-in-cwd/node_modules/is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "dependencies": { + "path-is-inside": "^1.0.2" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "node_modules/is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "node_modules/istextorbinary": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-5.12.0.tgz", + "integrity": "sha512-wLDRWD7qpNTYubk04+q3en1+XZGS4vYWK0+SxNSXJLaITMMEK+J3o/TlOMyULeH1qozVZ9uUkKcyMA8odyxz8w==", + "dev": true, + "dependencies": { + "binaryextensions": "^4.15.0", + "editions": "^6.1.0", + "textextensions": "^5.11.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/jake": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", + "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "dev": true, + "dependencies": { + "async": "0.9.x", + "chalk": "^2.4.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/jake/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/jake/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/jake/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/jake/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/jest-worker": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.5.0.tgz", + "integrity": "sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw==", + "dev": true, + "dependencies": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 8.3" + } + }, + "node_modules/js-base64": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/js-yaml/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/jsan": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/jsan/-/jsan-3.1.13.tgz", + "integrity": "sha512-9kGpCsGHifmw6oJet+y8HaCl14y7qgAsxVdV3pCHDySNR3BfDC30zgkssd7x5LRVAT22dnpbe9JdzzmXZnq9/g==", + "dev": true + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "devOptional": true + }, + "node_modules/json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", + "dev": true + }, + "node_modules/json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lazy-val": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.4.tgz", + "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==", + "dev": true + }, + "node_modules/linked-list": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/linked-list/-/linked-list-0.1.0.tgz", + "integrity": "sha1-eYsP+X0bkqT9CEgPVa6k6dSdN78=", + "dev": true + }, + "node_modules/load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/load-json-file/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/loader-utils/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "devOptional": true + }, + "node_modules/loglevel": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", + "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + }, + "funding": { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/loglevel" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "dependencies": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lower-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz", + "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==", + "dev": true, + "dependencies": { + "tslib": "^1.10.0" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "dependencies": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dev": true, + "dependencies": { + "mime-db": "1.44.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", + "integrity": "sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A==", + "dev": true, + "dependencies": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.4.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "dependencies": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dependencies": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dependencies": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "node_modules/move-concurrently/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "dependencies": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "node_modules/nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "devOptional": true + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz", + "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.1", + "tslib": "^1.10.0" + } + }, + "node_modules/node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "dev": true, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "dev": true, + "dependencies": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", + "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==", + "dev": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dependencies": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + } + }, + "node_modules/node-libs-browser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "node_modules/node-loader": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/node-loader/-/node-loader-0.6.0.tgz", + "integrity": "sha1-x5fvUQle1YWZArFX9jhPY2HgWug=", + "dev": true + }, + "node_modules/node-releases": { + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", + "dev": true + }, + "node_modules/node-sass": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz", + "integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash": "^4.17.15", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.13.2", + "node-gyp": "^3.8.0", + "npmlog": "^4.0.0", + "request": "^2.88.0", + "sass-graph": "2.2.5", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + }, + "bin": { + "node-sass": "bin/node-sass" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/node-sass/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/node-sass/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/node-sass/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/node-sass/node_modules/cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "node_modules/node-sass/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/node-sass/node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/node-sass/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/node-sass/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/node-sass/node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "node_modules/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "optional": true, + "dependencies": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.4.tgz", + "integrity": "sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "devOptional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", + "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors/node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors/node_modules/es-abstract": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", + "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.2", + "is-string": "^1.0.5", + "object-inspect": "^1.9.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors/node_modules/es-abstract/node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors/node_modules/get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors/node_modules/is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors/node_modules/is-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", + "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors/node_modules/object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors/node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.getownpropertydescriptors/node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "dependencies": { + "url-parse": "^1.4.3" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dev": true, + "dependencies": { + "retry": "^0.12.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dependencies": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "node_modules/param-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.3.tgz", + "integrity": "sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "dependencies": { + "error-ex": "^1.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz", + "integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==", + "dev": true, + "dependencies": { + "no-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" + }, + "node_modules/path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "devOptional": true + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "node_modules/path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "optional": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/plist": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz", + "integrity": "sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==", + "dev": true, + "optional": true, + "dependencies": { + "base64-js": "^1.5.1", + "xmlbuilder": "^9.0.7" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/plist/node_modules/xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true, + "optional": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, + "dependencies": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/portfinder/node_modules/async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/portfinder/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", + "dev": true, + "dependencies": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "dev": true, + "dependencies": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "dev": true, + "dependencies": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz", + "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "node_modules/postcss/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss/node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/postcss/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/postcss/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/postcss/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "engines": { + "node": ">=4" + } + }, + "node_modules/pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "dev": true, + "dependencies": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + }, + "node_modules/prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "optional": true + }, + "node_modules/proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dev": true, + "dependencies": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dependencies": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "node_modules/pumpify/node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "dependencies": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/react": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", + "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + }, + "peerDependencies": { + "react": "^16.14.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-tooltip": { + "version": "4.2.19", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-4.2.19.tgz", + "integrity": "sha512-wF6h0a2nqX3UHw9aSoj77Tv/+/KIjRdb107otHtX+1wISad1QoLD+j5chrBDx7mjY1T4WKfrV2DN+iFCimdZOw==", + "dependencies": { + "prop-types": "^15.7.2", + "uuid": "^7.0.3" + }, + "engines": { + "npm": ">=6.13" + }, + "peerDependencies": { + "react": ">=16.0.0", + "react-dom": ">=16.0.0" + } + }, + "node_modules/read-config-file": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.0.0.tgz", + "integrity": "sha512-PHjROSdpceKUmqS06wqwP92VrM46PZSTubmNIMJ5DrMwg1OgenSTSEHIkCa6TiOJ+y/J0xnG1fFwG3M+Oi1aNA==", + "dev": true, + "dependencies": { + "dotenv": "^8.2.0", + "dotenv-expand": "^5.1.0", + "js-yaml": "^3.13.1", + "json5": "^2.1.2", + "lazy-val": "^1.0.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "dependencies": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "dependencies": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "dependencies": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "dependencies": { + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "devOptional": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "dependencies": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/redent/node_modules/indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "dependencies": { + "repeating": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpu-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/remotedev": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/remotedev/-/remotedev-0.2.9.tgz", + "integrity": "sha512-W8dHOv9BcFnetFEd08yNb5O9Hd+zkTFFnf9FRjNCkb4u+JgQ/U152Aw4q83AmY3m34d6KZwhK5ip/Qc331+4vA==", + "dev": true, + "dependencies": { + "jsan": "^3.1.3", + "querystring": "^0.2.0", + "rn-host-detect": "^1.0.1", + "socketcluster-client": "^13.0.0" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "devOptional": true + }, + "node_modules/renderkid": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", + "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", + "dev": true, + "dependencies": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^3.0.1" + } + }, + "node_modules/renderkid/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/renderkid/node_modules/domhandler": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", + "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", + "dev": true, + "dependencies": { + "domelementtype": "^2.2.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domhandler/node_modules/domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/renderkid/node_modules/domutils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", + "dev": true, + "dependencies": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/renderkid/node_modules/domutils/node_modules/domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/renderkid/node_modules/htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "node_modules/renderkid/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "dependencies": { + "is-finite": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-dir/node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "deprecated": "https://github.com/lydell/resolve-url#deprecated" + }, + "node_modules/resolve-url-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.4.tgz", + "integrity": "sha512-D3sQ04o0eeQEySLrcz4DsX3saHfsr8/N6tfhblxgZKXxMT2Louargg12oGNfoTRLV09GXhVUe5/qgA5vdgNigg==", + "dev": true, + "dependencies": { + "adjust-sourcemap-loader": "3.0.0", + "camelcase": "5.3.1", + "compose-function": "3.0.3", + "convert-source-map": "1.7.0", + "es6-iterator": "2.0.3", + "loader-utils": "1.2.3", + "postcss": "7.0.36", + "rework": "1.0.1", + "rework-visit": "1.0.0", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/resolve-url-loader/node_modules/emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/resolve-url-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "engines": { + "node": ">=0.12" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/rework": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz", + "integrity": "sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=", + "dev": true, + "dependencies": { + "convert-source-map": "^0.3.3", + "css": "^2.0.0" + } + }, + "node_modules/rework-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz", + "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=", + "dev": true + }, + "node_modules/rework/node_modules/convert-source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", + "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=", + "dev": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rn-host-detect": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/rn-host-detect/-/rn-host-detect-1.2.0.tgz", + "integrity": "sha512-btNg5kzHcjZZ7t7mvvV/4wNJ9e3MPgrWivkRgWURzXL0JJ0pwWlU4zrbmdlz3HHzHOxhBhHB4D+/dbMFfu4/4A==", + "dev": true + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dependencies": { + "aproba": "^1.1.1" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sanitize-filename": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", + "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "dev": true, + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/sass-graph": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", + "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^13.3.2" + }, + "bin": { + "sassgraph": "bin/sassgraph" + } + }, + "node_modules/sass-graph/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sass-graph/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/sass-graph/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/sass-graph/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/sass-graph/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/sass-graph/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/sass-graph/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/sass-graph/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/sass-graph/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/sass-loader": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.3.1.tgz", + "integrity": "sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.0.1", + "neo-async": "^2.5.0", + "pify": "^4.0.1", + "semver": "^6.3.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^3.0.0 || ^4.0.0" + } + }, + "node_modules/sass-loader/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/sass-loader/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/sc-channel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/sc-channel/-/sc-channel-1.2.0.tgz", + "integrity": "sha512-M3gdq8PlKg0zWJSisWqAsMmTVxYRTpVRqw4CWAdKBgAfVKumFcTjoCV0hYu7lgUXccCtCD8Wk9VkkE+IXCxmZA==", + "dev": true, + "dependencies": { + "component-emitter": "1.2.1" + } + }, + "node_modules/sc-channel/node_modules/component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "node_modules/sc-errors": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sc-errors/-/sc-errors-1.4.1.tgz", + "integrity": "sha512-dBn92iIonpChTxYLgKkIT/PCApvmYT6EPIbRvbQKTgY6tbEbIy8XVUv4pGyKwEK4nCmvX4TKXcN0iXC6tNW6rQ==", + "dev": true + }, + "node_modules/sc-formatter": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sc-formatter/-/sc-formatter-3.0.2.tgz", + "integrity": "sha512-9PbqYBpCq+OoEeRQ3QfFIGE6qwjjBcd2j7UjgDlhnZbtSnuGgHdcRklPKYGuYFH82V/dwd+AIpu8XvA1zqTd+A==", + "dev": true + }, + "node_modules/scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "dev": true, + "dependencies": { + "js-base64": "^2.1.8", + "source-map": "^0.4.2" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "node_modules/selfsigned": { + "version": "1.10.8", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz", + "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==", + "dev": true, + "dependencies": { + "node-forge": "^0.10.0" + } + }, + "node_modules/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "devOptional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "optional": true + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "node_modules/serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "node_modules/slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "optional": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/smart-buffer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==", + "dev": true, + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/socketcluster-client": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/socketcluster-client/-/socketcluster-client-13.0.1.tgz", + "integrity": "sha512-hxiE2xz6mgaBlhXbtBa4POgWVEvIcjCoHzf5LTUVhI9IL8V2ltV3Ze8pQsi9egqTjSz4RHPfyrJ7BiETe5Kthw==", + "dev": true, + "dependencies": { + "base-64": "0.1.0", + "clone": "2.1.1", + "component-emitter": "1.2.1", + "linked-list": "0.1.0", + "querystring": "0.2.0", + "sc-channel": "^1.2.0", + "sc-errors": "^1.4.0", + "sc-formatter": "^3.0.1", + "uuid": "3.2.1", + "ws": "5.1.1" + } + }, + "node_modules/socketcluster-client/node_modules/component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "node_modules/socketcluster-client/node_modules/uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/socketcluster-client/node_modules/ws": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.1.1.tgz", + "integrity": "sha512-bOusvpCb09TOBLbpMKszd45WKC2KPtxiyiHanv+H2DE3Az+1db5a/L7sVJZVDPUC1Br8f0SKRr1KjLpD1U/IAw==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", + "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^3.4.0", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/sockjs-client": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.2.tgz", + "integrity": "sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ==", + "dev": true, + "dependencies": { + "debug": "^3.2.6", + "eventsource": "^1.0.7", + "faye-websocket": "^0.11.3", + "inherits": "^2.0.4", + "json3": "^3.3.3", + "url-parse": "^1.5.3" + } + }, + "node_modules/sockjs-client/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/sockjs/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "node_modules/source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/source-map-loader": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-1.1.3.tgz", + "integrity": "sha512-6YHeF+XzDOrT/ycFJNI53cgEsp/tHTMl37hi7uVyqFAlTXW109JazaQCkbc+jjoL2637qkH1amLi+JzrIpt5lA==", + "dependencies": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.2", + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0", + "source-map": "^0.6.1", + "whatwg-mimetype": "^2.3.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/source-map-loader/node_modules/schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dependencies": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/source-map-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "optional": true + }, + "node_modules/sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.1.tgz", + "integrity": "sha512-w+daCzXN89PseTL99MkA+fxJEcU3wfaE/ah0i0lnOlpG1CYLJ2ZjzEry68YBKfLs4JfoTShrTEsJkAZuNZ/stw==", + "dev": true, + "dependencies": { + "figgy-pudding": "^3.5.1", + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/stat-mode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", + "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.1" + } + }, + "node_modules/stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dependencies": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "node_modules/stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", + "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", + "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "dependencies": { + "is-utf8": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "dependencies": { + "get-stdin": "^4.0.1" + }, + "bin": { + "strip-indent": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/style-loader": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz", + "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "schema-utils": "^2.7.0" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/style-loader/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "deprecated": "This version of tar is no longer supported, and will not receive security updates. Please upgrade asap.", + "dev": true, + "dependencies": { + "block-stream": "*", + "fstream": "^1.0.12", + "inherits": "2" + } + }, + "node_modules/temp-file": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.7.tgz", + "integrity": "sha512-9tBJKt7GZAQt/Rg0QzVWA8Am8c1EFl+CAv04/aBVqlx5oyfQ508sFIABshQ0xbZu6mBrFLWIUXO/bbLYghW70g==", + "dev": true, + "dependencies": { + "async-exit-hook": "^2.0.1", + "fs-extra": "^8.1.0" + } + }, + "node_modules/terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz", + "integrity": "sha512-/fKw3R+hWyHfYx7Bv6oPqmk4HGQcrWLtV3X6ggvPuwPNHSnzvVV51z6OaaCOus4YLjutYGOz3pEpbhe6Up2s1w==", + "dev": true, + "dependencies": { + "cacache": "^13.0.1", + "find-cache-dir": "^3.3.1", + "jest-worker": "^25.4.0", + "p-limit": "^2.3.0", + "schema-utils": "^2.6.6", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.6.12", + "webpack-sources": "^1.4.3" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/terser-webpack-plugin/node_modules/find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/terser-webpack-plugin/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/terser/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/textextensions": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-5.12.0.tgz", + "integrity": "sha512-IYogUDaP65IXboCiPPC0jTLLBzYlhhw2Y4b0a2trPgbHNGGGEfuHE6tds+yDcCf4mpNDaGISFzwSSezcXt+d6w==", + "dev": true, + "engines": { + "node": ">=0.8" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "dev": true, + "dependencies": { + "glob": "^7.1.2" + } + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=", + "dev": true, + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "optional": true, + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unbox-primitive/node_modules/has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "devOptional": true, + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dev": true, + "dependencies": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "deprecated": "Please see https://github.com/lydell/urix#deprecated" + }, + "node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "dev": true, + "dependencies": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } + } + }, + "node_modules/url-loader/node_modules/loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/url-loader/node_modules/schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/url-parse": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", + "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/utf-8-validate": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.5.tgz", + "integrity": "sha512-+pnxRYsS/axEpkrrEpzYfNZGXp0IjC/9RIxwM5gntY4Koi8SHmUGSfxfWqxZdRxrtaoVstuOzUp/rbs3JSPELQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.2.0" + } + }, + "node_modules/utf8-byte-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", + "integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=", + "dev": true + }, + "node_modules/util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", + "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/version-compare": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/version-compare/-/version-compare-1.1.0.tgz", + "integrity": "sha512-zVKtPOJTC9x23lzS4+4D7J+drq80BXVYAmObnr5zqxxFVH7OffJ1lJlAS7LYsQNV56jx/wtbw0UV7XHLrvd6kQ==", + "dev": true, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/version-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-1.1.0.tgz", + "integrity": "sha512-R1Ggfg2EXamrnrV3TkZ6yBNgITDbclB3viwSjbZ3+eK0VVNK4ajkYJTnDz5N0bIMYDtK9MUBvXJUnKO5RWWJ6w==", + "dev": true, + "dependencies": { + "version-compare": "^1.0.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "node_modules/watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "dependencies": { + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + }, + "optionalDependencies": { + "chokidar": "^3.4.1", + "watchpack-chokidar2": "^2.0.1" + } + }, + "node_modules/watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "optional": true, + "dependencies": { + "chokidar": "^2.1.8" + } + }, + "node_modules/watchpack/node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "optional": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/watchpack/node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/watchpack/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "optional": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/watchpack/node_modules/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "optional": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/watchpack/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "optional": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/watchpack/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/watchpack/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "optional": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/watchpack/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "optional": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/watchpack/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "optional": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/watchpack/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "optional": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/watchpack/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "optional": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webpack": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", + "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", + "dependencies": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=6.11.5" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + }, + "webpack-command": { + "optional": true + } + } + }, + "node_modules/webpack-cli": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz", + "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "cross-spawn": "^6.0.5", + "enhanced-resolve": "^4.1.1", + "findup-sync": "^3.0.0", + "global-modules": "^2.0.0", + "import-local": "^2.0.0", + "interpret": "^1.4.0", + "loader-utils": "^1.4.0", + "supports-color": "^6.1.0", + "v8-compile-cache": "^2.1.1", + "yargs": "^13.3.2" + }, + "bin": { + "webpack-cli": "bin/cli.js" + }, + "engines": { + "node": ">=6.11.5" + }, + "peerDependencies": { + "webpack": "4.x.x" + } + }, + "node_modules/webpack-cli/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/webpack-cli/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/webpack-cli/node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/webpack-cli/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/webpack-cli/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/webpack-cli/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/webpack-cli/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/webpack-cli/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/webpack-cli/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-cli/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-cli/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-cli/node_modules/y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, + "node_modules/webpack-cli/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/webpack-cli/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/webpack-dev-middleware": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz", + "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==", + "dev": true, + "dependencies": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/webpack-dev-middleware/node_modules/memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "node_modules/webpack-dev-server": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.3.tgz", + "integrity": "sha512-3x31rjbEQWKMNzacUZRE6wXvUFuGpH7vr0lIEbYpMAG9BOxi0928QU1BBswOAP3kg3H1O4hiS+sq4YyAn6ANnA==", + "dev": true, + "dependencies": { + "ansi-html-community": "0.0.8", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.8", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.21", + "sockjs-client": "^1.5.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 6.11.5" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/webpack-dev-server/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/webpack-dev-server/node_modules/cliui/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/cliui/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/webpack-dev-server/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/webpack-dev-server/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/webpack-dev-server/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/webpack-dev-server/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/string-width/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/string-width/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack-dev-server/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/webpack-dev-server/node_modules/y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, + "node_modules/webpack-dev-server/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/webpack-dev-server/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "dependencies": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/webpack-log/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/webpack-merge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", + "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + } + }, + "node_modules/webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dependencies": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + } + }, + "node_modules/webpack-sources/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack/node_modules/cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "dependencies": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "node_modules/webpack/node_modules/enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "dependencies": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/webpack/node_modules/enhanced-resolve/node_modules/memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + }, + "engines": { + "node": ">=4.3.0 <5.0.0 || >=5.10" + } + }, + "node_modules/webpack/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/webpack/node_modules/memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dependencies": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "node_modules/webpack/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dependencies": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/webpack/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webpack/node_modules/ssri": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "dependencies": { + "figgy-pudding": "^3.5.1" + } + }, + "node_modules/webpack/node_modules/terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "dependencies": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "engines": { + "node": ">= 6.9.0" + }, + "peerDependencies": { + "webpack": "^4.0.0" + } + }, + "node_modules/webpack/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "node_modules/webpack/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dependencies": { + "errno": "~0.1.7" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/xpipe": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/xpipe/-/xpipe-1.0.5.tgz", + "integrity": "sha1-jdi/Rfw/f1Xw4FS4ePQ6YmFNr98=", + "dev": true + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.6.tgz", + "integrity": "sha512-PlVX4Y0lDTN6E2V4ES2tEdyvXkeKzxa8c/vo0pxPr/TqbztddTP0yn7zZylIyiAuxerqj0Q5GhpJ1YJCP8LaZQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.7", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", + "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/compat-data": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.12.7.tgz", + "integrity": "sha512-YaxPMGs/XIWtYqrdEOZOCPsVWfEoriXopnsz3/i7apYPXQ3698UFhS6dVT1KN5qOsWmVgw/FOrmQgpRaZayGsw==", + "dev": true + }, + "@babel/core": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.12.9.tgz", + "integrity": "sha512-gTXYh3M5wb7FRXQy+FErKFAv90BnlOuNn1QkCK2lREoPAjrQCO49+HVSrFoe5uakFAF5eenS75KbO2vQiLrTMQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.7", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.9", + "@babel/types": "^7.12.7", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.12.5.tgz", + "integrity": "sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A==", + "dev": true, + "requires": { + "@babel/types": "^7.12.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", + "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.12.5.tgz", + "integrity": "sha512-+qH6NrscMolUlzOYngSBMIOQpKUGPPsc61Bu5W10mg84LxZ7cmvnBHzARKbDoFxVvqqAbj6Tg6N7bSrWSPXMyw==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.12.5", + "@babel/helper-validator-option": "^7.12.1", + "browserslist": "^4.14.5", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.12.1.tgz", + "integrity": "sha512-hkL++rWeta/OVOBTRJc9a5Azh5mt5WgZUGAKMD8JM141YsE08K//bp1unBBieO6rUKkIPyUE0USQ30jAy3Sk1w==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-member-expression-to-functions": "^7.12.1", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-split-export-declaration": "^7.10.4" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.12.7.tgz", + "integrity": "sha512-idnutvQPdpbduutvi3JVfEgcVIHooQnhvhx0Nk9isOINOIGYkZea1Pk2JlJRiUnMefrlvr0vkByATBY/mB4vjQ==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "regexpu-core": "^4.7.1" + } + }, + "@babel/helper-define-map": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", + "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.12.1.tgz", + "integrity": "sha512-dmUwH8XmlrUpVqgtZ737tK88v07l840z9j3OEhCLwKTkjlvKpfqXVIZ0wpK3aeOxspwGrf/5AP5qLx4rO3w5rA==", + "dev": true, + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", + "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", + "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", + "dev": true, + "requires": { + "@babel/types": "^7.12.7" + } + }, + "@babel/helper-module-imports": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "dev": true, + "requires": { + "@babel/types": "^7.12.5" + } + }, + "@babel/helper-module-transforms": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.12.1.tgz", + "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-simple-access": "^7.12.1", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/helper-validator-identifier": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.1", + "@babel/types": "^7.12.1", + "lodash": "^4.17.19" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.7.tgz", + "integrity": "sha512-I5xc9oSJ2h59OwyUqjv95HRyzxj53DAubUERgQMrpcCEYQyToeHA+NEcUEsVWB4j53RDeskeBJ0SgRAYHDBckw==", + "dev": true, + "requires": { + "@babel/types": "^7.12.7" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.12.1.tgz", + "integrity": "sha512-9d0KQCRM8clMPcDwo8SevNs+/9a8yWVVmaE80FGJcEP8N1qToREmWEGnBn8BUlJhYRFz6fqxeRL1sl5Ogsed7A==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-wrap-function": "^7.10.4", + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-replace-supers": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.12.5.tgz", + "integrity": "sha512-5YILoed0ZyIpF4gKcpZitEnXEJ9UoDRki1Ey6xz46rxOzfNMAhVIJMoune1hmPVxh40LRv1+oafz7UsWX+vyWA==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.12.1", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.12.1.tgz", + "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", + "dev": true, + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.12.1.tgz", + "integrity": "sha512-Mf5AUuhG1/OCChOJ/HcADmvcHM42WJockombn8ATJG3OnyiSxBK/Mm5x78BQWvmtXZKHgbjdGL2kin/HOLlZGA==", + "dev": true, + "requires": { + "@babel/types": "^7.12.1" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.12.1.tgz", + "integrity": "sha512-YpJabsXlJVWP0USHjnC/AQDTLlZERbON577YUVO/wLpqyj6HAtVYnWaQaN0iUN+1/tWn3c+uKKXjRut5115Y2A==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.12.3", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.12.3.tgz", + "integrity": "sha512-Cvb8IuJDln3rs6tzjW3Y8UeelAOdnpB8xtQ4sme2MSZ9wOxrbThporC0y/EtE16VAtoyEfLM404Xr1e0OOp+ow==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helpers": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.12.5.tgz", + "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.12.7.tgz", + "integrity": "sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.12.1.tgz", + "integrity": "sha512-d+/o30tJxFxrA1lhzJqiUcEJdI6jKlNregCv5bASeGf2Q4MXmnwH7viDo7nhx1/ohf09oaH8j1GVYG/e3Yqk6A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.12.1", + "@babel/plugin-syntax-async-generators": "^7.8.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.12.1.tgz", + "integrity": "sha512-cKp3dlQsFsEs5CWKnN7BnSHOd0EOW8EKpEjkoz1pO2E5KzIDNV9Ros1b0CnmbVgAGXJubOYVBOGCT1OmJwOI7w==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.12.1.tgz", + "integrity": "sha512-a4rhUSZFuq5W8/OO8H7BL5zspjnc1FLd9hlOxIK/f7qG4a0qsqk8uvF/ywgBA8/OmjsapjpvaEOYItfGG1qIvQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.12.1.tgz", + "integrity": "sha512-6CThGf0irEkzujYS5LQcjBx8j/4aQGiVv7J9+2f7pGfxqyKh3WnmVJYW3hdrQjyksErMGBPQrCnHfOtna+WLbw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.12.1.tgz", + "integrity": "sha512-GoLDUi6U9ZLzlSda2Df++VSqDJg3CG+dR0+iWsv6XRw1rEq+zwt4DirM9yrxW6XWaTpmai1cWJLMfM8qQJf+yw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.0" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.12.1.tgz", + "integrity": "sha512-k8ZmVv0JU+4gcUGeCDZOGd0lCIamU/sMtIiX3UWnUc5yzgq6YUGyEolNYD+MLYKfSzgECPcqetVcJP9Afe/aCA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.12.1.tgz", + "integrity": "sha512-nZY0ESiaQDI1y96+jk6VxMOaL4LPo/QDHBqL+SF3/vl6dHkTwHlOI8L4ZwuRBHgakRBw5zsVylel7QPbbGuYgg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.12.7.tgz", + "integrity": "sha512-8c+uy0qmnRTeukiGsjLGy6uVs/TFjJchGXUeBqlG4VWYOdJWkhhVPdQ3uHwbmalfJwv2JsV0qffXP4asRfL2SQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.12.1.tgz", + "integrity": "sha512-s6SowJIjzlhx8o7lsFx5zmY4At6CTtDvgNQDdPzkBQucle58A6b/TTeEBYtyDgmcXjUTM+vE8YOGHZzzbc/ioA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.12.1" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.12.1.tgz", + "integrity": "sha512-hFvIjgprh9mMw5v42sJWLI1lzU5L2sznP805zeT6rySVRA0Y18StRhDqhSxlap0oVgItRsB6WSROp4YnJTJz0g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.12.7.tgz", + "integrity": "sha512-4ovylXZ0PWmwoOvhU2vhnzVNnm88/Sm9nx7V8BPgMvAzn5zDou3/Awy0EjglyubVHasJj+XCEkr/r1X3P5elCA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.12.1.tgz", + "integrity": "sha512-mwZ1phvH7/NHK6Kf8LP7MYDogGV+DKB1mryFOEwx5EBNQrosvIczzZFTUmWaeujd5xT6G1ELYWUz3CutMhjE1w==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.12.1.tgz", + "integrity": "sha512-MYq+l+PvHuw/rKUz1at/vb6nCnQ2gmJBNaM62z0OgH7B2W1D9pvkpYtlti9bGtizNIU1K3zm4bZF9F91efVY0w==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz", + "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz", + "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.12.1.tgz", + "integrity": "sha512-5QB50qyN44fzzz4/qxDPQMBCTHgxg3n0xRBLJUmBlLoU/sFvxVWGZF/ZUfMVDQuJUKXaBhbupxIzIfZ6Fwk/0A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.12.1.tgz", + "integrity": "sha512-SDtqoEcarK1DFlRJ1hHRY5HvJUj5kX4qmtpMAm2QnhOlyuMC4TMdCRgW6WXpv93rZeYNeLP22y8Aq2dbcDRM1A==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.12.1" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.12.1.tgz", + "integrity": "sha512-5OpxfuYnSgPalRpo8EWGPzIYf0lHBWORCkj5M0oLBwHdlux9Ri36QqGW3/LR13RSVOAoUUMzoPI/jpE4ABcHoA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.12.1.tgz", + "integrity": "sha512-zJyAC9sZdE60r1nVQHblcfCj29Dh2Y0DOvlMkcqSo0ckqjiCwNiUezUKw+RjOCwGfpLRwnAeQ2XlLpsnGkvv9w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.12.1.tgz", + "integrity": "sha512-/74xkA7bVdzQTBeSUhLLJgYIcxw/dpEpCdRDiHgPJ3Mv6uC11UhjpOhl72CgqbBCmt1qtssCyB2xnJm1+PFjog==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-define-map": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-split-export-declaration": "^7.10.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.12.1.tgz", + "integrity": "sha512-vVUOYpPWB7BkgUWPo4C44mUQHpTZXakEqFjbv8rQMg7TC6S6ZhGZ3otQcRH6u7+adSlE5i0sp63eMC/XGffrzg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.12.1.tgz", + "integrity": "sha512-fRMYFKuzi/rSiYb2uRLiUENJOKq4Gnl+6qOv5f8z0TZXg3llUwUhsNNwrwaT/6dUhJTzNpBr+CUvEWBtfNY1cw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.12.1.tgz", + "integrity": "sha512-B2pXeRKoLszfEW7J4Hg9LoFaWEbr/kzo3teWHmtFCszjRNa/b40f9mfeqZsIDLLt/FjwQ6pz/Gdlwy85xNckBA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.12.1.tgz", + "integrity": "sha512-iRght0T0HztAb/CazveUpUQrZY+aGKKaWXMJ4uf9YJtqxSUe09j3wteztCUDRHs+SRAL7yMuFqUsLoAKKzgXjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.12.1.tgz", + "integrity": "sha512-7tqwy2bv48q+c1EHbXK0Zx3KXd2RVQp6OC7PbwFNt/dPTAV3Lu5sWtWuAj8owr5wqtWnqHfl2/mJlUmqkChKug==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.12.1.tgz", + "integrity": "sha512-Zaeq10naAsuHo7heQvyV0ptj4dlZJwZgNAtBYBnu5nNKJoW62m0zKcIEyVECrUKErkUkg6ajMy4ZfnVZciSBhg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.12.1.tgz", + "integrity": "sha512-JF3UgJUILoFrFMEnOJLJkRHSk6LUSXLmEFsA23aR2O5CSLUxbeUX1IZ1YQ7Sn0aXb601Ncwjx73a+FVqgcljVw==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.12.1.tgz", + "integrity": "sha512-+PxVGA+2Ag6uGgL0A5f+9rklOnnMccwEBzwYFL3EUaKuiyVnUipyXncFcfjSkbimLrODoqki1U9XxZzTvfN7IQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.12.1.tgz", + "integrity": "sha512-1sxePl6z9ad0gFMB9KqmYofk34flq62aqMt9NqliS/7hPEpURUCMbyHXrMPlo282iY7nAvUB1aQd5mg79UD9Jg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.12.1.tgz", + "integrity": "sha512-tDW8hMkzad5oDtzsB70HIQQRBiTKrhfgwC/KkJeGsaNFTdWhKNt/BiE8c5yj19XiGyrxpbkOfH87qkNg1YGlOQ==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.12.1.tgz", + "integrity": "sha512-dY789wq6l0uLY8py9c1B48V8mVL5gZh/+PQ5ZPrylPYsnAvnEMjqsUXkuoDVPeVK+0VyGar+D08107LzDQ6pag==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-simple-access": "^7.12.1", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.12.1.tgz", + "integrity": "sha512-Hn7cVvOavVh8yvW6fLwveFqSnd7rbQN3zJvoPNyNaQSvgfKmDBO9U1YL9+PCXGRlZD9tNdWTy5ACKqMuzyn32Q==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.10.4", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-validator-identifier": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.12.1.tgz", + "integrity": "sha512-aEIubCS0KHKM0zUos5fIoQm+AZUMt1ZvMpqz0/H5qAQ7vWylr9+PLYurT+Ic7ID/bKLd4q8hDovaG3Zch2uz5Q==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.12.1.tgz", + "integrity": "sha512-tB43uQ62RHcoDp9v2Nsf+dSM8sbNodbEicbQNA53zHz8pWUhsgHSJCGpt7daXxRydjb0KnfmB+ChXOv3oADp1Q==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.12.1.tgz", + "integrity": "sha512-+eW/VLcUL5L9IvJH7rT1sT0CzkdUTvPrXC2PXTn/7z7tXLBuKvezYbGdxD5WMRoyvyaujOq2fWoKl869heKjhw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.12.1.tgz", + "integrity": "sha512-AvypiGJH9hsquNUn+RXVcBdeE3KHPZexWRdimhuV59cSoOt5kFBmqlByorAeUlGG2CJWd0U+4ZtNKga/TB0cAw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.12.1" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.12.1.tgz", + "integrity": "sha512-xq9C5EQhdPK23ZeCdMxl8bbRnAgHFrw5EOC3KJUsSylZqdkCaFEXxGSBuTSObOpiiHHNyb82es8M1QYgfQGfNg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.12.1.tgz", + "integrity": "sha512-6MTCR/mZ1MQS+AwZLplX4cEySjCpnIF26ToWo942nqn8hXSm7McaHQNeGx/pt7suI1TWOWMfa/NgBhiqSnX0cQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.12.1.tgz", + "integrity": "sha512-gYrHqs5itw6i4PflFX3OdBPMQdPbF4bj2REIUxlMRUFk0/ZOAIpDFuViuxPjUL7YC8UPnf+XG7/utJvqXdPKng==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.12.1.tgz", + "integrity": "sha512-pOnUfhyPKvZpVyBHhSBoX8vfA09b7r00Pmm1sH+29ae2hMTKVmSp4Ztsr8KBKjLjx17H0eJqaRC3bR2iThM54A==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.12.1.tgz", + "integrity": "sha512-GFZS3c/MhX1OusqB1MZ1ct2xRzX5ppQh2JU1h2Pnfk88HtFTM+TWQqJNfwkmxtPQtb/s1tk87oENfXJlx7rSDw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.12.1.tgz", + "integrity": "sha512-vuLp8CP0BE18zVYjsEBZ5xoCecMK6LBMMxYzJnh01rxQRvhNhH1csMMmBfNo5tGpGO+NhdSNW2mzIvBu3K1fng==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.12.1" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.12.7.tgz", + "integrity": "sha512-VEiqZL5N/QvDbdjfYQBhruN0HYjSPjC4XkeqW4ny/jNtH9gcbgaqBIXYEZCNnESMAGs0/K/R7oFGMhOyu/eIxg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.12.1.tgz", + "integrity": "sha512-b4Zx3KHi+taXB1dVRBhVJtEPi9h1THCeKmae2qP0YdUHIFhVjtpqqNfxeVAa1xeHVhAy4SbHxEwx5cltAu5apw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.12.1.tgz", + "integrity": "sha512-EPGgpGy+O5Kg5pJFNDKuxt9RdmTgj5sgrus2XVeMp/ZIbOESadgILUbm50SNpghOh3/6yrbsH+NB5+WJTmsA7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.12.1.tgz", + "integrity": "sha512-I8gNHJLIc7GdApm7wkVnStWssPNbSRMPtgHdmH3sRM1zopz09UWPS4x5V4n1yz/MIWTVnJ9sp6IkuXdWM4w+2Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.12.1.tgz", + "integrity": "sha512-SqH4ClNngh/zGwHZOOQMTD+e8FGWexILV+ePMyiDJttAWRh5dhDL8rcl5lSgU3Huiq6Zn6pWTMvdPAb21Dwdyg==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.12.1", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/preset-env": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.12.7.tgz", + "integrity": "sha512-OnNdfAr1FUQg7ksb7bmbKoby4qFOHw6DKWWUNB9KqnnCldxhxJlP+21dpyaWFmf2h0rTbOkXJtAGevY3XW1eew==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.12.7", + "@babel/helper-compilation-targets": "^7.12.5", + "@babel/helper-module-imports": "^7.12.5", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-validator-option": "^7.12.1", + "@babel/plugin-proposal-async-generator-functions": "^7.12.1", + "@babel/plugin-proposal-class-properties": "^7.12.1", + "@babel/plugin-proposal-dynamic-import": "^7.12.1", + "@babel/plugin-proposal-export-namespace-from": "^7.12.1", + "@babel/plugin-proposal-json-strings": "^7.12.1", + "@babel/plugin-proposal-logical-assignment-operators": "^7.12.1", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.12.1", + "@babel/plugin-proposal-numeric-separator": "^7.12.7", + "@babel/plugin-proposal-object-rest-spread": "^7.12.1", + "@babel/plugin-proposal-optional-catch-binding": "^7.12.1", + "@babel/plugin-proposal-optional-chaining": "^7.12.7", + "@babel/plugin-proposal-private-methods": "^7.12.1", + "@babel/plugin-proposal-unicode-property-regex": "^7.12.1", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-class-properties": "^7.12.1", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.12.1", + "@babel/plugin-transform-arrow-functions": "^7.12.1", + "@babel/plugin-transform-async-to-generator": "^7.12.1", + "@babel/plugin-transform-block-scoped-functions": "^7.12.1", + "@babel/plugin-transform-block-scoping": "^7.12.1", + "@babel/plugin-transform-classes": "^7.12.1", + "@babel/plugin-transform-computed-properties": "^7.12.1", + "@babel/plugin-transform-destructuring": "^7.12.1", + "@babel/plugin-transform-dotall-regex": "^7.12.1", + "@babel/plugin-transform-duplicate-keys": "^7.12.1", + "@babel/plugin-transform-exponentiation-operator": "^7.12.1", + "@babel/plugin-transform-for-of": "^7.12.1", + "@babel/plugin-transform-function-name": "^7.12.1", + "@babel/plugin-transform-literals": "^7.12.1", + "@babel/plugin-transform-member-expression-literals": "^7.12.1", + "@babel/plugin-transform-modules-amd": "^7.12.1", + "@babel/plugin-transform-modules-commonjs": "^7.12.1", + "@babel/plugin-transform-modules-systemjs": "^7.12.1", + "@babel/plugin-transform-modules-umd": "^7.12.1", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.12.1", + "@babel/plugin-transform-new-target": "^7.12.1", + "@babel/plugin-transform-object-super": "^7.12.1", + "@babel/plugin-transform-parameters": "^7.12.1", + "@babel/plugin-transform-property-literals": "^7.12.1", + "@babel/plugin-transform-regenerator": "^7.12.1", + "@babel/plugin-transform-reserved-words": "^7.12.1", + "@babel/plugin-transform-shorthand-properties": "^7.12.1", + "@babel/plugin-transform-spread": "^7.12.1", + "@babel/plugin-transform-sticky-regex": "^7.12.7", + "@babel/plugin-transform-template-literals": "^7.12.1", + "@babel/plugin-transform-typeof-symbol": "^7.12.1", + "@babel/plugin-transform-unicode-escapes": "^7.12.1", + "@babel/plugin-transform-unicode-regex": "^7.12.1", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.12.7", + "core-js-compat": "^3.7.0", + "semver": "^5.5.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "@babel/preset-modules": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", + "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/runtime": { + "version": "7.12.5", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", + "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.12.7.tgz", + "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.12.7", + "@babel/types": "^7.12.7" + } + }, + "@babel/traverse": { + "version": "7.12.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.12.9.tgz", + "integrity": "sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.5", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.12.7", + "@babel/types": "^7.12.7", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "@babel/types": { + "version": "7.12.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.12.7.tgz", + "integrity": "sha512-MNyI92qZq6jrQkXvtIiykvl4WtoRrVV9MPn+ZfsoEENjiWcBQ3ZSHrkxnJWgWtLX3XXqX5hrSQ+X69wkmesXuQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "@develar/schema-utils": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", + "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", + "dev": true, + "requires": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + } + }, + "@electron/get": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.13.1.tgz", + "integrity": "sha512-U5vkXDZ9DwXtkPqlB45tfYnnYBN8PePp1z/XDCupnSpdrxT8/ThCv9WCwPLf9oqiSGZTkH6dx2jDUPuoXpjkcA==", + "requires": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "global-agent": "^3.0.0", + "global-tunnel-ng": "^2.7.1", + "got": "^9.6.0", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + } + } + }, + "@electron/remote": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@electron/remote/-/remote-2.0.1.tgz", + "integrity": "sha512-bGX4/yB2bPZwXm1DsxgoABgH0Cz7oFtXJgkerB8VrStYdTyvhGAULzNLRn9rVmeAuC3VUDXaXpZIlZAZHpsLIA==", + "requires": {} + }, + "@electron/universal": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-1.0.4.tgz", + "integrity": "sha512-ajZoumi4XwqwmZe8YVhu4XGkZBCPyWZsVCQONPTIe9TUlleSN+dic3YpXlaWcilx/HOzTdldTKtabNTeI0gDoA==", + "dev": true, + "requires": { + "@malept/cross-spawn-promise": "^1.1.0", + "asar": "^3.0.3", + "debug": "^4.3.1", + "dir-compare": "^2.4.0", + "fs-extra": "^9.0.1" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "@malept/cross-spawn-promise": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz", + "integrity": "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.1" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==" + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "@types/anymatch": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", + "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==", + "dev": true + }, + "@types/debug": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", + "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", + "dev": true + }, + "@types/fs-extra": { + "version": "9.0.10", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.10.tgz", + "integrity": "sha512-O9T2LLkRDiTlalOBdjEkcnT0MRdT2+wglCl7pJUJ3mkWkR8hX4K+5bg2raQNJcLv4V8zGuTXe7Ud3wSqkTyuyQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-SEYeGAIQIQX8NN6LDKprLjbrd5dARM5EXsd8GI/A5l0apYI1fGMWgPHSe4ZKL4eozlAyI+doUE9XbYS4xCkQ1w==", + "dev": true, + "requires": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "@types/html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-giAlZwstKbmvMk1OO7WXSj4OZ0keXAcl2TQq4LWHiiPH2ByaH7WeUzng+Qej8UPxxv+8lRTuouo0iaNDBuzIBA==", + "dev": true + }, + "@types/json-schema": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.6.tgz", + "integrity": "sha512-3c+yGKvVP5Y9TYBEibGNR+kLtijnj7mYrXRg+WpFb2X9xm04g/DXYkfg4hmzJQosc9snFNUPkbYIhu+KAm6jJw==" + }, + "@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "dev": true + }, + "@types/node": { + "version": "12.19.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.6.tgz", + "integrity": "sha512-U2VopDdmBoYBmtm8Rz340mvvSz34VgX/K9+XCuckvcLGMkt3rbMX8soqFOikIPlPBc5lmw8By9NUK7bEFSBFlQ==", + "dev": true + }, + "@types/plist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.2.tgz", + "integrity": "sha512-ULqvZNGMv0zRFvqn8/4LSPtnmN4MfhlPNtJCTpKuIIxGVGZ2rYWzFXrvEBoh9CVyqSE7D6YFRJ1hydLHI6kbWw==", + "dev": true, + "optional": true, + "requires": { + "@types/node": "*", + "xmlbuilder": ">=11.0.1" + } + }, + "@types/source-list-map": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.2.tgz", + "integrity": "sha512-K5K+yml8LTo9bWJI/rECfIPrGgxdpeNbj+d53lwN4QjW1MCwlkhUms+gtdzigTeUyBr09+u8BwOIY3MXvHdcsA==", + "dev": true + }, + "@types/tapable": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-1.0.7.tgz", + "integrity": "sha512-0VBprVqfgFD7Ehb2vd8Lh9TG3jP98gvr8rgehQqzztZNI7o8zS8Ad4jyZneKELphpuE212D8J70LnSNQSyO6bQ==", + "dev": true + }, + "@types/uglify-js": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.13.0.tgz", + "integrity": "sha512-EGkrJD5Uy+Pg0NUR8uA4bJ5WMfljyad0G+784vLCNUkD+QwOJXUbBYExXfVGf7YtyzdQp3L/XMYcliB987kL5Q==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@types/verror": { + "version": "1.10.4", + "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.4.tgz", + "integrity": "sha512-OjJdqx6QlbyZw9LShPwRW+Kmiegeg3eWNI41MQQKaG3vjdU2L9SRElntM51HmHBY1cu7izxQJ1lMYioQh3XMBg==", + "dev": true, + "optional": true + }, + "@types/webpack": { + "version": "4.41.27", + "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-4.41.27.tgz", + "integrity": "sha512-wK/oi5gcHi72VMTbOaQ70VcDxSQ1uX8S2tukBK9ARuGXrYM/+u4ou73roc7trXDNmCxCoerE8zruQqX/wuHszA==", + "dev": true, + "requires": { + "@types/anymatch": "*", + "@types/node": "*", + "@types/tapable": "^1", + "@types/uglify-js": "*", + "@types/webpack-sources": "*", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "@types/webpack-env": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.16.0.tgz", + "integrity": "sha512-Fx+NpfOO0CpeYX2g9bkvX8O5qh9wrU1sOF4g8sft4Mu7z+qfe387YlyY8w8daDyDsKY5vUxM0yxkAYnbkRbZEw==", + "dev": true + }, + "@types/webpack-sources": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/webpack-sources/-/webpack-sources-2.1.0.tgz", + "integrity": "sha512-LXn/oYIpBeucgP1EIJbKQ2/4ZmpvRl+dlrFdX7+94SKRUV3Evy3FsfMZY318vGhkWUS5MPhtOM3w1/hCOAOXcg==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/source-list-map": "*", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, + "@types/yargs": { + "version": "15.0.13", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.13.tgz", + "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "20.2.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.0.tgz", + "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", + "dev": true + }, + "@webassemblyjs/ast": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", + "integrity": "sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA==", + "requires": { + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz", + "integrity": "sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz", + "integrity": "sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz", + "integrity": "sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA==" + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz", + "integrity": "sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA==", + "requires": { + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz", + "integrity": "sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw==" + }, + "@webassemblyjs/helper-module-context": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz", + "integrity": "sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g==", + "requires": { + "@webassemblyjs/ast": "1.9.0" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz", + "integrity": "sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz", + "integrity": "sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz", + "integrity": "sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz", + "integrity": "sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz", + "integrity": "sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz", + "integrity": "sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/helper-wasm-section": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-opt": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "@webassemblyjs/wast-printer": "1.9.0" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz", + "integrity": "sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz", + "integrity": "sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-buffer": "1.9.0", + "@webassemblyjs/wasm-gen": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz", + "integrity": "sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-wasm-bytecode": "1.9.0", + "@webassemblyjs/ieee754": "1.9.0", + "@webassemblyjs/leb128": "1.9.0", + "@webassemblyjs/utf8": "1.9.0" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz", + "integrity": "sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/floating-point-hex-parser": "1.9.0", + "@webassemblyjs/helper-api-error": "1.9.0", + "@webassemblyjs/helper-code-frame": "1.9.0", + "@webassemblyjs/helper-fsm": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz", + "integrity": "sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/wast-parser": "1.9.0", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "7zip": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/7zip/-/7zip-0.0.6.tgz", + "integrity": "sha1-nK+xca+CMpSQNTtIFvAzR6oVCjA=", + "dev": true + }, + "7zip-bin": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.0.3.tgz", + "integrity": "sha512-GLyWIFBbGvpKPGo55JyRZAo4lVbnBiD52cKlw/0Vt+wnmKvWJkpZvsjVoaIolyBXDeAQKSicRtqFNPem9w0WYA==", + "dev": true + }, + "abab": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz", + "integrity": "sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==" + }, + "adjust-sourcemap-loader": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-3.0.0.tgz", + "integrity": "sha512-YBrGyT2/uVQ/c6Rr+t6ZJXniY03YtHGMJQYal368burRGYKqhx9qGTWqcBU5s1CwYY9E/ri63RYyG1IacMZtqw==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "requires": {} + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "requires": { + "string-width": "^4.1.0" + } + }, + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "devOptional": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "devOptional": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "app-builder-bin": { + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-3.5.12.tgz", + "integrity": "sha512-lQARM2AielmFoBeIo6LZigAe+58Wwe07ZWkt+wVeDxzyieNmeWjlvz/V5dKzinydwdHd+CNswN86sww46yijjA==", + "dev": true + }, + "app-builder-lib": { + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-22.10.5.tgz", + "integrity": "sha512-/W8nlGamJCtKlQtsMWwU9vb+cX4pTNY+rJWCuc7oXUykVSMS50W7LhQusIjCelNfymUQ1XCu6cXEY/ylqhX12A==", + "dev": true, + "requires": { + "@develar/schema-utils": "~2.6.5", + "@electron/universal": "1.0.4", + "7zip-bin": "~5.0.3", + "async-exit-hook": "^2.0.1", + "bluebird-lst": "^1.0.9", + "builder-util": "22.10.5", + "builder-util-runtime": "8.7.3", + "chromium-pickle-js": "^0.2.0", + "debug": "^4.3.2", + "ejs": "^3.1.6", + "electron-publish": "22.10.5", + "fs-extra": "^9.1.0", + "hosted-git-info": "^3.0.8", + "is-ci": "^2.0.0", + "istextorbinary": "^5.12.0", + "js-yaml": "^4.0.0", + "lazy-val": "^1.0.4", + "minimatch": "^3.0.4", + "normalize-package-data": "^3.0.0", + "read-config-file": "6.0.0", + "sanitize-filename": "^1.6.3", + "semver": "^7.3.4", + "temp-file": "^3.3.7" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "normalize-package-data": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.2.tgz", + "integrity": "sha512-6CdZocmfGaKnIHPVFhJJZ3GuR8SsLKvDANFp47Jmy51aKIr8akjAWTSxtpI+MBgBFdSMRyo4hMpDlT6dTffgZg==", + "dev": true, + "requires": { + "hosted-git-info": "^4.0.1", + "resolve": "^1.20.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "hosted-git-info": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz", + "integrity": "sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + }, + "dependencies": { + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + } + } + }, + "arity-n": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arity-n/-/arity-n-1.0.4.tgz", + "integrity": "sha1-2edrEXM+CFacCEeuezmyhgswt0U=", + "dev": true + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-flatten": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz", + "integrity": "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==", + "dev": true + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "asar": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/asar/-/asar-3.0.3.tgz", + "integrity": "sha512-k7zd+KoR+n8pl71PvgElcoKHrVNiSXtw7odKbyNpmgKe7EGRF9Pnu3uLOukD37EvavKwVFxOUpqXTIZC5B5Pmw==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "chromium-pickle-js": "^0.2.0", + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "dependencies": { + "commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true + } + } + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "devOptional": true + }, + "async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "babel-loader": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.2.tgz", + "integrity": "sha512-JvTd0/D889PQBtUXJ2PXaKU/pjZDMtHA9V2ecm+eNRmmBCMR09a+fmpGTNwnJtFmFl5Ei7Vy47LjBb+L0wQ99g==", + "dev": true, + "requires": { + "find-cache-dir": "^3.3.1", + "loader-utils": "^1.4.0", + "make-dir": "^3.1.0", + "schema-utils": "^2.6.5" + }, + "dependencies": { + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + } + } + }, + "babel-plugin-component": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-component/-/babel-plugin-component-1.1.1.tgz", + "integrity": "sha512-WUw887kJf2GH80Ng/ZMctKZ511iamHNqPhd9uKo14yzisvV7Wt1EckIrb8oq/uCz3B3PpAW7Xfl7AkTLDYT6ag==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "7.0.0-beta.35" + }, + "dependencies": { + "@babel/helper-module-imports": { + "version": "7.0.0-beta.35", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.35.tgz", + "integrity": "sha512-vaC1KyIZSuyWb3Lj277fX0pxivyHwuDU4xZsofqgYAbkDxNieMg2vuhzP5AgMweMY7fCQUMTi+BgPqTLjkxXFg==", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.35", + "lodash": "^4.2.0" + } + }, + "@babel/types": { + "version": "7.0.0-beta.35", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.35.tgz", + "integrity": "sha512-y9XT11CozHDgjWcTdxmhSj13rJVXpa5ZXwjjOiTedjaM0ba5ItqdS02t31EhPl7HtOWxsZkYCCUNrSfrOisA6w==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.2.0", + "to-fast-properties": "^2.0.0" + } + } + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha1-eAqZyE59YAJgNhURxId2E78k9rs=", + "dev": true + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "devOptional": true + }, + "binaryextensions": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-4.15.0.tgz", + "integrity": "sha512-MkUl3szxXolQ2scI1PM14WOT951KnaTNJ0eMKg7WzOI4kvSxyNo/Cygx4LOBNhwyINhAuSQpJW1rYD9aBSxGaw==", + "dev": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, + "requires": { + "inherits": "~2.0.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "bluebird-lst": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/bluebird-lst/-/bluebird-lst-1.0.9.tgz", + "integrity": "sha512-7B1Rtx82hjnSD4PGLAjVWeYH3tHAcVUmChh85a3lltKQm6FresXh9ErQo6oAv6CqxttczC3/kEg8SY5NluPuUw==", + "dev": true, + "requires": { + "bluebird": "^3.5.5" + } + }, + "bn.js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", + "integrity": "sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "bonjour": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", + "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "dev": true, + "requires": { + "array-flatten": "^2.1.0", + "deep-equal": "^1.0.1", + "dns-equal": "^1.0.0", + "dns-txt": "^2.0.2", + "multicast-dns": "^6.0.1", + "multicast-dns-service-types": "^1.1.0" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", + "dev": true + }, + "boolean": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.1.4.tgz", + "integrity": "sha512-3hx0kwU3uzG6ReQ3pnaFQPSktpBw6RHN3/ivDKEuU8g1XSfafowyvDnadjv1xp8IZqhtSukxlwv9bF6FhX8m0w==", + "optional": true + }, + "boxen": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", + "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^6.2.0", + "chalk": "^4.1.0", + "cli-boxes": "^2.2.1", + "string-width": "^4.2.2", + "type-fest": "^0.20.2", + "widest-line": "^3.1.0", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "camelcase": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.1.tgz", + "integrity": "sha512-tVI4q5jjFV5CavAU8DXfza/TJcZutVKo/5Foskmsqcm0MsL91moHvwiGNnqaa2o6PF/7yT5ikDRcVcl8Rj6LCA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.1.tgz", + "integrity": "sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg==", + "requires": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.3", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=" + }, + "buffer-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-indexof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz", + "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "bufferutil": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.3.tgz", + "integrity": "sha512-yEYTwGndELGvfXsImMBLop58eaGW+YdONi1fNjTINSY98tmMmFijBG6WXgdkfuLNt4imzQNtIE+eBp1PVpMCSw==", + "dev": true, + "requires": { + "node-gyp-build": "^4.2.0" + } + }, + "builder-util": { + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-22.10.5.tgz", + "integrity": "sha512-/MkLhmyo1gU3xMwXJxccQaRj/9tm5eTd6ZyebTf8SYouY4r3hRser+LxhOm/f8Z9W6oJvfPe0jc9TFsxYfMcsg==", + "dev": true, + "requires": { + "@types/debug": "^4.1.5", + "@types/fs-extra": "^9.0.7", + "7zip-bin": "~5.0.3", + "app-builder-bin": "3.5.12", + "bluebird-lst": "^1.0.9", + "builder-util-runtime": "8.7.3", + "chalk": "^4.1.0", + "debug": "^4.3.2", + "fs-extra": "^9.1.0", + "is-ci": "^2.0.0", + "js-yaml": "^4.0.0", + "source-map-support": "^0.5.19", + "stat-mode": "^1.0.0", + "temp-file": "^3.3.7" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "builder-util-runtime": { + "version": "8.7.3", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.7.3.tgz", + "integrity": "sha512-1Q2ReBqFblimF5g/TLg2+0M5Xzv0Ih5LxJ/BMWXvEy/e6pQKeeEpbkPMGsN6OiQgkygaZo5VXCXIjOkOQG5EoQ==", + "dev": true, + "requires": { + "debug": "^4.3.2", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + } + } + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "bulma": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/bulma/-/bulma-0.9.2.tgz", + "integrity": "sha512-e14EF+3VSZ488yL/lJH0tR8mFWiEQVCMi/BQUMi2TGMBOk+zrDg4wryuwm/+dRSHJw0gMawp2tsW7X1JYUCE3A==" + }, + "bulma-tooltip": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bulma-tooltip/-/bulma-tooltip-3.0.2.tgz", + "integrity": "sha512-CsT3APjhlZScskFg38n8HYL8oYNUHQtcu4sz6ERarxkUpBRbk9v0h/5KAvXeKapVSn2dp9l7bOGit5SECP8EWQ==" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "dev": true + }, + "cacache": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz", + "integrity": "sha512-5ZvAxd05HDDU+y9BVvcqYu2LLXmPnQ0hW62h32g4xBTgL/MppR4/04NHfj/ycM2y6lmTnbw6HVi+1eN0Psba6w==", + "dev": true, + "requires": { + "chownr": "^1.1.2", + "figgy-pudding": "^3.5.1", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.2", + "infer-owner": "^1.0.4", + "lru-cache": "^5.1.1", + "minipass": "^3.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "p-map": "^3.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^2.7.1", + "ssri": "^7.0.0", + "unique-filename": "^1.1.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + } + } + }, + "call-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", + "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.0" + } + }, + "camel-case": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz", + "integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==", + "dev": true, + "requires": { + "pascal-case": "^3.1.1", + "tslib": "^1.10.0" + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + } + } + }, + "caniuse-lite": { + "version": "1.0.30001242", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001242.tgz", + "integrity": "sha512-KvNuZ/duufelMB3w2xtf9gEWCSxJwUgoxOx5b6ScLXC4kPc9xsczUVCPrQU26j5kOsHM4pSUL54tAZt5THQKug==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "devOptional": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" + }, + "chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha1-BKEGZywYsIWrd02YPfo+oTjyIgU=", + "dev": true + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "cli-truncate": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-1.1.0.tgz", + "integrity": "sha512-bAtZo0u82gCfaAGfSNxUdTI9mNyza7D8w4CVCcaOsy7sgwDzvx6ekr6cuWJqY3UGzgnQ1+4wgENup5eIhgxEYA==", + "dev": true, + "optional": true, + "requires": { + "slice-ansi": "^1.0.0", + "string-width": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "optional": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "optional": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "clone": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", + "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=", + "dev": true + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "dev": true + }, + "colors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "compose-function": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/compose-function/-/compose-function-3.0.3.tgz", + "integrity": "sha1-ntZ18TzFRQHTCVCkhv9qe6OrGF8=", + "dev": true, + "requires": { + "arity-n": "^1.0.4" + } + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dev": true, + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dev": true, + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "optional": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dev": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "dev": true + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "dev": true + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "core-js": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.12.1.tgz", + "integrity": "sha512-Ne9DKPHTObRuB09Dru5AjwKjY4cJHVGu+y5f7coGn1E9Grkc3p2iBwE9AI/nJzsE29mQF7oq+mhYYRqOMFN1Bw==" + }, + "core-js-compat": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.8.0.tgz", + "integrity": "sha512-o9QKelQSxQMYWHXc/Gc4L8bx/4F7TTraE5rhuN8I7mKBt5dBIUpXpIR3omv70ebr8ST5R3PqbDQr+ZI3+Tt1FQ==", + "dev": true, + "requires": { + "browserslist": "^4.14.7", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "optional": true, + "requires": { + "buffer": "^5.1.0" + }, + "dependencies": { + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "optional": true, + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + } + } + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "crocket": { + "version": "0.9.11", + "resolved": "https://registry.npmjs.org/crocket/-/crocket-0.9.11.tgz", + "integrity": "sha1-KI/KEe8NPdI5tixIgmXzDI7fsMU=", + "dev": true, + "requires": { + "xpipe": "*" + } + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "cross-unzip": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/cross-unzip/-/cross-unzip-0.0.2.tgz", + "integrity": "sha1-UYO8R6CVWb78+YzEZXlkmZNZNy8=", + "dev": true + }, + "cross-zip": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cross-zip/-/cross-zip-3.1.0.tgz", + "integrity": "sha512-aX02l0SD3KE27pMl69gkxDdDM5D3u9Ic4Je+2b1B2fP0dWnlWWY6ns2Vk5DEgCXJRhL3GasSpicNQRNbDkq0+w==", + "requires": { + "rimraf": "^3.0.0" + } + }, + "cross-zip-cli": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cross-zip-cli/-/cross-zip-cli-1.0.0.tgz", + "integrity": "sha1-loJvgpPo+x6rD1Y9a6ywDc42jPo=", + "requires": { + "cross-zip": "^2.1.3", + "minimist": "^1.2.0" + }, + "dependencies": { + "cross-zip": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/cross-zip/-/cross-zip-2.1.6.tgz", + "integrity": "sha512-xLIETNkzRcU6jGRzenJyRFxahbtP4628xEKMTI/Ql0Vu8m4h8M7uRLVi7E5OYHuJ6VQPsG4icJumKAFUvfm0+A==", + "requires": { + "rimraf": "^3.0.0" + } + } + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "css-hot-loader": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/css-hot-loader/-/css-hot-loader-1.4.4.tgz", + "integrity": "sha512-J/qXHz+r7FOT92qMIJfxUk0LC9fecQNZVr0MswQ4FOpKLyOCBjofVMfc6R268bh/5ktkTShrweMr0wWqerC92g==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "lodash": "^4.17.5", + "normalize-url": "^1.9.1" + }, + "dependencies": { + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + } + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + } + } + }, + "css-loader": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-3.6.0.tgz", + "integrity": "sha512-M5lSukoWi1If8dhQAUCvj4H8vUt3vOnwbQBH9DdTm/s4Ym2B/3dPMtYZeJmq7Q3S3Pa+I94DcZ7pc9bP14cWIQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "cssesc": "^3.0.0", + "icss-utils": "^4.1.1", + "loader-utils": "^1.2.3", + "normalize-path": "^3.0.0", + "postcss": "^7.0.32", + "postcss-modules-extract-imports": "^2.0.0", + "postcss-modules-local-by-default": "^3.0.2", + "postcss-modules-scope": "^2.2.0", + "postcss-modules-values": "^3.0.0", + "postcss-value-parser": "^4.1.0", + "schema-utils": "^2.7.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "css-select": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", + "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", + "dev": true, + "requires": { + "boolbase": "^1.0.0", + "css-what": "^5.0.0", + "domhandler": "^4.2.0", + "domutils": "^2.6.0", + "nth-check": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true + }, + "domhandler": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", + "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + } + }, + "domutils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + } + } + } + }, + "css-what": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", + "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", + "dev": true + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=" + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dev": true, + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-equal": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", + "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", + "dev": true, + "requires": { + "is-arguments": "^1.0.4", + "is-date-object": "^1.0.1", + "is-regex": "^1.0.4", + "object-is": "^1.0.1", + "object-keys": "^1.1.1", + "regexp.prototype.flags": "^1.2.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "default-gateway": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-4.2.0.tgz", + "integrity": "sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==", + "dev": true, + "requires": { + "execa": "^1.0.0", + "ip-regex": "^2.1.0" + } + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "devOptional": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "del": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", + "integrity": "sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==", + "dev": true, + "requires": { + "@types/glob": "^7.1.1", + "globby": "^6.1.0", + "is-path-cwd": "^2.0.0", + "is-path-in-cwd": "^2.0.0", + "p-map": "^2.0.0", + "pify": "^4.0.1", + "rimraf": "^2.6.3" + }, + "dependencies": { + "p-map": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", + "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "detect-node": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==", + "devOptional": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "dir-compare": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-2.4.0.tgz", + "integrity": "sha512-l9hmu8x/rjVC9Z2zmGzkhOEowZvW7pmYws5CWHutg8u1JgvsKWMx7Q/UODeu4djLZ4FgW5besw5yvMQnBHzuCA==", + "dev": true, + "requires": { + "buffer-equal": "1.0.0", + "colors": "1.0.3", + "commander": "2.9.0", + "minimatch": "3.0.4" + }, + "dependencies": { + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + } + } + } + }, + "dmg-builder": { + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-22.10.5.tgz", + "integrity": "sha512-58FEpfH8PEFqjbUNka4bYr52snRT8+LSXrP4gy6EZWOVICbOlmTOYj988pfoLam5C5iXb3odmyUQqwWOxlsEUw==", + "dev": true, + "requires": { + "app-builder-lib": "22.10.5", + "builder-util": "22.10.5", + "dmg-license": "^1.0.8", + "fs-extra": "^9.1.0", + "iconv-lite": "^0.6.2", + "js-yaml": "^4.0.0", + "sanitize-filename": "^1.6.3" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "js-yaml": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", + "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "dmg-license": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.8.tgz", + "integrity": "sha512-47GOb6b4yVzpovXC34heXElpH++ICg9GuWBeOTaokUNLAoAdWpE4VehudYEEtu96j2jXsgQWYf78nW7r+0Y3eg==", + "dev": true, + "optional": true, + "requires": { + "@types/plist": "^3.0.1", + "@types/verror": "^1.10.3", + "ajv": "^6.10.0", + "cli-truncate": "^1.1.0", + "crc": "^3.8.0", + "iconv-corefoundation": "^1.1.5", + "plist": "^3.0.1", + "smart-buffer": "^4.0.2", + "verror": "^1.10.0" + } + }, + "dns-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", + "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "dev": true + }, + "dns-packet": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz", + "integrity": "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA==", + "dev": true, + "requires": { + "ip": "^1.1.0", + "safe-buffer": "^5.0.1" + } + }, + "dns-txt": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", + "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "dev": true, + "requires": { + "buffer-indexof": "^1.0.0" + } + }, + "dom-converter": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", + "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==", + "dev": true, + "requires": { + "utila": "~0.4" + } + }, + "dom-serializer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.1.0.tgz", + "integrity": "sha512-ox7bvGXt2n+uLWtCRLybYx60IrOlWL/aCebWJk1T0d4m3y2tzf4U3ij9wBMUb6YJZpz06HCCYuyCDveE2xXmzQ==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "entities": "^2.0.0" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" + }, + "domelementtype": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.2.tgz", + "integrity": "sha512-wFwTwCVebUrMgGeAwRL/NhZtHAUyT9n9yg4IMDwf10+6iCMxSkVq9MGCVEH+QZWo1nNidy8kNvwmv4zWHDTqvA==", + "dev": true + }, + "domhandler": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.3.0.tgz", + "integrity": "sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1" + } + }, + "domutils": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.4.2.tgz", + "integrity": "sha512-NKbgaM8ZJOecTZsIzW5gSuplsX2IWW2mIK7xVr8hTQF2v1CJWTmLZ1HOCh5sH+IzVPAGE5IucooOkvwBRAdowA==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.0.1", + "domhandler": "^3.3.0" + } + }, + "dot-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz", + "integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==", + "dev": true, + "requires": { + "no-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "dev": true + }, + "dotenv-expand": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==", + "dev": true + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "editions": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.1.0.tgz", + "integrity": "sha512-h6nWEyIocfgho9J3sTSuhU/WoFOu1hTX75rPBebNrbF38Y9QFDjCDizYXdikHTySW7Y3mSxli8bpDz9RAtc7rA==", + "dev": true, + "requires": { + "errlop": "^4.0.0", + "version-range": "^1.0.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "ejs": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", + "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "dev": true, + "requires": { + "jake": "^10.6.1" + } + }, + "electron": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-16.0.1.tgz", + "integrity": "sha512-6TSDBcoKGgmKL/+W+LyaXidRVeRl1V4I81ZOWcqsVksdTMfM4AlxTgfaoYdK/nUhqBrUtuPDcqOyJE6Bc4qMpw==", + "requires": { + "@electron/get": "^1.13.0", + "@types/node": "^14.6.2", + "extract-zip": "^1.0.3" + }, + "dependencies": { + "@types/node": { + "version": "14.17.34", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.17.34.tgz", + "integrity": "sha512-USUftMYpmuMzeWobskoPfzDi+vkpe0dvcOBRNOscFrGxVp4jomnRxWuVohgqBow2xyIPC0S3gjxV/5079jhmDg==" + } + } + }, + "electron-builder": { + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-22.10.5.tgz", + "integrity": "sha512-0q/289UUJUhRou6lZKDz/wzK6WprIQ6VXMTmaI+w9qXvSNugPC9UA5s2zXInOkjZOvO/xKnjeyiavrVSHYF3tA==", + "dev": true, + "requires": { + "@types/yargs": "^15.0.13", + "app-builder-lib": "22.10.5", + "bluebird-lst": "^1.0.9", + "builder-util": "22.10.5", + "builder-util-runtime": "8.7.3", + "chalk": "^4.1.0", + "dmg-builder": "22.10.5", + "fs-extra": "^9.1.0", + "is-ci": "^2.0.0", + "lazy-val": "^1.0.4", + "read-config-file": "6.0.0", + "sanitize-filename": "^1.6.3", + "update-notifier": "^5.1.0", + "yargs": "^16.2.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "electron-publish": { + "version": "22.10.5", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-22.10.5.tgz", + "integrity": "sha512-dHyuazv3P3j1Xyv7pdwTwAvxWab2pCb0G0Oa6qWQoCc4b1/mRGY00M7AvYW1cPuUijj9zYAf1HmXfM6MifaMlA==", + "dev": true, + "requires": { + "@types/fs-extra": "^9.0.7", + "bluebird-lst": "^1.0.9", + "builder-util": "22.10.5", + "builder-util-runtime": "8.7.3", + "chalk": "^4.1.0", + "fs-extra": "^9.1.0", + "lazy-val": "^1.0.4", + "mime": "^2.5.0" + }, + "dependencies": { + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "dev": true + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "electron-to-chromium": { + "version": "1.3.766", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.766.tgz", + "integrity": "sha512-u2quJ862q9reRKh/je3GXis3w38+RoXH1J9N3XjtsS6NzmUAosNsyZgUVFZPN/ZlJ3v6T0rTyZR3q/J5c6Sy5w==", + "dev": true + }, + "electron-webpack": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/electron-webpack/-/electron-webpack-2.8.2.tgz", + "integrity": "sha512-rR7hxoOlZIcJf6R08mVl/4TBtFY+HW6sv4Z28TdMWETvcM4ZBIBdGNGylxF0gNwB8gkTgo8UkkDbXGX48K4Vow==", + "dev": true, + "requires": { + "@types/webpack-env": "^1.15.1", + "async-exit-hook": "^2.0.1", + "bluebird": "^3.7.2", + "chalk": "^4.0.0", + "crocket": "^0.9.11", + "css-hot-loader": "^1.4.4", + "css-loader": "^3.4.2", + "debug": "^4.1.1", + "dotenv": "^8.2.0", + "dotenv-expand": "^5.1.0", + "electron-devtools-installer": "^2.2.4", + "electron-webpack-js": "~2.4.1", + "file-loader": "^6.0.0", + "fs-extra": "^9.0.0", + "html-loader": "^1.1.0", + "html-webpack-plugin": "^4.0.4", + "lazy-val": "^1.0.4", + "mini-css-extract-plugin": "^0.9.0", + "node-loader": "^0.6.0", + "read-config-file": "~4.0.1", + "semver": "^7.1.3", + "source-map-support": "^0.5.16", + "style-loader": "^1.1.3", + "terser-webpack-plugin": "^2.3.5", + "url-loader": "^4.0.0", + "webpack-cli": "^3.3.11", + "webpack-dev-server": "^3.10.3", + "webpack-merge": "^4.2.2", + "yargs": "^15.3.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "electron-devtools-installer": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-2.2.4.tgz", + "integrity": "sha512-b5kcM3hmUqn64+RUcHjjr8ZMpHS2WJ5YO0pnG9+P/RTdx46of/JrEjuciHWux6pE+On6ynWhHJF53j/EDJN0PA==", + "dev": true, + "requires": { + "7zip": "0.0.6", + "cross-unzip": "0.0.2", + "rimraf": "^2.5.2", + "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "file-loader": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", + "integrity": "sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "fs-extra": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz", + "integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==", + "dev": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^1.0.0" + } + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + }, + "dependencies": { + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true + } + } + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "read-config-file": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-4.0.1.tgz", + "integrity": "sha512-5caED3uo2IAZMPcbh/9hx/O29s2430RLxtnFDdzxpH/epEpawOrQnGBHueotIXUrGPPIgdNQN+S/CIp2WmiSfw==", + "dev": true, + "requires": { + "ajv": "^6.10.1", + "ajv-keywords": "^3.4.1", + "dotenv": "^8.0.0", + "dotenv-expand": "^5.1.0", + "fs-extra": "^8.1.0", + "js-yaml": "^3.13.1", + "json5": "^2.1.0", + "lazy-val": "^1.0.4" + }, + "dependencies": { + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "universalify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz", + "integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==", + "dev": true + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "electron-webpack-js": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/electron-webpack-js/-/electron-webpack-js-2.4.1.tgz", + "integrity": "sha512-NPbcI4nnuclkLEKmwRI8sui2GNe37NKm0pCQR6KZA7YSV3KQdH4I7wOgIZ2AkeCpyeUHrBSMGQY+VqhPD7OtMA==", + "dev": true, + "requires": { + "@babel/core": "^7.9.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/preset-env": "^7.9.0", + "babel-loader": "^8.1.0", + "babel-plugin-component": "^1.1.1" + } + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "devOptional": true + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", + "integrity": "sha512-3e87LvavsdxyoCfGusJnrZ5G8SLPOFeHSNpZI/ATL9a5leXo2k0w6MKnbqhdBad9qTobSfB20Ld7UmgoNbAZkQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + } + }, + "entities": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", + "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "dev": true + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==" + }, + "errlop": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/errlop/-/errlop-4.1.0.tgz", + "integrity": "sha512-vul6gGBuVt0M2TPi1/WrcL86+Hb3Q2Tpu3TME3sbVhZrYf7J1ZMHCodI25RQKCVurh56qTfvgM0p3w5cT4reSQ==", + "dev": true + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.17.7", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.7.tgz", + "integrity": "sha512-VBl/gnfcJ7OercKA9MVaegWsBHFjV492syMudcnQZvt/Dw8ezpcOHYZXa/J96O8vx+g4x65YKhxOwDUh63aS5g==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.2", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.1", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "optional": true + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dev": true, + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "optional": true + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "eventsource": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.1.0.tgz", + "integrity": "sha512-VSJjT5oCNrFvCS6igjzPAt5hBzQ2qPBFIbJ03zLI9SE0mxwZpMw6BfJrbFHm1a141AavMEB8JHmBhWAd66PfCg==", + "dev": true, + "requires": { + "original": "^1.0.0" + } + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "dev": true, + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dev": true, + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", + "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==", + "dev": true + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extract-zip": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", + "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "requires": { + "concat-stream": "^1.6.2", + "debug": "^2.6.9", + "mkdirp": "^0.5.4", + "yauzl": "^2.10.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "requires": { + "pend": "~1.2.0" + } + }, + "figgy-pudding": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.2.tgz", + "integrity": "sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==" + }, + "file-loader": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-3.0.1.tgz", + "integrity": "sha512-4sNIOXgtH/9WZq4NvlfU3Opn5ynUsqBwSLyM+I7UOwdGigTBYfVVQEwe/msZNX/j4pCJTIM14Fsw66Svo1oVrw==", + "dev": true, + "requires": { + "loader-utils": "^1.0.2", + "schema-utils": "^1.0.0" + }, + "dependencies": { + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "filelist": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", + "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "dev": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "follow-redirects": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.0.tgz", + "integrity": "sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA==", + "dev": true + }, + "font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "requires": { + "globule": "^1.0.0" + } + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", + "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "devOptional": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "devOptional": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "optional": true, + "requires": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + } + }, + "global-dirs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.0.tgz", + "integrity": "sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==", + "dev": true, + "requires": { + "ini": "2.0.0" + }, + "dependencies": { + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true + } + } + }, + "global-modules": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", + "integrity": "sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==", + "dev": true, + "requires": { + "global-prefix": "^3.0.0" + }, + "dependencies": { + "global-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-3.0.0.tgz", + "integrity": "sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==", + "dev": true, + "requires": { + "ini": "^1.3.5", + "kind-of": "^6.0.2", + "which": "^1.3.1" + } + } + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "global-tunnel-ng": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz", + "integrity": "sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==", + "optional": true, + "requires": { + "encodeurl": "^1.0.2", + "lodash": "^4.17.10", + "npm-conf": "^1.1.3", + "tunnel": "^0.0.6" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globalthis": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.2.tgz", + "integrity": "sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ==", + "optional": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "requires": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "globule": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz", + "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==", + "dev": true, + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + } + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", + "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "html-entities": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.3.1.tgz", + "integrity": "sha512-rhE/4Z3hIhzHAUKbW8jVcCyuT5oJCXXqhN/6mXXVCpzTmvJnoH2HL/bt3EZ6p55jbFJBeAe1ZNpL5BugLujxNA==", + "dev": true + }, + "html-loader": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-1.3.2.tgz", + "integrity": "sha512-DEkUwSd0sijK5PF3kRWspYi56XP7bTNkyg5YWSzBdjaSDmvCufep5c4Vpb3PBf6lUL0YPtLwBfy9fL0t5hBAGA==", + "dev": true, + "requires": { + "html-minifier-terser": "^5.1.1", + "htmlparser2": "^4.1.0", + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "html-minifier-terser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", + "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", + "dev": true, + "requires": { + "camel-case": "^4.1.1", + "clean-css": "^4.2.3", + "commander": "^4.1.1", + "he": "^1.2.0", + "param-case": "^3.0.3", + "relateurl": "^0.2.7", + "terser": "^4.6.3" + }, + "dependencies": { + "commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true + } + } + }, + "html-webpack-plugin": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-4.5.2.tgz", + "integrity": "sha512-q5oYdzjKUIPQVjOosjgvCHQOv9Ett9CYYHlgvJeXG0qQvdSojnBq4vAdQBwn1+yGveAwHCoe/rMR86ozX3+c2A==", + "dev": true, + "requires": { + "@types/html-minifier-terser": "^5.0.0", + "@types/tapable": "^1.0.5", + "@types/webpack": "^4.41.8", + "html-minifier-terser": "^5.0.1", + "loader-utils": "^1.2.3", + "lodash": "^4.17.20", + "pretty-error": "^2.1.1", + "tapable": "^1.1.3", + "util.promisify": "1.0.0" + } + }, + "htmlparser2": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz", + "integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^3.0.0", + "domutils": "^2.0.0", + "entities": "^2.0.0" + } + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "http-parser-js": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.3.tgz", + "integrity": "sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-middleware": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", + "integrity": "sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==", + "dev": true, + "requires": { + "http-proxy": "^1.17.0", + "is-glob": "^4.0.0", + "lodash": "^4.17.11", + "micromatch": "^3.1.10" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "iconv-corefoundation": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.5.tgz", + "integrity": "sha512-hI4m7udfV04OcjleOmDaR4gwXnH4xumxN+ZmywHDiKf2CmAzsT9SVYe7Y4pdnQbyZfXwAQyrElykbE5PrPRfmQ==", + "dev": true, + "optional": true, + "requires": { + "cli-truncate": "^1.1.0", + "node-addon-api": "^1.6.3" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-4.1.1.tgz", + "integrity": "sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==", + "dev": true, + "requires": { + "postcss": "^7.0.14" + } + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "in-publish": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz", + "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "indexes-of": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", + "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "devOptional": true + }, + "internal-ip": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz", + "integrity": "sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==", + "dev": true, + "requires": { + "default-gateway": "^4.2.0", + "ipaddr.js": "^1.9.0" + } + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "dev": true + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "ip-regex": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true + }, + "is-absolute-url": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz", + "integrity": "sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arguments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.0.4.tgz", + "integrity": "sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", + "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "devOptional": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", + "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "dev": true, + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", + "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "devOptional": true + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "devOptional": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, + "is-npm": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", + "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-number-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, + "is-path-in-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz", + "integrity": "sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==", + "dev": true, + "requires": { + "is-path-inside": "^2.1.0" + }, + "dependencies": { + "is-path-inside": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", + "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", + "dev": true, + "requires": { + "path-is-inside": "^1.0.2" + } + } + } + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "dev": true + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istextorbinary": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-5.12.0.tgz", + "integrity": "sha512-wLDRWD7qpNTYubk04+q3en1+XZGS4vYWK0+SxNSXJLaITMMEK+J3o/TlOMyULeH1qozVZ9uUkKcyMA8odyxz8w==", + "dev": true, + "requires": { + "binaryextensions": "^4.15.0", + "editions": "^6.1.0", + "textextensions": "^5.11.0" + } + }, + "jake": { + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", + "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "dev": true, + "requires": { + "async": "0.9.x", + "chalk": "^2.4.2", + "filelist": "^1.0.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "jest-worker": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-25.5.0.tgz", + "integrity": "sha512-/dsSmUkIy5EBGfv/IjjqmFxrNAUpBERfGs1oHROyD7yxjG/w+t0GOJDX8O1k32ySmd7+a5IhnJU2qQFcJ4n1vw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + } + }, + "js-base64": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + } + } + }, + "jsan": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/jsan/-/jsan-3.1.13.tgz", + "integrity": "sha512-9kGpCsGHifmw6oJet+y8HaCl14y7qgAsxVdV3pCHDySNR3BfDC30zgkssd7x5LRVAT22dnpbe9JdzzmXZnq9/g==", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "devOptional": true + }, + "json3": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz", + "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==", + "dev": true + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "requires": { + "minimist": "^1.2.5" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "requires": { + "json-buffer": "3.0.0" + } + }, + "killable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", + "integrity": "sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, + "lazy-val": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.4.tgz", + "integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q==", + "dev": true + }, + "linked-list": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/linked-list/-/linked-list-0.1.0.tgz", + "integrity": "sha1-eYsP+X0bkqT9CEgPVa6k6dSdN78=", + "dev": true + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==" + }, + "loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "devOptional": true + }, + "loglevel": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz", + "integrity": "sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lower-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz", + "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==", + "dev": true, + "requires": { + "tslib": "^1.10.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==" + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "optional": true, + "requires": { + "escape-string-regexp": "^4.0.0" + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true + }, + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "dev": true + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "dev": true + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "dev": true + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dev": true, + "requires": { + "mime-db": "1.44.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "mini-css-extract-plugin": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.9.0.tgz", + "integrity": "sha512-lp3GeY7ygcgAmVIcRPBVhIkf8Us7FZjA+ILpal44qLdSu11wmjKQ3d9k15lfD7pO4esu9eUIAW7qiYIBppv40A==", + "dev": true, + "requires": { + "loader-utils": "^1.1.0", + "normalize-url": "1.9.1", + "schema-utils": "^1.0.0", + "webpack-sources": "^1.1.0" + }, + "dependencies": { + "normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + } + }, + "prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "minipass": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", + "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multicast-dns": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz", + "integrity": "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==", + "dev": true, + "requires": { + "dns-packet": "^1.3.1", + "thunky": "^1.0.2" + } + }, + "multicast-dns-service-types": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", + "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "dev": true + }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "devOptional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "no-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz", + "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==", + "dev": true, + "requires": { + "lower-case": "^2.0.1", + "tslib": "^1.10.0" + } + }, + "node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "dev": true + }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "dev": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + } + } + }, + "node-gyp-build": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz", + "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg==", + "dev": true + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + } + } + }, + "node-loader": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/node-loader/-/node-loader-0.6.0.tgz", + "integrity": "sha1-x5fvUQle1YWZArFX9jhPY2HgWug=", + "dev": true + }, + "node-releases": { + "version": "1.1.73", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", + "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", + "dev": true + }, + "node-sass": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz", + "integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==", + "dev": true, + "requires": { + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash": "^4.17.15", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.13.2", + "node-gyp": "^3.8.0", + "npmlog": "^4.0.0", + "request": "^2.88.0", + "sass-graph": "2.2.5", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + } + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "devOptional": true + }, + "normalize-url": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", + "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==" + }, + "npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "optional": true, + "requires": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "nth-check": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", + "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", + "dev": true, + "requires": { + "boolbase": "^1.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "object-is": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.4.tgz", + "integrity": "sha512-1ZvAZ4wlF7IyPVOcE1Omikt7UpaFlOQq0HlSti+ZvDH3UiD2brwGMwDbyV43jao2bKJ+4+WdPJHSd7kgzKYVqg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "devOptional": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.getownpropertydescriptors": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.2.tgz", + "integrity": "sha512-WtxeKSzfBjlzL+F9b7M7hewDzMwy+C8NRssHd1YrNlzHzIDrXcXiNOMrezdAEM4UXixgV+vvnyBeN7Rygl2ttQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2" + }, + "dependencies": { + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "es-abstract": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", + "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.2", + "is-string": "^1.0.5", + "object-inspect": "^1.9.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.0" + }, + "dependencies": { + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true + } + } + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "dev": true + }, + "is-regex": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.2.tgz", + "integrity": "sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.1" + } + }, + "object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "dev": true + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + } + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "requires": { + "is-wsl": "^1.1.0" + } + }, + "original": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", + "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==", + "dev": true, + "requires": { + "url-parse": "^1.4.3" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==" + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-3.0.1.tgz", + "integrity": "sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==", + "dev": true, + "requires": { + "retry": "^0.12.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "param-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.3.tgz", + "integrity": "sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA==", + "dev": true, + "requires": { + "dot-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "pascal-case": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz", + "integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==", + "dev": true, + "requires": { + "no-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "devOptional": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + }, + "pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "optional": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "optional": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "requires": { + "find-up": "^3.0.0" + } + }, + "plist": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.0.4.tgz", + "integrity": "sha512-ksrr8y9+nXOxQB2osVNqrgvX/XQPOXaU4BQMKjYq8PvaY1U18mo+fKgBSwzK+luSyinOuPae956lSVcBwxlAMg==", + "dev": true, + "optional": true, + "requires": { + "base64-js": "^1.5.1", + "xmlbuilder": "^9.0.7" + }, + "dependencies": { + "xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true, + "optional": true + } + } + }, + "portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "postcss-modules-extract-imports": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz", + "integrity": "sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==", + "dev": true, + "requires": { + "postcss": "^7.0.5" + } + }, + "postcss-modules-local-by-default": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.3.tgz", + "integrity": "sha512-e3xDq+LotiGesympRlKNgaJ0PCzoUIdpH0dj47iWAui/kyTgh3CiAr1qP54uodmJhl6p9rN6BoNcdEDVJx9RDw==", + "dev": true, + "requires": { + "icss-utils": "^4.1.1", + "postcss": "^7.0.32", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-2.2.0.tgz", + "integrity": "sha512-YyEgsTMRpNd+HmyC7H/mh3y+MeFWevy7V1evVhJWewmMbjDHIbZbOXICC2y+m1xI1UVfIT1HMW/O04Hxyu9oXQ==", + "dev": true, + "requires": { + "postcss": "^7.0.6", + "postcss-selector-parser": "^6.0.0" + } + }, + "postcss-modules-values": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz", + "integrity": "sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==", + "dev": true, + "requires": { + "icss-utils": "^4.0.0", + "postcss": "^7.0.6" + } + }, + "postcss-selector-parser": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.4.tgz", + "integrity": "sha512-gjMeXBempyInaBqpp8gODmwZ52WaYsVOsfr4L4lDQ7n3ncD6mEyySiDtgzCT+NYC0mmeOLvtsF8iaEf0YT6dBw==", + "dev": true, + "requires": { + "cssesc": "^3.0.0", + "indexes-of": "^1.0.1", + "uniq": "^1.0.1", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=" + }, + "pretty-error": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.2.tgz", + "integrity": "sha512-EY5oDzmsX5wvuynAByrmY0P0hcp+QpnAKbJng2A2MPjVKXCxrDSUkzghVJ4ZGPIv+JC4gX8fPUWscC0RtjsWGw==", + "dev": true, + "requires": { + "lodash": "^4.17.20", + "renderkid": "^2.0.4" + } + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" + }, + "prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "optional": true + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "dev": true, + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "pupa": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", + "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "dev": true, + "requires": { + "escape-goat": "^2.0.0" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true + }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "dependencies": { + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true + } + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "react": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + }, + "react-dom": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", + "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "react-tooltip": { + "version": "4.2.19", + "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-4.2.19.tgz", + "integrity": "sha512-wF6h0a2nqX3UHw9aSoj77Tv/+/KIjRdb107otHtX+1wISad1QoLD+j5chrBDx7mjY1T4WKfrV2DN+iFCimdZOw==", + "requires": { + "prop-types": "^15.7.2", + "uuid": "^7.0.3" + } + }, + "read-config-file": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/read-config-file/-/read-config-file-6.0.0.tgz", + "integrity": "sha512-PHjROSdpceKUmqS06wqwP92VrM46PZSTubmNIMJ5DrMwg1OgenSTSEHIkCa6TiOJ+y/J0xnG1fFwG3M+Oi1aNA==", + "dev": true, + "requires": { + "dotenv": "^8.2.0", + "dotenv-expand": "^5.1.0", + "js-yaml": "^3.13.1", + "json5": "^2.1.2", + "lazy-val": "^1.0.4" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + } + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "devOptional": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + }, + "dependencies": { + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + } + } + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + }, + "regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==", + "dev": true + }, + "regexp.prototype.flags": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz", + "integrity": "sha512-2+Q0C5g951OlYlJz6yu5/M33IcsESLlLfsyIaLJaG4FA2r4yP8MvVMJUUP/fVBkSpbbbZlS5gynbEWLipiiXiQ==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.0-next.1" + } + }, + "regexpu-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "registry-auth-token": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", + "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "remotedev": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/remotedev/-/remotedev-0.2.9.tgz", + "integrity": "sha512-W8dHOv9BcFnetFEd08yNb5O9Hd+zkTFFnf9FRjNCkb4u+JgQ/U152Aw4q83AmY3m34d6KZwhK5ip/Qc331+4vA==", + "dev": true, + "requires": { + "jsan": "^3.1.3", + "querystring": "^0.2.0", + "rn-host-detect": "^1.0.1", + "socketcluster-client": "^13.0.0" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "devOptional": true + }, + "renderkid": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.7.tgz", + "integrity": "sha512-oCcFyxaMrKsKcTY59qnCAtmDVSLfPbrv6A3tVbPdFMMrv5jaK10V6m40cKsoPNhAqN6rmHW9sswW4o3ruSrwUQ==", + "dev": true, + "requires": { + "css-select": "^4.1.3", + "dom-converter": "^0.2.0", + "htmlparser2": "^6.1.0", + "lodash": "^4.17.21", + "strip-ansi": "^3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "domhandler": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", + "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", + "dev": true, + "requires": { + "domelementtype": "^2.2.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true + } + } + }, + "domutils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", + "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", + "dev": true, + "requires": { + "dom-serializer": "^1.0.1", + "domelementtype": "^2.2.0", + "domhandler": "^4.2.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", + "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", + "dev": true + } + } + }, + "htmlparser2": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", + "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "domhandler": "^4.0.0", + "domutils": "^2.5.2", + "entities": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "dependencies": { + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + } + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "resolve-url-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-3.1.4.tgz", + "integrity": "sha512-D3sQ04o0eeQEySLrcz4DsX3saHfsr8/N6tfhblxgZKXxMT2Louargg12oGNfoTRLV09GXhVUe5/qgA5vdgNigg==", + "dev": true, + "requires": { + "adjust-sourcemap-loader": "3.0.0", + "camelcase": "5.3.1", + "compose-function": "3.0.3", + "convert-source-map": "1.7.0", + "es6-iterator": "2.0.3", + "loader-utils": "1.2.3", + "postcss": "7.0.36", + "rework": "1.0.1", + "rework-visit": "1.0.0", + "source-map": "0.6.1" + }, + "dependencies": { + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + }, + "rework": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rework/-/rework-1.0.1.tgz", + "integrity": "sha1-MIBqhBNCtUUQqkEQhQzUhTQUSqc=", + "dev": true, + "requires": { + "convert-source-map": "^0.3.3", + "css": "^2.0.0" + }, + "dependencies": { + "convert-source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-0.3.5.tgz", + "integrity": "sha1-8dgClQr33SYxof6+BZZVDIarMZA=", + "dev": true + } + } + }, + "rework-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rework-visit/-/rework-visit-1.0.0.tgz", + "integrity": "sha1-mUWygD8hni96ygCtuLyfZA+ELJo=", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rn-host-detect": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/rn-host-detect/-/rn-host-detect-1.2.0.tgz", + "integrity": "sha512-btNg5kzHcjZZ7t7mvvV/4wNJ9e3MPgrWivkRgWURzXL0JJ0pwWlU4zrbmdlz3HHzHOxhBhHB4D+/dbMFfu4/4A==", + "dev": true + }, + "roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "optional": true, + "requires": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "requires": { + "aproba": "^1.1.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sanitize-filename": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", + "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", + "dev": true, + "requires": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "sass-graph": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", + "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", + "dev": true, + "requires": { + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "sass-loader": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-7.3.1.tgz", + "integrity": "sha512-tuU7+zm0pTCynKYHpdqaPpe+MMTQ76I9TPZ7i4/5dZsigE350shQWe5EZNl5dBidM49TPET75tNqRbcsUZWeNA==", + "dev": true, + "requires": { + "clone-deep": "^4.0.1", + "loader-utils": "^1.0.1", + "neo-async": "^2.5.0", + "pify": "^4.0.1", + "semver": "^6.3.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "sc-channel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/sc-channel/-/sc-channel-1.2.0.tgz", + "integrity": "sha512-M3gdq8PlKg0zWJSisWqAsMmTVxYRTpVRqw4CWAdKBgAfVKumFcTjoCV0hYu7lgUXccCtCD8Wk9VkkE+IXCxmZA==", + "dev": true, + "requires": { + "component-emitter": "1.2.1" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + } + } + }, + "sc-errors": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/sc-errors/-/sc-errors-1.4.1.tgz", + "integrity": "sha512-dBn92iIonpChTxYLgKkIT/PCApvmYT6EPIbRvbQKTgY6tbEbIy8XVUv4pGyKwEK4nCmvX4TKXcN0iXC6tNW6rQ==", + "dev": true + }, + "sc-formatter": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sc-formatter/-/sc-formatter-3.0.2.tgz", + "integrity": "sha512-9PbqYBpCq+OoEeRQ3QfFIGE6qwjjBcd2j7UjgDlhnZbtSnuGgHdcRklPKYGuYFH82V/dwd+AIpu8XvA1zqTd+A==", + "dev": true + }, + "scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "schema-utils": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", + "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.5", + "ajv": "^6.12.4", + "ajv-keywords": "^3.5.2" + } + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "dev": true, + "requires": { + "js-base64": "^2.1.8", + "source-map": "^0.4.2" + } + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "dev": true + }, + "selfsigned": { + "version": "1.10.8", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz", + "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==", + "dev": true, + "requires": { + "node-forge": "^0.10.0" + } + }, + "semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "devOptional": true + }, + "semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", + "optional": true + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "optional": true, + "requires": { + "type-fest": "^0.13.1" + } + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "dev": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "optional": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0" + } + }, + "smart-buffer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==", + "dev": true, + "optional": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "socketcluster-client": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/socketcluster-client/-/socketcluster-client-13.0.1.tgz", + "integrity": "sha512-hxiE2xz6mgaBlhXbtBa4POgWVEvIcjCoHzf5LTUVhI9IL8V2ltV3Ze8pQsi9egqTjSz4RHPfyrJ7BiETe5Kthw==", + "dev": true, + "requires": { + "base-64": "0.1.0", + "clone": "2.1.1", + "component-emitter": "1.2.1", + "linked-list": "0.1.0", + "querystring": "0.2.0", + "sc-channel": "^1.2.0", + "sc-errors": "^1.4.0", + "sc-formatter": "^3.0.1", + "uuid": "3.2.1", + "ws": "5.1.1" + }, + "dependencies": { + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "uuid": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==", + "dev": true + }, + "ws": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.1.1.tgz", + "integrity": "sha512-bOusvpCb09TOBLbpMKszd45WKC2KPtxiyiHanv+H2DE3Az+1db5a/L7sVJZVDPUC1Br8f0SKRr1KjLpD1U/IAw==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, + "sockjs": { + "version": "0.3.21", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.21.tgz", + "integrity": "sha512-DhbPFGpxjc6Z3I+uX07Id5ZO2XwYsWOrYjaSeieES78cq+JaJvVe5q/m1uvjIQhXinhIeCFRH6JgXe+mvVMyXw==", + "dev": true, + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^3.4.0", + "websocket-driver": "^0.7.4" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, + "sockjs-client": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.2.tgz", + "integrity": "sha512-ZzRxPBISQE7RpzlH4tKJMQbHM9pabHluk0WBaxAQ+wm/UieeBVBou0p4wVnSQGN9QmpAZygQ0cDIypWuqOFmFQ==", + "dev": true, + "requires": { + "debug": "^3.2.6", + "eventsource": "^1.0.7", + "faye-websocket": "^0.11.3", + "inherits": "^2.0.4", + "json3": "^3.3.3", + "url-parse": "^1.5.3" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==" + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + }, + "source-map-loader": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-1.1.3.tgz", + "integrity": "sha512-6YHeF+XzDOrT/ycFJNI53cgEsp/tHTMl37hi7uVyqFAlTXW109JazaQCkbc+jjoL2637qkH1amLi+JzrIpt5lA==", + "requires": { + "abab": "^2.0.5", + "iconv-lite": "^0.6.2", + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0", + "source-map": "^0.6.1", + "whatwg-mimetype": "^2.3.0" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz", + "integrity": "sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "dev": true + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "optional": true + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-7.1.1.tgz", + "integrity": "sha512-w+daCzXN89PseTL99MkA+fxJEcU3wfaE/ah0i0lnOlpG1CYLJ2ZjzEry68YBKfLs4JfoTShrTEsJkAZuNZ/stw==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1", + "minipass": "^3.1.1" + } + }, + "stat-mode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", + "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + }, + "stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "string.prototype.trimend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz", + "integrity": "sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz", + "integrity": "sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "style-loader": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-1.3.0.tgz", + "integrity": "sha512-V7TCORko8rs9rIqkSrlMfkqA63DfoGBBJmK1kKGCcSi+BWb4cqz0SRsnp4l6rU5iwOEd0/2ePv68SV22VXon4Q==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^2.7.0" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, + "sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "requires": { + "debug": "^4.1.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==" + }, + "tar": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "dev": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.12", + "inherits": "2" + } + }, + "temp-file": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.7.tgz", + "integrity": "sha512-9tBJKt7GZAQt/Rg0QzVWA8Am8c1EFl+CAv04/aBVqlx5oyfQ508sFIABshQ0xbZu6mBrFLWIUXO/bbLYghW70g==", + "dev": true, + "requires": { + "async-exit-hook": "^2.0.1", + "fs-extra": "^8.1.0" + } + }, + "terser": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", + "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "terser-webpack-plugin": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz", + "integrity": "sha512-/fKw3R+hWyHfYx7Bv6oPqmk4HGQcrWLtV3X6ggvPuwPNHSnzvVV51z6OaaCOus4YLjutYGOz3pEpbhe6Up2s1w==", + "dev": true, + "requires": { + "cacache": "^13.0.1", + "find-cache-dir": "^3.3.1", + "jest-worker": "^25.4.0", + "p-limit": "^2.3.0", + "schema-utils": "^2.6.6", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.6.12", + "webpack-sources": "^1.4.3" + }, + "dependencies": { + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "textextensions": { + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-5.12.0.tgz", + "integrity": "sha512-IYogUDaP65IXboCiPPC0jTLLBzYlhhw2Y4b0a2trPgbHNGGGEfuHE6tds+yDcCf4mpNDaGISFzwSSezcXt+d6w==", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "requires": { + "setimmediate": "^1.0.4" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==" + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "dev": true, + "requires": { + "glob": "^7.1.2" + } + }, + "truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=", + "dev": true, + "requires": { + "utf8-byte-length": "^1.0.1" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" + }, + "tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "optional": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", + "dev": true + }, + "type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "optional": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "dependencies": { + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", + "dev": true + } + } + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "uniq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", + "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=", + "dev": true + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "devOptional": true + }, + "update-notifier": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", + "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "dev": true, + "requires": { + "boxen": "^5.0.0", + "chalk": "^4.1.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.4.0", + "is-npm": "^5.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.1.0", + "pupa": "^2.1.1", + "semver": "^7.3.4", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "dependencies": { + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" + }, + "dependencies": { + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "schema-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", + "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.6", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "url-parse": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.3.tgz", + "integrity": "sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "requires": { + "prepend-http": "^2.0.0" + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "utf-8-validate": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.5.tgz", + "integrity": "sha512-+pnxRYsS/axEpkrrEpzYfNZGXp0IjC/9RIxwM5gntY4Koi8SHmUGSfxfWqxZdRxrtaoVstuOzUp/rbs3JSPELQ==", + "dev": true, + "requires": { + "node-gyp-build": "^4.2.0" + } + }, + "utf8-byte-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", + "integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E=", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "requires": { + "inherits": "2.0.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "utila": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", + "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=", + "dev": true + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true + }, + "uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==" + }, + "v8-compile-cache": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz", + "integrity": "sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "version-compare": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/version-compare/-/version-compare-1.1.0.tgz", + "integrity": "sha512-zVKtPOJTC9x23lzS4+4D7J+drq80BXVYAmObnr5zqxxFVH7OffJ1lJlAS7LYsQNV56jx/wtbw0UV7XHLrvd6kQ==", + "dev": true + }, + "version-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-1.1.0.tgz", + "integrity": "sha512-R1Ggfg2EXamrnrV3TkZ6yBNgITDbclB3viwSjbZ3+eK0VVNK4ajkYJTnDz5N0bIMYDtK9MUBvXJUnKO5RWWJ6w==", + "dev": true, + "requires": { + "version-compare": "^1.0.0" + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "watchpack": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz", + "integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==", + "requires": { + "chokidar": "^3.4.1", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0", + "watchpack-chokidar2": "^2.0.1" + }, + "dependencies": { + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "optional": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "optional": true + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "optional": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "optional": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "optional": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "optional": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "optional": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "optional": true + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "optional": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "optional": true, + "requires": { + "is-number": "^7.0.0" + } + } + } + }, + "watchpack-chokidar2": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz", + "integrity": "sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww==", + "optional": true, + "requires": { + "chokidar": "^2.1.8" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "webpack": { + "version": "4.46.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz", + "integrity": "sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q==", + "requires": { + "@webassemblyjs/ast": "1.9.0", + "@webassemblyjs/helper-module-context": "1.9.0", + "@webassemblyjs/wasm-edit": "1.9.0", + "@webassemblyjs/wasm-parser": "1.9.0", + "acorn": "^6.4.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.5.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.3", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.3", + "watchpack": "^1.7.4", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "cacache": { + "version": "12.0.4", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz", + "integrity": "sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ==", + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + } + }, + "enhanced-resolve": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz", + "integrity": "sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==", + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "ssri": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.2.tgz", + "integrity": "sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==", + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "terser-webpack-plugin": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.5.tgz", + "integrity": "sha512-04Rfe496lN8EYruwi6oPQkG0vo8C+HT49X687FZnpPF0qMAIHONI6HEXYPKDOE8e5HjXTyKfqRd/agHtH0kOtw==", + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^4.0.0", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + } + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "webpack-cli": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-3.3.12.tgz", + "integrity": "sha512-NVWBaz9k839ZH/sinurM+HcDvJOTXwSjYp1ku+5XKeOC03z8v5QitnK/x+lAxGXFyhdayoIf/GOpv85z3/xPag==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "cross-spawn": "^6.0.5", + "enhanced-resolve": "^4.1.1", + "findup-sync": "^3.0.0", + "global-modules": "^2.0.0", + "import-local": "^2.0.0", + "interpret": "^1.4.0", + "loader-utils": "^1.4.0", + "supports-color": "^6.1.0", + "v8-compile-cache": "^2.1.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "webpack-dev-middleware": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz", + "integrity": "sha512-1xC42LxbYoqLNAhV6YzTYacicgMZQTqRd27Sim9wn5hJrX3I5nxYy1SxSd4+gjUFsz1dQFj+yEe6zEVmSkeJjw==", + "dev": true, + "requires": { + "memory-fs": "^0.4.1", + "mime": "^2.4.4", + "mkdirp": "^0.5.1", + "range-parser": "^1.2.1", + "webpack-log": "^2.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "webpack-dev-server": { + "version": "3.11.3", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-3.11.3.tgz", + "integrity": "sha512-3x31rjbEQWKMNzacUZRE6wXvUFuGpH7vr0lIEbYpMAG9BOxi0928QU1BBswOAP3kg3H1O4hiS+sq4YyAn6ANnA==", + "dev": true, + "requires": { + "ansi-html-community": "0.0.8", + "bonjour": "^3.5.0", + "chokidar": "^2.1.8", + "compression": "^1.7.4", + "connect-history-api-fallback": "^1.6.0", + "debug": "^4.1.1", + "del": "^4.1.1", + "express": "^4.17.1", + "html-entities": "^1.3.1", + "http-proxy-middleware": "0.19.1", + "import-local": "^2.0.0", + "internal-ip": "^4.3.0", + "ip": "^1.1.5", + "is-absolute-url": "^3.0.3", + "killable": "^1.0.1", + "loglevel": "^1.6.8", + "opn": "^5.5.0", + "p-retry": "^3.0.1", + "portfinder": "^1.0.26", + "schema-utils": "^1.0.0", + "selfsigned": "^1.10.8", + "semver": "^6.3.0", + "serve-index": "^1.9.1", + "sockjs": "^0.3.21", + "sockjs-client": "^1.5.0", + "spdy": "^4.0.2", + "strip-ansi": "^3.0.1", + "supports-color": "^6.1.0", + "url": "^0.11.0", + "webpack-dev-middleware": "^3.7.2", + "webpack-log": "^2.0.0", + "ws": "^6.2.1", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + } + } + }, + "y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "webpack-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/webpack-log/-/webpack-log-2.0.0.tgz", + "integrity": "sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } + } + }, + "webpack-merge": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.2.2.tgz", + "integrity": "sha512-TUE1UGoTX2Cd42j3krGYqObZbOD+xF7u28WB7tfUordytSjbWTIjK/8V0amkBfTYN4/pB/GIDlJZZ657BGG19g==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz", + "integrity": "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + }, + "xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "optional": true + }, + "xpipe": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/xpipe/-/xpipe-1.0.5.tgz", + "integrity": "sha1-jdi/Rfw/f1Xw4FS4ePQ6YmFNr98=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.6.tgz", + "integrity": "sha512-PlVX4Y0lDTN6E2V4ES2tEdyvXkeKzxa8c/vo0pxPr/TqbztddTP0yn7zZylIyiAuxerqj0Q5GhpJ1YJCP8LaZQ==", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.7", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", + "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", + "dev": true + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..1a719f2 --- /dev/null +++ b/package.json @@ -0,0 +1,92 @@ +{ + "name": "issie", + "version": "2.4.4", + "description": "Schematic editor and Simulator", + "homepage": "https://github.com/tomcl/issie", + "bugs": { + "url": "https://github.com/tomcl/issie/issues" + }, + "license": "", + "author": "tomcl", + "main": "app/main.js", + "repository": { + "type": "git", + "url": "https://github.com/tomcl/issie.git" + }, + "scripts": { + "clean-dev-mac": "sudo killall -9 node && sudo killall -9 dotnet && sudo killall -9 issie", + "clean-dev-win": "taskkill /f /im node.exe && taskkill /f /im dotnet.exe && taskkill /f /im issie.exe", + "compile": "dotnet fable src/Main -s && dotnet fable src/Renderer -s", + "dev": "dotnet fable watch src/Main -s --run npm run devrenderer", + "devfast": "dotnet fable watch src/Main -s --run npm run devrenderer-fast", + "devmain": "dotnet fable watch src/Main --run npm run webpackdev", + "devrenderer": "dotnet fable watch src/Renderer -s --define ASSERTS --run npm run webpackdev", + "devrenderer-fast": "dotnet fable watch src/Renderer -s --run npm run webpackdev", + "webpackdev": "electron-webpack dev", + "webpack": "electron-webpack", + "dist": "npm run compile && npm run webpack && electron-builder", + "distwin": "npm run compile && electron-webpack && electron-builder -w", + "distmac": "npm run compile && electron-webpack && electron-builder -m", + "buildonly": "electron-builder", + "compile-sass": "cd src/renderer/scss && node-sass main.scss main.css" + }, + "electronWebpack": { + "main": { + "sourceDirectory": "src/Main", + "webpackConfig": "webpack.additions.main.js" + }, + "renderer": { + "sourceDirectory": "src/Renderer", + "webpackConfig": "webpack.additions.renderer.js" + }, + "title": true + }, + "build": { + "appId": "ISSIE", + "asar": true, + "win": { + "target": "zip" + }, + "mac": { + "target": { + "target": "default", + "arch": [ + "x64", + "arm64" + ] + } + } + }, + "dependencies": { + "@electron/remote": "^2.0.1", + "bulma": "^0.9.2", + "bulma-tooltip": "^3.0.2", + "core-js": "^3.12.1", + "cross-zip": "^3.1.0", + "cross-zip-cli": "^1.0.0", + "font-awesome": "^4.7.0", + "react": "^16.7.0", + "react-dom": "^16.7.0", + "react-tooltip": "^4.2.19", + "source-map-loader": "^1.1.3", + "source-map-support": "0.5.19" + }, + "devDependencies": { + "bufferutil": "^4.0.3", + "electron": "^16", + "electron-builder": "^22", + "electron-webpack": "^2.8.2", + "file-loader": "^3.0.1", + "html-webpack-plugin": "^4.5.2", + "loglevel": "^1.7.1", + "node-sass": "^4.0.0", + "remotedev": "^0.2.9", + "resolve-url-loader": "^3.1.3", + "sass-loader": "^7.3.1", + "url-loader": "^4.1.0", + "utf-8-validate": "^5.0.5", + "webpack": "4.46.0", + "webpack-cli": "^3.3.12" + }, + "private": true +} diff --git a/paket.dependencies b/paket.dependencies new file mode 100644 index 0000000..2741d5a --- /dev/null +++ b/paket.dependencies @@ -0,0 +1,56 @@ + + +framework: auto-detect +source https://api.nuget.org/v3/index.json + +group Electron + source https://api.nuget.org/v3/index.json + nuget Fable.Browser.Css + nuget Fable.Electron + nuget Fable.Elmish + nuget Fable.Elmish.Debugger + nuget Fable.Elmish.HMR + nuget Fable.Elmish.React + nuget Fable.Import.Node + nuget Fable.Browser.Dom + nuget Fable.SimpleJson + nuget Fable.Promise + nuget Fable.React + nuget FSharp.Core redirects:force + nuget Fulma + nuget Fulma.Extensions.Wikiki.Tooltip + +group Testing + source https://api.nuget.org/v3/index.json + + nuget Expecto + nuget Expecto.BenchmarkDotNet + nuget Expecto.FsCheck + nuget Expecto.TestResults + nuget Foq + nuget FSharp.Core redirects:force + nuget FSharp.Data + nuget Logary + nuget Microsoft.NETCore.Platforms + + + +group FakeBuild + source https://api.nuget.org/v3/index.json + + storage: none + nuget FSharp.Core ~> 6.0.1 redirects:force + nuget Fake.Core.Target + nuget Fake.Core.ReleaseNotes + nuget Fake.DotNet.AssemblyInfoFile + nuget Fake.DotNet.Cli + nuget Fake.DotNet.MSBuild + nuget Fake.DotNet.Paket + nuget Fake.IO.FileSystem + nuget Fake.Tools.Git + nuget Fake.JavaScript.Npm + nuget FSharp.Json + nuget dotnet-fake + nuget dotnet-fable + + \ No newline at end of file diff --git a/paket.lock b/paket.lock new file mode 100644 index 0000000..b3daf31 --- /dev/null +++ b/paket.lock @@ -0,0 +1,668 @@ +RESTRICTION: || (== netcoreapp3.1) (== netstandard2.0) + +GROUP Electron +NUGET + remote: https://api.nuget.org/v3/index.json + Fable.Browser.Blob (1.1) - restriction: >= netstandard2.0 + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.6.2) - restriction: >= netstandard2.0 + Fable.Browser.Css (2.0) + Fable.Browser.Dom (>= 1.2) - restriction: >= netstandard2.0 + Fable.Browser.Svg (>= 1.0) - restriction: >= netstandard2.0 + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7) - restriction: >= netstandard2.0 + Fable.Browser.Dom (2.3) + Fable.Browser.Blob (>= 1.1) - restriction: >= netstandard2.0 + Fable.Browser.Event (>= 1.3) - restriction: >= netstandard2.0 + Fable.Browser.WebStorage (>= 1.0) - restriction: >= netstandard2.0 + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fable.Browser.Event (1.3) - restriction: >= netstandard2.0 + Fable.Browser.Gamepad (>= 1.0) - restriction: >= netstandard2.0 + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fable.Browser.Gamepad (1.0) - restriction: >= netstandard2.0 + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fable.Browser.Svg (2.0) - restriction: >= netstandard2.0 + Fable.Browser.Dom (>= 2.0) - restriction: >= netstandard2.0 + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7) - restriction: >= netstandard2.0 + Fable.Browser.WebStorage (1.0) - restriction: >= netstandard2.0 + Fable.Browser.Event (>= 1.0) - restriction: >= netstandard2.0 + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.5.2) - restriction: >= netstandard2.0 + Fable.Core (3.2.5) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fable.Electron (6.0) + Fable.Browser.Dom (>= 1.0) - restriction: >= netstandard2.0 + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + Fable.Node (>= 1.0) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.5.2) - restriction: >= netstandard2.0 + Fable.Elmish (3.1) + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.6.2) - restriction: >= netstandard2.0 + Fable.Elmish.Browser (3.0.4) - restriction: >= netstandard2.0 + Fable.Browser.Dom (>= 1.0) - restriction: >= netstandard2.0 + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + Fable.Elmish (>= 3.0) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.6.2) - restriction: >= netstandard2.0 + Fable.Elmish.Debugger (3.2) + Fable.Core (>= 3.1.5) - restriction: >= netstandard2.0 + Fable.Elmish (>= 3.0) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7) - restriction: >= netstandard2.0 + Thoth.Json (>= 4.0) - restriction: >= netstandard2.0 + Fable.Elmish.HMR (4.1) + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + Fable.Elmish.Browser (>= 3.0.4) - restriction: >= netstandard2.0 + Fable.Elmish.React (>= 3.0.1) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.6.2) - restriction: >= netstandard2.0 + Fable.Elmish.React (3.0.1) + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + Fable.Elmish (>= 3.0) - restriction: >= netstandard2.0 + Fable.React (>= 5.1) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.6.2) - restriction: >= netstandard2.0 + Fable.Import.Node (0.4.3) + Fable.Core (>= 1.3.8) - restriction: >= netstandard2.0 + Fable.Node (1.2) - restriction: >= netstandard2.0 + Fable.Core (>= 3.1.2) - restriction: >= netstandard2.0 + FSharp.Core (>= 5.0) - restriction: >= netstandard2.0 + Fable.Parsimmon (4.1) - restriction: >= netstandard2.0 + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.6.2) - restriction: >= netstandard2.0 + Fable.Promise (2.2) + Fable.Core (>= 3.1.5) - restriction: >= netstandard2.0 + FSharp.Core (>= 5.0) - restriction: >= netstandard2.0 + Fable.React (7.3) + Fable.Browser.Dom (>= 2.0.1) - restriction: >= netstandard2.0 + Fable.Core (>= 3.1.5) - restriction: >= netstandard2.0 + FSharp.Core (>= 5.0) - restriction: >= netstandard2.0 + Fable.SimpleJson (3.19) + Fable.Core (>= 3.1.5) - restriction: >= netstandard2.0 + Fable.Parsimmon (>= 4.0) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7) - restriction: >= netstandard2.0 + FSharp.Core (5.0.1) - redirects: force + Fulma (2.10) + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + Fable.React (>= 5.1) - restriction: >= netstandard2.0 + Fulma.Extensions.Wikiki.Tooltip (3.0) + Fable.Core (>= 3.0) - restriction: >= netstandard2.0 + Fable.React (>= 5.1) - restriction: >= netstandard2.0 + Fulma (>= 2.3) - restriction: >= netstandard2.0 + Thoth.Json (5.1) - restriction: >= netstandard2.0 + Fable.Core (>= 3.1.6) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + +GROUP FakeBuild +STORAGE: NONE +NUGET + remote: https://api.nuget.org/v3/index.json + BlackFox.VsWhere (1.1) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.0.0.1) - restriction: >= net45 + FSharp.Core (>= 4.2.3) - restriction: && (< net45) (>= netstandard2.0) + Microsoft.Win32.Registry (>= 4.7) - restriction: && (< net45) (>= netstandard2.0) + Chessie (0.6) - restriction: >= netcoreapp2.0 + FSharp.Core (>= 4.0.1.7-alpha) - restriction: >= netstandard1.6 + NETStandard.Library (>= 1.6) - restriction: >= netstandard1.6 + dotnet-fable (2.0.11) + Dotnet.ProjInfo (>= 0.20) - restriction: >= netcoreapp2.0 + FSharp.Compiler.Service (>= 25.0.1) - restriction: >= netcoreapp2.0 + FSharp.Core (>= 4.5.2) - restriction: >= netcoreapp2.0 + Microsoft.NETCore.App (>= 2.0) - restriction: >= netcoreapp2.0 + Newtonsoft.Json (>= 11.0.2) - restriction: >= netcoreapp2.0 + dotnet-fake (5.18.3) + Fake.Core.CommandLineParsing (>= 5.18.3) - restriction: >= netcoreapp2.0 + Fake.Runtime (>= 5.18.3) - restriction: >= netcoreapp2.0 + FSharp.Core (>= 4.7) - restriction: >= netcoreapp2.0 + Microsoft.NETCore.App (>= 2.0) - restriction: >= netcoreapp2.0 + Mono.Cecil (>= 0.11) - restriction: >= netcoreapp2.0 + Paket.Core (>= 5.226) - restriction: >= netcoreapp2.0 + Dotnet.ProjInfo (0.44) - restriction: >= netcoreapp2.0 + FSharp.Core (>= 4.6.2) - restriction: || (>= net461) (>= netstandard2.0) + Microsoft.NETFramework.ReferenceAssemblies (>= 1.0) - restriction: || (>= net461) (>= netstandard2.0) + System.ValueTuple (>= 4.4) - restriction: || (>= net461) (>= netstandard2.0) + Fake.Core.CommandLineParsing (5.20.4) - restriction: >= netstandard2.0 + FParsec (>= 1.1.1) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Core.Context (5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Core.DependencyManager.Paket (5.20.4) - restriction: >= netcoreapp2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Core.Environment (5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Core.FakeVar (5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Context (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Core.Process (5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Environment (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.FakeVar (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.String (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.IO.FileSystem (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + System.Collections.Immutable (>= 1.7.1) - restriction: >= netstandard2.0 + Fake.Core.ReleaseNotes (5.20.4) + Fake.Core.SemVer (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.String (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Core.SemVer (5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Core.String (5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Core.Target (5.20.4) + Fake.Core.CommandLineParsing (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Context (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Environment (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.FakeVar (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Process (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.String (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Control.Reactive (>= 4.4.2) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Core.Tasks (5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Core.Trace (5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Environment (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.FakeVar (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Core.Xml (5.20.4) - restriction: >= netstandard2.0 + Fake.Core.String (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.DotNet.AssemblyInfoFile (5.20.4) + Fake.Core.Environment (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.String (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.IO.FileSystem (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.DotNet.Cli (5.20.4) + Fake.Core.Environment (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Process (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.String (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.DotNet.MSBuild (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.DotNet.NuGet (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.IO.FileSystem (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Mono.Posix.NETStandard (>= 1.0) - restriction: >= netstandard2.0 + Newtonsoft.Json (>= 12.0.3) - restriction: >= netstandard2.0 + Fake.DotNet.MSBuild (5.20.4) + BlackFox.VsWhere (>= 1.1) - restriction: >= netstandard2.0 + Fake.Core.Environment (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Process (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.String (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.IO.FileSystem (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + MSBuild.StructuredLogger (>= 2.1.176) - restriction: >= netstandard2.0 + Fake.DotNet.NuGet (5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Environment (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Process (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.SemVer (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.String (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Tasks (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Xml (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.IO.FileSystem (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Net.Http (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Newtonsoft.Json (>= 12.0.3) - restriction: >= netstandard2.0 + NuGet.Protocol (>= 5.6) - restriction: >= netstandard2.0 + Fake.DotNet.Paket (5.20.4) + Fake.Core.Process (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.String (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.DotNet.Cli (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.IO.FileSystem (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.IO.FileSystem (5.20.4) + Fake.Core.String (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.JavaScript.Npm (5.20.4) + Fake.Core.Environment (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Process (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.IO.FileSystem (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Testing.Common (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Net.Http (5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Runtime (5.20.3) - restriction: >= netcoreapp2.0 + Fake.Core.Context (>= 5.20.3) - restriction: >= netstandard2.0 + Fake.Core.DependencyManager.Paket (>= 5.20.3) - restriction: >= netstandard2.0 + FSharp.Compiler.Service (>= 36.0.3) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Microsoft.DotNet.PlatformAbstractions (>= 2.1) - restriction: >= netstandard2.0 + Mono.Cecil (>= 0.11.2) - restriction: >= netstandard2.0 + Paket.Core (>= 5.249) - restriction: >= netstandard2.0 + System.Runtime.Loader (>= 4.3) - restriction: >= netstandard2.0 + Fake.Testing.Common (5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Fake.Tools.Git (5.20.4) + Fake.Core.Environment (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Process (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.SemVer (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.String (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.Core.Trace (>= 5.20.4) - restriction: >= netstandard2.0 + Fake.IO.FileSystem (>= 5.20.4) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + FParsec (1.1.1) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.3.4) - restriction: || (>= net45) (>= netstandard2.0) + System.ValueTuple (>= 4.4) - restriction: >= net45 + FSharp.Compiler.Service (37.0) - restriction: >= netcoreapp2.0 + FSharp.Core (>= 4.6.2) - restriction: || (>= net461) (>= netstandard2.0) + Microsoft.Build.Framework (>= 16.6) - restriction: || (>= net461) (>= netstandard2.0) + Microsoft.Build.Tasks.Core (>= 16.6) - restriction: || (>= net461) (>= netstandard2.0) + Microsoft.Build.Utilities.Core (>= 16.6) - restriction: || (>= net461) (>= netstandard2.0) + System.Buffers (>= 4.5) - restriction: || (>= net461) (>= netstandard2.0) + System.Collections.Immutable (>= 1.5) - restriction: || (>= net461) (>= netstandard2.0) + System.Memory (>= 4.5.3) - restriction: || (>= net461) (>= netstandard2.0) + System.Reflection.Emit (>= 4.3) - restriction: && (< net461) (>= netstandard2.0) + System.Reflection.Metadata (>= 1.6) - restriction: || (>= net461) (>= netstandard2.0) + System.Reflection.TypeExtensions (>= 4.3) - restriction: && (< net461) (>= netstandard2.0) + System.Runtime.Loader (>= 4.0) - restriction: && (< net461) (>= netstandard2.0) + FSharp.Control.Reactive (5.0.2) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + System.Reactive (>= 5.0) - restriction: >= netstandard2.0 + FSharp.Core (6.0.1) - redirects: force + FSharp.Json (0.4) + FSharp.Core (>= 4.6.2) - restriction: >= netstandard2.0 + Microsoft.Bcl.AsyncInterfaces (5.0) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0) (>= netcoreapp2.1)) (&& (< monoandroid) (< netcoreapp2.0) (>= netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.1) (< netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= monotouch) (>= netcoreapp2.1)) (&& (>= net461) (>= netcoreapp2.1)) (>= net472) (&& (< netcoreapp2.0) (>= netcoreapp2.1) (>= xamarinios)) (&& (< netcoreapp2.0) (>= netcoreapp2.1) (>= xamarinmac)) (&& (>= netcoreapp2.1) (< netstandard2.0) (>= xamarintvos)) (&& (>= netcoreapp2.1) (< netstandard2.0) (>= xamarinwatchos)) (&& (>= netcoreapp2.1) (>= uap10.1)) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net461) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) + Microsoft.Build (16.9) - restriction: >= netstandard2.0 + Microsoft.Build.Framework (>= 16.9) - restriction: || (>= net472) (>= netcoreapp2.1) + Microsoft.VisualStudio.Setup.Configuration.Interop (>= 1.16.30) - restriction: >= net472 + Microsoft.Win32.Registry (>= 4.3) - restriction: >= netcoreapp2.1 + System.Collections.Immutable (>= 5.0) - restriction: || (>= net472) (>= netcoreapp2.1) + System.Memory (>= 4.5.4) - restriction: || (>= net472) (>= netcoreapp2.1) + System.Reflection.Metadata (>= 1.6) - restriction: >= netcoreapp2.1 + System.Security.Principal.Windows (>= 4.7) - restriction: >= netcoreapp2.1 + System.Text.Encoding.CodePages (>= 4.0.1) - restriction: >= netcoreapp2.1 + System.Text.Json (>= 4.7) - restriction: || (>= net472) (>= netcoreapp2.1) + System.Threading.Tasks.Dataflow (>= 4.9) - restriction: || (>= net472) (>= netcoreapp2.1) + Microsoft.Build.Framework (16.9) - restriction: >= netstandard2.0 + System.Security.Permissions (>= 4.7) - restriction: && (< net472) (>= netstandard2.0) + Microsoft.Build.Tasks.Core (16.9) - restriction: >= netstandard2.0 + Microsoft.Build.Framework (>= 16.9) - restriction: >= netstandard2.0 + Microsoft.Build.Utilities.Core (>= 16.9) - restriction: >= netstandard2.0 + Microsoft.Win32.Registry (>= 4.3) - restriction: && (< net472) (>= netstandard2.0) + System.CodeDom (>= 4.4) - restriction: && (< net472) (>= netstandard2.0) + System.Collections.Immutable (>= 5.0) - restriction: >= netstandard2.0 + System.Reflection.Metadata (>= 1.6) - restriction: && (< net472) (>= netstandard2.0) + System.Reflection.TypeExtensions (>= 4.1) - restriction: && (< net472) (>= netstandard2.0) + System.Resources.Extensions (>= 4.6) - restriction: >= netstandard2.0 + System.Runtime.InteropServices (>= 4.3) - restriction: && (< net472) (>= netstandard2.0) + System.Security.Cryptography.Pkcs (>= 4.7) - restriction: && (< net472) (>= netstandard2.0) + System.Security.Cryptography.Xml (>= 4.7) - restriction: && (< net472) (>= netstandard2.0) + System.Security.Permissions (>= 4.7) - restriction: && (< net472) (>= netstandard2.0) + System.Threading.Tasks.Dataflow (>= 4.9) - restriction: >= netstandard2.0 + Microsoft.Build.Utilities.Core (16.9) - restriction: >= netstandard2.0 + Microsoft.Build.Framework (>= 16.9) - restriction: >= netstandard2.0 + Microsoft.VisualStudio.Setup.Configuration.Interop (>= 1.16.30) - restriction: >= net472 + Microsoft.Win32.Registry (>= 4.3) - restriction: && (< net472) (>= netstandard2.0) + System.Collections.Immutable (>= 5.0) - restriction: >= netstandard2.0 + System.Security.Permissions (>= 4.7) - restriction: && (< net472) (>= netstandard2.0) + System.Text.Encoding.CodePages (>= 4.0.1) - restriction: && (< net472) (>= netstandard2.0) + Microsoft.DotNet.PlatformAbstractions (3.1.6) - restriction: >= netcoreapp2.0 + Microsoft.NETCore.App (2.2.8) - restriction: >= netcoreapp2.0 + Microsoft.NETCore.DotNetHostPolicy (>= 2.2.8) - restriction: >= netcoreapp2.2 + Microsoft.NETCore.Platforms (>= 2.2.4) - restriction: >= netcoreapp2.2 + Microsoft.NETCore.Targets (>= 2.0) - restriction: >= netcoreapp2.2 + NETStandard.Library (>= 2.0.3) - restriction: >= netcoreapp2.2 + Microsoft.NETCore.DotNetAppHost (5.0.5) - restriction: >= netcoreapp2.2 + Microsoft.NETCore.DotNetHostPolicy (5.0.5) - restriction: >= netcoreapp2.2 + Microsoft.NETCore.DotNetHostResolver (>= 5.0.5) + Microsoft.NETCore.DotNetHostResolver (5.0.5) - restriction: >= netcoreapp2.2 + Microsoft.NETCore.DotNetAppHost (>= 5.0.5) + Microsoft.NETCore.Platforms (5.0.2) - restriction: || (&& (< monoandroid) (>= net5.0) (< netstandard2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netcoreapp2.0)) (&& (>= net461) (>= netcoreapp2.0)) (&& (>= netcoreapp2.0) (>= uap10.1)) (&& (>= netcoreapp2.0) (>= xamarinios)) (&& (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp2.0) (>= xamarinmac)) (&& (>= netcoreapp2.0) (>= xamarintvos)) (&& (>= netcoreapp2.0) (>= xamarinwatchos)) (>= netcoreapp2.1) (&& (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + Microsoft.NETCore.Targets (5.0) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.2)) (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.5)) (&& (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= netcoreapp2.2) + Microsoft.NETFramework.ReferenceAssemblies (1.0) - restriction: >= netcoreapp2.0 + Microsoft.VisualStudio.Setup.Configuration.Interop (1.16.30) - restriction: >= net472 + Microsoft.Win32.Registry (5.0) - restriction: || (&& (< net45) (>= netstandard2.0)) (&& (< net472) (>= netstandard2.0)) (>= netcoreapp2.0) + System.Buffers (>= 4.5.1) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0)) (&& (< monoandroid) (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= monotouch) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Memory (>= 4.5.4) - restriction: || (&& (< monoandroid) (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= uap10.1) + System.Security.AccessControl (>= 5.0) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0)) (&& (< monoandroid) (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (&& (< monoandroid) (>= netcoreapp2.0)) (>= monotouch) (>= net461) (>= netcoreapp2.1) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0)) (&& (< monoandroid) (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (&& (< monoandroid) (>= netcoreapp2.0)) (>= monotouch) (>= net461) (>= netcoreapp2.1) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + Microsoft.Win32.SystemEvents (5.0) - restriction: && (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + Microsoft.NETCore.Platforms (>= 5.0) - restriction: >= netcoreapp2.0 + Mono.Cecil (0.11.3) - restriction: >= netcoreapp2.0 + Mono.Posix.NETStandard (1.0) - restriction: >= netstandard2.0 + MSBuild.StructuredLogger (2.1.404) - restriction: >= netstandard2.0 + Microsoft.Build (>= 16.4) - restriction: >= netstandard2.0 + Microsoft.Build.Framework (>= 16.4) - restriction: >= netstandard2.0 + Microsoft.Build.Tasks.Core (>= 16.4) - restriction: >= netstandard2.0 + Microsoft.Build.Utilities.Core (>= 16.4) - restriction: >= netstandard2.0 + NETStandard.Library (2.0.3) - restriction: >= netcoreapp2.0 + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (>= net45) (< netstandard1.3)) (&& (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.3) (< netstandard1.4) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.4) (< netstandard1.5) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.5) (< netstandard1.6) (< win8) (< wpa81)) (&& (< net45) (>= netstandard1.6) (< netstandard2.0) (< win8) (< wpa81)) (&& (< net45) (>= netstandard2.0)) (&& (>= net46) (< netstandard1.4)) (>= net461) (>= netcoreapp2.0) (&& (>= netstandard1.0) (< portable-net45+win8+wpa81)) (&& (< netstandard1.0) (>= portable-net45+win8) (< win8)) (&& (< netstandard1.0) (< portable-net45+win8) (>= portable-net45+win8+wpa81)) (&& (< netstandard1.0) (>= portable-net45+win8+wp8+wpa81) (< portable-net45+win8+wpa81)) (&& (< netstandard1.0) (>= win8)) (&& (< netstandard1.3) (< win8) (>= wpa81)) (&& (< netstandard1.5) (>= uap10.0)) (>= uap10.1) (>= wp8) + Newtonsoft.Json (13.0.1) - restriction: >= netstandard2.0 + NuGet.Common (5.9) - restriction: >= netstandard2.0 + NuGet.Frameworks (>= 5.9) - restriction: || (>= net45) (>= netstandard2.0) + NuGet.Configuration (5.9) - restriction: >= netstandard2.0 + NuGet.Common (>= 5.9) - restriction: || (>= net45) (>= netstandard2.0) + System.Security.Cryptography.ProtectedData (>= 4.4) - restriction: && (< net45) (>= netstandard2.0) + NuGet.Frameworks (5.9) - restriction: >= netstandard2.0 + NuGet.Packaging (5.9) - restriction: >= netstandard2.0 + Newtonsoft.Json (>= 9.0.1) - restriction: >= netstandard2.0 + NuGet.Configuration (>= 5.9) - restriction: >= netstandard2.0 + NuGet.Versioning (>= 5.9) - restriction: >= netstandard2.0 + System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) + System.Security.Cryptography.Pkcs (>= 5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= net5.0) + NuGet.Protocol (5.9) - restriction: >= netstandard2.0 + NuGet.Packaging (>= 5.9) - restriction: >= netstandard2.0 + NuGet.Versioning (5.9) - restriction: >= netstandard2.0 + Paket.Core (5.257) - restriction: >= netcoreapp2.0 + Chessie (>= 0.6) - restriction: || (>= net45) (>= netstandard2.0) + Mono.Cecil (>= 0.10.0-beta6) - restriction: || (>= net45) (>= netstandard2.0) + Newtonsoft.Json (>= 10.0.3) - restriction: && (< net45) (>= netstandard2.0) + System.Net.Http.WinHttpHandler (>= 4.5) - restriction: && (< net45) (>= netstandard2.0) + System.Security.Cryptography.ProtectedData (>= 4.4) - restriction: && (< net45) (>= netstandard2.0) + System.Buffers (4.5.1) - restriction: || (&& (>= monoandroid) (>= netcoreapp2.1)) (&& (>= monoandroid) (>= netstandard2.0)) (&& (< monoandroid) (< net45) (>= netstandard2.0)) (&& (< monoandroid) (>= netcoreapp2.1) (< xamarintvos) (< xamarinwatchos)) (&& (>= monotouch) (>= netcoreapp2.1)) (&& (>= monotouch) (>= netstandard2.0)) (&& (>= net461) (>= netcoreapp2.1)) (>= net472) (>= netcoreapp2.0) (&& (>= netcoreapp2.1) (< netstandard2.0) (>= xamarintvos)) (&& (>= netcoreapp2.1) (< netstandard2.0) (>= xamarinwatchos)) (&& (>= netstandard2.0) (>= xamarintvos)) (&& (>= netstandard2.0) (>= xamarinwatchos)) (>= xamarinios) (>= xamarinmac) + System.CodeDom (5.0) - restriction: >= netcoreapp2.0 + System.Collections.Immutable (5.0) - restriction: || (&& (>= net461) (>= netcoreapp2.0)) (&& (< net5.0) (>= netcoreapp2.0)) (&& (>= netcoreapp2.0) (< netstandard1.1)) (>= netstandard2.0) + System.Memory (>= 4.5.4) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (< netstandard2.0)) (>= net461) (>= uap10.1) + System.Drawing.Common (5.0.2) - restriction: >= netcoreapp3.0 + Microsoft.Win32.SystemEvents (>= 5.0) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + System.Formats.Asn1 (5.0) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1)) (&& (>= monotouch) (>= netcoreapp2.0)) (&& (>= net5.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp2.0) (>= uap10.1)) (&& (>= netcoreapp2.0) (>= xamarinios)) (&& (>= netcoreapp2.0) (>= xamarinmac)) (&& (>= netcoreapp2.0) (>= xamarintvos)) (&& (>= netcoreapp2.0) (>= xamarinwatchos)) (>= netcoreapp3.0) + System.Buffers (>= 4.5.1) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0)) (&& (< monoandroid) (< netcoreapp2.0) (>= netstandard2.0)) (>= monotouch) (>= net461) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Memory (>= 4.5.4) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net461) (>= uap10.1) + System.IO (4.3) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (< net46) (>= net461) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.4)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.4)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) + Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) + System.Text.Encoding (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) + System.Threading.Tasks (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) + System.Memory (4.5.4) - restriction: || (&& (< monoandroid) (< net45) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.1) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= netcoreapp2.1) (< netstandard2.0)) (&& (>= net461) (>= netcoreapp2.1)) (>= net472) (>= netcoreapp2.0) (&& (>= netcoreapp2.1) (>= uap10.1)) (&& (>= netstandard2.0) (>= uap10.1)) + System.Buffers (>= 4.5.1) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0)) (&& (< monoandroid) (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (< netstandard1.1) (>= portable-net45+win8+wpa81) (< win8)) (>= monotouch) (&& (>= net45) (< netstandard2.0)) (>= net461) (&& (< netstandard1.1) (>= win8)) (&& (< netstandard2.0) (< uap10.1) (>= wpa81)) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0)) (&& (< monoandroid) (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (< monoandroid) (< netstandard1.1) (>= portable-net45+win8+wpa81) (< win8)) (>= monotouch) (&& (>= net45) (< netstandard2.0)) (>= net461) (&& (< netstandard1.1) (>= win8)) (&& (< netstandard2.0) (>= wpa81)) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Net.Http.WinHttpHandler (5.0) - restriction: >= netcoreapp2.0 + System.Buffers (>= 4.5.1) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0)) (&& (< monoandroid) (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= monotouch) (>= net461) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Memory (>= 4.5.4) - restriction: || (&& (< monoandroid) (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net461) (>= uap10.1) + System.Numerics.Vectors (4.5) - restriction: || (&& (< monoandroid) (< netcoreapp2.0) (>= netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net461) (>= netcoreapp2.1)) (>= net472) + System.Reactive (5.0) - restriction: >= netstandard2.0 + System.Runtime.InteropServices.WindowsRuntime (>= 4.3) - restriction: && (< net472) (< netcoreapp3.1) (>= netstandard2.0) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net472) (&& (< netcoreapp3.1) (>= netstandard2.0)) (>= uap10.1) + System.Reflection (4.3) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.2)) (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.5)) (&& (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) + Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) + System.IO (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) + System.Reflection.Primitives (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) + System.Reflection.Emit (4.7) - restriction: >= netcoreapp2.0 + System.Reflection.Metadata (5.0) - restriction: >= netcoreapp2.0 + System.Collections.Immutable (>= 5.0) - restriction: || (&& (>= net45) (< netstandard2.0)) (&& (< net45) (< net5.0) (>= netstandard2.0)) (&& (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81)) (>= net461) (&& (< netstandard1.1) (>= portable-net45+win8+wpa81) (< win8)) (&& (< netstandard1.1) (>= win8)) (&& (< netstandard2.0) (>= wpa81)) + System.Reflection.Primitives (4.3) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.2)) (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.5)) (&& (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + Microsoft.NETCore.Platforms (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + Microsoft.NETCore.Targets (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Runtime (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Reflection.TypeExtensions (4.7) - restriction: >= netcoreapp2.0 + System.Resources.Extensions (5.0) - restriction: >= netcoreapp2.0 + System.Memory (>= 4.5.4) - restriction: || (&& (< monoandroid) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net461) + System.Runtime (4.3.1) - restriction: || (&& (< monoandroid) (< net45) (< netcoreapp3.1) (>= netstandard2.0) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.2)) (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.5)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (< net46) (>= net461) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.4)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.4)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= netcoreapp2.0)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) (&& (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + Microsoft.NETCore.Platforms (>= 1.1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) + Microsoft.NETCore.Targets (>= 1.1.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) + System.Runtime.CompilerServices.Unsafe (5.0) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0) (>= netcoreapp2.1)) (&& (< monoandroid) (< net45) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net5.0) (>= netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net5.0) (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.1)) (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard2.0)) (&& (< monoandroid) (< netcoreapp2.0) (>= netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.1) (< netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netstandard1.0) (>= netstandard2.0) (< win8)) (&& (>= monotouch) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netcoreapp2.1)) (&& (>= net45) (>= netcoreapp2.0) (< netstandard2.0)) (&& (>= net461) (>= netcoreapp2.0)) (&& (>= net461) (>= netcoreapp2.1)) (&& (>= net461) (>= netstandard2.0)) (>= net472) (&& (>= netcoreapp2.0) (< netstandard1.1) (>= win8)) (&& (>= netcoreapp2.0) (< netstandard2.0) (>= wpa81)) (&& (>= netcoreapp2.0) (>= uap10.1)) (&& (>= netcoreapp2.0) (>= xamarinios)) (&& (>= netcoreapp2.0) (>= xamarinmac)) (&& (>= netcoreapp2.0) (>= xamarintvos)) (&& (>= netcoreapp2.0) (>= xamarinwatchos)) (&& (< netcoreapp2.0) (>= netcoreapp2.1) (>= xamarinios)) (&& (< netcoreapp2.0) (>= netcoreapp2.1) (>= xamarinmac)) (&& (>= netcoreapp2.1) (< netstandard2.0) (>= xamarintvos)) (&& (>= netcoreapp2.1) (< netstandard2.0) (>= xamarinwatchos)) (&& (>= netcoreapp2.1) (>= uap10.1)) (&& (< netstandard1.0) (>= netstandard2.0) (>= win8)) (&& (>= netstandard2.0) (>= uap10.1)) (&& (>= netstandard2.0) (>= wp8)) + System.Runtime.Handles (4.3) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.5)) (&& (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + Microsoft.NETCore.Platforms (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + Microsoft.NETCore.Targets (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Runtime (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Runtime.InteropServices (4.3) - restriction: >= netcoreapp2.0 + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (< netcoreapp1.1) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (>= netcoreapp1.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (< netcoreapp1.1) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (>= netcoreapp1.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + System.Reflection (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (< netcoreapp1.1) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (>= netcoreapp1.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + System.Reflection.Primitives (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (< netcoreapp1.1) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (>= netcoreapp1.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (< netcoreapp1.1) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net462) (&& (>= netcoreapp1.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + System.Runtime.Handles (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (< netcoreapp1.1) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (&& (>= netcoreapp1.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + System.Runtime.InteropServices.WindowsRuntime (4.3) - restriction: && (< net472) (< netcoreapp3.1) (>= netstandard2.0) + System.Runtime (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Runtime.Loader (4.3) - restriction: >= netcoreapp2.0 + System.IO (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net462) (>= netstandard1.5) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Reflection (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net462) (>= netstandard1.5) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Runtime (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net462) (>= netstandard1.5) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Security.AccessControl (5.0) - restriction: || (&& (>= monoandroid) (>= netstandard2.0)) (&& (< monoandroid) (< net45) (>= netstandard2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net45) (>= net461) (>= netstandard2.0)) (>= netcoreapp2.0) (&& (>= netstandard2.0) (>= uap10.1)) (&& (>= netstandard2.0) (>= xamarintvos)) (&& (>= netstandard2.0) (>= xamarinwatchos)) (>= xamarinios) (>= xamarinmac) + Microsoft.NETCore.Platforms (>= 5.0) - restriction: >= netcoreapp2.0 + System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (>= net46) (< netstandard2.0)) (&& (< net46) (>= netstandard1.3) (< netstandard2.0) (< uap10.1)) (&& (< net46) (>= netstandard2.0)) (>= net461) (>= netcoreapp2.0) + System.Security.Cryptography.Algorithms (4.3.1) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (>= net46) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net461) (< net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) + System.IO (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (>= net463) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (>= net463) + System.Security.Cryptography.Encoding (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net463) + System.Security.Cryptography.Primitives (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net46) (>= netstandard1.6) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6)) (&& (>= net46) (< netstandard1.4)) (&& (>= net461) (< netstandard1.6)) (>= net463) + System.Security.Cryptography.Cng (5.0) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.1) (< netstandard2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< net472) (>= netstandard2.0)) (>= net5.0) (&& (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + Microsoft.NETCore.Platforms (>= 5.0) - restriction: && (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Formats.Asn1 (>= 5.0) - restriction: && (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Security.Cryptography.Algorithms (>= 4.3.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net46) (>= netstandard1.6) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net46) (>= netstandard1.3) (< netstandard1.4)) (&& (< monoandroid) (< net46) (>= netstandard1.4) (< netstandard1.6) (< uap10.1)) (&& (>= net46) (< netstandard1.4)) (&& (>= net461) (< net462) (< netstandard1.6)) (&& (>= net462) (< netstandard1.6)) (>= net47) + System.Security.Cryptography.Encoding (4.3) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) + System.Security.Cryptography.Pkcs (5.0.1) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= netcoreapp2.0) + System.Formats.Asn1 (>= 5.0) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0) (< netstandard2.1)) (&& (< monoandroid) (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1)) (&& (< monoandroid) (< netcoreapp2.0) (>= netstandard2.1)) (>= monotouch) (>= netcoreapp3.0) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Memory (>= 4.5.4) - restriction: || (&& (< monoandroid) (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= uap10.1) + System.Security.Cryptography.Cng (>= 5.0) - restriction: || (&& (< monoandroid) (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netcoreapp2.0) (>= netstandard2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.1) (< netstandard2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + System.Security.Cryptography.Primitives (4.3) - restriction: || (&& (< monoandroid) (< net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< monoandroid) (< net46) (< netstandard1.6) (>= netstandard2.0)) (&& (< monoandroid) (>= net5.0) (< netstandard1.4)) (&& (< monoandroid) (>= net5.0) (< netstandard1.6)) (&& (< monoandroid) (>= net5.0) (< netstandard2.0) (< xamarintvos) (< xamarinwatchos)) (&& (>= net46) (>= net5.0) (< netstandard1.4)) (&& (>= net46) (< netstandard1.4) (>= netstandard2.0)) (&& (< net46) (>= net461) (< netstandard1.6) (>= netstandard2.0)) (&& (< net46) (>= net47) (>= netstandard2.0)) (&& (>= net461) (< net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net461) (>= net5.0) (< netstandard1.4)) (&& (>= net461) (>= net5.0) (< netstandard1.6)) (&& (>= net461) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net462) (>= net5.0) (< netstandard1.4)) (&& (>= net462) (>= net5.0) (< netstandard1.6)) (&& (>= net462) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net462) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net463) (>= net5.0) (< netstandard1.4)) (&& (>= net463) (>= net5.0) (< netstandard1.6)) (&& (>= net463) (>= net5.0) (< netstandard2.0)) (&& (>= net463) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net463) (< netstandard1.6) (>= netstandard2.0)) (&& (>= net47) (< net472) (>= netstandard2.0)) (&& (>= net47) (>= net5.0)) (&& (>= net47) (< netstandard1.4) (>= netstandard2.0)) (&& (>= net47) (< netstandard1.6) (>= netstandard2.0)) + System.Security.Cryptography.ProtectedData (5.0) - restriction: || (&& (< net45) (>= netstandard2.0)) (>= netcoreapp2.0) + System.Memory (>= 4.5.4) - restriction: && (< monoandroid) (< net46) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Security.Cryptography.Xml (5.0) - restriction: >= netcoreapp2.0 + System.Memory (>= 4.5.4) - restriction: && (< monoandroid) (< net461) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Security.Cryptography.Pkcs (>= 5.0) - restriction: || (>= monoandroid) (>= monotouch) (&& (< net461) (>= netstandard2.0)) (>= netcoreapp2.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Security.Permissions (>= 5.0) - restriction: || (>= monoandroid) (>= monotouch) (>= net461) (>= netstandard2.0) (>= xamarintvos) (>= xamarinwatchos) + System.Security.Permissions (5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= netcoreapp2.0) + System.Security.AccessControl (>= 5.0) - restriction: || (>= net461) (>= netstandard2.0) + System.Windows.Extensions (>= 5.0) - restriction: >= netcoreapp3.0 + System.Security.Principal.Windows (5.0) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0) (>= netstandard2.0)) (&& (< monoandroid) (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (&& (< monoandroid) (>= netcoreapp2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net45) (>= net461) (>= netstandard2.0)) (>= netcoreapp2.1) (&& (>= netstandard2.0) (>= uap10.1)) (&& (>= netstandard2.0) (>= xamarintvos)) (&& (>= netstandard2.0) (>= xamarinwatchos)) (>= xamarinios) (>= xamarinmac) + Microsoft.NETCore.Platforms (>= 5.0) - restriction: || (&& (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (>= netcoreapp2.1) (< netcoreapp3.0)) + System.Text.Encoding (4.3) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.5)) (&& (< monoandroid) (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) + Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) + System.Text.Encoding.CodePages (5.0) - restriction: || (&& (< net472) (>= netstandard2.0)) (>= netcoreapp2.1) + Microsoft.NETCore.Platforms (>= 5.0) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Runtime.CompilerServices.Unsafe (>= 5.0) - restriction: || (&& (< monoandroid) (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net5.0) (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net461) + System.Text.Encodings.Web (5.0.1) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0) (>= netcoreapp2.1)) (&& (< monoandroid) (< net5.0) (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netcoreapp2.0) (>= netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.1) (< netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= monotouch) (>= netcoreapp2.1)) (&& (>= net461) (>= netcoreapp2.1)) (>= net472) (&& (< netcoreapp2.0) (>= netcoreapp2.1) (>= xamarinios)) (&& (< netcoreapp2.0) (>= netcoreapp2.1) (>= xamarinmac)) (&& (>= netcoreapp2.1) (< netstandard2.0) (>= xamarintvos)) (&& (>= netcoreapp2.1) (< netstandard2.0) (>= xamarinwatchos)) (&& (>= netcoreapp2.1) (>= uap10.1)) + System.Buffers (>= 4.5.1) - restriction: || (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1)) (>= net461) + System.Memory (>= 4.5.4) - restriction: || (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1)) (>= net461) (&& (>= netcoreapp2.0) (< netcoreapp2.1) (< netstandard2.1)) (>= uap10.1) + System.Text.Json (5.0.2) - restriction: || (>= net472) (>= netcoreapp2.1) + Microsoft.Bcl.AsyncInterfaces (>= 5.0) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.1) (< netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= monotouch) (>= net461) (&& (< netcoreapp2.0) (>= xamarinios)) (&& (< netcoreapp2.0) (>= xamarinmac)) (&& (< netstandard2.0) (>= xamarintvos)) (&& (< netstandard2.0) (>= xamarinwatchos)) (>= uap10.1) + System.Buffers (>= 4.5.1) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0)) (&& (< monoandroid) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= monotouch) (>= net461) (&& (< netcoreapp2.0) (>= xamarinios)) (&& (< netcoreapp2.0) (>= xamarinmac)) (&& (< netstandard2.0) (>= xamarintvos)) (&& (< netstandard2.0) (>= xamarinwatchos)) + System.Memory (>= 4.5.4) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net461) (>= uap10.1) + System.Numerics.Vectors (>= 4.5) - restriction: || (&& (< monoandroid) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net461) + System.Runtime.CompilerServices.Unsafe (>= 5.0) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0)) (&& (< monoandroid) (< net5.0) (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.1) (< netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= monotouch) (>= net461) (&& (< netcoreapp2.0) (>= xamarinios)) (&& (< netcoreapp2.0) (>= xamarinmac)) (&& (< netstandard2.0) (>= xamarintvos)) (&& (< netstandard2.0) (>= xamarinwatchos)) (>= uap10.1) + System.Text.Encodings.Web (>= 5.0.1) - restriction: || (&& (>= monoandroid) (< netcoreapp2.0)) (&& (< monoandroid) (< net5.0) (>= netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (>= netcoreapp2.1) (< netcoreapp3.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= monotouch) (>= net461) (&& (< netcoreapp2.0) (>= xamarinios)) (&& (< netcoreapp2.0) (>= xamarinmac)) (&& (< netstandard2.0) (>= xamarintvos)) (&& (< netstandard2.0) (>= xamarinwatchos)) (>= uap10.1) + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net461) (>= uap10.1) + System.ValueTuple (>= 4.5) - restriction: >= net461 + System.Threading.Tasks (4.3) - restriction: || (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.3)) (&& (< monoandroid) (>= netcoreapp2.0) (< netstandard1.5)) (&& (< monoandroid) (>= netcoreapp2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) + Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) + System.Threading.Tasks.Dataflow (5.0) - restriction: || (>= net472) (>= netcoreapp2.0) + System.Threading.Tasks.Extensions (4.5.4) - restriction: || (&& (< monoandroid) (< netcoreapp2.0) (>= netcoreapp2.1) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (>= net461) (>= netcoreapp2.1)) (>= net472) (&& (>= netcoreapp2.1) (>= uap10.1)) (&& (< netcoreapp3.1) (>= netstandard2.0)) (&& (>= netstandard2.0) (>= uap10.1)) + System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< netstandard1.0) (>= portable-net45+win8+wp8+wpa81) (< win8)) (&& (>= net45) (< netstandard2.0)) (>= net461) (&& (< netstandard1.0) (>= win8)) (&& (< netstandard2.0) (>= wpa81)) (>= wp8) + System.ValueTuple (4.5) - restriction: || (&& (>= net45) (>= netstandard2.0)) (&& (>= net461) (>= netcoreapp2.1)) (>= net472) (>= netcoreapp2.0) + System.Windows.Extensions (5.0) - restriction: >= netcoreapp3.0 + System.Drawing.Common (>= 5.0) - restriction: >= netcoreapp3.0 + +GROUP Testing +NUGET + remote: https://api.nuget.org/v3/index.json + BenchmarkDotNet (0.12.1) - restriction: || (>= net461) (>= netstandard2.0) + BenchmarkDotNet.Annotations (>= 0.12.1) - restriction: >= netstandard2.0 + CommandLineParser (>= 2.4.3) - restriction: >= netstandard2.0 + Iced (>= 1.4) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.CSharp (>= 2.10) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.NETCore.Client (>= 0.2.61701) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.Runtime (>= 1.1.57604) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.Tracing.TraceEvent (>= 2.0.49) - restriction: >= netstandard2.0 + Microsoft.DotNet.PlatformAbstractions (>= 2.1) - restriction: >= netstandard2.0 + Microsoft.Win32.Registry (>= 4.5) - restriction: >= netstandard2.0 + Perfolizer (>= 0.2.1) - restriction: >= netstandard2.0 + System.Management (>= 4.5) - restriction: >= netstandard2.0 + System.Reflection.Emit (>= 4.3) - restriction: >= netstandard2.0 + System.Reflection.Emit.Lightweight (>= 4.3) - restriction: >= netstandard2.0 + System.Threading.Tasks.Extensions (>= 4.5.2) - restriction: >= netstandard2.0 + System.ValueTuple (>= 4.5) - restriction: >= netstandard2.0 + BenchmarkDotNet.Annotations (0.12.1) - restriction: >= netstandard2.0 + CommandLineParser (2.8) - restriction: >= netstandard2.0 + Expecto (9.0.2) + FSharp.Core (>= 4.6) - restriction: || (>= net461) (>= netstandard2.0) + Mono.Cecil (>= 0.11.2) - restriction: || (>= net461) (>= netstandard2.0) + Expecto.BenchmarkDotNet (9.0.2) + BenchmarkDotNet (>= 0.12.1) - restriction: || (>= net461) (>= netstandard2.0) + FSharp.Core (>= 4.6) - restriction: || (>= net461) (>= netstandard2.0) + Expecto.FsCheck (9.0.2) + Expecto (>= 9.0.2) - restriction: || (>= net461) (>= netstandard2.0) + FsCheck (>= 2.14.2) - restriction: || (>= net461) (>= netstandard2.0) + Expecto.TestResults (8.13.2) + Expecto (>= 8.13.2) - restriction: || (>= net461) (>= netstandard2.0) + FSharp.Core (>= 4.6) - restriction: || (>= net461) (>= netstandard2.0) + Foq (1.8) + FSharp.Core (>= 3.0.2) - restriction: || (&& (>= net40) (< netstandard2.0)) (>= net45) + FSharp.Core (>= 4.2.3) - restriction: && (< net40) (>= netstandard2.0) + System.Reflection.Emit (>= 4.3) - restriction: && (< net40) (>= netstandard2.0) + System.ValueTuple (>= 4.3.1) - restriction: || (&& (>= net40) (< netstandard2.0)) (>= net45) + FParsec (1.1.1) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.3.4) - restriction: || (>= net45) (>= netstandard2.0) + System.ValueTuple (>= 4.4) - restriction: >= net45 + FsCheck (2.15.1) - restriction: || (>= net461) (>= netstandard2.0) + FSharp.Core (>= 4.2.3) - restriction: || (>= net452) (>= netstandard1.6) + FSharp.Core (5.0.1) - redirects: force + FSharp.Data (4.0.1) + FSharp.Core (>= 4.7.2) - restriction: >= netstandard2.0 + Hopac (0.5) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.5.2) - restriction: >= netstandard2.0 + Iced (1.11) - restriction: >= netstandard2.0 + Logary (5.0.1) + FParsec (>= 1.1.1) - restriction: >= netstandard2.0 + FSharp.Core (>= 4.7) - restriction: >= netstandard2.0 + Hopac (>= 0.4.1) - restriction: >= netstandard2.0 + NodaTime (>= 2.4.8) - restriction: >= netstandard2.0 + Microsoft.Bcl.AsyncInterfaces (5.0) - restriction: >= netstandard2.0 + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: || (>= net461) (&& (< netcoreapp2.1) (>= netstandard2.0) (< netstandard2.1)) + Microsoft.CodeAnalysis.Analyzers (3.3.2) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.Common (3.9) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.Analyzers (>= 3.0) - restriction: >= netstandard2.0 + System.Collections.Immutable (>= 5.0) - restriction: >= netstandard2.0 + System.Memory (>= 4.5.4) - restriction: >= netstandard2.0 + System.Reflection.Metadata (>= 5.0) - restriction: >= netstandard2.0 + System.Runtime.CompilerServices.Unsafe (>= 5.0) - restriction: >= netstandard2.0 + System.Text.Encoding.CodePages (>= 4.5.1) - restriction: >= netstandard2.0 + System.Threading.Tasks.Extensions (>= 4.5.4) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.CSharp (3.9) - restriction: >= netstandard2.0 + Microsoft.CodeAnalysis.Common (3.9) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.NETCore.Client (0.2.217401) - restriction: >= netstandard2.0 + Microsoft.Bcl.AsyncInterfaces (>= 1.1) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.Runtime (2.0.217201) - restriction: >= netstandard2.0 + Microsoft.Diagnostics.NETCore.Client (>= 0.2.61701) + System.Buffers (>= 4.5.1) + System.Collections.Immutable (>= 1.7.1) + System.Memory (>= 4.5.4) + System.Reflection.Metadata (>= 1.8.1) + System.Runtime.CompilerServices.Unsafe (>= 4.7.1) + Microsoft.Diagnostics.Tracing.TraceEvent (2.0.66) - restriction: >= netstandard2.0 + System.Runtime.CompilerServices.Unsafe (>= 4.5.2) - restriction: || (>= net45) (>= netstandard1.6) + Microsoft.DotNet.PlatformAbstractions (3.1.6) - restriction: >= netstandard2.0 + System.Runtime.InteropServices.RuntimeInformation (>= 4.0) - restriction: || (>= net45) (&& (>= netstandard1.3) (< netstandard2.0)) + Microsoft.NETCore.Platforms (5.0.2) + Microsoft.NETCore.Targets (5.0) - restriction: >= net5.0 + Microsoft.Win32.Registry (5.0) - restriction: >= netstandard2.0 + System.Buffers (>= 4.5.1) - restriction: || (>= monoandroid) (>= monotouch) (&& (< net46) (< netcoreapp2.0) (>= netstandard2.0)) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Memory (>= 4.5.4) - restriction: || (&& (< monoandroid) (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac)) (&& (>= netcoreapp2.0) (< netcoreapp2.1)) (>= uap10.1) + System.Security.AccessControl (>= 5.0) - restriction: || (>= monoandroid) (>= monotouch) (&& (< net46) (>= netstandard2.0)) (>= net461) (>= netcoreapp2.0) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Security.Principal.Windows (>= 5.0) - restriction: || (>= monoandroid) (>= monotouch) (&& (< net46) (>= netstandard2.0)) (>= net461) (>= netcoreapp2.0) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + Mono.Cecil (0.11.3) - restriction: || (>= net461) (>= netstandard2.0) + NodaTime (3.0.5) - restriction: >= netstandard2.0 + System.Runtime.CompilerServices.Unsafe (>= 4.7.1) - restriction: >= netstandard2.0 + Perfolizer (0.2.1) - restriction: >= netstandard2.0 + System.Memory (>= 4.5.3) - restriction: >= netstandard2.0 + System.Buffers (4.5.1) - restriction: >= netstandard2.0 + System.CodeDom (5.0) - restriction: || (&& (< net45) (>= netstandard2.0)) (>= netcoreapp2.0) + System.Collections.Immutable (5.0) - restriction: >= netstandard2.0 + System.Memory (>= 4.5.4) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac)) (&& (>= net46) (< netstandard2.0)) (>= net461) (>= uap10.1) + System.Globalization (4.3) - restriction: >= net5.0 + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (>= net5.0) + Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (>= net5.0) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (>= net5.0) + System.IO (4.3) - restriction: >= net5.0 + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net5.0) + Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net5.0) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net5.0) + System.Text.Encoding (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net5.0) + System.Threading.Tasks (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net5.0) + System.Management (5.0) - restriction: >= netstandard2.0 + Microsoft.NETCore.Platforms (>= 5.0) - restriction: >= netcoreapp2.0 + Microsoft.Win32.Registry (>= 5.0) - restriction: >= netcoreapp2.0 + System.CodeDom (>= 5.0) - restriction: || (&& (< net45) (>= netstandard2.0)) (>= netcoreapp2.0) + System.Memory (4.5.4) - restriction: || (&& (>= netcoreapp2.0) (< netcoreapp2.1)) (>= netstandard2.0) + System.Buffers (>= 4.5.1) - restriction: || (>= monoandroid) (>= monotouch) (&& (>= net45) (< netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (&& (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81)) (>= net461) (&& (< netstandard1.1) (>= portable-net45+win8+wpa81) (< win8)) (&& (< netstandard1.1) (>= win8)) (&& (< netstandard2.0) (< uap10.1) (>= wpa81)) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Numerics.Vectors (>= 4.4) - restriction: && (< monoandroid) (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac) + System.Numerics.Vectors (>= 4.5) - restriction: >= net461 + System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (>= monoandroid) (>= monotouch) (&& (>= net45) (< netstandard2.0)) (&& (< net45) (< netcoreapp2.0) (>= netstandard2.0)) (&& (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81)) (>= net461) (&& (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (< netstandard1.1) (>= portable-net45+win8+wpa81) (< win8)) (&& (< netstandard1.1) (>= win8)) (&& (< netstandard2.0) (>= wpa81)) (>= uap10.1) (>= xamarinios) (>= xamarinmac) (>= xamarintvos) (>= xamarinwatchos) + System.Numerics.Vectors (4.5) - restriction: || (&& (< monoandroid) (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac)) (&& (>= net461) (>= netstandard2.0)) + System.Reflection (4.3) - restriction: >= net5.0 + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net5.0) + Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net5.0) + System.IO (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net5.0) + System.Reflection.Primitives (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net5.0) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net5.0) + System.Reflection.Emit (4.7) - restriction: >= netstandard2.0 + System.IO (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Reflection (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Reflection.Emit.ILGeneration (>= 4.7) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1) (< xamarinios) (< xamarinmac)) (&& (< monoandroid) (< netstandard1.1) (>= portable-net45+win8+wpa81) (< win8)) (>= net5.0) (&& (< netstandard1.1) (>= win8)) (&& (< netstandard2.0) (>= wpa81)) (>= uap10.1) + System.Reflection.Primitives (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Resources.ResourceManager (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Runtime.InteropServices (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Reflection.Emit.ILGeneration (4.7) - restriction: || (&& (< monoandroid) (< net40) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1) (< xamarinios) (< xamarinmac)) (&& (< monoandroid) (< net40) (< netstandard1.1) (>= netstandard2.0) (< win8)) (>= net5.0) (&& (< netstandard1.1) (>= netstandard2.0) (>= win8)) (&& (>= netstandard2.0) (>= uap10.1)) + System.Reflection (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wp8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Reflection.Primitives (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wp8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Resources.ResourceManager (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wp8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wp8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Reflection.Emit.Lightweight (4.7) - restriction: >= netstandard2.0 + System.Reflection (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wp8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Reflection.Emit.ILGeneration (>= 4.7) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wp8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netcoreapp2.0) (>= netstandard2.0) (< netstandard2.1) (< xamarinios) (< xamarinmac)) (>= net5.0) (&& (< netstandard2.0) (>= wpa81)) (&& (>= portable-net45+win8+wp8+wpa81) (< portable-net45+wp8) (< win8)) (&& (< portable-net45+wp8) (>= win8)) (>= uap10.1) + System.Reflection.Primitives (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wp8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Resources.ResourceManager (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wp8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wp8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Reflection.Metadata (5.0) - restriction: >= netstandard2.0 + System.Collections.Immutable (>= 5.0) - restriction: || (&& (>= net45) (< netstandard2.0)) (&& (< net45) (< net5.0) (>= netstandard2.0)) (&& (< net45) (>= netstandard1.1) (< netstandard2.0) (< win8) (< wpa81)) (>= net461) (&& (< netstandard1.1) (>= portable-net45+win8+wpa81) (< win8)) (&& (< netstandard1.1) (>= win8)) (&& (< netstandard2.0) (>= wpa81)) + System.Reflection.Primitives (4.3) - restriction: >= net5.0 + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Resources.ResourceManager (4.3) - restriction: >= net5.0 + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Globalization (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Reflection (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< win8) (< wp8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (>= net5.0) + System.Runtime (4.3.1) - restriction: >= net5.0 + Microsoft.NETCore.Platforms (>= 1.1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net5.0) + Microsoft.NETCore.Targets (>= 1.1.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.2) (< win8) (< wp8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net5.0) + System.Runtime.CompilerServices.Unsafe (5.0) - restriction: || (&& (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (>= netcoreapp2.0) (< net5.0)) (>= netstandard2.0) + System.Runtime.Handles (4.3) - restriction: >= net5.0 + Microsoft.NETCore.Platforms (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + Microsoft.NETCore.Targets (>= 1.1) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Runtime (>= 4.3) - restriction: && (< monoandroid) (< monotouch) (< net46) (>= netstandard1.3) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos) + System.Runtime.InteropServices (4.3) - restriction: >= net5.0 + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= netcoreapp1.1) + Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= netcoreapp1.1) + System.Reflection (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= netcoreapp1.1) + System.Reflection.Primitives (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= netcoreapp1.1) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.1) (< netstandard1.2) (< win8)) (&& (< monoandroid) (< net45) (>= netstandard1.2) (< netstandard1.3) (< win8) (< wpa81)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= net462) (>= netcoreapp1.1) + System.Runtime.Handles (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.5) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.3) (< netstandard1.5) (< win8) (< wpa81)) (>= netcoreapp1.1) + System.Runtime.InteropServices.RuntimeInformation (4.3) - restriction: && (>= net45) (>= netstandard2.0) + System.Security.AccessControl (5.0) - restriction: || (&& (>= monoandroid) (>= netstandard2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net46) (>= netstandard2.0)) (&& (>= net461) (>= netstandard2.0)) (>= netcoreapp2.0) (&& (>= netstandard2.0) (>= uap10.1)) (&& (>= netstandard2.0) (>= xamarintvos)) (&& (>= netstandard2.0) (>= xamarinwatchos)) (>= xamarinios) (>= xamarinmac) + Microsoft.NETCore.Platforms (>= 5.0) - restriction: >= netcoreapp2.0 + System.Security.Principal.Windows (>= 5.0) - restriction: || (&& (>= net46) (< netstandard2.0)) (&& (< net46) (>= netstandard1.3) (< netstandard2.0) (< uap10.1)) (&& (< net46) (>= netstandard2.0)) (>= net461) (>= netcoreapp2.0) + System.Security.Principal.Windows (5.0) - restriction: || (&& (>= monoandroid) (>= netstandard2.0)) (&& (>= monotouch) (>= netstandard2.0)) (&& (< net46) (>= netstandard2.0)) (&& (>= net461) (>= netstandard2.0)) (>= netcoreapp2.0) (&& (>= netstandard2.0) (>= uap10.1)) (&& (>= netstandard2.0) (>= xamarintvos)) (&& (>= netstandard2.0) (>= xamarinwatchos)) (>= xamarinios) (>= xamarinmac) + Microsoft.NETCore.Platforms (>= 5.0) - restriction: || (&& (>= netcoreapp2.0) (< netcoreapp2.1)) (&& (>= netcoreapp2.1) (< netcoreapp3.0)) + System.Text.Encoding (4.3) - restriction: >= net5.0 + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (>= net5.0) + Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (>= net5.0) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (>= net5.0) + System.Text.Encoding.CodePages (5.0) - restriction: >= netstandard2.0 + Microsoft.NETCore.Platforms (>= 5.0) - restriction: >= netcoreapp2.0 + System.Runtime.CompilerServices.Unsafe (>= 5.0) - restriction: || (&& (< monoandroid) (< net46) (< netcoreapp2.0) (>= netstandard2.0) (< xamarinios) (< xamarinmac)) (>= net461) (&& (>= netcoreapp2.0) (< net5.0)) + System.Threading.Tasks (4.3) - restriction: >= net5.0 + Microsoft.NETCore.Platforms (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (>= net5.0) + Microsoft.NETCore.Targets (>= 1.1) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (>= net5.0) + System.Runtime (>= 4.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.3) (< win8) (< wpa81) (< xamarinios) (< xamarinmac) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (>= netstandard1.0) (< netstandard1.3) (< win8) (< wp8) (< wpa81)) (>= net5.0) + System.Threading.Tasks.Extensions (4.5.4) - restriction: >= netstandard2.0 + System.Runtime.CompilerServices.Unsafe (>= 4.5.3) - restriction: || (&& (< monoandroid) (< monotouch) (< net45) (>= netstandard1.0) (< netstandard2.0) (< win8) (< wpa81) (< xamarintvos) (< xamarinwatchos)) (&& (< monoandroid) (< net45) (< netcoreapp2.1) (>= netstandard2.0) (< xamarinios) (< xamarinmac)) (&& (< monoandroid) (< netstandard1.0) (>= portable-net45+win8+wp8+wpa81) (< win8)) (&& (>= net45) (< netstandard2.0)) (>= net461) (&& (< netstandard1.0) (>= win8)) (&& (< netstandard2.0) (>= wpa81)) (>= wp8) + System.ValueTuple (4.5) - restriction: || (>= net40) (>= netstandard2.0) diff --git a/paket.references b/paket.references new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/paket.references @@ -0,0 +1 @@ + diff --git a/scc.exe b/scc.exe new file mode 100644 index 0000000..9904158 Binary files /dev/null and b/scc.exe differ diff --git a/src/Main/AssemblyInfo.fs b/src/Main/AssemblyInfo.fs new file mode 100644 index 0000000..2ae2041 --- /dev/null +++ b/src/Main/AssemblyInfo.fs @@ -0,0 +1,22 @@ +// Auto-Generated by FAKE; do not edit +namespace System +open System.Reflection +open System.Runtime.CompilerServices + +[] +[] +[] +[] +[] +[] +[] +do () + +module internal AssemblyVersionInformation = + let [] AssemblyTitle = "Main" + let [] AssemblyProduct = "issie" + let [] AssemblyDescription = "Schematic editor and Simulator" + let [] AssemblyVersion = "0.5.0" + let [] AssemblyFileVersion = "0.5.0" + let [] AssemblyConfiguration = "Release" + let [] InternalsVisibleTo = "Main.Tests" diff --git a/src/Main/Main.fs b/src/Main/Main.fs new file mode 100644 index 0000000..13a71bd --- /dev/null +++ b/src/Main/Main.fs @@ -0,0 +1,220 @@ +module Main + +open Fable.Core +open Fable.Core.JsInterop +open ElectronAPI +open Node + + +mainProcess.systemPreferences.setUserDefault?("NSDisabledDictationMenuItem","boolean", "true") +mainProcess.systemPreferences.setUserDefault?("NSDisabledCharacterPaletteMenu","boolean", "true") + +let args = + Api.``process``.argv + |> Seq.toList + |> List.map (fun s -> s.ToLower()) + +/// Returns true if any of flags are present as command line argument. +let argFlagIsOn (flags:string list) = + let fl = List.map (fun (s:string) -> s.ToLower()) flags + List.exists (fun flag -> List.contains flag args) fl + +let hasDebugArgs() = argFlagIsOn ["--debug";"-d"] + +//[] +//let initRemote():Unit = jsNative + + +/// Fix to access the deprecated @electron.remote module. +/// This must be enabled from main.fs +/// NB the interface used here is not precisely correct, because it +/// exposes the original electron-remote API. The @electron.remote API is +/// a bit reduced, but with some extra code to control access. +/// electronRemote replaces electron.remote and renderer.remote in old interface +[] +let electronRemote : RemoteMainInterface = jsNative +electronRemote?initialize() // one-off initialization (see also electronRemote.enable below) + + + +//initRemote() + + +let debug = false + +let isMacos = Api.``process``.platform = Base.Darwin +let isWin = Api.``process``.platform = Base.Win32 + + + + + +mainProcess.app.name <- "Issie" + + + +// Keep a global reference of the window object, if you don't, the window will +// be closed automatically when the JavaScript object is garbage collected. +let mutable mainWindow: BrowserWindow option = Option.None + +[] +let staticDir() :string = jsNative + +let mutable closeAfterSave = false + +let wait n cont = + Async.StartImmediate(async { + try + for i in [1..n] do + printf "%i before" i + do! Async.Sleep 1000 + printfn "%i after" i + finally + cont () + }) + +let createMainWindow () = + let options = jsOptions <| fun options -> + options.show <- Some <| true + options.autoHideMenuBar <- Some false + options.backgroundColor <- Some "#FFFFFF" // BUG - colors do not work + options.opacity <- Some 0.8 + + // fix for icons not working on linux + // requires better solution for dist, maybe + //if Api.``process``.platform = Base.Win32 then + options.icon <- Some (U2.Case2 (path.join(staticDir(), "icon-1.png"))) + //elif Api.``process``.platform = Base.Darwin then + //options.icon <- (U2.Case2 (path.join(staticDir(), "icon.icns"))) (the icns icon does not work) + options.title <- Some "issie" + options.webPreferences <- Some ( + jsOptions <| fun o -> + o.nodeIntegration <- Some true + o.contextIsolation <- Some false + o.devTools <- Some true) // allow dev tools to be opened + + let window = mainProcess.BrowserWindow.Create options + + let webContents = window.webContents + // enable electronRemote for the renderer window + electronRemote?enable webContents + mainWindow <- Some window + window + + // This method will be called when Electron has finished + // initialization and is ready to create browser windows. +let startRenderer (doAfterReady: BrowserWindow -> Unit) = + mainProcess.app.on_ready(fun _ _ -> + let window = createMainWindow() + //printfn "window created" + window + |> doAfterReady) |> ignore + + +let loadAppIntoWidowWhenReady (window: BrowserWindow) = + //printfn "setting up load when ready..." + let loadWindowContent (window: BrowserWindow) = + //printfn "starting load..." + if window.isMinimized() then window.show() + + // Load the index.html of the app. + + let isDev = (``process``?defaultApp = true) + + if isDev then + // run the dev tools + if debug then window.webContents.openDevTools() // default open in this case + + sprintf $"http://localhost:{``process``.env?ELECTRON_WEBPACK_WDS_PORT}" + |> window.loadURL + |> ignore + + ``process``.on("uncaughtException", fun err -> JS.console.error(err)) + |> ignore + else + // run the app + let url = + path.join ( __dirname, "index.html") + |> sprintf "file:///%s" + |> Api.URL.Create + + Api.URL.format(url, createEmpty) + |> window.loadURL + |> ignore + //printfn "done load" + loadWindowContent window + window.webContents.on("did-finish-load", ( fun () -> + window.setOpacity 1.0 + window.maximize())) + + +let rec addListeners (window: BrowserWindow) = + // Emitted when the window is closed. + //printfn "adding Main process listeners" + window.on_closed <| (new Function(fun _ -> + // Dereference the window object, usually you would store windows + // in an array if your app supports multi windows, this is the time + // when you should delete the corresponding element. + mainWindow <- Option.None)) + |> ignore + + (window.on: (string * (obj -> unit)) -> Events.EventEmitter)( + // called when attempt is made to close the window + // send this to renderer to let it decide what to do + // unless closeAfterSave is true. + "close", ( fun e -> + if not closeAfterSave then + // prevent default closure + ((unbox e):Event).preventDefault() |> ignore + window.webContents.send("closingWindow"))) + |> ignore + + // quit programmatically from renderer + mainProcess.ipcMain.on ("exit-the-app", fun _ -> + closeAfterSave <- true + //printfn "Closing Issie..." + mainWindow + |> Option.iter (fun win -> win.close())) + |> ignore + + mainProcess.ipcMain.on ("toggle-dev-tools", fun _ _ -> + mainWindow + |> Option.iter (fun win -> win.webContents.toggleDevTools())) + |> ignore + + // Quit when all windows are closed. + mainProcess.app.``on_window-all-closed`` <| Function(fun _ -> + // On Macos it is common for applications and their menu bar + // to stay active until the user quits explicitly with Cmd + Q + // currently this feature can't be properly implemented + // if Api.``process``.platform <> Base.Darwin then + mainProcess.app.quit()) |> ignore + + mainProcess.app.on_activate (fun _ _ -> + // On OS X it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if mainWindow.IsNone then + //printfn "recreating window..." + window = createMainWindow() |> ignore + mainWindow <- Some window + addListeners window + |> loadAppIntoWidowWhenReady |> ignore + mainWindow <- Some window) |> ignore + window + +let rec startup() = + startRenderer( fun win -> + win + |> addListeners + |> loadAppIntoWidowWhenReady + |> ignore) + +startup() + + + + + + + + diff --git a/src/Main/Main.fsproj b/src/Main/Main.fsproj new file mode 100644 index 0000000..07aa06d --- /dev/null +++ b/src/Main/Main.fsproj @@ -0,0 +1,15 @@ + + + netcoreapp3.1 + win-x64;linux-x64 + + + + + + + + + + + \ No newline at end of file diff --git a/src/Main/main.js b/src/Main/main.js new file mode 100644 index 0000000..871fed5 --- /dev/null +++ b/src/Main/main.js @@ -0,0 +1 @@ +// Simple workaround for https://github.com/electron-userland/electron-webpack/issues/225 \ No newline at end of file diff --git a/src/Main/paket.references b/src/Main/paket.references new file mode 100644 index 0000000..5709242 --- /dev/null +++ b/src/Main/paket.references @@ -0,0 +1,13 @@ +group Electron + Fable.Core + Fable.Browser.Dom + Fable.Electron + Fable.Elmish + Fable.Elmish.React + Fable.Elmish.Debugger + Fable.Elmish.HMR + Fable.Node + Fable.Promise + Fable.React + Fulma + Fable.SimpleJson diff --git a/src/Renderer/AssemblyInfo.fs b/src/Renderer/AssemblyInfo.fs new file mode 100644 index 0000000..aab6b51 --- /dev/null +++ b/src/Renderer/AssemblyInfo.fs @@ -0,0 +1,22 @@ +// Auto-Generated by FAKE; do not edit +namespace System +open System.Reflection +open System.Runtime.CompilerServices + +[] +[] +[] +[] +[] +[] +[] +do () + +module internal AssemblyVersionInformation = + let [] AssemblyTitle = "Renderer" + let [] AssemblyProduct = "issie" + let [] AssemblyDescription = "Schematic editor and Simulator" + let [] AssemblyVersion = "0.5.0" + let [] AssemblyFileVersion = "0.5.0" + let [] AssemblyConfiguration = "Release" + let [] InternalsVisibleTo = "Renderer.Tests" diff --git a/src/Renderer/Common/CommonTypes.fs b/src/Renderer/Common/CommonTypes.fs new file mode 100644 index 0000000..203371c --- /dev/null +++ b/src/Renderer/Common/CommonTypes.fs @@ -0,0 +1,563 @@ +(* + These are types used throughout the application +*) + +module CommonTypes + open Fable.Core + + //=================================================// + // Faster version of Map for objects with SHA hash // + //=================================================// + + // Currently not used. Does it work? + + type HMap<'T> = + | Tree of HMap<'T> array + | Found of 'T + | Empty + + let inline initHArray() = Array.create 16 Empty + + let charCodeF = int 'a' + let charCode0 = int '0' + + let inline getHashDigit n (h:string) = + let ch = h[n] + if System.Char.IsDigit ch then + int ch - charCode0 + elif System.Char.IsLetter ch then + int ch - charCodeF + 10 + elif ch = '-' then 0 + else + failwithf "Hash to digit conversion failed on n={n}, char={ch}" + + let getFastHash (sha:string) = + sha + |> Seq.toArray + |> Array.mapi (fun i _ -> getHashDigit i sha) + + let getFastHItem (x,_,_) = x + + let getFastSHA (sha:string, x:int array, _) n = x[n] + + let inline copyUpdate n item arr = + Array.init + (Array.length arr) + (fun i -> if i = n then item else Empty) + + let hMapAdd (getFastEq: 'T -> string) (getSHA: 'T -> int -> int) (item: 'T) (hm: HMap<'T>) = + let hash = getSHA item + let rec hAdd shaIndex hm = + match hm with + | Empty -> Found item + | Found item' -> + let hash' = getSHA item' + if getFastEq item' = getFastEq item then + Found item + else + let h = hash shaIndex + let h' = hash' shaIndex + let arr = initHArray() + if h <> h' then + arr[h] <- Found item + arr[h'] <- Found item' + Tree arr + else + arr[h'] <- hAdd (shaIndex+1) (Found item') + Tree arr + | Tree arr -> + let h = hash shaIndex + let hm' = hAdd (shaIndex+1) arr[h] + Tree <| copyUpdate h hm' arr + hAdd 0 hm + + + let hMapAddMutate (getFastEq: 'T -> string) (getSHA: 'T -> int -> int) (item: 'T) (hm: HMap<'T>) = + let hash = getSHA item + let rec hAdd shaIndex hm = + match hm with + | Empty -> Found item + | Found item' -> + let hash' = getSHA item' + if getFastEq item = getFastEq item' then + Found item + else + let arr = initHArray() + let h = hash shaIndex + let h' = hash' shaIndex + if h <> h' then + arr[h] <- Found item + arr[h'] <- Found item' + Tree arr + else + arr[h'] <- hAdd (shaIndex+1) (Found item') + Tree arr + + | Tree arr -> + let h = hash shaIndex + let hm' = hAdd (shaIndex+1) arr[h] + arr[h] <- hm' + Tree arr + hAdd 0 hm + + let hMapTryFind (getFastEq: 'T -> string) (getSHA: 'T -> int -> int) (item: 'T) (hm: HMap<'T>) = + let rec lookup shaIndex (hm:HMap<'T>) = + match hm with + | Found item' when getFastEq item' = getFastEq item -> + Some item' + | Tree arr -> + let hit = arr[getSHA item shaIndex] + lookup (shaIndex+1) hit + | _ -> None + lookup 0 hm + + let rec hMapFilter (pred: 'T -> bool) (hm: HMap<'T>) = + match hm with + | Found item' as x when pred item' -> x + | Tree arr -> + let arr' = Array.map (hMapFilter pred) arr + if Array.exists (fun x -> x <> Empty) arr' then + Tree arr' + else Empty + | _ -> Empty + + let rec hMapToArray (hm: HMap<'T>) = + match hm with + | Empty -> [||] + | Found x -> [|x|] + | Tree arr -> + arr + |> Array.map hMapToArray + |> Array.concat + + let rec arrayToHmap (getFastEq: 'T -> string) (getSHA: 'T -> int -> int) (arr: 'T array) = + (Empty, arr) + ||> Array.fold (fun hm item -> hMapAddMutate getFastEq getSHA item hm) + + + let rec hMapCount (hm: HMap<'T>) = + match hm with + | Empty -> 0 + | Found _ -> 1 + | Tree arr -> + arr + |> Array.map hMapCount + |> Array.sum + + + + + + + //==========================================// + // Canvas state mapped to f# data structure // + //==========================================// + + /// Specify the type of a port in a Component. + type PortType = Input | Output + + (* + Note on Ports. Ports are used throughout Issie to represent I/Os of components. + Because a design sheet can be instantiated as a component they can also represent I/Os of a sheet. + + 1. Port records are used on both connections and components, a connection + source or target port will have port Id matching that of the port on the + component it connects to. All ports also specify the componentId of the + component they are on (HostID). + 2. Port records on connections do NOT have port numbers, note this means that connection ports + cannot be the same as the corresponding component port. + 3. Port numbers on components are contiguous from 0 separtely for input + and output ports. + 4. Port numbers must match with the index of the port in the corresponding component + InputPorts or OutputPorts list + 5. For custom components port numbers match index of the port in InputPortNames,OutputPortNames + 6. For symbols port numbers determine the vertical order in which ports are displayed. + 7. Thus when changing the order of number of I/Os on a custom component port numbers can be changed + as long as port lists and port name lists are similarly re-ordered. + 8. In the simulation port numbers are not relevant for custom comps - connections match port names with the + sheet input or output component for the port + 9. In the simulation port numbers matter for all other ports: the simulator defines operation based on them. + 10.In model.Symbol ports are kept in a single global map, including port numbers. If port numbers are permuted on + custom components the port numbers in this map must be changed. However this will normally happen since + model.Symbol symbols and ports are changed at the same time by AddSymbol or deleteSymbol or LoadComponents + messages. + *) + + + /// A component I/O. + /// + /// Id (like any other Id) is a string generated with 32 random hex charactes, + /// so it is (practically) globally unique. These Ids are used + /// to uniquely refer to ports and components. They are generated via uuid(). + /// + /// PortNumber is used to identify which port is which on a component, contiguous from 0 + /// separately for inputs and outputs. See comments above type definition for details + /// + /// HostId is the unique Id of the component where the port is. For example, + /// all three ports on the same And component will have the same HostId. + type Port = { + Id : string + // For example, an And would have input ports 0 and 1, and output port 0. + // If the port is used in a Connection record as Source or Target, the Number is None. + PortNumber : int option + PortType : PortType + HostId : string + } + + // NB - this.Text() is not currently used. + + /// This width is for wire displaying, >8 buswires displayed with 8px thickness. Actual size stored in Port type + type Width = One | Two | Three | Four | Five | Six | Seven | Eight + with + member this.Text() = // the match statement is used for performance + match this with + | One -> "1px" + | Two -> "2px" + | Three -> "3px" + | Four -> "4px" + | Five -> "5px" + | Six -> "6px" + | Seven -> "7px" + | Eight -> "8px" + + + /// Name identifies the LoadedComponent used. + /// The labels define legends on symbol designating inputs or outputs: and are the names of the Input or Output components of the CC sheet. + /// Label strings are unique per CustomComponent. + /// Label position in list determines inputPortNumber or outputPortNumber of label. + /// Multiple CustomComponent instances are differentiated by Component data. + type CustomComponentType = { + Name: string + // Tuples with (label * connection width). + InputLabels: (string * int) list + OutputLabels: (string * int) list + } + + type Memory = { + // How many bits the address should have. + // The memory will have 2^AddressWidth memory locations. + AddressWidth : int + // How wide each memory word should be, in bits. + WordWidth : int + // Data is a list of <2^AddressWidth> elements, where each element is a + // 64 bit integer. This makes words longer than 64 bits not supported. + // This can be changed by using strings instead of int64, but that is way + // less memory efficient. + Data : Map + } + + type InitMemData = + | FromData // old method (from data field) + | FromFile of string // FromFile fName => read a file fName.ram for data + | ToFile of string // ToFile fName => write data to a file fName.ram + | ToFileBadName of string // as ToFile but the name does not validate + | UnsignedMultiplier + | SignedMultiplier + + + type Memory1 = { + // is the data initialised from a file name.ram in the project directory, or some other way? + Init: InitMemData + // How many bits the address should have. + // The memory will have 2^AddressWidth memory locations. + AddressWidth : int + // How wide each memory word should be, in bits. + WordWidth : int + // Data is a list of <2^AddressWidth> elements, where each element is a + // 64 bit integer. This makes words longer than 64 bits not supported. + // This can be changed by using strings instead of int64, but that is way + // less memory efficient. + Data : Map + } + + // Types instantiating objects in the Digital extension. + type ComponentType = + | Input of BusWidth: int | Output of BusWidth: int | Viewer of BusWidth: int | IOLabel + | BusCompare of BusWidth: int * CompareValue: uint32 + | BusSelection of OutputWidth: int * OutputLSBit: int + | Constant of Width: int * ConstValue: int64 + | Constant1 of Width: int * ConstValue: int64 * DialogTextValue: string + | Not | And | Or | Xor | Nand | Nor | Xnor |Decode4 + | Mux2 | Demux2 + | NbitsAdder of BusWidth: int | NbitsXor of BusWidth:int + | Custom of CustomComponentType // schematic sheet used as component + | MergeWires | SplitWire of BusWidth: int // int is bus width + // DFFE is a DFF with an enable signal. + // No initial state for DFF or Register? Default 0. + | DFF | DFFE | Register of BusWidth: int | RegisterE of BusWidth: int + | AsyncROM of Memory | ROM of Memory | RAM of Memory // legacy components - to be deleted + | AsyncROM1 of Memory1 | ROM1 of Memory1 | RAM1 of Memory1 | AsyncRAM1 of Memory1 + + /// Active pattern which matches 2-input gate component types. + /// NB - NOT gates are not included here. + let (|IsBinaryGate|NotBinaryGate|) cType = + match cType with + | And | Or | Xor | Nand | Nor | Xnor -> IsBinaryGate + | _ -> NotBinaryGate + + /// get memory component type constructor + /// NB only works with new-style memory components + let getMemType (cType: ComponentType) = + match cType with + | RAM1 _ -> RAM1 + | AsyncRAM1 _ -> AsyncRAM1 + | ROM1 _ -> ROM1 + | AsyncROM1 _ -> AsyncROM1 + | _ -> failwithf $"Can't get memory type from {cType}" + + + /// JSComponent mapped to F# record. + /// Id uniquely identifies the component within a sheet. + /// Label is optional descriptor displayed on schematic. + type Component = { + Id : string + Type : ComponentType + Label : string // All components have a label that may be empty. + InputPorts : Port list // position on this list determines inputPortNumber + OutputPorts : Port list // position in this lits determines OutputPortNumber + X : int + Y : int + H : int + W : int + } + + /// JSConnection mapped to F# record. + /// Id uniquely identifies connection globally and is used by library. + type Connection = { + Id : string + Source : Port + Target : Port + Vertices : (float * float) list + } + + /// F# data describing the contents of a single schematic sheet. + type CanvasState = Component list * Connection list + + //=======// + // Other // + //=======// + + ///unconfigured replaces Some -1, Error replaces None, Configured of int replaces Some (positive int) + type WireWidth = | Configured of int | Unconfigured | ErrorWidth + + type NumberBase = | Hex | Dec | Bin | SDec + + /// Colors to highlight components + /// Case name is used as HTML color name. + /// See JSHelpers.getColorString + /// lots of colors can be added, see https://www.w3schools.com/colors/colors_names.asp + /// The Text() method converts it to the correct HTML string + /// Where speed matters the color must be added as a case in the match statement + type HighLightColor = Red | Blue | Yellow | Green | Orange | Grey | White | Purple | DarkSlateGrey | Thistle | Brown + with + member this.Text() = // the match statement is used for performance + match this with + | Red -> "Red" + | Blue -> "Blue" + | Yellow -> "Yellow" + | Green -> "Green" + | Grey -> "Grey" + | Purple -> "Purple" + | DarkSlateGrey -> "darkslategrey" + | Thistle -> "thistle" + | c -> sprintf "%A" c + + + + // The next types are not strictly necessary, but help in understanding what is what. + // Used consistently they provide type protection that greatly reduces coding errors + + /// SHA hash unique to a component - common between JS and F# + [] + type ComponentId = | ComponentId of string + + /// SHA hash unique to a segment + [] + type SegmentId = | SegmentId of string + + /// SHA hash unique to a connection - common between JS and F# + + /// SHA hash unique to a connection - common between JS and F# + [] + type ConnectionId = | ConnectionId of string + + /// Human-readable name of component as displayed on sheet. + /// For I/O/labelIO components a width indication eg (7:0) is also displayed, but NOT included here + [] + type ComponentLabel = | ComponentLabel of string + + /// SHA hash unique to a component port - common between JS and F#. + /// Connection ports and connected component ports have the same port Id + /// InputPortId and OutputPortID wrap the hash to distinguish component + /// inputs and outputs some times (e.g. in simulation) + [] + type InputPortId = | InputPortId of string + + /// SHA hash unique to a component port - common between JS and F#. + /// Connection ports and connected component ports have the same port Id + /// InputPortId and OutputPortID wrap the hash to distinguish component + /// inputs and outputs some times (e.g. in simulation) + [] + type OutputPortId = | OutputPortId of string + + /// Port numbers are sequential unique with port lists. + /// Inputs and Outputs are both numberd from 0 up. + [] + type InputPortNumber = | InputPortNumber of int + + /// Port numbers are sequential unique with port lists. + /// Inputs and Outputs are both numberd from 0 up. + [] + type OutputPortNumber = | OutputPortNumber of int + + (*---------------------------Types for wave Simulation----------------------------------------*) + + + type MoreWaveData = + | RamWaveData of addr: uint32 * ramPath: ComponentId list * label:string + | ExtraData of ramPath: ComponentId list * label:string + + // The "NetList" types contain all the circuit from Diagram in an abstracted form that + // removed layout info and connections as separate entities. However, connection Ids are + // available as fileds in components for interface to the Diagram conmponents + + /// The driven (output) side of a connection. + /// This is stored with a NLComponent output port number. + /// Note that one output port can drive multiple NLTargets. + type NLTarget = { + TargetCompId: ComponentId + InputPort: InputPortNumber + TargetConnId: ConnectionId + } + + /// The driving (input) side of a connection. + /// This is stored with a NLComponent input port number + type NLSource = { + SourceCompId: ComponentId + OutputPort: OutputPortNumber + SourceConnId: ConnectionId + } + + /// Components with inputs and outputs directly referencing other components. + /// Output ports can connect to multiple components, or none. + /// Input ports connect to a single driver, or nothing. + type NetListComponent = { + Id : ComponentId + Type : ComponentType + Label : string + // List of input port numbers, and single mapped driving output port + // and component. + Inputs : Map + // Mapping from each output port number to all of the input ports and + // Components connected to that port. + Outputs : Map + } + + /// Circuit topology with connections abstracted away. + /// Good for Wavesim calculations. + type NetList = Map + + + (*-----------------------------------------------------------------------------*) + // Types used within waveform Simulation code, and for saved wavesim configuartion + + /// Identifies a fully connected net + /// This ties together labelled nets. + /// should it include the display name(s)? this can be calculated + type NetGroup = { + driverComp: NetListComponent + driverPort: OutputPortNumber + driverNet: NLTarget list + connectedNets: NLTarget list array } + + /// Info saved by Wave Sim. + /// This info is not necessarilu uptodate with deletions or additions in the Diagram. + /// The wavesim code processing this will not fail if non-existent nets are referenced. + type SavedWaveInfo = { + ClkWidth: float + Cursor: uint32 + Radix: NumberBase + LastClk: uint32 + DisplayedPortIds: string array + } + + (*--------------------------------------------------------------------------------------------------*) + + /// Static data describing a schematic sheet loaded as a custom component. + /// Every sheet is always identified with a file from which it is loaded/saved. + /// Name is human readable (and is the filename - without extension) and identifies sheet. + /// File path is the sheet directory and name (with extension). + /// InputLabels, OutputLabels are the I/O connections. + /// The I/O connection integers are bus widths. + /// The I/O connection strings are human readable. The strings are guaranteed + /// to be unique in the I/O connection list. I.e. An input label may be the same + /// as an output label, but two input (or output) labels cannot be the same. + /// The position in the I/O connections list is important as it implicitly + /// indicates the port number. For example, the first element in the InputLabels + /// list is related to the Component's Port with PortNumber 0. + /// Two instances of a loaded component have the same LoadedComponent data. + type LoadedComponent = { + /// File name without extension = sheet name + Name: string + /// When the component was last saved + TimeStamp: System.DateTime + /// Complete file path, including name and dgm extension + FilePath : string + /// Info on WaveSim settings + WaveInfo: SavedWaveInfo option + /// F# equivalent of Diagram components and connections including layout + CanvasState : CanvasState + /// Input port names, and port numbers in any created custom component + InputLabels : (string * int) list + /// Output port names, and port numbers in any created custom component + OutputLabels : (string * int) list + } + + /// Type for an open project which represents a complete design. + /// ProjectPath is directory containing project files. + /// OpenFileName is name of file from which current schematic sheet is loaded/saved, without extension or path + /// LoadedComponents contains the list of schematic sheets, each as a component, one per sheet. + type Project = { + /// directory which contains the project files + ProjectPath : string + /// name of open sheet (without extension) + OpenFileName : string + /// componnets have one-one correspondence with files + LoadedComponents : LoadedComponent list + } + + (*-----------------------------------------------------------------------------*) + // Types used for naming of waveforms in the Waveform Simulator + + /// Identifies the name of a single driving component of a waveform + type LabelSegment = { + LabName : string + BitLimits : int*int + } + + /// Identifies the names of the driving components and the named labels of a waveform + type WaveLabel = { + /// Identifies the names of Output and IOLabel components connected to the waveform's net + OutputsAndIOLabels : string list + /// Identifies the driving components' names + ComposingLabels : LabelSegment list + } + + + /// Value set to None if the connection width could not be inferred. + type ConnectionsWidth = Map + + /// Documents user circuit error found during connection width inference + type WidthInferError = { + Msg : string + ConnectionsAffected : ConnectionId list // A list of connection Ids. + } + + + /// Messages sent from draw block + type JSDiagramMsg = + | InitCanvas of CanvasState // Has to be dispatched only once. + | SelectComponent of Component + | UnselectComponent of unit + | InferWidths of unit + | SetHasUnsavedChanges of bool \ No newline at end of file diff --git a/src/Renderer/Common/DrawHelpers.fs b/src/Renderer/Common/DrawHelpers.fs new file mode 100644 index 0000000..e6717c8 --- /dev/null +++ b/src/Renderer/Common/DrawHelpers.fs @@ -0,0 +1,290 @@ +(* + Helper functions for drawing on SVG canvas: mainly used by the draw block. +*) + +module DrawHelpers +open Browser.Types +open Fable.Core.JsInterop +open Fable.React +open Fable.React.Props + + +//-------------------------------------------------------------------------// +//------------------------------Types--------------------------------------// +//-------------------------------------------------------------------------// + +/// Position on SVG canvas +/// Positions can be added, subtracted, scaled using overloaded +,-, * operators +/// currently these custom operators are not used in Issie - they should be! +type XYPos = + { + X : float + Y : float + } + + /// allowed tolerance when comparing positions with floating point errors for equality + static member epsilon = 0.0000001 + /// Add postions as vectors (overlaoded operator) + + static member ( + ) (left: XYPos, right: XYPos) = + { X = left.X + right.X; Y = left.Y + right.Y } + + /// Subtract positions as vectors (overloaded operator) + static member ( - ) (left: XYPos, right: XYPos) = + { X = left.X - right.X; Y = left.Y - right.Y } + + /// Scale a position by a number (overloaded operator). + static member ( * ) (pos: XYPos, scaleFactor: float) = + { X = pos.X*scaleFactor; Y = pos.Y * scaleFactor } + + /// Compare positions as vectors. Comparison is approximate so + /// it will work even with floating point errors. New infix operator. + static member ( =~ ) (left: XYPos, right: XYPos) = + abs (left.X - right.X) <= XYPos.epsilon && abs (left.Y - right.Y) <= XYPos.epsilon + +let euclideanDistance (pos1: XYPos) (pos2:XYPos) = + let vec = pos1 - pos2 + sqrt(vec.X**2 + vec.Y**2) + +/// example use of comparison operator: note that F# type inference will not work without at least +/// one of the two operator arguments having a known XYPos type. +let private testXYPosComparison a (b:XYPos) = + a =~ b + + +type BoundingBox = { + X: float + Y: float + W: float + H: float +} + +type PortLocation = { + X: float + Y: float + R: float +} + +type MouseOp = + /// button up + | Up + /// button down + | Down + /// Move with button up + | Move + /// Move with button Down + | Drag + +type MouseT = { + Pos: XYPos + Movement: XYPos + Op: MouseOp} + +/// Record to help draw SVG circles +type Circle = { + /// Radius of the circle + R: float + /// color of outline: default => black color + Stroke: string + /// width of outline: default => thin + StrokeWidth: string + /// Fill: 0.0 => transparent, 1.0 => opaque + FillOpacity: float // transparent fill + /// color of fill: default => black color + Fill: string +} + +/// Record tonhelp draw SVG lines +type Line = { + /// color of outline: default => black color + Stroke: string + /// width of outline: default => thin + StrokeWidth: string + /// what type of line: default => solid + StrokeDashArray: string +} + + +/// Record to help create SVG paths (for wire segment jumps ONLY) +type Path = { + Stroke: string + StrokeWidth: string + StrokeDashArray: string + StrokeLinecap: string + Fill: string +} + +/// Record to help create SVG polygons +type Polygon = { + Stroke: string + StrokeWidth: string + FillOpacity: float + Fill: string +} + +/// Record to help create SVG text +type Text = { + /// left/right/middle: horizontal algnment vs (X,Y) + TextAnchor: string + FontSize: string + FontWeight: string + FontFamily: string + Fill: string + UserSelect: UserSelectOptions + /// auto/middle/hanging: vertical alignment vs (X,Y) + DominantBaseline: string +} + +let testCanvas = Browser.Dom.document.createElement("canvas") :?> HTMLCanvasElement +let canvasWidthContext = testCanvas.getContext_2d() + +let getTextWidthInPixels(txt:string, font:string) = + canvasWidthContext.font <- font; // e.g. "16px times new roman"; + canvasWidthContext.measureText(txt).width; + + +/// Default line, change this one to create new lines +let defaultLine = { + Stroke = "Black" + StrokeWidth = "1px" + StrokeDashArray = "None" +} + +/// Default path, change this one to create new paths +let defaultPath = { + Stroke = "Black" + StrokeWidth = "1px" + StrokeDashArray = "None" + StrokeLinecap = "butt" + Fill = "transparent" +} + +/// Default polygon, change this one to create new polygons +let defaultPolygon = { + Stroke = "Black" + StrokeWidth = "1px" + FillOpacity = 1.0 + Fill = "None" +} + +/// Default circle, change this one to create new circles +let defaultCircle = { + R = 5.0 + Stroke = "Black" + StrokeWidth = "1px" + FillOpacity = 1.0 + Fill = "None" +} + +/// Default text, change this to create new text types +let defaultText = { + TextAnchor = "Middle" + FontSize = "10px" + FontFamily = "Verdana, Arial, Helvetica, sans-serif" // Change font family to something good + FontWeight = "Normal" + Fill = "Black" + UserSelect = UserSelectOptions.None + DominantBaseline = "Hanging" +} + +/// Port circle, used by both Sheet and Symbol to create ports +let portCircle = { defaultCircle with R = 5.0; Stroke = "Black"; StrokeWidth = "1.0px"; Fill = "Grey"} +//--------------------------------------------------------------------------// +//-----------------------------Helpers--------------------------------------// +//--------------------------------------------------------------------------// + +/// return a v4 (random) universally unique identifier (UUID) +/// works under .NET and FABLE +#if FABLE_COMPILER +let uuid():string = import "v4" "uuid" +#else +let uuid():string = System.Guid.NewGuid.ToString() +#endif + +// ----------------------------- SVG Helpers ----------------------------- // + +/// Makes a line ReactElement, wildcard inputs as position can be a number or a string +let makeLine (x1: 'a) (y1: 'b) (x2: 'c) (y2: 'd) (lineParameters: Line) = + line [ + X1 x1 + Y1 y1 + X2 x2 + Y2 y2 + SVGAttr.Stroke lineParameters.Stroke + SVGAttr.StrokeWidth lineParameters.StrokeWidth + SVGAttr.StrokeDasharray lineParameters.StrokeDashArray + ] [] + +/// Makes a path ReactElement, points are to be given as an XYPos record element. +/// Please note that this function is designed to create ONLY "Move to - Bézier Curve" +///paths (this is what the "M" and "C" attributes stand for) and NOT a generalized SVG path element. +let makePath (startingPoint: XYPos) (startingControlPoint: XYPos) (endingControlPoint: XYPos) (endingPoint: XYPos) (pathParameters: Path) = + let x1, y1, x2, y2 = startingPoint.X, startingPoint.Y, endingPoint.X, endingPoint.Y + let dx1, dy1, dx2, dy2 = startingControlPoint.X, startingControlPoint.Y, endingControlPoint.X, endingControlPoint.Y + let dAttrribute = sprintf "M %f %f C %f %f, %f %f, %f %f" x1 y1 dx1 dy1 dx2 dy2 x2 y2 + path [ + D dAttrribute + SVGAttr.Stroke pathParameters.Stroke + SVGAttr.StrokeWidth pathParameters.StrokeWidth + SVGAttr.StrokeDasharray pathParameters.StrokeDashArray + SVGAttr.StrokeLinecap pathParameters.StrokeLinecap + SVGAttr.Fill pathParameters.Fill + ] [] + +/// Makes a polygon ReactElement, points are to be given as a correctly formatted SVGAttr.Points string +let makePolygon (points: string) (polygonParameters: Polygon) = + polygon [ + SVGAttr.Points points + SVGAttr.Stroke polygonParameters.Stroke + SVGAttr.StrokeWidth polygonParameters.StrokeWidth + SVGAttr.Fill polygonParameters.Fill + SVGAttr.FillOpacity polygonParameters.FillOpacity + ] [] + +/// Makes a circle ReactElement +let makeCircle (centreX: float) (centreY: float) (circleParameters: Circle) = + circle + [ + Cx centreX + Cy centreY + R circleParameters.R + SVGAttr.Fill circleParameters.Fill + SVGAttr.FillOpacity circleParameters.FillOpacity + SVGAttr.Stroke circleParameters.Stroke + SVGAttr.StrokeWidth circleParameters.StrokeWidth + ] [] + +/// Makes a text ReactElement +let makeText (posX: float) (posY: float) (displayedText: string) (textParameters: Text) = + text [ + X posX; + Y posY; + Style [ + TextAnchor textParameters.TextAnchor + DominantBaseline textParameters.DominantBaseline + FontWeight textParameters.FontWeight + FontSize textParameters.FontSize + Fill textParameters.Fill + UserSelect textParameters.UserSelect + + ] + ] [str <| sprintf "%s" (displayedText)] + + + +/// deliver string suitable for HTML color from a HighlightColor type value +let getColorString (col: CommonTypes.HighLightColor) = + (sprintf "%A" col).ToLower() + + + +//--------------------------------Constants----------------------------------// + +/// these determine the size of the draw block canvas relative to the objects on it. +let canvasUnscaledSize = 3500.0 + + + + + + diff --git a/src/Renderer/Common/EEExtensions.fs b/src/Renderer/Common/EEExtensions.fs new file mode 100644 index 0000000..d3160d9 --- /dev/null +++ b/src/Renderer/Common/EEExtensions.fs @@ -0,0 +1,334 @@ +(* + This module contains some general purpose library functions +*) + +namespace EEExtensions +/// CHANGELIST +/// July 2018: add String.regexMatchGroups, correct documentation for regexMatch + +/// Miscellaneous extensions to core F# library functions +/// Additions to Char, String, Map + + +/// various functions that exist in normal F# but cannot work in fable +module FableReplacements = + let optionMap2 f v1 v2 = match v1, v2 with + | Some v1, Some v2 -> Some (f v1 v2) + | _ -> None + + let listChunkBySize chunkSize l = + let rec listChunkBySize' state chunksLeft itemsRemaining = + match chunksLeft, itemsRemaining with + | _, [] -> state + | 0, _ -> listChunkBySize' ([] :: state) chunkSize itemsRemaining + | _, nextItem::itemsTail -> listChunkBySize' ((nextItem :: List.head state) :: (List.tail state)) (chunksLeft - 1) itemsTail + + match l with + | [] -> [] + | _ -> listChunkBySize' [] 0 l |> List.map List.rev |> List.rev + + let hexToString (x : uint32) = + let rec loop str = + function + | 0u -> str + | num -> loop ((sprintf "%X" (num % 16u)) + str) (num / 16u) + match x with + | 0u -> "0" + | _ -> loop "" x + +// Following char method to convert to integer is partly based on code found on +// http://www.fssnip.net/25/title/Hex-encode-decode +[] +[] +module Char = + + [] + let inline toInt(ch: char): int = + match ch with + | c when c >= '0' && c <= '9' -> int c - int '0' + | c when c >= 'a' && c <= 'f' -> (int c - int 'a') + 10 + | c when c >= 'A' && c <= 'F' -> (int c - int 'A') + 10 + | _ -> failwithf "What ? Error while converting character to digit" + +[] +[] +module String = + + open System + + [] + let inline ofChar( ch: char): string = [| ch |] |> Seq.ofArray |> System.String.Concat + + [] + let inline ofSeq (chars: char seq) : string = System.String.Concat chars + + [] + let inline toSeq (str: string) : char seq = str :> char seq + + [] + let inline ofList (chars: char list) = chars |> Seq.ofList |> System.String.Concat + + + [] + let inline ofArray (chars: char array) = chars |> Seq.ofArray |> System.String.Concat + + [] + let inline toList (str: string): char list = str |> List.ofSeq + + [] + let inline toArray (str: string): char array = str |> Array.ofSeq + + /// splits text into its array of non-whitepace strings separated by whitespace + [] + let splitOnWhitespace (text:string): string array = + text.Split( ([||]: char array) , System.StringSplitOptions.RemoveEmptyEntries) + + let [] DefaultComparison = StringComparison.Ordinal + let inline emptyIfNull str = + match str with + | null -> String.Empty + | _ -> str + /// Concatenate a sequence of strings + /// Using sep as separator + [] + let concat sep (strings : seq) = + String.Join(sep, strings) + + [] + let length (str:string) = + let str = emptyIfNull str + str.Length + + /// True if str contains value + [] + let contains (value:string) (str:string) = + str.Contains(value) + + [] + let compare (strB:string) (strA:string) = + String.Compare(strA, strB, DefaultComparison) + + /// True if str ends with value + [] + let endsWith (value:string) (str:string) = + str.EndsWith(value, DefaultComparison) + /// See String.Equals + [] + let equals (comparisonType:StringComparison) (value:string) (str:string) = + str.Equals(value, comparisonType) + + let inline checkIndex func (comparisonType:StringComparison) value = + let index = func(value, comparisonType) + if index = -1 then None + else Some index + + /// Replace all occurences of oldChar by newchar + [] + let replaceChar (oldChar:char) (newChar:char) (str:string) = + str.Replace(oldChar, newChar) + + /// Replace all occurences of oldValue by newValue + [] + let replace (oldValue:string) (newValue:string) (str:string) = + str.Replace(oldValue, newValue) + + /// Split str at all of separator array elements + /// Return array of strings + /// Adjacent separators generate empty strings + [] + let split (separator:char array) (str:string) = + str.Split(separator, StringSplitOptions.None) + + /// Split str at all of separator array elements + /// Return array of strings + /// Adjacent separators do not generate strings + [] + let splitRemoveEmptyEntries (separator:char array) (str:string) = + str.Split(separator, StringSplitOptions.RemoveEmptyEntries) + + /// Split str at all of separator string array elements + /// Return array of strings + /// Adjacent separators generate empty strings + [] + let splitString (separator:string array) (str:string) = + str.Split(separator, StringSplitOptions.None) + /// Split str at all of separator string array elements + /// Return array of strings + /// Adjacent separators do not generate strings + [] + let splitStringRemoveEmptyEntries (separator:string array) (str:string) = + str.Split(separator, StringSplitOptions.RemoveEmptyEntries) + + /// Return true if str starts with value + [] + let startsWith (value:string) (str:string) = + str.StartsWith(value, DefaultComparison) + + /// Return substring of str at startIndex of length chars + /// Throw ArgumentOutOfRange exception if any part of + /// selected string lies outside str. + [] + let substringLength (startIndex:int) (length: int) (str:string) = + str.Substring(startIndex, length) + /// Return str from startIndex till end + /// Throw ArgumentOutOfRange exception if startWith + /// lies outside str + [] + let substring (startIndex:int) (str:string) = + str.Substring(startIndex) + + [] + let toLower(str:string) = + str.ToLowerInvariant() + + [] + let toUpper(str:string) = + str.ToUpperInvariant() + /// Remove all leading and training whitespace + [] + let trim(str:string) = + str.Trim() + /// Remove all leading and trailing chars in trimChars + [] + let trimChars (trimChars:char []) (str:string) = + str.Trim(trimChars) + /// Remove all leading whitespace + [] + let trimStart (trimChars:char []) (str:string) = + str.TrimStart(trimChars) + /// Remove all trailing whitespace + [] + let trimEnd(trimChars:char []) (str:string) = + str.TrimEnd(trimChars) + + /// Match a regular expression + /// Return Some [grps] where m is the match string, + /// grps is the list of match groups (if any) + /// return None on no match + [] + let regexMatchGroups (regex:string) (str:string) = + let m = Text.RegularExpressions.Regex.Match(str, regex) + if m.Success then + Some [ for n in [1..m.Groups.Count] -> m.Groups[n].Value ] + else None + + /// Match a regular expression + /// Return Some m where m is the match string, + /// return None on no match + [] + let regexMatch (regex:string) (str:string) = + let m = Text.RegularExpressions.Regex(regex).Match(str) + if m.Success + then + Some m.Value // TODO workaround + //let mLst = [ for x in m.Groups -> x.Value ] + //Some (List.head mLst, List.tail mLst) + else None + + /// convert a System.XXX numeric parse function to idiomatic F# option. + /// e.g. String.TryParsewith System.Int32 will return Some n on successful Int32 parse or None. + [] + let tryParseWith (tryParseFunc: string -> bool*'T) = tryParseFunc >> function + | true, v -> Some v + | false, _ -> None + + +[] +[] +module List = + [] + let toString (chars: char list) = chars |> Seq.ofList |> System.String.Concat + + /// Split list into list of lists each such that each element for which pred returns true starts a sublist. + /// Every sublist must contain at least one element. + /// Every sublist except possibly the first starts with an element el for which pred el is true + [] + let chunkAt1 pred lst = + let mutable i = 0 // should optimise this using sequences and yield! to group by subarray + [ for el in lst do + if pred el then i <- i + 1 + yield (i, el); + yield! []] + |> List.groupBy fst + |> List.sortBy fst + |> List.map (snd >> (List.map snd)) + + /// Split list into list of lists each such that each element for which pred returns true starts a sublist. + /// Every sublist must contain at least one element. + /// Every sublist except possibly the first starts with an element el for which pred el is true. + [] + let chunkAt pred list = + let rec loop chunk chunks list = + match list with + | [] -> List.rev ((List.rev chunk)::chunks) + | x::xs when pred x && List.isEmpty chunk -> loop [x] chunks xs + | x::xs when pred x -> loop [x] ((List.rev chunk)::chunks) xs + | x::xs -> loop (x::chunk) chunks xs + loop [] [] list + + + /// Extract Ok elements from result list, return list of Ok values + + + + + + + + [] + let okList lst = [ for x in lst do match x with | Ok y -> yield y | _ -> (); yield! []] + + /// Extract Error elements from result list, return list of errors + [] + let errorList lst = [ for x in lst do match x with | Error y -> yield y | _ -> (); yield! []] + + /// split Result list into pair of Ok and Error value lists repectively + [] + let splitResult resL = + List.fold (fun (rl,el) -> function | Error e -> rl, e :: el | Ok r -> r :: rl, el) ([],[]) resL + + +[] +[] +module Array = + + [] + let toString (chars: char array) = chars |> Seq.ofArray |> System.String.Concat + + /// Split array into array of arrays each such that each element for which pred returns true starts a subarray. + /// Every subarray must contain at least one element. + /// Every subarray except possibly the first starts with an element el for which pred el is true. + [] + let chunkAt pred arr = // should optimise this using sequences and yield! to group by subarray + let mutable i = 0 + [| for x in arr do + if pred x then i <- i + 1 + yield i, x |] + |> Array.groupBy fst + |> Array.map (snd >> (Array.map snd)) + + + +[] +[] +module Map = + /// Looks up key in table, returning defaultValue if + /// key is not in table + [] + let findWithDefault (key:'Key) (table:Map<'Key,'Value>) (defaultValue:'Value) = + match table.TryFind key with | Some v -> v |None -> defaultValue + + /// Return array of all values in table + [] + let values (table:Map<'Key,'Value>) = + table |> Map.toArray |> Array.map snd + + /// Return array of all keys in table + [] + let keys (table:Map<'Key,'Value>) = + table |> Map.toArray |> Array.map fst + + + + + diff --git a/src/Renderer/Common/ElectronAPI.fs b/src/Renderer/Common/ElectronAPI.fs new file mode 100644 index 0000000..b7934e9 --- /dev/null +++ b/src/Renderer/Common/ElectronAPI.fs @@ -0,0 +1,13714 @@ +(* + This module contains the interface to the Electron API. It is autogenerated from the published electron + typescript definitions converted by ts2fable. However, these do not exactly work, some changes are needed +*) + +// ts2fable 0.8.0 +module rec ElectronAPI + +#nowarn "3390" // disable warnings for invalid XML comments +#nowarn "0044" // disable warnings for `Obsolete` usage + +open System +open Fable.Core +open Fable.Core.JS +open Browser.Types + + +/// bool Option -> bool, with None -> false +let jsToBool (b : bool option) = + Option.defaultValue false b + +type NodeEventEmitter = Node.Events.EventEmitter + +type [] MessagePort = + interface end + + + +type [] HTMLElementEventMap = + interface end + +type [] EventListenerOrEventListenerObject = + interface end + +[] type KeyOf<'T> = Key of string +type Array<'T> = System.Collections.Generic.IList<'T> + +type Function = System.Action + +type Record<'T,'S> = 'T * 'S + + +type String = string + + + +type [] GlobalEvent = + interface end + + + +[] +module Electron = + let [] common: Common.IExports = jsNative + let electron = common + + let [] main: Electron.IExports = jsNative + let mainProcess = main + + [] + let renderer: Renderer.IExports = jsNative + + type Remote = + inherit RemoteMainInterface + /// Returns the object returned by require(module) in the main process. + /// Modules specified by their relative path will resolve relative to the + /// entrypoint of the main process. + abstract require: ``module``: string -> obj option + /// Returns the window to which this web page belongs. + /// + /// Note: Do not use removeAllListeners on BrowserWindow. Use of this can + /// remove all blur listeners, disable click events on touch bar buttons, and + /// other unintended consequences. + abstract getCurrentWindow: unit -> BrowserWindow + /// Returns the web contents of this web page. + abstract getCurrentWebContents: unit -> WebContents + /// Returns the global variable of name (e.g. global[name]) in the main + /// process. + abstract getGlobal: name: string -> obj option + /// The `process` object in the main process. This is the same as + /// remote.getGlobal('process') but is cached. + abstract ``process``: NodeJS.Process + + type [] IExports = + abstract NodeEventEmitter: obj + abstract Accelerator: AcceleratorStatic + abstract BrowserView: BrowserViewStatic + abstract BrowserWindow: BrowserWindowStatic + abstract BrowserWindowProxy: BrowserWindowProxyStatic + abstract ClientRequest: ClientRequestStatic + abstract CommandLine: CommandLineStatic + abstract Cookies: CookiesStatic + abstract Debugger: DebuggerStatic + abstract Dock: DockStatic + abstract DownloadItem: DownloadItemStatic + abstract IncomingMessage: IncomingMessageStatic + abstract Menu: MenuStatic + abstract MenuItem: MenuItemStatic + abstract MessageChannelMain: MessageChannelMainStatic + abstract MessagePortMain: MessagePortMainStatic + abstract NativeImage: NativeImageStatic + abstract Notification: NotificationStatic + abstract ServiceWorkers: ServiceWorkersStatic + abstract Session: SessionStatic + abstract ShareMenu: ShareMenuStatic + abstract TouchBar: TouchBarStatic + abstract TouchBarButton: TouchBarButtonStatic + abstract TouchBarColorPicker: TouchBarColorPickerStatic + abstract TouchBarGroup: TouchBarGroupStatic + abstract TouchBarLabel: TouchBarLabelStatic + abstract TouchBarOtherItemsProxy: TouchBarOtherItemsProxyStatic + abstract TouchBarPopover: TouchBarPopoverStatic + abstract TouchBarScrubber: TouchBarScrubberStatic + abstract TouchBarSegmentedControl: TouchBarSegmentedControlStatic + abstract TouchBarSlider: TouchBarSliderStatic + abstract TouchBarSpacer: TouchBarSpacerStatic + abstract Tray: TrayStatic + abstract WebContents: WebContentsStatic + abstract WebFrameMain: WebFrameMainStatic + abstract WebRequest: WebRequestStatic + abstract app: App + abstract autoUpdater: AutoUpdater + abstract clipboard: Clipboard + abstract contentTracing: ContentTracing + abstract contextBridge: ContextBridge + abstract crashReporter: CrashReporter + abstract desktopCapturer: DesktopCapturer + abstract dialog: Dialog + abstract globalShortcut: GlobalShortcut + abstract inAppPurchase: InAppPurchase + abstract ipcMain: IpcMain + abstract ipcRenderer: IpcRenderer + abstract nativeImage: obj + abstract nativeTheme: NativeTheme + abstract net: Net + abstract netLog: NetLog + abstract powerMonitor: PowerMonitor + abstract powerSaveBlocker: PowerSaveBlocker + abstract protocol: Protocol + abstract screen: Screen + abstract session: obj + abstract shell: Shell + abstract systemPreferences: SystemPreferences + abstract webContents: WebContents + abstract webFrame: WebFrame + abstract webFrameMain: obj + abstract webviewTag: WebviewTag + + type Accelerator = string + + + type [] AcceleratorStatic = + [] abstract Create: unit -> Accelerator + + type [] App = + inherit NodeJS.EventEmitter + /// + /// Emitted when Chrome's accessibility support changes. This event fires when + /// assistive technologies, such as screen readers, are enabled or disabled. See + /// for more + /// details. + /// + [] abstract ``on_accessibility-support-changed``: listener: (Event -> bool -> unit) -> App + [] abstract ``once_accessibility-support-changed``: listener: (Event -> bool -> unit) -> App + [] abstract ``addListener_accessibility-support-changed``: listener: (Event -> bool -> unit) -> App + [] abstract ``removeListener_accessibility-support-changed``: listener: (Event -> bool -> unit) -> App + /// + /// Emitted when the application is activated. Various actions can trigger this + /// event, such as launching the application for the first time, attempting to + /// re-launch the application when it's already running, or clicking on the + /// application's dock or taskbar icon. + /// + [] abstract on_activate: listener: (Event -> bool -> unit) -> App + [] abstract once_activate: listener: (Event -> bool -> unit) -> App + [] abstract addListener_activate: listener: (Event -> bool -> unit) -> App + [] abstract removeListener_activate: listener: (Event -> bool -> unit) -> App + /// + /// Emitted during Handoff after an activity from this device was successfully + /// resumed on another one. + /// + [] abstract ``on_activity-was-continued``: listener: (Event -> string -> obj -> unit) -> App + [] abstract ``once_activity-was-continued``: listener: (Event -> string -> obj -> unit) -> App + [] abstract ``addListener_activity-was-continued``: listener: (Event -> string -> obj -> unit) -> App + [] abstract ``removeListener_activity-was-continued``: listener: (Event -> string -> obj -> unit) -> App + /// + /// Emitted before the application starts closing its windows. Calling + /// event.preventDefault() will prevent the default behavior, which is terminating + /// the application. + /// + /// **Note:** If application quit was initiated by autoUpdater.quitAndInstall(), + /// then before-quit is emitted *after* emitting close event on all windows and + /// closing them. + /// + /// **Note:** On Windows, this event will not be emitted if the app is closed due to + /// a shutdown/restart of the system or a user logout. + /// + [] abstract ``on_before-quit``: listener: (Event -> unit) -> App + [] abstract ``once_before-quit``: listener: (Event -> unit) -> App + [] abstract ``addListener_before-quit``: listener: (Event -> unit) -> App + [] abstract ``removeListener_before-quit``: listener: (Event -> unit) -> App + /// Emitted when a browserWindow gets blurred. + [] abstract ``on_browser-window-blur``: listener: (Event -> BrowserWindow -> unit) -> App + [] abstract ``once_browser-window-blur``: listener: (Event -> BrowserWindow -> unit) -> App + [] abstract ``addListener_browser-window-blur``: listener: (Event -> BrowserWindow -> unit) -> App + [] abstract ``removeListener_browser-window-blur``: listener: (Event -> BrowserWindow -> unit) -> App + /// Emitted when a new browserWindow is created. + [] abstract ``on_browser-window-created``: listener: (Event -> BrowserWindow -> unit) -> App + [] abstract ``once_browser-window-created``: listener: (Event -> BrowserWindow -> unit) -> App + [] abstract ``addListener_browser-window-created``: listener: (Event -> BrowserWindow -> unit) -> App + [] abstract ``removeListener_browser-window-created``: listener: (Event -> BrowserWindow -> unit) -> App + /// Emitted when a browserWindow gets focused. + [] abstract ``on_browser-window-focus``: listener: (Event -> BrowserWindow -> unit) -> App + [] abstract ``once_browser-window-focus``: listener: (Event -> BrowserWindow -> unit) -> App + [] abstract ``addListener_browser-window-focus``: listener: (Event -> BrowserWindow -> unit) -> App + [] abstract ``removeListener_browser-window-focus``: listener: (Event -> BrowserWindow -> unit) -> App + /// + /// Emitted when failed to verify the certificate for url, to trust the + /// certificate you should prevent the default behavior with + /// event.preventDefault() and call callback(true). + /// + [] abstract ``on_certificate-error``: listener: (Event -> WebContents -> string -> string -> Certificate -> (bool -> unit) -> unit) -> App + [] abstract ``once_certificate-error``: listener: (Event -> WebContents -> string -> string -> Certificate -> (bool -> unit) -> unit) -> App + [] abstract ``addListener_certificate-error``: listener: (Event -> WebContents -> string -> string -> Certificate -> (bool -> unit) -> unit) -> App + [] abstract ``removeListener_certificate-error``: listener: (Event -> WebContents -> string -> string -> Certificate -> (bool -> unit) -> unit) -> App + /// Emitted when the child process unexpectedly disappears. This is normally because + /// it was crashed or killed. It does not include renderer processes. + [] abstract ``on_child-process-gone``: listener: (Event -> Details -> unit) -> App + [] abstract ``once_child-process-gone``: listener: (Event -> Details -> unit) -> App + [] abstract ``addListener_child-process-gone``: listener: (Event -> Details -> unit) -> App + [] abstract ``removeListener_child-process-gone``: listener: (Event -> Details -> unit) -> App + /// + /// Emitted during Handoff when an activity from a different device wants to be + /// resumed. You should call event.preventDefault() if you want to handle this + /// event. + /// + /// A user activity can be continued only in an app that has the same developer Team + /// ID as the activity's source app and that supports the activity's type. Supported + /// activity types are specified in the app's Info.plist under the + /// NSUserActivityTypes key. + /// + [] abstract ``on_continue-activity``: listener: (Event -> string -> obj -> unit) -> App + [] abstract ``once_continue-activity``: listener: (Event -> string -> obj -> unit) -> App + [] abstract ``addListener_continue-activity``: listener: (Event -> string -> obj -> unit) -> App + [] abstract ``removeListener_continue-activity``: listener: (Event -> string -> obj -> unit) -> App + /// + /// Emitted during Handoff when an activity from a different device fails to be + /// resumed. + /// + [] abstract ``on_continue-activity-error``: listener: (Event -> string -> string -> unit) -> App + [] abstract ``once_continue-activity-error``: listener: (Event -> string -> string -> unit) -> App + [] abstract ``addListener_continue-activity-error``: listener: (Event -> string -> string -> unit) -> App + [] abstract ``removeListener_continue-activity-error``: listener: (Event -> string -> string -> unit) -> App + /// + /// Emitted when desktopCapturer.getSources() is called in the renderer process of + /// webContents. Calling event.preventDefault() will make it return empty + /// sources. + /// + [] abstract ``on_desktop-capturer-get-sources``: listener: (Event -> WebContents -> unit) -> App + [] abstract ``once_desktop-capturer-get-sources``: listener: (Event -> WebContents -> unit) -> App + [] abstract ``addListener_desktop-capturer-get-sources``: listener: (Event -> WebContents -> unit) -> App + [] abstract ``removeListener_desktop-capturer-get-sources``: listener: (Event -> WebContents -> unit) -> App + /// + /// Emitted when mac application become active. Difference from activate event is + /// that did-become-active is emitted every time the app becomes active, not only + /// when Dock icon is clicked or application is re-launched. + /// + [] abstract ``on_did-become-active``: listener: (Event -> unit) -> App + [] abstract ``once_did-become-active``: listener: (Event -> unit) -> App + [] abstract ``addListener_did-become-active``: listener: (Event -> unit) -> App + [] abstract ``removeListener_did-become-active``: listener: (Event -> unit) -> App + /// Emitted whenever there is a GPU info update. + [] abstract ``on_gpu-info-update``: listener: Function -> App + [] abstract ``once_gpu-info-update``: listener: Function -> App + [] abstract ``addListener_gpu-info-update``: listener: Function -> App + [] abstract ``removeListener_gpu-info-update``: listener: Function -> App + /// + /// Emitted when the GPU process crashes or is killed. + /// + /// **Deprecated:** This event is superceded by the child-process-gone event which + /// contains more information about why the child process disappeared. It isn't + /// always because it crashed. The killed boolean can be replaced by checking + /// reason === 'killed' when you switch to that event. + /// + [] + [] abstract ``on_gpu-process-crashed``: listener: (Event -> bool -> unit) -> App + [] abstract ``once_gpu-process-crashed``: listener: (Event -> bool -> unit) -> App + [] abstract ``addListener_gpu-process-crashed``: listener: (Event -> bool -> unit) -> App + [] abstract ``removeListener_gpu-process-crashed``: listener: (Event -> bool -> unit) -> App + /// + /// Emitted when webContents wants to do basic auth. + /// + /// The default behavior is to cancel all authentications. To override this you + /// should prevent the default behavior with event.preventDefault() and call + /// callback(username, password) with the credentials. + /// + /// If callback is called without a username or password, the authentication + /// request will be cancelled and the authentication error will be returned to the + /// page. + /// + [] abstract on_login: listener: (Event -> WebContents -> AuthenticationResponseDetails -> AuthInfo -> ((string) option -> (string) option -> unit) -> unit) -> App + [] abstract once_login: listener: (Event -> WebContents -> AuthenticationResponseDetails -> AuthInfo -> ((string) option -> (string) option -> unit) -> unit) -> App + [] abstract addListener_login: listener: (Event -> WebContents -> AuthenticationResponseDetails -> AuthInfo -> ((string) option -> (string) option -> unit) -> unit) -> App + [] abstract removeListener_login: listener: (Event -> WebContents -> AuthenticationResponseDetails -> AuthInfo -> ((string) option -> (string) option -> unit) -> unit) -> App + /// + /// Emitted when the user clicks the native macOS new tab button. The new tab button + /// is only visible if the current BrowserWindow has a tabbingIdentifier + /// + [] abstract ``on_new-window-for-tab``: listener: (Event -> unit) -> App + [] abstract ``once_new-window-for-tab``: listener: (Event -> unit) -> App + [] abstract ``addListener_new-window-for-tab``: listener: (Event -> unit) -> App + [] abstract ``removeListener_new-window-for-tab``: listener: (Event -> unit) -> App + /// + /// Emitted when the user wants to open a file with the application. The open-file + /// event is usually emitted when the application is already open and the OS wants + /// to reuse the application to open the file. open-file is also emitted when a + /// file is dropped onto the dock and the application is not yet running. Make sure + /// to listen for the open-file event very early in your application startup to + /// handle this case (even before the ready event is emitted). + /// + /// You should call event.preventDefault() if you want to handle this event. + /// + /// On Windows, you have to parse process.argv (in the main process) to get the + /// filepath. + /// + [] abstract ``on_open-file``: listener: (Event -> string -> unit) -> App + [] abstract ``once_open-file``: listener: (Event -> string -> unit) -> App + [] abstract ``addListener_open-file``: listener: (Event -> string -> unit) -> App + [] abstract ``removeListener_open-file``: listener: (Event -> string -> unit) -> App + /// + /// Emitted when the user wants to open a URL with the application. Your + /// application's Info.plist file must define the URL scheme within the + /// CFBundleURLTypes key, and set NSPrincipalClass to AtomApplication. + /// + /// You should call event.preventDefault() if you want to handle this event. + /// + [] abstract ``on_open-url``: listener: (Event -> string -> unit) -> App + [] abstract ``once_open-url``: listener: (Event -> string -> unit) -> App + [] abstract ``addListener_open-url``: listener: (Event -> string -> unit) -> App + [] abstract ``removeListener_open-url``: listener: (Event -> string -> unit) -> App + /// Emitted when the application is quitting. + /// + /// **Note:** On Windows, this event will not be emitted if the app is closed due to + /// a shutdown/restart of the system or a user logout. + [] abstract on_quit: listener: (Event -> float -> unit) -> App + [] abstract once_quit: listener: (Event -> float -> unit) -> App + [] abstract addListener_quit: listener: (Event -> float -> unit) -> App + [] abstract removeListener_quit: listener: (Event -> float -> unit) -> App + /// + /// Emitted once, when Electron has finished initializing. On macOS, launchInfo + /// holds the userInfo of the NSUserNotification or information from + /// UNNotificationResponse that was used to open the application, if it was + /// launched from Notification Center. You can also call app.isReady() to check if + /// this event has already fired and app.whenReady() to get a Promise that is + /// fulfilled when Electron is initialized. + /// + [] abstract on_ready: listener: (Event -> U2, NotificationResponse> -> unit) -> App + [] abstract once_ready: listener: (Event -> U2, NotificationResponse> -> unit) -> App + [] abstract addListener_ready: listener: (Event -> U2, NotificationResponse> -> unit) -> App + [] abstract removeListener_ready: listener: (Event -> U2, NotificationResponse> -> unit) -> App + /// Emitted when the renderer process unexpectedly disappears. This is normally + /// because it was crashed or killed. + [] abstract ``on_render-process-gone``: listener: (Event -> WebContents -> RenderProcessGoneDetails -> unit) -> App + [] abstract ``once_render-process-gone``: listener: (Event -> WebContents -> RenderProcessGoneDetails -> unit) -> App + [] abstract ``addListener_render-process-gone``: listener: (Event -> WebContents -> RenderProcessGoneDetails -> unit) -> App + [] abstract ``removeListener_render-process-gone``: listener: (Event -> WebContents -> RenderProcessGoneDetails -> unit) -> App + /// + /// Emitted when the renderer process of webContents crashes or is killed. + /// + /// **Deprecated:** This event is superceded by the render-process-gone event + /// which contains more information about why the render process disappeared. It + /// isn't always because it crashed. The killed boolean can be replaced by + /// checking reason === 'killed' when you switch to that event. + /// + [] + [] abstract ``on_renderer-process-crashed``: listener: (Event -> WebContents -> bool -> unit) -> App + [] abstract ``once_renderer-process-crashed``: listener: (Event -> WebContents -> bool -> unit) -> App + [] abstract ``addListener_renderer-process-crashed``: listener: (Event -> WebContents -> bool -> unit) -> App + [] abstract ``removeListener_renderer-process-crashed``: listener: (Event -> WebContents -> bool -> unit) -> App + /// + /// This event will be emitted inside the primary instance of your application when + /// a second instance has been executed and calls app.requestSingleInstanceLock(). + /// + /// argv is an Array of the second instance's command line arguments, and + /// workingDirectory is its current working directory. Usually applications + /// respond to this by making their primary window focused and non-minimized. + /// + /// **Note:** If the second instance is started by a different user than the first, + /// the argv array will not include the arguments. + /// + /// This event is guaranteed to be emitted after the ready event of app gets + /// emitted. + /// + /// **Note:** Extra command line arguments might be added by Chromium, such as + /// --original-process-start-time. + /// + [] abstract ``on_second-instance``: listener: (Event -> ResizeArray -> string -> unit) -> App + [] abstract ``once_second-instance``: listener: (Event -> ResizeArray -> string -> unit) -> App + [] abstract ``addListener_second-instance``: listener: (Event -> ResizeArray -> string -> unit) -> App + [] abstract ``removeListener_second-instance``: listener: (Event -> ResizeArray -> string -> unit) -> App + /// + /// Emitted when a client certificate is requested. + /// + /// The url corresponds to the navigation entry requesting the client certificate + /// and callback can be called with an entry filtered from the list. Using + /// event.preventDefault() prevents the application from using the first + /// certificate from the store. + /// + [] abstract ``on_select-client-certificate``: listener: (Event -> WebContents -> string -> ResizeArray -> ((Certificate) option -> unit) -> unit) -> App + [] abstract ``once_select-client-certificate``: listener: (Event -> WebContents -> string -> ResizeArray -> ((Certificate) option -> unit) -> unit) -> App + [] abstract ``addListener_select-client-certificate``: listener: (Event -> WebContents -> string -> ResizeArray -> ((Certificate) option -> unit) -> unit) -> App + [] abstract ``removeListener_select-client-certificate``: listener: (Event -> WebContents -> string -> ResizeArray -> ((Certificate) option -> unit) -> unit) -> App + /// Emitted when Electron has created a new session. + [] abstract ``on_session-created``: listener: (Session -> unit) -> App + [] abstract ``once_session-created``: listener: (Session -> unit) -> App + [] abstract ``addListener_session-created``: listener: (Session -> unit) -> App + [] abstract ``removeListener_session-created``: listener: (Session -> unit) -> App + /// + /// Emitted when Handoff is about to be resumed on another device. If you need to + /// update the state to be transferred, you should call event.preventDefault() + /// immediately, construct a new userInfo dictionary and call + /// app.updateCurrentActivity() in a timely manner. Otherwise, the operation will + /// fail and continue-activity-error will be called. + /// + [] abstract ``on_update-activity-state``: listener: (Event -> string -> obj -> unit) -> App + [] abstract ``once_update-activity-state``: listener: (Event -> string -> obj -> unit) -> App + [] abstract ``addListener_update-activity-state``: listener: (Event -> string -> obj -> unit) -> App + [] abstract ``removeListener_update-activity-state``: listener: (Event -> string -> obj -> unit) -> App + /// Emitted when a new webContents is created. + [] abstract ``on_web-contents-created``: listener: (Event -> WebContents -> unit) -> App + [] abstract ``once_web-contents-created``: listener: (Event -> WebContents -> unit) -> App + [] abstract ``addListener_web-contents-created``: listener: (Event -> WebContents -> unit) -> App + [] abstract ``removeListener_web-contents-created``: listener: (Event -> WebContents -> unit) -> App + /// + /// Emitted during Handoff before an activity from a different device wants to be + /// resumed. You should call event.preventDefault() if you want to handle this + /// event. + /// + [] abstract ``on_will-continue-activity``: listener: (Event -> string -> unit) -> App + [] abstract ``once_will-continue-activity``: listener: (Event -> string -> unit) -> App + [] abstract ``addListener_will-continue-activity``: listener: (Event -> string -> unit) -> App + [] abstract ``removeListener_will-continue-activity``: listener: (Event -> string -> unit) -> App + /// + /// Emitted when the application has finished basic startup. On Windows and Linux, + /// the will-finish-launching event is the same as the ready event; on macOS, + /// this event represents the applicationWillFinishLaunching notification of + /// NSApplication. You would usually set up listeners for the open-file and + /// open-url events here, and start the crash reporter and auto updater. + /// + /// In most cases, you should do everything in the ready event handler. + /// + [] abstract ``on_will-finish-launching``: listener: Function -> App + [] abstract ``once_will-finish-launching``: listener: Function -> App + [] abstract ``addListener_will-finish-launching``: listener: Function -> App + [] abstract ``removeListener_will-finish-launching``: listener: Function -> App + /// + /// Emitted when all windows have been closed and the application will quit. Calling + /// event.preventDefault() will prevent the default behavior, which is terminating + /// the application. + /// + /// See the description of the window-all-closed event for the differences between + /// the will-quit and window-all-closed events. + /// + /// **Note:** On Windows, this event will not be emitted if the app is closed due to + /// a shutdown/restart of the system or a user logout. + /// + [] abstract ``on_will-quit``: listener: (Event -> unit) -> App + [] abstract ``once_will-quit``: listener: (Event -> unit) -> App + [] abstract ``addListener_will-quit``: listener: (Event -> unit) -> App + [] abstract ``removeListener_will-quit``: listener: (Event -> unit) -> App + /// + /// Emitted when all windows have been closed. + /// + /// If you do not subscribe to this event and all windows are closed, the default + /// behavior is to quit the app; however, if you subscribe, you control whether the + /// app quits or not. If the user pressed Cmd + Q, or the developer called + /// app.quit(), Electron will first try to close all the windows and then emit the + /// will-quit event, and in this case the window-all-closed event would not be + /// emitted. + /// + [] abstract ``on_window-all-closed``: listener: Function -> App + [] abstract ``once_window-all-closed``: listener: Function -> App + [] abstract ``addListener_window-all-closed``: listener: Function -> App + [] abstract ``removeListener_window-all-closed``: listener: Function -> App + /// + /// Adds path to the recent documents list. + /// + /// This list is managed by the OS. On Windows, you can visit the list from the task + /// bar, and on macOS, you can visit it from dock menu. + /// + abstract addRecentDocument: path: string -> unit + /// Clears the recent documents list. + abstract clearRecentDocuments: unit -> unit + /// By default, Chromium disables 3D APIs (e.g. WebGL) until restart on a per domain + /// basis if the GPU processes crashes too frequently. This function disables that + /// behavior. + /// + /// This method can only be called before app is ready. + abstract disableDomainBlockingFor3DAPIs: unit -> unit + /// Disables hardware acceleration for current app. + /// + /// This method can only be called before app is ready. + abstract disableHardwareAcceleration: unit -> unit + /// + /// Enables full sandbox mode on the app. This means that all renderers will be + /// launched sandboxed, regardless of the value of the sandbox flag in + /// WebPreferences. + /// + /// This method can only be called before app is ready. + /// + abstract enableSandbox: unit -> unit + /// + /// Exits immediately with exitCode. exitCode defaults to 0. + /// + /// All windows will be closed immediately without asking the user, and the + /// before-quit and will-quit events will not be emitted. + /// + abstract exit: ?exitCode: float -> unit + /// + /// On Linux, focuses on the first visible window. On macOS, makes the application + /// the active app. On Windows, focuses on the application's first window. + /// + /// You should seek to use the steal option as sparingly as possible. + /// + abstract focus: ?options: FocusOptions -> unit + /// + /// Resolve with an object containing the following: + /// + /// * icon NativeImage - the display icon of the app handling the protocol. + /// * path String - installation path of the app handling the protocol. + /// * name String - display name of the app handling the protocol. + /// + /// This method returns a promise that contains the application name, icon and path + /// of the default handler for the protocol (aka URI scheme) of a URL. + /// + abstract getApplicationInfoForProtocol: url: string -> Promise + /// + /// Name of the application handling the protocol, or an empty string if there is no + /// handler. For instance, if Electron is the default handler of the URL, this could + /// be Electron on Windows and Mac. However, don't rely on the precise format + /// which is not guaranteed to remain unchanged. Expect a different format on Linux, + /// possibly with a .desktop suffix. + /// + /// This method returns the application name of the default handler for the protocol + /// (aka URI scheme) of a URL. + /// + abstract getApplicationNameForProtocol: url: string -> string + /// + /// Array of ProcessMetric objects that correspond to memory and CPU usage + /// statistics of all the processes associated with the app. + /// + abstract getAppMetrics: unit -> ResizeArray + /// The current application directory. + abstract getAppPath: unit -> string + /// The current value displayed in the counter badge. + abstract getBadgeCount: unit -> float + /// The type of the currently running activity. + abstract getCurrentActivityType: unit -> string + /// + /// fulfilled with the app's icon, which is a NativeImage. + /// + /// Fetches a path's associated icon. + /// + /// On _Windows_, there a 2 kinds of icons: + /// + /// * Icons associated with certain file extensions, like .mp3, .png, etc. + /// * Icons inside the file itself, like .exe, .dll, .ico. + /// + /// On _Linux_ and _macOS_, icons depend on the application associated with file + /// mime type. + /// + abstract getFileIcon: path: string * ?options: FileIconOptions -> Promise + /// + /// The Graphics Feature Status from chrome://gpu/. + /// + /// **Note:** This information is only usable after the gpu-info-update event is + /// emitted. + /// + abstract getGPUFeatureStatus: unit -> GPUFeatureStatus + /// + /// For infoType equal to complete: Promise is fulfilled with Object + /// containing all the GPU Information as in chromium's GPUInfo object. This + /// includes the version and driver information that's shown on chrome://gpu page. + /// + /// For infoType equal to basic: Promise is fulfilled with Object containing + /// fewer attributes than when requested with complete. Here's an example of basic + /// response: + /// + /// Using basic should be preferred if only basic information like vendorId or + /// driverId is needed. + /// + abstract getGPUInfo: infoType: AppGetGPUInfo -> Promise + /// + /// * minItems Integer - The minimum number of items that will be shown in the + /// Jump List (for a more detailed description of this value see the MSDN docs). + /// * removedItems JumpListItem[] - Array of JumpListItem objects that + /// correspond to items that the user has explicitly removed from custom categories + /// in the Jump List. These items must not be re-added to the Jump List in the + /// **next** call to app.setJumpList(), Windows will not display any custom + /// category that contains any of the removed items. + /// + abstract getJumpListSettings: unit -> JumpListSettings + /// + /// The current application locale, fetched using Chromium's l10n_util library. + /// Possible return values are documented here. + /// + /// To set the locale, you'll want to use a command line switch at app startup, + /// which may be found here. + /// + /// **Note:** When distributing your packaged app, you have to also ship the + /// locales folder. + /// + /// **Note:** On Windows, you have to call it after the ready events gets emitted. + /// + abstract getLocale: unit -> string + /// User operating system's locale two-letter ISO 3166 country code. The value is + /// taken from native OS APIs. + /// + /// **Note:** When unable to detect locale country code, it returns empty string. + abstract getLocaleCountryCode: unit -> string + /// + /// If you provided path and args options to app.setLoginItemSettings, then + /// you need to pass the same arguments here for openAtLogin to be set correctly. + /// + /// + /// * openAtLogin Boolean - true if the app is set to open at login. + /// * openAsHidden Boolean _macOS_ - true if the app is set to open as hidden at + /// login. This setting is not available on MAS builds. + /// * wasOpenedAtLogin Boolean _macOS_ - true if the app was opened at login + /// automatically. This setting is not available on MAS builds. + /// * wasOpenedAsHidden Boolean _macOS_ - true if the app was opened as a hidden + /// login item. This indicates that the app should not open any windows at startup. + /// This setting is not available on MAS builds. + /// * restoreState Boolean _macOS_ - true if the app was opened as a login item + /// that should restore the state from the previous session. This indicates that the + /// app should restore the windows that were open the last time the app was closed. + /// This setting is not available on MAS builds. + /// * executableWillLaunchAtLogin Boolean _Windows_ - true if app is set to open + /// at login and its run key is not deactivated. This differs from openAtLogin as + /// it ignores the args option, this property will be true if the given executable + /// would be launched at login with **any** arguments. + /// * launchItems Object[] _Windows_ + /// * name String _Windows_ - name value of a registry entry. + /// * path String _Windows_ - The executable to an app that corresponds to a + /// registry entry. + /// * args String[] _Windows_ - the command-line arguments to pass to the + /// executable. + /// * scope String _Windows_ - one of user or machine. Indicates whether the + /// registry entry is under HKEY_CURRENT USER or HKEY_LOCAL_MACHINE. + /// * enabled Boolean _Windows_ - true if the app registry key is startup + /// approved and therefore shows as enabled in Task Manager and Windows settings. + /// + abstract getLoginItemSettings: ?options: LoginItemSettingsOptions -> LoginItemSettings + /// + /// The current application's name, which is the name in the application's + /// package.json file. + /// + /// Usually the name field of package.json is a short lowercase name, according + /// to the npm modules spec. You should usually also specify a productName field, + /// which is your application's full capitalized name, and which will be preferred + /// over name by Electron. + /// + abstract getName: unit -> string + /// + /// A path to a special directory or file associated with name. On failure, an + /// Error is thrown. + /// + /// If app.getPath('logs') is called without called app.setAppLogsPath() being + /// called first, a default log directory will be created equivalent to calling + /// app.setAppLogsPath() without a path parameter. + /// + abstract getPath: name: AppGetPath -> string + /// + /// The version of the loaded application. If no version is found in the + /// application's package.json file, the version of the current bundle or + /// executable is returned. + /// + abstract getVersion: unit -> string + /// + /// This method returns whether or not this instance of your app is currently + /// holding the single instance lock. You can request the lock with + /// app.requestSingleInstanceLock() and release with + /// app.releaseSingleInstanceLock() + /// + abstract hasSingleInstanceLock: unit -> bool + /// Hides all application windows without minimizing them. + abstract hide: unit -> unit + /// + /// Imports the certificate in pkcs12 format into the platform certificate store. + /// callback is called with the result of import operation, a value of 0 + /// indicates success while any other value indicates failure according to Chromium + /// net_error_list. + /// + abstract importCertificate: options: ImportCertificateOptions * callback: (float -> unit) -> unit + /// Invalidates the current Handoff user activity. + abstract invalidateCurrentActivity: unit -> unit + /// + /// true if Chrome's accessibility support is enabled, false otherwise. This API + /// will return true if the use of assistive technologies, such as screen readers, + /// has been detected. See + /// for more + /// details. + /// + abstract isAccessibilitySupportEnabled: unit -> bool + /// + /// Whether the current executable is the default handler for a protocol (aka URI + /// scheme). + /// + /// **Note:** On macOS, you can use this method to check if the app has been + /// registered as the default protocol handler for a protocol. You can also verify + /// this by checking ~/Library/Preferences/com.apple.LaunchServices.plist on the + /// macOS machine. Please refer to Apple's documentation for details. + /// + /// The API uses the Windows Registry and LSCopyDefaultHandlerForURLScheme + /// internally. + /// + abstract isDefaultProtocolClient: protocol: string * ?path: string * ?args: ResizeArray -> bool + /// whether or not the current OS version allows for native emoji pickers. + abstract isEmojiPanelSupported: unit -> bool + /// + /// Whether the application is currently running from the systems Application + /// folder. Use in combination with app.moveToApplicationsFolder() + /// + abstract isInApplicationsFolder: unit -> bool + /// + /// true if Electron has finished initializing, false otherwise. See also + /// app.whenReady(). + /// + abstract isReady: unit -> bool + /// + /// whether Secure Keyboard Entry is enabled. + /// + /// By default this API will return false. + /// + abstract isSecureKeyboardEntryEnabled: unit -> bool + /// Whether the current desktop environment is Unity launcher. + abstract isUnityRunning: unit -> bool + /// + /// Whether the move was successful. Please note that if the move is successful, + /// your application will quit and relaunch. + /// + /// No confirmation dialog will be presented by default. If you wish to allow the + /// user to confirm the operation, you may do so using the dialog API. + /// + /// **NOTE:** This method throws errors if anything other than the user causes the + /// move to fail. For instance if the user cancels the authorization dialog, this + /// method returns false. If we fail to perform the copy, then this method will + /// throw an error. The message in the error should be informative and tell you + /// exactly what went wrong. + /// + /// By default, if an app of the same name as the one being moved exists in the + /// Applications directory and is _not_ running, the existing app will be trashed + /// and the active app moved into its place. If it _is_ running, the pre-existing + /// running app will assume focus and the previously active app will quit itself. + /// This behavior can be changed by providing the optional conflict handler, where + /// the boolean returned by the handler determines whether or not the move conflict + /// is resolved with default behavior. i.e. returning false will ensure no + /// further action is taken, returning true will result in the default behavior + /// and the method continuing. + /// + /// For example: + /// + /// Would mean that if an app already exists in the user directory, if the user + /// chooses to 'Continue Move' then the function would continue with its default + /// behavior and the existing app will be trashed and the active app moved into its + /// place. + /// + abstract moveToApplicationsFolder: ?options: MoveToApplicationsFolderOptions -> bool + /// + /// Try to close all windows. The before-quit event will be emitted first. If all + /// windows are successfully closed, the will-quit event will be emitted and by + /// default the application will terminate. + /// + /// This method guarantees that all beforeunload and unload event handlers are + /// correctly executed. It is possible that a window cancels the quitting by + /// returning false in the beforeunload event handler. + /// + abstract quit: unit -> unit + /// + /// Relaunches the app when current instance exits. + /// + /// By default, the new instance will use the same working directory and command + /// line arguments with current instance. When args is specified, the args will + /// be passed as command line arguments instead. When execPath is specified, the + /// execPath will be executed for relaunch instead of current app. + /// + /// Note that this method does not quit the app when executed, you have to call + /// app.quit or app.exit after calling app.relaunch to make the app restart. + /// + /// When app.relaunch is called for multiple times, multiple instances will be + /// started after current instance exited. + /// + /// An example of restarting current instance immediately and adding a new command + /// line argument to the new instance: + /// + abstract relaunch: ?options: RelaunchOptions -> unit + /// + /// Releases all locks that were created by requestSingleInstanceLock. This will + /// allow multiple instances of the application to once again run side by side. + /// + abstract releaseSingleInstanceLock: unit -> unit + /// + /// Whether the call succeeded. + /// + /// This method checks if the current executable as the default handler for a + /// protocol (aka URI scheme). If so, it will remove the app as the default handler. + /// + abstract removeAsDefaultProtocolClient: protocol: string * ?path: string * ?args: ResizeArray -> bool + /// + /// The return value of this method indicates whether or not this instance of your + /// application successfully obtained the lock. If it failed to obtain the lock, + /// you can assume that another instance of your application is already running with + /// the lock and exit immediately. + /// + /// I.e. This method returns true if your process is the primary instance of your + /// application and your app should continue loading. It returns false if your + /// process should immediately quit as it has sent its parameters to another + /// instance that has already acquired the lock. + /// + /// On macOS, the system enforces single instance automatically when users try to + /// open a second instance of your app in Finder, and the open-file and open-url + /// events will be emitted for that. However when users start your app in command + /// line, the system's single instance mechanism will be bypassed, and you have to + /// use this method to ensure single instance. + /// + /// An example of activating the window of primary instance when a second instance + /// starts: + /// + abstract requestSingleInstanceLock: unit -> bool + /// Marks the current Handoff user activity as inactive without invalidating it. + abstract resignCurrentActivity: unit -> unit + /// + /// Set the about panel options. This will override the values defined in the app's + /// .plist file on macOS. See the Apple docs for more details. On Linux, values + /// must be set in order to be shown; there are no defaults. + /// + /// If you do not set credits but still wish to surface them in your app, AppKit + /// will look for a file named "Credits.html", "Credits.rtf", and "Credits.rtfd", in + /// that order, in the bundle returned by the NSBundle class method main. The first + /// file found is used, and if none is found, the info area is left blank. See Apple + /// documentation for more information. + /// + abstract setAboutPanelOptions: options: AboutPanelOptionsOptions -> unit + /// + /// Manually enables Chrome's accessibility support, allowing to expose + /// accessibility switch to users in application settings. See Chromium's + /// accessibility docs for more details. Disabled by default. + /// + /// This API must be called after the ready event is emitted. + /// + /// **Note:** Rendering accessibility tree can significantly affect the performance + /// of your app. It should not be enabled by default. + /// + abstract setAccessibilitySupportEnabled: enabled: bool -> unit + /// + /// Sets the activation policy for a given app. + /// + /// Activation policy types: + /// + /// * 'regular' - The application is an ordinary app that appears in the Dock and + /// may have a user interface. + /// * 'accessory' - The application doesn’t appear in the Dock and doesn’t have a + /// menu bar, but it may be activated programmatically or by clicking on one of its + /// windows. + /// * 'prohibited' - The application doesn’t appear in the Dock and may not create + /// windows or be activated. + /// + abstract setActivationPolicy: policy: AppSetActivationPolicy -> unit + /// + /// Sets or creates a directory your app's logs which can then be manipulated with + /// app.getPath() or app.setPath(pathName, newPath). + /// + /// Calling app.setAppLogsPath() without a path parameter will result in this + /// directory being set to ~/Library/Logs/YourAppName on _macOS_, and inside the + /// userData directory on _Linux_ and _Windows_. + /// + abstract setAppLogsPath: ?path: string -> unit + /// Changes the Application User Model ID to id. + abstract setAppUserModelId: id: string -> unit + /// + /// Whether the call succeeded. + /// + /// Sets the current executable as the default handler for a protocol (aka URI + /// scheme). It allows you to integrate your app deeper into the operating system. + /// Once registered, all links with your-protocol:// will be opened with the + /// current executable. The whole link, including protocol, will be passed to your + /// application as a parameter. + /// + /// **Note:** On macOS, you can only register protocols that have been added to your + /// app's info.plist, which cannot be modified at runtime. However, you can change + /// the file during build time via Electron Forge, Electron Packager, or by editing + /// info.plist with a text editor. Please refer to Apple's documentation for + /// details. + /// + /// **Note:** In a Windows Store environment (when packaged as an appx) this API + /// will return true for all calls but the registry key it sets won't be + /// accessible by other applications. In order to register your Windows Store + /// application as a default protocol handler you must declare the protocol in your + /// manifest. + /// + /// The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme + /// internally. + /// + abstract setAsDefaultProtocolClient: protocol: string * ?path: string * ?args: ResizeArray -> bool + /// + /// Whether the call succeeded. + /// + /// Sets the counter badge for current app. Setting the count to 0 will hide the + /// badge. + /// + /// On macOS, it shows on the dock icon. On Linux, it only works for Unity launcher. + /// + /// **Note:** Unity launcher requires a .desktop file to work. For more + /// information, please read the Unity integration documentation. + /// + abstract setBadgeCount: ?count: float -> bool + /// + /// Sets or removes a custom Jump List for the application, and returns one of the + /// following strings: + /// + /// * ok - Nothing went wrong. + /// * error - One or more errors occurred, enable runtime logging to figure out + /// the likely cause. + /// * invalidSeparatorError - An attempt was made to add a separator to a custom + /// category in the Jump List. Separators are only allowed in the standard Tasks + /// category. + /// * fileTypeRegistrationError - An attempt was made to add a file link to the + /// Jump List for a file type the app isn't registered to handle. + /// * customCategoryAccessDeniedError - Custom categories can't be added to the + /// Jump List due to user privacy or group policy settings. + /// + /// If categories is null the previously set custom Jump List (if any) will be + /// replaced by the standard Jump List for the app (managed by Windows). + /// + /// **Note:** If a JumpListCategory object has neither the type nor the name + /// property set then its type is assumed to be tasks. If the name property is + /// set but the type property is omitted then the type is assumed to be + /// custom. + /// + /// **Note:** Users can remove items from custom categories, and Windows will not + /// allow a removed item to be added back into a custom category until **after** the + /// next successful call to app.setJumpList(categories). Any attempt to re-add a + /// removed item to a custom category earlier than that will result in the entire + /// custom category being omitted from the Jump List. The list of removed items can + /// be obtained using app.getJumpListSettings(). + /// + /// **Note:** The maximum length of a Jump List item's description property is 260 + /// characters. Beyond this limit, the item will not be added to the Jump List, nor + /// will it be displayed. + /// + /// Here's a very simple example of creating a custom Jump List: + /// + abstract setJumpList: categories: ResizeArray option -> unit + /// + /// To work with Electron's autoUpdater on Windows, which uses Squirrel, you'll + /// want to set the launch path to Update.exe, and pass arguments that specify your + /// application name. For example: + /// + abstract setLoginItemSettings: settings: Settings -> unit + /// Overrides the current application's name. + /// + /// **Note:** This function overrides the name used internally by Electron; it does + /// not affect the name that the OS uses. + abstract setName: name: string -> unit + /// + /// Overrides the path to a special directory or file associated with name. If + /// the path specifies a directory that does not exist, an Error is thrown. In + /// that case, the directory should be created with fs.mkdirSync or similar. + /// + /// You can only override paths of a name defined in app.getPath. + /// + /// By default, web pages' cookies and caches will be stored under the userData + /// directory. If you want to change this location, you have to override the + /// userData path before the ready event of the app module is emitted. + /// + abstract setPath: name: string * path: string -> unit + /// + /// Set the Secure Keyboard Entry is enabled in your application. + /// + /// By using this API, important information such as password and other sensitive + /// information can be prevented from being intercepted by other processes. + /// + /// See Apple's documentation for more details. + /// + /// **Note:** Enable Secure Keyboard Entry only when it is needed and disable it + /// when it is no longer needed. + /// + abstract setSecureKeyboardEntryEnabled: enabled: bool -> unit + /// + /// Creates an NSUserActivity and sets it as the current activity. The activity is + /// eligible for Handoff to another device afterward. + /// + abstract setUserActivity: ``type``: string * userInfo: obj option * ?webpageURL: string -> unit + /// + /// Adds tasks to the Tasks category of the Jump List on Windows. + /// + /// tasks is an array of Task objects. + /// + /// Whether the call succeeded. + /// + /// **Note:** If you'd like to customize the Jump List even more use + /// app.setJumpList(categories) instead. + /// + abstract setUserTasks: tasks: ResizeArray -> bool + /// + /// Shows application windows after they were hidden. Does not automatically focus + /// them. + /// + abstract show: unit -> unit + /// + /// Show the app's about panel options. These options can be overridden with + /// app.setAboutPanelOptions(options). + /// + abstract showAboutPanel: unit -> unit + /// Show the platform's native emoji picker. + abstract showEmojiPanel: unit -> unit + /// + /// This function **must** be called once you have finished accessing the security + /// scoped file. If you do not remember to stop accessing the bookmark, kernel + /// resources will be leaked and your app will lose its ability to reach outside the + /// sandbox completely, until your app is restarted. + /// + /// Start accessing a security scoped resource. With this method Electron + /// applications that are packaged for the Mac App Store may reach outside their + /// sandbox to access files chosen by the user. See Apple's documentation for a + /// description of how this system works. + /// + abstract startAccessingSecurityScopedResource: bookmarkData: string -> Function + /// + /// Updates the current activity if its type matches type, merging the entries + /// from userInfo into its current userInfo dictionary. + /// + abstract updateCurrentActivity: ``type``: string * userInfo: obj option -> unit + /// + /// fulfilled when Electron is initialized. May be used as a convenient alternative + /// to checking app.isReady() and subscribing to the ready event if the app is + /// not ready yet. + /// + abstract whenReady: unit -> Promise + /// + /// A Boolean property that's true if Chrome's accessibility support is enabled, + /// false otherwise. This property will be true if the use of assistive + /// technologies, such as screen readers, has been detected. Setting this property + /// to true manually enables Chrome's accessibility support, allowing developers + /// to expose accessibility switch to users in application settings. + /// + /// See Chromium's accessibility docs for more details. Disabled by default. + /// + /// This API must be called after the ready event is emitted. + /// + /// **Note:** Rendering accessibility tree can significantly affect the performance + /// of your app. It should not be enabled by default. + /// + abstract accessibilitySupportEnabled: bool with get, set + /// + /// A Menu | null property that returns Menu if one has been set and null + /// otherwise. Users can pass a Menu to set this property. + /// + abstract applicationMenu: Menu option with get, set + /// + /// An Integer property that returns the badge count for current app. Setting the + /// count to 0 will hide the badge. + /// + /// On macOS, setting this with any nonzero integer shows on the dock icon. On + /// Linux, this property only works for Unity launcher. + /// + /// **Note:** Unity launcher requires a .desktop file to work. For more + /// information, please read the Unity integration documentation. + /// + /// **Note:** On macOS, you need to ensure that your application has the permission + /// to display notifications for this property to take effect. + /// + abstract badgeCount: float with get, set + /// + /// A CommandLine object that allows you to read and manipulate the command line + /// arguments that Chromium uses. + /// + abstract commandLine: CommandLine + /// + /// A Dock | undefined object that allows you to perform actions on your app + /// icon in the user's dock on macOS. + /// + abstract dock: Dock + /// + /// A Boolean property that returns true if the app is packaged, false + /// otherwise. For many apps, this property can be used to distinguish development + /// and production environments. + /// + abstract isPackaged: bool + /// + /// A String property that indicates the current application's name, which is the + /// name in the application's package.json file. + /// + /// Usually the name field of package.json is a short lowercase name, according + /// to the npm modules spec. You should usually also specify a productName field, + /// which is your application's full capitalized name, and which will be preferred + /// over name by Electron. + /// + abstract name: string with get, set + /// + /// A Boolean which when true indicates that the app is currently running under + /// the Rosetta Translator Environment. + /// + /// You can use this property to prompt users to download the arm64 version of your + /// application when they are running the x64 version under Rosetta incorrectly. + /// + abstract runningUnderRosettaTranslation: bool + /// + /// A String which is the user agent string Electron will use as a global + /// fallback. + /// + /// This is the user agent that will be used when no user agent is set at the + /// webContents or session level. It is useful for ensuring that your entire + /// app has the same user agent. Set to a custom value as early as possible in your + /// app's initialization to ensure that your overridden value is used. + /// + abstract userAgentFallback: string with get, set + + type [] AutoUpdater = + inherit NodeJS.EventEmitter + /// + /// This event is emitted after a user calls quitAndInstall(). + /// + /// When this API is called, the before-quit event is not emitted before all + /// windows are closed. As a result you should listen to this event if you wish to + /// perform actions before the windows are closed while a process is quitting, as + /// well as listening to before-quit. + /// + [] abstract ``on_before-quit-for-update``: listener: Function -> AutoUpdater + [] abstract ``once_before-quit-for-update``: listener: Function -> AutoUpdater + [] abstract ``addListener_before-quit-for-update``: listener: Function -> AutoUpdater + [] abstract ``removeListener_before-quit-for-update``: listener: Function -> AutoUpdater + /// Emitted when checking if an update has started. + [] abstract ``on_checking-for-update``: listener: Function -> AutoUpdater + [] abstract ``once_checking-for-update``: listener: Function -> AutoUpdater + [] abstract ``addListener_checking-for-update``: listener: Function -> AutoUpdater + [] abstract ``removeListener_checking-for-update``: listener: Function -> AutoUpdater + /// Emitted when there is an error while updating. + [] abstract on_error: listener: (ExceptError -> unit) -> AutoUpdater + [] abstract once_error: listener: (ExceptError -> unit) -> AutoUpdater + [] abstract addListener_error: listener: (ExceptError -> unit) -> AutoUpdater + [] abstract removeListener_error: listener: (ExceptError -> unit) -> AutoUpdater + /// Emitted when there is an available update. The update is downloaded + /// automatically. + [] abstract ``on_update-available``: listener: Function -> AutoUpdater + [] abstract ``once_update-available``: listener: Function -> AutoUpdater + [] abstract ``addListener_update-available``: listener: Function -> AutoUpdater + [] abstract ``removeListener_update-available``: listener: Function -> AutoUpdater + /// + /// Emitted when an update has been downloaded. + /// + /// On Windows only releaseName is available. + /// + /// **Note:** It is not strictly necessary to handle this event. A successfully + /// downloaded update will still be applied the next time the application starts. + /// + [] abstract ``on_update-downloaded``: listener: (Event -> string -> string -> DateTime -> string -> unit) -> AutoUpdater + [] abstract ``once_update-downloaded``: listener: (Event -> string -> string -> DateTime -> string -> unit) -> AutoUpdater + [] abstract ``addListener_update-downloaded``: listener: (Event -> string -> string -> DateTime -> string -> unit) -> AutoUpdater + [] abstract ``removeListener_update-downloaded``: listener: (Event -> string -> string -> DateTime -> string -> unit) -> AutoUpdater + /// Emitted when there is no available update. + [] abstract ``on_update-not-available``: listener: Function -> AutoUpdater + [] abstract ``once_update-not-available``: listener: Function -> AutoUpdater + [] abstract ``addListener_update-not-available``: listener: Function -> AutoUpdater + [] abstract ``removeListener_update-not-available``: listener: Function -> AutoUpdater + /// + /// Asks the server whether there is an update. You must call setFeedURL before + /// using this API. + /// + /// **Note:** If an update is available it will be downloaded automatically. Calling + /// autoUpdater.checkForUpdates() twice will download the update two times. + /// + abstract checkForUpdates: unit -> unit + /// The current update feed URL. + abstract getFeedURL: unit -> string + /// + /// Restarts the app and installs the update after it has been downloaded. It should + /// only be called after update-downloaded has been emitted. + /// + /// Under the hood calling autoUpdater.quitAndInstall() will close all application + /// windows first, and automatically call app.quit() after all windows have been + /// closed. + /// + /// **Note:** It is not strictly necessary to call this function to apply an update, + /// as a successfully downloaded update will always be applied the next time the + /// application starts. + /// + abstract quitAndInstall: unit -> unit + /// Sets the url and initialize the auto updater. + abstract setFeedURL: options: FeedURLOptions -> unit + + type [] BluetoothDevice = + abstract deviceId: string with get, set + abstract deviceName: string with get, set + + type [] BrowserView = + /// The bounds of this BrowserView instance as Object. + abstract getBounds: unit -> Rectangle + abstract setAutoResize: options: AutoResizeOptions -> unit + abstract setBackgroundColor: color: string -> unit + /// Resizes and moves the view to the supplied bounds relative to the window. + abstract setBounds: bounds: Rectangle -> unit + /// A WebContents object owned by this view. + abstract webContents: WebContents with get, set + + type [] BrowserViewStatic = + /// BrowserView + [] abstract Create: ?options: BrowserViewConstructorOptions -> BrowserView + + type [] BrowserWindow = + inherit NodeEventEmitter + /// Emitted when the window is set or unset to show always on top of other windows. + [] abstract ``on_always-on-top-changed``: listener: (Event -> bool -> unit) -> BrowserWindow + [] abstract ``once_always-on-top-changed``: listener: (Event -> bool -> unit) -> BrowserWindow + [] abstract ``addListener_always-on-top-changed``: listener: (Event -> bool -> unit) -> BrowserWindow + [] abstract ``removeListener_always-on-top-changed``: listener: (Event -> bool -> unit) -> BrowserWindow + /// + /// Emitted when an App Command is invoked. These are typically related to keyboard + /// media keys or browser commands, as well as the "Back" button built into some + /// mice on Windows. + /// + /// Commands are lowercased, underscores are replaced with hyphens, and the + /// APPCOMMAND_ prefix is stripped off. e.g. APPCOMMAND_BROWSER_BACKWARD is + /// emitted as browser-backward. + /// + /// The following app commands are explicitly supported on Linux: + /// + /// * browser-backward + /// * browser-forward + /// + [] abstract ``on_app-command``: listener: (Event -> string -> unit) -> BrowserWindow + [] abstract ``once_app-command``: listener: (Event -> string -> unit) -> BrowserWindow + [] abstract ``addListener_app-command``: listener: (Event -> string -> unit) -> BrowserWindow + [] abstract ``removeListener_app-command``: listener: (Event -> string -> unit) -> BrowserWindow + /// Emitted when the window loses focus. + [] abstract on_blur: listener: Function -> BrowserWindow + [] abstract once_blur: listener: Function -> BrowserWindow + [] abstract addListener_blur: listener: Function -> BrowserWindow + [] abstract removeListener_blur: listener: Function -> BrowserWindow + /// + /// Emitted when the window is going to be closed. It's emitted before the + /// beforeunload and unload event of the DOM. Calling event.preventDefault() + /// will cancel the close. + /// + /// Usually you would want to use the beforeunload handler to decide whether the + /// window should be closed, which will also be called when the window is reloaded. + /// In Electron, returning any value other than undefined would cancel the close. + /// For example: + /// + /// _**Note**: There is a subtle difference between the behaviors of + /// window.onbeforeunload = handler and `window.addEventListener('beforeunload', + /// handler). It is recommended to always set the event.returnValue` explicitly, + /// instead of only returning a value, as the former works more consistently within + /// Electron._ + /// + [] abstract on_close: listener: (Event -> unit) -> BrowserWindow + [] abstract once_close: listener: (Event -> unit) -> BrowserWindow + [] abstract addListener_close: listener: (Event -> unit) -> BrowserWindow + [] abstract removeListener_close: listener: (Event -> unit) -> BrowserWindow + /// Emitted when the window is closed. After you have received this event you should + /// remove the reference to the window and avoid using it any more. + [] abstract on_closed: listener: Function -> BrowserWindow + [] abstract once_closed: listener: Function -> BrowserWindow + [] abstract addListener_closed: listener: Function -> BrowserWindow + [] abstract removeListener_closed: listener: Function -> BrowserWindow + /// Emitted when the window enters a full-screen state. + [] abstract ``on_enter-full-screen``: listener: Function -> BrowserWindow + [] abstract ``once_enter-full-screen``: listener: Function -> BrowserWindow + [] abstract ``addListener_enter-full-screen``: listener: Function -> BrowserWindow + [] abstract ``removeListener_enter-full-screen``: listener: Function -> BrowserWindow + /// Emitted when the window enters a full-screen state triggered by HTML API. + [] abstract ``on_enter-html-full-screen``: listener: Function -> BrowserWindow + [] abstract ``once_enter-html-full-screen``: listener: Function -> BrowserWindow + [] abstract ``addListener_enter-html-full-screen``: listener: Function -> BrowserWindow + [] abstract ``removeListener_enter-html-full-screen``: listener: Function -> BrowserWindow + /// Emitted when the window gains focus. + [] abstract on_focus: listener: Function -> BrowserWindow + [] abstract once_focus: listener: Function -> BrowserWindow + [] abstract addListener_focus: listener: Function -> BrowserWindow + [] abstract removeListener_focus: listener: Function -> BrowserWindow + /// Emitted when the window is hidden. + [] abstract on_hide: listener: Function -> BrowserWindow + [] abstract once_hide: listener: Function -> BrowserWindow + [] abstract addListener_hide: listener: Function -> BrowserWindow + [] abstract removeListener_hide: listener: Function -> BrowserWindow + /// Emitted when the window leaves a full-screen state. + [] abstract ``on_leave-full-screen``: listener: Function -> BrowserWindow + [] abstract ``once_leave-full-screen``: listener: Function -> BrowserWindow + [] abstract ``addListener_leave-full-screen``: listener: Function -> BrowserWindow + [] abstract ``removeListener_leave-full-screen``: listener: Function -> BrowserWindow + /// Emitted when the window leaves a full-screen state triggered by HTML API. + [] abstract ``on_leave-html-full-screen``: listener: Function -> BrowserWindow + [] abstract ``once_leave-html-full-screen``: listener: Function -> BrowserWindow + [] abstract ``addListener_leave-html-full-screen``: listener: Function -> BrowserWindow + [] abstract ``removeListener_leave-html-full-screen``: listener: Function -> BrowserWindow + /// Emitted when window is maximized. + [] abstract on_maximize: listener: Function -> BrowserWindow + [] abstract once_maximize: listener: Function -> BrowserWindow + [] abstract addListener_maximize: listener: Function -> BrowserWindow + [] abstract removeListener_maximize: listener: Function -> BrowserWindow + /// Emitted when the window is minimized. + [] abstract on_minimize: listener: Function -> BrowserWindow + [] abstract once_minimize: listener: Function -> BrowserWindow + [] abstract addListener_minimize: listener: Function -> BrowserWindow + [] abstract removeListener_minimize: listener: Function -> BrowserWindow + /// Emitted when the window is being moved to a new position. + [] abstract on_move: listener: Function -> BrowserWindow + [] abstract once_move: listener: Function -> BrowserWindow + [] abstract addListener_move: listener: Function -> BrowserWindow + [] abstract removeListener_move: listener: Function -> BrowserWindow + /// + /// Emitted once when the window is moved to a new position. + /// + /// __Note__: On macOS this event is an alias of move. + /// + [] abstract on_moved: listener: Function -> BrowserWindow + [] abstract once_moved: listener: Function -> BrowserWindow + [] abstract addListener_moved: listener: Function -> BrowserWindow + [] abstract removeListener_moved: listener: Function -> BrowserWindow + /// Emitted when the native new tab button is clicked. + [] abstract ``on_new-window-for-tab``: listener: Function -> BrowserWindow + [] abstract ``once_new-window-for-tab``: listener: Function -> BrowserWindow + [] abstract ``addListener_new-window-for-tab``: listener: Function -> BrowserWindow + [] abstract ``removeListener_new-window-for-tab``: listener: Function -> BrowserWindow + /// + /// Emitted when the document changed its title, calling event.preventDefault() + /// will prevent the native window's title from changing. explicitSet is false + /// when title is synthesized from file URL. + /// + [] abstract ``on_page-title-updated``: listener: (Event -> string -> bool -> unit) -> BrowserWindow + [] abstract ``once_page-title-updated``: listener: (Event -> string -> bool -> unit) -> BrowserWindow + [] abstract ``addListener_page-title-updated``: listener: (Event -> string -> bool -> unit) -> BrowserWindow + [] abstract ``removeListener_page-title-updated``: listener: (Event -> string -> bool -> unit) -> BrowserWindow + /// + /// Emitted when the web page has been rendered (while not being shown) and window + /// can be displayed without a visual flash. + /// + /// Please note that using this event implies that the renderer will be considered + /// "visible" and paint even though show is false. This event will never fire if + /// you use paintWhenInitiallyHidden: false + /// + [] abstract ``on_ready-to-show``: listener: Function -> BrowserWindow + [] abstract ``once_ready-to-show``: listener: Function -> BrowserWindow + [] abstract ``addListener_ready-to-show``: listener: Function -> BrowserWindow + [] abstract ``removeListener_ready-to-show``: listener: Function -> BrowserWindow + /// Emitted after the window has been resized. + [] abstract on_resize: listener: Function -> BrowserWindow + [] abstract once_resize: listener: Function -> BrowserWindow + [] abstract addListener_resize: listener: Function -> BrowserWindow + [] abstract removeListener_resize: listener: Function -> BrowserWindow + /// + /// Emitted once when the window has finished being resized. + /// + /// This is usually emitted when the window has been resized manually. On macOS, + /// resizing the window with setBounds/setSize and setting the animate + /// parameter to true will also emit this event once resizing has finished. + /// + [] abstract on_resized: listener: Function -> BrowserWindow + [] abstract once_resized: listener: Function -> BrowserWindow + [] abstract addListener_resized: listener: Function -> BrowserWindow + [] abstract removeListener_resized: listener: Function -> BrowserWindow + /// Emitted when the unresponsive web page becomes responsive again. + [] abstract on_responsive: listener: Function -> BrowserWindow + [] abstract once_responsive: listener: Function -> BrowserWindow + [] abstract addListener_responsive: listener: Function -> BrowserWindow + [] abstract removeListener_responsive: listener: Function -> BrowserWindow + /// Emitted when the window is restored from a minimized state. + [] abstract on_restore: listener: Function -> BrowserWindow + [] abstract once_restore: listener: Function -> BrowserWindow + [] abstract addListener_restore: listener: Function -> BrowserWindow + [] abstract removeListener_restore: listener: Function -> BrowserWindow + /// + /// Emitted on trackpad rotation gesture. Continually emitted until rotation gesture + /// is ended. The rotation value on each emission is the angle in degrees rotated + /// since the last emission. The last emitted event upon a rotation gesture will + /// always be of value 0. Counter-clockwise rotation values are positive, while + /// clockwise ones are negative. + /// + [] abstract ``on_rotate-gesture``: listener: (Event -> float -> unit) -> BrowserWindow + [] abstract ``once_rotate-gesture``: listener: (Event -> float -> unit) -> BrowserWindow + [] abstract ``addListener_rotate-gesture``: listener: (Event -> float -> unit) -> BrowserWindow + [] abstract ``removeListener_rotate-gesture``: listener: (Event -> float -> unit) -> BrowserWindow + /// Emitted when scroll wheel event phase has begun. + [] abstract ``on_scroll-touch-begin``: listener: Function -> BrowserWindow + [] abstract ``once_scroll-touch-begin``: listener: Function -> BrowserWindow + [] abstract ``addListener_scroll-touch-begin``: listener: Function -> BrowserWindow + [] abstract ``removeListener_scroll-touch-begin``: listener: Function -> BrowserWindow + /// Emitted when scroll wheel event phase filed upon reaching the edge of element. + [] abstract ``on_scroll-touch-edge``: listener: Function -> BrowserWindow + [] abstract ``once_scroll-touch-edge``: listener: Function -> BrowserWindow + [] abstract ``addListener_scroll-touch-edge``: listener: Function -> BrowserWindow + [] abstract ``removeListener_scroll-touch-edge``: listener: Function -> BrowserWindow + /// Emitted when scroll wheel event phase has ended. + [] abstract ``on_scroll-touch-end``: listener: Function -> BrowserWindow + [] abstract ``once_scroll-touch-end``: listener: Function -> BrowserWindow + [] abstract ``addListener_scroll-touch-end``: listener: Function -> BrowserWindow + [] abstract ``removeListener_scroll-touch-end``: listener: Function -> BrowserWindow + /// + /// Emitted when window session is going to end due to force shutdown or machine + /// restart or session log off. + /// + [] abstract ``on_session-end``: listener: Function -> BrowserWindow + [] abstract ``once_session-end``: listener: Function -> BrowserWindow + [] abstract ``addListener_session-end``: listener: Function -> BrowserWindow + [] abstract ``removeListener_session-end``: listener: Function -> BrowserWindow + /// Emitted when the window opens a sheet. + [] abstract ``on_sheet-begin``: listener: Function -> BrowserWindow + [] abstract ``once_sheet-begin``: listener: Function -> BrowserWindow + [] abstract ``addListener_sheet-begin``: listener: Function -> BrowserWindow + [] abstract ``removeListener_sheet-begin``: listener: Function -> BrowserWindow + /// Emitted when the window has closed a sheet. + [] abstract ``on_sheet-end``: listener: Function -> BrowserWindow + [] abstract ``once_sheet-end``: listener: Function -> BrowserWindow + [] abstract ``addListener_sheet-end``: listener: Function -> BrowserWindow + [] abstract ``removeListener_sheet-end``: listener: Function -> BrowserWindow + /// Emitted when the window is shown. + [] abstract on_show: listener: Function -> BrowserWindow + [] abstract once_show: listener: Function -> BrowserWindow + [] abstract addListener_show: listener: Function -> BrowserWindow + [] abstract removeListener_show: listener: Function -> BrowserWindow + /// + /// Emitted on 3-finger swipe. Possible directions are up, right, down, + /// left. + /// + /// The method underlying this event is built to handle older macOS-style trackpad + /// swiping, where the content on the screen doesn't move with the swipe. Most macOS + /// trackpads are not configured to allow this kind of swiping anymore, so in order + /// for it to emit properly the 'Swipe between pages' preference in `System + /// Preferences > Trackpad > More Gestures` must be set to 'Swipe with two or three + /// fingers'. + /// + [] abstract on_swipe: listener: (Event -> string -> unit) -> BrowserWindow + [] abstract once_swipe: listener: (Event -> string -> unit) -> BrowserWindow + [] abstract addListener_swipe: listener: (Event -> string -> unit) -> BrowserWindow + [] abstract removeListener_swipe: listener: (Event -> string -> unit) -> BrowserWindow + /// + /// Emitted when the system context menu is triggered on the window, this is + /// normally only triggered when the user right clicks on the non-client area of + /// your window. This is the window titlebar or any area you have declared as + /// -webkit-app-region: drag in a frameless window. + /// + /// Calling event.preventDefault() will prevent the menu from being displayed. + /// + [] abstract ``on_system-context-menu``: listener: (Event -> Point -> unit) -> BrowserWindow + [] abstract ``once_system-context-menu``: listener: (Event -> Point -> unit) -> BrowserWindow + [] abstract ``addListener_system-context-menu``: listener: (Event -> Point -> unit) -> BrowserWindow + [] abstract ``removeListener_system-context-menu``: listener: (Event -> Point -> unit) -> BrowserWindow + /// Emitted when the window exits from a maximized state. + [] abstract on_unmaximize: listener: Function -> BrowserWindow + [] abstract once_unmaximize: listener: Function -> BrowserWindow + [] abstract addListener_unmaximize: listener: Function -> BrowserWindow + [] abstract removeListener_unmaximize: listener: Function -> BrowserWindow + /// Emitted when the web page becomes unresponsive. + [] abstract on_unresponsive: listener: Function -> BrowserWindow + [] abstract once_unresponsive: listener: Function -> BrowserWindow + [] abstract addListener_unresponsive: listener: Function -> BrowserWindow + [] abstract removeListener_unresponsive: listener: Function -> BrowserWindow + /// + /// Emitted before the window is moved. On Windows, calling event.preventDefault() + /// will prevent the window from being moved. + /// + /// Note that this is only emitted when the window is being resized manually. + /// Resizing the window with setBounds/setSize will not emit this event. + /// + [] abstract ``on_will-move``: listener: (Event -> Rectangle -> unit) -> BrowserWindow + [] abstract ``once_will-move``: listener: (Event -> Rectangle -> unit) -> BrowserWindow + [] abstract ``addListener_will-move``: listener: (Event -> Rectangle -> unit) -> BrowserWindow + [] abstract ``removeListener_will-move``: listener: (Event -> Rectangle -> unit) -> BrowserWindow + /// + /// Emitted before the window is resized. Calling event.preventDefault() will + /// prevent the window from being resized. + /// + /// Note that this is only emitted when the window is being resized manually. + /// Resizing the window with setBounds/setSize will not emit this event. + /// + [] abstract ``on_will-resize``: listener: (Event -> Rectangle -> unit) -> BrowserWindow + [] abstract ``once_will-resize``: listener: (Event -> Rectangle -> unit) -> BrowserWindow + [] abstract ``addListener_will-resize``: listener: (Event -> Rectangle -> unit) -> BrowserWindow + [] abstract ``removeListener_will-resize``: listener: (Event -> Rectangle -> unit) -> BrowserWindow + /// Replacement API for setBrowserView supporting work with multi browser views. + abstract addBrowserView: browserView: BrowserView -> unit + /// Adds a window as a tab on this window, after the tab for the window instance. + abstract addTabbedWindow: browserWindow: BrowserWindow -> unit + /// Removes focus from the window. + abstract blur: unit -> unit + abstract blurWebView: unit -> unit + /// + /// Resolves with a NativeImage + /// + /// Captures a snapshot of the page within rect. Omitting rect will capture the + /// whole visible page. If the page is not visible, rect may be empty. + /// + abstract capturePage: ?rect: Rectangle -> Promise + /// Moves window to the center of the screen. + abstract center: unit -> unit + /// Try to close the window. This has the same effect as a user manually clicking + /// the close button of the window. The web page may cancel the close though. See + /// the close event. + abstract close: unit -> unit + /// Closes the currently open Quick Look panel. + abstract closeFilePreview: unit -> unit + /// + /// Force closing the window, the unload and beforeunload event won't be emitted + /// for the web page, and close event will also not be emitted for this window, + /// but it guarantees the closed event will be emitted. + /// + abstract destroy: unit -> unit + /// Starts or stops flashing the window to attract user's attention. + abstract flashFrame: flag: bool -> unit + /// Focuses on the window. + abstract focus: unit -> unit + abstract focusOnWebView: unit -> unit + /// Gets the background color of the window. See Setting backgroundColor. + abstract getBackgroundColor: unit -> string + /// The bounds of the window as Object. + abstract getBounds: unit -> Rectangle + /// + /// The BrowserView attached to win. Returns null if one is not attached. + /// Throws an error if multiple BrowserViews are attached. + /// + abstract getBrowserView: unit -> BrowserView option + /// + /// an array of all BrowserViews that have been attached with addBrowserView or + /// setBrowserView. + /// + /// **Note:** The BrowserView API is currently experimental and may change or be + /// removed in future Electron releases. + /// + abstract getBrowserViews: unit -> ResizeArray + /// All child windows. + abstract getChildWindows: unit -> ResizeArray + /// The bounds of the window's client area as Object. + abstract getContentBounds: unit -> Rectangle + /// Contains the window's client area's width and height. + abstract getContentSize: unit -> ResizeArray + /// Contains the window's maximum width and height. + abstract getMaximumSize: unit -> ResizeArray + /// + /// Window id in the format of DesktopCapturerSource's id. For example + /// "window:1324:0". + /// + /// More precisely the format is window:id:other_id where id is HWND on + /// Windows, CGWindowID (uint64_t) on macOS and Window (unsigned long) on + /// Linux. other_id is used to identify web contents (tabs) so within the same top + /// level window. + /// + abstract getMediaSourceId: unit -> string + /// Contains the window's minimum width and height. + abstract getMinimumSize: unit -> ResizeArray + /// + /// The platform-specific handle of the window. + /// + /// The native type of the handle is HWND on Windows, NSView* on macOS, and + /// Window (unsigned long) on Linux. + /// + abstract getNativeWindowHandle: unit -> Buffer + /// + /// Contains the window bounds of the normal state + /// + /// **Note:** whatever the current state of the window : maximized, minimized or in + /// fullscreen, this function always returns the position and size of the window in + /// normal state. In normal state, getBounds and getNormalBounds returns the same + /// Rectangle. + /// + abstract getNormalBounds: unit -> Rectangle + /// between 0.0 (fully transparent) and 1.0 (fully opaque). On Linux, always returns + /// 1. + abstract getOpacity: unit -> float + /// The parent window or null if there is no parent. + abstract getParentWindow: unit -> BrowserWindow option + /// Contains the window's current position. + abstract getPosition: unit -> ResizeArray + /// The pathname of the file the window represents. + abstract getRepresentedFilename: unit -> string + /// Contains the window's width and height. + abstract getSize: unit -> ResizeArray + /// The title of the native window. + /// + /// **Note:** The title of the web page can be different from the title of the + /// native window. + abstract getTitle: unit -> string + /// The custom position for the traffic light buttons in frameless window. + abstract getTrafficLightPosition: unit -> Point + /// Whether the window has a shadow. + abstract hasShadow: unit -> bool + /// Hides the window. + abstract hide: unit -> unit + /// + /// Hooks a windows message. The callback is called when the message is received + /// in the WndProc. + /// + abstract hookWindowMessage: message: float * callback: (obj option -> obj option -> unit) -> unit + /// Whether the window is always on top of other windows. + abstract isAlwaysOnTop: unit -> bool + /// + /// Whether the window can be manually closed by user. + /// + /// On Linux always returns true. + /// + abstract isClosable: unit -> bool + /// Whether the window is destroyed. + abstract isDestroyed: unit -> bool + /// Whether the window's document has been edited. + abstract isDocumentEdited: unit -> bool + /// whether the window is enabled. + abstract isEnabled: unit -> bool + /// Returns whether the window can be focused. + abstract isFocusable: unit -> unit + /// Whether the window is focused. + abstract isFocused: unit -> bool + /// Whether the window is in fullscreen mode. + abstract isFullScreen: unit -> bool + /// Whether the maximize/zoom window button toggles fullscreen mode or maximizes the + /// window. + abstract isFullScreenable: unit -> bool + /// Whether the window is in kiosk mode. + abstract isKiosk: unit -> bool + /// + /// Whether the window can be manually maximized by user. + /// + /// On Linux always returns true. + /// + abstract isMaximizable: unit -> bool + /// Whether the window is maximized. + abstract isMaximized: unit -> bool + /// Whether menu bar automatically hides itself. + abstract isMenuBarAutoHide: unit -> bool + /// Whether the menu bar is visible. + abstract isMenuBarVisible: unit -> bool + /// + /// Whether the window can be manually minimized by the user. + /// + /// On Linux always returns true. + /// + abstract isMinimizable: unit -> bool + /// Whether the window is minimized. + abstract isMinimized: unit -> bool + /// Whether current window is a modal window. + abstract isModal: unit -> bool + /// + /// Whether the window can be moved by user. + /// + /// On Linux always returns true. + /// + abstract isMovable: unit -> bool + /// Whether the window is in normal state (not maximized, not minimized, not in + /// fullscreen mode). + abstract isNormal: unit -> bool + /// Whether the window can be manually resized by the user. + abstract isResizable: unit -> bool + /// Whether the window is in simple (pre-Lion) fullscreen mode. + abstract isSimpleFullScreen: unit -> bool + /// + /// Whether the window is in Windows 10 tablet mode. + /// + /// Since Windows 10 users can use their PC as tablet, under this mode apps can + /// choose to optimize their UI for tablets, such as enlarging the titlebar and + /// hiding titlebar buttons. + /// + /// This API returns whether the window is in tablet mode, and the resize event + /// can be be used to listen to changes to tablet mode. + /// + abstract isTabletMode: unit -> bool + /// Whether the window is visible to the user. + abstract isVisible: unit -> bool + /// Whether the window is visible on all workspaces. + /// + /// **Note:** This API always returns false on Windows. + abstract isVisibleOnAllWorkspaces: unit -> bool + /// true or false depending on whether the message is hooked. + abstract isWindowMessageHooked: message: float -> bool + /// + /// the promise will resolve when the page has finished loading (see + /// did-finish-load), and rejects if the page fails to load (see did-fail-load). + /// + /// Same as webContents.loadFile, filePath should be a path to an HTML file + /// relative to the root of your application. See the webContents docs for more + /// information. + /// + abstract loadFile: filePath: string * ?options: LoadFileOptions -> Promise + /// + /// the promise will resolve when the page has finished loading (see + /// did-finish-load), and rejects if the page fails to load (see did-fail-load). + /// + /// Same as webContents.loadURL(url[, options]). + /// + /// The url can be a remote address (e.g. http://) or a path to a local HTML + /// file using the file:// protocol. + /// + /// To ensure that file URLs are properly formatted, it is recommended to use Node's + /// url.format method: + /// + /// You can load a URL using a POST request with URL-encoded data by doing the + /// following: + /// + abstract loadURL: url: string * ?options: LoadURLOptions -> Promise + /// Maximizes the window. This will also show (but not focus) the window if it isn't + /// being displayed already. + abstract maximize: unit -> unit + /// + /// Merges all windows into one window with multiple tabs when native tabs are + /// enabled and there is more than one open window. + /// + abstract mergeAllWindows: unit -> unit + /// Minimizes the window. On some platforms the minimized window will be shown in + /// the Dock. + abstract minimize: unit -> unit + /// + /// Moves window above the source window in the sense of z-order. If the + /// mediaSourceId is not of type window or if the window does not exist then this + /// method throws an error. + /// + abstract moveAbove: mediaSourceId: string -> unit + /// + /// Moves the current tab into a new window if native tabs are enabled and there is + /// more than one tab in the current window. + /// + abstract moveTabToNewWindow: unit -> unit + /// Moves window to top(z-order) regardless of focus + abstract moveTop: unit -> unit + /// Uses Quick Look to preview a file at a given path. + abstract previewFile: path: string * ?displayName: string -> unit + /// Same as webContents.reload. + abstract reload: unit -> unit + abstract removeBrowserView: browserView: BrowserView -> unit + /// Remove the window's menu bar. + abstract removeMenu: unit -> unit + /// Restores the window from minimized state to its previous state. + abstract restore: unit -> unit + /// + /// Selects the next tab when native tabs are enabled and there are other tabs in + /// the window. + /// + abstract selectNextTab: unit -> unit + /// + /// Selects the previous tab when native tabs are enabled and there are other tabs + /// in the window. + /// + abstract selectPreviousTab: unit -> unit + /// Sets whether the window should show always on top of other windows. After + /// setting this, the window is still a normal window, not a toolbox window which + /// can not be focused on. + abstract setAlwaysOnTop: flag: bool * ?level: BrowserWindowSetAlwaysOnTop * ?relativeLevel: float -> unit + /// + /// Sets the properties for the window's taskbar button. + /// + /// **Note:** relaunchCommand and relaunchDisplayName must always be set + /// together. If one of those properties is not set, then neither will be used. + /// + abstract setAppDetails: options: AppDetailsOptions -> unit + /// + /// This will make a window maintain an aspect ratio. The extra size allows a + /// developer to have space, specified in pixels, not included within the aspect + /// ratio calculations. This API already takes into account the difference between a + /// window's size and its content size. + /// + /// Consider a normal window with an HD video player and associated controls. + /// Perhaps there are 15 pixels of controls on the left edge, 25 pixels of controls + /// on the right edge and 50 pixels of controls below the player. In order to + /// maintain a 16:9 aspect ratio (standard aspect ratio for HD @1920x1080) within + /// the player itself we would call this function with arguments of 16/9 and { + /// width: 40, height: 50 }. The second argument doesn't care where the extra width + /// and height are within the content view--only that they exist. Sum any extra + /// width and height areas you have within the overall content view. + /// + /// The aspect ratio is not respected when window is resized programmatically with + /// APIs like win.setSize. + /// + abstract setAspectRatio: aspectRatio: float * ?extraSize: Size -> unit + /// Controls whether to hide cursor when typing. + abstract setAutoHideCursor: autoHide: bool -> unit + /// + /// Sets whether the window menu bar should hide itself automatically. Once set the + /// menu bar will only show when users press the single Alt key. + /// + /// If the menu bar is already visible, calling setAutoHideMenuBar(true) won't + /// hide it immediately. + /// + abstract setAutoHideMenuBar: hide: bool -> unit + /// Sets the background color of the window. See Setting backgroundColor. + abstract setBackgroundColor: backgroundColor: string -> unit + /// Resizes and moves the window to the supplied bounds. Any properties that are not + /// supplied will default to their current values. + abstract setBounds: bounds: obj * ?animate: bool -> unit + abstract setBrowserView: browserView: BrowserView option -> unit + /// Sets whether the window can be manually closed by user. On Linux does nothing. + abstract setClosable: closable: bool -> unit + /// Resizes and moves the window's client area (e.g. the web page) to the supplied + /// bounds. + abstract setContentBounds: bounds: Rectangle * ?animate: bool -> unit + /// + /// Prevents the window contents from being captured by other apps. + /// + /// On macOS it sets the NSWindow's sharingType to NSWindowSharingNone. On Windows + /// it calls SetWindowDisplayAffinity with WDA_EXCLUDEFROMCAPTURE. For Windows 10 + /// version 2004 and up the window will be removed from capture entirely, older + /// Windows versions behave as if WDA_MONITOR is applied capturing a black window. + /// + abstract setContentProtection: enable: bool -> unit + /// Resizes the window's client area (e.g. the web page) to width and height. + abstract setContentSize: width: float * height: float * ?animate: bool -> unit + /// + /// Specifies whether the window’s document has been edited, and the icon in title + /// bar will become gray when set to true. + /// + abstract setDocumentEdited: edited: bool -> unit + /// Disable or enable the window. + abstract setEnabled: enable: bool -> unit + /// + /// Changes whether the window can be focused. + /// + /// On macOS it does not remove the focus from the window. + /// + abstract setFocusable: focusable: bool -> unit + /// Sets whether the window should be in fullscreen mode. + abstract setFullScreen: flag: bool -> unit + /// Sets whether the maximize/zoom window button toggles fullscreen mode or + /// maximizes the window. + abstract setFullScreenable: fullscreenable: bool -> unit + /// Sets whether the window should have a shadow. + abstract setHasShadow: hasShadow: bool -> unit + /// Changes window icon. + abstract setIcon: icon: U2 -> unit + /// Makes the window ignore all mouse events. + /// + /// All mouse events happened in this window will be passed to the window below this + /// window, but if this window has focus, it will still receive keyboard events. + abstract setIgnoreMouseEvents: ignore: bool * ?options: IgnoreMouseEventsOptions -> unit + /// Enters or leaves kiosk mode. + abstract setKiosk: flag: bool -> unit + /// + /// Sets whether the window can be manually maximized by user. On Linux does + /// nothing. + /// + abstract setMaximizable: maximizable: bool -> unit + /// Sets the maximum size of window to width and height. + abstract setMaximumSize: width: float * height: float -> unit + /// Sets the menu as the window's menu bar. + abstract setMenu: menu: Menu option -> unit + /// + /// Sets whether the menu bar should be visible. If the menu bar is auto-hide, users + /// can still bring up the menu bar by pressing the single Alt key. + /// + abstract setMenuBarVisibility: visible: bool -> unit + /// + /// Sets whether the window can be manually minimized by user. On Linux does + /// nothing. + /// + abstract setMinimizable: minimizable: bool -> unit + /// Sets the minimum size of window to width and height. + abstract setMinimumSize: width: float * height: float -> unit + /// Sets whether the window can be moved by user. On Linux does nothing. + abstract setMovable: movable: bool -> unit + /// + /// Sets the opacity of the window. On Linux, does nothing. Out of bound number + /// values are clamped to the [0, 1] range. + /// + abstract setOpacity: opacity: float -> unit + /// + /// Sets a 16 x 16 pixel overlay onto the current taskbar icon, usually used to + /// convey some sort of application status or to passively notify the user. + /// + abstract setOverlayIcon: overlay: NativeImage option * description: string -> unit + /// + /// Sets parent as current window's parent window, passing null will turn + /// current window into a top-level window. + /// + abstract setParentWindow: parent: BrowserWindow option -> unit + /// Moves window to x and y. + abstract setPosition: x: float * y: float * ?animate: bool -> unit + /// + /// Sets progress value in progress bar. Valid range is [0, 1.0]. + /// + /// Remove progress bar when progress < 0; Change to indeterminate mode when + /// progress > 1. + /// + /// On Linux platform, only supports Unity desktop environment, you need to specify + /// the *.desktop file name to desktopName field in package.json. By default, + /// it will assume {app.name}.desktop. + /// + /// On Windows, a mode can be passed. Accepted values are none, normal, + /// indeterminate, error, and paused. If you call setProgressBar without a + /// mode set (but with a value within the valid range), normal will be assumed. + /// + abstract setProgressBar: progress: float * ?options: ProgressBarOptions -> unit + /// + /// Sets the pathname of the file the window represents, and the icon of the file + /// will show in window's title bar. + /// + abstract setRepresentedFilename: filename: string -> unit + /// Sets whether the window can be manually resized by the user. + abstract setResizable: resizable: bool -> unit + /// + /// Setting a window shape determines the area within the window where the system + /// permits drawing and user interaction. Outside of the given region, no pixels + /// will be drawn and no mouse events will be registered. Mouse events outside of + /// the region will not be received by that window, but will fall through to + /// whatever is behind the window. + /// + abstract setShape: rects: ResizeArray -> unit + /// + /// Changes the attachment point for sheets on macOS. By default, sheets are + /// attached just below the window frame, but you may want to display them beneath a + /// HTML-rendered toolbar. For example: + /// + abstract setSheetOffset: offsetY: float * ?offsetX: float -> unit + /// + /// Enters or leaves simple fullscreen mode. + /// + /// Simple fullscreen mode emulates the native fullscreen behavior found in versions + /// of macOS prior to Lion (10.7). + /// + abstract setSimpleFullScreen: flag: bool -> unit + /// + /// Resizes the window to width and height. If width or height are below any + /// set minimum size constraints the window will snap to its minimum size. + /// + abstract setSize: width: float * height: float * ?animate: bool -> unit + /// Makes the window not show in the taskbar. + abstract setSkipTaskbar: skip: bool -> unit + /// + /// Whether the buttons were added successfully + /// + /// Add a thumbnail toolbar with a specified set of buttons to the thumbnail image + /// of a window in a taskbar button layout. Returns a Boolean object indicates + /// whether the thumbnail has been added successfully. + /// + /// The number of buttons in thumbnail toolbar should be no greater than 7 due to + /// the limited room. Once you setup the thumbnail toolbar, the toolbar cannot be + /// removed due to the platform's limitation. But you can call the API with an empty + /// array to clean the buttons. + /// + /// The buttons is an array of Button objects: + /// + /// * Button Object + /// * icon NativeImage - The icon showing in thumbnail toolbar. + /// * click Function + /// * tooltip String (optional) - The text of the button's tooltip. + /// * flags String[] (optional) - Control specific states and behaviors of the + /// button. By default, it is ['enabled']. + /// + /// The flags is an array that can include following Strings: + /// + /// * enabled - The button is active and available to the user. + /// * disabled - The button is disabled. It is present, but has a visual state + /// indicating it will not respond to user action. + /// * dismissonclick - When the button is clicked, the thumbnail window closes + /// immediately. + /// * nobackground - Do not draw a button border, use only the image. + /// * hidden - The button is not shown to the user. + /// * noninteractive - The button is enabled but not interactive; no pressed + /// button state is drawn. This value is intended for instances where the button is + /// used in a notification. + /// + abstract setThumbarButtons: buttons: ResizeArray -> bool + /// + /// Sets the region of the window to show as the thumbnail image displayed when + /// hovering over the window in the taskbar. You can reset the thumbnail to be the + /// entire window by specifying an empty region: `{ x: 0, y: 0, width: 0, height: 0 + /// }`. + /// + abstract setThumbnailClip: region: Rectangle -> unit + /// + /// Sets the toolTip that is displayed when hovering over the window thumbnail in + /// the taskbar. + /// + abstract setThumbnailToolTip: toolTip: string -> unit + /// Changes the title of native window to title. + abstract setTitle: title: string -> unit + /// + /// Raises browserView above other BrowserViews attached to win. Throws an + /// error if browserView is not attached to win. + /// + abstract setTopBrowserView: browserView: BrowserView -> unit + /// + /// Sets the touchBar layout for the current window. Specifying null or + /// undefined clears the touch bar. This method only has an effect if the machine + /// has a touch bar and is running on macOS 10.12.1+. + /// + /// **Note:** The TouchBar API is currently experimental and may change or be + /// removed in future Electron releases. + /// + abstract setTouchBar: touchBar: TouchBar option -> unit + /// Set a custom position for the traffic light buttons in frameless window. + abstract setTrafficLightPosition: position: Point -> unit + /// + /// Adds a vibrancy effect to the browser window. Passing null or an empty string + /// will remove the vibrancy effect on the window. + /// + /// Note that appearance-based, light, dark, medium-light, and ultra-dark + /// have been deprecated and will be removed in an upcoming version of macOS. + /// + abstract setVibrancy: ``type``: BrowserWindowSetVibrancy option -> unit + /// Sets whether the window should be visible on all workspaces. + /// + /// **Note:** This API does nothing on Windows. + abstract setVisibleOnAllWorkspaces: visible: bool * ?options: VisibleOnAllWorkspacesOptions -> unit + /// Sets whether the window traffic light buttons should be visible. + abstract setWindowButtonVisibility: visible: bool -> unit + /// Shows and gives focus to the window. + abstract show: unit -> unit + /// Same as webContents.showDefinitionForSelection(). + abstract showDefinitionForSelection: unit -> unit + /// Shows the window but doesn't focus on it. + abstract showInactive: unit -> unit + /// + /// Toggles the visibility of the tab bar if native tabs are enabled and there is + /// only one tab in the current window. + /// + abstract toggleTabBar: unit -> unit + /// Unhooks all of the window messages. + abstract unhookAllWindowMessages: unit -> unit + /// Unhook the window message. + abstract unhookWindowMessage: message: float -> unit + /// Unmaximizes the window. + abstract unmaximize: unit -> unit + /// + /// A String property that defines an alternative title provided only to + /// accessibility tools such as screen readers. This string is not directly visible + /// to users. + /// + abstract accessibleTitle: string with get, set + /// + /// A Boolean property that determines whether the window menu bar should hide + /// itself automatically. Once set, the menu bar will only show when users press the + /// single Alt key. + /// + /// If the menu bar is already visible, setting this property to true won't hide + /// it immediately. + /// + abstract autoHideMenuBar: bool with get, set + /// + /// A Boolean property that determines whether the window can be manually closed + /// by user. + /// + /// On Linux the setter is a no-op, although the getter returns true. + /// + abstract closable: bool with get, set + /// + /// A Boolean property that specifies whether the window’s document has been + /// edited. + /// + /// The icon in title bar will become gray when set to true. + /// + abstract documentEdited: bool with get, set + /// + /// A Boolean property that determines whether the window is excluded from the + /// application’s Windows menu. false by default. + /// + abstract excludedFromShownWindowsMenu: bool with get, set + /// A Boolean property that determines whether the window is focusable. + abstract focusable: bool with get, set + /// A Boolean property that determines whether the window is in fullscreen mode. + abstract fullScreen: bool with get, set + /// + /// A Boolean property that determines whether the maximize/zoom window button + /// toggles fullscreen mode or maximizes the window. + /// + abstract fullScreenable: bool with get, set + /// + /// A Integer property representing the unique ID of the window. Each ID is unique + /// among all BrowserWindow instances of the entire Electron application. + /// + abstract id: float + /// A Boolean property that determines whether the window is in kiosk mode. + abstract kiosk: bool with get, set + /// + /// A Boolean property that determines whether the window can be manually + /// maximized by user. + /// + /// On Linux the setter is a no-op, although the getter returns true. + /// + abstract maximizable: bool with get, set + /// + /// A Boolean property that determines whether the menu bar should be visible. + /// + /// **Note:** If the menu bar is auto-hide, users can still bring up the menu bar by + /// pressing the single Alt key. + /// + abstract menuBarVisible: bool with get, set + /// + /// A Boolean property that determines whether the window can be manually + /// minimized by user. + /// + /// On Linux the setter is a no-op, although the getter returns true. + /// + abstract minimizable: bool with get, set + /// + /// A Boolean property that determines Whether the window can be moved by user. + /// + /// On Linux the setter is a no-op, although the getter returns true. + /// + abstract movable: bool with get, set + /// + /// A String property that determines the pathname of the file the window + /// represents, and the icon of the file will show in window's title bar. + /// + abstract representedFilename: string with get, set + /// + /// A Boolean property that determines whether the window can be manually resized + /// by user. + /// + abstract resizable: bool with get, set + /// A Boolean property that determines whether the window has a shadow. + abstract shadow: bool with get, set + /// + /// A Boolean property that determines whether the window is in simple (pre-Lion) + /// fullscreen mode. + /// + abstract simpleFullScreen: bool with get, set + /// + /// A String property that determines the title of the native window. + /// + /// **Note:** The title of the web page can be different from the title of the + /// native window. + /// + abstract title: string with get, set + /// + /// A Boolean property that determines whether the window is visible on all + /// workspaces. + /// + /// **Note:** Always returns false on Windows. + /// + abstract visibleOnAllWorkspaces: bool with get, set + /// + /// A WebContents object this window owns. All web page related events and + /// operations will be done via it. + /// + /// See the webContents documentation for its methods and events. + /// + abstract webContents: WebContents + + type [] BrowserWindowStatic = + /// BrowserWindow + [] abstract Create: ?options: BrowserWindowConstructorOptions -> BrowserWindow + /// + /// The window that owns the given browserView. If the given view is not attached + /// to any window, returns null. + /// + abstract fromBrowserView: browserView: BrowserView -> BrowserWindow option + /// The window with the given id. + abstract fromId: id: float -> BrowserWindow option + /// + /// The window that owns the given webContents or null if the contents are not + /// owned by a window. + /// + abstract fromWebContents: webContents: WebContents -> BrowserWindow option + /// An array of all opened browser windows. + abstract getAllWindows: unit -> ResizeArray + /// The window that is focused in this application, otherwise returns null. + abstract getFocusedWindow: unit -> BrowserWindow option + + type [] BrowserWindowProxy = + /// Removes focus from the child window. + abstract blur: unit -> unit + /// Forcefully closes the child window without calling its unload event. + abstract close: unit -> unit + /// Evaluates the code in the child window. + abstract eval: code: string -> unit + /// Focuses the child window (brings the window to front). + abstract focus: unit -> unit + /// + /// Sends a message to the child window with the specified origin or * for no + /// origin preference. + /// + /// In addition to these methods, the child window implements window.opener object + /// with no properties and a single method. + /// + abstract postMessage: message: obj option * targetOrigin: string -> unit + /// Invokes the print dialog on the child window. + abstract print: unit -> unit + /// A Boolean that is set to true after the child window gets closed. + abstract closed: bool with get, set + + type [] BrowserWindowProxyStatic = + [] abstract Create: unit -> BrowserWindowProxy + + type [] Certificate = + /// PEM encoded data + abstract data: string with get, set + /// Fingerprint of the certificate + abstract fingerprint: string with get, set + /// Issuer principal + abstract issuer: CertificatePrincipal with get, set + /// Issuer certificate (if not self-signed) + abstract issuerCert: Certificate with get, set + /// Issuer's Common Name + abstract issuerName: string with get, set + /// Hex value represented string + abstract serialNumber: string with get, set + /// Subject principal + abstract subject: CertificatePrincipal with get, set + /// Subject's Common Name + abstract subjectName: string with get, set + /// End date of the certificate being valid in seconds + abstract validExpiry: float with get, set + /// Start date of the certificate being valid in seconds + abstract validStart: float with get, set + + type [] CertificatePrincipal = + /// Common Name. + abstract commonName: string with get, set + /// Country or region. + abstract country: string with get, set + /// Locality. + abstract locality: string with get, set + /// Organization names. + abstract organizations: ResizeArray with get, set + /// Organization Unit names. + abstract organizationUnits: ResizeArray with get, set + /// State or province. + abstract state: string with get, set + + type [] ClientRequest = + inherit NodeEventEmitter + /// + /// Emitted when the request is aborted. The abort event will not be fired if + /// the request is already closed. + /// + [] abstract on_abort: listener: Function -> ClientRequest + [] abstract once_abort: listener: Function -> ClientRequest + [] abstract addListener_abort: listener: Function -> ClientRequest + [] abstract removeListener_abort: listener: Function -> ClientRequest + /// + /// Emitted as the last event in the HTTP request-response transaction. The close + /// event indicates that no more events will be emitted on either the request or + /// response objects. + /// + [] abstract on_close: listener: Function -> ClientRequest + [] abstract once_close: listener: Function -> ClientRequest + [] abstract addListener_close: listener: Function -> ClientRequest + [] abstract removeListener_close: listener: Function -> ClientRequest + /// + /// Emitted when the net module fails to issue a network request. Typically when + /// the request object emits an error event, a close event will subsequently + /// follow and no response object will be provided. + /// + [] abstract on_error: listener: (ExceptError -> unit) -> ClientRequest + [] abstract once_error: listener: (ExceptError -> unit) -> ClientRequest + [] abstract addListener_error: listener: (ExceptError -> unit) -> ClientRequest + [] abstract removeListener_error: listener: (ExceptError -> unit) -> ClientRequest + /// + /// Emitted just after the last chunk of the request's data has been written into + /// the request object. + /// + [] abstract on_finish: listener: Function -> ClientRequest + [] abstract once_finish: listener: Function -> ClientRequest + [] abstract addListener_finish: listener: Function -> ClientRequest + [] abstract removeListener_finish: listener: Function -> ClientRequest + /// + /// Emitted when an authenticating proxy is asking for user credentials. + /// + /// The callback function is expected to be called back with user credentials: + /// + /// * username String + /// * password String + /// + /// Providing empty credentials will cancel the request and report an authentication + /// error on the response object: + /// + [] abstract on_login: listener: (AuthInfo -> ((string) option -> (string) option -> unit) -> unit) -> ClientRequest + [] abstract once_login: listener: (AuthInfo -> ((string) option -> (string) option -> unit) -> unit) -> ClientRequest + [] abstract addListener_login: listener: (AuthInfo -> ((string) option -> (string) option -> unit) -> unit) -> ClientRequest + [] abstract removeListener_login: listener: (AuthInfo -> ((string) option -> (string) option -> unit) -> unit) -> ClientRequest + /// + /// Emitted when the server returns a redirect response (e.g. 301 Moved + /// Permanently). Calling request.followRedirect will continue with the + /// redirection. If this event is handled, request.followRedirect must be called + /// **synchronously**, otherwise the request will be cancelled. + /// + [] abstract on_redirect: listener: (float -> string -> string -> Record> -> unit) -> ClientRequest + [] abstract once_redirect: listener: (float -> string -> string -> Record> -> unit) -> ClientRequest + [] abstract addListener_redirect: listener: (float -> string -> string -> Record> -> unit) -> ClientRequest + [] abstract removeListener_redirect: listener: (float -> string -> string -> Record> -> unit) -> ClientRequest + [] abstract on_response: listener: (IncomingMessage -> unit) -> ClientRequest + [] abstract once_response: listener: (IncomingMessage -> unit) -> ClientRequest + [] abstract addListener_response: listener: (IncomingMessage -> unit) -> ClientRequest + [] abstract removeListener_response: listener: (IncomingMessage -> unit) -> ClientRequest + /// + /// Cancels an ongoing HTTP transaction. If the request has already emitted the + /// close event, the abort operation will have no effect. Otherwise an ongoing + /// event will emit abort and close events. Additionally, if there is an ongoing + /// response object,it will emit the aborted event. + /// + abstract abort: unit -> unit + /// + /// Sends the last chunk of the request data. Subsequent write or end operations + /// will not be allowed. The finish event is emitted just after the end operation. + /// + abstract ``end``: ?chunk: U2 * ?encoding: string * ?callback: (unit -> unit) -> unit + /// + /// Continues any pending redirection. Can only be called during a 'redirect' + /// event. + /// + abstract followRedirect: unit -> unit + /// The value of a previously set extra header name. + abstract getHeader: name: string -> string + /// + /// * active Boolean - Whether the request is currently active. If this is false + /// no other properties will be set + /// * started Boolean - Whether the upload has started. If this is false both + /// current and total will be set to 0. + /// * current Integer - The number of bytes that have been uploaded so far + /// * total Integer - The number of bytes that will be uploaded this request + /// + /// You can use this method in conjunction with POST requests to get the progress + /// of a file upload or other data transfer. + /// + abstract getUploadProgress: unit -> UploadProgress + /// Removes a previously set extra header name. This method can be called only + /// before first write. Trying to call it after the first write will throw an error. + abstract removeHeader: name: string -> unit + /// + /// Adds an extra HTTP header. The header name will be issued as-is without + /// lowercasing. It can be called only before first write. Calling this method after + /// the first write will throw an error. If the passed value is not a String, its + /// toString() method will be called to obtain the final value. + /// + /// Certain headers are restricted from being set by apps. These headers are listed + /// below. More information on restricted headers can be found in Chromium's header + /// utils. + /// + /// * Content-Length + /// * Host + /// * Trailer or Te + /// * Upgrade + /// * Cookie2 + /// * Keep-Alive + /// * Transfer-Encoding + /// + /// Additionally, setting the Connection header to the value upgrade is also + /// disallowed. + /// + abstract setHeader: name: string * value: string -> unit + /// + /// callback is essentially a dummy function introduced in the purpose of keeping + /// similarity with the Node.js API. It is called asynchronously in the next tick + /// after chunk content have been delivered to the Chromium networking layer. + /// Contrary to the Node.js implementation, it is not guaranteed that chunk + /// content have been flushed on the wire before callback is called. + /// + /// Adds a chunk of data to the request body. The first write operation may cause + /// the request headers to be issued on the wire. After the first write operation, + /// it is not allowed to add or remove a custom header. + /// + abstract write: chunk: U2 * ?encoding: string * ?callback: (unit -> unit) -> unit + /// + /// A Boolean specifying whether the request will use HTTP chunked transfer + /// encoding or not. Defaults to false. The property is readable and writable, + /// however it can be set only before the first write operation as the HTTP headers + /// are not yet put on the wire. Trying to set the chunkedEncoding property after + /// the first write will throw an error. + /// + /// Using chunked encoding is strongly recommended if you need to send a large + /// request body as data will be streamed in small chunks instead of being + /// internally buffered inside Electron process memory. + /// + abstract chunkedEncoding: bool with get, set + + type [] ClientRequestStatic = + /// ClientRequest + [] abstract Create: options: U2 -> ClientRequest + + type [] Clipboard = + /// An array of supported formats for the clipboard type. + abstract availableFormats: ?``type``: ClipboardAvailableFormats -> ResizeArray + /// Clears the clipboard content. + abstract clear: ?``type``: ClipboardAvailableFormats -> unit + /// Whether the clipboard supports the specified format. + abstract has: format: string * ?``type``: ClipboardAvailableFormats -> bool + /// + /// Reads format type from the clipboard. + /// + /// format should contain valid ASCII characters and have / separator. a/c, + /// a/bc are valid formats while /abc, abc/, a/, /a, a are not valid. + /// + abstract read: format: string -> string + /// + /// * title String + /// * url String + /// + /// Returns an Object containing title and url keys representing the bookmark in + /// the clipboard. The title and url values will be empty strings when the + /// bookmark is unavailable. + /// + abstract readBookmark: unit -> ReadBookmark + /// Reads format type from the clipboard. + abstract readBuffer: format: string -> Buffer + /// + /// The text on the find pasteboard, which is the pasteboard that holds information + /// about the current state of the active application’s find panel. + /// + /// This method uses synchronous IPC when called from the renderer process. The + /// cached value is reread from the find pasteboard whenever the application is + /// activated. + /// + abstract readFindText: unit -> string + /// The content in the clipboard as markup. + abstract readHTML: ?``type``: ClipboardAvailableFormats -> string + /// The image content in the clipboard. + abstract readImage: ?``type``: ClipboardAvailableFormats -> NativeImage + /// The content in the clipboard as RTF. + abstract readRTF: ?``type``: ClipboardAvailableFormats -> string + /// The content in the clipboard as plain text. + abstract readText: ?``type``: ClipboardAvailableFormats -> string + /// Writes data to the clipboard. + abstract write: data: Data * ?``type``: ClipboardAvailableFormats -> unit + /// + /// Writes the title and url into the clipboard as a bookmark. + /// + /// **Note:** Most apps on Windows don't support pasting bookmarks into them so you + /// can use clipboard.write to write both a bookmark and fallback text to the + /// clipboard. + /// + abstract writeBookmark: title: string * url: string * ?``type``: ClipboardAvailableFormats -> unit + /// Writes the buffer into the clipboard as format. + abstract writeBuffer: format: string * buffer: Buffer * ?``type``: ClipboardAvailableFormats -> unit + /// + /// Writes the text into the find pasteboard (the pasteboard that holds + /// information about the current state of the active application’s find panel) as + /// plain text. This method uses synchronous IPC when called from the renderer + /// process. + /// + abstract writeFindText: text: string -> unit + /// Writes markup to the clipboard. + abstract writeHTML: markup: string * ?``type``: ClipboardAvailableFormats -> unit + /// Writes image to the clipboard. + abstract writeImage: image: NativeImage * ?``type``: ClipboardAvailableFormats -> unit + /// Writes the text into the clipboard in RTF. + abstract writeRTF: text: string * ?``type``: ClipboardAvailableFormats -> unit + /// Writes the text into the clipboard as plain text. + abstract writeText: text: string * ?``type``: ClipboardAvailableFormats -> unit + + type [] CommandLine = + /// + /// Append an argument to Chromium's command line. The argument will be quoted + /// correctly. Switches will precede arguments regardless of appending order. + /// + /// If you're appending an argument like --switch=value, consider using + /// appendSwitch('switch', 'value') instead. + /// + /// **Note:** This will not affect process.argv. The intended usage of this + /// function is to control Chromium's behavior. + /// + abstract appendArgument: value: string -> unit + /// + /// Append a switch (with optional value) to Chromium's command line. + /// + /// **Note:** This will not affect process.argv. The intended usage of this + /// function is to control Chromium's behavior. + /// + abstract appendSwitch: the_switch: string * ?value: string -> unit + /// The command-line switch value. + /// + /// **Note:** When the switch is not present or has no value, it returns empty + /// string. + abstract getSwitchValue: the_switch: string -> string + /// Whether the command-line switch is present. + abstract hasSwitch: the_switch: string -> bool + + type [] CommandLineStatic = + [] abstract Create: unit -> CommandLine + + type [] ContentTracing = + /// + /// resolves with an array of category groups once all child processes have + /// acknowledged the getCategories request + /// + /// Get a set of category groups. The category groups can change as new code paths + /// are reached. See also the list of built-in tracing categories. + /// + /// > **NOTE:** Electron adds a non-default tracing category called "electron". + /// This category can be used to capture Electron-specific tracing events. + /// + abstract getCategories: unit -> Promise> + /// + /// Resolves with an object containing the value and percentage of trace buffer + /// maximum usage + /// + /// * value Number + /// * percentage Number + /// + /// Get the maximum usage across processes of trace buffer as a percentage of the + /// full state. + /// + abstract getTraceBufferUsage: unit -> Promise + /// + /// resolved once all child processes have acknowledged the startRecording + /// request. + /// + /// Start recording on all processes. + /// + /// Recording begins immediately locally and asynchronously on child processes as + /// soon as they receive the EnableRecording request. + /// + /// If a recording is already running, the promise will be immediately resolved, as + /// only one trace operation can be in progress at a time. + /// + abstract startRecording: options: U2 -> Promise + /// + /// resolves with a path to a file that contains the traced data once all child + /// processes have acknowledged the stopRecording request + /// + /// Stop recording on all processes. + /// + /// Child processes typically cache trace data and only rarely flush and send trace + /// data back to the main process. This helps to minimize the runtime overhead of + /// tracing since sending trace data over IPC can be an expensive operation. So, to + /// end tracing, Chromium asynchronously asks all child processes to flush any + /// pending trace data. + /// + /// Trace data will be written into resultFilePath. If resultFilePath is empty + /// or not provided, trace data will be written to a temporary file, and the path + /// will be returned in the promise. + /// + abstract stopRecording: ?resultFilePath: string -> Promise + + type [] ContextBridge = + abstract exposeInMainWorld: apiKey: string * api: obj option -> unit + + type [] Cookie = + /// The domain of the cookie; this will be normalized with a preceding dot so that + /// it's also valid for subdomains. + abstract domain: string option with get, set + /// The expiration date of the cookie as the number of seconds since the UNIX epoch. + /// Not provided for session cookies. + abstract expirationDate: float option with get, set + /// + /// Whether the cookie is a host-only cookie; this will only be true if no domain + /// was passed. + /// + abstract hostOnly: bool option with get, set + /// Whether the cookie is marked as HTTP only. + abstract httpOnly: bool option with get, set + /// The name of the cookie. + abstract name: string with get, set + /// The path of the cookie. + abstract path: string option with get, set + /// + /// The Same Site policy applied to this cookie. Can be unspecified, + /// no_restriction, lax or strict. + /// + abstract sameSite: CookieSameSite with get, set + /// Whether the cookie is marked as secure. + abstract secure: bool option with get, set + /// Whether the cookie is a session cookie or a persistent cookie with an expiration + /// date. + abstract session: bool option with get, set + /// The value of the cookie. + abstract value: string with get, set + + type [] Cookies = + inherit NodeEventEmitter + /// Emitted when a cookie is changed because it was added, edited, removed, or + /// expired. + [] abstract on_changed: listener: (Event -> Cookie -> CookiesOn_changed -> bool -> unit) -> Cookies + [] abstract once_changed: listener: (Event -> Cookie -> CookiesOn_changed -> bool -> unit) -> Cookies + [] abstract addListener_changed: listener: (Event -> Cookie -> CookiesOn_changed -> bool -> unit) -> Cookies + [] abstract removeListener_changed: listener: (Event -> Cookie -> CookiesOn_changed -> bool -> unit) -> Cookies + /// A promise which resolves when the cookie store has been flushed + /// + /// Writes any unwritten cookies data to disk. + abstract flushStore: unit -> Promise + /// + /// A promise which resolves an array of cookie objects. + /// + /// Sends a request to get all cookies matching filter, and resolves a promise + /// with the response. + /// + abstract get: filter: CookiesGetFilter -> Promise> + /// + /// A promise which resolves when the cookie has been removed + /// + /// Removes the cookies matching url and name + /// + abstract remove: url: string * name: string -> Promise + /// + /// A promise which resolves when the cookie has been set + /// + /// Sets a cookie with details. + /// + abstract set: details: CookiesSetDetails -> Promise + + type [] CookiesStatic = + [] abstract Create: unit -> Cookies + + type [] CPUUsage = + /// The number of average idle CPU wakeups per second since the last call to + /// getCPUUsage. First call returns 0. Will always return 0 on Windows. + abstract idleWakeupsPerSecond: float with get, set + /// Percentage of CPU used since the last call to getCPUUsage. First call returns 0. + abstract percentCPUUsage: float with get, set + + type [] CrashReport = + abstract date: DateTime with get, set + abstract id: string with get, set + + type [] CrashReporter = + /// + /// Set an extra parameter to be sent with the crash report. The values specified + /// here will be sent in addition to any values set via the extra option when + /// start was called. + /// + /// Parameters added in this fashion (or via the extra parameter to + /// crashReporter.start) are specific to the calling process. Adding extra + /// parameters in the main process will not cause those parameters to be sent along + /// with crashes from renderer or other child processes. Similarly, adding extra + /// parameters in a renderer process will not result in those parameters being sent + /// with crashes that occur in other renderer processes or in the main process. + /// + /// **Note:** Parameters have limits on the length of the keys and values. Key names + /// must be no longer than 39 bytes, and values must be no longer than 20320 bytes. + /// Keys with names longer than the maximum will be silently ignored. Key values + /// longer than the maximum length will be truncated. + /// + /// **Note:** On linux values that are longer than 127 bytes will be chunked into + /// multiple keys, each 127 bytes in length. E.g. `addExtraParameter('foo', + /// 'a'.repeat(130)) will result in two chunked keys foo__1 and foo__2`, the + /// first will contain the first 127 bytes and the second will contain the remaining + /// 3 bytes. On your crash reporting backend you should stitch together keys in + /// this format. + /// + abstract addExtraParameter: key: string * value: string -> unit + /// + /// The date and ID of the last crash report. Only crash reports that have been + /// uploaded will be returned; even if a crash report is present on disk it will not + /// be returned until it is uploaded. In the case that there are no uploaded + /// reports, null is returned. + /// + /// **Note:** This method is only available in the main process. + /// + abstract getLastCrashReport: unit -> CrashReport + /// The current 'extra' parameters of the crash reporter. + abstract getParameters: unit -> Record + /// Returns all uploaded crash reports. Each report contains the date and uploaded + /// ID. + /// + /// **Note:** This method is only available in the main process. + abstract getUploadedReports: unit -> ResizeArray + /// + /// Whether reports should be submitted to the server. Set through the start + /// method or setUploadToServer. + /// + /// **Note:** This method is only available in the main process. + /// + abstract getUploadToServer: unit -> bool + /// Remove an extra parameter from the current set of parameters. Future crashes + /// will not include this parameter. + abstract removeExtraParameter: key: string -> unit + /// + /// This would normally be controlled by user preferences. This has no effect if + /// called before start is called. + /// + /// **Note:** This method is only available in the main process. + /// + abstract setUploadToServer: uploadToServer: bool -> unit + /// + /// This method must be called before using any other crashReporter APIs. Once + /// initialized this way, the crashpad handler collects crashes from all + /// subsequently created processes. The crash reporter cannot be disabled once + /// started. + /// + /// This method should be called as early as possible in app startup, preferably + /// before app.on('ready'). If the crash reporter is not initialized at the time a + /// renderer process is created, then that renderer process will not be monitored by + /// the crash reporter. + /// + /// **Note:** You can test out the crash reporter by generating a crash using + /// process.crash(). + /// + /// **Note:** If you need to send additional/updated extra parameters after your + /// first call start you can call addExtraParameter. + /// + /// **Note:** Parameters passed in extra, globalExtra or set with + /// addExtraParameter have limits on the length of the keys and values. Key names + /// must be at most 39 bytes long, and values must be no longer than 127 bytes. Keys + /// with names longer than the maximum will be silently ignored. Key values longer + /// than the maximum length will be truncated. + /// + /// **Note:** This method is only available in the main process. + /// + abstract start: options: CrashReporterStartOptions -> unit + + type [] CustomScheme = + abstract privileges: Privileges option with get, set + /// Custom schemes to be registered with options. + abstract scheme: string with get, set + + type [] Debugger = + inherit NodeEventEmitter + /// + /// Emitted when the debugging session is terminated. This happens either when + /// webContents is closed or devtools is invoked for the attached webContents. + /// + [] abstract on_detach: listener: (Event -> string -> unit) -> Debugger + [] abstract once_detach: listener: (Event -> string -> unit) -> Debugger + [] abstract addListener_detach: listener: (Event -> string -> unit) -> Debugger + [] abstract removeListener_detach: listener: (Event -> string -> unit) -> Debugger + /// Emitted whenever the debugging target issues an instrumentation event. + [] abstract on_message: listener: (Event -> string -> obj option -> string -> unit) -> Debugger + [] abstract once_message: listener: (Event -> string -> obj option -> string -> unit) -> Debugger + [] abstract addListener_message: listener: (Event -> string -> obj option -> string -> unit) -> Debugger + [] abstract removeListener_message: listener: (Event -> string -> obj option -> string -> unit) -> Debugger + /// Attaches the debugger to the webContents. + abstract attach: ?protocolVersion: string -> unit + /// Detaches the debugger from the webContents. + abstract detach: unit -> unit + /// Whether a debugger is attached to the webContents. + abstract isAttached: unit -> bool + /// A promise that resolves with the response defined by the 'returns' attribute of + /// the command description in the remote debugging protocol or is rejected + /// indicating the failure of the command. + /// + /// Send given command to the debugging target. + abstract sendCommand: method: string * ?commandParams: obj * ?sessionId: string -> Promise + + type [] DebuggerStatic = + [] abstract Create: unit -> Debugger + + type [] DesktopCapturer = + /// + /// Resolves with an array of DesktopCapturerSource objects, each + /// DesktopCapturerSource represents a screen or an individual window that can be + /// captured. + /// + /// **Note** Capturing the screen contents requires user consent on macOS 10.15 + /// Catalina or higher, which can detected by + /// systemPreferences.getMediaAccessStatus. + /// + abstract getSources: options: SourcesOptions -> Promise> + + type [] DesktopCapturerSource = + /// An icon image of the application that owns the window or null if the source has + /// a type screen. The size of the icon is not known in advance and depends on what + /// the application provides. + abstract appIcon: NativeImage with get, set + /// + /// A unique identifier that will correspond to the id of the matching Display + /// returned by the Screen API. On some platforms, this is equivalent to the XX + /// portion of the id field above and on others it will differ. It will be an + /// empty string if not available. + /// + abstract display_id: string with get, set + /// + /// The identifier of a window or screen that can be used as a chromeMediaSourceId + /// constraint when calling [navigator.webkitGetUserMedia]. The format of the + /// identifier will be window:XX:YY or screen:ZZ:0. XX is the windowID/handle. + /// YY is 1 for the current process, and 0 for all others. ZZ is a sequential number + /// that represents the screen, and it does not equal to the index in the source's + /// name. + /// + abstract id: string with get, set + /// + /// A screen source will be named either Entire Screen or Screen <index>, while + /// the name of a window source will match the window title. + /// + abstract name: string with get, set + /// + /// A thumbnail image. **Note:** There is no guarantee that the size of the + /// thumbnail is the same as the thumbnailSize specified in the options passed + /// to desktopCapturer.getSources. The actual size depends on the scale of the + /// screen or window. + /// + abstract thumbnail: NativeImage with get, set + + type [] Dialog = + /// + /// resolves when the certificate trust dialog is shown. + /// + /// On macOS, this displays a modal dialog that shows a message and certificate + /// information, and gives the user the option of trusting/importing the + /// certificate. If you provide a browserWindow argument the dialog will be + /// attached to the parent window, making it modal. + /// + /// On Windows the options are more limited, due to the Win32 APIs used: + /// + /// * The message argument is not used, as the OS provides its own confirmation + /// dialog. + /// * The browserWindow argument is ignored since it is not possible to make this + /// confirmation dialog modal. + /// + abstract showCertificateTrustDialog: browserWindow: BrowserWindow * options: CertificateTrustDialogOptions -> Promise + /// + /// resolves when the certificate trust dialog is shown. + /// + /// On macOS, this displays a modal dialog that shows a message and certificate + /// information, and gives the user the option of trusting/importing the + /// certificate. If you provide a browserWindow argument the dialog will be + /// attached to the parent window, making it modal. + /// + /// On Windows the options are more limited, due to the Win32 APIs used: + /// + /// * The message argument is not used, as the OS provides its own confirmation + /// dialog. + /// * The browserWindow argument is ignored since it is not possible to make this + /// confirmation dialog modal. + /// + abstract showCertificateTrustDialog: options: CertificateTrustDialogOptions -> Promise + /// + /// Displays a modal dialog that shows an error message. + /// + /// This API can be called safely before the ready event the app module emits, + /// it is usually used to report errors in early stage of startup. If called before + /// the app readyevent on Linux, the message will be emitted to stderr, and no GUI + /// dialog will appear. + /// + abstract showErrorBox: title: string * content: string -> unit + /// + /// resolves with a promise containing the following properties: + /// + /// * response Number - The index of the clicked button. + /// * checkboxChecked Boolean - The checked state of the checkbox if + /// checkboxLabel was set. Otherwise false. + /// + /// Shows a message box. + /// + /// The browserWindow argument allows the dialog to attach itself to a parent + /// window, making it modal. + /// + abstract showMessageBox: browserWindow: BrowserWindow * options: MessageBoxOptions -> Promise + /// + /// resolves with a promise containing the following properties: + /// + /// * response Number - The index of the clicked button. + /// * checkboxChecked Boolean - The checked state of the checkbox if + /// checkboxLabel was set. Otherwise false. + /// + /// Shows a message box. + /// + /// The browserWindow argument allows the dialog to attach itself to a parent + /// window, making it modal. + /// + abstract showMessageBox: options: MessageBoxOptions -> Promise + /// + /// the index of the clicked button. + /// + /// Shows a message box, it will block the process until the message box is closed. + /// It returns the index of the clicked button. + /// + /// The browserWindow argument allows the dialog to attach itself to a parent + /// window, making it modal. If browserWindow is not shown dialog will not be + /// attached to it. In such case it will be displayed as an independent window. + /// + abstract showMessageBoxSync: browserWindow: BrowserWindow * options: MessageBoxSyncOptions -> float + /// + /// the index of the clicked button. + /// + /// Shows a message box, it will block the process until the message box is closed. + /// It returns the index of the clicked button. + /// + /// The browserWindow argument allows the dialog to attach itself to a parent + /// window, making it modal. If browserWindow is not shown dialog will not be + /// attached to it. In such case it will be displayed as an independent window. + /// + abstract showMessageBoxSync: options: MessageBoxSyncOptions -> float + /// + /// Resolve with an object containing the following: + /// + /// * canceled Boolean - whether or not the dialog was canceled. + /// * filePaths String[] - An array of file paths chosen by the user. If the + /// dialog is cancelled this will be an empty array. + /// * bookmarks String[] (optional) _macOS_ _mas_ - An array matching the + /// filePaths array of base64 encoded strings which contains security scoped + /// bookmark data. securityScopedBookmarks must be enabled for this to be + /// populated. (For return values, see table here.) + /// + /// The browserWindow argument allows the dialog to attach itself to a parent + /// window, making it modal. + /// + /// The filters specifies an array of file types that can be displayed or selected + /// when you want to limit the user to a specific type. For example: + /// + /// The extensions array should contain extensions without wildcards or dots (e.g. + /// 'png' is good but '.png' and '*.png' are bad). To show all files, use the + /// '*' wildcard (no other wildcard is supported). + /// + /// **Note:** On Windows and Linux an open dialog can not be both a file selector + /// and a directory selector, so if you set properties to `['openFile', + /// 'openDirectory']` on these platforms, a directory selector will be shown. + /// + abstract showOpenDialog: browserWindow: BrowserWindow * options: OpenDialogOptions -> Promise + /// + /// Resolve with an object containing the following: + /// + /// * canceled Boolean - whether or not the dialog was canceled. + /// * filePaths String[] - An array of file paths chosen by the user. If the + /// dialog is cancelled this will be an empty array. + /// * bookmarks String[] (optional) _macOS_ _mas_ - An array matching the + /// filePaths array of base64 encoded strings which contains security scoped + /// bookmark data. securityScopedBookmarks must be enabled for this to be + /// populated. (For return values, see table here.) + /// + /// The browserWindow argument allows the dialog to attach itself to a parent + /// window, making it modal. + /// + /// The filters specifies an array of file types that can be displayed or selected + /// when you want to limit the user to a specific type. For example: + /// + /// The extensions array should contain extensions without wildcards or dots (e.g. + /// 'png' is good but '.png' and '*.png' are bad). To show all files, use the + /// '*' wildcard (no other wildcard is supported). + /// + /// **Note:** On Windows and Linux an open dialog can not be both a file selector + /// and a directory selector, so if you set properties to `['openFile', + /// 'openDirectory']` on these platforms, a directory selector will be shown. + /// + abstract showOpenDialog: options: OpenDialogOptions -> Promise + /// + /// the file paths chosen by the user; if the dialog is cancelled it returns + /// undefined. + /// + /// The browserWindow argument allows the dialog to attach itself to a parent + /// window, making it modal. + /// + /// The filters specifies an array of file types that can be displayed or selected + /// when you want to limit the user to a specific type. For example: + /// + /// The extensions array should contain extensions without wildcards or dots (e.g. + /// 'png' is good but '.png' and '*.png' are bad). To show all files, use the + /// '*' wildcard (no other wildcard is supported). + /// + /// **Note:** On Windows and Linux an open dialog can not be both a file selector + /// and a directory selector, so if you set properties to `['openFile', + /// 'openDirectory']` on these platforms, a directory selector will be shown. + /// + abstract showOpenDialogSync: browserWindow: BrowserWindow * options: OpenDialogSyncOptions -> ResizeArray option + /// + /// the file paths chosen by the user; if the dialog is cancelled it returns + /// undefined. + /// + /// The browserWindow argument allows the dialog to attach itself to a parent + /// window, making it modal. + /// + /// The filters specifies an array of file types that can be displayed or selected + /// when you want to limit the user to a specific type. For example: + /// + /// The extensions array should contain extensions without wildcards or dots (e.g. + /// 'png' is good but '.png' and '*.png' are bad). To show all files, use the + /// '*' wildcard (no other wildcard is supported). + /// + /// **Note:** On Windows and Linux an open dialog can not be both a file selector + /// and a directory selector, so if you set properties to `['openFile', + /// 'openDirectory']` on these platforms, a directory selector will be shown. + /// + abstract showOpenDialogSync: options: OpenDialogSyncOptions -> ResizeArray option + /// + /// Resolve with an object containing the following: + /// + /// * canceled Boolean - whether or not the dialog was canceled. + /// * filePath String (optional) - If the dialog is canceled, this will be + /// undefined. + /// * bookmark String (optional) _macOS_ _mas_ - Base64 encoded string which + /// contains the security scoped bookmark data for the saved file. + /// securityScopedBookmarks must be enabled for this to be present. (For return + /// values, see table here.) + /// + /// The browserWindow argument allows the dialog to attach itself to a parent + /// window, making it modal. + /// + /// The filters specifies an array of file types that can be displayed, see + /// dialog.showOpenDialog for an example. + /// + /// **Note:** On macOS, using the asynchronous version is recommended to avoid + /// issues when expanding and collapsing the dialog. + /// + abstract showSaveDialog: browserWindow: BrowserWindow * options: SaveDialogOptions -> Promise + /// + /// Resolve with an object containing the following: + /// + /// * canceled Boolean - whether or not the dialog was canceled. + /// * filePath String (optional) - If the dialog is canceled, this will be + /// undefined. + /// * bookmark String (optional) _macOS_ _mas_ - Base64 encoded string which + /// contains the security scoped bookmark data for the saved file. + /// securityScopedBookmarks must be enabled for this to be present. (For return + /// values, see table here.) + /// + /// The browserWindow argument allows the dialog to attach itself to a parent + /// window, making it modal. + /// + /// The filters specifies an array of file types that can be displayed, see + /// dialog.showOpenDialog for an example. + /// + /// **Note:** On macOS, using the asynchronous version is recommended to avoid + /// issues when expanding and collapsing the dialog. + /// + abstract showSaveDialog: options: SaveDialogOptions -> Promise + /// + /// the path of the file chosen by the user; if the dialog is cancelled it returns + /// undefined. + /// + /// The browserWindow argument allows the dialog to attach itself to a parent + /// window, making it modal. + /// + /// The filters specifies an array of file types that can be displayed, see + /// dialog.showOpenDialog for an example. + /// + abstract showSaveDialogSync: browserWindow: BrowserWindow * options: SaveDialogSyncOptions -> string option + /// + /// the path of the file chosen by the user; if the dialog is cancelled it returns + /// undefined. + /// + /// The browserWindow argument allows the dialog to attach itself to a parent + /// window, making it modal. + /// + /// The filters specifies an array of file types that can be displayed, see + /// dialog.showOpenDialog for an example. + /// + abstract showSaveDialogSync: options: SaveDialogSyncOptions -> string option + + type [] Display = + /// Can be available, unavailable, unknown. + abstract accelerometerSupport: DisplayAccelerometerSupport with get, set + /// the bounds of the display in DIP points. + abstract bounds: Rectangle with get, set + /// The number of bits per pixel. + abstract colorDepth: float with get, set + /// represent a color space (three-dimensional object which contains all realizable + /// color combinations) for the purpose of color conversions + abstract colorSpace: string with get, set + /// The number of bits per color component. + abstract depthPerComponent: float with get, set + /// The display refresh rate. + abstract displayFrequency: float with get, set + /// Unique identifier associated with the display. + abstract id: float with get, set + /// true for an internal display and false for an external display + abstract ``internal``: bool with get, set + /// Whether or not the display is a monochrome display. + abstract monochrome: bool with get, set + /// Can be 0, 90, 180, 270, represents screen rotation in clock-wise degrees. + abstract rotation: float with get, set + /// Output device's pixel scale factor. + abstract scaleFactor: float with get, set + abstract size: Size with get, set + /// Can be available, unavailable, unknown. + abstract touchSupport: DisplayAccelerometerSupport with get, set + /// the work area of the display in DIP points. + abstract workArea: Rectangle with get, set + abstract workAreaSize: Size with get, set + + type [] Dock = + /// + /// an ID representing the request. + /// + /// When critical is passed, the dock icon will bounce until either the + /// application becomes active or the request is canceled. + /// + /// When informational is passed, the dock icon will bounce for one second. + /// However, the request remains active until either the application becomes active + /// or the request is canceled. + /// + /// **Nota Bene:** This method can only be used while the app is not focused; when + /// the app is focused it will return -1. + /// + abstract bounce: ?``type``: DockBounce -> float + /// Cancel the bounce of id. + abstract cancelBounce: id: float -> unit + /// Bounces the Downloads stack if the filePath is inside the Downloads folder. + abstract downloadFinished: filePath: string -> unit + /// The badge string of the dock. + abstract getBadge: unit -> string + /// The application's [dock menu][dock-menu]. + abstract getMenu: unit -> Menu option + /// Hides the dock icon. + abstract hide: unit -> unit + /// Whether the dock icon is visible. + abstract isVisible: unit -> bool + /// Sets the string to be displayed in the dock’s badging area. + abstract setBadge: text: string -> unit + /// Sets the image associated with this dock icon. + abstract setIcon: image: U2 -> unit + /// Sets the application's [dock menu][dock-menu]. + abstract setMenu: menu: Menu -> unit + /// Resolves when the dock icon is shown. + abstract show: unit -> Promise + + type [] DockStatic = + [] abstract Create: unit -> Dock + + type [] DownloadItem = + inherit NodeEventEmitter + /// + /// Emitted when the download is in a terminal state. This includes a completed + /// download, a cancelled download (via downloadItem.cancel()), and interrupted + /// download that can't be resumed. + /// + /// The state can be one of following: + /// + /// * completed - The download completed successfully. + /// * cancelled - The download has been cancelled. + /// * interrupted - The download has interrupted and can not resume. + /// + [] abstract on_done: listener: (Event -> DownloadItemOn_done -> unit) -> DownloadItem + [] abstract once_done: listener: (Event -> DownloadItemOn_done -> unit) -> DownloadItem + [] abstract addListener_done: listener: (Event -> DownloadItemOn_done -> unit) -> DownloadItem + [] abstract removeListener_done: listener: (Event -> DownloadItemOn_done -> unit) -> DownloadItem + /// + /// Emitted when the download has been updated and is not done. + /// + /// The state can be one of following: + /// + /// * progressing - The download is in-progress. + /// * interrupted - The download has interrupted and can be resumed. + /// + [] abstract on_updated: listener: (Event -> DownloadItemOn_updated -> unit) -> DownloadItem + [] abstract once_updated: listener: (Event -> DownloadItemOn_updated -> unit) -> DownloadItem + [] abstract addListener_updated: listener: (Event -> DownloadItemOn_updated -> unit) -> DownloadItem + [] abstract removeListener_updated: listener: (Event -> DownloadItemOn_updated -> unit) -> DownloadItem + /// Cancels the download operation. + abstract cancel: unit -> unit + /// Whether the download can resume. + abstract canResume: unit -> bool + /// The Content-Disposition field from the response header. + abstract getContentDisposition: unit -> string + /// ETag header value. + abstract getETag: unit -> string + /// The file name of the download item. + /// + /// **Note:** The file name is not always the same as the actual one saved in local + /// disk. If user changes the file name in a prompted download saving dialog, the + /// actual name of saved file will be different. + abstract getFilename: unit -> string + /// Last-Modified header value. + abstract getLastModifiedTime: unit -> string + /// The files mime type. + abstract getMimeType: unit -> string + /// The received bytes of the download item. + abstract getReceivedBytes: unit -> float + /// + /// Returns the object previously set by + /// downloadItem.setSaveDialogOptions(options). + /// + abstract getSaveDialogOptions: unit -> SaveDialogOptions + /// + /// The save path of the download item. This will be either the path set via + /// downloadItem.setSavePath(path) or the path selected from the shown save + /// dialog. + /// + abstract getSavePath: unit -> string + /// Number of seconds since the UNIX epoch when the download was started. + abstract getStartTime: unit -> float + /// + /// The current state. Can be progressing, completed, cancelled or + /// interrupted. + /// + /// **Note:** The following methods are useful specifically to resume a cancelled + /// item when session is restarted. + /// + abstract getState: unit -> DownloadItemGetState + /// The total size in bytes of the download item. + /// + /// If the size is unknown, it returns 0. + abstract getTotalBytes: unit -> float + /// The origin URL where the item is downloaded from. + abstract getURL: unit -> string + /// The complete URL chain of the item including any redirects. + abstract getURLChain: unit -> ResizeArray + /// Whether the download has user gesture. + abstract hasUserGesture: unit -> bool + /// Whether the download is paused. + abstract isPaused: unit -> bool + /// Pauses the download. + abstract pause: unit -> unit + /// + /// Resumes the download that has been paused. + /// + /// **Note:** To enable resumable downloads the server you are downloading from must + /// support range requests and provide both Last-Modified and ETag header + /// values. Otherwise resume() will dismiss previously received bytes and restart + /// the download from the beginning. + /// + abstract resume: unit -> unit + /// + /// This API allows the user to set custom options for the save dialog that opens + /// for the download item by default. The API is only available in session's + /// will-download callback function. + /// + abstract setSaveDialogOptions: options: SaveDialogOptions -> unit + /// + /// The API is only available in session's will-download callback function. If + /// path doesn't exist, Electron will try to make the directory recursively. If + /// user doesn't set the save path via the API, Electron will use the original + /// routine to determine the save path; this usually prompts a save dialog. + /// + abstract setSavePath: path: string -> unit + /// + /// A String property that determines the save file path of the download item. + /// + /// The property is only available in session's will-download callback function. + /// If user doesn't set the save path via the property, Electron will use the + /// original routine to determine the save path; this usually prompts a save dialog. + /// + abstract savePath: string with get, set + + type [] DownloadItemStatic = + [] abstract Create: unit -> DownloadItem + + type [] Event = + inherit GlobalEvent + abstract preventDefault: (unit -> unit) with get, set + + type [] Extension = + abstract id: string with get, set + /// Copy of the extension's manifest data. + abstract manifest: obj option with get, set + abstract name: string with get, set + /// The extension's file path. + abstract path: string with get, set + /// The extension's chrome-extension:// URL. + abstract url: string with get, set + abstract version: string with get, set + + type [] ExtensionInfo = + abstract name: string with get, set + abstract version: string with get, set + + type [] FileFilter = + abstract extensions: ResizeArray with get, set + abstract name: string with get, set + + type [] FilePathWithHeaders = + /// Additional headers to be sent. + abstract headers: Record option with get, set + /// The path to the file to send. + abstract path: string with get, set + + type [] GlobalShortcut = + /// + /// Whether this application has registered accelerator. + /// + /// When the accelerator is already taken by other applications, this call will + /// still return false. This behavior is intended by operating systems, since they + /// don't want applications to fight for global shortcuts. + /// + abstract isRegistered: accelerator: Accelerator -> bool + /// + /// Whether or not the shortcut was registered successfully. + /// + /// Registers a global shortcut of accelerator. The callback is called when the + /// registered shortcut is pressed by the user. + /// + /// When the accelerator is already taken by other applications, this call will + /// silently fail. This behavior is intended by operating systems, since they don't + /// want applications to fight for global shortcuts. + /// + /// The following accelerators will not be registered successfully on macOS 10.14 + /// Mojave unless the app has been authorized as a trusted accessibility client: + /// + /// * "Media Play/Pause" + /// * "Media Next Track" + /// * "Media Previous Track" + /// * "Media Stop" + /// + abstract register: accelerator: Accelerator * callback: (unit -> unit) -> bool + /// + /// Registers a global shortcut of all accelerator items in accelerators. The + /// callback is called when any of the registered shortcuts are pressed by the + /// user. + /// + /// When a given accelerator is already taken by other applications, this call will + /// silently fail. This behavior is intended by operating systems, since they don't + /// want applications to fight for global shortcuts. + /// + /// The following accelerators will not be registered successfully on macOS 10.14 + /// Mojave unless the app has been authorized as a trusted accessibility client: + /// + /// * "Media Play/Pause" + /// * "Media Next Track" + /// * "Media Previous Track" + /// * "Media Stop" + /// + abstract registerAll: accelerators: ResizeArray * callback: (unit -> unit) -> unit + /// Unregisters the global shortcut of accelerator. + abstract unregister: accelerator: Accelerator -> unit + /// Unregisters all of the global shortcuts. + abstract unregisterAll: unit -> unit + + type [] GPUFeatureStatus = + /// Canvas. + abstract ``2d_canvas``: string with get, set + /// Flash. + abstract flash_3d: string with get, set + /// Flash Stage3D. + abstract flash_stage3d: string with get, set + /// Flash Stage3D Baseline profile. + abstract flash_stage3d_baseline: string with get, set + /// Compositing. + abstract gpu_compositing: string with get, set + /// Multiple Raster Threads. + abstract multiple_raster_threads: string with get, set + /// Native GpuMemoryBuffers. + abstract native_gpu_memory_buffers: string with get, set + /// Rasterization. + abstract rasterization: string with get, set + /// Video Decode. + abstract video_decode: string with get, set + /// Video Encode. + abstract video_encode: string with get, set + /// VPx Video Decode. + abstract vpx_decode: string with get, set + /// WebGL. + abstract webgl: string with get, set + /// WebGL2. + abstract webgl2: string with get, set + + type [] HIDDevice = + /// Unique identifier for the device. + abstract deviceId: string with get, set + /// Unique identifier for the HID interface. A device may have multiple HID + /// interfaces. + abstract guid: string option with get, set + /// Name of the device. + abstract name: string with get, set + /// The USB product ID. + abstract productId: float with get, set + /// The USB device serial number. + abstract serialNumber: string option with get, set + /// The USB vendor ID. + abstract vendorId: float with get, set + + type [] InAppPurchase = + inherit NodeJS.EventEmitter + [] abstract ``on_transactions-updated``: listener: Function -> InAppPurchase + [] abstract ``once_transactions-updated``: listener: Function -> InAppPurchase + [] abstract ``addListener_transactions-updated``: listener: Function -> InAppPurchase + [] abstract ``removeListener_transactions-updated``: listener: Function -> InAppPurchase + /// whether a user can make a payment. + abstract canMakePayments: unit -> bool + /// Completes all pending transactions. + abstract finishAllTransactions: unit -> unit + /// Completes the pending transactions corresponding to the date. + abstract finishTransactionByDate: date: string -> unit + /// + /// Resolves with an array of Product objects. + /// + /// Retrieves the product descriptions. + /// + abstract getProducts: productIDs: ResizeArray -> Promise> + /// the path to the receipt. + abstract getReceiptURL: unit -> string + /// + /// Returns true if the product is valid and added to the payment queue. + /// + /// You should listen for the transactions-updated event as soon as possible and + /// certainly before you call purchaseProduct. + /// + abstract purchaseProduct: productID: string * ?quantity: float -> Promise + /// Restores finished transactions. This method can be called either to install + /// purchases on additional devices, or to restore purchases for an application that + /// the user deleted and reinstalled. + /// + /// The payment queue delivers a new transaction for each previously completed + /// transaction that can be restored. Each transaction includes a copy of the + /// original transaction. + abstract restoreCompletedTransactions: unit -> unit + + type [] IncomingMessage = + inherit NodeEventEmitter + /// Emitted when a request has been canceled during an ongoing HTTP transaction. + [] abstract on_aborted: listener: Function -> IncomingMessage + [] abstract once_aborted: listener: Function -> IncomingMessage + [] abstract addListener_aborted: listener: Function -> IncomingMessage + [] abstract removeListener_aborted: listener: Function -> IncomingMessage + /// + /// The data event is the usual method of transferring response data into + /// applicative code. + /// + [] abstract on_data: listener: (Buffer -> unit) -> IncomingMessage + [] abstract once_data: listener: (Buffer -> unit) -> IncomingMessage + [] abstract addListener_data: listener: (Buffer -> unit) -> IncomingMessage + [] abstract removeListener_data: listener: (Buffer -> unit) -> IncomingMessage + /// Indicates that response body has ended. Must be placed before 'data' event. + [] abstract on_end: listener: Function -> IncomingMessage + [] abstract once_end: listener: Function -> IncomingMessage + [] abstract addListener_end: listener: Function -> IncomingMessage + [] abstract removeListener_end: listener: Function -> IncomingMessage + /// + /// Returns: + /// + /// error Error - Typically holds an error string identifying failure root cause. + /// + /// Emitted when an error was encountered while streaming response data events. For + /// instance, if the server closes the underlying while the response is still + /// streaming, an error event will be emitted on the response object and a close + /// event will subsequently follow on the request object. + /// + [] abstract on_error: listener: Function -> IncomingMessage + [] abstract once_error: listener: Function -> IncomingMessage + [] abstract addListener_error: listener: Function -> IncomingMessage + [] abstract removeListener_error: listener: Function -> IncomingMessage + /// + /// A Record<string, string | string[]> representing the HTTP response headers. + /// The headers object is formatted as follows: + /// + /// * All header names are lowercased. + /// * Duplicates of age, authorization, content-length, content-type, + /// etag, expires, from, host, if-modified-since, if-unmodified-since, + /// last-modified, location, max-forwards, proxy-authorization, referer, + /// retry-after, server, or user-agent are discarded. + /// * set-cookie is always an array. Duplicates are added to the array. + /// * For duplicate cookie headers, the values are joined together with '; '. + /// * For all other headers, the values are joined together with ', '. + /// + abstract headers: Record>> with get, set + /// + /// A String indicating the HTTP protocol version number. Typical values are '1.0' + /// or '1.1'. Additionally httpVersionMajor and httpVersionMinor are two + /// Integer-valued readable properties that return respectively the HTTP major and + /// minor version numbers. + /// + abstract httpVersion: string with get, set + /// An Integer indicating the HTTP protocol major version number. + abstract httpVersionMajor: float with get, set + /// An Integer indicating the HTTP protocol minor version number. + abstract httpVersionMinor: float with get, set + /// An Integer indicating the HTTP response status code. + abstract statusCode: float with get, set + /// A String representing the HTTP status message. + abstract statusMessage: string with get, set + + type [] IncomingMessageStatic = + [] abstract Create: unit -> IncomingMessage + + type [] InputEvent = + /// + /// An array of modifiers of the event, can be shift, control, ctrl, alt, + /// meta, command, cmd, isKeypad, isAutoRepeat, leftButtonDown, + /// middleButtonDown, rightButtonDown, capsLock, numLock, left, right. + /// + abstract modifiers: Array option with get, set + + type [] IOCounters = + /// Then number of I/O other operations. + abstract otherOperationCount: float with get, set + /// Then number of I/O other transfers. + abstract otherTransferCount: float with get, set + /// The number of I/O read operations. + abstract readOperationCount: float with get, set + /// The number of I/O read transfers. + abstract readTransferCount: float with get, set + /// The number of I/O write operations. + abstract writeOperationCount: float with get, set + /// The number of I/O write transfers. + abstract writeTransferCount: float with get, set + + type [] IpcMain = + inherit NodeJS.EventEmitter + /// + /// Adds a handler for an invokeable IPC. This handler will be called whenever a + /// renderer calls ipcRenderer.invoke(channel, ...args). + /// + /// If listener returns a Promise, the eventual result of the promise will be + /// returned as a reply to the remote caller. Otherwise, the return value of the + /// listener will be used as the value of the reply. + /// + /// The event that is passed as the first argument to the handler is the same as + /// that passed to a regular event listener. It includes information about which + /// WebContents is the source of the invoke request. + /// + /// Errors thrown through handle in the main process are not transparent as they + /// are serialized and only the message property from the original error is + /// provided to the renderer process. Please refer to #24427 for details. + /// + abstract handle: channel: string * listener: (IpcMainInvokeEvent -> ResizeArray -> U2, obj option>) -> unit + /// + /// Handles a single invokeable IPC message, then removes the listener. See + /// ipcMain.handle(channel, listener). + /// + abstract handleOnce: channel: string * listener: (IpcMainInvokeEvent -> ResizeArray -> U2, obj option>) -> unit + /// + /// Listens to channel, when a new message arrives listener would be called with + /// listener(event, args...). + /// + abstract on: channel: string * listener: (IpcMainEvent -> ResizeArray -> unit) -> IpcMain + /// + /// Adds a one time listener function for the event. This listener is invoked + /// only the next time a message is sent to channel, after which it is removed. + /// + abstract once: channel: string * listener: (IpcMainEvent -> ResizeArray -> unit) -> IpcMain + /// Removes listeners of the specified channel. + abstract removeAllListeners: ?channel: string -> IpcMain + /// Removes any handler for channel, if present. + abstract removeHandler: channel: string -> unit + /// + /// Removes the specified listener from the listener array for the specified + /// channel. + /// + abstract removeListener: channel: string * listener: (ResizeArray -> unit) -> IpcMain + + type [] IpcMainEvent = + inherit Event + /// The ID of the renderer frame that sent this message + abstract frameId: float with get, set + /// A list of MessagePorts that were transferred with this message + abstract ports: ResizeArray with get, set + /// The internal ID of the renderer process that sent this message + abstract processId: float with get, set + /// A function that will send an IPC message to the renderer frame that sent the + /// original message that you are currently handling. You should use this method to + /// "reply" to the sent message in order to guarantee the reply will go to the + /// correct process and frame. + abstract reply: Function with get, set + /// Set this to the value to be returned in a synchronous message + abstract returnValue: obj option with get, set + /// Returns the webContents that sent the message + abstract sender: WebContents with get, set + /// The frame that sent this message + abstract senderFrame: WebFrameMain + + type [] IpcMainInvokeEvent = + inherit Event + /// The ID of the renderer frame that sent this message + abstract frameId: float with get, set + /// The internal ID of the renderer process that sent this message + abstract processId: float with get, set + /// Returns the webContents that sent the message + abstract sender: WebContents with get, set + /// The frame that sent this message + abstract senderFrame: WebFrameMain + + type [] IpcRenderer = + inherit NodeJS.EventEmitter + /// + /// Resolves with the response from the main process. + /// + /// Send a message to the main process via channel and expect a result + /// asynchronously. Arguments will be serialized with the Structured Clone + /// Algorithm, just like window.postMessage, so prototype chains will not be + /// included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw + /// an exception. + /// + /// > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special + /// Electron objects will throw an exception. + /// + /// Since the main process does not have support for DOM objects such as + /// ImageBitmap, File, DOMMatrix and so on, such objects cannot be sent over + /// Electron's IPC to the main process, as the main process would have no way to + /// decode them. Attempting to send such objects over IPC will result in an error. + /// + /// The main process should listen for channel with ipcMain.handle(). + /// + /// For example: + /// + /// If you need to transfer a MessagePort to the main process, use + /// ipcRenderer.postMessage. + /// + /// If you do not need a response to the message, consider using ipcRenderer.send. + /// + abstract invoke: channel: string * [] args: obj option[] -> Promise + /// + /// Listens to channel, when a new message arrives listener would be called with + /// listener(event, args...). + /// + abstract on: channel: string * listener: (IpcRendererEvent -> ResizeArray -> unit) -> IpcRenderer + /// + /// Adds a one time listener function for the event. This listener is invoked + /// only the next time a message is sent to channel, after which it is removed. + /// + abstract once: channel: string * listener: (IpcRendererEvent -> ResizeArray -> unit) -> IpcRenderer + /// + /// Send a message to the main process, optionally transferring ownership of zero or + /// more MessagePort objects. + /// + /// The transferred MessagePort objects will be available in the main process as + /// MessagePortMain objects by accessing the ports property of the emitted + /// event. + /// + /// For example: + /// + /// For more information on using MessagePort and MessageChannel, see the MDN + /// documentation. + /// + abstract postMessage: channel: string * message: obj option * ?transfer: ResizeArray -> unit + /// Removes all listeners, or those of the specified channel. + abstract removeAllListeners: channel: string -> IpcRenderer + /// + /// Removes the specified listener from the listener array for the specified + /// channel. + /// + abstract removeListener: channel: string * listener: (ResizeArray -> unit) -> IpcRenderer + /// + /// Send an asynchronous message to the main process via channel, along with + /// arguments. Arguments will be serialized with the Structured Clone Algorithm, + /// just like window.postMessage, so prototype chains will not be included. + /// Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an + /// exception. + /// + /// > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special + /// Electron objects will throw an exception. + /// + /// Since the main process does not have support for DOM objects such as + /// ImageBitmap, File, DOMMatrix and so on, such objects cannot be sent over + /// Electron's IPC to the main process, as the main process would have no way to + /// decode them. Attempting to send such objects over IPC will result in an error. + /// + /// The main process handles it by listening for channel with the ipcMain + /// module. + /// + /// If you need to transfer a MessagePort to the main process, use + /// ipcRenderer.postMessage. + /// + /// If you want to receive a single response from the main process, like the result + /// of a method call, consider using ipcRenderer.invoke. + /// + abstract send: channel: string * [] args: obj option[] -> unit + /// + /// The value sent back by the ipcMain handler. + /// + /// Send a message to the main process via channel and expect a result + /// synchronously. Arguments will be serialized with the Structured Clone Algorithm, + /// just like window.postMessage, so prototype chains will not be included. + /// Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an + /// exception. + /// + /// > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special + /// Electron objects will throw an exception. + /// + /// Since the main process does not have support for DOM objects such as + /// ImageBitmap, File, DOMMatrix and so on, such objects cannot be sent over + /// Electron's IPC to the main process, as the main process would have no way to + /// decode them. Attempting to send such objects over IPC will result in an error. + /// + /// The main process handles it by listening for channel with ipcMain module, + /// and replies by setting event.returnValue. + /// + /// > :warning: **WARNING**: Sending a synchronous message will block the whole + /// renderer process until the reply is received, so use this method only as a last + /// resort. It's much better to use the asynchronous version, invoke(). + /// + abstract sendSync: channel: string * [] args: obj option[] -> obj option + /// Sends a message to a window with webContentsId via channel. + abstract sendTo: webContentsId: float * channel: string * [] args: obj option[] -> unit + /// + /// Like ipcRenderer.send but the event will be sent to the <webview> element in + /// the host page instead of the main process. + /// + abstract sendToHost: channel: string * [] args: obj option[] -> unit + + type [] IpcRendererEvent = + inherit Event + /// A list of MessagePorts that were transferred with this message + abstract ports: ResizeArray with get, set + /// The IpcRenderer instance that emitted the event originally + abstract sender: IpcRenderer with get, set + /// + /// The webContents.id that sent the message, you can call + /// event.sender.sendTo(event.senderId, ...) to reply to the message, see + /// ipcRenderer.sendTo for more information. This only applies to messages sent from + /// a different renderer. Messages sent directly from the main process set + /// event.senderId to 0. + /// + abstract senderId: float with get, set + + type [] JumpListCategory = + /// + /// Array of JumpListItem objects if type is tasks or custom, otherwise it + /// should be omitted. + /// + abstract items: ResizeArray option with get, set + /// Must be set if type is custom, otherwise it should be omitted. + abstract name: string option with get, set + /// One of the following: + abstract ``type``: JumpListCategoryType option with get, set + + type [] JumpListItem = + /// + /// The command line arguments when program is executed. Should only be set if + /// type is task. + /// + abstract args: string option with get, set + /// + /// Description of the task (displayed in a tooltip). Should only be set if type + /// is task. Maximum length 260 characters. + /// + abstract description: string option with get, set + /// The index of the icon in the resource file. If a resource file contains multiple + /// icons this value can be used to specify the zero-based index of the icon that + /// should be displayed for this task. If a resource file contains only one icon, + /// this property should be set to zero. + abstract iconIndex: float option with get, set + /// + /// The absolute path to an icon to be displayed in a Jump List, which can be an + /// arbitrary resource file that contains an icon (e.g. .ico, .exe, .dll). You + /// can usually specify process.execPath to show the program icon. + /// + abstract iconPath: string option with get, set + /// Path of the file to open, should only be set if type is file. + abstract path: string option with get, set + /// + /// Path of the program to execute, usually you should specify process.execPath + /// which opens the current program. Should only be set if type is task. + /// + abstract program: string option with get, set + /// + /// The text to be displayed for the item in the Jump List. Should only be set if + /// type is task. + /// + abstract title: string option with get, set + /// One of the following: + abstract ``type``: JumpListItemType option with get, set + /// The working directory. Default is empty. + abstract workingDirectory: string option with get, set + + type [] KeyboardEvent = + /// whether an Alt key was used in an accelerator to trigger the Event + abstract altKey: bool option with get, set + /// whether the Control key was used in an accelerator to trigger the Event + abstract ctrlKey: bool option with get, set + /// whether a meta key was used in an accelerator to trigger the Event + abstract metaKey: bool option with get, set + /// whether a Shift key was used in an accelerator to trigger the Event + abstract shiftKey: bool option with get, set + /// whether an accelerator was used to trigger the event as opposed to another user + /// gesture like mouse click + abstract triggeredByAccelerator: bool option with get, set + + type [] KeyboardInputEvent = + inherit InputEvent + /// The character that will be sent as the keyboard event. Should only use the valid + /// key codes in Accelerator. + abstract keyCode: string with get, set + /// The type of the event, can be keyDown, keyUp or char. + abstract ``type``: KeyboardInputEventType with get, set + + type [] MemoryInfo = + /// The maximum amount of memory that has ever been pinned to actual physical RAM. + abstract peakWorkingSetSize: float with get, set + /// + /// The amount of memory not shared by other processes, such as JS heap or HTML + /// content. + /// + abstract privateBytes: float option with get, set + /// The amount of memory currently pinned to actual physical RAM. + abstract workingSetSize: float with get, set + + type [] MemoryUsageDetails = + abstract count: float with get, set + abstract liveSize: float with get, set + abstract size: float with get, set + + type [] Menu = + /// Emitted when a popup is closed either manually or with menu.closePopup(). + [] abstract ``on_menu-will-close``: listener: (Event -> unit) -> Menu + [] abstract ``once_menu-will-close``: listener: (Event -> unit) -> Menu + [] abstract ``addListener_menu-will-close``: listener: (Event -> unit) -> Menu + [] abstract ``removeListener_menu-will-close``: listener: (Event -> unit) -> Menu + /// Emitted when menu.popup() is called. + [] abstract ``on_menu-will-show``: listener: (Event -> unit) -> Menu + [] abstract ``once_menu-will-show``: listener: (Event -> unit) -> Menu + [] abstract ``addListener_menu-will-show``: listener: (Event -> unit) -> Menu + [] abstract ``removeListener_menu-will-show``: listener: (Event -> unit) -> Menu + /// Appends the menuItem to the menu. + abstract append: menuItem: MenuItem -> unit + /// Closes the context menu in the browserWindow. + abstract closePopup: ?browserWindow: BrowserWindow -> unit + /// the item with the specified id + abstract getMenuItemById: id: string -> MenuItem option + /// Inserts the menuItem to the pos position of the menu. + abstract insert: pos: float * menuItem: MenuItem -> unit + /// Pops up this menu as a context menu in the BrowserWindow. + abstract popup: ?options: PopupOptions -> unit + /// + /// A MenuItem[] array containing the menu's items. + /// + /// Each Menu consists of multiple MenuItems and each MenuItem can have a + /// submenu. + /// + abstract items: ResizeArray with get, set + + type [] MenuStatic = + /// Menu + [] abstract Create: unit -> Menu + /// + /// Generally, the template is an array of options for constructing a MenuItem. + /// The usage can be referenced above. + /// + /// You can also attach other fields to the element of the template and they will + /// become properties of the constructed menu items. + /// + abstract buildFromTemplate: template: Array> -> Menu + /// + /// The application menu, if set, or null, if not set. + /// + /// **Note:** The returned Menu instance doesn't support dynamic addition or + /// removal of menu items. Instance properties can still be dynamically modified. + /// + abstract getApplicationMenu: unit -> Menu option + /// + /// Sends the action to the first responder of application. This is used for + /// emulating default macOS menu behaviors. Usually you would use the role + /// property of a MenuItem. + /// + /// See the macOS Cocoa Event Handling Guide for more information on macOS' native + /// actions. + /// + abstract sendActionToFirstResponder: action: string -> unit + /// + /// Sets menu as the application menu on macOS. On Windows and Linux, the menu + /// will be set as each window's top menu. + /// + /// Also on Windows and Linux, you can use a & in the top-level item name to + /// indicate which letter should get a generated accelerator. For example, using + /// &File for the file menu would result in a generated Alt-F accelerator that + /// opens the associated menu. The indicated character in the button label then gets + /// an underline, and the & character is not displayed on the button label. + /// + /// In order to escape the & character in an item name, add a proceeding &. For + /// example, &&File would result in &File displayed on the button label. + /// + /// Passing null will suppress the default menu. On Windows and Linux, this has + /// the additional effect of removing the menu bar from the window. + /// + /// **Note:** The default menu will be created automatically if the app does not set + /// one. It contains standard items such as File, Edit, View, Window and + /// Help. + /// + abstract setApplicationMenu: menu: Menu option -> unit + + type [] MenuItem = + /// A Accelerator (optional) indicating the item's accelerator, if set. + abstract accelerator: Accelerator option with get, set + /// + /// A Boolean indicating whether the item is checked, this property can be + /// dynamically changed. + /// + /// A checkbox menu item will toggle the checked property on and off when + /// selected. + /// + /// A radio menu item will turn on its checked property when clicked, and will + /// turn off that property for all adjacent items in the same menu. + /// + /// You can add a click function for additional behavior. + /// + abstract ``checked``: bool with get, set + /// + /// A Function that is fired when the MenuItem receives a click event. It can be + /// called with menuItem.click(event, focusedWindow, focusedWebContents). + /// + /// * event KeyboardEvent + /// * focusedWindow BrowserWindow + /// * focusedWebContents WebContents + /// + abstract click: Function with get, set + /// A Number indicating an item's sequential unique id. + abstract commandId: float with get, set + /// + /// A Boolean indicating whether the item is enabled, this property can be + /// dynamically changed. + /// + abstract enabled: bool with get, set + /// A NativeImage | String (optional) indicating the item's icon, if set. + abstract icon: U2 option with get, set + /// + /// A String indicating the item's unique id, this property can be dynamically + /// changed. + /// + abstract id: string with get, set + /// A String indicating the item's visible label. + abstract label: string with get, set + /// A Menu that the item is a part of. + abstract menu: Menu with get, set + /// + /// A Boolean indicating if the accelerator should be registered with the system + /// or just displayed. + /// + /// This property can be dynamically changed. + /// + abstract registerAccelerator: bool with get, set + /// + /// A String (optional) indicating the item's role, if set. Can be undo, redo, + /// cut, copy, paste, pasteAndMatchStyle, delete, selectAll, reload, + /// forceReload, toggleDevTools, resetZoom, zoomIn, zoomOut, + /// toggleSpellChecker, togglefullscreen, window, minimize, close, help, + /// about, services, hide, hideOthers, unhide, quit, startSpeaking, + /// stopSpeaking, zoom, front, appMenu, fileMenu, editMenu, viewMenu, + /// shareMenu, recentDocuments, toggleTabBar, selectNextTab, + /// selectPreviousTab, mergeAllWindows, clearRecentDocuments, + /// moveTabToNewWindow or windowMenu + /// + abstract role: MenuItemRole option with get, set + /// + /// A SharingItem indicating the item to share when the role is shareMenu. + /// + /// This property can be dynamically changed. + /// + abstract sharingItem: SharingItem with get, set + /// A String indicating the item's sublabel. + abstract sublabel: string with get, set + /// A Menu (optional) containing the menu item's submenu, if present. + abstract submenu: Menu option with get, set + /// A String indicating the item's hover text. + abstract toolTip: string with get, set + /// + /// A String indicating the type of the item. Can be normal, separator, + /// submenu, checkbox or radio. + /// + abstract ``type``: MenuItemType with get, set + /// + /// A Boolean indicating whether the item is visible, this property can be + /// dynamically changed. + /// + abstract visible: bool with get, set + + type [] MenuItemStatic = + /// MenuItem + [] abstract Create: options: MenuItemConstructorOptions -> MenuItem + + type [] MessageChannelMain = + inherit NodeEventEmitter + /// A MessagePortMain property. + abstract port1: MessagePortMain with get, set + /// A MessagePortMain property. + abstract port2: MessagePortMain with get, set + + type [] MessageChannelMainStatic = + [] abstract Create: unit -> MessageChannelMain + + type [] MessagePortMain = + inherit NodeEventEmitter + /// Emitted when the remote end of a MessagePortMain object becomes disconnected. + [] abstract on_close: listener: Function -> MessagePortMain + [] abstract once_close: listener: Function -> MessagePortMain + [] abstract addListener_close: listener: Function -> MessagePortMain + [] abstract removeListener_close: listener: Function -> MessagePortMain + /// Emitted when a MessagePortMain object receives a message. + [] abstract on_message: listener: (MessageEvent -> unit) -> MessagePortMain + [] abstract once_message: listener: (MessageEvent -> unit) -> MessagePortMain + [] abstract addListener_message: listener: (MessageEvent -> unit) -> MessagePortMain + [] abstract removeListener_message: listener: (MessageEvent -> unit) -> MessagePortMain + /// Disconnects the port, so it is no longer active. + abstract close: unit -> unit + /// Sends a message from the port, and optionally, transfers ownership of objects to + /// other browsing contexts. + abstract postMessage: message: obj option * ?transfer: ResizeArray -> unit + /// Starts the sending of messages queued on the port. Messages will be queued until + /// this method is called. + abstract start: unit -> unit + + type [] MessagePortMainStatic = + [] abstract Create: unit -> MessagePortMain + + type [] MimeTypedBuffer = + /// Charset of the buffer. + abstract charset: string option with get, set + /// The actual Buffer content. + abstract data: Buffer with get, set + /// MIME type of the buffer. + abstract mimeType: string option with get, set + + type [] MouseInputEvent = + inherit InputEvent + /// The button pressed, can be left, middle, right. + abstract button: MouseInputEventButton option with get, set + abstract clickCount: float option with get, set + abstract globalX: float option with get, set + abstract globalY: float option with get, set + abstract movementX: float option with get, set + abstract movementY: float option with get, set + /// + /// The type of the event, can be mouseDown, mouseUp, mouseEnter, + /// mouseLeave, contextMenu, mouseWheel or mouseMove. + /// + abstract ``type``: MouseInputEventType with get, set + abstract x: float with get, set + abstract y: float with get, set + + type [] MouseWheelInputEvent = + inherit MouseInputEvent + abstract accelerationRatioX: float option with get, set + abstract accelerationRatioY: float option with get, set + abstract canScroll: bool option with get, set + abstract deltaX: float option with get, set + abstract deltaY: float option with get, set + abstract hasPreciseScrollingDeltas: bool option with get, set + /// The type of the event, can be mouseWheel. + abstract ``type``: string with get, set + abstract wheelTicksX: float option with get, set + abstract wheelTicksY: float option with get, set + + type [] NativeImage = + /// Add an image representation for a specific scale factor. This can be used to + /// explicitly add different scale factor representations to an image. This can be + /// called on empty images. + abstract addRepresentation: options: AddRepresentationOptions -> unit + /// The cropped image. + abstract crop: rect: Rectangle -> NativeImage + /// + /// The image's aspect ratio. + /// + /// If scaleFactor is passed, this will return the aspect ratio corresponding to + /// the image representation most closely matching the passed value. + /// + abstract getAspectRatio: ?scaleFactor: float -> float + /// + /// A Buffer that contains the image's raw bitmap pixel data. + /// + /// The difference between getBitmap() and toBitmap() is that getBitmap() does + /// not copy the bitmap data, so you have to use the returned Buffer immediately in + /// current event loop tick; otherwise the data might be changed or destroyed. + /// + abstract getBitmap: ?options: BitmapOptions -> Buffer + /// + /// A Buffer that stores C pointer to underlying native handle of the image. On + /// macOS, a pointer to NSImage instance would be returned. + /// + /// Notice that the returned pointer is a weak pointer to the underlying native + /// image instead of a copy, so you _must_ ensure that the associated nativeImage + /// instance is kept around. + /// + abstract getNativeHandle: unit -> Buffer + /// An array of all scale factors corresponding to representations for a given + /// nativeImage. + abstract getScaleFactors: unit -> ResizeArray + /// + /// If scaleFactor is passed, this will return the size corresponding to the image + /// representation most closely matching the passed value. + /// + abstract getSize: ?scaleFactor: float -> Size + /// Whether the image is empty. + abstract isEmpty: unit -> bool + /// Whether the image is a template image. + abstract isTemplateImage: unit -> bool + /// + /// The resized image. + /// + /// If only the height or the width are specified then the current aspect ratio + /// will be preserved in the resized image. + /// + abstract resize: options: ResizeOptions -> NativeImage + /// Marks the image as a template image. + abstract setTemplateImage: option: bool -> unit + /// A Buffer that contains a copy of the image's raw bitmap pixel data. + abstract toBitmap: ?options: ToBitmapOptions -> Buffer + /// The data URL of the image. + abstract toDataURL: ?options: ToDataURLOptions -> string + /// A Buffer that contains the image's JPEG encoded data. + abstract toJPEG: quality: float -> Buffer + /// A Buffer that contains the image's PNG encoded data. + abstract toPNG: ?options: ToPNGOptions -> Buffer + /// + /// A Boolean property that determines whether the image is considered a template + /// image. + /// + /// Please note that this property only has an effect on macOS. + /// + abstract isMacTemplateImage: bool with get, set + + type [] NativeImageStatic = + [] abstract Create: unit -> NativeImage + /// Creates an empty NativeImage instance. + abstract createEmpty: unit -> NativeImage + /// + /// Creates a new NativeImage instance from buffer that contains the raw bitmap + /// pixel data returned by toBitmap(). The specific format is platform-dependent. + /// + abstract createFromBitmap: buffer: Buffer * options: CreateFromBitmapOptions -> NativeImage + /// + /// Creates a new NativeImage instance from buffer. Tries to decode as PNG or + /// JPEG first. + /// + abstract createFromBuffer: buffer: Buffer * ?options: CreateFromBufferOptions -> NativeImage + /// Creates a new NativeImage instance from dataURL. + abstract createFromDataURL: dataURL: string -> NativeImage + /// + /// Creates a new NativeImage instance from the NSImage that maps to the given + /// image name. See System Icons for a list of possible values. + /// + /// The hslShift is applied to the image with the following rules: + /// + /// * hsl_shift[0] (hue): The absolute hue value for the image - 0 and 1 map to 0 + /// and 360 on the hue color wheel (red). + /// * hsl_shift[1] (saturation): A saturation shift for the image, with the + /// following key values: 0 = remove all color. 0.5 = leave unchanged. 1 = fully + /// saturate the image. + /// * hsl_shift[2] (lightness): A lightness shift for the image, with the + /// following key values: 0 = remove all lightness (make all pixels black). 0.5 = + /// leave unchanged. 1 = full lightness (make all pixels white). + /// + /// This means that [-1, 0, 1] will make the image completely white and `[-1, 1, + /// 0]` will make the image completely black. + /// + /// In some cases, the NSImageName doesn't match its string representation; one + /// example of this is NSFolderImageName, whose string representation would + /// actually be NSFolder. Therefore, you'll need to determine the correct string + /// representation for your image before passing it in. This can be done with the + /// following: + /// + /// `echo -e '#import <Cocoa/Cocoa.h>\nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); + /// }' | clang -otest -x objective-c -framework Cocoa - && ./test` + /// + /// where SYSTEM_IMAGE_NAME should be replaced with any value from this list. + /// + abstract createFromNamedImage: imageName: string * ?hslShift: ResizeArray -> NativeImage + /// + /// Creates a new NativeImage instance from a file located at path. This method + /// returns an empty image if the path does not exist, cannot be read, or is not a + /// valid image. + /// + abstract createFromPath: path: string -> NativeImage + /// fulfilled with the file's thumbnail preview image, which is a NativeImage. + abstract createThumbnailFromPath: path: string * maxSize: Size -> Promise + + type [] NativeTheme = + inherit NodeJS.EventEmitter + /// + /// Emitted when something in the underlying NativeTheme has changed. This normally + /// means that either the value of shouldUseDarkColors, + /// shouldUseHighContrastColors or shouldUseInvertedColorScheme has changed. You + /// will have to check them to determine which one has changed. + /// + [] abstract on_updated: listener: Function -> NativeTheme + [] abstract once_updated: listener: Function -> NativeTheme + [] abstract addListener_updated: listener: Function -> NativeTheme + [] abstract removeListener_updated: listener: Function -> NativeTheme + /// + /// A Boolean for if the OS / Chromium currently has a dark mode enabled or is + /// being instructed to show a dark-style UI. If you want to modify this value you + /// should use themeSource below. + /// + abstract shouldUseDarkColors: bool + /// + /// A Boolean for if the OS / Chromium currently has high-contrast mode enabled or + /// is being instructed to show a high-contrast UI. + /// + abstract shouldUseHighContrastColors: bool + /// + /// A Boolean for if the OS / Chromium currently has an inverted color scheme or + /// is being instructed to use an inverted color scheme. + /// + abstract shouldUseInvertedColorScheme: bool + /// + /// A String property that can be system, light or dark. It is used to + /// override and supersede the value that Chromium has chosen to use internally. + /// + /// Setting this property to system will remove the override and everything will + /// be reset to the OS default. By default themeSource is system. + /// + /// Settings this property to dark will have the following effects: + /// + /// * nativeTheme.shouldUseDarkColors will be true when accessed + /// * Any UI Electron renders on Linux and Windows including context menus, + /// devtools, etc. will use the dark UI. + /// * Any UI the OS renders on macOS including menus, window frames, etc. will use + /// the dark UI. + /// * The prefers-color-scheme CSS query will match dark mode. + /// * The updated event will be emitted + /// + /// Settings this property to light will have the following effects: + /// + /// * nativeTheme.shouldUseDarkColors will be false when accessed + /// * Any UI Electron renders on Linux and Windows including context menus, + /// devtools, etc. will use the light UI. + /// * Any UI the OS renders on macOS including menus, window frames, etc. will use + /// the light UI. + /// * The prefers-color-scheme CSS query will match light mode. + /// * The updated event will be emitted + /// + /// The usage of this property should align with a classic "dark mode" state machine + /// in your application where the user has three options. + /// + /// * Follow OS --> themeSource = 'system' + /// * Dark Mode --> themeSource = 'dark' + /// * Light Mode --> themeSource = 'light' + /// + /// Your application should then always use shouldUseDarkColors to determine what + /// CSS to apply. + /// + abstract themeSource: NativeThemeThemeSource with get, set + + type [] Net = + /// + /// Whether there is currently internet connection. + /// + /// A return value of false is a pretty strong indicator that the user won't be + /// able to connect to remote sites. However, a return value of true is + /// inconclusive; even if some link is up, it is uncertain whether a particular + /// connection attempt to a particular remote site will be successful. + /// + abstract isOnline: unit -> bool + /// + /// Creates a ClientRequest instance using the provided options which are + /// directly forwarded to the ClientRequest constructor. The net.request method + /// would be used to issue both secure and insecure HTTP requests according to the + /// specified protocol scheme in the options object. + /// + abstract request: options: U2 -> ClientRequest + /// + /// A Boolean property. Whether there is currently internet connection. + /// + /// A return value of false is a pretty strong indicator that the user won't be + /// able to connect to remote sites. However, a return value of true is + /// inconclusive; even if some link is up, it is uncertain whether a particular + /// connection attempt to a particular remote site will be successful. + /// + abstract online: bool + + type [] NetLog = + /// + /// resolves when the net log has begun recording. + /// + /// Starts recording network events to path. + /// + abstract startLogging: path: string * ?options: StartLoggingOptions -> Promise + /// resolves when the net log has been flushed to disk. + /// + /// Stops recording network events. If not called, net logging will automatically + /// end when app quits. + abstract stopLogging: unit -> Promise + /// + /// A Boolean property that indicates whether network logs are currently being + /// recorded. + /// + abstract currentlyLogging: bool + + type [] NewWindowWebContentsEvent = + inherit Event + abstract newGuest: BrowserWindow option with get, set + + type [] Notification = + inherit NodeEventEmitter + [] abstract on_action: listener: (Event -> float -> unit) -> Notification + [] abstract once_action: listener: (Event -> float -> unit) -> Notification + [] abstract addListener_action: listener: (Event -> float -> unit) -> Notification + [] abstract removeListener_action: listener: (Event -> float -> unit) -> Notification + /// Emitted when the notification is clicked by the user. + [] abstract on_click: listener: (Event -> unit) -> Notification + [] abstract once_click: listener: (Event -> unit) -> Notification + [] abstract addListener_click: listener: (Event -> unit) -> Notification + [] abstract removeListener_click: listener: (Event -> unit) -> Notification + /// Emitted when the notification is closed by manual intervention from the user. + /// + /// This event is not guaranteed to be emitted in all cases where the notification + /// is closed. + [] abstract on_close: listener: (Event -> unit) -> Notification + [] abstract once_close: listener: (Event -> unit) -> Notification + [] abstract addListener_close: listener: (Event -> unit) -> Notification + [] abstract removeListener_close: listener: (Event -> unit) -> Notification + /// + /// Emitted when an error is encountered while creating and showing the native + /// notification. + /// + [] abstract on_failed: listener: (Event -> string -> unit) -> Notification + [] abstract once_failed: listener: (Event -> string -> unit) -> Notification + [] abstract addListener_failed: listener: (Event -> string -> unit) -> Notification + [] abstract removeListener_failed: listener: (Event -> string -> unit) -> Notification + /// + /// Emitted when the user clicks the "Reply" button on a notification with + /// hasReply: true. + /// + [] abstract on_reply: listener: (Event -> string -> unit) -> Notification + [] abstract once_reply: listener: (Event -> string -> unit) -> Notification + [] abstract addListener_reply: listener: (Event -> string -> unit) -> Notification + [] abstract removeListener_reply: listener: (Event -> string -> unit) -> Notification + /// + /// Emitted when the notification is shown to the user, note this could be fired + /// multiple times as a notification can be shown multiple times through the + /// show() method. + /// + [] abstract on_show: listener: (Event -> unit) -> Notification + [] abstract once_show: listener: (Event -> unit) -> Notification + [] abstract addListener_show: listener: (Event -> unit) -> Notification + [] abstract removeListener_show: listener: (Event -> unit) -> Notification + /// Dismisses the notification. + abstract close: unit -> unit + /// + /// Immediately shows the notification to the user, please note this means unlike + /// the HTML5 Notification implementation, instantiating a new Notification does + /// not immediately show it to the user, you need to call this method before the OS + /// will display it. + /// + /// If the notification has been shown before, this method will dismiss the + /// previously shown notification and create a new one with identical properties. + /// + abstract show: unit -> unit + /// A NotificationAction[] property representing the actions of the notification. + abstract actions: ResizeArray with get, set + /// A String property representing the body of the notification. + abstract body: string with get, set + /// A String property representing the close button text of the notification. + abstract closeButtonText: string with get, set + /// A Boolean property representing whether the notification has a reply action. + abstract hasReply: bool with get, set + /// A String property representing the reply placeholder of the notification. + abstract replyPlaceholder: string with get, set + /// A Boolean property representing whether the notification is silent. + abstract silent: bool with get, set + /// A String property representing the sound of the notification. + abstract sound: string with get, set + /// A String property representing the subtitle of the notification. + abstract subtitle: string with get, set + /// + /// A String property representing the type of timeout duration for the + /// notification. Can be 'default' or 'never'. + /// + /// If timeoutType is set to 'never', the notification never expires. It stays + /// open until closed by the calling API or the user. + /// + abstract timeoutType: NotificationTimeoutType with get, set + /// A String property representing the title of the notification. + abstract title: string with get, set + /// A String property representing the custom Toast XML of the notification. + abstract toastXml: string with get, set + /// + /// A String property representing the urgency level of the notification. Can be + /// 'normal', 'critical', or 'low'. + /// + /// Default is 'low' - see NotifyUrgency for more information. + /// + abstract urgency: NotificationUrgency with get, set + + type [] NotificationStatic = + /// Notification + [] abstract Create: ?options: NotificationConstructorOptions -> Notification + /// Whether or not desktop notifications are supported on the current system + abstract isSupported: unit -> bool + + type [] NotificationAction = + /// The label for the given action. + abstract text: string option with get, set + /// The type of action, can be button. + abstract ``type``: string with get, set + + type [] NotificationResponse = + /// The identifier string of the action that the user selected. + abstract actionIdentifier: string with get, set + /// The delivery date of the notification. + abstract date: float with get, set + /// The unique identifier for this notification request. + abstract identifier: string with get, set + /// A dictionary of custom information associated with the notification. + abstract userInfo: Record with get, set + /// The text entered or chosen by the user. + abstract userText: string option with get, set + + type [] OverlayOptions = + /// + /// The CSS color of the Window Controls Overlay when enabled. Default is the system + /// color. + /// + abstract color: string option with get, set + /// + /// The CSS color of the symbols on the Window Controls Overlay when enabled. + /// Default is the system color. + /// + abstract symbolColor: string option with get, set + + type [] Point = + abstract x: float with get, set + abstract y: float with get, set + + type [] PostBody = + /// + /// The boundary used to separate multiple parts of the message. Only valid when + /// contentType is multipart/form-data. + /// + abstract boundary: string option with get, set + /// + /// The content-type header used for the data. One of + /// application/x-www-form-urlencoded or multipart/form-data. Corresponds to the + /// enctype attribute of the submitted HTML form. + /// + abstract contentType: string with get, set + /// The post data to be sent to the new window. + abstract data: Array> with get, set + + type [] PowerMonitor = + inherit NodeJS.EventEmitter + /// Emitted when the system is about to lock the screen. + [] abstract ``on_lock-screen``: listener: Function -> PowerMonitor + [] abstract ``once_lock-screen``: listener: Function -> PowerMonitor + [] abstract ``addListener_lock-screen``: listener: Function -> PowerMonitor + [] abstract ``removeListener_lock-screen``: listener: Function -> PowerMonitor + /// Emitted when the system changes to AC power. + [] abstract ``on_on-ac``: listener: Function -> PowerMonitor + [] abstract ``once_on-ac``: listener: Function -> PowerMonitor + [] abstract ``addListener_on-ac``: listener: Function -> PowerMonitor + [] abstract ``removeListener_on-ac``: listener: Function -> PowerMonitor + /// Emitted when system changes to battery power. + [] abstract ``on_on-battery``: listener: Function -> PowerMonitor + [] abstract ``once_on-battery``: listener: Function -> PowerMonitor + [] abstract ``addListener_on-battery``: listener: Function -> PowerMonitor + [] abstract ``removeListener_on-battery``: listener: Function -> PowerMonitor + /// Emitted when system is resuming. + [] abstract on_resume: listener: Function -> PowerMonitor + [] abstract once_resume: listener: Function -> PowerMonitor + [] abstract addListener_resume: listener: Function -> PowerMonitor + [] abstract removeListener_resume: listener: Function -> PowerMonitor + /// + /// Emitted when the system is about to reboot or shut down. If the event handler + /// invokes e.preventDefault(), Electron will attempt to delay system shutdown in + /// order for the app to exit cleanly. If e.preventDefault() is called, the app + /// should exit as soon as possible by calling something like app.quit(). + /// + [] abstract on_shutdown: listener: Function -> PowerMonitor + [] abstract once_shutdown: listener: Function -> PowerMonitor + [] abstract addListener_shutdown: listener: Function -> PowerMonitor + [] abstract removeListener_shutdown: listener: Function -> PowerMonitor + /// Emitted when the system is suspending. + [] abstract on_suspend: listener: Function -> PowerMonitor + [] abstract once_suspend: listener: Function -> PowerMonitor + [] abstract addListener_suspend: listener: Function -> PowerMonitor + [] abstract removeListener_suspend: listener: Function -> PowerMonitor + /// Emitted as soon as the systems screen is unlocked. + [] abstract ``on_unlock-screen``: listener: Function -> PowerMonitor + [] abstract ``once_unlock-screen``: listener: Function -> PowerMonitor + [] abstract ``addListener_unlock-screen``: listener: Function -> PowerMonitor + [] abstract ``removeListener_unlock-screen``: listener: Function -> PowerMonitor + /// + /// Emitted when a login session is activated. See documentation for more + /// information. + /// + [] abstract ``on_user-did-become-active``: listener: Function -> PowerMonitor + [] abstract ``once_user-did-become-active``: listener: Function -> PowerMonitor + [] abstract ``addListener_user-did-become-active``: listener: Function -> PowerMonitor + [] abstract ``removeListener_user-did-become-active``: listener: Function -> PowerMonitor + /// + /// Emitted when a login session is deactivated. See documentation for more + /// information. + /// + [] abstract ``on_user-did-resign-active``: listener: Function -> PowerMonitor + [] abstract ``once_user-did-resign-active``: listener: Function -> PowerMonitor + [] abstract ``addListener_user-did-resign-active``: listener: Function -> PowerMonitor + [] abstract ``removeListener_user-did-resign-active``: listener: Function -> PowerMonitor + /// + /// The system's current state. Can be active, idle, locked or unknown. + /// + /// Calculate the system idle state. idleThreshold is the amount of time (in + /// seconds) before considered idle. locked is available on supported systems + /// only. + /// + abstract getSystemIdleState: idleThreshold: float -> PowerMonitorGetSystemIdleState + /// Idle time in seconds + /// + /// Calculate system idle time in seconds. + abstract getSystemIdleTime: unit -> float + /// + /// Whether the system is on battery power. + /// + /// To monitor for changes in this property, use the on-battery and on-ac + /// events. + /// + abstract isOnBatteryPower: unit -> bool + /// + /// A Boolean property. True if the system is on battery power. + /// + /// See powerMonitor.isOnBatteryPower(). + /// + abstract onBatteryPower: bool with get, set + + type [] PowerSaveBlocker = + /// Whether the corresponding powerSaveBlocker has started. + abstract isStarted: id: float -> bool + /// + /// The blocker ID that is assigned to this power blocker. + /// + /// Starts preventing the system from entering lower-power mode. Returns an integer + /// identifying the power save blocker. + /// + /// **Note:** prevent-display-sleep has higher precedence over + /// prevent-app-suspension. Only the highest precedence type takes effect. In + /// other words, prevent-display-sleep always takes precedence over + /// prevent-app-suspension. + /// + /// For example, an API calling A requests for prevent-app-suspension, and another + /// calling B requests for prevent-display-sleep. prevent-display-sleep will be + /// used until B stops its request. After that, prevent-app-suspension is used. + /// + abstract start: ``type``: PowerSaveBlockerStart -> float + /// Stops the specified power save blocker. + abstract stop: id: float -> unit + + type [] PrinterInfo = + /// a longer description of the printer's type. + abstract description: string with get, set + /// the name of the printer as shown in Print Preview. + abstract displayName: string with get, set + /// whether or not a given printer is set as the default printer on the OS. + abstract isDefault: bool with get, set + /// the name of the printer as understood by the OS. + abstract name: string with get, set + /// an object containing a variable number of platform-specific printer information. + abstract options: Options with get, set + /// the current status of the printer. + abstract status: float with get, set + + type [] ProcessMemoryInfo = + /// The amount of memory not shared by other processes, such as JS heap or HTML + /// content in Kilobytes. + abstract ``private``: float with get, set + /// The amount of memory currently pinned to actual physical RAM in Kilobytes. + abstract residentSet: float with get, set + /// The amount of memory shared between processes, typically memory consumed by the + /// Electron code itself in Kilobytes. + abstract shared: float with get, set + + type [] ProcessMetric = + /// CPU usage of the process. + abstract cpu: CPUUsage with get, set + /// + /// Creation time for this process. The time is represented as number of + /// milliseconds since epoch. Since the pid can be reused after a process dies, it + /// is useful to use both the pid and the creationTime to uniquely identify a + /// process. + /// + abstract creationTime: float with get, set + /// One of the following values: + abstract integrityLevel: ProcessMetricIntegrityLevel option with get, set + /// Memory information for the process. + abstract memory: MemoryInfo with get, set + /// + /// The name of the process. Examples for utility: Audio Service, `Content + /// Decryption Module Service, Network Service, Video Capture`, etc. + /// + abstract name: string option with get, set + /// Process id of the process. + abstract pid: float with get, set + /// Whether the process is sandboxed on OS level. + abstract sandboxed: bool option with get, set + /// The non-localized name of the process. + abstract serviceName: string option with get, set + /// Process type. One of the following values: + abstract ``type``: ProcessMetricType with get, set + + type [] Product = + /// The total size of the content, in bytes. + abstract contentLengths: ResizeArray with get, set + /// A string that identifies the version of the content. + abstract contentVersion: string with get, set + /// 3 character code presenting a product's currency based on the ISO 4217 standard. + abstract currencyCode: string with get, set + /// The locale formatted price of the product. + abstract formattedPrice: string with get, set + /// + /// A Boolean value that indicates whether the App Store has downloadable content + /// for this product. true if at least one file has been associated with the + /// product. + /// + abstract isDownloadable: bool with get, set + /// A description of the product. + abstract localizedDescription: string with get, set + /// The name of the product. + abstract localizedTitle: string with get, set + /// The cost of the product in the local currency. + abstract price: float with get, set + /// The string that identifies the product to the Apple App Store. + abstract productIdentifier: string with get, set + + type [] Protocol = + /// + /// Whether the protocol was successfully intercepted + /// + /// Intercepts scheme protocol and uses handler as the protocol's new handler + /// which sends a Buffer as a response. + /// + abstract interceptBufferProtocol: scheme: string * handler: (ProtocolRequest -> (U2 -> unit) -> unit) -> bool + /// + /// Whether the protocol was successfully intercepted + /// + /// Intercepts scheme protocol and uses handler as the protocol's new handler + /// which sends a file as a response. + /// + abstract interceptFileProtocol: scheme: string * handler: (ProtocolRequest -> (U2 -> unit) -> unit) -> bool + /// + /// Whether the protocol was successfully intercepted + /// + /// Intercepts scheme protocol and uses handler as the protocol's new handler + /// which sends a new HTTP request as a response. + /// + abstract interceptHttpProtocol: scheme: string * handler: (ProtocolRequest -> (ProtocolResponse -> unit) -> unit) -> bool + /// + /// Whether the protocol was successfully intercepted + /// + /// Same as protocol.registerStreamProtocol, except that it replaces an existing + /// protocol handler. + /// + abstract interceptStreamProtocol: scheme: string * handler: (ProtocolRequest -> (U2 -> unit) -> unit) -> bool + /// + /// Whether the protocol was successfully intercepted + /// + /// Intercepts scheme protocol and uses handler as the protocol's new handler + /// which sends a String as a response. + /// + abstract interceptStringProtocol: scheme: string * handler: (ProtocolRequest -> (U2 -> unit) -> unit) -> bool + /// Whether scheme is already intercepted. + abstract isProtocolIntercepted: scheme: string -> bool + /// Whether scheme is already registered. + abstract isProtocolRegistered: scheme: string -> bool + /// + /// Whether the protocol was successfully registered + /// + /// Registers a protocol of scheme that will send a Buffer as a response. + /// + /// The usage is the same with registerFileProtocol, except that the callback + /// should be called with either a Buffer object or an object that has the data + /// property. + /// + /// Example: + /// + abstract registerBufferProtocol: scheme: string * handler: (ProtocolRequest -> (U2 -> unit) -> unit) -> bool + /// + /// Whether the protocol was successfully registered + /// + /// Registers a protocol of scheme that will send a file as the response. The + /// handler will be called with request and callback where request is an + /// incoming request for the scheme. + /// + /// To handle the request, the callback should be called with either the file's + /// path or an object that has a path property, e.g. callback(filePath) or + /// callback({ path: filePath }). The filePath must be an absolute path. + /// + /// By default the scheme is treated like http:, which is parsed differently + /// from protocols that follow the "generic URI syntax" like file:. + /// + abstract registerFileProtocol: scheme: string * handler: (ProtocolRequest -> (U2 -> unit) -> unit) -> bool + /// + /// Whether the protocol was successfully registered + /// + /// Registers a protocol of scheme that will send an HTTP request as a response. + /// + /// The usage is the same with registerFileProtocol, except that the callback + /// should be called with an object that has the url property. + /// + abstract registerHttpProtocol: scheme: string * handler: (ProtocolRequest -> (ProtocolResponse -> unit) -> unit) -> bool + /// + /// **Note:** This method can only be used before the ready event of the app + /// module gets emitted and can be called only once. + /// + /// Registers the scheme as standard, secure, bypasses content security policy for + /// resources, allows registering ServiceWorker, supports fetch API, and streaming + /// video/audio. Specify a privilege with the value of true to enable the + /// capability. + /// + /// An example of registering a privileged scheme, that bypasses Content Security + /// Policy: + /// + /// A standard scheme adheres to what RFC 3986 calls generic URI syntax. For example + /// http and https are standard schemes, while file is not. + /// + /// Registering a scheme as standard allows relative and absolute resources to be + /// resolved correctly when served. Otherwise the scheme will behave like the file + /// protocol, but without the ability to resolve relative URLs. + /// + /// For example when you load following page with custom protocol without + /// registering it as standard scheme, the image will not be loaded because + /// non-standard schemes can not recognize relative URLs: + /// + /// Registering a scheme as standard will allow access to files through the + /// FileSystem API. Otherwise the renderer will throw a security error for the + /// scheme. + /// + /// By default web storage apis (localStorage, sessionStorage, webSQL, indexedDB, + /// cookies) are disabled for non standard schemes. So in general if you want to + /// register a custom protocol to replace the http protocol, you have to register + /// it as a standard scheme. + /// + /// Protocols that use streams (http and stream protocols) should set `stream: + /// true. The <video> and <audio>` HTML elements expect protocols to buffer + /// their responses by default. The stream flag configures those elements to + /// correctly expect streaming responses. + /// + abstract registerSchemesAsPrivileged: customSchemes: ResizeArray -> unit + /// + /// Whether the protocol was successfully registered + /// + /// Registers a protocol of scheme that will send a stream as a response. + /// + /// The usage is the same with registerFileProtocol, except that the callback + /// should be called with either a ReadableStream object or an object that has the + /// data property. + /// + /// Example: + /// + /// It is possible to pass any object that implements the readable stream API (emits + /// data/end/error events). For example, here's how a file could be returned: + /// + abstract registerStreamProtocol: scheme: string * handler: (ProtocolRequest -> (U2 -> unit) -> unit) -> bool + /// + /// Whether the protocol was successfully registered + /// + /// Registers a protocol of scheme that will send a String as a response. + /// + /// The usage is the same with registerFileProtocol, except that the callback + /// should be called with either a String or an object that has the data + /// property. + /// + abstract registerStringProtocol: scheme: string * handler: (ProtocolRequest -> (U2 -> unit) -> unit) -> bool + /// + /// Whether the protocol was successfully unintercepted + /// + /// Remove the interceptor installed for scheme and restore its original handler. + /// + abstract uninterceptProtocol: scheme: string -> bool + /// + /// Whether the protocol was successfully unregistered + /// + /// Unregisters the custom protocol of scheme. + /// + abstract unregisterProtocol: scheme: string -> bool + + type [] ProtocolRequest = + abstract headers: Record with get, set + abstract method: string with get, set + abstract referrer: string with get, set + abstract uploadData: ResizeArray option with get, set + abstract url: string with get, set + + type [] ProtocolResponse = + /// The charset of response body, default is "utf-8". + abstract charset: string option with get, set + /// + /// The response body. When returning stream as response, this is a Node.js readable + /// stream representing the response body. When returning Buffer as response, this + /// is a Buffer. When returning String as response, this is a String. This is + /// ignored for other types of responses. + /// + abstract data: U3 option with get, set + /// + /// When assigned, the request will fail with the error number . For the + /// available error numbers you can use, please see the net error list. + /// + abstract error: float option with get, set + /// An object containing the response headers. The keys must be String, and values + /// must be either String or Array of String. + abstract headers: Record>> option with get, set + /// The HTTP method. This is only used for file and URL responses. + abstract method: string option with get, set + /// + /// The MIME type of response body, default is "text/html". Setting mimeType + /// would implicitly set the content-type header in response, but if + /// content-type is already set in headers, the mimeType would be ignored. + /// + abstract mimeType: string option with get, set + /// Path to the file which would be sent as response body. This is only used for + /// file responses. + abstract path: string option with get, set + /// The referrer URL. This is only used for file and URL responses. + abstract referrer: string option with get, set + /// + /// The session used for requesting URL, by default the HTTP request will reuse the + /// current session. Setting session to null would use a random independent + /// session. This is only used for URL responses. + /// + abstract session: Session option with get, set + /// The HTTP response code, default is 200. + abstract statusCode: float option with get, set + /// + /// The data used as upload data. This is only used for URL responses when method + /// is "POST". + /// + abstract uploadData: ProtocolResponseUploadData option with get, set + /// + /// Download the url and pipe the result as response body. This is only used for + /// URL responses. + /// + abstract url: string option with get, set + + type [] ProtocolResponseUploadData = + /// MIME type of the content. + abstract contentType: string with get, set + /// Content to be sent. + abstract data: U2 with get, set + + type [] Rectangle = + /// The height of the rectangle (must be an integer). + abstract height: float with get, set + /// The width of the rectangle (must be an integer). + abstract width: float with get, set + /// The x coordinate of the origin of the rectangle (must be an integer). + abstract x: float with get, set + /// The y coordinate of the origin of the rectangle (must be an integer). + abstract y: float with get, set + + type [] Referrer = + /// + /// Can be default, unsafe-url, no-referrer-when-downgrade, no-referrer, + /// origin, strict-origin-when-cross-origin, same-origin or strict-origin. + /// See the Referrer-Policy spec for more details on the meaning of these values. + /// + abstract policy: ReferrerPolicy with get, set + /// HTTP Referrer URL. + abstract url: string with get, set + + type [] Screen = + inherit NodeJS.EventEmitter + /// Emitted when newDisplay has been added. + [] abstract ``on_display-added``: listener: (Event -> Display -> unit) -> Screen + [] abstract ``once_display-added``: listener: (Event -> Display -> unit) -> Screen + [] abstract ``addListener_display-added``: listener: (Event -> Display -> unit) -> Screen + [] abstract ``removeListener_display-added``: listener: (Event -> Display -> unit) -> Screen + /// + /// Emitted when one or more metrics change in a display. The changedMetrics is + /// an array of strings that describe the changes. Possible changes are bounds, + /// workArea, scaleFactor and rotation. + /// + [] abstract ``on_display-metrics-changed``: listener: (Event -> Display -> ResizeArray -> unit) -> Screen + [] abstract ``once_display-metrics-changed``: listener: (Event -> Display -> ResizeArray -> unit) -> Screen + [] abstract ``addListener_display-metrics-changed``: listener: (Event -> Display -> ResizeArray -> unit) -> Screen + [] abstract ``removeListener_display-metrics-changed``: listener: (Event -> Display -> ResizeArray -> unit) -> Screen + /// Emitted when oldDisplay has been removed. + [] abstract ``on_display-removed``: listener: (Event -> Display -> unit) -> Screen + [] abstract ``once_display-removed``: listener: (Event -> Display -> unit) -> Screen + [] abstract ``addListener_display-removed``: listener: (Event -> Display -> unit) -> Screen + [] abstract ``removeListener_display-removed``: listener: (Event -> Display -> unit) -> Screen + /// + /// Converts a screen DIP point to a screen physical point. The DPI scale is + /// performed relative to the display containing the DIP point. + /// + abstract dipToScreenPoint: point: Point -> Point + /// + /// Converts a screen DIP rect to a screen physical rect. The DPI scale is performed + /// relative to the display nearest to window. If window is null, scaling will + /// be performed to the display nearest to rect. + /// + abstract dipToScreenRect: window: BrowserWindow option * rect: Rectangle -> Rectangle + /// An array of displays that are currently available. + abstract getAllDisplays: unit -> ResizeArray + /// The current absolute position of the mouse pointer. + /// + /// **Note:** The return value is a DIP point, not a screen physical point. + abstract getCursorScreenPoint: unit -> Point + /// The display that most closely intersects the provided bounds. + abstract getDisplayMatching: rect: Rectangle -> Display + /// The display nearest the specified point. + abstract getDisplayNearestPoint: point: Point -> Display + /// The primary display. + abstract getPrimaryDisplay: unit -> Display + /// + /// Converts a screen physical point to a screen DIP point. The DPI scale is + /// performed relative to the display containing the physical point. + /// + abstract screenToDipPoint: point: Point -> Point + /// + /// Converts a screen physical rect to a screen DIP rect. The DPI scale is performed + /// relative to the display nearest to window. If window is null, scaling will + /// be performed to the display nearest to rect. + /// + abstract screenToDipRect: window: BrowserWindow option * rect: Rectangle -> Rectangle + + type [] ScrubberItem = + /// The image to appear in this item. + abstract icon: NativeImage option with get, set + /// The text to appear in this item. + abstract label: string option with get, set + + type [] SegmentedControlSegment = + /// Whether this segment is selectable. Default: true. + abstract enabled: bool option with get, set + /// The image to appear in this segment. + abstract icon: NativeImage option with get, set + /// The text to appear in this segment. + abstract label: string option with get, set + + type [] SerialPort = + /// A stable identifier on Windows that can be used for device permissions. + abstract deviceInstanceId: string option with get, set + /// A string suitable for display to the user for describing this device. + abstract displayName: string with get, set + /// Unique identifier for the port. + abstract portId: string with get, set + /// Name of the port. + abstract portName: string with get, set + /// Optional USB product ID. + abstract productId: string with get, set + /// The USB device serial number. + abstract serialNumber: string with get, set + /// Represents a single serial port on macOS can be enumerated by multiple drivers. + abstract usbDriverName: string option with get, set + /// Optional USB vendor ID. + abstract vendorId: string with get, set + + type [] ServiceWorkerInfo = + /// + /// The virtual ID of the process that this service worker is running in. This is + /// not an OS level PID. This aligns with the ID set used for + /// webContents.getProcessId(). + /// + abstract renderProcessId: float with get, set + /// The base URL that this service worker is active for. + abstract scope: string with get, set + /// The full URL to the script that this service worker runs + abstract scriptUrl: string with get, set + + type [] ServiceWorkers = + inherit NodeEventEmitter + /// Emitted when a service worker logs something to the console. + [] abstract ``on_console-message``: listener: (Event -> MessageDetails -> unit) -> ServiceWorkers + [] abstract ``once_console-message``: listener: (Event -> MessageDetails -> unit) -> ServiceWorkers + [] abstract ``addListener_console-message``: listener: (Event -> MessageDetails -> unit) -> ServiceWorkers + [] abstract ``removeListener_console-message``: listener: (Event -> MessageDetails -> unit) -> ServiceWorkers + /// + /// Emitted when a service worker has been registered. Can occur after a call to + /// navigator.serviceWorker.register('/sw.js') successfully resolves or when a + /// Chrome extension is loaded. + /// + [] abstract ``on_registration-completed``: listener: (Event -> RegistrationCompletedDetails -> unit) -> ServiceWorkers + [] abstract ``once_registration-completed``: listener: (Event -> RegistrationCompletedDetails -> unit) -> ServiceWorkers + [] abstract ``addListener_registration-completed``: listener: (Event -> RegistrationCompletedDetails -> unit) -> ServiceWorkers + [] abstract ``removeListener_registration-completed``: listener: (Event -> RegistrationCompletedDetails -> unit) -> ServiceWorkers + /// A ServiceWorkerInfo object where the keys are the service worker version ID and + /// the values are the information about that service worker. + abstract getAllRunning: unit -> Record + /// Information about this service worker + /// + /// If the service worker does not exist or is not running this method will throw an + /// exception. + abstract getFromVersionID: versionId: float -> ServiceWorkerInfo + + type [] ServiceWorkersStatic = + [] abstract Create: unit -> ServiceWorkers + + type [] Session = + inherit NodeEventEmitter + /// + /// Emitted after an extension is loaded. This occurs whenever an extension is added + /// to the "enabled" set of extensions. This includes: + /// + /// * Extensions being loaded from Session.loadExtension. + /// * Extensions being reloaded: + /// * from a crash. + /// * if the extension requested it (chrome.runtime.reload()). + /// + [] abstract ``on_extension-loaded``: listener: (Event -> Extension -> unit) -> Session + [] abstract ``once_extension-loaded``: listener: (Event -> Extension -> unit) -> Session + [] abstract ``addListener_extension-loaded``: listener: (Event -> Extension -> unit) -> Session + [] abstract ``removeListener_extension-loaded``: listener: (Event -> Extension -> unit) -> Session + /// Emitted after an extension is loaded and all necessary browser state is + /// initialized to support the start of the extension's background page. + [] abstract ``on_extension-ready``: listener: (Event -> Extension -> unit) -> Session + [] abstract ``once_extension-ready``: listener: (Event -> Extension -> unit) -> Session + [] abstract ``addListener_extension-ready``: listener: (Event -> Extension -> unit) -> Session + [] abstract ``removeListener_extension-ready``: listener: (Event -> Extension -> unit) -> Session + /// + /// Emitted after an extension is unloaded. This occurs when + /// Session.removeExtension is called. + /// + [] abstract ``on_extension-unloaded``: listener: (Event -> Extension -> unit) -> Session + [] abstract ``once_extension-unloaded``: listener: (Event -> Extension -> unit) -> Session + [] abstract ``addListener_extension-unloaded``: listener: (Event -> Extension -> unit) -> Session + [] abstract ``removeListener_extension-unloaded``: listener: (Event -> Extension -> unit) -> Session + /// + /// Emitted when a new HID device becomes available. For example, when a new USB + /// device is plugged in. + /// + /// This event will only be emitted after navigator.hid.requestDevice has been + /// called and select-hid-device has fired. + /// + [] abstract ``on_hid-device-added``: listener: (Event -> HidDeviceAddedDetails -> unit) -> Session + [] abstract ``once_hid-device-added``: listener: (Event -> HidDeviceAddedDetails -> unit) -> Session + [] abstract ``addListener_hid-device-added``: listener: (Event -> HidDeviceAddedDetails -> unit) -> Session + [] abstract ``removeListener_hid-device-added``: listener: (Event -> HidDeviceAddedDetails -> unit) -> Session + /// + /// Emitted when a HID device has been removed. For example, this event will fire + /// when a USB device is unplugged. + /// + /// This event will only be emitted after navigator.hid.requestDevice has been + /// called and select-hid-device has fired. + /// + [] abstract ``on_hid-device-removed``: listener: (Event -> HidDeviceRemovedDetails -> unit) -> Session + [] abstract ``once_hid-device-removed``: listener: (Event -> HidDeviceRemovedDetails -> unit) -> Session + [] abstract ``addListener_hid-device-removed``: listener: (Event -> HidDeviceRemovedDetails -> unit) -> Session + [] abstract ``removeListener_hid-device-removed``: listener: (Event -> HidDeviceRemovedDetails -> unit) -> Session + /// Emitted when a render process requests preconnection to a URL, generally due to + /// a resource hint. + [] abstract on_preconnect: listener: (Event -> string -> bool -> unit) -> Session + [] abstract once_preconnect: listener: (Event -> string -> bool -> unit) -> Session + [] abstract addListener_preconnect: listener: (Event -> string -> bool -> unit) -> Session + [] abstract removeListener_preconnect: listener: (Event -> string -> bool -> unit) -> Session + /// + /// Emitted when a HID device needs to be selected when a call to + /// navigator.hid.requestDevice is made. callback should be called with + /// deviceId to be selected; passing no arguments to callback will cancel the + /// request. Additionally, permissioning on navigator.hid can be further managed + /// by using ses.setPermissionCheckHandler(handler) and + /// ses.setDevicePermissionHandler(handler)`. + /// + [] abstract ``on_select-hid-device``: listener: (Event -> SelectHidDeviceDetails -> ((string) option -> unit) -> unit) -> Session + [] abstract ``once_select-hid-device``: listener: (Event -> SelectHidDeviceDetails -> ((string) option -> unit) -> unit) -> Session + [] abstract ``addListener_select-hid-device``: listener: (Event -> SelectHidDeviceDetails -> ((string) option -> unit) -> unit) -> Session + [] abstract ``removeListener_select-hid-device``: listener: (Event -> SelectHidDeviceDetails -> ((string) option -> unit) -> unit) -> Session + /// + /// Emitted when a serial port needs to be selected when a call to + /// navigator.serial.requestPort is made. callback should be called with + /// portId to be selected, passing an empty string to callback will cancel the + /// request. Additionally, permissioning on navigator.serial can be managed by + /// using ses.setPermissionCheckHandler(handler) with the serial permission. + /// + [] abstract ``on_select-serial-port``: listener: (Event -> ResizeArray -> WebContents -> (string -> unit) -> unit) -> Session + [] abstract ``once_select-serial-port``: listener: (Event -> ResizeArray -> WebContents -> (string -> unit) -> unit) -> Session + [] abstract ``addListener_select-serial-port``: listener: (Event -> ResizeArray -> WebContents -> (string -> unit) -> unit) -> Session + [] abstract ``removeListener_select-serial-port``: listener: (Event -> ResizeArray -> WebContents -> (string -> unit) -> unit) -> Session + /// + /// Emitted after navigator.serial.requestPort has been called and + /// select-serial-port has fired if a new serial port becomes available. For + /// example, this event will fire when a new USB device is plugged in. + /// + [] abstract ``on_serial-port-added``: listener: (Event -> SerialPort -> WebContents -> unit) -> Session + [] abstract ``once_serial-port-added``: listener: (Event -> SerialPort -> WebContents -> unit) -> Session + [] abstract ``addListener_serial-port-added``: listener: (Event -> SerialPort -> WebContents -> unit) -> Session + [] abstract ``removeListener_serial-port-added``: listener: (Event -> SerialPort -> WebContents -> unit) -> Session + /// + /// Emitted after navigator.serial.requestPort has been called and + /// select-serial-port has fired if a serial port has been removed. For example, + /// this event will fire when a USB device is unplugged. + /// + [] abstract ``on_serial-port-removed``: listener: (Event -> SerialPort -> WebContents -> unit) -> Session + [] abstract ``once_serial-port-removed``: listener: (Event -> SerialPort -> WebContents -> unit) -> Session + [] abstract ``addListener_serial-port-removed``: listener: (Event -> SerialPort -> WebContents -> unit) -> Session + [] abstract ``removeListener_serial-port-removed``: listener: (Event -> SerialPort -> WebContents -> unit) -> Session + /// Emitted when a hunspell dictionary file starts downloading + [] abstract ``on_spellcheck-dictionary-download-begin``: listener: (Event -> string -> unit) -> Session + [] abstract ``once_spellcheck-dictionary-download-begin``: listener: (Event -> string -> unit) -> Session + [] abstract ``addListener_spellcheck-dictionary-download-begin``: listener: (Event -> string -> unit) -> Session + [] abstract ``removeListener_spellcheck-dictionary-download-begin``: listener: (Event -> string -> unit) -> Session + /// Emitted when a hunspell dictionary file download fails. For details on the + /// failure you should collect a netlog and inspect the download request. + [] abstract ``on_spellcheck-dictionary-download-failure``: listener: (Event -> string -> unit) -> Session + [] abstract ``once_spellcheck-dictionary-download-failure``: listener: (Event -> string -> unit) -> Session + [] abstract ``addListener_spellcheck-dictionary-download-failure``: listener: (Event -> string -> unit) -> Session + [] abstract ``removeListener_spellcheck-dictionary-download-failure``: listener: (Event -> string -> unit) -> Session + /// Emitted when a hunspell dictionary file has been successfully downloaded + [] abstract ``on_spellcheck-dictionary-download-success``: listener: (Event -> string -> unit) -> Session + [] abstract ``once_spellcheck-dictionary-download-success``: listener: (Event -> string -> unit) -> Session + [] abstract ``addListener_spellcheck-dictionary-download-success``: listener: (Event -> string -> unit) -> Session + [] abstract ``removeListener_spellcheck-dictionary-download-success``: listener: (Event -> string -> unit) -> Session + /// Emitted when a hunspell dictionary file has been successfully initialized. This + /// occurs after the file has been downloaded. + [] abstract ``on_spellcheck-dictionary-initialized``: listener: (Event -> string -> unit) -> Session + [] abstract ``once_spellcheck-dictionary-initialized``: listener: (Event -> string -> unit) -> Session + [] abstract ``addListener_spellcheck-dictionary-initialized``: listener: (Event -> string -> unit) -> Session + [] abstract ``removeListener_spellcheck-dictionary-initialized``: listener: (Event -> string -> unit) -> Session + /// + /// Emitted when Electron is about to download item in webContents. + /// + /// Calling event.preventDefault() will cancel the download and item will not be + /// available from next tick of the process. + /// + [] abstract ``on_will-download``: listener: (Event -> DownloadItem -> WebContents -> unit) -> Session + [] abstract ``once_will-download``: listener: (Event -> DownloadItem -> WebContents -> unit) -> Session + [] abstract ``addListener_will-download``: listener: (Event -> DownloadItem -> WebContents -> unit) -> Session + [] abstract ``removeListener_will-download``: listener: (Event -> DownloadItem -> WebContents -> unit) -> Session + /// Whether the word was successfully written to the custom dictionary. This API + /// will not work on non-persistent (in-memory) sessions. + /// + /// **Note:** On macOS and Windows 10 this word will be written to the OS custom + /// dictionary as well + abstract addWordToSpellCheckerDictionary: word: string -> bool + /// Dynamically sets whether to always send credentials for HTTP NTLM or Negotiate + /// authentication. + abstract allowNTLMCredentialsForDomains: domains: string -> unit + /// resolves when the session’s HTTP authentication cache has been cleared. + abstract clearAuthCache: unit -> Promise + /// resolves when the cache clear operation is complete. + /// + /// Clears the session’s HTTP cache. + abstract clearCache: unit -> Promise + /// Resolves when the operation is complete. + /// + /// Clears the host resolver cache. + abstract clearHostResolverCache: unit -> Promise + /// resolves when the storage data has been cleared. + abstract clearStorageData: ?options: ClearStorageDataOptions -> Promise + /// Resolves when all connections are closed. + /// + /// **Note:** It will terminate / fail all requests currently in flight. + abstract closeAllConnections: unit -> Promise + /// + /// Allows resuming cancelled or interrupted downloads from previous Session. + /// The API will generate a DownloadItem that can be accessed with the will-download + /// event. The DownloadItem will not have any WebContents associated with it and + /// the initial state will be interrupted. The download will start only when the + /// resume API is called on the DownloadItem. + /// + abstract createInterruptedDownload: options: CreateInterruptedDownloadOptions -> unit + /// + /// Disables any network emulation already active for the session. Resets to the + /// original network configuration. + /// + abstract disableNetworkEmulation: unit -> unit + /// + /// Initiates a download of the resource at url. The API will generate a + /// DownloadItem that can be accessed with the will-download event. + /// + /// **Note:** This does not perform any security checks that relate to a page's + /// origin, unlike webContents.downloadURL. + /// + abstract downloadURL: url: string -> unit + /// Emulates network with the given configuration for the session. + abstract enableNetworkEmulation: options: EnableNetworkEmulationOptions -> unit + /// Writes any unwritten DOMStorage data to disk. + abstract flushStorageData: unit -> unit + /// + /// Resolves when the all internal states of proxy service is reset and the latest + /// proxy configuration is reapplied if it's already available. The pac script will + /// be fetched from pacScript again if the proxy mode is pac_script. + /// + abstract forceReloadProxyConfig: unit -> Promise + /// + /// A list of all loaded extensions. + /// + /// **Note:** This API cannot be called before the ready event of the app module + /// is emitted. + /// + abstract getAllExtensions: unit -> ResizeArray + /// resolves with blob data. + abstract getBlobData: identifier: string -> Promise + /// the session's current cache size, in bytes. + abstract getCacheSize: unit -> Promise + /// + /// | null - The loaded extension with the given ID. + /// + /// **Note:** This API cannot be called before the ready event of the app module + /// is emitted. + /// + abstract getExtension: extensionId: string -> Extension + /// an array of paths to preload scripts that have been registered. + abstract getPreloads: unit -> ResizeArray + /// + /// An array of language codes the spellchecker is enabled for. If this list is + /// empty the spellchecker will fallback to using en-US. By default on launch if + /// this setting is an empty list Electron will try to populate this setting with + /// the current OS locale. This setting is persisted across restarts. + /// + /// **Note:** On macOS the OS spellchecker is used and has its own list of + /// languages. This API is a no-op on macOS. + /// + abstract getSpellCheckerLanguages: unit -> ResizeArray + /// + /// A String | null indicating the absolute file system path where data for this + /// session is persisted on disk. For in memory sessions this returns null. + /// + abstract getStoragePath: unit -> unit + /// The user agent for this session. + abstract getUserAgent: unit -> string + /// + /// Whether or not this session is a persistent one. The default webContents + /// session of a BrowserWindow is persistent. When creating a session from a + /// partition, session prefixed with persist: will be persistent, while others + /// will be temporary. + /// + abstract isPersistent: unit -> bool + /// Whether the builtin spell checker is enabled. + abstract isSpellCheckerEnabled: unit -> bool + /// An array of all words in app's custom dictionary. Resolves when the full + /// dictionary is loaded from disk. + abstract listWordsInSpellCheckerDictionary: unit -> Promise> + /// + /// resolves when the extension is loaded. + /// + /// This method will raise an exception if the extension could not be loaded. If + /// there are warnings when installing the extension (e.g. if the extension requests + /// an API that Electron does not support) then they will be logged to the console. + /// + /// Note that Electron does not support the full range of Chrome extensions APIs. + /// See Supported Extensions APIs for more details on what is supported. + /// + /// Note that in previous versions of Electron, extensions that were loaded would be + /// remembered for future runs of the application. This is no longer the case: + /// loadExtension must be called on every boot of your app if you want the + /// extension to be loaded. + /// + /// This API does not support loading packed (.crx) extensions. + /// + /// **Note:** This API cannot be called before the ready event of the app module + /// is emitted. + /// + /// **Note:** Loading extensions into in-memory (non-persistent) sessions is not + /// supported and will throw an error. + /// + abstract loadExtension: path: string * ?options: LoadExtensionOptions -> Promise + /// Preconnects the given number of sockets to an origin. + abstract preconnect: options: PreconnectOptions -> unit + /// + /// Unloads an extension. + /// + /// **Note:** This API cannot be called before the ready event of the app module + /// is emitted. + /// + abstract removeExtension: extensionId: string -> unit + /// Whether the word was successfully removed from the custom dictionary. This API + /// will not work on non-persistent (in-memory) sessions. + /// + /// **Note:** On macOS and Windows 10 this word will be removed from the OS custom + /// dictionary as well + abstract removeWordFromSpellCheckerDictionary: word: string -> bool + /// Resolves with the proxy information for url. + abstract resolveProxy: url: string -> Promise + /// + /// Sets the certificate verify proc for session, the proc will be called with + /// proc(request, callback) whenever a server certificate verification is + /// requested. Calling callback(0) accepts the certificate, calling callback(-2) + /// rejects it. + /// + /// Calling setCertificateVerifyProc(null) will revert back to default certificate + /// verify proc. + /// + /// > **NOTE:** The result of this procedure is cached by the network service. + /// + abstract setCertificateVerifyProc: proc: (Request -> (float -> unit) -> unit) option -> unit + /// + /// Sets the handler which can be used to respond to device permission checks for + /// the session. Returning true will allow the device to be permitted and + /// false will reject it. To clear the handler, call + /// setDevicePermissionHandler(null). This handler can be used to provide default + /// permissioning to devices without first calling for permission to devices (eg via + /// navigator.hid.requestDevice). If this handler is not defined, the default + /// device permissions as granted through device selection (eg via + /// navigator.hid.requestDevice) will be used. Additionally, the default behavior + /// of Electron is to store granted device permision through the lifetime of the + /// corresponding WebContents. If longer term storage is needed, a developer can + /// store granted device permissions (eg when handling the select-hid-device + /// event) and then read from that storage with setDevicePermissionHandler. + /// + abstract setDevicePermissionHandler: handler: (DevicePermissionHandlerHandlerDetails -> bool) option -> unit + /// + /// Sets download saving directory. By default, the download directory will be the + /// Downloads under the respective app folder. + /// + abstract setDownloadPath: path: string -> unit + /// + /// Sets the handler which can be used to respond to permission checks for the + /// session. Returning true will allow the permission and false will reject + /// it. Please note that you must also implement setPermissionRequestHandler to + /// get complete permission handling. Most web APIs do a permission check and then + /// make a permission request if the check is denied. To clear the handler, call + /// setPermissionCheckHandler(null). + /// + abstract setPermissionCheckHandler: handler: (WebContents option -> string -> string -> PermissionCheckHandlerHandlerDetails -> bool) option -> unit + /// + /// Sets the handler which can be used to respond to permission requests for the + /// session. Calling callback(true) will allow the permission and + /// callback(false) will reject it. To clear the handler, call + /// setPermissionRequestHandler(null). Please note that you must also implement + /// setPermissionCheckHandler to get complete permission handling. Most web APIs + /// do a permission check and then make a permission request if the check is denied. + /// + abstract setPermissionRequestHandler: handler: (WebContents -> SessionSetPermissionRequestHandler -> (bool -> unit) -> PermissionRequestHandlerHandlerDetails -> unit) option -> unit + /// + /// Adds scripts that will be executed on ALL web contents that are associated with + /// this session just before normal preload scripts run. + /// + abstract setPreloads: preloads: ResizeArray -> unit + /// + /// Resolves when the proxy setting process is complete. + /// + /// Sets the proxy settings. + /// + /// When mode is unspecified, pacScript and proxyRules are provided together, + /// the proxyRules option is ignored and pacScript configuration is applied. + /// + /// You may need ses.closeAllConnections to close currently in flight connections + /// to prevent pooled sockets using previous proxy from being reused by future + /// requests. + /// + /// The proxyRules has to follow the rules below: + /// + /// For example: + /// + /// * http=foopy:80;ftp=foopy2 - Use HTTP proxy foopy:80 for http:// URLs, and + /// HTTP proxy foopy2:80 for ftp:// URLs. + /// * foopy:80 - Use HTTP proxy foopy:80 for all URLs. + /// * foopy:80,bar,direct:// - Use HTTP proxy foopy:80 for all URLs, failing + /// over to bar if foopy:80 is unavailable, and after that using no proxy. + /// * socks4://foopy - Use SOCKS v4 proxy foopy:1080 for all URLs. + /// * http=foopy,socks5://bar.com - Use HTTP proxy foopy for http URLs, and fail + /// over to the SOCKS5 proxy bar.com if foopy is unavailable. + /// * http=foopy,direct:// - Use HTTP proxy foopy for http URLs, and use no + /// proxy if foopy is unavailable. + /// * http=foopy;socks=foopy2 - Use HTTP proxy foopy for http URLs, and use + /// socks4://foopy2 for all other URLs. + /// + /// The proxyBypassRules is a comma separated list of rules described below: + /// + /// * [ URL_SCHEME "://" ] HOSTNAME_PATTERN [ ":" <port> ] + /// + /// Match all hostnames that match the pattern HOSTNAME_PATTERN. + /// + /// Examples: "foobar.com", "*foobar.com", "*.foobar.com", "*foobar.com:99", + /// " + /// * "." HOSTNAME_SUFFIX_PATTERN [ ":" PORT ] + /// + /// Match a particular domain suffix. + /// + /// Examples: ".google.com", ".com", " + /// * [ SCHEME "://" ] IP_LITERAL [ ":" PORT ] + /// + /// Match URLs which are IP address literals. + /// + /// Examples: "127.0.1", "[0:0::1]", "[::1]", " + /// * IP_LITERAL "/" PREFIX_LENGTH_IN_BITS + /// + /// Match any URL that is to an IP literal that falls between the given range. IP + /// range is specified using CIDR notation. + /// + /// Examples: "192.168.1.1/16", "fefe:13::abc/33". + /// * <local> + /// + /// Match local addresses. The meaning of <local> is whether the host matches one + /// of: "127.0.0.1", "::1", "localhost". + /// + abstract setProxy: config: Config -> Promise + /// + /// By default Electron will download hunspell dictionaries from the Chromium CDN. + /// If you want to override this behavior you can use this API to point the + /// dictionary downloader at your own hosted version of the hunspell dictionaries. + /// We publish a hunspell_dictionaries.zip file with each release which contains + /// the files you need to host here, the file server must be **case insensitive** + /// you must upload each file twice, once with the case it has in the ZIP file and + /// once with the filename as all lower case. + /// + /// If the files present in hunspell_dictionaries.zip are available at + /// https://example.com/dictionaries/language-code.bdic then you should call this + /// api with + /// ses.setSpellCheckerDictionaryDownloadURL('https://example.com/dictionaries/'). + /// Please note the trailing slash. The URL to the dictionaries is formed as + /// ${url}${filename}. + /// + /// **Note:** On macOS the OS spellchecker is used and therefore we do not download + /// any dictionary files. This API is a no-op on macOS. + /// + abstract setSpellCheckerDictionaryDownloadURL: url: string -> unit + /// Sets whether to enable the builtin spell checker. + abstract setSpellCheckerEnabled: enable: bool -> unit + /// + /// The built in spellchecker does not automatically detect what language a user is + /// typing in. In order for the spell checker to correctly check their words you + /// must call this API with an array of language codes. You can get the list of + /// supported language codes with the ses.availableSpellCheckerLanguages property. + /// + /// **Note:** On macOS the OS spellchecker is used and will detect your language + /// automatically. This API is a no-op on macOS. + /// + abstract setSpellCheckerLanguages: languages: ResizeArray -> unit + /// Sets the SSL configuration for the session. All subsequent network requests will + /// use the new configuration. Existing network connections (such as WebSocket + /// connections) will not be terminated, but old sockets in the pool will not be + /// reused for new connections. + abstract setSSLConfig: config: SSLConfigConfig -> unit + /// + /// Overrides the userAgent and acceptLanguages for this session. + /// + /// The acceptLanguages must a comma separated ordered list of language codes, for + /// example "en-US,fr,de,ko,zh-CN,ja". + /// + /// This doesn't affect existing WebContents, and each WebContents can use + /// webContents.setUserAgent to override the session-wide user agent. + /// + abstract setUserAgent: userAgent: string * ?acceptLanguages: string -> unit + /// + /// A String[] array which consists of all the known available spell checker + /// languages. Providing a language code to the setSpellCheckerLanguages API that + /// isn't in this array will result in an error. + /// + abstract availableSpellCheckerLanguages: ResizeArray + /// A Cookies object for this session. + abstract cookies: Cookies + /// A NetLog object for this session. + abstract netLog: NetLog + /// A Protocol object for this session. + abstract protocol: Protocol + /// A ServiceWorkers object for this session. + abstract serviceWorkers: ServiceWorkers + /// A Boolean indicating whether builtin spell checker is enabled. + abstract spellCheckerEnabled: bool with get, set + /// + /// A String | null indicating the absolute file system path where data for this + /// session is persisted on disk. For in memory sessions this returns null. + /// + abstract storagePath: string option + /// A WebRequest object for this session. + abstract webRequest: WebRequest + + type [] SessionStatic = + [] abstract Create: unit -> Session + /// + /// A session instance from partition string. When there is an existing Session + /// with the same partition, it will be returned; otherwise a new Session + /// instance will be created with options. + /// + /// If partition starts with persist:, the page will use a persistent session + /// available to all pages in the app with the same partition. if there is no + /// persist: prefix, the page will use an in-memory session. If the partition is + /// empty then default session of the app will be returned. + /// + /// To create a Session with options, you have to ensure the Session with the + /// partition has never been used before. There is no way to change the options + /// of an existing Session object. + /// + abstract fromPartition: partition: string * ?options: FromPartitionOptions -> Session + /// A Session object, the default session object of the app. + abstract defaultSession: Session with get, set + + type [] SharedWorkerInfo = + /// The unique id of the shared worker. + abstract id: string with get, set + /// The url of the shared worker. + abstract url: string with get, set + + type [] ShareMenu = + inherit NodeEventEmitter + /// Closes the context menu in the browserWindow. + abstract closePopup: ?browserWindow: BrowserWindow -> unit + /// Pops up this menu as a context menu in the BrowserWindow. + abstract popup: ?options: PopupOptions -> unit + + type [] ShareMenuStatic = + /// ShareMenu + [] abstract Create: sharingItem: SharingItem -> ShareMenu + + type [] SharingItem = + /// An array of files to share. + abstract filePaths: ResizeArray option with get, set + /// An array of text to share. + abstract texts: ResizeArray option with get, set + /// An array of URLs to share. + abstract urls: ResizeArray option with get, set + + type [] Shell = + /// Play the beep sound. + abstract beep: unit -> unit + /// Open the given external protocol URL in the desktop's default manner. (For + /// example, mailto: URLs in the user's default mail agent). + abstract openExternal: url: string * ?options: OpenExternalOptions -> Promise + /// Resolves with a string containing the error message corresponding to the failure + /// if a failure occurred, otherwise "". + /// + /// Open the given file in the desktop's default manner. + abstract openPath: path: string -> Promise + /// + /// Resolves the shortcut link at shortcutPath. + /// + /// An exception will be thrown when any error happens. + /// + abstract readShortcutLink: shortcutPath: string -> ShortcutDetails + /// Show the given file in a file manager. If possible, select the file. + abstract showItemInFolder: fullPath: string -> unit + /// Resolves when the operation has been completed. Rejects if there was an error + /// while deleting the requested item. + /// + /// This moves a path to the OS-specific trash location (Trash on macOS, Recycle Bin + /// on Windows, and a desktop-environment-specific location on Linux). + abstract trashItem: path: string -> Promise + /// + /// Whether the shortcut was created successfully. + /// + /// Creates or updates a shortcut link at shortcutPath. + /// + abstract writeShortcutLink: shortcutPath: string * operation: ShellWriteShortcutLink * options: ShortcutDetails -> bool + /// + /// Whether the shortcut was created successfully. + /// + /// Creates or updates a shortcut link at shortcutPath. + /// + abstract writeShortcutLink: shortcutPath: string * options: ShortcutDetails -> bool + + type [] ShortcutDetails = + /// The Application User Model ID. Default is empty. + abstract appUserModelId: string option with get, set + /// + /// The arguments to be applied to target when launching from this shortcut. + /// Default is empty. + /// + abstract args: string option with get, set + /// The working directory. Default is empty. + abstract cwd: string option with get, set + /// The description of the shortcut. Default is empty. + abstract description: string option with get, set + /// + /// The path to the icon, can be a DLL or EXE. icon and iconIndex have to be set + /// together. Default is empty, which uses the target's icon. + /// + abstract icon: string option with get, set + /// The resource ID of icon when icon is a DLL or EXE. Default is 0. + abstract iconIndex: float option with get, set + /// The target to launch from this shortcut. + abstract target: string with get, set + /// The Application Toast Activator CLSID. Needed for participating in Action + /// Center. + abstract toastActivatorClsid: string option with get, set + + type [] Size = + abstract height: float with get, set + abstract width: float with get, set + + type [] SystemPreferences = + inherit NodeJS.EventEmitter + [] abstract ``on_accent-color-changed``: listener: (Event -> string -> unit) -> SystemPreferences + [] abstract ``once_accent-color-changed``: listener: (Event -> string -> unit) -> SystemPreferences + [] abstract ``addListener_accent-color-changed``: listener: (Event -> string -> unit) -> SystemPreferences + [] abstract ``removeListener_accent-color-changed``: listener: (Event -> string -> unit) -> SystemPreferences + [] abstract ``on_color-changed``: listener: (Event -> unit) -> SystemPreferences + [] abstract ``once_color-changed``: listener: (Event -> unit) -> SystemPreferences + [] abstract ``addListener_color-changed``: listener: (Event -> unit) -> SystemPreferences + [] abstract ``removeListener_color-changed``: listener: (Event -> unit) -> SystemPreferences + /// **Deprecated:** Should use the new updated event on the nativeTheme module. + [] + [] abstract ``on_high-contrast-color-scheme-changed``: listener: (Event -> bool -> unit) -> SystemPreferences + [] abstract ``once_high-contrast-color-scheme-changed``: listener: (Event -> bool -> unit) -> SystemPreferences + [] abstract ``addListener_high-contrast-color-scheme-changed``: listener: (Event -> bool -> unit) -> SystemPreferences + [] abstract ``removeListener_high-contrast-color-scheme-changed``: listener: (Event -> bool -> unit) -> SystemPreferences + /// **Deprecated:** Should use the new updated event on the nativeTheme module. + [] + [] abstract ``on_inverted-color-scheme-changed``: listener: (Event -> bool -> unit) -> SystemPreferences + [] abstract ``once_inverted-color-scheme-changed``: listener: (Event -> bool -> unit) -> SystemPreferences + [] abstract ``addListener_inverted-color-scheme-changed``: listener: (Event -> bool -> unit) -> SystemPreferences + [] abstract ``removeListener_inverted-color-scheme-changed``: listener: (Event -> bool -> unit) -> SystemPreferences + /// + /// A promise that resolves with true if consent was granted and false if it was + /// denied. If an invalid mediaType is passed, the promise will be rejected. If an + /// access request was denied and later is changed through the System Preferences + /// pane, a restart of the app will be required for the new permissions to take + /// effect. If access has already been requested and denied, it _must_ be changed + /// through the preference pane; an alert will not pop up and the promise will + /// resolve with the existing access status. + /// + /// **Important:** In order to properly leverage this API, you must set the + /// NSMicrophoneUsageDescription and NSCameraUsageDescription strings in your + /// app's Info.plist file. The values for these keys will be used to populate the + /// permission dialogs so that the user will be properly informed as to the purpose + /// of the permission request. See Electron Application Distribution for more + /// information about how to set these in the context of Electron. + /// + /// This user consent was not required until macOS 10.14 Mojave, so this method will + /// always return true if your system is running 10.13 High Sierra or lower. + /// + abstract askForMediaAccess: mediaType: SystemPreferencesAskForMediaAccess -> Promise + /// + /// whether or not this device has the ability to use Touch ID. + /// + /// **NOTE:** This API will return false on macOS systems older than Sierra + /// 10.12.2. + /// + abstract canPromptTouchID: unit -> bool + /// + /// The users current system wide accent color preference in RGBA hexadecimal form. + /// + /// This API is only available on macOS 10.14 Mojave or newer. + /// + abstract getAccentColor: unit -> string + /// + /// * shouldRenderRichAnimation Boolean - Returns true if rich animations should + /// be rendered. Looks at session type (e.g. remote desktop) and accessibility + /// settings to give guidance for heavy animations. + /// * scrollAnimationsEnabledBySystem Boolean - Determines on a per-platform basis + /// whether scroll animations (e.g. produced by home/end key) should be enabled. + /// * prefersReducedMotion Boolean - Determines whether the user desires reduced + /// motion based on platform APIs. + /// + /// Returns an object with system animation settings. + /// + abstract getAnimationSettings: unit -> AnimationSettings + /// + /// | null - Can be dark, light or unknown. + /// + /// Gets the macOS appearance setting that you have declared you want for your + /// application, maps to NSApplication.appearance. You can use the + /// setAppLevelAppearance API to set this value. + /// + [] + abstract getAppLevelAppearance: unit -> SystemPreferencesGetAppLevelAppearance + /// + /// The system color setting in RGB hexadecimal form (#ABCDEF). See the Windows + /// docs and the macOS docs for more details. + /// + /// The following colors are only available on macOS 10.14: find-highlight, + /// selected-content-background, separator, + /// unemphasized-selected-content-background, + /// unemphasized-selected-text-background, and unemphasized-selected-text. + /// + abstract getColor: color: SystemPreferencesGetColor -> string + /// + /// Can be dark, light or unknown. + /// + /// Gets the macOS appearance setting that is currently applied to your application, + /// maps to NSApplication.effectiveAppearance + /// + abstract getEffectiveAppearance: unit -> SystemPreferencesGetAppLevelAppearance + /// + /// Can be not-determined, granted, denied, restricted or unknown. + /// + /// This user consent was not required on macOS 10.13 High Sierra or lower so this + /// method will always return granted. macOS 10.14 Mojave or higher requires + /// consent for microphone and camera access. macOS 10.15 Catalina or higher + /// requires consent for screen access. + /// + /// Windows 10 has a global setting controlling microphone and camera access for + /// all win32 applications. It will always return granted for screen and for all + /// media types on older versions of Windows. + /// + abstract getMediaAccessStatus: mediaType: SystemPreferencesGetMediaAccessStatus -> SystemPreferencesGetMediaAccessStatus2 + /// + /// The standard system color formatted as #RRGGBBAA. + /// + /// Returns one of several standard system colors that automatically adapt to + /// vibrancy and changes in accessibility settings like 'Increase contrast' and + /// 'Reduce transparency'. See Apple Documentation for more details. + /// + abstract getSystemColor: color: SystemPreferencesGetSystemColor -> string + /// + /// The value of key in NSUserDefaults. + /// + /// Some popular key and types are: + /// + /// * AppleInterfaceStyle: string + /// * AppleAquaColorVariant: integer + /// * AppleHighlightColor: string + /// * AppleShowScrollBars: string + /// * NSNavRecentPlaces: array + /// * NSPreferredWebServices: dictionary + /// * NSUserDictionaryReplacementItems: array + /// + abstract getUserDefault: key: string * ``type``: KeyOf -> obj + /// + /// true if DWM composition (Aero Glass) is enabled, and false otherwise. + /// + /// An example of using it to determine if you should create a transparent window or + /// not (transparent windows won't work correctly when DWM composition is disabled): + /// + abstract isAeroGlassEnabled: unit -> bool + /// + /// Whether the system is in Dark Mode. + /// + /// **Deprecated:** Should use the new nativeTheme.shouldUseDarkColors API. + /// + [] + abstract isDarkMode: unit -> bool + /// + /// true if a high contrast theme is active, false otherwise. + /// + /// **Deprecated:** Should use the new nativeTheme.shouldUseHighContrastColors + /// API. + /// + [] + abstract isHighContrastColorScheme: unit -> bool + /// + /// true if an inverted color scheme (a high contrast color scheme with light text + /// and dark backgrounds) is active, false otherwise. + /// + /// **Deprecated:** Should use the new nativeTheme.shouldUseInvertedColorScheme + /// API. + /// + [] + abstract isInvertedColorScheme: unit -> bool + /// Whether the Swipe between pages setting is on. + abstract isSwipeTrackingFromScrollEventsEnabled: unit -> bool + /// + /// true if the current process is a trusted accessibility client and false if + /// it is not. + /// + abstract isTrustedAccessibilityClient: prompt: bool -> bool + /// + /// Posts event as native notifications of macOS. The userInfo is an Object that + /// contains the user information dictionary sent along with the notification. + /// + abstract postLocalNotification: ``event``: string * userInfo: Record -> unit + /// + /// Posts event as native notifications of macOS. The userInfo is an Object that + /// contains the user information dictionary sent along with the notification. + /// + abstract postNotification: ``event``: string * userInfo: Record * ?deliverImmediately: bool -> unit + /// + /// Posts event as native notifications of macOS. The userInfo is an Object that + /// contains the user information dictionary sent along with the notification. + /// + abstract postWorkspaceNotification: ``event``: string * userInfo: Record -> unit + /// + /// resolves if the user has successfully authenticated with Touch ID. + /// + /// This API itself will not protect your user data; rather, it is a mechanism to + /// allow you to do so. Native apps will need to set Access Control Constants like + /// kSecAccessControlUserPresence on their keychain entry so that reading it would + /// auto-prompt for Touch ID biometric consent. This could be done with + /// node-keytar, such that one would store an encryption key with node-keytar + /// and only fetch it if promptTouchID() resolves. + /// + /// **NOTE:** This API will return a rejected Promise on macOS systems older than + /// Sierra 10.12.2. + /// + abstract promptTouchID: reason: string -> Promise + /// Add the specified defaults to your application's NSUserDefaults. + abstract registerDefaults: defaults: Record> -> unit + /// + /// Removes the key in NSUserDefaults. This can be used to restore the default + /// or global value of a key previously set with setUserDefault. + /// + abstract removeUserDefault: key: string -> unit + /// + /// Sets the appearance setting for your application, this should override the + /// system default and override the value of getEffectiveAppearance. + /// + [] + abstract setAppLevelAppearance: appearance: SystemPreferencesSetAppLevelAppearance option -> unit + /// + /// Set the value of key in NSUserDefaults. + /// + /// Note that type should match actual type of value. An exception is thrown if + /// they don't. + /// + /// Some popular key and types are: + /// + /// * ApplePressAndHoldEnabled: boolean + /// + abstract setUserDefault: key: string * ``type``: SystemPreferencesSetUserDefault * value: string -> unit + /// + /// The ID of this subscription + /// + /// Same as subscribeNotification, but uses NSNotificationCenter for local + /// defaults. This is necessary for events such as + /// NSUserDefaultsDidChangeNotification. + /// + abstract subscribeLocalNotification: ``event``: string * callback: (string -> Record -> string -> unit) -> float + /// + /// The ID of this subscription + /// + /// Subscribes to native notifications of macOS, callback will be called with + /// callback(event, userInfo) when the corresponding event happens. The + /// userInfo is an Object that contains the user information dictionary sent along + /// with the notification. The object is the sender of the notification, and only + /// supports NSString values for now. + /// + /// The id of the subscriber is returned, which can be used to unsubscribe the + /// event. + /// + /// Under the hood this API subscribes to NSDistributedNotificationCenter, example + /// values of event are: + /// + /// * AppleInterfaceThemeChangedNotification + /// * AppleAquaColorVariantChanged + /// * AppleColorPreferencesChangedNotification + /// * AppleShowScrollBarsSettingChanged + /// + abstract subscribeNotification: ``event``: string * callback: (string -> Record -> string -> unit) -> float + /// + /// The ID of this subscription + /// + /// Same as subscribeNotification, but uses + /// NSWorkspace.sharedWorkspace.notificationCenter. This is necessary for events + /// such as NSWorkspaceDidActivateApplicationNotification. + /// + abstract subscribeWorkspaceNotification: ``event``: string * callback: (string -> Record -> string -> unit) -> float + /// + /// Same as unsubscribeNotification, but removes the subscriber from + /// NSNotificationCenter. + /// + abstract unsubscribeLocalNotification: id: float -> unit + /// Removes the subscriber with id. + abstract unsubscribeNotification: id: float -> unit + /// + /// Same as unsubscribeNotification, but removes the subscriber from + /// NSWorkspace.sharedWorkspace.notificationCenter. + /// + abstract unsubscribeWorkspaceNotification: id: float -> unit + /// + /// A String property that can be dark, light or unknown. It determines the + /// macOS appearance setting for your application. This maps to values in: + /// NSApplication.appearance. Setting this will override the system default as well + /// as the value of getEffectiveAppearance. + /// + /// Possible values that can be set are dark and light, and possible return + /// values are dark, light, and unknown. + /// + /// This property is only available on macOS 10.14 Mojave or newer. + /// + abstract appLevelAppearance: SystemPreferencesGetAppLevelAppearance with get, set + /// + /// A String property that can be dark, light or unknown. + /// + /// Returns the macOS appearance setting that is currently applied to your + /// application, maps to NSApplication.effectiveAppearance + /// + abstract effectiveAppearance: SystemPreferencesGetAppLevelAppearance + + type [] Task = + /// The command line arguments when program is executed. + abstract arguments: string with get, set + /// Description of this task. + abstract description: string with get, set + /// The icon index in the icon file. If an icon file consists of two or more icons, + /// set this value to identify the icon. If an icon file consists of one icon, this + /// value is 0. + abstract iconIndex: float with get, set + /// + /// The absolute path to an icon to be displayed in a JumpList, which can be an + /// arbitrary resource file that contains an icon. You can usually specify + /// process.execPath to show the icon of the program. + /// + abstract iconPath: string with get, set + /// + /// Path of the program to execute, usually you should specify process.execPath + /// which opens the current program. + /// + abstract program: string with get, set + /// The string to be displayed in a JumpList. + abstract title: string with get, set + /// The working directory. Default is empty. + abstract workingDirectory: string option with get, set + + type [] ThumbarButton = + abstract click: Function with get, set + /// + /// Control specific states and behaviors of the button. By default, it is + /// ['enabled']. + /// + abstract flags: ResizeArray option with get, set + /// The icon showing in thumbnail toolbar. + abstract icon: NativeImage with get, set + /// The text of the button's tooltip. + abstract tooltip: string option with get, set + + type [] TouchBar = + /// + /// A TouchBarItem that will replace the "esc" button on the touch bar when set. + /// Setting to null restores the default "esc" button. Changing this value + /// immediately updates the escape item in the touch bar. + /// + abstract escapeItem: obj with get, set + + type [] TouchBarStatic = + /// TouchBar + [] abstract Create: options: TouchBarConstructorOptions -> TouchBar + /// A typeof TouchBarButton reference to the TouchBarButton class. + abstract TouchBarButton: obj with get, set + /// A typeof TouchBarColorPicker reference to the TouchBarColorPicker class. + abstract TouchBarColorPicker: obj with get, set + /// A typeof TouchBarGroup reference to the TouchBarGroup class. + abstract TouchBarGroup: obj with get, set + /// A typeof TouchBarLabel reference to the TouchBarLabel class. + abstract TouchBarLabel: obj with get, set + /// + /// A typeof TouchBarOtherItemsProxy reference to the TouchBarOtherItemsProxy + /// class. + /// + abstract TouchBarOtherItemsProxy: obj with get, set + /// A typeof TouchBarPopover reference to the TouchBarPopover class. + abstract TouchBarPopover: obj with get, set + /// A typeof TouchBarScrubber reference to the TouchBarScrubber class. + abstract TouchBarScrubber: obj with get, set + /// + /// A typeof TouchBarSegmentedControl reference to the TouchBarSegmentedControl + /// class. + /// + abstract TouchBarSegmentedControl: obj with get, set + /// A typeof TouchBarSlider reference to the TouchBarSlider class. + abstract TouchBarSlider: obj with get, set + /// A typeof TouchBarSpacer reference to the TouchBarSpacer class. + abstract TouchBarSpacer: obj with get, set + + type [] TouchBarButton = + /// + /// A String representing the description of the button to be read by a screen + /// reader. Will only be read by screen readers if no label is set. + /// + abstract accessibilityLabel: string with get, set + /// + /// A String hex code representing the button's current background color. Changing + /// this value immediately updates the button in the touch bar. + /// + abstract backgroundColor: string with get, set + /// A Boolean representing whether the button is in an enabled state. + abstract enabled: bool with get, set + /// + /// A NativeImage representing the button's current icon. Changing this value + /// immediately updates the button in the touch bar. + /// + abstract icon: NativeImage with get, set + /// A String - Can be left, right or overlay. Defaults to overlay. + abstract iconPosition: TouchBarButtonIconPosition with get, set + /// + /// A String representing the button's current text. Changing this value + /// immediately updates the button in the touch bar. + /// + abstract label: string with get, set + + type [] TouchBarButtonStatic = + /// TouchBarButton + [] abstract Create: options: TouchBarButtonConstructorOptions -> TouchBarButton + + type [] TouchBarColorPicker = + inherit NodeEventEmitter + /// + /// A String[] array representing the color picker's available colors to select. + /// Changing this value immediately updates the color picker in the touch bar. + /// + abstract availableColors: ResizeArray with get, set + /// + /// A String hex code representing the color picker's currently selected color. + /// Changing this value immediately updates the color picker in the touch bar. + /// + abstract selectedColor: string with get, set + + type [] TouchBarColorPickerStatic = + /// TouchBarColorPicker + [] abstract Create: options: TouchBarColorPickerConstructorOptions -> TouchBarColorPicker + + type [] TouchBarGroup = + inherit NodeEventEmitter + + type [] TouchBarGroupStatic = + /// TouchBarGroup + [] abstract Create: options: TouchBarGroupConstructorOptions -> TouchBarGroup + + type [] TouchBarLabel = + inherit NodeEventEmitter + /// + /// A String representing the description of the label to be read by a screen + /// reader. + /// + abstract accessibilityLabel: string with get, set + /// + /// A String representing the label's current text. Changing this value + /// immediately updates the label in the touch bar. + /// + abstract label: string with get, set + /// + /// A String hex code representing the label's current text color. Changing this + /// value immediately updates the label in the touch bar. + /// + abstract textColor: string with get, set + + type [] TouchBarLabelStatic = + /// TouchBarLabel + [] abstract Create: options: TouchBarLabelConstructorOptions -> TouchBarLabel + + type [] TouchBarOtherItemsProxy = + inherit NodeEventEmitter + + type [] TouchBarOtherItemsProxyStatic = + /// TouchBarOtherItemsProxy + [] abstract Create: unit -> TouchBarOtherItemsProxy + + type [] TouchBarPopover = + inherit NodeEventEmitter + /// + /// A NativeImage representing the popover's current button icon. Changing this + /// value immediately updates the popover in the touch bar. + /// + abstract icon: NativeImage with get, set + /// + /// A String representing the popover's current button text. Changing this value + /// immediately updates the popover in the touch bar. + /// + abstract label: string with get, set + + type [] TouchBarPopoverStatic = + /// TouchBarPopover + [] abstract Create: options: TouchBarPopoverConstructorOptions -> TouchBarPopover + + type [] TouchBarScrubber = + inherit NodeEventEmitter + /// + /// A Boolean representing whether this scrubber is continuous or not. Updating + /// this value immediately updates the control in the touch bar. + /// + abstract continuous: bool with get, set + /// + /// A ScrubberItem[] array representing the items in this scrubber. Updating this + /// value immediately updates the control in the touch bar. Updating deep properties + /// inside this array **does not update the touch bar**. + /// + abstract items: ResizeArray with get, set + /// + /// A String representing the mode of this scrubber. Updating this value + /// immediately updates the control in the touch bar. Possible values: + /// + /// * fixed - Maps to NSScrubberModeFixed. + /// * free - Maps to NSScrubberModeFree. + /// + abstract mode: TouchBarScrubberMode with get, set + /// + /// A String representing the style that selected items in the scrubber should + /// have. This style is overlayed on top of the scrubber item instead of being + /// placed behind it. Updating this value immediately updates the control in the + /// touch bar. Possible values: + /// + /// * background - Maps to [NSScrubberSelectionStyle roundedBackgroundStyle]. + /// * outline - Maps to [NSScrubberSelectionStyle outlineOverlayStyle]. + /// * none - Removes all styles. + /// + abstract overlayStyle: TouchBarScrubberOverlayStyle with get, set + /// + /// A String representing the style that selected items in the scrubber should + /// have. Updating this value immediately updates the control in the touch bar. + /// Possible values: + /// + /// * background - Maps to [NSScrubberSelectionStyle roundedBackgroundStyle]. + /// * outline - Maps to [NSScrubberSelectionStyle outlineOverlayStyle]. + /// * none - Removes all styles. + /// + abstract selectedStyle: TouchBarScrubberOverlayStyle with get, set + /// + /// A Boolean representing whether to show the left / right selection arrows in + /// this scrubber. Updating this value immediately updates the control in the touch + /// bar. + /// + abstract showArrowButtons: bool with get, set + + type [] TouchBarScrubberStatic = + /// TouchBarScrubber + [] abstract Create: options: TouchBarScrubberConstructorOptions -> TouchBarScrubber + + type [] TouchBarSegmentedControl = + inherit NodeEventEmitter + /// + /// A String representing the current selection mode of the control. Can be + /// single, multiple or buttons. + /// + abstract mode: TouchBarSegmentedControlMode with get, set + /// + /// A SegmentedControlSegment[] array representing the segments in this control. + /// Updating this value immediately updates the control in the touch bar. Updating + /// deep properties inside this array **does not update the touch bar**. + /// + abstract segments: ResizeArray with get, set + /// + /// A String representing the controls current segment style. Updating this value + /// immediately updates the control in the touch bar. + /// + abstract segmentStyle: string with get, set + /// + /// An Integer representing the currently selected segment. Changing this value + /// immediately updates the control in the touch bar. User interaction with the + /// touch bar will update this value automatically. + /// + abstract selectedIndex: float with get, set + + type [] TouchBarSegmentedControlStatic = + /// TouchBarSegmentedControl + [] abstract Create: options: TouchBarSegmentedControlConstructorOptions -> TouchBarSegmentedControl + + type [] TouchBarSlider = + inherit NodeEventEmitter + /// + /// A String representing the slider's current text. Changing this value + /// immediately updates the slider in the touch bar. + /// + abstract label: string with get, set + /// + /// A Number representing the slider's current maximum value. Changing this value + /// immediately updates the slider in the touch bar. + /// + abstract maxValue: float with get, set + /// + /// A Number representing the slider's current minimum value. Changing this value + /// immediately updates the slider in the touch bar. + /// + abstract minValue: float with get, set + /// + /// A Number representing the slider's current value. Changing this value + /// immediately updates the slider in the touch bar. + /// + abstract value: float with get, set + + type [] TouchBarSliderStatic = + /// TouchBarSlider + [] abstract Create: options: TouchBarSliderConstructorOptions -> TouchBarSlider + + type [] TouchBarSpacer = + inherit NodeEventEmitter + /// + /// A String representing the size of the spacer. Can be small, large or + /// flexible. + /// + abstract size: TouchBarSpacerSize with get, set + + type [] TouchBarSpacerStatic = + /// TouchBarSpacer + [] abstract Create: options: TouchBarSpacerConstructorOptions -> TouchBarSpacer + + type [] TraceCategoriesAndOptions = + /// + /// A filter to control what category groups should be traced. A filter can have an + /// optional '-' prefix to exclude category groups that contain a matching category. + /// Having both included and excluded category patterns in the same list is not + /// supported. Examples: test_MyTest*, test_MyTest*,test_OtherStuff, + /// -excluded_category1,-excluded_category2. + /// + abstract categoryFilter: string with get, set + /// + /// Controls what kind of tracing is enabled, it is a comma-delimited sequence of + /// the following strings: record-until-full, record-continuously, + /// trace-to-console, enable-sampling, enable-systrace, e.g. + /// 'record-until-full,enable-sampling'. The first 3 options are trace recording + /// modes and hence mutually exclusive. If more than one trace recording modes + /// appear in the traceOptions string, the last one takes precedence. If none of + /// the trace recording modes are specified, recording mode is record-until-full. + /// The trace option will first be reset to the default option (record_mode set to + /// record-until-full, enable_sampling and enable_systrace set to false) + /// before options parsed from traceOptions are applied on it. + /// + abstract traceOptions: string with get, set + + type [] TraceConfig = + /// if true, filter event data according to a specific list of events that have been + /// manually vetted to not include any PII. See the implementation in Chromium for + /// specifics. + abstract enable_argument_filter: bool option with get, set + /// + /// a list of tracing categories to exclude. Can include glob-like patterns using + /// * at the end of the category name. See tracing categories for the list of + /// categories. + /// + abstract excluded_categories: ResizeArray option with get, set + /// a list of histogram names to report with the trace. + abstract histogram_names: ResizeArray option with get, set + /// + /// a list of tracing categories to include. Can include glob-like patterns using + /// * at the end of the category name. See tracing categories for the list of + /// categories. + /// + abstract included_categories: ResizeArray option with get, set + /// a list of process IDs to include in the trace. If not specified, trace all + /// processes. + abstract included_process_ids: ResizeArray option with get, set + /// + /// if the disabled-by-default-memory-infra category is enabled, this contains + /// optional additional configuration for data collection. See the Chromium + /// memory-infra docs for more information. + /// + abstract memory_dump_config: Record option with get, set + /// + /// Can be record-until-full, record-continuously, record-as-much-as-possible + /// or trace-to-console. Defaults to record-until-full. + /// + abstract recording_mode: TraceConfigRecording_mode option with get, set + /// maximum size of the trace recording buffer in events. + abstract trace_buffer_size_in_events: float option with get, set + /// maximum size of the trace recording buffer in kilobytes. Defaults to 100MB. + abstract trace_buffer_size_in_kb: float option with get, set + + type [] Transaction = + /// The error code if an error occurred while processing the transaction. + abstract errorCode: float with get, set + /// The error message if an error occurred while processing the transaction. + abstract errorMessage: string with get, set + /// The identifier of the restored transaction by the App Store. + abstract originalTransactionIdentifier: string with get, set + abstract payment: Payment with get, set + /// The date the transaction was added to the App Store’s payment queue. + abstract transactionDate: string with get, set + /// A string that uniquely identifies a successful payment transaction. + abstract transactionIdentifier: string with get, set + /// + /// The transaction state, can be purchasing, purchased, failed, restored or + /// deferred. + /// + abstract transactionState: TransactionTransactionState with get, set + + type [] Tray = + inherit NodeEventEmitter + /// Emitted when the tray balloon is clicked. + [] abstract ``on_balloon-click``: listener: Function -> Tray + [] abstract ``once_balloon-click``: listener: Function -> Tray + [] abstract ``addListener_balloon-click``: listener: Function -> Tray + [] abstract ``removeListener_balloon-click``: listener: Function -> Tray + /// + /// Emitted when the tray balloon is closed because of timeout or user manually + /// closes it. + /// + [] abstract ``on_balloon-closed``: listener: Function -> Tray + [] abstract ``once_balloon-closed``: listener: Function -> Tray + [] abstract ``addListener_balloon-closed``: listener: Function -> Tray + [] abstract ``removeListener_balloon-closed``: listener: Function -> Tray + /// Emitted when the tray balloon shows. + [] abstract ``on_balloon-show``: listener: Function -> Tray + [] abstract ``once_balloon-show``: listener: Function -> Tray + [] abstract ``addListener_balloon-show``: listener: Function -> Tray + [] abstract ``removeListener_balloon-show``: listener: Function -> Tray + /// Emitted when the tray icon is clicked. + [] abstract on_click: listener: (KeyboardEvent -> Rectangle -> Point -> unit) -> Tray + [] abstract once_click: listener: (KeyboardEvent -> Rectangle -> Point -> unit) -> Tray + [] abstract addListener_click: listener: (KeyboardEvent -> Rectangle -> Point -> unit) -> Tray + [] abstract removeListener_click: listener: (KeyboardEvent -> Rectangle -> Point -> unit) -> Tray + /// Emitted when the tray icon is double clicked. + [] abstract ``on_double-click``: listener: (KeyboardEvent -> Rectangle -> unit) -> Tray + [] abstract ``once_double-click``: listener: (KeyboardEvent -> Rectangle -> unit) -> Tray + [] abstract ``addListener_double-click``: listener: (KeyboardEvent -> Rectangle -> unit) -> Tray + [] abstract ``removeListener_double-click``: listener: (KeyboardEvent -> Rectangle -> unit) -> Tray + /// Emitted when a drag operation ends on the tray or ends at another location. + [] abstract ``on_drag-end``: listener: Function -> Tray + [] abstract ``once_drag-end``: listener: Function -> Tray + [] abstract ``addListener_drag-end``: listener: Function -> Tray + [] abstract ``removeListener_drag-end``: listener: Function -> Tray + /// Emitted when a drag operation enters the tray icon. + [] abstract ``on_drag-enter``: listener: Function -> Tray + [] abstract ``once_drag-enter``: listener: Function -> Tray + [] abstract ``addListener_drag-enter``: listener: Function -> Tray + [] abstract ``removeListener_drag-enter``: listener: Function -> Tray + /// Emitted when a drag operation exits the tray icon. + [] abstract ``on_drag-leave``: listener: Function -> Tray + [] abstract ``once_drag-leave``: listener: Function -> Tray + [] abstract ``addListener_drag-leave``: listener: Function -> Tray + [] abstract ``removeListener_drag-leave``: listener: Function -> Tray + /// Emitted when any dragged items are dropped on the tray icon. + [] abstract on_drop: listener: Function -> Tray + [] abstract once_drop: listener: Function -> Tray + [] abstract addListener_drop: listener: Function -> Tray + [] abstract removeListener_drop: listener: Function -> Tray + /// Emitted when dragged files are dropped in the tray icon. + [] abstract ``on_drop-files``: listener: (Event -> ResizeArray -> unit) -> Tray + [] abstract ``once_drop-files``: listener: (Event -> ResizeArray -> unit) -> Tray + [] abstract ``addListener_drop-files``: listener: (Event -> ResizeArray -> unit) -> Tray + [] abstract ``removeListener_drop-files``: listener: (Event -> ResizeArray -> unit) -> Tray + /// Emitted when dragged text is dropped in the tray icon. + [] abstract ``on_drop-text``: listener: (Event -> string -> unit) -> Tray + [] abstract ``once_drop-text``: listener: (Event -> string -> unit) -> Tray + [] abstract ``addListener_drop-text``: listener: (Event -> string -> unit) -> Tray + [] abstract ``removeListener_drop-text``: listener: (Event -> string -> unit) -> Tray + /// Emitted when the mouse clicks the tray icon. + [] abstract ``on_mouse-down``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``once_mouse-down``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``addListener_mouse-down``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``removeListener_mouse-down``: listener: (KeyboardEvent -> Point -> unit) -> Tray + /// Emitted when the mouse enters the tray icon. + [] abstract ``on_mouse-enter``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``once_mouse-enter``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``addListener_mouse-enter``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``removeListener_mouse-enter``: listener: (KeyboardEvent -> Point -> unit) -> Tray + /// Emitted when the mouse exits the tray icon. + [] abstract ``on_mouse-leave``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``once_mouse-leave``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``addListener_mouse-leave``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``removeListener_mouse-leave``: listener: (KeyboardEvent -> Point -> unit) -> Tray + /// Emitted when the mouse moves in the tray icon. + [] abstract ``on_mouse-move``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``once_mouse-move``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``addListener_mouse-move``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``removeListener_mouse-move``: listener: (KeyboardEvent -> Point -> unit) -> Tray + /// + /// Emitted when the mouse is released from clicking the tray icon. + /// + /// Note: This will not be emitted if you have set a context menu for your Tray + /// using tray.setContextMenu, as a result of macOS-level constraints. + /// + [] abstract ``on_mouse-up``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``once_mouse-up``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``addListener_mouse-up``: listener: (KeyboardEvent -> Point -> unit) -> Tray + [] abstract ``removeListener_mouse-up``: listener: (KeyboardEvent -> Point -> unit) -> Tray + /// Emitted when the tray icon is right clicked. + [] abstract ``on_right-click``: listener: (KeyboardEvent -> Rectangle -> unit) -> Tray + [] abstract ``once_right-click``: listener: (KeyboardEvent -> Rectangle -> unit) -> Tray + [] abstract ``addListener_right-click``: listener: (KeyboardEvent -> Rectangle -> unit) -> Tray + [] abstract ``removeListener_right-click``: listener: (KeyboardEvent -> Rectangle -> unit) -> Tray + /// Closes an open context menu, as set by tray.setContextMenu(). + abstract closeContextMenu: unit -> unit + /// Destroys the tray icon immediately. + abstract destroy: unit -> unit + /// Displays a tray balloon. + abstract displayBalloon: options: DisplayBalloonOptions -> unit + /// + /// Returns focus to the taskbar notification area. Notification area icons should + /// use this message when they have completed their UI operation. For example, if + /// the icon displays a shortcut menu, but the user presses ESC to cancel it, use + /// tray.focus() to return focus to the notification area. + /// + abstract focus: unit -> unit + /// The bounds of this tray icon as Object. + abstract getBounds: unit -> Rectangle + /// Whether double click events will be ignored. + abstract getIgnoreDoubleClickEvents: unit -> bool + /// the title displayed next to the tray icon in the status bar + abstract getTitle: unit -> string + /// Whether the tray icon is destroyed. + abstract isDestroyed: unit -> bool + /// + /// Pops up the context menu of the tray icon. When menu is passed, the menu + /// will be shown instead of the tray icon's context menu. + /// + /// The position is only available on Windows, and it is (0, 0) by default. + /// + abstract popUpContextMenu: ?menu: Menu * ?position: Point -> unit + /// Removes a tray balloon. + abstract removeBalloon: unit -> unit + /// Sets the context menu for this icon. + abstract setContextMenu: menu: Menu option -> unit + /// + /// Sets the option to ignore double click events. Ignoring these events allows you + /// to detect every individual click of the tray icon. + /// + /// This value is set to false by default. + /// + abstract setIgnoreDoubleClickEvents: ignore: bool -> unit + /// Sets the image associated with this tray icon. + abstract setImage: image: U2 -> unit + /// Sets the image associated with this tray icon when pressed on macOS. + abstract setPressedImage: image: U2 -> unit + /// + /// Sets the title displayed next to the tray icon in the status bar (Support ANSI + /// colors). + /// + abstract setTitle: title: string * ?options: TitleOptions -> unit + /// Sets the hover text for this tray icon. + abstract setToolTip: toolTip: string -> unit + + type [] TrayStatic = + /// Tray + [] abstract Create: image: U2 * ?guid: string -> Tray + + type [] UploadData = + /// UUID of blob data. Use ses.getBlobData method to retrieve the data. + abstract blobUUID: string option with get, set + /// Content being sent. + abstract bytes: Buffer with get, set + /// Path of file being uploaded. + abstract file: string option with get, set + + type [] UploadFile = + /// Path of file to be uploaded. + abstract filePath: string with get, set + /// Number of bytes to read from offset. Defaults to 0. + abstract length: float with get, set + /// Last Modification time in number of seconds since the UNIX epoch. + abstract modificationTime: float with get, set + /// Defaults to 0. + abstract offset: float with get, set + /// file. + abstract ``type``: string with get, set + + type [] UploadRawData = + /// Data to be uploaded. + abstract bytes: Buffer with get, set + /// rawData. + abstract ``type``: string with get, set + + type [] UserDefaultTypes = + abstract array: Array with get, set + abstract boolean: bool with get, set + abstract dictionary: Record with get, set + abstract double: float with get, set + abstract float: float with get, set + abstract integer: float with get, set + abstract string: string with get, set + abstract url: string with get, set + + type [] WebContents = + inherit NodeEventEmitter + /// + /// Emitted before dispatching the keydown and keyup events in the page. Calling + /// event.preventDefault will prevent the page keydown/keyup events and the + /// menu shortcuts. + /// + /// To only prevent the menu shortcuts, use setIgnoreMenuShortcuts: + /// + [] abstract ``on_before-input-event``: listener: (Event -> Input -> unit) -> WebContents + [] abstract ``once_before-input-event``: listener: (Event -> Input -> unit) -> WebContents + [] abstract ``addListener_before-input-event``: listener: (Event -> Input -> unit) -> WebContents + [] abstract ``removeListener_before-input-event``: listener: (Event -> Input -> unit) -> WebContents + /// + /// Emitted when failed to verify the certificate for url. + /// + /// The usage is the same with the certificate-error event of app. + /// + [] abstract ``on_certificate-error``: listener: (Event -> string -> string -> Certificate -> (bool -> unit) -> unit) -> WebContents + [] abstract ``once_certificate-error``: listener: (Event -> string -> string -> Certificate -> (bool -> unit) -> unit) -> WebContents + [] abstract ``addListener_certificate-error``: listener: (Event -> string -> string -> Certificate -> (bool -> unit) -> unit) -> WebContents + [] abstract ``removeListener_certificate-error``: listener: (Event -> string -> string -> Certificate -> (bool -> unit) -> unit) -> WebContents + /// Emitted when the associated window logs a console message. + [] abstract ``on_console-message``: listener: (Event -> float -> string -> float -> string -> unit) -> WebContents + [] abstract ``once_console-message``: listener: (Event -> float -> string -> float -> string -> unit) -> WebContents + [] abstract ``addListener_console-message``: listener: (Event -> float -> string -> float -> string -> unit) -> WebContents + [] abstract ``removeListener_console-message``: listener: (Event -> float -> string -> float -> string -> unit) -> WebContents + /// Emitted when there is a new context menu that needs to be handled. + [] abstract ``on_context-menu``: listener: (Event -> ContextMenuParams -> unit) -> WebContents + [] abstract ``once_context-menu``: listener: (Event -> ContextMenuParams -> unit) -> WebContents + [] abstract ``addListener_context-menu``: listener: (Event -> ContextMenuParams -> unit) -> WebContents + [] abstract ``removeListener_context-menu``: listener: (Event -> ContextMenuParams -> unit) -> WebContents + /// + /// Emitted when the renderer process crashes or is killed. + /// + /// **Deprecated:** This event is superceded by the render-process-gone event + /// which contains more information about why the render process disappeared. It + /// isn't always because it crashed. The killed boolean can be replaced by + /// checking reason === 'killed' when you switch to that event. + /// + [] + [] abstract on_crashed: listener: (Event -> bool -> unit) -> WebContents + [] abstract once_crashed: listener: (Event -> bool -> unit) -> WebContents + [] abstract addListener_crashed: listener: (Event -> bool -> unit) -> WebContents + [] abstract removeListener_crashed: listener: (Event -> bool -> unit) -> WebContents + /// + /// Emitted when the cursor's type changes. The type parameter can be default, + /// crosshair, pointer, text, wait, help, e-resize, n-resize, + /// ne-resize, nw-resize, s-resize, se-resize, sw-resize, w-resize, + /// ns-resize, ew-resize, nesw-resize, nwse-resize, col-resize, + /// row-resize, m-panning, e-panning, n-panning, ne-panning, nw-panning, + /// s-panning, se-panning, sw-panning, w-panning, move, vertical-text, + /// cell, context-menu, alias, progress, nodrop, copy, none, + /// not-allowed, zoom-in, zoom-out, grab, grabbing or custom. + /// + /// If the type parameter is custom, the image parameter will hold the custom + /// cursor image in a NativeImage, and scale, size and hotspot will hold + /// additional information about the custom cursor. + /// + [] abstract ``on_cursor-changed``: listener: (Event -> string -> NativeImage -> float -> Size -> Point -> unit) -> WebContents + [] abstract ``once_cursor-changed``: listener: (Event -> string -> NativeImage -> float -> Size -> Point -> unit) -> WebContents + [] abstract ``addListener_cursor-changed``: listener: (Event -> string -> NativeImage -> float -> Size -> Point -> unit) -> WebContents + [] abstract ``removeListener_cursor-changed``: listener: (Event -> string -> NativeImage -> float -> Size -> Point -> unit) -> WebContents + /// + /// Emitted when desktopCapturer.getSources() is called in the renderer process. + /// Calling event.preventDefault() will make it return empty sources. + /// + [] abstract ``on_desktop-capturer-get-sources``: listener: (Event -> unit) -> WebContents + [] abstract ``once_desktop-capturer-get-sources``: listener: (Event -> unit) -> WebContents + [] abstract ``addListener_desktop-capturer-get-sources``: listener: (Event -> unit) -> WebContents + [] abstract ``removeListener_desktop-capturer-get-sources``: listener: (Event -> unit) -> WebContents + /// Emitted when webContents is destroyed. + [] abstract on_destroyed: listener: Function -> WebContents + [] abstract once_destroyed: listener: Function -> WebContents + [] abstract addListener_destroyed: listener: Function -> WebContents + [] abstract removeListener_destroyed: listener: Function -> WebContents + /// Emitted when DevTools is closed. + [] abstract ``on_devtools-closed``: listener: Function -> WebContents + [] abstract ``once_devtools-closed``: listener: Function -> WebContents + [] abstract ``addListener_devtools-closed``: listener: Function -> WebContents + [] abstract ``removeListener_devtools-closed``: listener: Function -> WebContents + /// Emitted when DevTools is focused / opened. + [] abstract ``on_devtools-focused``: listener: Function -> WebContents + [] abstract ``once_devtools-focused``: listener: Function -> WebContents + [] abstract ``addListener_devtools-focused``: listener: Function -> WebContents + [] abstract ``removeListener_devtools-focused``: listener: Function -> WebContents + /// Emitted when DevTools is opened. + [] abstract ``on_devtools-opened``: listener: Function -> WebContents + [] abstract ``once_devtools-opened``: listener: Function -> WebContents + [] abstract ``addListener_devtools-opened``: listener: Function -> WebContents + [] abstract ``removeListener_devtools-opened``: listener: Function -> WebContents + /// Emitted when the devtools window instructs the webContents to reload + [] abstract ``on_devtools-reload-page``: listener: Function -> WebContents + [] abstract ``once_devtools-reload-page``: listener: Function -> WebContents + [] abstract ``addListener_devtools-reload-page``: listener: Function -> WebContents + [] abstract ``removeListener_devtools-reload-page``: listener: Function -> WebContents + /// Emitted when a <webview> has been attached to this web contents. + [] abstract ``on_did-attach-webview``: listener: (Event -> WebContents -> unit) -> WebContents + [] abstract ``once_did-attach-webview``: listener: (Event -> WebContents -> unit) -> WebContents + [] abstract ``addListener_did-attach-webview``: listener: (Event -> WebContents -> unit) -> WebContents + [] abstract ``removeListener_did-attach-webview``: listener: (Event -> WebContents -> unit) -> WebContents + /// Emitted when a page's theme color changes. This is usually due to encountering a + /// meta tag: + [] abstract ``on_did-change-theme-color``: listener: (Event -> string option -> unit) -> WebContents + [] abstract ``once_did-change-theme-color``: listener: (Event -> string option -> unit) -> WebContents + [] abstract ``addListener_did-change-theme-color``: listener: (Event -> string option -> unit) -> WebContents + [] abstract ``removeListener_did-change-theme-color``: listener: (Event -> string option -> unit) -> WebContents + /// + /// Emitted _after_ successful creation of a window via window.open in the + /// renderer. Not emitted if the creation of the window is canceled from + /// webContents.setWindowOpenHandler. + /// + /// See window.open() for more details and how to use this in conjunction with + /// webContents.setWindowOpenHandler. + /// + [] abstract ``on_did-create-window``: listener: (BrowserWindow -> DidCreateWindowDetails -> unit) -> WebContents + [] abstract ``once_did-create-window``: listener: (BrowserWindow -> DidCreateWindowDetails -> unit) -> WebContents + [] abstract ``addListener_did-create-window``: listener: (BrowserWindow -> DidCreateWindowDetails -> unit) -> WebContents + [] abstract ``removeListener_did-create-window``: listener: (BrowserWindow -> DidCreateWindowDetails -> unit) -> WebContents + /// + /// This event is like did-finish-load but emitted when the load failed. The full + /// list of error codes and their meaning is available here. + /// + [] abstract ``on_did-fail-load``: listener: (Event -> float -> string -> string -> bool -> float -> float -> unit) -> WebContents + [] abstract ``once_did-fail-load``: listener: (Event -> float -> string -> string -> bool -> float -> float -> unit) -> WebContents + [] abstract ``addListener_did-fail-load``: listener: (Event -> float -> string -> string -> bool -> float -> float -> unit) -> WebContents + [] abstract ``removeListener_did-fail-load``: listener: (Event -> float -> string -> string -> bool -> float -> float -> unit) -> WebContents + /// + /// This event is like did-fail-load but emitted when the load was cancelled (e.g. + /// window.stop() was invoked). + /// + [] abstract ``on_did-fail-provisional-load``: listener: (Event -> float -> string -> string -> bool -> float -> float -> unit) -> WebContents + [] abstract ``once_did-fail-provisional-load``: listener: (Event -> float -> string -> string -> bool -> float -> float -> unit) -> WebContents + [] abstract ``addListener_did-fail-provisional-load``: listener: (Event -> float -> string -> string -> bool -> float -> float -> unit) -> WebContents + [] abstract ``removeListener_did-fail-provisional-load``: listener: (Event -> float -> string -> string -> bool -> float -> float -> unit) -> WebContents + /// + /// Emitted when the navigation is done, i.e. the spinner of the tab has stopped + /// spinning, and the onload event was dispatched. + /// + [] abstract ``on_did-finish-load``: listener: Function -> WebContents + [] abstract ``once_did-finish-load``: listener: Function -> WebContents + [] abstract ``addListener_did-finish-load``: listener: Function -> WebContents + [] abstract ``removeListener_did-finish-load``: listener: Function -> WebContents + /// Emitted when a frame has done navigation. + [] abstract ``on_did-frame-finish-load``: listener: (Event -> bool -> float -> float -> unit) -> WebContents + [] abstract ``once_did-frame-finish-load``: listener: (Event -> bool -> float -> float -> unit) -> WebContents + [] abstract ``addListener_did-frame-finish-load``: listener: (Event -> bool -> float -> float -> unit) -> WebContents + [] abstract ``removeListener_did-frame-finish-load``: listener: (Event -> bool -> float -> float -> unit) -> WebContents + /// + /// Emitted when any frame navigation is done. + /// + /// This event is not emitted for in-page navigations, such as clicking anchor links + /// or updating the window.location.hash. Use did-navigate-in-page event for + /// this purpose. + /// + [] abstract ``on_did-frame-navigate``: listener: (Event -> string -> float -> string -> bool -> float -> float -> unit) -> WebContents + [] abstract ``once_did-frame-navigate``: listener: (Event -> string -> float -> string -> bool -> float -> float -> unit) -> WebContents + [] abstract ``addListener_did-frame-navigate``: listener: (Event -> string -> float -> string -> bool -> float -> float -> unit) -> WebContents + [] abstract ``removeListener_did-frame-navigate``: listener: (Event -> string -> float -> string -> bool -> float -> float -> unit) -> WebContents + /// + /// Emitted when a main frame navigation is done. + /// + /// This event is not emitted for in-page navigations, such as clicking anchor links + /// or updating the window.location.hash. Use did-navigate-in-page event for + /// this purpose. + /// + [] abstract ``on_did-navigate``: listener: (Event -> string -> float -> string -> unit) -> WebContents + [] abstract ``once_did-navigate``: listener: (Event -> string -> float -> string -> unit) -> WebContents + [] abstract ``addListener_did-navigate``: listener: (Event -> string -> float -> string -> unit) -> WebContents + [] abstract ``removeListener_did-navigate``: listener: (Event -> string -> float -> string -> unit) -> WebContents + /// + /// Emitted when an in-page navigation happened in any frame. + /// + /// When in-page navigation happens, the page URL changes but does not cause + /// navigation outside of the page. Examples of this occurring are when anchor links + /// are clicked or when the DOM hashchange event is triggered. + /// + [] abstract ``on_did-navigate-in-page``: listener: (Event -> string -> bool -> float -> float -> unit) -> WebContents + [] abstract ``once_did-navigate-in-page``: listener: (Event -> string -> bool -> float -> float -> unit) -> WebContents + [] abstract ``addListener_did-navigate-in-page``: listener: (Event -> string -> bool -> float -> float -> unit) -> WebContents + [] abstract ``removeListener_did-navigate-in-page``: listener: (Event -> string -> bool -> float -> float -> unit) -> WebContents + /// + /// Emitted after a server side redirect occurs during navigation. For example a + /// 302 redirect. + /// + /// This event cannot be prevented, if you want to prevent redirects you should + /// checkout out the will-redirect event above. + /// + [] abstract ``on_did-redirect-navigation``: listener: (Event -> string -> bool -> bool -> float -> float -> unit) -> WebContents + [] abstract ``once_did-redirect-navigation``: listener: (Event -> string -> bool -> bool -> float -> float -> unit) -> WebContents + [] abstract ``addListener_did-redirect-navigation``: listener: (Event -> string -> bool -> bool -> float -> float -> unit) -> WebContents + [] abstract ``removeListener_did-redirect-navigation``: listener: (Event -> string -> bool -> bool -> float -> float -> unit) -> WebContents + /// Corresponds to the points in time when the spinner of the tab started spinning. + [] abstract ``on_did-start-loading``: listener: Function -> WebContents + [] abstract ``once_did-start-loading``: listener: Function -> WebContents + [] abstract ``addListener_did-start-loading``: listener: Function -> WebContents + [] abstract ``removeListener_did-start-loading``: listener: Function -> WebContents + /// + /// Emitted when any frame (including main) starts navigating. isInPlace will be + /// true for in-page navigations. + /// + [] abstract ``on_did-start-navigation``: listener: (Event -> string -> bool -> bool -> float -> float -> unit) -> WebContents + [] abstract ``once_did-start-navigation``: listener: (Event -> string -> bool -> bool -> float -> float -> unit) -> WebContents + [] abstract ``addListener_did-start-navigation``: listener: (Event -> string -> bool -> bool -> float -> float -> unit) -> WebContents + [] abstract ``removeListener_did-start-navigation``: listener: (Event -> string -> bool -> bool -> float -> float -> unit) -> WebContents + /// Corresponds to the points in time when the spinner of the tab stopped spinning. + [] abstract ``on_did-stop-loading``: listener: Function -> WebContents + [] abstract ``once_did-stop-loading``: listener: Function -> WebContents + [] abstract ``addListener_did-stop-loading``: listener: Function -> WebContents + [] abstract ``removeListener_did-stop-loading``: listener: Function -> WebContents + /// Emitted when the document in the given frame is loaded. + [] abstract ``on_dom-ready``: listener: (Event -> unit) -> WebContents + [] abstract ``once_dom-ready``: listener: (Event -> unit) -> WebContents + [] abstract ``addListener_dom-ready``: listener: (Event -> unit) -> WebContents + [] abstract ``removeListener_dom-ready``: listener: (Event -> unit) -> WebContents + /// Emitted when the window enters a full-screen state triggered by HTML API. + [] abstract ``on_enter-html-full-screen``: listener: Function -> WebContents + [] abstract ``once_enter-html-full-screen``: listener: Function -> WebContents + [] abstract ``addListener_enter-html-full-screen``: listener: Function -> WebContents + [] abstract ``removeListener_enter-html-full-screen``: listener: Function -> WebContents + /// Emitted when a result is available for [webContents.findInPage] request. + [] abstract ``on_found-in-page``: listener: (Event -> Result -> unit) -> WebContents + [] abstract ``once_found-in-page``: listener: (Event -> Result -> unit) -> WebContents + [] abstract ``addListener_found-in-page``: listener: (Event -> Result -> unit) -> WebContents + [] abstract ``removeListener_found-in-page``: listener: (Event -> Result -> unit) -> WebContents + /// + /// Emitted when the renderer process sends an asynchronous message via + /// ipcRenderer.send(). + /// + [] abstract ``on_ipc-message``: listener: (Event -> string -> ResizeArray -> unit) -> WebContents + [] abstract ``once_ipc-message``: listener: (Event -> string -> ResizeArray -> unit) -> WebContents + [] abstract ``addListener_ipc-message``: listener: (Event -> string -> ResizeArray -> unit) -> WebContents + [] abstract ``removeListener_ipc-message``: listener: (Event -> string -> ResizeArray -> unit) -> WebContents + /// + /// Emitted when the renderer process sends a synchronous message via + /// ipcRenderer.sendSync(). + /// + [] abstract ``on_ipc-message-sync``: listener: (Event -> string -> ResizeArray -> unit) -> WebContents + [] abstract ``once_ipc-message-sync``: listener: (Event -> string -> ResizeArray -> unit) -> WebContents + [] abstract ``addListener_ipc-message-sync``: listener: (Event -> string -> ResizeArray -> unit) -> WebContents + [] abstract ``removeListener_ipc-message-sync``: listener: (Event -> string -> ResizeArray -> unit) -> WebContents + /// Emitted when the window leaves a full-screen state triggered by HTML API. + [] abstract ``on_leave-html-full-screen``: listener: Function -> WebContents + [] abstract ``once_leave-html-full-screen``: listener: Function -> WebContents + [] abstract ``addListener_leave-html-full-screen``: listener: Function -> WebContents + [] abstract ``removeListener_leave-html-full-screen``: listener: Function -> WebContents + /// + /// Emitted when webContents wants to do basic auth. + /// + /// The usage is the same with the login event of app. + /// + [] abstract on_login: listener: (Event -> AuthenticationResponseDetails -> AuthInfo -> ((string) option -> (string) option -> unit) -> unit) -> WebContents + [] abstract once_login: listener: (Event -> AuthenticationResponseDetails -> AuthInfo -> ((string) option -> (string) option -> unit) -> unit) -> WebContents + [] abstract addListener_login: listener: (Event -> AuthenticationResponseDetails -> AuthInfo -> ((string) option -> (string) option -> unit) -> unit) -> WebContents + [] abstract removeListener_login: listener: (Event -> AuthenticationResponseDetails -> AuthInfo -> ((string) option -> (string) option -> unit) -> unit) -> WebContents + /// Emitted when media is paused or done playing. + [] abstract ``on_media-paused``: listener: Function -> WebContents + [] abstract ``once_media-paused``: listener: Function -> WebContents + [] abstract ``addListener_media-paused``: listener: Function -> WebContents + [] abstract ``removeListener_media-paused``: listener: Function -> WebContents + /// Emitted when media starts playing. + [] abstract ``on_media-started-playing``: listener: Function -> WebContents + [] abstract ``once_media-started-playing``: listener: Function -> WebContents + [] abstract ``addListener_media-started-playing``: listener: Function -> WebContents + [] abstract ``removeListener_media-started-playing``: listener: Function -> WebContents + /// + /// Deprecated in favor of webContents.setWindowOpenHandler. + /// + /// Emitted when the page requests to open a new window for a url. It could be + /// requested by window.open or an external link like <a target='_blank'>. + /// + /// By default a new BrowserWindow will be created for the url. + /// + /// Calling event.preventDefault() will prevent Electron from automatically + /// creating a new BrowserWindow. If you call event.preventDefault() and + /// manually create a new BrowserWindow then you must set event.newGuest to + /// reference the new BrowserWindow instance, failing to do so may result in + /// unexpected behavior. For example: + /// + [] + [] abstract ``on_new-window``: listener: (NewWindowWebContentsEvent -> string -> string -> WebContentsOn_newWindow -> BrowserWindowConstructorOptions -> ResizeArray -> Referrer -> PostBody -> unit) -> WebContents + [] abstract ``once_new-window``: listener: (NewWindowWebContentsEvent -> string -> string -> WebContentsOn_newWindow -> BrowserWindowConstructorOptions -> ResizeArray -> Referrer -> PostBody -> unit) -> WebContents + [] abstract ``addListener_new-window``: listener: (NewWindowWebContentsEvent -> string -> string -> WebContentsOn_newWindow -> BrowserWindowConstructorOptions -> ResizeArray -> Referrer -> PostBody -> unit) -> WebContents + [] abstract ``removeListener_new-window``: listener: (NewWindowWebContentsEvent -> string -> string -> WebContentsOn_newWindow -> BrowserWindowConstructorOptions -> ResizeArray -> Referrer -> PostBody -> unit) -> WebContents + /// Emitted when page receives favicon urls. + [] abstract ``on_page-favicon-updated``: listener: (Event -> ResizeArray -> unit) -> WebContents + [] abstract ``once_page-favicon-updated``: listener: (Event -> ResizeArray -> unit) -> WebContents + [] abstract ``addListener_page-favicon-updated``: listener: (Event -> ResizeArray -> unit) -> WebContents + [] abstract ``removeListener_page-favicon-updated``: listener: (Event -> ResizeArray -> unit) -> WebContents + /// + /// Fired when page title is set during navigation. explicitSet is false when + /// title is synthesized from file url. + /// + [] abstract ``on_page-title-updated``: listener: (Event -> string -> bool -> unit) -> WebContents + [] abstract ``once_page-title-updated``: listener: (Event -> string -> bool -> unit) -> WebContents + [] abstract ``addListener_page-title-updated``: listener: (Event -> string -> bool -> unit) -> WebContents + [] abstract ``removeListener_page-title-updated``: listener: (Event -> string -> bool -> unit) -> WebContents + /// Emitted when a new frame is generated. Only the dirty area is passed in the + /// buffer. + [] abstract on_paint: listener: (Event -> Rectangle -> NativeImage -> unit) -> WebContents + [] abstract once_paint: listener: (Event -> Rectangle -> NativeImage -> unit) -> WebContents + [] abstract addListener_paint: listener: (Event -> Rectangle -> NativeImage -> unit) -> WebContents + [] abstract removeListener_paint: listener: (Event -> Rectangle -> NativeImage -> unit) -> WebContents + /// Emitted when a plugin process has crashed. + [] abstract ``on_plugin-crashed``: listener: (Event -> string -> string -> unit) -> WebContents + [] abstract ``once_plugin-crashed``: listener: (Event -> string -> string -> unit) -> WebContents + [] abstract ``addListener_plugin-crashed``: listener: (Event -> string -> string -> unit) -> WebContents + [] abstract ``removeListener_plugin-crashed``: listener: (Event -> string -> string -> unit) -> WebContents + /// + /// Emitted when the WebContents preferred size has changed. + /// + /// This event will only be emitted when enablePreferredSizeMode is set to true + /// in webPreferences. + /// + [] abstract ``on_preferred-size-changed``: listener: (Event -> Size -> unit) -> WebContents + [] abstract ``once_preferred-size-changed``: listener: (Event -> Size -> unit) -> WebContents + [] abstract ``addListener_preferred-size-changed``: listener: (Event -> Size -> unit) -> WebContents + [] abstract ``removeListener_preferred-size-changed``: listener: (Event -> Size -> unit) -> WebContents + /// + /// Emitted when the preload script preloadPath throws an unhandled exception + /// error. + /// + [] abstract ``on_preload-error``: listener: (Event -> string -> ExceptError -> unit) -> WebContents + [] abstract ``once_preload-error``: listener: (Event -> string -> ExceptError -> unit) -> WebContents + [] abstract ``addListener_preload-error``: listener: (Event -> string -> ExceptError -> unit) -> WebContents + [] abstract ``removeListener_preload-error``: listener: (Event -> string -> ExceptError -> unit) -> WebContents + /// Emitted when the renderer process unexpectedly disappears. This is normally + /// because it was crashed or killed. + [] abstract ``on_render-process-gone``: listener: (Event -> RenderProcessGoneDetails -> unit) -> WebContents + [] abstract ``once_render-process-gone``: listener: (Event -> RenderProcessGoneDetails -> unit) -> WebContents + [] abstract ``addListener_render-process-gone``: listener: (Event -> RenderProcessGoneDetails -> unit) -> WebContents + [] abstract ``removeListener_render-process-gone``: listener: (Event -> RenderProcessGoneDetails -> unit) -> WebContents + /// Emitted when the unresponsive web page becomes responsive again. + [] abstract on_responsive: listener: Function -> WebContents + [] abstract once_responsive: listener: Function -> WebContents + [] abstract addListener_responsive: listener: Function -> WebContents + [] abstract removeListener_responsive: listener: Function -> WebContents + /// + /// Emitted when bluetooth device needs to be selected on call to + /// navigator.bluetooth.requestDevice. To use navigator.bluetooth api + /// webBluetooth should be enabled. If event.preventDefault is not called, first + /// available device will be selected. callback should be called with deviceId + /// to be selected, passing empty string to callback will cancel the request. + /// + [] abstract ``on_select-bluetooth-device``: listener: (Event -> ResizeArray -> (string -> unit) -> unit) -> WebContents + [] abstract ``once_select-bluetooth-device``: listener: (Event -> ResizeArray -> (string -> unit) -> unit) -> WebContents + [] abstract ``addListener_select-bluetooth-device``: listener: (Event -> ResizeArray -> (string -> unit) -> unit) -> WebContents + [] abstract ``removeListener_select-bluetooth-device``: listener: (Event -> ResizeArray -> (string -> unit) -> unit) -> WebContents + /// + /// Emitted when a client certificate is requested. + /// + /// The usage is the same with the select-client-certificate event of app. + /// + [] abstract ``on_select-client-certificate``: listener: (Event -> string -> ResizeArray -> (Certificate -> unit) -> unit) -> WebContents + [] abstract ``once_select-client-certificate``: listener: (Event -> string -> ResizeArray -> (Certificate -> unit) -> unit) -> WebContents + [] abstract ``addListener_select-client-certificate``: listener: (Event -> string -> ResizeArray -> (Certificate -> unit) -> unit) -> WebContents + [] abstract ``removeListener_select-client-certificate``: listener: (Event -> string -> ResizeArray -> (Certificate -> unit) -> unit) -> WebContents + /// Emitted when the web page becomes unresponsive. + [] abstract on_unresponsive: listener: Function -> WebContents + [] abstract once_unresponsive: listener: Function -> WebContents + [] abstract addListener_unresponsive: listener: Function -> WebContents + [] abstract removeListener_unresponsive: listener: Function -> WebContents + /// Emitted when mouse moves over a link or the keyboard moves the focus to a link. + [] abstract ``on_update-target-url``: listener: (Event -> string -> unit) -> WebContents + [] abstract ``once_update-target-url``: listener: (Event -> string -> unit) -> WebContents + [] abstract ``addListener_update-target-url``: listener: (Event -> string -> unit) -> WebContents + [] abstract ``removeListener_update-target-url``: listener: (Event -> string -> unit) -> WebContents + /// + /// Emitted when a <webview>'s web contents is being attached to this web + /// contents. Calling event.preventDefault() will destroy the guest page. + /// + /// This event can be used to configure webPreferences for the webContents of a + /// <webview> before it's loaded, and provides the ability to set settings that + /// can't be set via <webview> attributes. + /// + /// **Note:** The specified preload script option will appear as preloadURL (not + /// preload) in the webPreferences object emitted with this event. + /// + [] abstract ``on_will-attach-webview``: listener: (Event -> WebPreferences -> Record -> unit) -> WebContents + [] abstract ``once_will-attach-webview``: listener: (Event -> WebPreferences -> Record -> unit) -> WebContents + [] abstract ``addListener_will-attach-webview``: listener: (Event -> WebPreferences -> Record -> unit) -> WebContents + [] abstract ``removeListener_will-attach-webview``: listener: (Event -> WebPreferences -> Record -> unit) -> WebContents + /// + /// Emitted when a user or the page wants to start navigation. It can happen when + /// the window.location object is changed or a user clicks a link in the page. + /// + /// This event will not emit when the navigation is started programmatically with + /// APIs like webContents.loadURL and webContents.back. + /// + /// It is also not emitted for in-page navigations, such as clicking anchor links or + /// updating the window.location.hash. Use did-navigate-in-page event for this + /// purpose. + /// + /// Calling event.preventDefault() will prevent the navigation. + /// + [] abstract ``on_will-navigate``: listener: (Event -> string -> unit) -> WebContents + [] abstract ``once_will-navigate``: listener: (Event -> string -> unit) -> WebContents + [] abstract ``addListener_will-navigate``: listener: (Event -> string -> unit) -> WebContents + [] abstract ``removeListener_will-navigate``: listener: (Event -> string -> unit) -> WebContents + /// + /// Emitted when a beforeunload event handler is attempting to cancel a page + /// unload. + /// + /// Calling event.preventDefault() will ignore the beforeunload event handler + /// and allow the page to be unloaded. + /// + /// **Note:** This will be emitted for BrowserViews but will _not_ be respected - + /// this is because we have chosen not to tie the BrowserView lifecycle to its + /// owning BrowserWindow should one exist per the specification. + /// + [] abstract ``on_will-prevent-unload``: listener: (Event -> unit) -> WebContents + [] abstract ``once_will-prevent-unload``: listener: (Event -> unit) -> WebContents + [] abstract ``addListener_will-prevent-unload``: listener: (Event -> unit) -> WebContents + [] abstract ``removeListener_will-prevent-unload``: listener: (Event -> unit) -> WebContents + /// + /// Emitted as a server side redirect occurs during navigation. For example a 302 + /// redirect. + /// + /// This event will be emitted after did-start-navigation and always before the + /// did-redirect-navigation event for the same navigation. + /// + /// Calling event.preventDefault() will prevent the navigation (not just the + /// redirect). + /// + [] abstract ``on_will-redirect``: listener: (Event -> string -> bool -> bool -> float -> float -> unit) -> WebContents + [] abstract ``once_will-redirect``: listener: (Event -> string -> bool -> bool -> float -> float -> unit) -> WebContents + [] abstract ``addListener_will-redirect``: listener: (Event -> string -> bool -> bool -> float -> float -> unit) -> WebContents + [] abstract ``removeListener_will-redirect``: listener: (Event -> string -> bool -> bool -> float -> float -> unit) -> WebContents + /// Emitted when the user is requesting to change the zoom level using the mouse + /// wheel. + [] abstract ``on_zoom-changed``: listener: (Event -> WebContentsOn_zoomChanged -> unit) -> WebContents + [] abstract ``once_zoom-changed``: listener: (Event -> WebContentsOn_zoomChanged -> unit) -> WebContents + [] abstract ``addListener_zoom-changed``: listener: (Event -> WebContentsOn_zoomChanged -> unit) -> WebContents + [] abstract ``removeListener_zoom-changed``: listener: (Event -> WebContentsOn_zoomChanged -> unit) -> WebContents + /// Adds the specified path to DevTools workspace. Must be used after DevTools + /// creation: + abstract addWorkSpace: path: string -> unit + /// + /// Begin subscribing for presentation events and captured frames, the callback + /// will be called with callback(image, dirtyRect) when there is a presentation + /// event. + /// + /// The image is an instance of NativeImage that stores the captured frame. + /// + /// The dirtyRect is an object with x, y, width, height properties that + /// describes which part of the page was repainted. If onlyDirty is set to true, + /// image will only contain the repainted area. onlyDirty defaults to false. + /// + abstract beginFrameSubscription: onlyDirty: bool * callback: (NativeImage -> Rectangle -> unit) -> unit + /// + /// Begin subscribing for presentation events and captured frames, the callback + /// will be called with callback(image, dirtyRect) when there is a presentation + /// event. + /// + /// The image is an instance of NativeImage that stores the captured frame. + /// + /// The dirtyRect is an object with x, y, width, height properties that + /// describes which part of the page was repainted. If onlyDirty is set to true, + /// image will only contain the repainted area. onlyDirty defaults to false. + /// + abstract beginFrameSubscription: callback: (NativeImage -> Rectangle -> unit) -> unit + /// Whether the browser can go back to previous web page. + abstract canGoBack: unit -> bool + /// Whether the browser can go forward to next web page. + abstract canGoForward: unit -> bool + /// Whether the web page can go to offset. + abstract canGoToOffset: offset: float -> bool + /// + /// Resolves with a NativeImage + /// + /// Captures a snapshot of the page within rect. Omitting rect will capture the + /// whole visible page. + /// + abstract capturePage: ?rect: Rectangle -> Promise + /// Clears the navigation history. + abstract clearHistory: unit -> unit + /// Closes the devtools. + abstract closeDevTools: unit -> unit + /// Executes the editing command copy in web page. + abstract copy: unit -> unit + /// Copy the image at the given position to the clipboard. + abstract copyImageAt: x: float * y: float -> unit + /// Executes the editing command cut in web page. + abstract cut: unit -> unit + /// + /// Decrease the capturer count by one. The page will be set to hidden or occluded + /// state when its browser window is hidden or occluded and the capturer count + /// reaches zero. If you want to decrease the hidden capturer count instead you + /// should set stayHidden to true. + /// + abstract decrementCapturerCount: ?stayHidden: bool * ?stayAwake: bool -> unit + /// Executes the editing command delete in web page. + abstract delete: unit -> unit + /// Disable device emulation enabled by webContents.enableDeviceEmulation. + abstract disableDeviceEmulation: unit -> unit + /// + /// Initiates a download of the resource at url without navigating. The + /// will-download event of session will be triggered. + /// + abstract downloadURL: url: string -> unit + /// Enable device emulation with the given parameters. + abstract enableDeviceEmulation: parameters: Parameters -> unit + /// End subscribing for frame presentation events. + abstract endFrameSubscription: unit -> unit + /// + /// A promise that resolves with the result of the executed code or is rejected if + /// the result of the code is a rejected promise. + /// + /// Evaluates code in page. + /// + /// In the browser window some HTML APIs like requestFullScreen can only be + /// invoked by a gesture from the user. Setting userGesture to true will remove + /// this limitation. + /// + /// Code execution will be suspended until web page stop loading. + /// + abstract executeJavaScript: code: string * ?userGesture: bool -> Promise + /// + /// A promise that resolves with the result of the executed code or is rejected if + /// the result of the code is a rejected promise. + /// + /// Works like executeJavaScript but evaluates scripts in an isolated context. + /// + abstract executeJavaScriptInIsolatedWorld: worldId: float * scripts: ResizeArray * ?userGesture: bool -> Promise + /// + /// The request id used for the request. + /// + /// Starts a request to find all matches for the text in the web page. The result + /// of the request can be obtained by subscribing to found-in-page event. + /// + abstract findInPage: text: string * ?options: FindInPageOptions -> float + /// Focuses the web page. + abstract focus: unit -> unit + /// + /// Forcefully terminates the renderer process that is currently hosting this + /// webContents. This will cause the render-process-gone event to be emitted + /// with the reason=killed || reason=crashed. Please note that some webContents + /// share renderer processes and therefore calling this method may also crash the + /// host process for other webContents as well. + /// + /// Calling reload() immediately after calling this method will force the reload + /// to occur in a new process. This should be used when this process is unstable or + /// unusable, for instance in order to recover from the unresponsive event. + /// + abstract forcefullyCrashRenderer: unit -> unit + /// Information about all Shared Workers. + abstract getAllSharedWorkers: unit -> ResizeArray + /// whether or not this WebContents will throttle animations and timers when the + /// page becomes backgrounded. This also affects the Page Visibility API. + abstract getBackgroundThrottling: unit -> bool + /// If *offscreen rendering* is enabled returns the current frame rate. + abstract getFrameRate: unit -> float + /// The operating system pid of the associated renderer process. + abstract getOSProcessId: unit -> float + /// Get the system printer list. + abstract getPrinters: unit -> ResizeArray + /// + /// The Chromium internal pid of the associated renderer. Can be compared to the + /// frameProcessId passed by frame specific navigation events (e.g. + /// did-frame-navigate) + /// + abstract getProcessId: unit -> float + /// The title of the current web page. + abstract getTitle: unit -> string + /// + /// the type of the webContent. Can be backgroundPage, window, browserView, + /// remote, webview or offscreen. + /// + abstract getType: unit -> WebContentsGetType + /// The URL of the current web page. + abstract getURL: unit -> string + /// The user agent for this web page. + abstract getUserAgent: unit -> string + /// Returns the WebRTC IP Handling Policy. + abstract getWebRTCIPHandlingPolicy: unit -> string + /// the current zoom factor. + abstract getZoomFactor: unit -> float + /// the current zoom level. + abstract getZoomLevel: unit -> float + /// Makes the browser go back a web page. + abstract goBack: unit -> unit + /// Makes the browser go forward a web page. + abstract goForward: unit -> unit + /// Navigates browser to the specified absolute web page index. + abstract goToIndex: index: float -> unit + /// Navigates to the specified offset from the "current entry". + abstract goToOffset: offset: float -> unit + /// + /// Increase the capturer count by one. The page is considered visible when its + /// browser window is hidden and the capturer count is non-zero. If you would like + /// the page to stay hidden, you should ensure that stayHidden is set to true. + /// + /// This also affects the Page Visibility API. + /// + abstract incrementCapturerCount: ?size: Size * ?stayHidden: bool * ?stayAwake: bool -> unit + /// + /// A promise that resolves with a key for the inserted CSS that can later be used + /// to remove the CSS via contents.removeInsertedCSS(key). + /// + /// Injects CSS into the current web page and returns a unique key for the inserted + /// stylesheet. + /// + abstract insertCSS: css: string * ?options: InsertCSSOptions -> Promise + /// Inserts text to the focused element. + abstract insertText: text: string -> Promise + /// Starts inspecting element at position (x, y). + abstract inspectElement: x: float * y: float -> unit + /// Opens the developer tools for the service worker context. + abstract inspectServiceWorker: unit -> unit + /// Opens the developer tools for the shared worker context. + abstract inspectSharedWorker: unit -> unit + /// Inspects the shared worker based on its ID. + abstract inspectSharedWorkerById: workerId: string -> unit + /// + /// Schedules a full repaint of the window this web contents is in. + /// + /// If *offscreen rendering* is enabled invalidates the frame and generates a new + /// one through the 'paint' event. + /// + abstract invalidate: unit -> unit + /// Whether this page has been muted. + abstract isAudioMuted: unit -> bool + /// Whether this page is being captured. It returns true when the capturer count is + /// large then 0. + abstract isBeingCaptured: unit -> bool + /// Whether the renderer process has crashed. + abstract isCrashed: unit -> bool + /// Whether audio is currently playing. + abstract isCurrentlyAudible: unit -> bool + /// Whether the web page is destroyed. + abstract isDestroyed: unit -> bool + /// Whether the devtools view is focused . + abstract isDevToolsFocused: unit -> bool + /// Whether the devtools is opened. + abstract isDevToolsOpened: unit -> bool + /// Whether the web page is focused. + abstract isFocused: unit -> bool + /// Whether web page is still loading resources. + abstract isLoading: unit -> bool + /// Whether the main frame (and not just iframes or frames within it) is still + /// loading. + abstract isLoadingMainFrame: unit -> bool + /// Indicates whether *offscreen rendering* is enabled. + abstract isOffscreen: unit -> bool + /// If *offscreen rendering* is enabled returns whether it is currently painting. + abstract isPainting: unit -> bool + /// Whether the web page is waiting for a first-response from the main resource of + /// the page. + abstract isWaitingForResponse: unit -> bool + /// + /// the promise will resolve when the page has finished loading (see + /// did-finish-load), and rejects if the page fails to load (see did-fail-load). + /// + /// Loads the given file in the window, filePath should be a path to an HTML file + /// relative to the root of your application. For instance an app structure like + /// this: + /// + /// Would require code like this + /// + abstract loadFile: filePath: string * ?options: LoadFileOptions -> Promise + /// + /// the promise will resolve when the page has finished loading (see + /// did-finish-load), and rejects if the page fails to load (see did-fail-load). + /// A noop rejection handler is already attached, which avoids unhandled rejection + /// errors. + /// + /// Loads the url in the window. The url must contain the protocol prefix, e.g. + /// the http:// or file://. If the load should bypass http cache then use the + /// pragma header to achieve it. + /// + abstract loadURL: url: string * ?options: LoadURLOptions -> Promise + /// + /// Opens the devtools. + /// + /// When contents is a <webview> tag, the mode would be detach by default, + /// explicitly passing an empty mode can force using last used dock state. + /// + abstract openDevTools: ?options: OpenDevToolsOptions -> unit + /// Executes the editing command paste in web page. + abstract paste: unit -> unit + /// Executes the editing command pasteAndMatchStyle in web page. + abstract pasteAndMatchStyle: unit -> unit + /// + /// Send a message to the renderer process, optionally transferring ownership of + /// zero or more [MessagePortMain][] objects. + /// + /// The transferred MessagePortMain objects will be available in the renderer + /// process by accessing the ports property of the emitted event. When they arrive + /// in the renderer, they will be native DOM MessagePort objects. + /// + /// For example: + /// + abstract postMessage: channel: string * message: obj option * ?transfer: ResizeArray -> unit + /// + /// When a custom pageSize is passed, Chromium attempts to validate platform + /// specific minimum values for width_microns and height_microns. Width and + /// height must both be minimum 353 microns but may be higher on some operating + /// systems. + /// + /// Prints window's web page. When silent is set to true, Electron will pick the + /// system's default printer if deviceName is empty and the default settings for + /// printing. + /// + /// Use page-break-before: always; CSS style to force to print to a new page. + /// + /// Example usage: + /// + abstract print: ?options: WebContentsPrintOptions * ?callback: (bool -> string -> unit) -> unit + /// + /// Resolves with the generated PDF data. + /// + /// Prints window's web page as PDF with Chromium's preview printing custom + /// settings. + /// + /// The landscape will be ignored if @page CSS at-rule is used in the web page. + /// + /// By default, an empty options will be regarded as: + /// + /// Use page-break-before: always; CSS style to force to print to a new page. + /// + /// An example of webContents.printToPDF: + /// + abstract printToPDF: options: PrintToPDFOptions -> Promise + /// Executes the editing command redo in web page. + abstract redo: unit -> unit + /// Reloads the current web page. + abstract reload: unit -> unit + /// Reloads current page and ignores cache. + abstract reloadIgnoringCache: unit -> unit + /// + /// Resolves if the removal was successful. + /// + /// Removes the inserted CSS from the current web page. The stylesheet is identified + /// by its key, which is returned from contents.insertCSS(css). + /// + abstract removeInsertedCSS: key: string -> Promise + /// Removes the specified path from DevTools workspace. + abstract removeWorkSpace: path: string -> unit + /// Executes the editing command replace in web page. + abstract replace: text: string -> unit + /// Executes the editing command replaceMisspelling in web page. + abstract replaceMisspelling: text: string -> unit + /// resolves if the page is saved. + abstract savePage: fullPath: string * saveType: WebContentsSavePage -> Promise + /// Executes the editing command selectAll in web page. + abstract selectAll: unit -> unit + /// + /// Send an asynchronous message to the renderer process via channel, along with + /// arguments. Arguments will be serialized with the Structured Clone Algorithm, + /// just like postMessage, so prototype chains will not be included. Sending + /// Functions, Promises, Symbols, WeakMaps, or WeakSets will throw an exception. + /// + /// > **NOTE**: Sending non-standard JavaScript types such as DOM objects or special + /// Electron objects will throw an exception. + /// + /// The renderer process can handle the message by listening to channel with the + /// ipcRenderer module. + /// + /// An example of sending messages from the main process to the renderer process: + /// + abstract send: channel: string * [] args: obj option[] -> unit + /// + /// Sends an input event to the page. **Note:** The BrowserWindow containing the + /// contents needs to be focused for sendInputEvent() to work. + /// + abstract sendInputEvent: inputEvent: U3 -> unit + /// + /// Send an asynchronous message to a specific frame in a renderer process via + /// channel, along with arguments. Arguments will be serialized with the + /// Structured Clone Algorithm, just like postMessage, so prototype chains will + /// not be included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets + /// will throw an exception. + /// + /// > **NOTE:** Sending non-standard JavaScript types such as DOM objects or special + /// Electron objects will throw an exception. + /// + /// The renderer process can handle the message by listening to channel with the + /// ipcRenderer module. + /// + /// If you want to get the frameId of a given renderer context you should use the + /// webFrame.routingId value. E.g. + /// + /// You can also read frameId from all incoming IPC messages in the main process. + /// + abstract sendToFrame: frameId: U2 * channel: string * [] args: obj option[] -> unit + /// Mute the audio on the current web page. + abstract setAudioMuted: muted: bool -> unit + /// Controls whether or not this WebContents will throttle animations and timers + /// when the page becomes backgrounded. This also affects the Page Visibility API. + abstract setBackgroundThrottling: allowed: bool -> unit + /// + /// Uses the devToolsWebContents as the target WebContents to show devtools. + /// + /// The devToolsWebContents must not have done any navigation, and it should not + /// be used for other purposes after the call. + /// + /// By default Electron manages the devtools by creating an internal WebContents + /// with native view, which developers have very limited control of. With the + /// setDevToolsWebContents method, developers can use any WebContents to show + /// the devtools in it, including BrowserWindow, BrowserView and <webview> + /// tag. + /// + /// Note that closing the devtools does not destroy the devToolsWebContents, it is + /// caller's responsibility to destroy devToolsWebContents. + /// + /// An example of showing devtools in a <webview> tag: + /// + /// An example of showing devtools in a BrowserWindow: + /// + abstract setDevToolsWebContents: devToolsWebContents: WebContents -> unit + /// If *offscreen rendering* is enabled sets the frame rate to the specified number. + /// Only values between 1 and 240 are accepted. + abstract setFrameRate: fps: float -> unit + /// Ignore application menu shortcuts while this web contents is focused. + abstract setIgnoreMenuShortcuts: ignore: bool -> unit + /// Overrides the user agent for this web page. + abstract setUserAgent: userAgent: string -> unit + /// Sets the maximum and minimum pinch-to-zoom level. + /// + /// > **NOTE**: Visual zoom is disabled by default in Electron. To re-enable it, + /// call: + abstract setVisualZoomLevelLimits: minimumLevel: float * maximumLevel: float -> Promise + /// Setting the WebRTC IP handling policy allows you to control which IPs are + /// exposed via WebRTC. See BrowserLeaks for more details. + abstract setWebRTCIPHandlingPolicy: policy: WebContentsSetWebRTCIPHandlingPolicy -> unit + /// + /// Called before creating a window a new window is requested by the renderer, e.g. + /// by window.open(), a link with target="_blank", shift+clicking on a link, or + /// submitting a form with <form target="_blank">. See window.open() for more + /// details and how to use this in conjunction with did-create-window. + /// + abstract setWindowOpenHandler: handler: (HandlerDetails -> U2<{| action: string |}, {| action: string; overrideBrowserWindowOptions: BrowserWindowConstructorOptions option |}>) -> unit + /// Changes the zoom factor to the specified factor. Zoom factor is zoom percent + /// divided by 100, so 300% = 3.0. + /// + /// The factor must be greater than 0.0. + abstract setZoomFactor: factor: float -> unit + /// + /// Changes the zoom level to the specified level. The original size is 0 and each + /// increment above or below represents zooming 20% larger or smaller to default + /// limits of 300% and 50% of original size, respectively. The formula for this is + /// scale := 1.2 ^ level. + /// + /// > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that + /// the zoom level for a specific domain propagates across all instances of windows + /// with the same domain. Differentiating the window URLs will make zoom work + /// per-window. + /// + abstract setZoomLevel: level: float -> unit + /// Shows pop-up dictionary that searches the selected word on the page. + abstract showDefinitionForSelection: unit -> unit + /// + /// Sets the item as dragging item for current drag-drop operation, file is the + /// absolute path of the file to be dragged, and icon is the image showing under + /// the cursor when dragging. + /// + abstract startDrag: item: Item -> unit + /// If *offscreen rendering* is enabled and not painting, start painting. + abstract startPainting: unit -> unit + /// Stops any pending navigation. + abstract stop: unit -> unit + /// Stops any findInPage request for the webContents with the provided action. + abstract stopFindInPage: action: WebContentsStopFindInPage -> unit + /// If *offscreen rendering* is enabled and painting, stop painting. + abstract stopPainting: unit -> unit + /// + /// Indicates whether the snapshot has been created successfully. + /// + /// Takes a V8 heap snapshot and saves it to filePath. + /// + abstract takeHeapSnapshot: filePath: string -> Promise + /// Toggles the developer tools. + abstract toggleDevTools: unit -> unit + /// Executes the editing command undo in web page. + abstract undo: unit -> unit + /// Executes the editing command unselect in web page. + abstract unselect: unit -> unit + /// A Boolean property that determines whether this page is muted. + abstract audioMuted: bool with get, set + /// + /// A Boolean property that determines whether or not this WebContents will + /// throttle animations and timers when the page becomes backgrounded. This also + /// affects the Page Visibility API. + /// + abstract backgroundThrottling: bool with get, set + /// A Debugger instance for this webContents. + abstract debugger: Debugger + /// + /// A WebContents | null property that represents the of DevTools WebContents + /// associated with a given WebContents. + /// + /// **Note:** Users should never store this object because it may become null when + /// the DevTools has been closed. + /// + abstract devToolsWebContents: WebContents option + /// + /// An Integer property that sets the frame rate of the web contents to the + /// specified number. Only values between 1 and 240 are accepted. + /// + /// Only applicable if *offscreen rendering* is enabled. + /// + abstract frameRate: float with get, set + /// A WebContents instance that might own this WebContents. + abstract hostWebContents: WebContents + /// + /// A Integer representing the unique ID of this WebContents. Each ID is unique + /// among all WebContents instances of the entire Electron application. + /// + abstract id: float + /// + /// A WebFrameMain property that represents the top frame of the page's frame + /// hierarchy. + /// + abstract mainFrame: WebFrameMain + /// A Session used by this webContents. + abstract session: Session + /// A String property that determines the user agent for this web page. + abstract userAgent: string with get, set + /// + /// A Number property that determines the zoom factor for this web contents. + /// + /// The zoom factor is the zoom percent divided by 100, so 300% = 3.0. + /// + abstract zoomFactor: float with get, set + /// + /// A Number property that determines the zoom level for this web contents. + /// + /// The original size is 0 and each increment above or below represents zooming 20% + /// larger or smaller to default limits of 300% and 50% of original size, + /// respectively. The formula for this is scale := 1.2 ^ level. + /// + abstract zoomLevel: float with get, set + + type [] WebContentsStatic = + [] abstract Create: unit -> WebContents + /// + /// | undefined - A WebContents instance with the given TargetID, or undefined if + /// there is no WebContents associated with the given TargetID. + /// + /// When communicating with the Chrome DevTools Protocol, it can be useful to lookup + /// a WebContents instance based on its assigned TargetID. + /// + abstract fromDevToolsTargetId: targetId: string -> WebContents + /// + /// | undefined - A WebContents instance with the given ID, or undefined if there + /// is no WebContents associated with the given ID. + /// + abstract fromId: id: float -> WebContents + /// + /// An array of all WebContents instances. This will contain web contents for all + /// windows, webviews, opened devtools, and devtools extension background pages. + /// + abstract getAllWebContents: unit -> ResizeArray + /// The web contents that is focused in this application, otherwise returns null. + abstract getFocusedWebContents: unit -> WebContents + + type [] WebFrame = + inherit NodeJS.EventEmitter + /// Attempts to free memory that is no longer being used (like images from a + /// previous navigation). + /// + /// Note that blindly calling this method probably makes Electron slower since it + /// will have to refill these emptied caches, you should only call it if an event in + /// your app has occurred that makes you think your page is actually using less + /// memory (i.e. you have navigated from a super heavy page to a mostly empty one, + /// and intend to stay there). + abstract clearCache: unit -> unit + /// + /// A promise that resolves with the result of the executed code or is rejected if + /// execution throws or results in a rejected promise. + /// + /// Evaluates code in page. + /// + /// In the browser window some HTML APIs like requestFullScreen can only be + /// invoked by a gesture from the user. Setting userGesture to true will remove + /// this limitation. + /// + abstract executeJavaScript: code: string * ?userGesture: bool * ?callback: (obj option -> ExceptError -> unit) -> Promise + /// + /// A promise that resolves with the result of the executed code or is rejected if + /// execution could not start. + /// + /// Works like executeJavaScript but evaluates scripts in an isolated context. + /// + /// Note that when the execution of script fails, the returned promise will not + /// reject and the result would be undefined. This is because Chromium does not + /// dispatch errors of isolated worlds to foreign worlds. + /// + abstract executeJavaScriptInIsolatedWorld: worldId: float * scripts: ResizeArray * ?userGesture: bool * ?callback: (obj option -> ExceptError -> unit) -> Promise + /// + /// A child of webFrame with the supplied name, null would be returned if + /// there's no such frame or if the frame is not in the current renderer process. + /// + abstract findFrameByName: name: string -> WebFrame + /// that has the supplied routingId, null if not found. + abstract findFrameByRoutingId: routingId: float -> WebFrame + /// + /// The frame element in webFrame's document selected by selector, null would + /// be returned if selector does not select a frame or if the frame is not in the + /// current renderer process. + /// + abstract getFrameForSelector: selector: string -> WebFrame + /// + /// * images MemoryUsageDetails + /// * scripts MemoryUsageDetails + /// * cssStyleSheets MemoryUsageDetails + /// * xslStyleSheets MemoryUsageDetails + /// * fonts MemoryUsageDetails + /// * other MemoryUsageDetails + /// + /// Returns an object describing usage information of Blink's internal memory + /// caches. + /// + /// This will generate: + /// + abstract getResourceUsage: unit -> ResourceUsage + /// A list of suggested words for a given word. If the word is spelled correctly, + /// the result will be empty. + abstract getWordSuggestions: word: string -> ResizeArray + /// The current zoom factor. + abstract getZoomFactor: unit -> float + /// The current zoom level. + abstract getZoomLevel: unit -> float + /// + /// A key for the inserted CSS that can later be used to remove the CSS via + /// webFrame.removeInsertedCSS(key). + /// + /// Injects CSS into the current web page and returns a unique key for the inserted + /// stylesheet. + /// + abstract insertCSS: css: string -> string + /// Inserts text to the focused element. + abstract insertText: text: string -> unit + /// True if the word is misspelled according to the built in spellchecker, false + /// otherwise. If no dictionary is loaded, always return false. + abstract isWordMisspelled: word: string -> bool + /// + /// Removes the inserted CSS from the current web page. The stylesheet is identified + /// by its key, which is returned from webFrame.insertCSS(css). + /// + abstract removeInsertedCSS: key: string -> unit + /// + /// Set the security origin, content security policy and name of the isolated world. + /// Note: If the csp is specified, then the securityOrigin also has to be + /// specified. + /// + abstract setIsolatedWorldInfo: worldId: float * info: Info -> unit + /// + /// Sets a provider for spell checking in input fields and text areas. + /// + /// If you want to use this method you must disable the builtin spellchecker when + /// you construct the window. + /// + /// The provider must be an object that has a spellCheck method that accepts an + /// array of individual words for spellchecking. The spellCheck function runs + /// asynchronously and calls the callback function with an array of misspelt words + /// when complete. + /// + /// An example of using node-spellchecker as provider: + /// + abstract setSpellCheckProvider: language: string * provider: Provider -> unit + /// Sets the maximum and minimum pinch-to-zoom level. + /// + /// > **NOTE**: Visual zoom is disabled by default in Electron. To re-enable it, + /// call: + /// + /// > **NOTE**: Visual zoom only applies to pinch-to-zoom behavior. Cmd+/-/0 zoom + /// shortcuts are controlled by the 'zoomIn', 'zoomOut', and 'resetZoom' MenuItem + /// roles in the application Menu. To disable shortcuts, manually define the Menu + /// and omit zoom roles from the definition. + abstract setVisualZoomLevelLimits: minimumLevel: float * maximumLevel: float -> unit + /// Changes the zoom factor to the specified factor. Zoom factor is zoom percent + /// divided by 100, so 300% = 3.0. + /// + /// The factor must be greater than 0.0. + abstract setZoomFactor: factor: float -> unit + /// Changes the zoom level to the specified level. The original size is 0 and each + /// increment above or below represents zooming 20% larger or smaller to default + /// limits of 300% and 50% of original size, respectively. + /// + /// > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that + /// the zoom level for a specific domain propagates across all instances of windows + /// with the same domain. Differentiating the window URLs will make zoom work + /// per-window. + abstract setZoomLevel: level: float -> unit + /// + /// A WebFrame | null representing the first child frame of webFrame, the + /// property would be null if webFrame has no children or if first child is not + /// in the current renderer process. + /// + abstract firstChild: WebFrame option + /// + /// A WebFrame | null representing next sibling frame, the property would be + /// null if webFrame is the last frame in its parent or if the next sibling is + /// not in the current renderer process. + /// + abstract nextSibling: WebFrame option + /// + /// A WebFrame | null representing the frame which opened webFrame, the property + /// would be null if there's no opener or opener is not in the current renderer + /// process. + /// + abstract opener: WebFrame option + /// + /// A WebFrame | null representing parent frame of webFrame, the property would + /// be null if webFrame is top or parent is not in the current renderer process. + /// + abstract parent: WebFrame option + /// + /// An Integer representing the unique frame id in the current renderer process. + /// Distinct WebFrame instances that refer to the same underlying frame will have + /// the same routingId. + /// + abstract routingId: float + /// + /// A WebFrame | null representing top frame in frame hierarchy to which + /// webFrame belongs, the property would be null if top frame is not in the + /// current renderer process. + /// + abstract top: WebFrame option + + type [] WebFrameMain = + inherit NodeEventEmitter + /// + /// A promise that resolves with the result of the executed code or is rejected if + /// execution throws or results in a rejected promise. + /// + /// Evaluates code in page. + /// + /// In the browser window some HTML APIs like requestFullScreen can only be + /// invoked by a gesture from the user. Setting userGesture to true will remove + /// this limitation. + /// + abstract executeJavaScript: code: string * ?userGesture: bool -> Promise + /// + /// Send a message to the renderer process, optionally transferring ownership of + /// zero or more [MessagePortMain][] objects. + /// + /// The transferred MessagePortMain objects will be available in the renderer + /// process by accessing the ports property of the emitted event. When they arrive + /// in the renderer, they will be native DOM MessagePort objects. + /// + /// For example: + /// + abstract postMessage: channel: string * message: obj option * ?transfer: ResizeArray -> unit + /// + /// Whether the reload was initiated successfully. Only results in false when the + /// frame has no history. + /// + abstract reload: unit -> bool + /// + /// Send an asynchronous message to the renderer process via channel, along with + /// arguments. Arguments will be serialized with the [Structured Clone + /// Algorithm][SCA], just like [postMessage][], so prototype chains will not be + /// included. Sending Functions, Promises, Symbols, WeakMaps, or WeakSets will throw + /// an exception. + /// + /// The renderer process can handle the message by listening to channel with the + /// ipcRenderer module. + /// + abstract send: channel: string * [] args: obj option[] -> unit + /// A WebFrameMain[] collection containing the direct descendents of frame. + abstract frames: ResizeArray + /// + /// A WebFrameMain[] collection containing every frame in the subtree of frame, + /// including itself. This can be useful when traversing through all frames. + /// + abstract framesInSubtree: ResizeArray + /// + /// An Integer representing the id of the frame's internal FrameTreeNode instance. + /// This id is browser-global and uniquely identifies a frame that hosts content. + /// The identifier is fixed at the creation of the frame and stays constant for the + /// lifetime of the frame. When the frame is removed, the id is not used again. + /// + abstract frameTreeNodeId: float + /// A String representing the frame name. + abstract name: string + /// + /// An Integer representing the operating system pid of the process which owns + /// this frame. + /// + abstract osProcessId: float + /// + /// A WebFrameMain | null representing parent frame of frame, the property would + /// be null if frame is the top frame in the frame hierarchy. + /// + abstract parent: WebFrameMain option + /// + /// An Integer representing the Chromium internal pid of the process which owns + /// this frame. This is not the same as the OS process ID; to read that use + /// frame.osProcessId. + /// + abstract processId: float + /// + /// An Integer representing the unique frame id in the current renderer process. + /// Distinct WebFrameMain instances that refer to the same underlying frame will + /// have the same routingId. + /// + abstract routingId: float + /// + /// A WebFrameMain | null representing top frame in the frame hierarchy to which + /// frame belongs. + /// + abstract top: WebFrameMain option + /// A string representing the current URL of the frame. + abstract url: string + /// + /// A string representing the visibility state of the frame. + /// + /// See also how the Page Visibility API is affected by other Electron APIs. + /// + abstract visibilityState: string + + type [] WebFrameMainStatic = + [] abstract Create: unit -> WebFrameMain + /// + /// A frame with the given process and routing IDs, or undefined if there is no + /// WebFrameMain associated with the given IDs. + /// + abstract fromId: processId: float * routingId: float -> WebFrameMain option + + type [] WebRequest = + /// + /// The listener will be called with listener(details) when a server initiated + /// redirect is about to occur. + /// + abstract onBeforeRedirect: filter: Filter * listener: (OnBeforeRedirectListenerDetails -> unit) option -> unit + /// + /// The listener will be called with listener(details) when a server initiated + /// redirect is about to occur. + /// + abstract onBeforeRedirect: listener: (OnBeforeRedirectListenerDetails -> unit) option -> unit + /// + /// The listener will be called with listener(details, callback) when a request + /// is about to occur. + /// + /// The uploadData is an array of UploadData objects. + /// + /// The callback has to be called with an response object. + /// + /// Some examples of valid urls: + /// + abstract onBeforeRequest: filter: Filter * listener: (OnBeforeRequestListenerDetails -> (Response -> unit) -> unit) option -> unit + /// + /// The listener will be called with listener(details, callback) when a request + /// is about to occur. + /// + /// The uploadData is an array of UploadData objects. + /// + /// The callback has to be called with an response object. + /// + /// Some examples of valid urls: + /// + abstract onBeforeRequest: listener: (OnBeforeRequestListenerDetails -> (Response -> unit) -> unit) option -> unit + /// + /// The listener will be called with listener(details, callback) before sending + /// an HTTP request, once the request headers are available. This may occur after a + /// TCP connection is made to the server, but before any http data is sent. + /// + /// The callback has to be called with a response object. + /// + abstract onBeforeSendHeaders: filter: Filter * listener: (OnBeforeSendHeadersListenerDetails -> (BeforeSendResponse -> unit) -> unit) option -> unit + /// + /// The listener will be called with listener(details, callback) before sending + /// an HTTP request, once the request headers are available. This may occur after a + /// TCP connection is made to the server, but before any http data is sent. + /// + /// The callback has to be called with a response object. + /// + abstract onBeforeSendHeaders: listener: (OnBeforeSendHeadersListenerDetails -> (BeforeSendResponse -> unit) -> unit) option -> unit + /// + /// The listener will be called with listener(details) when a request is + /// completed. + /// + abstract onCompleted: filter: Filter * listener: (OnCompletedListenerDetails -> unit) option -> unit + /// + /// The listener will be called with listener(details) when a request is + /// completed. + /// + abstract onCompleted: listener: (OnCompletedListenerDetails -> unit) option -> unit + /// The listener will be called with listener(details) when an error occurs. + abstract onErrorOccurred: filter: Filter * listener: (OnErrorOccurredListenerDetails -> unit) option -> unit + /// The listener will be called with listener(details) when an error occurs. + abstract onErrorOccurred: listener: (OnErrorOccurredListenerDetails -> unit) option -> unit + /// + /// The listener will be called with listener(details, callback) when HTTP + /// response headers of a request have been received. + /// + /// The callback has to be called with a response object. + /// + abstract onHeadersReceived: filter: Filter * listener: (OnHeadersReceivedListenerDetails -> (HeadersReceivedResponse -> unit) -> unit) option -> unit + /// + /// The listener will be called with listener(details, callback) when HTTP + /// response headers of a request have been received. + /// + /// The callback has to be called with a response object. + /// + abstract onHeadersReceived: listener: (OnHeadersReceivedListenerDetails -> (HeadersReceivedResponse -> unit) -> unit) option -> unit + /// + /// The listener will be called with listener(details) when first byte of the + /// response body is received. For HTTP requests, this means that the status line + /// and response headers are available. + /// + abstract onResponseStarted: filter: Filter * listener: (OnResponseStartedListenerDetails -> unit) option -> unit + /// + /// The listener will be called with listener(details) when first byte of the + /// response body is received. For HTTP requests, this means that the status line + /// and response headers are available. + /// + abstract onResponseStarted: listener: (OnResponseStartedListenerDetails -> unit) option -> unit + /// + /// The listener will be called with listener(details) just before a request is + /// going to be sent to the server, modifications of previous onBeforeSendHeaders + /// response are visible by the time this listener is fired. + /// + abstract onSendHeaders: filter: Filter * listener: (OnSendHeadersListenerDetails -> unit) option -> unit + /// + /// The listener will be called with listener(details) just before a request is + /// going to be sent to the server, modifications of previous onBeforeSendHeaders + /// response are visible by the time this listener is fired. + /// + abstract onSendHeaders: listener: (OnSendHeadersListenerDetails -> unit) option -> unit + + type [] WebRequestStatic = + [] abstract Create: unit -> WebRequest + + type [] WebSource = + abstract code: string with get, set + /// Default is 1. + abstract startLine: float option with get, set + abstract url: string option with get, set + + type [] WebviewTag = + inherit HTMLElement + /// Fired when a load has committed. This includes navigation within the current + /// document as well as subframe document-level loads, but does not include + /// asynchronous resource loads. + [] abstract ``addEventListener_load-commit``: listener: (LoadCommitEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_load-commit``: listener: (LoadCommitEvent -> unit) -> WebviewTag + /// + /// Fired when the navigation is done, i.e. the spinner of the tab will stop + /// spinning, and the onload event is dispatched. + /// + [] abstract ``addEventListener_did-finish-load``: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_did-finish-load``: listener: (Event -> unit) -> WebviewTag + /// + /// This event is like did-finish-load, but fired when the load failed or was + /// cancelled, e.g. window.stop() is invoked. + /// + [] abstract ``addEventListener_did-fail-load``: listener: (DidFailLoadEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_did-fail-load``: listener: (DidFailLoadEvent -> unit) -> WebviewTag + /// Fired when a frame has done navigation. + [] abstract ``addEventListener_did-frame-finish-load``: listener: (DidFrameFinishLoadEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_did-frame-finish-load``: listener: (DidFrameFinishLoadEvent -> unit) -> WebviewTag + /// Corresponds to the points in time when the spinner of the tab starts spinning. + [] abstract ``addEventListener_did-start-loading``: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_did-start-loading``: listener: (Event -> unit) -> WebviewTag + /// Corresponds to the points in time when the spinner of the tab stops spinning. + [] abstract ``addEventListener_did-stop-loading``: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_did-stop-loading``: listener: (Event -> unit) -> WebviewTag + /// Fired when attached to the embedder web contents. + [] abstract ``addEventListener_did-attach``: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_did-attach``: listener: (Event -> unit) -> WebviewTag + /// Fired when document in the given frame is loaded. + [] abstract ``addEventListener_dom-ready``: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_dom-ready``: listener: (Event -> unit) -> WebviewTag + /// + /// Fired when page title is set during navigation. explicitSet is false when + /// title is synthesized from file url. + /// + [] abstract ``addEventListener_page-title-updated``: listener: (PageTitleUpdatedEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_page-title-updated``: listener: (PageTitleUpdatedEvent -> unit) -> WebviewTag + /// Fired when page receives favicon urls. + [] abstract ``addEventListener_page-favicon-updated``: listener: (PageFaviconUpdatedEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_page-favicon-updated``: listener: (PageFaviconUpdatedEvent -> unit) -> WebviewTag + /// Fired when page enters fullscreen triggered by HTML API. + [] abstract ``addEventListener_enter-html-full-screen``: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_enter-html-full-screen``: listener: (Event -> unit) -> WebviewTag + /// Fired when page leaves fullscreen triggered by HTML API. + [] abstract ``addEventListener_leave-html-full-screen``: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_leave-html-full-screen``: listener: (Event -> unit) -> WebviewTag + /// Fired when the guest window logs a console message. + /// + /// The following example code forwards all log messages to the embedder's console + /// without regard for log level or other properties. + [] abstract ``addEventListener_console-message``: listener: (ConsoleMessageEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_console-message``: listener: (ConsoleMessageEvent -> unit) -> WebviewTag + /// Fired when a result is available for webview.findInPage request. + [] abstract ``addEventListener_found-in-page``: listener: (FoundInPageEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_found-in-page``: listener: (FoundInPageEvent -> unit) -> WebviewTag + /// Fired when the guest page attempts to open a new browser window. + /// + /// The following example code opens the new url in system's default browser. + [] abstract ``addEventListener_new-window``: listener: (NewWindowEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_new-window``: listener: (NewWindowEvent -> unit) -> WebviewTag + /// + /// Emitted when a user or the page wants to start navigation. It can happen when + /// the window.location object is changed or a user clicks a link in the page. + /// + /// This event will not emit when the navigation is started programmatically with + /// APIs like <webview>.loadURL and <webview>.back. + /// + /// It is also not emitted during in-page navigation, such as clicking anchor links + /// or updating the window.location.hash. Use did-navigate-in-page event for + /// this purpose. + /// + /// Calling event.preventDefault() does __NOT__ have any effect. + /// + [] abstract ``addEventListener_will-navigate``: listener: (WillNavigateEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_will-navigate``: listener: (WillNavigateEvent -> unit) -> WebviewTag + /// + /// Emitted when any frame (including main) starts navigating. isInPlace will be + /// true for in-page navigations. + /// + [] abstract ``addEventListener_did-start-navigation``: listener: (DidStartNavigationEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_did-start-navigation``: listener: (DidStartNavigationEvent -> unit) -> WebviewTag + /// + /// Emitted when a navigation is done. + /// + /// This event is not emitted for in-page navigations, such as clicking anchor links + /// or updating the window.location.hash. Use did-navigate-in-page event for + /// this purpose. + /// + [] abstract ``addEventListener_did-navigate``: listener: (DidNavigateEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_did-navigate``: listener: (DidNavigateEvent -> unit) -> WebviewTag + /// + /// Emitted when any frame navigation is done. + /// + /// This event is not emitted for in-page navigations, such as clicking anchor links + /// or updating the window.location.hash. Use did-navigate-in-page event for + /// this purpose. + /// + [] abstract ``addEventListener_did-frame-navigate``: listener: (DidFrameNavigateEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_did-frame-navigate``: listener: (DidFrameNavigateEvent -> unit) -> WebviewTag + /// + /// Emitted when an in-page navigation happened. + /// + /// When in-page navigation happens, the page URL changes but does not cause + /// navigation outside of the page. Examples of this occurring are when anchor links + /// are clicked or when the DOM hashchange event is triggered. + /// + [] abstract ``addEventListener_did-navigate-in-page``: listener: (DidNavigateInPageEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_did-navigate-in-page``: listener: (DidNavigateInPageEvent -> unit) -> WebviewTag + /// + /// Fired when the guest page attempts to close itself. + /// + /// The following example code navigates the webview to about:blank when the + /// guest attempts to close itself. + /// + [] abstract addEventListener_close: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract removeEventListener_close: listener: (Event -> unit) -> WebviewTag + /// + /// Fired when the guest page has sent an asynchronous message to embedder page. + /// + /// With sendToHost method and ipc-message event you can communicate between + /// guest page and embedder page: + /// + [] abstract ``addEventListener_ipc-message``: listener: (IpcMessageEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_ipc-message``: listener: (IpcMessageEvent -> unit) -> WebviewTag + /// Fired when the renderer process is crashed. + [] abstract addEventListener_crashed: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract removeEventListener_crashed: listener: (Event -> unit) -> WebviewTag + /// Fired when a plugin process is crashed. + [] abstract ``addEventListener_plugin-crashed``: listener: (PluginCrashedEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_plugin-crashed``: listener: (PluginCrashedEvent -> unit) -> WebviewTag + /// Fired when the WebContents is destroyed. + [] abstract addEventListener_destroyed: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract removeEventListener_destroyed: listener: (Event -> unit) -> WebviewTag + /// Emitted when media starts playing. + [] abstract ``addEventListener_media-started-playing``: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_media-started-playing``: listener: (Event -> unit) -> WebviewTag + /// Emitted when media is paused or done playing. + [] abstract ``addEventListener_media-paused``: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_media-paused``: listener: (Event -> unit) -> WebviewTag + /// Emitted when a page's theme color changes. This is usually due to encountering a + /// meta tag: + [] abstract ``addEventListener_did-change-theme-color``: listener: (DidChangeThemeColorEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_did-change-theme-color``: listener: (DidChangeThemeColorEvent -> unit) -> WebviewTag + /// Emitted when mouse moves over a link or the keyboard moves the focus to a link. + [] abstract ``addEventListener_update-target-url``: listener: (UpdateTargetUrlEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_update-target-url``: listener: (UpdateTargetUrlEvent -> unit) -> WebviewTag + /// Emitted when DevTools is opened. + [] abstract ``addEventListener_devtools-opened``: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_devtools-opened``: listener: (Event -> unit) -> WebviewTag + /// Emitted when DevTools is closed. + [] abstract ``addEventListener_devtools-closed``: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_devtools-closed``: listener: (Event -> unit) -> WebviewTag + /// Emitted when DevTools is focused / opened. + [] abstract ``addEventListener_devtools-focused``: listener: (Event -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_devtools-focused``: listener: (Event -> unit) -> WebviewTag + /// Emitted when there is a new context menu that needs to be handled. + [] abstract ``addEventListener_context-menu``: listener: (ContextMenuEvent -> unit) * ?useCapture: bool -> WebviewTag + [] abstract ``removeEventListener_context-menu``: listener: (ContextMenuEvent -> unit) -> WebviewTag + abstract addEventListener: ``type``: KeyOf * listener: (HTMLElement -> obj -> obj option) * ?useCapture: bool -> unit + abstract addEventListener: ``type``: string * listener: EventListenerOrEventListenerObject * ?useCapture: bool -> unit + abstract removeEventListener: ``type``: KeyOf * listener: (HTMLElement -> obj -> obj option) * ?useCapture: bool -> unit + abstract removeEventListener: ``type``: string * listener: EventListenerOrEventListenerObject * ?useCapture: bool -> unit + /// Whether the guest page can go back. + abstract canGoBack: unit -> bool + /// Whether the guest page can go forward. + abstract canGoForward: unit -> bool + /// Whether the guest page can go to offset. + abstract canGoToOffset: offset: float -> bool + /// + /// Resolves with a NativeImage + /// + /// Captures a snapshot of the page within rect. Omitting rect will capture the + /// whole visible page. + /// + abstract capturePage: ?rect: Rectangle -> Promise + /// Clears the navigation history. + abstract clearHistory: unit -> unit + /// Closes the DevTools window of guest page. + abstract closeDevTools: unit -> unit + /// Executes editing command copy in page. + abstract copy: unit -> unit + /// Executes editing command cut in page. + abstract cut: unit -> unit + /// Executes editing command delete in page. + abstract delete: unit -> unit + /// Initiates a download of the resource at url without navigating. + abstract downloadURL: url: string -> unit + /// + /// A promise that resolves with the result of the executed code or is rejected if + /// the result of the code is a rejected promise. + /// + /// Evaluates code in page. If userGesture is set, it will create the user + /// gesture context in the page. HTML APIs like requestFullScreen, which require + /// user action, can take advantage of this option for automation. + /// + abstract executeJavaScript: code: string * ?userGesture: bool -> Promise + /// + /// The request id used for the request. + /// + /// Starts a request to find all matches for the text in the web page. The result + /// of the request can be obtained by subscribing to found-in-page event. + /// + abstract findInPage: text: string * ?options: FindInPageOptions -> float + /// The title of guest page. + abstract getTitle: unit -> string + /// The URL of guest page. + abstract getURL: unit -> string + /// The user agent for guest page. + abstract getUserAgent: unit -> string + /// The WebContents ID of this webview. + abstract getWebContentsId: unit -> float + /// the current zoom factor. + abstract getZoomFactor: unit -> float + /// the current zoom level. + abstract getZoomLevel: unit -> float + /// Makes the guest page go back. + abstract goBack: unit -> unit + /// Makes the guest page go forward. + abstract goForward: unit -> unit + /// Navigates to the specified absolute index. + abstract goToIndex: index: float -> unit + /// Navigates to the specified offset from the "current entry". + abstract goToOffset: offset: float -> unit + /// + /// A promise that resolves with a key for the inserted CSS that can later be used + /// to remove the CSS via <webview>.removeInsertedCSS(key). + /// + /// Injects CSS into the current web page and returns a unique key for the inserted + /// stylesheet. + /// + abstract insertCSS: css: string -> Promise + /// Inserts text to the focused element. + abstract insertText: text: string -> Promise + /// Starts inspecting element at position (x, y) of guest page. + abstract inspectElement: x: float * y: float -> unit + /// Opens the DevTools for the service worker context present in the guest page. + abstract inspectServiceWorker: unit -> unit + /// Opens the DevTools for the shared worker context present in the guest page. + abstract inspectSharedWorker: unit -> unit + /// Whether guest page has been muted. + abstract isAudioMuted: unit -> bool + /// Whether the renderer process has crashed. + abstract isCrashed: unit -> bool + /// Whether audio is currently playing. + abstract isCurrentlyAudible: unit -> bool + /// Whether DevTools window of guest page is focused. + abstract isDevToolsFocused: unit -> bool + /// Whether guest page has a DevTools window attached. + abstract isDevToolsOpened: unit -> bool + /// Whether guest page is still loading resources. + abstract isLoading: unit -> bool + /// Whether the main frame (and not just iframes or frames within it) is still + /// loading. + abstract isLoadingMainFrame: unit -> bool + /// Whether the guest page is waiting for a first-response for the main resource of + /// the page. + abstract isWaitingForResponse: unit -> bool + /// + /// The promise will resolve when the page has finished loading (see + /// did-finish-load), and rejects if the page fails to load (see did-fail-load). + /// + /// Loads the url in the webview, the url must contain the protocol prefix, e.g. + /// the http:// or file://. + /// + abstract loadURL: url: string * ?options: LoadURLOptions -> Promise + /// Opens a DevTools window for guest page. + abstract openDevTools: unit -> unit + /// Executes editing command paste in page. + abstract paste: unit -> unit + /// Executes editing command pasteAndMatchStyle in page. + abstract pasteAndMatchStyle: unit -> unit + /// Prints webview's web page. Same as webContents.print([options]). + abstract print: ?options: WebviewTagPrintOptions -> Promise + /// + /// Resolves with the generated PDF data. + /// + /// Prints webview's web page as PDF, Same as webContents.printToPDF(options). + /// + abstract printToPDF: options: PrintToPDFOptions -> Promise + /// Executes editing command redo in page. + abstract redo: unit -> unit + /// Reloads the guest page. + abstract reload: unit -> unit + /// Reloads the guest page and ignores cache. + abstract reloadIgnoringCache: unit -> unit + /// + /// Resolves if the removal was successful. + /// + /// Removes the inserted CSS from the current web page. The stylesheet is identified + /// by its key, which is returned from <webview>.insertCSS(css). + /// + abstract removeInsertedCSS: key: string -> Promise + /// Executes editing command replace in page. + abstract replace: text: string -> unit + /// Executes editing command replaceMisspelling in page. + abstract replaceMisspelling: text: string -> unit + /// Executes editing command selectAll in page. + abstract selectAll: unit -> unit + /// + /// Send an asynchronous message to renderer process via channel, you can also + /// send arbitrary arguments. The renderer process can handle the message by + /// listening to the channel event with the ipcRenderer module. + /// + /// See webContents.send for examples. + /// + abstract send: channel: string * [] args: obj option[] -> Promise + /// + /// Sends an input event to the page. + /// + /// See webContents.sendInputEvent for detailed description of event object. + /// + abstract sendInputEvent: ``event``: U3 -> Promise + /// Set guest page muted. + abstract setAudioMuted: muted: bool -> unit + /// Overrides the user agent for the guest page. + abstract setUserAgent: userAgent: string -> unit + /// Sets the maximum and minimum pinch-to-zoom level. + abstract setVisualZoomLevelLimits: minimumLevel: float * maximumLevel: float -> Promise + /// Changes the zoom factor to the specified factor. Zoom factor is zoom percent + /// divided by 100, so 300% = 3.0. + abstract setZoomFactor: factor: float -> unit + /// + /// Changes the zoom level to the specified level. The original size is 0 and each + /// increment above or below represents zooming 20% larger or smaller to default + /// limits of 300% and 50% of original size, respectively. The formula for this is + /// scale := 1.2 ^ level. + /// + /// > **NOTE**: The zoom policy at the Chromium level is same-origin, meaning that + /// the zoom level for a specific domain propagates across all instances of windows + /// with the same domain. Differentiating the window URLs will make zoom work + /// per-window. + /// + abstract setZoomLevel: level: float -> unit + /// Shows pop-up dictionary that searches the selected word on the page. + abstract showDefinitionForSelection: unit -> unit + /// Stops any pending navigation. + abstract stop: unit -> unit + /// Stops any findInPage request for the webview with the provided action. + abstract stopFindInPage: action: WebContentsStopFindInPage -> unit + /// Executes editing command undo in page. + abstract undo: unit -> unit + /// Executes editing command unselect in page. + abstract unselect: unit -> unit + /// + /// A Boolean. When this attribute is present the guest page will be allowed to + /// open new windows. Popups are disabled by default. + /// + abstract allowpopups: bool with get, set + /// + /// A String which is a list of strings which specifies the blink features to be + /// disabled separated by ,. The full list of supported feature strings can be + /// found in the RuntimeEnabledFeatures.json5 file. + /// + abstract disableblinkfeatures: string with get, set + /// + /// A Boolean. When this attribute is present the guest page will have web + /// security disabled. Web security is enabled by default. + /// + abstract disablewebsecurity: bool with get, set + /// + /// A String which is a list of strings which specifies the blink features to be + /// enabled separated by ,. The full list of supported feature strings can be + /// found in the RuntimeEnabledFeatures.json5 file. + /// + abstract enableblinkfeatures: string with get, set + /// A String that sets the referrer URL for the guest page. + abstract httpreferrer: string with get, set + /// + /// A Boolean. When this attribute is present the guest page in webview will + /// have node integration and can use node APIs like require and process to + /// access low level system resources. Node integration is disabled by default in + /// the guest page. + /// + abstract nodeintegration: bool with get, set + /// + /// A Boolean for the experimental option for enabling NodeJS support in + /// sub-frames such as iframes inside the webview. All your preloads will load for + /// every iframe, you can use process.isMainFrame to determine if you are in the + /// main frame or not. This option is disabled by default in the guest page. + /// + abstract nodeintegrationinsubframes: bool with get, set + /// + /// A String that sets the session used by the page. If partition starts with + /// persist:, the page will use a persistent session available to all pages in the + /// app with the same partition. if there is no persist: prefix, the page will + /// use an in-memory session. By assigning the same partition, multiple pages can + /// share the same session. If the partition is unset then default session of the + /// app will be used. + /// + /// This value can only be modified before the first navigation, since the session + /// of an active renderer process cannot change. Subsequent attempts to modify the + /// value will fail with a DOM exception. + /// + abstract partition: string with get, set + /// + /// A Boolean. When this attribute is present the guest page in webview will be + /// able to use browser plugins. Plugins are disabled by default. + /// + abstract plugins: bool with get, set + /// + /// A String that specifies a script that will be loaded before other scripts run + /// in the guest page. The protocol of script's URL must be file: (even when using + /// asar: archives) because it will be loaded by Node's require under the hood, + /// which treats asar: archives as virtual directories. + /// + /// When the guest page doesn't have node integration this script will still have + /// access to all Node APIs, but global objects injected by Node will be deleted + /// after this script has finished executing. + /// + /// **Note:** This option will appear as preloadURL (not preload) in the + /// webPreferences specified to the will-attach-webview event. + /// + abstract preload: string with get, set + /// + /// A String representing the visible URL. Writing to this attribute initiates + /// top-level navigation. + /// + /// Assigning src its own value will reload the current page. + /// + /// The src attribute can also accept data URLs, such as `data:text/plain,Hello, + /// world!`. + /// + abstract src: string with get, set + /// + /// A String that sets the user agent for the guest page before the page is + /// navigated to. Once the page is loaded, use the setUserAgent method to change + /// the user agent. + /// + abstract useragent: string with get, set + /// + /// A String which is a comma separated list of strings which specifies the web + /// preferences to be set on the webview. The full list of supported preference + /// strings can be found in BrowserWindow. + /// + /// The string follows the same format as the features string in window.open. A + /// name by itself is given a true boolean value. A preference can be set to + /// another value by including an =, followed by the value. Special values yes + /// and 1 are interpreted as true, while no and 0 are interpreted as + /// false. + /// + abstract webpreferences: string with get, set + + type [] AboutPanelOptionsOptions = + /// The app's name. + abstract applicationName: string option with get, set + /// The app's version. + abstract applicationVersion: string option with get, set + /// Copyright information. + abstract copyright: string option with get, set + /// The app's build version number. + abstract version: string option with get, set + /// Credit information. + abstract credits: string option with get, set + /// List of app authors. + abstract authors: ResizeArray option with get, set + /// The app's website. + abstract website: string option with get, set + /// + /// Path to the app's icon in a JPEG or PNG file format. On Linux, will be shown as + /// 64x64 pixels while retaining aspect ratio. + /// + abstract iconPath: string option with get, set + + type [] AddRepresentationOptions = + /// The scale factor to add the image representation for. + abstract scaleFactor: float with get, set + /// Defaults to 0. Required if a bitmap buffer is specified as buffer. + abstract width: float option with get, set + /// Defaults to 0. Required if a bitmap buffer is specified as buffer. + abstract height: float option with get, set + /// The buffer containing the raw image data. + abstract buffer: Buffer option with get, set + /// The data URL containing either a base 64 encoded PNG or JPEG image. + abstract dataURL: string option with get, set + + type [] AnimationSettings = + /// Returns true if rich animations should be rendered. Looks at session type (e.g. + /// remote desktop) and accessibility settings to give guidance for heavy + /// animations. + abstract shouldRenderRichAnimation: bool with get, set + /// Determines on a per-platform basis whether scroll animations (e.g. produced by + /// home/end key) should be enabled. + abstract scrollAnimationsEnabledBySystem: bool with get, set + /// Determines whether the user desires reduced motion based on platform APIs. + abstract prefersReducedMotion: bool with get, set + + type [] AppDetailsOptions = + /// Window's App User Model ID. It has to be set, otherwise the other options will + /// have no effect. + abstract appId: string option with get, set + /// Window's Relaunch Icon. + abstract appIconPath: string option with get, set + /// + /// Index of the icon in appIconPath. Ignored when appIconPath is not set. + /// Default is 0. + /// + abstract appIconIndex: float option with get, set + /// Window's Relaunch Command. + abstract relaunchCommand: string option with get, set + /// Window's Relaunch Display Name. + abstract relaunchDisplayName: string option with get, set + + type [] ApplicationInfoForProtocolReturnValue = + /// the display icon of the app handling the protocol. + abstract icon: NativeImage with get, set + /// installation path of the app handling the protocol. + abstract path: string with get, set + /// display name of the app handling the protocol. + abstract name: string with get, set + + type [] AuthenticationResponseDetails = + abstract url: string with get, set + + type [] AuthInfo = + abstract isProxy: bool with get, set + abstract scheme: string with get, set + abstract host: string with get, set + abstract port: float with get, set + abstract realm: string with get, set + + type [] AutoResizeOptions = + /// + /// If true, the view's width will grow and shrink together with the window. + /// false by default. + /// + abstract width: bool option with get, set + /// + /// If true, the view's height will grow and shrink together with the window. + /// false by default. + /// + abstract height: bool option with get, set + /// + /// If true, the view's x position and width will grow and shrink proportionally + /// with the window. false by default. + /// + abstract horizontal: bool option with get, set + /// + /// If true, the view's y position and height will grow and shrink proportionally + /// with the window. false by default. + /// + abstract vertical: bool option with get, set + + type [] BeforeSendResponse = + abstract cancel: bool option with get, set + /// When provided, request will be made with these headers. + abstract requestHeaders: Record>> option with get, set + + type [] BitmapOptions = + /// Defaults to 1.0. + abstract scaleFactor: float option with get, set + + type [] BlinkMemoryInfo = + /// Size of all allocated objects in Kilobytes. + abstract allocated: float with get, set + /// Size of all marked objects in Kilobytes. + abstract marked: float with get, set + /// Total allocated space in Kilobytes. + abstract total: float with get, set + + type [] BrowserViewConstructorOptions = + /// See BrowserWindow. + abstract webPreferences: WebPreferences option with get, set + + type [] BrowserWindowConstructorOptions = + /// Window's width in pixels. Default is 800. + abstract width: float option with get, set + /// Window's height in pixels. Default is 600. + abstract height: float option with get, set + /// (**required** if y is used) Window's left offset from screen. Default is to + /// center the window. + abstract x: float option with get, set + /// (**required** if x is used) Window's top offset from screen. Default is to + /// center the window. + abstract y: float option with get, set + /// + /// The width and height would be used as web page's size, which means the + /// actual window's size will include window frame's size and be slightly larger. + /// Default is false. + /// + abstract useContentSize: bool option with get, set + /// Show window in the center of the screen. + abstract center: bool option with get, set + /// Window's minimum width. Default is 0. + abstract minWidth: float option with get, set + /// Window's minimum height. Default is 0. + abstract minHeight: float option with get, set + /// Window's maximum width. Default is no limit. + abstract maxWidth: float option with get, set + /// Window's maximum height. Default is no limit. + abstract maxHeight: float option with get, set + /// Whether window is resizable. Default is true. + abstract resizable: bool option with get, set + /// Whether window is movable. This is not implemented on Linux. Default is true. + abstract movable: bool option with get, set + /// + /// Whether window is minimizable. This is not implemented on Linux. Default is + /// true. + /// + abstract minimizable: bool option with get, set + /// + /// Whether window is maximizable. This is not implemented on Linux. Default is + /// true. + /// + abstract maximizable: bool option with get, set + /// Whether window is closable. This is not implemented on Linux. Default is true. + abstract closable: bool option with get, set + /// + /// Whether the window can be focused. Default is true. On Windows setting + /// focusable: false also implies setting skipTaskbar: true. On Linux setting + /// focusable: false makes the window stop interacting with wm, so the window will + /// always stay on top in all workspaces. + /// + abstract focusable: bool option with get, set + /// + /// Whether the window should always stay on top of other windows. Default is + /// false. + /// + abstract alwaysOnTop: bool option with get, set + /// + /// Whether the window should show in fullscreen. When explicitly set to false the + /// fullscreen button will be hidden or disabled on macOS. Default is false. + /// + abstract fullscreen: bool option with get, set + /// + /// Whether the window can be put into fullscreen mode. On macOS, also whether the + /// maximize/zoom button should toggle full screen mode or maximize window. Default + /// is true. + /// + abstract fullscreenable: bool option with get, set + /// Use pre-Lion fullscreen on macOS. Default is false. + abstract simpleFullscreen: bool option with get, set + /// Whether to show the window in taskbar. Default is false. + abstract skipTaskbar: bool option with get, set + /// Whether the window is in kiosk mode. Default is false. + abstract kiosk: bool option with get, set + /// + /// Default window title. Default is "Electron". If the HTML tag <title> is + /// defined in the HTML file loaded by loadURL(), this property will be ignored. + /// + abstract title: string option with get, set + /// + /// The window icon. On Windows it is recommended to use ICO icons to get best + /// visual effects, you can also leave it undefined so the executable's icon will be + /// used. + /// + abstract icon: U2 option with get, set + /// Whether window should be shown when created. Default is true. + abstract show: bool option with get, set + /// + /// Whether the renderer should be active when show is false and it has just + /// been created. In order for document.visibilityState to work correctly on + /// first load with show: false you should set this to false. Setting this to + /// false will cause the ready-to-show event to not fire. Default is true. + /// + abstract paintWhenInitiallyHidden: bool option with get, set + /// Specify false to create a Frameless Window. Default is true. + abstract frame: bool option with get, set + /// Specify parent window. Default is null. + abstract parent: BrowserWindow option with get, set + /// + /// Whether this is a modal window. This only works when the window is a child + /// window. Default is false. + /// + abstract modal: bool option with get, set + /// + /// Whether clicking an inactive window will also click through to the web contents. + /// Default is false on macOS. This option is not configurable on other platforms. + /// + abstract acceptFirstMouse: bool option with get, set + /// Whether to hide cursor when typing. Default is false. + abstract disableAutoHideCursor: bool option with get, set + /// Auto hide the menu bar unless the Alt key is pressed. Default is false. + abstract autoHideMenuBar: bool option with get, set + /// + /// Enable the window to be resized larger than screen. Only relevant for macOS, as + /// other OSes allow larger-than-screen windows by default. Default is false. + /// + abstract enableLargerThanScreen: bool option with get, set + /// + /// Window's background color as a hexadecimal value, like #66CD00 or #FFF or + /// #80FFFFFF (alpha in #AARRGGBB format is supported if transparent is set to + /// true). Default is #FFF (white). + /// + abstract backgroundColor: string option with get, set + /// Whether window should have a shadow. Default is true. + abstract hasShadow: bool option with get, set + /// Set the initial opacity of the window, between 0.0 (fully transparent) and 1.0 + /// (fully opaque). This is only implemented on Windows and macOS. + abstract opacity: float option with get, set + /// + /// Forces using dark theme for the window, only works on some GTK+3 desktop + /// environments. Default is false. + /// + abstract darkTheme: bool option with get, set + /// + /// Makes the window transparent. Default is false. On Windows, does not work + /// unless the window is frameless. + /// + abstract transparent: bool option with get, set + /// The type of window, default is normal window. See more about this below. + abstract ``type``: string option with get, set + /// + /// Specify how the material appearance should reflect window activity state on + /// macOS. Must be used with the vibrancy property. Possible values are: + /// + abstract visualEffectState: BrowserWindowConstructorOptionsVisualEffectState option with get, set + /// The style of window title bar. Default is default. Possible values are: + abstract titleBarStyle: BrowserWindowConstructorOptionsTitleBarStyle option with get, set + /// Set a custom position for the traffic light buttons in frameless windows. + abstract trafficLightPosition: Point option with get, set + /// + /// Whether frameless window should have rounded corners on macOS. Default is + /// true. + /// + abstract roundedCorners: bool option with get, set + /// + /// Shows the title in the title bar in full screen mode on macOS for hiddenInset + /// titleBarStyle. Default is false. + /// + [] + abstract fullscreenWindowTitle: bool option with get, set + /// + /// Use WS_THICKFRAME style for frameless windows on Windows, which adds standard + /// window frame. Setting it to false will remove window shadow and window + /// animations. Default is true. + /// + abstract thickFrame: bool option with get, set + /// + /// Add a type of vibrancy effect to the window, only on macOS. Can be + /// appearance-based, light, dark, titlebar, selection, menu, popover, + /// sidebar, medium-light, ultra-dark, header, sheet, window, hud, + /// fullscreen-ui, tooltip, content, under-window, or under-page. Please + /// note that appearance-based, light, dark, medium-light, and ultra-dark + /// are deprecated and have been removed in macOS Catalina (10.15). + /// + abstract vibrancy: BrowserWindowSetVibrancy option with get, set + /// + /// Controls the behavior on macOS when option-clicking the green stoplight button + /// on the toolbar or by clicking the Window > Zoom menu item. If true, the window + /// will grow to the preferred width of the web page when zoomed, false will cause + /// it to zoom to the width of the screen. This will also affect the behavior when + /// calling maximize() directly. Default is false. + /// + abstract zoomToPageWidth: bool option with get, set + /// + /// Tab group name, allows opening the window as a native tab on macOS 10.12+. + /// Windows with the same tabbing identifier will be grouped together. This also + /// adds a native new tab button to your window's tab bar and allows your app and + /// window to receive the new-window-for-tab event. + /// + abstract tabbingIdentifier: string option with get, set + /// Settings of web page's features. + abstract webPreferences: WebPreferences option with get, set + /// + /// When using a frameless window in conjuction with + /// win.setWindowButtonVisibility(true) on macOS or using a titleBarStyle so + /// that the standard window controls ("traffic lights" on macOS) are visible, this + /// property enables the Window Controls Overlay JavaScript APIs and CSS Environment + /// Variables. Specifying true will result in an overlay with default system + /// colors. Default is false. On Windows, the OverlayOptions can be used instead + /// of a boolean to specify colors for the overlay. + /// + abstract titleBarOverlay: U2 option with get, set + + type [] CertificateTrustDialogOptions = + /// The certificate to trust/import. + abstract certificate: Certificate with get, set + /// The message to display to the user. + abstract message: string with get, set + + type [] ClearStorageDataOptions = + /// Should follow window.location.origin’s representation scheme://host:port. + abstract origin: string option with get, set + /// + /// The types of storages to clear, can contain: appcache, cookies, + /// filesystem, indexdb, localstorage, shadercache, websql, + /// serviceworkers, cachestorage. If not specified, clear all storage types. + /// + abstract storages: ResizeArray option with get, set + /// + /// The types of quotas to clear, can contain: temporary, persistent, + /// syncable. If not specified, clear all quotas. + /// + abstract quotas: ResizeArray option with get, set + + type [] ClientRequestConstructorOptions = + /// The HTTP request method. Defaults to the GET method. + abstract method: string option with get, set + /// The request URL. Must be provided in the absolute form with the protocol scheme + /// specified as http or https. + abstract url: string option with get, set + /// The Session instance with which the request is associated. + abstract session: Session option with get, set + /// + /// The name of the partition with which the request is associated. Defaults to + /// the empty string. The session option supersedes partition. Thus if a + /// session is explicitly specified, partition is ignored. + /// + abstract partition: string option with get, set + /// + /// Can be include or omit. Whether to send credentials with this request. If + /// set to include, credentials from the session associated with the request will + /// be used. If set to omit, credentials will not be sent with the request (and + /// the 'login' event will not be triggered in the event of a 401). This matches + /// the behavior of the fetch option of the same name. If this option is not + /// specified, authentication data from the session will be sent, and cookies will + /// not be sent (unless useSessionCookies is set). + /// + abstract credentials: ClientRequestConstructorOptionsCredentials option with get, set + /// + /// Whether to send cookies with this request from the provided session. If + /// credentials is specified, this option has no effect. Default is false. + /// + abstract useSessionCookies: bool option with get, set + /// + /// Can be http: or https:. The protocol scheme in the form 'scheme:'. Defaults + /// to 'http:'. + /// + abstract protocol: string option with get, set + /// The server host provided as a concatenation of the hostname and the port number + /// 'hostname:port'. + abstract host: string option with get, set + /// The server host name. + abstract hostname: string option with get, set + /// The server's listening port number. + abstract port: float option with get, set + /// The path part of the request URL. + abstract path: string option with get, set + /// + /// Can be follow, error or manual. The redirect mode for this request. When + /// mode is error, any redirection will be aborted. When mode is manual the + /// redirection will be cancelled unless request.followRedirect is invoked + /// synchronously during the redirect event. Defaults to follow. + /// + abstract redirect: ClientRequestConstructorOptionsRedirect option with get, set + /// The origin URL of the request. + abstract origin: string option with get, set + + type [] Config = + /// + /// The proxy mode. Should be one of direct, auto_detect, pac_script, + /// fixed_servers or system. If it's unspecified, it will be automatically + /// determined based on other specified options. + /// + abstract mode: ConfigMode option with get, set + /// The URL associated with the PAC file. + abstract pacScript: string option with get, set + /// Rules indicating which proxies to use. + abstract proxyRules: string option with get, set + /// Rules indicating which URLs should bypass the proxy settings. + abstract proxyBypassRules: string option with get, set + + type [] ConsoleMessageEvent = + inherit Event + /// + /// The log level, from 0 to 3. In order it matches verbose, info, warning and + /// error. + /// + abstract level: float with get, set + /// The actual console message + abstract message: string with get, set + /// The line number of the source that triggered this console message + abstract line: float with get, set + abstract sourceId: string with get, set + + type [] ContextMenuEvent = + inherit Event + abstract ``params``: Params with get, set + + type [] ContextMenuParams = + /// x coordinate. + abstract x: float with get, set + /// y coordinate. + abstract y: float with get, set + /// URL of the link that encloses the node the context menu was invoked on. + abstract linkURL: string with get, set + /// Text associated with the link. May be an empty string if the contents of the + /// link are an image. + abstract linkText: string with get, set + /// URL of the top level page that the context menu was invoked on. + abstract pageURL: string with get, set + /// URL of the subframe that the context menu was invoked on. + abstract frameURL: string with get, set + /// Source URL for the element that the context menu was invoked on. Elements with + /// source URLs are images, audio and video. + abstract srcURL: string with get, set + /// + /// Type of the node the context menu was invoked on. Can be none, image, + /// audio, video, canvas, file or plugin. + /// + abstract mediaType: ContextMenuParamsMediaType with get, set + /// Whether the context menu was invoked on an image which has non-empty contents. + abstract hasImageContents: bool with get, set + /// Whether the context is editable. + abstract isEditable: bool with get, set + /// Text of the selection that the context menu was invoked on. + abstract selectionText: string with get, set + /// Title text of the selection that the context menu was invoked on. + abstract titleText: string with get, set + /// Alt text of the selection that the context menu was invoked on. + abstract altText: string with get, set + /// Suggested filename to be used when saving file through 'Save Link As' option of + /// context menu. + abstract suggestedFilename: string with get, set + /// Rect representing the coordinates in the document space of the selection. + abstract selectionRect: Rectangle with get, set + /// Start position of the selection text. + abstract selectionStartOffset: float with get, set + /// The referrer policy of the frame on which the menu is invoked. + abstract referrerPolicy: Referrer with get, set + /// The misspelled word under the cursor, if any. + abstract misspelledWord: string with get, set + /// + /// An array of suggested words to show the user to replace the misspelledWord. + /// Only available if there is a misspelled word and spellchecker is enabled. + /// + abstract dictionarySuggestions: ResizeArray with get, set + /// The character encoding of the frame on which the menu was invoked. + abstract frameCharset: string with get, set + /// + /// If the context menu was invoked on an input field, the type of that field. + /// Possible values are none, plainText, password, other. + /// + abstract inputFieldType: string with get, set + /// If the context is editable, whether or not spellchecking is enabled. + abstract spellcheckEnabled: bool with get, set + /// + /// Input source that invoked the context menu. Can be none, mouse, keyboard, + /// touch, touchMenu, longPress, longTap, touchHandle, stylus, + /// adjustSelection, or adjustSelectionReset. + /// + abstract menuSourceType: ContextMenuParamsMenuSourceType with get, set + /// The flags for the media element the context menu was invoked on. + abstract mediaFlags: MediaFlags with get, set + /// These flags indicate whether the renderer believes it is able to perform the + /// corresponding action. + abstract editFlags: EditFlags with get, set + + type [] CookiesGetFilter = + /// + /// Retrieves cookies which are associated with url. Empty implies retrieving + /// cookies of all URLs. + /// + abstract url: string option with get, set + /// Filters cookies by name. + abstract name: string option with get, set + /// Retrieves cookies whose domains match or are subdomains of domains. + abstract domain: string option with get, set + /// Retrieves cookies whose path matches path. + abstract path: string option with get, set + /// Filters cookies by their Secure property. + abstract secure: bool option with get, set + /// Filters out session or persistent cookies. + abstract session: bool option with get, set + + type [] CookiesSetDetails = + /// The URL to associate the cookie with. The promise will be rejected if the URL is + /// invalid. + abstract url: string with get, set + /// The name of the cookie. Empty by default if omitted. + abstract name: string option with get, set + /// The value of the cookie. Empty by default if omitted. + abstract value: string option with get, set + /// The domain of the cookie; this will be normalized with a preceding dot so that + /// it's also valid for subdomains. Empty by default if omitted. + abstract domain: string option with get, set + /// The path of the cookie. Empty by default if omitted. + abstract path: string option with get, set + /// Whether the cookie should be marked as Secure. Defaults to false. + abstract secure: bool option with get, set + /// Whether the cookie should be marked as HTTP only. Defaults to false. + abstract httpOnly: bool option with get, set + /// The expiration date of the cookie as the number of seconds since the UNIX epoch. + /// If omitted then the cookie becomes a session cookie and will not be retained + /// between sessions. + abstract expirationDate: float option with get, set + /// + /// The Same Site policy to apply to this cookie. Can be unspecified, + /// no_restriction, lax or strict. Default is no_restriction. + /// + abstract sameSite: CookieSameSite option with get, set + + type [] CrashReporterStartOptions = + /// + /// URL that crash reports will be sent to as POST. Required unless uploadToServer + /// is false. + /// + abstract submitURL: string option with get, set + /// Defaults to app.name. + abstract productName: string option with get, set + /// Deprecated alias for { globalExtra: { _companyName: ... } }. + [] + abstract companyName: string option with get, set + /// + /// Whether crash reports should be sent to the server. If false, crash reports will + /// be collected and stored in the crashes directory, but not uploaded. Default is + /// true. + /// + abstract uploadToServer: bool option with get, set + /// + /// If true, crashes generated in the main process will not be forwarded to the + /// system crash handler. Default is false. + /// + abstract ignoreSystemCrashHandler: bool option with get, set + /// If true, limit the number of crashes uploaded to 1/hour. Default is false. + abstract rateLimit: bool option with get, set + /// + /// If true, crash reports will be compressed and uploaded with `Content-Encoding: + /// gzip. Default is true`. + /// + abstract compress: bool option with get, set + /// + /// Extra string key/value annotations that will be sent along with crash reports + /// that are generated in the main process. Only string values are supported. + /// Crashes generated in child processes will not contain these extra parameters to + /// crash reports generated from child processes, call addExtraParameter from the + /// child process. + /// + abstract extra: Record option with get, set + /// + /// Extra string key/value annotations that will be sent along with any crash + /// reports generated in any process. These annotations cannot be changed once the + /// crash reporter has been started. If a key is present in both the global extra + /// parameters and the process-specific extra parameters, then the global one will + /// take precedence. By default, productName and the app version are included, as + /// well as the Electron version. + /// + abstract globalExtra: Record option with get, set + + type [] CreateFromBitmapOptions = + abstract width: float with get, set + abstract height: float with get, set + /// Defaults to 1.0. + abstract scaleFactor: float option with get, set + + type [] CreateFromBufferOptions = + /// Required for bitmap buffers. + abstract width: float option with get, set + /// Required for bitmap buffers. + abstract height: float option with get, set + /// Defaults to 1.0. + abstract scaleFactor: float option with get, set + + type [] CreateInterruptedDownloadOptions = + /// Absolute path of the download. + abstract path: string with get, set + /// Complete URL chain for the download. + abstract urlChain: ResizeArray with get, set + abstract mimeType: string option with get, set + /// Start range for the download. + abstract offset: float with get, set + /// Total length of the download. + abstract length: float with get, set + /// Last-Modified header value. + abstract lastModified: string option with get, set + /// ETag header value. + abstract eTag: string option with get, set + /// Time when download was started in number of seconds since UNIX epoch. + abstract startTime: float option with get, set + + type [] Data = + abstract text: string option with get, set + abstract html: string option with get, set + abstract image: NativeImage option with get, set + abstract rtf: string option with get, set + /// The title of the URL at text. + abstract bookmark: string option with get, set + + type [] Details = + /// Process type. One of the following values: + abstract ``type``: DetailsType with get, set + /// The reason the child process is gone. Possible values: + abstract reason: DetailsReason with get, set + /// The exit code for the process (e.g. status from waitpid if on posix, from + /// GetExitCodeProcess on Windows). + abstract exitCode: float with get, set + /// The non-localized name of the process. + abstract serviceName: string option with get, set + /// + /// The name of the process. Examples for utility: Audio Service, `Content + /// Decryption Module Service, Network Service, Video Capture`, etc. + /// + abstract name: string option with get, set + + type [] DevicePermissionHandlerHandlerDetails = + /// + /// The type of device that permission is being requested on, can be hid or + /// serial. + /// + abstract deviceType: DevicePermissionHandlerHandlerDetailsDeviceType with get, set + /// The origin URL of the device permission check. + abstract origin: string with get, set + /// the device that permission is being requested for. + abstract device: U2 with get, set + /// WebFrameMain checking the device permission. + abstract frame: WebFrameMain with get, set + + type [] DidChangeThemeColorEvent = + inherit Event + abstract themeColor: string with get, set + + type [] DidCreateWindowDetails = + /// URL for the created window. + abstract url: string with get, set + /// Name given to the created window in the window.open() call. + abstract frameName: string with get, set + /// + /// The options used to create the BrowserWindow. They are merged in increasing + /// precedence: parsed options from the features string from window.open(), + /// security-related webPreferences inherited from the parent, and options given by + /// webContents.setWindowOpenHandler. Unrecognized options are not filtered out. + /// + abstract options: BrowserWindowConstructorOptions with get, set + /// + /// The referrer that will be passed to the new window. May or may not result in the + /// Referer header being sent, depending on the referrer policy. + /// + abstract referrer: Referrer with get, set + /// + /// The post data that will be sent to the new window, along with the appropriate + /// headers that will be set. If no post data is to be sent, the value will be + /// null. Only defined when the window is being created by a form that set + /// target=_blank. + /// + abstract postBody: PostBody option with get, set + /// + /// Can be default, foreground-tab, background-tab, new-window, + /// save-to-disk and other. + /// + abstract disposition: WebContentsOn_newWindow with get, set + + type [] DidFailLoadEvent = + inherit Event + abstract errorCode: float with get, set + abstract errorDescription: string with get, set + abstract validatedURL: string with get, set + abstract isMainFrame: bool with get, set + + type [] DidFrameFinishLoadEvent = + inherit Event + abstract isMainFrame: bool with get, set + + type [] DidFrameNavigateEvent = + inherit Event + abstract url: string with get, set + /// -1 for non HTTP navigations + abstract httpResponseCode: float with get, set + /// empty for non HTTP navigations, + abstract httpStatusText: string with get, set + abstract isMainFrame: bool with get, set + abstract frameProcessId: float with get, set + abstract frameRoutingId: float with get, set + + type [] DidNavigateEvent = + inherit Event + abstract url: string with get, set + + type [] DidNavigateInPageEvent = + inherit Event + abstract isMainFrame: bool with get, set + abstract url: string with get, set + + type [] DidStartNavigationEvent = + inherit Event + abstract url: string with get, set + abstract isInPlace: bool with get, set + abstract isMainFrame: bool with get, set + abstract frameProcessId: float with get, set + abstract frameRoutingId: float with get, set + + type [] DisplayBalloonOptions = + /// Icon to use when iconType is custom. + abstract icon: U2 option with get, set + /// Can be none, info, warning, error or custom. Default is custom. + abstract iconType: DisplayBalloonOptionsIconType option with get, set + abstract title: string with get, set + abstract content: string with get, set + /// + /// The large version of the icon should be used. Default is true. Maps to + /// NIIF_LARGE_ICON. + /// + abstract largeIcon: bool option with get, set + /// Do not play the associated sound. Default is false. Maps to NIIF_NOSOUND. + abstract noSound: bool option with get, set + /// + /// Do not display the balloon notification if the current user is in "quiet time". + /// Default is false. Maps to NIIF_RESPECT_QUIET_TIME. + /// + abstract respectQuietTime: bool option with get, set + + type [] EnableNetworkEmulationOptions = + /// Whether to emulate network outage. Defaults to false. + abstract offline: bool option with get, set + /// RTT in ms. Defaults to 0 which will disable latency throttling. + abstract latency: float option with get, set + /// Download rate in Bps. Defaults to 0 which will disable download throttling. + abstract downloadThroughput: float option with get, set + /// Upload rate in Bps. Defaults to 0 which will disable upload throttling. + abstract uploadThroughput: float option with get, set + + type [] FeedURLOptions = + abstract url: string with get, set + /// HTTP request headers. + abstract headers: Record option with get, set + /// Can be json or default, see the Squirrel.Mac README for more information. + abstract serverType: FeedURLOptionsServerType option with get, set + + type [] FileIconOptions = + abstract size: FileIconOptionsSize with get, set + + type [] Filter = + /// Array of URL patterns that will be used to filter out the requests that do not + /// match the URL patterns. + abstract urls: ResizeArray with get, set + + type [] FindInPageOptions = + /// Whether to search forward or backward, defaults to true. + abstract forward: bool option with get, set + /// + /// Whether to begin a new text finding session with this request. Should be true + /// for initial requests, and false for follow-up requests. Defaults to false. + /// + abstract findNext: bool option with get, set + /// Whether search should be case-sensitive, defaults to false. + abstract matchCase: bool option with get, set + + type [] FocusOptions = + /// Make the receiver the active app even if another app is currently active. + abstract steal: bool with get, set + + type [] FoundInPageEvent = + inherit Event + abstract result: FoundInPageResult with get, set + + type [] FromPartitionOptions = + /// Whether to enable cache. + abstract cache: bool with get, set + + type [] HandlerDetails = + /// + /// The _resolved_ version of the URL passed to window.open(). e.g. opening a + /// window with window.open('foo') will yield something like + /// https://the-origin/the/current/path/foo. + /// + abstract url: string with get, set + /// Name of the window provided in window.open() + abstract frameName: string with get, set + /// Comma separated list of window features provided to window.open(). + abstract features: string with get, set + /// + /// Can be default, foreground-tab, background-tab, new-window, + /// save-to-disk or other. + /// + abstract disposition: WebContentsOn_newWindow with get, set + /// + /// The referrer that will be passed to the new window. May or may not result in the + /// Referer header being sent, depending on the referrer policy. + /// + abstract referrer: Referrer with get, set + /// + /// The post data that will be sent to the new window, along with the appropriate + /// headers that will be set. If no post data is to be sent, the value will be + /// null. Only defined when the window is being created by a form that set + /// target=_blank. + /// + abstract postBody: PostBody option with get, set + + type [] HeadersReceivedResponse = + abstract cancel: bool option with get, set + /// When provided, the server is assumed to have responded with these headers. + abstract responseHeaders: Record>> option with get, set + /// + /// Should be provided when overriding responseHeaders to change header status + /// otherwise original response header's status will be used. + /// + abstract statusLine: string option with get, set + + type [] HeapStatistics = + abstract totalHeapSize: float with get, set + abstract totalHeapSizeExecutable: float with get, set + abstract totalPhysicalSize: float with get, set + abstract totalAvailableSize: float with get, set + abstract usedHeapSize: float with get, set + abstract heapSizeLimit: float with get, set + abstract mallocedMemory: float with get, set + abstract peakMallocedMemory: float with get, set + abstract doesZapGarbage: bool with get, set + + type [] HidDeviceAddedDetails = + abstract device: ResizeArray with get, set + abstract frame: WebFrameMain with get, set + + type [] HidDeviceRemovedDetails = + abstract device: ResizeArray with get, set + abstract frame: WebFrameMain with get, set + + type [] IgnoreMouseEventsOptions = + /// + /// If true, forwards mouse move messages to Chromium, enabling mouse related events + /// such as mouseleave. Only used when ignore is true. If ignore is false, + /// forwarding is always disabled regardless of this value. + /// + abstract forward: bool option with get, set + + type [] ImportCertificateOptions = + /// Path for the pkcs12 file. + abstract certificate: string with get, set + /// Passphrase for the certificate. + abstract password: string with get, set + + type [] Info = + /// Security origin for the isolated world. + abstract securityOrigin: string option with get, set + /// Content Security Policy for the isolated world. + abstract csp: string option with get, set + /// Name for isolated world. Useful in devtools. + abstract name: string option with get, set + + type [] Input = + /// Either keyUp or keyDown. + abstract ``type``: string with get, set + /// Equivalent to KeyboardEvent.key. + abstract key: string with get, set + /// Equivalent to KeyboardEvent.code. + abstract code: string with get, set + /// Equivalent to KeyboardEvent.repeat. + abstract isAutoRepeat: bool with get, set + /// Equivalent to KeyboardEvent.isComposing. + abstract isComposing: bool with get, set + /// Equivalent to KeyboardEvent.shiftKey. + abstract shift: bool with get, set + /// Equivalent to KeyboardEvent.controlKey. + abstract control: bool with get, set + /// Equivalent to KeyboardEvent.altKey. + abstract alt: bool with get, set + /// Equivalent to KeyboardEvent.metaKey. + abstract meta: bool with get, set + + type [] InsertCSSOptions = + /// Can be either 'user' or 'author'; Specifying 'user' enables you to prevent + /// websites from overriding the CSS you insert. Default is 'author'. + abstract cssOrigin: string option with get, set + + type [] IpcMessageEvent = + inherit Event + abstract channel: string with get, set + abstract args: ResizeArray with get, set + + type [] Item = + /// The path to the file being dragged. + abstract file: string with get, set + /// The paths to the files being dragged. (files will override file field) + abstract files: ResizeArray option with get, set + /// The image must be non-empty on macOS. + abstract icon: U2 with get, set + + type [] JumpListSettings = + /// The minimum number of items that will be shown in the Jump List (for a more + /// detailed description of this value see the MSDN docs). + abstract minItems: float with get, set + /// + /// Array of JumpListItem objects that correspond to items that the user has + /// explicitly removed from custom categories in the Jump List. These items must not + /// be re-added to the Jump List in the **next** call to app.setJumpList(), + /// Windows will not display any custom category that contains any of the removed + /// items. + /// + abstract removedItems: ResizeArray with get, set + + type [] LoadCommitEvent = + inherit Event + abstract url: string with get, set + abstract isMainFrame: bool with get, set + + type [] LoadExtensionOptions = + /// + /// Whether to allow the extension to read local files over file:// protocol and + /// inject content scripts into file:// pages. This is required e.g. for loading + /// devtools extensions on file:// URLs. Defaults to false. + /// + abstract allowFileAccess: bool with get, set + + type [] LoadFileOptions = + /// Passed to url.format(). + abstract query: Record option with get, set + /// Passed to url.format(). + abstract search: string option with get, set + /// Passed to url.format(). + abstract hash: string option with get, set + + type [] LoadURLOptions = + /// An HTTP Referrer url. + abstract httpReferrer: U2 option with get, set + /// A user agent originating the request. + abstract userAgent: string option with get, set + /// Extra headers separated by "\n" + abstract extraHeaders: string option with get, set + abstract postData: Array> option with get, set + /// + /// Base url (with trailing path separator) for files to be loaded by the data url. + /// This is needed only if the specified url is a data url and needs to load other + /// files. + /// + abstract baseURLForDataURL: string option with get, set + + type [] LoginItemSettings = + /// true if the app is set to open at login. + abstract openAtLogin: bool with get, set + /// + /// true if the app is set to open as hidden at login. This setting is not + /// available on MAS builds. + /// + abstract openAsHidden: bool with get, set + /// + /// true if the app was opened at login automatically. This setting is not + /// available on MAS builds. + /// + abstract wasOpenedAtLogin: bool with get, set + /// + /// true if the app was opened as a hidden login item. This indicates that the app + /// should not open any windows at startup. This setting is not available on MAS + /// builds. + /// + abstract wasOpenedAsHidden: bool with get, set + /// + /// true if the app was opened as a login item that should restore the state from + /// the previous session. This indicates that the app should restore the windows + /// that were open the last time the app was closed. This setting is not available + /// on MAS builds. + /// + abstract restoreState: bool with get, set + /// + /// true if app is set to open at login and its run key is not deactivated. This + /// differs from openAtLogin as it ignores the args option, this property will + /// be true if the given executable would be launched at login with **any** + /// arguments. + /// + abstract executableWillLaunchAtLogin: bool with get, set + abstract launchItems: ResizeArray with get, set + + type [] LoginItemSettingsOptions = + /// The executable path to compare against. Defaults to process.execPath. + abstract path: string option with get, set + /// The command-line arguments to compare against. Defaults to an empty array. + abstract args: ResizeArray option with get, set + + type [] MenuItemConstructorOptions = + /// + /// Will be called with click(menuItem, browserWindow, event) when the menu item + /// is clicked. + /// + abstract click: (MenuItem -> BrowserWindow option -> KeyboardEvent -> unit) option with get, set + /// + /// Can be undo, redo, cut, copy, paste, pasteAndMatchStyle, delete, + /// selectAll, reload, forceReload, toggleDevTools, resetZoom, zoomIn, + /// zoomOut, toggleSpellChecker, togglefullscreen, window, minimize, + /// close, help, about, services, hide, hideOthers, unhide, quit, + /// startSpeaking, stopSpeaking, zoom, front, appMenu, fileMenu, + /// editMenu, viewMenu, shareMenu, recentDocuments, toggleTabBar, + /// selectNextTab, selectPreviousTab, mergeAllWindows, clearRecentDocuments, + /// moveTabToNewWindow or windowMenu - Define the action of the menu item, when + /// specified the click property will be ignored. See roles. + /// + abstract role: MenuItemRole option with get, set + /// Can be normal, separator, submenu, checkbox or radio. + abstract ``type``: MenuItemType option with get, set + abstract label: string option with get, set + abstract sublabel: string option with get, set + /// Hover text for this menu item. + abstract toolTip: string option with get, set + abstract accelerator: Accelerator option with get, set + abstract icon: U2 option with get, set + /// If false, the menu item will be greyed out and unclickable. + abstract enabled: bool option with get, set + /// + /// default is true, and when false will prevent the accelerator from triggering + /// the item if the item is not visible`. + /// + abstract acceleratorWorksWhenHidden: bool option with get, set + /// If false, the menu item will be entirely hidden. + abstract visible: bool option with get, set + /// Should only be specified for checkbox or radio type menu items. + abstract ``checked``: bool option with get, set + /// + /// If false, the accelerator won't be registered with the system, but it will still + /// be displayed. Defaults to true. + /// + abstract registerAccelerator: bool option with get, set + /// The item to share when the role is shareMenu. + abstract sharingItem: SharingItem option with get, set + /// + /// Should be specified for submenu type menu items. If submenu is specified, + /// the type: 'submenu' can be omitted. If the value is not a Menu then it will + /// be automatically converted to one using Menu.buildFromTemplate. + /// + abstract submenu: U2, Menu> option with get, set + /// Unique within a single menu. If defined then it can be used as a reference to + /// this item by the position attribute. + abstract id: string option with get, set + /// Inserts this item before the item with the specified label. If the referenced + /// item doesn't exist the item will be inserted at the end of the menu. Also + /// implies that the menu item in question should be placed in the same “group” as + /// the item. + abstract before: ResizeArray option with get, set + /// Inserts this item after the item with the specified label. If the referenced + /// item doesn't exist the item will be inserted at the end of the menu. + abstract after: ResizeArray option with get, set + /// Provides a means for a single context menu to declare the placement of their + /// containing group before the containing group of the item with the specified + /// label. + abstract beforeGroupContaining: ResizeArray option with get, set + /// Provides a means for a single context menu to declare the placement of their + /// containing group after the containing group of the item with the specified + /// label. + abstract afterGroupContaining: ResizeArray option with get, set + + type [] MessageBoxOptions = + /// Content of the message box. + abstract message: string with get, set + /// + /// Can be "none", "info", "error", "question" or "warning". On Windows, + /// "question" displays the same icon as "info", unless you set an icon using + /// the "icon" option. On macOS, both "warning" and "error" display the same + /// warning icon. + /// + abstract ``type``: string option with get, set + /// Array of texts for buttons. On Windows, an empty array will result in one button + /// labeled "OK". + abstract buttons: ResizeArray option with get, set + /// Index of the button in the buttons array which will be selected by default when + /// the message box opens. + abstract defaultId: float option with get, set + /// Title of the message box, some platforms will not show it. + abstract title: string option with get, set + /// Extra information of the message. + abstract detail: string option with get, set + /// If provided, the message box will include a checkbox with the given label. + abstract checkboxLabel: string option with get, set + /// Initial checked state of the checkbox. false by default. + abstract checkboxChecked: bool option with get, set + abstract icon: NativeImage option with get, set + /// + /// The index of the button to be used to cancel the dialog, via the Esc key. By + /// default this is assigned to the first button with "cancel" or "no" as the label. + /// If no such labeled buttons exist and this option is not set, 0 will be used as + /// the return value. + /// + abstract cancelId: float option with get, set + /// + /// On Windows Electron will try to figure out which one of the buttons are common + /// buttons (like "Cancel" or "Yes"), and show the others as command links in the + /// dialog. This can make the dialog appear in the style of modern Windows apps. If + /// you don't like this behavior, you can set noLink to true. + /// + abstract noLink: bool option with get, set + /// + /// Normalize the keyboard access keys across platforms. Default is false. + /// Enabling this assumes & is used in the button labels for the placement of the + /// keyboard shortcut access key and labels will be converted so they work correctly + /// on each platform, & characters are removed on macOS, converted to _ on + /// Linux, and left untouched on Windows. For example, a button label of Vie&w + /// will be converted to Vie_w on Linux and View on macOS and can be selected + /// via Alt-W on Windows and Linux. + /// + abstract normalizeAccessKeys: bool option with get, set + + type [] MessageBoxReturnValue = + /// The index of the clicked button. + abstract response: float with get, set + /// The checked state of the checkbox if checkboxLabel was set. Otherwise false. + abstract checkboxChecked: bool with get, set + + type [] MessageBoxSyncOptions = + /// Content of the message box. + abstract message: string with get, set + /// + /// Can be "none", "info", "error", "question" or "warning". On Windows, + /// "question" displays the same icon as "info", unless you set an icon using + /// the "icon" option. On macOS, both "warning" and "error" display the same + /// warning icon. + /// + abstract ``type``: string option with get, set + /// Array of texts for buttons. On Windows, an empty array will result in one button + /// labeled "OK". + abstract buttons: ResizeArray option with get, set + /// Index of the button in the buttons array which will be selected by default when + /// the message box opens. + abstract defaultId: float option with get, set + /// Title of the message box, some platforms will not show it. + abstract title: string option with get, set + /// Extra information of the message. + abstract detail: string option with get, set + abstract icon: U2 option with get, set + /// + /// The index of the button to be used to cancel the dialog, via the Esc key. By + /// default this is assigned to the first button with "cancel" or "no" as the label. + /// If no such labeled buttons exist and this option is not set, 0 will be used as + /// the return value. + /// + abstract cancelId: float option with get, set + /// + /// On Windows Electron will try to figure out which one of the buttons are common + /// buttons (like "Cancel" or "Yes"), and show the others as command links in the + /// dialog. This can make the dialog appear in the style of modern Windows apps. If + /// you don't like this behavior, you can set noLink to true. + /// + abstract noLink: bool option with get, set + /// + /// Normalize the keyboard access keys across platforms. Default is false. + /// Enabling this assumes & is used in the button labels for the placement of the + /// keyboard shortcut access key and labels will be converted so they work correctly + /// on each platform, & characters are removed on macOS, converted to _ on + /// Linux, and left untouched on Windows. For example, a button label of Vie&w + /// will be converted to Vie_w on Linux and View on macOS and can be selected + /// via Alt-W on Windows and Linux. + /// + abstract normalizeAccessKeys: bool option with get, set + + type [] MessageDetails = + /// The actual console message + abstract message: string with get, set + /// The version ID of the service worker that sent the log message + abstract versionId: float with get, set + /// + /// The type of source for this message. Can be javascript, xml, network, + /// console-api, storage, app-cache, rendering, security, deprecation, + /// worker, violation, intervention, recommendation or other. + /// + abstract source: MessageDetailsSource with get, set + /// + /// The log level, from 0 to 3. In order it matches verbose, info, warning and + /// error. + /// + abstract level: float with get, set + /// The URL the message came from + abstract sourceUrl: string with get, set + /// The line number of the source that triggered this console message + abstract lineNumber: float with get, set + + type [] MessageEvent = + abstract data: obj option with get, set + abstract ports: ResizeArray with get, set + + type [] MoveToApplicationsFolderOptions = + /// A handler for potential conflict in move failure. + abstract conflictHandler: (MoveToApplicationsFolderOptionsConflictHandler -> bool) option with get, set + + type [] NewWindowEvent = + inherit Event + abstract url: string with get, set + abstract frameName: string with get, set + /// + /// Can be default, foreground-tab, background-tab, new-window, + /// save-to-disk and other. + /// + abstract disposition: WebContentsOn_newWindow with get, set + /// The options which should be used for creating the new BrowserWindow. + abstract options: BrowserWindowConstructorOptions with get, set + + type [] NotificationConstructorOptions = + /// A title for the notification, which will be shown at the top of the notification + /// window when it is shown. + abstract title: string option with get, set + /// A subtitle for the notification, which will be displayed below the title. + abstract subtitle: string option with get, set + /// The body text of the notification, which will be displayed below the title or + /// subtitle. + abstract body: string option with get, set + /// Whether or not to emit an OS notification noise when showing the notification. + abstract silent: bool option with get, set + /// An icon to use in the notification. + abstract icon: U2 option with get, set + /// Whether or not to add an inline reply option to the notification. + abstract hasReply: bool option with get, set + /// The timeout duration of the notification. Can be 'default' or 'never'. + abstract timeoutType: NotificationTimeoutType option with get, set + /// The placeholder to write in the inline reply input field. + abstract replyPlaceholder: string option with get, set + /// The name of the sound file to play when the notification is shown. + abstract sound: string option with get, set + /// The urgency level of the notification. Can be 'normal', 'critical', or 'low'. + abstract urgency: NotificationUrgency option with get, set + /// + /// Actions to add to the notification. Please read the available actions and + /// limitations in the NotificationAction documentation. + /// + abstract actions: ResizeArray option with get, set + /// + /// A custom title for the close button of an alert. An empty string will cause the + /// default localized text to be used. + /// + abstract closeButtonText: string option with get, set + /// + /// A custom description of the Notification on Windows superseding all properties + /// above. Provides full customization of design and behavior of the notification. + /// + abstract toastXml: string option with get, set + + type [] OnBeforeRedirectListenerDetails = + abstract id: float with get, set + abstract url: string with get, set + abstract method: string with get, set + abstract webContentsId: float option with get, set + abstract webContents: WebContents option with get, set + abstract frame: WebFrameMain option with get, set + /// + /// Can be mainFrame, subFrame, stylesheet, script, image, font, + /// object, xhr, ping, cspReport, media, webSocket or other. + /// + abstract resourceType: OnBeforeRedirectListenerDetailsResourceType with get, set + abstract referrer: string with get, set + abstract timestamp: float with get, set + abstract redirectURL: string with get, set + abstract statusCode: float with get, set + abstract statusLine: string with get, set + /// The server IP address that the request was actually sent to. + abstract ip: string option with get, set + abstract fromCache: bool with get, set + abstract responseHeaders: Record> option with get, set + + type [] OnBeforeRequestListenerDetails = + abstract id: float with get, set + abstract url: string with get, set + abstract method: string with get, set + abstract webContentsId: float option with get, set + abstract webContents: WebContents option with get, set + abstract frame: WebFrameMain option with get, set + /// + /// Can be mainFrame, subFrame, stylesheet, script, image, font, + /// object, xhr, ping, cspReport, media, webSocket or other. + /// + abstract resourceType: OnBeforeRedirectListenerDetailsResourceType with get, set + abstract referrer: string with get, set + abstract timestamp: float with get, set + abstract uploadData: ResizeArray with get, set + + type [] OnBeforeSendHeadersListenerDetails = + abstract id: float with get, set + abstract url: string with get, set + abstract method: string with get, set + abstract webContentsId: float option with get, set + abstract webContents: WebContents option with get, set + abstract frame: WebFrameMain option with get, set + /// + /// Can be mainFrame, subFrame, stylesheet, script, image, font, + /// object, xhr, ping, cspReport, media, webSocket or other. + /// + abstract resourceType: OnBeforeRedirectListenerDetailsResourceType with get, set + abstract referrer: string with get, set + abstract timestamp: float with get, set + abstract requestHeaders: Record with get, set + + type [] OnCompletedListenerDetails = + abstract id: float with get, set + abstract url: string with get, set + abstract method: string with get, set + abstract webContentsId: float option with get, set + abstract webContents: WebContents option with get, set + abstract frame: WebFrameMain option with get, set + /// + /// Can be mainFrame, subFrame, stylesheet, script, image, font, + /// object, xhr, ping, cspReport, media, webSocket or other. + /// + abstract resourceType: OnBeforeRedirectListenerDetailsResourceType with get, set + abstract referrer: string with get, set + abstract timestamp: float with get, set + abstract responseHeaders: Record> option with get, set + abstract fromCache: bool with get, set + abstract statusCode: float with get, set + abstract statusLine: string with get, set + abstract error: string with get, set + + type [] OnErrorOccurredListenerDetails = + abstract id: float with get, set + abstract url: string with get, set + abstract method: string with get, set + abstract webContentsId: float option with get, set + abstract webContents: WebContents option with get, set + abstract frame: WebFrameMain option with get, set + /// + /// Can be mainFrame, subFrame, stylesheet, script, image, font, + /// object, xhr, ping, cspReport, media, webSocket or other. + /// + abstract resourceType: OnBeforeRedirectListenerDetailsResourceType with get, set + abstract referrer: string with get, set + abstract timestamp: float with get, set + abstract fromCache: bool with get, set + /// The error description. + abstract error: string with get, set + + type [] OnHeadersReceivedListenerDetails = + abstract id: float with get, set + abstract url: string with get, set + abstract method: string with get, set + abstract webContentsId: float option with get, set + abstract webContents: WebContents option with get, set + abstract frame: WebFrameMain option with get, set + /// + /// Can be mainFrame, subFrame, stylesheet, script, image, font, + /// object, xhr, ping, cspReport, media, webSocket or other. + /// + abstract resourceType: OnBeforeRedirectListenerDetailsResourceType with get, set + abstract referrer: string with get, set + abstract timestamp: float with get, set + abstract statusLine: string with get, set + abstract statusCode: float with get, set + abstract responseHeaders: Record> option with get, set + + type [] OnResponseStartedListenerDetails = + abstract id: float with get, set + abstract url: string with get, set + abstract method: string with get, set + abstract webContentsId: float option with get, set + abstract webContents: WebContents option with get, set + abstract frame: WebFrameMain option with get, set + /// + /// Can be mainFrame, subFrame, stylesheet, script, image, font, + /// object, xhr, ping, cspReport, media, webSocket or other. + /// + abstract resourceType: OnBeforeRedirectListenerDetailsResourceType with get, set + abstract referrer: string with get, set + abstract timestamp: float with get, set + abstract responseHeaders: Record> option with get, set + /// Indicates whether the response was fetched from disk cache. + abstract fromCache: bool with get, set + abstract statusCode: float with get, set + abstract statusLine: string with get, set + + type [] OnSendHeadersListenerDetails = + abstract id: float with get, set + abstract url: string with get, set + abstract method: string with get, set + abstract webContentsId: float option with get, set + abstract webContents: WebContents option with get, set + abstract frame: WebFrameMain option with get, set + /// + /// Can be mainFrame, subFrame, stylesheet, script, image, font, + /// object, xhr, ping, cspReport, media, webSocket or other. + /// + abstract resourceType: OnBeforeRedirectListenerDetailsResourceType with get, set + abstract referrer: string with get, set + abstract timestamp: float with get, set + abstract requestHeaders: Record with get, set + + type [] OpenDevToolsOptions = + /// + /// Opens the devtools with specified dock state, can be right, bottom, + /// undocked, detach. Defaults to last used dock state. In undocked mode it's + /// possible to dock back. In detach mode it's not. + /// + abstract mode: OpenDevToolsOptionsMode with get, set + /// + /// Whether to bring the opened devtools window to the foreground. The default is + /// true. + /// + abstract activate: bool option with get, set + + type [] OpenDialogOptions = + abstract title: string option with get, set + abstract defaultPath: string option with get, set + /// Custom label for the confirmation button, when left empty the default label will + /// be used. + abstract buttonLabel: string option with get, set + abstract filters: ResizeArray option with get, set + /// Contains which features the dialog should use. The following values are + /// supported: + abstract properties: Array option with get, set + /// Message to display above input boxes. + abstract message: string option with get, set + /// Create security scoped bookmarks when packaged for the Mac App Store. + abstract securityScopedBookmarks: bool option with get, set + + type [] OpenDialogReturnValue = + /// whether or not the dialog was canceled. + abstract canceled: bool with get, set + /// An array of file paths chosen by the user. If the dialog is cancelled this will + /// be an empty array. + abstract filePaths: ResizeArray with get, set + /// + /// An array matching the filePaths array of base64 encoded strings which contains + /// security scoped bookmark data. securityScopedBookmarks must be enabled for + /// this to be populated. (For return values, see table here.) + /// + abstract bookmarks: ResizeArray option with get, set + + type [] OpenDialogSyncOptions = + abstract title: string option with get, set + abstract defaultPath: string option with get, set + /// Custom label for the confirmation button, when left empty the default label will + /// be used. + abstract buttonLabel: string option with get, set + abstract filters: ResizeArray option with get, set + /// Contains which features the dialog should use. The following values are + /// supported: + abstract properties: Array option with get, set + /// Message to display above input boxes. + abstract message: string option with get, set + /// Create security scoped bookmarks when packaged for the Mac App Store. + abstract securityScopedBookmarks: bool option with get, set + + type [] OpenExternalOptions = + /// true to bring the opened application to the foreground. The default is true. + abstract activate: bool option with get, set + /// The working directory. + abstract workingDirectory: string option with get, set + + type [] Options = + interface end + + type [] PageFaviconUpdatedEvent = + inherit Event + /// Array of URLs. + abstract favicons: ResizeArray with get, set + + type [] PageTitleUpdatedEvent = + inherit Event + abstract title: string with get, set + abstract explicitSet: bool with get, set + + type [] Parameters = + /// Specify the screen type to emulate (default: desktop): + abstract screenPosition: ParametersScreenPosition with get, set + /// Set the emulated screen size (screenPosition == mobile). + abstract screenSize: Size with get, set + /// Position the view on the screen (screenPosition == mobile) (default: `{ x: 0, y: + /// 0 }`). + abstract viewPosition: Point with get, set + /// + /// Set the device scale factor (if zero defaults to original device scale factor) + /// (default: 0). + /// + abstract deviceScaleFactor: float with get, set + /// Set the emulated view size (empty means no override) + abstract viewSize: Size with get, set + /// + /// Scale of emulated view inside available space (not in fit to view mode) + /// (default: 1). + /// + abstract scale: float with get, set + + type [] Payment = + /// The identifier of the purchased product. + abstract productIdentifier: string with get, set + /// The quantity purchased. + abstract quantity: float with get, set + + type [] PermissionCheckHandlerHandlerDetails = + /// The origin of the frame embedding the frame that made the permission check. + /// Only set for cross-origin sub frames making permission checks. + abstract embeddingOrigin: string option with get, set + /// The security origin of the media check. + abstract securityOrigin: string option with get, set + /// The type of media access being requested, can be video, audio or unknown + abstract mediaType: PermissionCheckHandlerHandlerDetailsMediaType option with get, set + /// The last URL the requesting frame loaded. This is not provided for cross-origin + /// sub frames making permission checks. + abstract requestingUrl: string option with get, set + /// Whether the frame making the request is the main frame + abstract isMainFrame: bool with get, set + + type [] PermissionRequestHandlerHandlerDetails = + /// The url of the openExternal request. + abstract externalURL: string option with get, set + /// The security origin of the media request. + abstract securityOrigin: string option with get, set + /// The types of media access being requested, elements can be video or audio + abstract mediaTypes: Array option with get, set + /// The last URL the requesting frame loaded + abstract requestingUrl: string with get, set + /// Whether the frame making the request is the main frame + abstract isMainFrame: bool with get, set + + type [] PluginCrashedEvent = + inherit Event + abstract name: string with get, set + abstract version: string with get, set + + type [] PopupOptions = + /// Default is the focused window. + abstract window: BrowserWindow option with get, set + /// + /// Default is the current mouse cursor position. Must be declared if y is + /// declared. + /// + abstract x: float option with get, set + /// + /// Default is the current mouse cursor position. Must be declared if x is + /// declared. + /// + abstract y: float option with get, set + /// + /// The index of the menu item to be positioned under the mouse cursor at the + /// specified coordinates. Default is -1. + /// + abstract positioningItem: float option with get, set + /// Called when menu is closed. + abstract callback: (unit -> unit) option with get, set + + type [] PreconnectOptions = + /// URL for preconnect. Only the origin is relevant for opening the socket. + abstract url: string with get, set + /// number of sockets to preconnect. Must be between 1 and 6. Defaults to 1. + abstract numSockets: float option with get, set + + type [] PrintToPDFOptions = + /// the header and footer for the PDF. + abstract headerFooter: Record option with get, set + /// true for landscape, false for portrait. + abstract landscape: bool option with get, set + /// + /// Specifies the type of margins to use. Uses 0 for default margin, 1 for no + /// margin, and 2 for minimum margin. and width in microns. + /// + abstract marginsType: float option with get, set + /// The scale factor of the web page. Can range from 0 to 100. + abstract scaleFactor: float option with get, set + /// The page range to print. On macOS, only the first range is honored. + abstract pageRanges: Record option with get, set + /// + /// Specify page size of the generated PDF. Can be A3, A4, A5, Legal, + /// Letter, Tabloid or an Object containing height + /// + abstract pageSize: U2 option with get, set + /// Whether to print CSS backgrounds. + abstract printBackground: bool option with get, set + /// Whether to print selection only. + abstract printSelectionOnly: bool option with get, set + + type [] Privileges = + /// Default false. + abstract standard: bool option with get, set + /// Default false. + abstract secure: bool option with get, set + /// Default false. + abstract bypassCSP: bool option with get, set + /// Default false. + abstract allowServiceWorkers: bool option with get, set + /// Default false. + abstract supportFetchAPI: bool option with get, set + /// Default false. + abstract corsEnabled: bool option with get, set + /// Default false. + abstract stream: bool option with get, set + + type [] ProgressBarOptions = + /// + /// Mode for the progress bar. Can be none, normal, indeterminate, error or + /// paused. + /// + abstract mode: ProgressBarOptionsMode with get, set + + type [] Provider = + abstract spellCheck: (ResizeArray -> (ResizeArray -> unit) -> unit) with get, set + + type [] ReadBookmark = + abstract title: string with get, set + abstract url: string with get, set + + type [] RegistrationCompletedDetails = + /// The base URL that a service worker is registered for + abstract scope: string with get, set + + type [] RelaunchOptions = + abstract args: ResizeArray option with get, set + abstract execPath: string option with get, set + + type [] RenderProcessGoneDetails = + /// The reason the render process is gone. Possible values: + abstract reason: DetailsReason with get, set + /// + /// The exit code of the process, unless reason is launch-failed, in which case + /// exitCode will be a platform-specific launch failure error code. + /// + abstract exitCode: float with get, set + + type [] Request = + abstract hostname: string with get, set + abstract certificate: Certificate with get, set + abstract validatedCertificate: Certificate with get, set + /// Verification result from chromium. + abstract verificationResult: string with get, set + /// Error code. + abstract errorCode: float with get, set + + type [] ResizeOptions = + /// Defaults to the image's width. + abstract width: float option with get, set + /// Defaults to the image's height. + abstract height: float option with get, set + /// + /// The desired quality of the resize image. Possible values are good, better, + /// or best. The default is best. These values express a desired quality/speed + /// tradeoff. They are translated into an algorithm-specific method that depends on + /// the capabilities (CPU, GPU) of the underlying platform. It is possible for all + /// three methods to be mapped to the same algorithm on a given platform. + /// + abstract quality: string option with get, set + + type [] ResourceUsage = + abstract images: MemoryUsageDetails with get, set + abstract scripts: MemoryUsageDetails with get, set + abstract cssStyleSheets: MemoryUsageDetails with get, set + abstract xslStyleSheets: MemoryUsageDetails with get, set + abstract fonts: MemoryUsageDetails with get, set + abstract other: MemoryUsageDetails with get, set + + type [] Response = + abstract cancel: bool option with get, set + /// The original request is prevented from being sent or completed and is instead + /// redirected to the given URL. + abstract redirectURL: string option with get, set + + type [] Result = + abstract requestId: float with get, set + /// Position of the active match. + abstract activeMatchOrdinal: float with get, set + /// Number of Matches. + abstract matches: float with get, set + /// Coordinates of first match region. + abstract selectionArea: Rectangle with get, set + abstract finalUpdate: bool with get, set + + type [] SaveDialogOptions = + /// The dialog title. Cannot be displayed on some _Linux_ desktop environments. + abstract title: string option with get, set + /// Absolute directory path, absolute file path, or file name to use by default. + abstract defaultPath: string option with get, set + /// Custom label for the confirmation button, when left empty the default label will + /// be used. + abstract buttonLabel: string option with get, set + abstract filters: ResizeArray option with get, set + /// Message to display above text fields. + abstract message: string option with get, set + /// Custom label for the text displayed in front of the filename text field. + abstract nameFieldLabel: string option with get, set + /// Show the tags input box, defaults to true. + abstract showsTagField: bool option with get, set + abstract properties: Array option with get, set + /// + /// Create a security scoped bookmark when packaged for the Mac App Store. If this + /// option is enabled and the file doesn't already exist a blank file will be + /// created at the chosen path. + /// + abstract securityScopedBookmarks: bool option with get, set + + type [] SaveDialogReturnValue = + /// whether or not the dialog was canceled. + abstract canceled: bool with get, set + /// If the dialog is canceled, this will be undefined. + abstract filePath: string option with get, set + /// + /// Base64 encoded string which contains the security scoped bookmark data for the + /// saved file. securityScopedBookmarks must be enabled for this to be present. + /// (For return values, see table here.) + /// + abstract bookmark: string option with get, set + + type [] SaveDialogSyncOptions = + /// The dialog title. Cannot be displayed on some _Linux_ desktop environments. + abstract title: string option with get, set + /// Absolute directory path, absolute file path, or file name to use by default. + abstract defaultPath: string option with get, set + /// Custom label for the confirmation button, when left empty the default label will + /// be used. + abstract buttonLabel: string option with get, set + abstract filters: ResizeArray option with get, set + /// Message to display above text fields. + abstract message: string option with get, set + /// Custom label for the text displayed in front of the filename text field. + abstract nameFieldLabel: string option with get, set + /// Show the tags input box, defaults to true. + abstract showsTagField: bool option with get, set + abstract properties: Array option with get, set + /// + /// Create a security scoped bookmark when packaged for the Mac App Store. If this + /// option is enabled and the file doesn't already exist a blank file will be + /// created at the chosen path. + /// + abstract securityScopedBookmarks: bool option with get, set + + type [] SelectHidDeviceDetails = + abstract deviceList: ResizeArray with get, set + abstract frame: WebFrameMain with get, set + + type [] Settings = + /// + /// true to open the app at login, false to remove the app as a login item. + /// Defaults to false. + /// + abstract openAtLogin: bool option with get, set + /// + /// true to open the app as hidden. Defaults to false. The user can edit this + /// setting from the System Preferences so + /// app.getLoginItemSettings().wasOpenedAsHidden should be checked when the app is + /// opened to know the current value. This setting is not available on MAS builds. + /// + abstract openAsHidden: bool option with get, set + /// The executable to launch at login. Defaults to process.execPath. + abstract path: string option with get, set + /// + /// The command-line arguments to pass to the executable. Defaults to an empty + /// array. Take care to wrap paths in quotes. + /// + abstract args: ResizeArray option with get, set + /// + /// true will change the startup approved registry key and enable / disable the + /// App in Task Manager and Windows Settings. Defaults to true. + /// + abstract enabled: bool option with get, set + /// + /// value name to write into registry. Defaults to the app's AppUserModelId(). Set + /// the app's login item settings. + /// + abstract name: string option with get, set + + type [] SourcesOptions = + /// + /// An array of Strings that lists the types of desktop sources to be captured, + /// available types are screen and window. + /// + abstract types: ResizeArray with get, set + /// + /// The size that the media source thumbnail should be scaled to. Default is 150 x + /// 150. Set width or height to 0 when you do not need the thumbnails. This will + /// save the processing time required for capturing the content of each window and + /// screen. + /// + abstract thumbnailSize: Size option with get, set + /// Set to true to enable fetching window icons. The default value is false. When + /// false the appIcon property of the sources return null. Same if a source has the + /// type screen. + abstract fetchWindowIcons: bool option with get, set + + type [] SSLConfigConfig = + /// + /// Can be tls1, tls1.1, tls1.2 or tls1.3. The minimum SSL version to allow + /// when connecting to remote servers. Defaults to tls1. + /// + abstract minVersion: string option with get, set + /// + /// Can be tls1.2 or tls1.3. The maximum SSL version to allow when connecting to + /// remote servers. Defaults to tls1.3. + /// + abstract maxVersion: string option with get, set + /// + /// List of cipher suites which should be explicitly prevented from being used in + /// addition to those disabled by the net built-in policy. Supported literal forms: + /// 0xAABB, where AA is cipher_suite[0] and BB is cipher_suite[1], as defined in + /// RFC 2246, Section 7.4.1.2. Unrecognized but parsable cipher suites in this form + /// will not return an error. Ex: To disable TLS_RSA_WITH_RC4_128_MD5, specify + /// 0x0004, while to disable TLS_ECDH_ECDSA_WITH_RC4_128_SHA, specify 0xC002. Note + /// that TLSv1.3 ciphers cannot be disabled using this mechanism. + /// + abstract disabledCipherSuites: ResizeArray option with get, set + + type [] StartLoggingOptions = + /// + /// What kinds of data should be captured. By default, only metadata about requests + /// will be captured. Setting this to includeSensitive will include cookies and + /// authentication data. Setting it to everything will include all bytes + /// transferred on sockets. Can be default, includeSensitive or everything. + /// + abstract captureMode: StartLoggingOptionsCaptureMode option with get, set + /// When the log grows beyond this size, logging will automatically stop. Defaults + /// to unlimited. + abstract maxFileSize: float option with get, set + + type [] SystemMemoryInfo = + /// The total amount of physical memory in Kilobytes available to the system. + abstract total: float with get, set + /// The total amount of memory not being used by applications or disk cache. + abstract free: float with get, set + /// The total amount of swap memory in Kilobytes available to the system. + abstract swapTotal: float with get, set + /// The free amount of swap memory in Kilobytes available to the system. + abstract swapFree: float with get, set + + type [] TitleOptions = + /// + /// The font family variant to display, can be monospaced or monospacedDigit. + /// monospaced is available in macOS 10.15+ and monospacedDigit is available in + /// macOS 10.11+. When left blank, the title uses the default system font. + /// + abstract fontType: TitleOptionsFontType option with get, set + + type [] ToBitmapOptions = + /// Defaults to 1.0. + abstract scaleFactor: float option with get, set + + type [] ToDataURLOptions = + /// Defaults to 1.0. + abstract scaleFactor: float option with get, set + + type [] ToPNGOptions = + /// Defaults to 1.0. + abstract scaleFactor: float option with get, set + + type [] TouchBarButtonConstructorOptions = + /// Button text. + abstract label: string option with get, set + /// A short description of the button for use by screenreaders like VoiceOver. + abstract accessibilityLabel: string option with get, set + /// Button background color in hex format, i.e #ABCDEF. + abstract backgroundColor: string option with get, set + /// Button icon. + abstract icon: U2 option with get, set + /// Can be left, right or overlay. Defaults to overlay. + abstract iconPosition: TouchBarButtonIconPosition option with get, set + /// Function to call when the button is clicked. + abstract click: (unit -> unit) option with get, set + /// Whether the button is in an enabled state. Default is true. + abstract enabled: bool option with get, set + + type [] TouchBarColorPickerConstructorOptions = + /// Array of hex color strings to appear as possible colors to select. + abstract availableColors: ResizeArray option with get, set + /// The selected hex color in the picker, i.e #ABCDEF. + abstract selectedColor: string option with get, set + /// Function to call when a color is selected. + abstract change: (string -> unit) option with get, set + + type [] TouchBarConstructorOptions = + abstract items: Array option with get, set + abstract escapeItem: obj option with get, set + + type [] TouchBarGroupConstructorOptions = + /// Items to display as a group. + abstract items: TouchBar with get, set + + type [] TouchBarLabelConstructorOptions = + /// Text to display. + abstract label: string option with get, set + /// A short description of the button for use by screenreaders like VoiceOver. + abstract accessibilityLabel: string option with get, set + /// Hex color of text, i.e #ABCDEF. + abstract textColor: string option with get, set + + type [] TouchBarPopoverConstructorOptions = + /// Popover button text. + abstract label: string option with get, set + /// Popover button icon. + abstract icon: NativeImage option with get, set + /// Items to display in the popover. + abstract items: TouchBar with get, set + /// + /// true to display a close button on the left of the popover, false to not show + /// it. Default is true. + /// + abstract showCloseButton: bool option with get, set + + type [] TouchBarScrubberConstructorOptions = + /// An array of items to place in this scrubber. + abstract items: ResizeArray with get, set + /// Called when the user taps an item that was not the last tapped item. + abstract select: (float -> unit) option with get, set + /// Called when the user taps any item. + abstract highlight: (float -> unit) option with get, set + /// + /// Selected item style. Can be background, outline or none. Defaults to + /// none. + /// + abstract selectedStyle: TouchBarScrubberOverlayStyle option with get, set + /// + /// Selected overlay item style. Can be background, outline or none. Defaults + /// to none. + /// + abstract overlayStyle: TouchBarScrubberOverlayStyle option with get, set + /// + /// Whether to show arrow buttons. Defaults to false and is only shown if items + /// is non-empty. + /// + abstract showArrowButtons: bool option with get, set + /// Can be fixed or free. The default is free. + abstract mode: TouchBarScrubberMode option with get, set + /// Defaults to true. + abstract continuous: bool option with get, set + + type [] TouchBarSegmentedControlConstructorOptions = + /// Style of the segments: + abstract segmentStyle: TouchBarSegmentedControlConstructorOptionsSegmentStyle option with get, set + /// The selection mode of the control: + abstract mode: TouchBarSegmentedControlMode option with get, set + /// An array of segments to place in this control. + abstract segments: ResizeArray with get, set + /// + /// The index of the currently selected segment, will update automatically with user + /// interaction. When the mode is multiple it will be the last selected item. + /// + abstract selectedIndex: float option with get, set + /// Called when the user selects a new segment. + abstract change: (float -> bool -> unit) option with get, set + + type [] TouchBarSliderConstructorOptions = + /// Label text. + abstract label: string option with get, set + /// Selected value. + abstract value: float option with get, set + /// Minimum value. + abstract minValue: float option with get, set + /// Maximum value. + abstract maxValue: float option with get, set + /// Function to call when the slider is changed. + abstract change: (float -> unit) option with get, set + + type [] TouchBarSpacerConstructorOptions = + /// Size of spacer, possible values are: + abstract size: TouchBarSpacerSize option with get, set + + type [] TraceBufferUsageReturnValue = + abstract value: float with get, set + abstract percentage: float with get, set + + type [] UpdateTargetUrlEvent = + inherit Event + abstract url: string with get, set + + type [] UploadProgress = + /// Whether the request is currently active. If this is false no other properties + /// will be set + abstract active: bool with get, set + /// + /// Whether the upload has started. If this is false both current and total will + /// be set to 0. + /// + abstract started: bool with get, set + /// The number of bytes that have been uploaded so far + abstract current: float with get, set + /// The number of bytes that will be uploaded this request + abstract total: float with get, set + + type [] VisibleOnAllWorkspacesOptions = + /// Sets whether the window should be visible above fullscreen windows. + abstract visibleOnFullScreen: bool option with get, set + /// + /// Calling setVisibleOnAllWorkspaces will by default transform the process type + /// between UIElementApplication and ForegroundApplication to ensure the correct + /// behavior. However, this will hide the window and dock for a short time every + /// time it is called. If your window is already of type UIElementApplication, you + /// can bypass this transformation by passing true to skipTransformProcessType. + /// + abstract skipTransformProcessType: bool option with get, set + + type [] WebContentsPrintOptions = + /// Don't ask user for print settings. Default is false. + abstract silent: bool option with get, set + /// Prints the background color and image of the web page. Default is false. + abstract printBackground: bool option with get, set + /// Set the printer device name to use. Must be the system-defined name and not the + /// 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'. + abstract deviceName: string option with get, set + /// + /// Set whether the printed web page will be in color or grayscale. Default is + /// true. + /// + abstract color: bool option with get, set + abstract margins: Margins option with get, set + /// Whether the web page should be printed in landscape mode. Default is false. + abstract landscape: bool option with get, set + /// The scale factor of the web page. + abstract scaleFactor: float option with get, set + /// The number of pages to print per page sheet. + abstract pagesPerSheet: float option with get, set + /// Whether the web page should be collated. + abstract collate: bool option with get, set + /// The number of copies of the web page to print. + abstract copies: float option with get, set + /// The page range to print. On macOS, only one range is honored. + abstract pageRanges: ResizeArray option with get, set + /// + /// Set the duplex mode of the printed web page. Can be simplex, shortEdge, or + /// longEdge. + /// + abstract duplexMode: WebContentsPrintOptionsDuplexMode option with get, set + abstract dpi: Record option with get, set + /// String to be printed as page header. + abstract header: string option with get, set + /// String to be printed as page footer. + abstract footer: string option with get, set + /// + /// Specify page size of the printed document. Can be A3, A4, A5, Legal, + /// Letter, Tabloid or an Object containing height. + /// + abstract pageSize: U2 option with get, set + + type [] WebviewTagPrintOptions = + /// Don't ask user for print settings. Default is false. + abstract silent: bool option with get, set + /// Prints the background color and image of the web page. Default is false. + abstract printBackground: bool option with get, set + /// Set the printer device name to use. Must be the system-defined name and not the + /// 'friendly' name, e.g 'Brother_QL_820NWB' and not 'Brother QL-820NWB'. + abstract deviceName: string option with get, set + /// + /// Set whether the printed web page will be in color or grayscale. Default is + /// true. + /// + abstract color: bool option with get, set + abstract margins: Margins option with get, set + /// Whether the web page should be printed in landscape mode. Default is false. + abstract landscape: bool option with get, set + /// The scale factor of the web page. + abstract scaleFactor: float option with get, set + /// The number of pages to print per page sheet. + abstract pagesPerSheet: float option with get, set + /// Whether the web page should be collated. + abstract collate: bool option with get, set + /// The number of copies of the web page to print. + abstract copies: float option with get, set + /// The page range to print. + abstract pageRanges: ResizeArray option with get, set + /// + /// Set the duplex mode of the printed web page. Can be simplex, shortEdge, or + /// longEdge. + /// + abstract duplexMode: WebContentsPrintOptionsDuplexMode option with get, set + abstract dpi: Record option with get, set + /// String to be printed as page header. + abstract header: string option with get, set + /// String to be printed as page footer. + abstract footer: string option with get, set + /// + /// Specify page size of the printed document. Can be A3, A4, A5, Legal, + /// Letter, Tabloid or an Object containing height. + /// + abstract pageSize: U2 option with get, set + + type [] WillNavigateEvent = + inherit Event + abstract url: string with get, set + + type [] EditFlags = + /// Whether the renderer believes it can undo. + abstract canUndo: bool with get, set + /// Whether the renderer believes it can redo. + abstract canRedo: bool with get, set + /// Whether the renderer believes it can cut. + abstract canCut: bool with get, set + /// Whether the renderer believes it can copy. + abstract canCopy: bool with get, set + /// Whether the renderer believes it can paste. + abstract canPaste: bool with get, set + /// Whether the renderer believes it can delete. + abstract canDelete: bool with get, set + /// Whether the renderer believes it can select all. + abstract canSelectAll: bool with get, set + /// Whether the renderer believes it can edit text richly. + abstract canEditRichly: bool with get, set + + type [] FoundInPageResult = + abstract requestId: float with get, set + /// Position of the active match. + abstract activeMatchOrdinal: float with get, set + /// Number of Matches. + abstract matches: float with get, set + /// Coordinates of first match region. + abstract selectionArea: Rectangle with get, set + abstract finalUpdate: bool with get, set + + type [] LaunchItems = + /// name value of a registry entry. + abstract name: string with get, set + /// The executable to an app that corresponds to a registry entry. + abstract path: string with get, set + /// the command-line arguments to pass to the executable. + abstract args: ResizeArray with get, set + /// + /// one of user or machine. Indicates whether the registry entry is under + /// HKEY_CURRENT USER or HKEY_LOCAL_MACHINE. + /// + abstract scope: string with get, set + /// + /// true if the app registry key is startup approved and therefore shows as + /// enabled in Task Manager and Windows settings. + /// + abstract enabled: bool with get, set + + type [] Margins = + /// + /// Can be default, none, printableArea, or custom. If custom is chosen, + /// you will also need to specify top, bottom, left, and right. + /// + abstract marginType: MarginsMarginType option with get, set + /// The top margin of the printed web page, in pixels. + abstract top: float option with get, set + /// The bottom margin of the printed web page, in pixels. + abstract bottom: float option with get, set + /// The left margin of the printed web page, in pixels. + abstract left: float option with get, set + /// The right margin of the printed web page, in pixels. + abstract right: float option with get, set + + type [] MediaFlags = + /// Whether the media element has crashed. + abstract inError: bool with get, set + /// Whether the media element is paused. + abstract isPaused: bool with get, set + /// Whether the media element is muted. + abstract isMuted: bool with get, set + /// Whether the media element has audio. + abstract hasAudio: bool with get, set + /// Whether the media element is looping. + abstract isLooping: bool with get, set + /// Whether the media element's controls are visible. + abstract isControlsVisible: bool with get, set + /// Whether the media element's controls are toggleable. + abstract canToggleControls: bool with get, set + /// Whether the media element can be printed. + abstract canPrint: bool with get, set + /// Whether or not the media element can be downloaded. + abstract canSave: bool with get, set + /// Whether the media element can show picture-in-picture. + abstract canShowPictureInPicture: bool with get, set + /// Whether the media element is currently showing picture-in-picture. + abstract isShowingPictureInPicture: bool with get, set + /// Whether the media element can be rotated. + abstract canRotate: bool with get, set + /// Whether the media element can be looped. + abstract canLoop: bool with get, set + + type [] PageRanges = + /// Index of the first page to print (0-based). + abstract from: float with get, set + /// Index of the last page to print (inclusive) (0-based). + abstract ``to``: float with get, set + + type [] Params = + /// x coordinate. + abstract x: float with get, set + /// y coordinate. + abstract y: float with get, set + /// URL of the link that encloses the node the context menu was invoked on. + abstract linkURL: string with get, set + /// Text associated with the link. May be an empty string if the contents of the + /// link are an image. + abstract linkText: string with get, set + /// URL of the top level page that the context menu was invoked on. + abstract pageURL: string with get, set + /// URL of the subframe that the context menu was invoked on. + abstract frameURL: string with get, set + /// Source URL for the element that the context menu was invoked on. Elements with + /// source URLs are images, audio and video. + abstract srcURL: string with get, set + /// + /// Type of the node the context menu was invoked on. Can be none, image, + /// audio, video, canvas, file or plugin. + /// + abstract mediaType: ContextMenuParamsMediaType with get, set + /// Whether the context menu was invoked on an image which has non-empty contents. + abstract hasImageContents: bool with get, set + /// Whether the context is editable. + abstract isEditable: bool with get, set + /// Text of the selection that the context menu was invoked on. + abstract selectionText: string with get, set + /// Title text of the selection that the context menu was invoked on. + abstract titleText: string with get, set + /// Alt text of the selection that the context menu was invoked on. + abstract altText: string with get, set + /// Suggested filename to be used when saving file through 'Save Link As' option of + /// context menu. + abstract suggestedFilename: string with get, set + /// Rect representing the coordinates in the document space of the selection. + abstract selectionRect: Rectangle with get, set + /// Start position of the selection text. + abstract selectionStartOffset: float with get, set + /// The referrer policy of the frame on which the menu is invoked. + abstract referrerPolicy: Referrer with get, set + /// The misspelled word under the cursor, if any. + abstract misspelledWord: string with get, set + /// + /// An array of suggested words to show the user to replace the misspelledWord. + /// Only available if there is a misspelled word and spellchecker is enabled. + /// + abstract dictionarySuggestions: ResizeArray with get, set + /// The character encoding of the frame on which the menu was invoked. + abstract frameCharset: string with get, set + /// + /// If the context menu was invoked on an input field, the type of that field. + /// Possible values are none, plainText, password, other. + /// + abstract inputFieldType: string with get, set + /// If the context is editable, whether or not spellchecking is enabled. + abstract spellcheckEnabled: bool with get, set + /// + /// Input source that invoked the context menu. Can be none, mouse, keyboard, + /// touch, touchMenu, longPress, longTap, touchHandle, stylus, + /// adjustSelection, or adjustSelectionReset. + /// + abstract menuSourceType: ContextMenuParamsMenuSourceType with get, set + /// The flags for the media element the context menu was invoked on. + abstract mediaFlags: MediaFlags with get, set + /// These flags indicate whether the renderer believes it is able to perform the + /// corresponding action. + abstract editFlags: EditFlags with get, set + + type [] WebPreferences = + /// + /// Whether to enable DevTools. If it is set to false, can not use + /// BrowserWindow.webContents.openDevTools() to open DevTools. Default is true. + /// + abstract devTools: bool option with get, set + /// Whether node integration is enabled. Default is false. + abstract nodeIntegration: bool option with get, set + /// + /// Whether node integration is enabled in web workers. Default is false. More + /// about this can be found in Multithreading. + /// + abstract nodeIntegrationInWorker: bool option with get, set + /// + /// Experimental option for enabling Node.js support in sub-frames such as iframes + /// and child windows. All your preloads will load for every iframe, you can use + /// process.isMainFrame to determine if you are in the main frame or not. + /// + abstract nodeIntegrationInSubFrames: bool option with get, set + /// Specifies a script that will be loaded before other scripts run in the page. + /// This script will always have access to node APIs no matter whether node + /// integration is turned on or off. The value should be the absolute file path to + /// the script. When node integration is turned off, the preload script can + /// reintroduce Node global symbols back to the global scope. See example here. + abstract preload: string option with get, set + /// + /// If set, this will sandbox the renderer associated with the window, making it + /// compatible with the Chromium OS-level sandbox and disabling the Node.js engine. + /// This is not the same as the nodeIntegration option and the APIs available to + /// the preload script are more limited. Read more about the option here. + /// + abstract sandbox: bool option with get, set + /// + /// Sets the session used by the page. Instead of passing the Session object + /// directly, you can also choose to use the partition option instead, which + /// accepts a partition string. When both session and partition are provided, + /// session will be preferred. Default is the default session. + /// + abstract session: Session option with get, set + /// + /// Sets the session used by the page according to the session's partition string. + /// If partition starts with persist:, the page will use a persistent session + /// available to all pages in the app with the same partition. If there is no + /// persist: prefix, the page will use an in-memory session. By assigning the same + /// partition, multiple pages can share the same session. Default is the default + /// session. + /// + abstract partition: string option with get, set + /// The default zoom factor of the page, 3.0 represents 300%. Default is 1.0. + abstract zoomFactor: float option with get, set + /// Enables JavaScript support. Default is true. + abstract javascript: bool option with get, set + /// + /// When false, it will disable the same-origin policy (usually using testing + /// websites by people), and set allowRunningInsecureContent to true if this + /// options has not been set by user. Default is true. + /// + abstract webSecurity: bool option with get, set + /// + /// Allow an https page to run JavaScript, CSS or plugins from http URLs. Default is + /// false. + /// + abstract allowRunningInsecureContent: bool option with get, set + /// Enables image support. Default is true. + abstract images: bool option with get, set + /// Make TextArea elements resizable. Default is true. + abstract textAreasAreResizable: bool option with get, set + /// Enables WebGL support. Default is true. + abstract webgl: bool option with get, set + /// Whether plugins should be enabled. Default is false. + abstract plugins: bool option with get, set + /// Enables Chromium's experimental features. Default is false. + abstract experimentalFeatures: bool option with get, set + /// Enables scroll bounce (rubber banding) effect on macOS. Default is false. + abstract scrollBounce: bool option with get, set + /// + /// A list of feature strings separated by ,, like CSSVariables,KeyboardEventKey + /// to enable. The full list of supported feature strings can be found in the + /// RuntimeEnabledFeatures.json5 file. + /// + abstract enableBlinkFeatures: string option with get, set + /// + /// A list of feature strings separated by ,, like CSSVariables,KeyboardEventKey + /// to disable. The full list of supported feature strings can be found in the + /// RuntimeEnabledFeatures.json5 file. + /// + abstract disableBlinkFeatures: string option with get, set + /// Sets the default font for the font-family. + abstract defaultFontFamily: DefaultFontFamily option with get, set + /// Defaults to 16. + abstract defaultFontSize: float option with get, set + /// Defaults to 13. + abstract defaultMonospaceFontSize: float option with get, set + /// Defaults to 0. + abstract minimumFontSize: float option with get, set + /// Defaults to ISO-8859-1. + abstract defaultEncoding: string option with get, set + /// + /// Whether to throttle animations and timers when the page becomes background. This + /// also affects the Page Visibility API. Defaults to true. + /// + abstract backgroundThrottling: bool option with get, set + /// + /// Whether to enable offscreen rendering for the browser window. Defaults to + /// false. See the offscreen rendering tutorial for more details. + /// + abstract offscreen: bool option with get, set + /// + /// Whether to run Electron APIs and the specified preload script in a separate + /// JavaScript context. Defaults to true. The context that the preload script + /// runs in will only have access to its own dedicated document and window + /// globals, as well as its own set of JavaScript builtins (Array, Object, + /// JSON, etc.), which are all invisible to the loaded content. The Electron API + /// will only be available in the preload script and not the loaded page. This + /// option should be used when loading potentially untrusted remote content to + /// ensure the loaded content cannot tamper with the preload script and any + /// Electron APIs being used. This option uses the same technique used by Chrome + /// Content Scripts. You can access this context in the dev tools by selecting the + /// 'Electron Isolated Context' entry in the combo box at the top of the Console + /// tab. + /// + abstract contextIsolation: bool option with get, set + /// + /// Whether to use native window.open(). Defaults to false. Child windows will + /// always have node integration disabled unless nodeIntegrationInSubFrames is + /// true. **Note:** The default value will be changing to true in Electron 15. + /// + abstract nativeWindowOpen: bool option with get, set + /// + /// Whether to enable the <webview> tag. Defaults to false. **Note:** The + /// preload script configured for the <webview> will have node integration + /// enabled when it is executed so you should ensure remote/untrusted content is not + /// able to create a <webview> tag with a possibly malicious preload script. You + /// can use the will-attach-webview event on webContents to strip away the + /// preload script and to validate or alter the <webview>'s initial settings. + /// + abstract webviewTag: bool option with get, set + /// + /// A list of strings that will be appended to process.argv in the renderer + /// process of this app. Useful for passing small bits of data down to renderer + /// process preload scripts. + /// + abstract additionalArguments: ResizeArray option with get, set + /// + /// Whether to enable browser style consecutive dialog protection. Default is + /// false. + /// + abstract safeDialogs: bool option with get, set + /// The message to display when consecutive dialog protection is triggered. If not + /// defined the default message would be used, note that currently the default + /// message is in English and not localized. + abstract safeDialogsMessage: string option with get, set + /// + /// Whether to disable dialogs completely. Overrides safeDialogs. Default is + /// false. + /// + abstract disableDialogs: bool option with get, set + /// + /// Whether dragging and dropping a file or link onto the page causes a navigation. + /// Default is false. + /// + abstract navigateOnDragDrop: bool option with get, set + /// + /// Autoplay policy to apply to content in the window, can be + /// no-user-gesture-required, user-gesture-required, + /// document-user-activation-required. Defaults to no-user-gesture-required. + /// + abstract autoplayPolicy: WebPreferencesAutoplayPolicy option with get, set + /// + /// Whether to prevent the window from resizing when entering HTML Fullscreen. + /// Default is false. + /// + abstract disableHtmlFullscreenWindowResize: bool option with get, set + /// An alternative title string provided only to accessibility tools such as screen + /// readers. This string is not directly visible to users. + abstract accessibleTitle: string option with get, set + /// Whether to enable the builtin spellchecker. Default is true. + abstract spellcheck: bool option with get, set + /// Whether to enable the WebSQL api. Default is true. + abstract enableWebSQL: bool option with get, set + /// Enforces the v8 code caching policy used by blink. Accepted values are + abstract v8CacheOptions: WebPreferencesV8CacheOptions option with get, set + /// + /// Whether to enable preferred size mode. The preferred size is the minimum size + /// needed to contain the layout of the document—without requiring scrolling. + /// Enabling this will cause the preferred-size-changed event to be emitted on the + /// WebContents when the preferred size changes. Default is false. + /// + abstract enablePreferredSizeMode: bool option with get, set + + type [] DefaultFontFamily = + /// Defaults to Times New Roman. + abstract standard: string option with get, set + /// Defaults to Times New Roman. + abstract serif: string option with get, set + /// Defaults to Arial. + abstract sansSerif: string option with get, set + /// Defaults to Courier New. + abstract monospace: string option with get, set + /// Defaults to Script. + abstract cursive: string option with get, set + /// Defaults to Impact. + abstract fantasy: string option with get, set + + type [] RemoteMainInterface = + abstract app: App with get, set + abstract autoUpdater: AutoUpdater with get, set + abstract BrowserView: BrowserView with get, set + abstract BrowserWindow: BrowserWindow with get, set + abstract ClientRequest: obj with get, set + abstract clipboard: Clipboard with get, set + abstract CommandLine: obj with get, set + abstract contentTracing: ContentTracing with get, set + abstract Cookies: obj with get, set + abstract crashReporter: CrashReporter with get, set + abstract Debugger: obj with get, set + abstract desktopCapturer: DesktopCapturer with get, set + abstract dialog: Dialog with get, set + abstract Dock: obj with get, set + abstract DownloadItem: obj with get, set + abstract globalShortcut: GlobalShortcut with get, set + abstract inAppPurchase: InAppPurchase with get, set + abstract IncomingMessage: obj with get, set + abstract ipcMain: IpcMain with get, set + abstract Menu: MenuStatic with get, set + abstract MenuItem: MenuItemStatic with get, set + abstract MessageChannelMain: obj with get, set + abstract MessagePortMain: obj with get, set + abstract nativeImage: obj with get, set + abstract nativeTheme: NativeTheme with get, set + abstract net: Net with get, set + abstract netLog: NetLog with get, set + abstract Notification: obj with get, set + abstract powerMonitor: PowerMonitor with get, set + abstract powerSaveBlocker: PowerSaveBlocker with get, set + abstract protocol: Protocol with get, set + abstract screen: Screen with get, set + abstract ServiceWorkers: obj with get, set + abstract session: obj with get, set + abstract ShareMenu: obj with get, set + abstract shell: Shell with get, set + abstract systemPreferences: SystemPreferences with get, set + abstract TouchBar: obj with get, set + abstract TouchBarButton: obj with get, set + abstract TouchBarColorPicker: obj with get, set + abstract TouchBarGroup: obj with get, set + abstract TouchBarLabel: obj with get, set + abstract TouchBarOtherItemsProxy: obj with get, set + abstract TouchBarPopover: obj with get, set + abstract TouchBarScrubber: obj with get, set + abstract TouchBarSegmentedControl: obj with get, set + abstract TouchBarSlider: obj with get, set + abstract TouchBarSpacer: obj with get, set + abstract Tray: obj with get, set + abstract webContents: WebContentsStatic with get, set + abstract webFrameMain: obj with get, set + abstract WebRequest: obj with get, set + + module Common = + + type [] IExports = + abstract clipboard: Clipboard + abstract crashReporter: CrashReporter + abstract desktopCapturer: DesktopCapturer + abstract NativeImage: NativeImageStatic + abstract nativeImage: obj + abstract shell: Shell + + type [] NativeImage = + inherit Electron.NativeImage + + type [] NativeImageStatic = + [] abstract Create: unit -> NativeImage + + type nativeImage = + NativeImage + + type AboutPanelOptionsOptions = + Electron.AboutPanelOptionsOptions + + type AddRepresentationOptions = + Electron.AddRepresentationOptions + + type AnimationSettings = + Electron.AnimationSettings + + type AppDetailsOptions = + Electron.AppDetailsOptions + + type ApplicationInfoForProtocolReturnValue = + Electron.ApplicationInfoForProtocolReturnValue + + type AuthenticationResponseDetails = + Electron.AuthenticationResponseDetails + + type AuthInfo = + Electron.AuthInfo + + type AutoResizeOptions = + Electron.AutoResizeOptions + + type BeforeSendResponse = + Electron.BeforeSendResponse + + type BitmapOptions = + Electron.BitmapOptions + + type BlinkMemoryInfo = + Electron.BlinkMemoryInfo + + type BrowserViewConstructorOptions = + Electron.BrowserViewConstructorOptions + + type BrowserWindowConstructorOptions = + Electron.BrowserWindowConstructorOptions + + type CertificateTrustDialogOptions = + Electron.CertificateTrustDialogOptions + + type ClearStorageDataOptions = + Electron.ClearStorageDataOptions + + type ClientRequestConstructorOptions = + Electron.ClientRequestConstructorOptions + + type Config = + Electron.Config + + type ConsoleMessageEvent = + Electron.ConsoleMessageEvent + + type ContextMenuEvent = + Electron.ContextMenuEvent + + type ContextMenuParams = + Electron.ContextMenuParams + + type CookiesGetFilter = + Electron.CookiesGetFilter + + type CookiesSetDetails = + Electron.CookiesSetDetails + + type CrashReporterStartOptions = + Electron.CrashReporterStartOptions + + type CreateFromBitmapOptions = + Electron.CreateFromBitmapOptions + + type CreateFromBufferOptions = + Electron.CreateFromBufferOptions + + type CreateInterruptedDownloadOptions = + Electron.CreateInterruptedDownloadOptions + + type Data = + Electron.Data + + type Details = + Electron.Details + + type DevicePermissionHandlerHandlerDetails = + Electron.DevicePermissionHandlerHandlerDetails + + type DidChangeThemeColorEvent = + Electron.DidChangeThemeColorEvent + + type DidCreateWindowDetails = + Electron.DidCreateWindowDetails + + type DidFailLoadEvent = + Electron.DidFailLoadEvent + + type DidFrameFinishLoadEvent = + Electron.DidFrameFinishLoadEvent + + type DidFrameNavigateEvent = + Electron.DidFrameNavigateEvent + + type DidNavigateEvent = + Electron.DidNavigateEvent + + type DidNavigateInPageEvent = + Electron.DidNavigateInPageEvent + + type DidStartNavigationEvent = + Electron.DidStartNavigationEvent + + type DisplayBalloonOptions = + Electron.DisplayBalloonOptions + + type EnableNetworkEmulationOptions = + Electron.EnableNetworkEmulationOptions + + type FeedURLOptions = + Electron.FeedURLOptions + + type FileIconOptions = + Electron.FileIconOptions + + type Filter = + Electron.Filter + + type FindInPageOptions = + Electron.FindInPageOptions + + type FocusOptions = + Electron.FocusOptions + + type FoundInPageEvent = + Electron.FoundInPageEvent + + type FromPartitionOptions = + Electron.FromPartitionOptions + + type HandlerDetails = + Electron.HandlerDetails + + type HeadersReceivedResponse = + Electron.HeadersReceivedResponse + + type HeapStatistics = + Electron.HeapStatistics + + type HidDeviceAddedDetails = + Electron.HidDeviceAddedDetails + + type HidDeviceRemovedDetails = + Electron.HidDeviceRemovedDetails + + type IgnoreMouseEventsOptions = + Electron.IgnoreMouseEventsOptions + + type ImportCertificateOptions = + Electron.ImportCertificateOptions + + type Info = + Electron.Info + + type Input = + Electron.Input + + type InsertCSSOptions = + Electron.InsertCSSOptions + + type IpcMessageEvent = + Electron.IpcMessageEvent + + type Item = + Electron.Item + + type JumpListSettings = + Electron.JumpListSettings + + type LoadCommitEvent = + Electron.LoadCommitEvent + + type LoadExtensionOptions = + Electron.LoadExtensionOptions + + type LoadFileOptions = + Electron.LoadFileOptions + + type LoadURLOptions = + Electron.LoadURLOptions + + type LoginItemSettings = + Electron.LoginItemSettings + + type LoginItemSettingsOptions = + Electron.LoginItemSettingsOptions + + type MenuItemConstructorOptions = + Electron.MenuItemConstructorOptions + + type MessageBoxOptions = + Electron.MessageBoxOptions + + type MessageBoxReturnValue = + Electron.MessageBoxReturnValue + + type MessageBoxSyncOptions = + Electron.MessageBoxSyncOptions + + type MessageDetails = + Electron.MessageDetails + + type MessageEvent = + Electron.MessageEvent + + type MoveToApplicationsFolderOptions = + Electron.MoveToApplicationsFolderOptions + + type NewWindowEvent = + Electron.NewWindowEvent + + type NotificationConstructorOptions = + Electron.NotificationConstructorOptions + + type OnBeforeRedirectListenerDetails = + Electron.OnBeforeRedirectListenerDetails + + type OnBeforeRequestListenerDetails = + Electron.OnBeforeRequestListenerDetails + + type OnBeforeSendHeadersListenerDetails = + Electron.OnBeforeSendHeadersListenerDetails + + type OnCompletedListenerDetails = + Electron.OnCompletedListenerDetails + + type OnErrorOccurredListenerDetails = + Electron.OnErrorOccurredListenerDetails + + type OnHeadersReceivedListenerDetails = + Electron.OnHeadersReceivedListenerDetails + + type OnResponseStartedListenerDetails = + Electron.OnResponseStartedListenerDetails + + type OnSendHeadersListenerDetails = + Electron.OnSendHeadersListenerDetails + + type OpenDevToolsOptions = + Electron.OpenDevToolsOptions + + type OpenDialogOptions = + Electron.OpenDialogOptions + + type OpenDialogReturnValue = + Electron.OpenDialogReturnValue + + type OpenDialogSyncOptions = + Electron.OpenDialogSyncOptions + + type OpenExternalOptions = + Electron.OpenExternalOptions + + type Options = + Electron.Options + + type PageFaviconUpdatedEvent = + Electron.PageFaviconUpdatedEvent + + type PageTitleUpdatedEvent = + Electron.PageTitleUpdatedEvent + + type Parameters = + Electron.Parameters + + type Payment = + Electron.Payment + + type PermissionCheckHandlerHandlerDetails = + Electron.PermissionCheckHandlerHandlerDetails + + type PermissionRequestHandlerHandlerDetails = + Electron.PermissionRequestHandlerHandlerDetails + + type PluginCrashedEvent = + Electron.PluginCrashedEvent + + type PopupOptions = + Electron.PopupOptions + + type PreconnectOptions = + Electron.PreconnectOptions + + type PrintToPDFOptions = + Electron.PrintToPDFOptions + + type Privileges = + Electron.Privileges + + type ProgressBarOptions = + Electron.ProgressBarOptions + + type Provider = + Electron.Provider + + type ReadBookmark = + Electron.ReadBookmark + + type RegistrationCompletedDetails = + Electron.RegistrationCompletedDetails + + type RelaunchOptions = + Electron.RelaunchOptions + + type RenderProcessGoneDetails = + Electron.RenderProcessGoneDetails + + type Request = + Electron.Request + + type ResizeOptions = + Electron.ResizeOptions + + type ResourceUsage = + Electron.ResourceUsage + + type Response = + Electron.Response + + type Result = + Electron.Result + + type SaveDialogOptions = + Electron.SaveDialogOptions + + type SaveDialogReturnValue = + Electron.SaveDialogReturnValue + + type SaveDialogSyncOptions = + Electron.SaveDialogSyncOptions + + type SelectHidDeviceDetails = + Electron.SelectHidDeviceDetails + + type Settings = + Electron.Settings + + type SourcesOptions = + Electron.SourcesOptions + + type SSLConfigConfig = + Electron.SSLConfigConfig + + type StartLoggingOptions = + Electron.StartLoggingOptions + + type SystemMemoryInfo = + Electron.SystemMemoryInfo + + type TitleOptions = + Electron.TitleOptions + + type ToBitmapOptions = + Electron.ToBitmapOptions + + type ToDataURLOptions = + Electron.ToDataURLOptions + + type ToPNGOptions = + Electron.ToPNGOptions + + type TouchBarButtonConstructorOptions = + Electron.TouchBarButtonConstructorOptions + + type TouchBarColorPickerConstructorOptions = + Electron.TouchBarColorPickerConstructorOptions + + type TouchBarConstructorOptions = + Electron.TouchBarConstructorOptions + + type TouchBarGroupConstructorOptions = + Electron.TouchBarGroupConstructorOptions + + type TouchBarLabelConstructorOptions = + Electron.TouchBarLabelConstructorOptions + + type TouchBarPopoverConstructorOptions = + Electron.TouchBarPopoverConstructorOptions + + type TouchBarScrubberConstructorOptions = + Electron.TouchBarScrubberConstructorOptions + + type TouchBarSegmentedControlConstructorOptions = + Electron.TouchBarSegmentedControlConstructorOptions + + type TouchBarSliderConstructorOptions = + Electron.TouchBarSliderConstructorOptions + + type TouchBarSpacerConstructorOptions = + Electron.TouchBarSpacerConstructorOptions + + type TraceBufferUsageReturnValue = + Electron.TraceBufferUsageReturnValue + + type UpdateTargetUrlEvent = + Electron.UpdateTargetUrlEvent + + type UploadProgress = + Electron.UploadProgress + + type VisibleOnAllWorkspacesOptions = + Electron.VisibleOnAllWorkspacesOptions + + type WebContentsPrintOptions = + Electron.WebContentsPrintOptions + + type WebviewTagPrintOptions = + Electron.WebviewTagPrintOptions + + type WillNavigateEvent = + Electron.WillNavigateEvent + + type EditFlags = + Electron.EditFlags + + type FoundInPageResult = + Electron.FoundInPageResult + + type LaunchItems = + Electron.LaunchItems + + type Margins = + Electron.Margins + + type MediaFlags = + Electron.MediaFlags + + type PageRanges = + Electron.PageRanges + + type Params = + Electron.Params + + type WebPreferences = + Electron.WebPreferences + + type DefaultFontFamily = + Electron.DefaultFontFamily + + type BluetoothDevice = + Electron.BluetoothDevice + + type Certificate = + Electron.Certificate + + type CertificatePrincipal = + Electron.CertificatePrincipal + + type Cookie = + Electron.Cookie + + type CPUUsage = + Electron.CPUUsage + + type CrashReport = + Electron.CrashReport + + type CustomScheme = + Electron.CustomScheme + + type DesktopCapturerSource = + Electron.DesktopCapturerSource + + type Display = + Electron.Display + + type Event = + Electron.Event + + type Extension = + Electron.Extension + + type ExtensionInfo = + Electron.ExtensionInfo + + type FileFilter = + Electron.FileFilter + + type FilePathWithHeaders = + Electron.FilePathWithHeaders + + type GPUFeatureStatus = + Electron.GPUFeatureStatus + + type HIDDevice = + Electron.HIDDevice + + type InputEvent = + Electron.InputEvent + + type IOCounters = + Electron.IOCounters + + type IpcMainEvent = + Electron.IpcMainEvent + + type IpcMainInvokeEvent = + Electron.IpcMainInvokeEvent + + type IpcRendererEvent = + Electron.IpcRendererEvent + + type JumpListCategory = + Electron.JumpListCategory + + type JumpListItem = + Electron.JumpListItem + + type KeyboardEvent = + Electron.KeyboardEvent + + type KeyboardInputEvent = + Electron.KeyboardInputEvent + + type MemoryInfo = + Electron.MemoryInfo + + type MemoryUsageDetails = + Electron.MemoryUsageDetails + + type MimeTypedBuffer = + Electron.MimeTypedBuffer + + type MouseInputEvent = + Electron.MouseInputEvent + + type MouseWheelInputEvent = + Electron.MouseWheelInputEvent + + type NewWindowWebContentsEvent = + Electron.NewWindowWebContentsEvent + + type NotificationAction = + Electron.NotificationAction + + type NotificationResponse = + Electron.NotificationResponse + + type OverlayOptions = + Electron.OverlayOptions + + type Point = + Electron.Point + + type PostBody = + Electron.PostBody + + type PrinterInfo = + Electron.PrinterInfo + + type ProcessMemoryInfo = + Electron.ProcessMemoryInfo + + type ProcessMetric = + Electron.ProcessMetric + + type Product = + Electron.Product + + type ProtocolRequest = + Electron.ProtocolRequest + + type ProtocolResponse = + Electron.ProtocolResponse + + type ProtocolResponseUploadData = + Electron.ProtocolResponseUploadData + + type Rectangle = + Electron.Rectangle + + type Referrer = + Electron.Referrer + + type ScrubberItem = + Electron.ScrubberItem + + type SegmentedControlSegment = + Electron.SegmentedControlSegment + + type SerialPort = + Electron.SerialPort + + type ServiceWorkerInfo = + Electron.ServiceWorkerInfo + + type SharedWorkerInfo = + Electron.SharedWorkerInfo + + type SharingItem = + Electron.SharingItem + + type ShortcutDetails = + Electron.ShortcutDetails + + type Size = + Electron.Size + + type Task = + Electron.Task + + type ThumbarButton = + Electron.ThumbarButton + + type TraceCategoriesAndOptions = + Electron.TraceCategoriesAndOptions + + type TraceConfig = + Electron.TraceConfig + + type Transaction = + Electron.Transaction + + type UploadData = + Electron.UploadData + + type UploadFile = + Electron.UploadFile + + type UploadRawData = + Electron.UploadRawData + + type UserDefaultTypes = + Electron.UserDefaultTypes + + type WebSource = + Electron.WebSource + + module Main = + + type [] IExports = + abstract app: App + abstract autoUpdater: AutoUpdater + abstract BrowserView: BrowserViewStatic + abstract BrowserWindow: BrowserWindowStatic + abstract ClientRequest: ClientRequestStatic + abstract CommandLine: CommandLineStatic + abstract contentTracing: ContentTracing + abstract Cookies: CookiesStatic + abstract Debugger: DebuggerStatic + abstract dialog: Dialog + abstract Dock: DockStatic + abstract DownloadItem: DownloadItemStatic + abstract globalShortcut: GlobalShortcut + abstract inAppPurchase: InAppPurchase + abstract IncomingMessage: IncomingMessageStatic + abstract ipcMain: IpcMain + abstract Menu: MenuStatic + abstract MenuItem: MenuItemStatic + abstract MessageChannelMain: MessageChannelMainStatic + abstract MessagePortMain: MessagePortMainStatic + abstract nativeTheme: NativeTheme + abstract net: Net + abstract netLog: NetLog + abstract Notification: NotificationStatic + abstract powerMonitor: PowerMonitor + abstract powerSaveBlocker: PowerSaveBlocker + abstract protocol: Protocol + abstract screen: Screen + abstract ServiceWorkers: ServiceWorkersStatic + abstract Session: SessionStatic + abstract session: obj + abstract ShareMenu: ShareMenuStatic + abstract systemPreferences: SystemPreferences + abstract TouchBar: TouchBarStatic + abstract TouchBarButton: TouchBarButtonStatic + abstract TouchBarColorPicker: TouchBarColorPickerStatic + abstract TouchBarGroup: TouchBarGroupStatic + abstract TouchBarLabel: TouchBarLabelStatic + abstract TouchBarOtherItemsProxy: TouchBarOtherItemsProxyStatic + abstract TouchBarPopover: TouchBarPopoverStatic + abstract TouchBarScrubber: TouchBarScrubberStatic + abstract TouchBarSegmentedControl: TouchBarSegmentedControlStatic + abstract TouchBarSlider: TouchBarSliderStatic + abstract TouchBarSpacer: TouchBarSpacerStatic + abstract Tray: TrayStatic + abstract WebContents: WebContentsStatic + abstract webContents: obj + abstract WebFrameMain: WebFrameMainStatic + abstract webFrameMain: obj + abstract WebRequest: WebRequestStatic + + type [] BrowserView = + inherit Electron.BrowserView + + type [] BrowserViewStatic = + [] abstract Create: unit -> BrowserView + + type [] BrowserWindow = + inherit Electron.BrowserWindow + + type [] BrowserWindowStatic = + [] abstract Create: unit -> BrowserWindow + + type [] ClientRequest = + inherit Electron.ClientRequest + + type [] ClientRequestStatic = + [] abstract Create: unit -> ClientRequest + + type [] CommandLine = + inherit Electron.CommandLine + + type [] CommandLineStatic = + [] abstract Create: unit -> CommandLine + + type [] Cookies = + inherit Electron.Cookies + + type [] CookiesStatic = + [] abstract Create: unit -> Cookies + + type [] Debugger = + inherit Electron.Debugger + + type [] DebuggerStatic = + [] abstract Create: unit -> Debugger + + type [] Dock = + inherit Electron.Dock + + type [] DockStatic = + [] abstract Create: unit -> Dock + + type [] DownloadItem = + inherit Electron.DownloadItem + + type [] DownloadItemStatic = + [] abstract Create: unit -> DownloadItem + + type [] IncomingMessage = + inherit Electron.IncomingMessage + + type [] IncomingMessageStatic = + [] abstract Create: unit -> IncomingMessage + + type [] Menu = + inherit Electron.Menu + + type [] MenuStatic = + [] abstract Create: unit -> Menu + + type [] MenuItem = + inherit Electron.MenuItem + + type [] MenuItemStatic = + [] abstract Create: unit -> MenuItem + + type [] MessageChannelMain = + inherit Electron.MessageChannelMain + + type [] MessageChannelMainStatic = + [] abstract Create: unit -> MessageChannelMain + + type [] MessagePortMain = + inherit Electron.MessagePortMain + + type [] MessagePortMainStatic = + [] abstract Create: unit -> MessagePortMain + + type [] Notification = + inherit Electron.Notification + + type [] NotificationStatic = + [] abstract Create: unit -> Notification + + type [] ServiceWorkers = + inherit Electron.ServiceWorkers + + type [] ServiceWorkersStatic = + [] abstract Create: unit -> ServiceWorkers + + type [] Session = + inherit Electron.Session + + type [] SessionStatic = + [] abstract Create: unit -> Session + + type session = + Session + + type [] ShareMenu = + inherit Electron.ShareMenu + + type [] ShareMenuStatic = + [] abstract Create: unit -> ShareMenu + + type [] TouchBar = + inherit Electron.TouchBar + + type [] TouchBarStatic = + [] abstract Create: unit -> TouchBar + + type [] TouchBarButton = + inherit Electron.TouchBarButton + + type [] TouchBarButtonStatic = + [] abstract Create: unit -> TouchBarButton + + type [] TouchBarColorPicker = + inherit Electron.TouchBarColorPicker + + type [] TouchBarColorPickerStatic = + [] abstract Create: unit -> TouchBarColorPicker + + type [] TouchBarGroup = + inherit Electron.TouchBarGroup + + type [] TouchBarGroupStatic = + [] abstract Create: unit -> TouchBarGroup + + type [] TouchBarLabel = + inherit Electron.TouchBarLabel + + type [] TouchBarLabelStatic = + [] abstract Create: unit -> TouchBarLabel + + type [] TouchBarOtherItemsProxy = + inherit Electron.TouchBarOtherItemsProxy + + type [] TouchBarOtherItemsProxyStatic = + [] abstract Create: unit -> TouchBarOtherItemsProxy + + type [] TouchBarPopover = + inherit Electron.TouchBarPopover + + type [] TouchBarPopoverStatic = + [] abstract Create: unit -> TouchBarPopover + + type [] TouchBarScrubber = + inherit Electron.TouchBarScrubber + + type [] TouchBarScrubberStatic = + [] abstract Create: unit -> TouchBarScrubber + + type [] TouchBarSegmentedControl = + inherit Electron.TouchBarSegmentedControl + + type [] TouchBarSegmentedControlStatic = + [] abstract Create: unit -> TouchBarSegmentedControl + + type [] TouchBarSlider = + inherit Electron.TouchBarSlider + + type [] TouchBarSliderStatic = + [] abstract Create: unit -> TouchBarSlider + + type [] TouchBarSpacer = + inherit Electron.TouchBarSpacer + + type [] TouchBarSpacerStatic = + [] abstract Create: unit -> TouchBarSpacer + + type [] Tray = + inherit Electron.Tray + + type [] TrayStatic = + [] abstract Create: unit -> Tray + + type [] WebContents = + inherit Electron.WebContents + + type [] WebContentsStatic = + [] abstract Create: unit -> WebContents + + type webContents = + WebContents + + type [] WebFrameMain = + inherit Electron.WebFrameMain + + type [] WebFrameMainStatic = + [] abstract Create: unit -> WebFrameMain + + type webFrameMain = + WebFrameMain + + type [] WebRequest = + inherit Electron.WebRequest + + type [] WebRequestStatic = + [] abstract Create: unit -> WebRequest + + type AboutPanelOptionsOptions = + Electron.AboutPanelOptionsOptions + + type AddRepresentationOptions = + Electron.AddRepresentationOptions + + type AnimationSettings = + Electron.AnimationSettings + + type AppDetailsOptions = + Electron.AppDetailsOptions + + type ApplicationInfoForProtocolReturnValue = + Electron.ApplicationInfoForProtocolReturnValue + + type AuthenticationResponseDetails = + Electron.AuthenticationResponseDetails + + type AuthInfo = + Electron.AuthInfo + + type AutoResizeOptions = + Electron.AutoResizeOptions + + type BeforeSendResponse = + Electron.BeforeSendResponse + + type BitmapOptions = + Electron.BitmapOptions + + type BlinkMemoryInfo = + Electron.BlinkMemoryInfo + + type BrowserViewConstructorOptions = + Electron.BrowserViewConstructorOptions + + type BrowserWindowConstructorOptions = + Electron.BrowserWindowConstructorOptions + + type CertificateTrustDialogOptions = + Electron.CertificateTrustDialogOptions + + type ClearStorageDataOptions = + Electron.ClearStorageDataOptions + + type ClientRequestConstructorOptions = + Electron.ClientRequestConstructorOptions + + type Config = + Electron.Config + + type ConsoleMessageEvent = + Electron.ConsoleMessageEvent + + type ContextMenuEvent = + Electron.ContextMenuEvent + + type ContextMenuParams = + Electron.ContextMenuParams + + type CookiesGetFilter = + Electron.CookiesGetFilter + + type CookiesSetDetails = + Electron.CookiesSetDetails + + type CrashReporterStartOptions = + Electron.CrashReporterStartOptions + + type CreateFromBitmapOptions = + Electron.CreateFromBitmapOptions + + type CreateFromBufferOptions = + Electron.CreateFromBufferOptions + + type CreateInterruptedDownloadOptions = + Electron.CreateInterruptedDownloadOptions + + type Data = + Electron.Data + + type Details = + Electron.Details + + type DevicePermissionHandlerHandlerDetails = + Electron.DevicePermissionHandlerHandlerDetails + + type DidChangeThemeColorEvent = + Electron.DidChangeThemeColorEvent + + type DidCreateWindowDetails = + Electron.DidCreateWindowDetails + + type DidFailLoadEvent = + Electron.DidFailLoadEvent + + type DidFrameFinishLoadEvent = + Electron.DidFrameFinishLoadEvent + + type DidFrameNavigateEvent = + Electron.DidFrameNavigateEvent + + type DidNavigateEvent = + Electron.DidNavigateEvent + + type DidNavigateInPageEvent = + Electron.DidNavigateInPageEvent + + type DidStartNavigationEvent = + Electron.DidStartNavigationEvent + + type DisplayBalloonOptions = + Electron.DisplayBalloonOptions + + type EnableNetworkEmulationOptions = + Electron.EnableNetworkEmulationOptions + + type FeedURLOptions = + Electron.FeedURLOptions + + type FileIconOptions = + Electron.FileIconOptions + + type Filter = + Electron.Filter + + type FindInPageOptions = + Electron.FindInPageOptions + + type FocusOptions = + Electron.FocusOptions + + type FoundInPageEvent = + Electron.FoundInPageEvent + + type FromPartitionOptions = + Electron.FromPartitionOptions + + type HandlerDetails = + Electron.HandlerDetails + + type HeadersReceivedResponse = + Electron.HeadersReceivedResponse + + type HeapStatistics = + Electron.HeapStatistics + + type HidDeviceAddedDetails = + Electron.HidDeviceAddedDetails + + type HidDeviceRemovedDetails = + Electron.HidDeviceRemovedDetails + + type IgnoreMouseEventsOptions = + Electron.IgnoreMouseEventsOptions + + type ImportCertificateOptions = + Electron.ImportCertificateOptions + + type Info = + Electron.Info + + type Input = + Electron.Input + + type InsertCSSOptions = + Electron.InsertCSSOptions + + type IpcMessageEvent = + Electron.IpcMessageEvent + + type Item = + Electron.Item + + type JumpListSettings = + Electron.JumpListSettings + + type LoadCommitEvent = + Electron.LoadCommitEvent + + type LoadExtensionOptions = + Electron.LoadExtensionOptions + + type LoadFileOptions = + Electron.LoadFileOptions + + type LoadURLOptions = + Electron.LoadURLOptions + + type LoginItemSettings = + Electron.LoginItemSettings + + type LoginItemSettingsOptions = + Electron.LoginItemSettingsOptions + + type MenuItemConstructorOptions = + Electron.MenuItemConstructorOptions + + type MessageBoxOptions = + Electron.MessageBoxOptions + + type MessageBoxReturnValue = + Electron.MessageBoxReturnValue + + type MessageBoxSyncOptions = + Electron.MessageBoxSyncOptions + + type MessageDetails = + Electron.MessageDetails + + type MessageEvent = + Electron.MessageEvent + + type MoveToApplicationsFolderOptions = + Electron.MoveToApplicationsFolderOptions + + type NewWindowEvent = + Electron.NewWindowEvent + + type NotificationConstructorOptions = + Electron.NotificationConstructorOptions + + type OnBeforeRedirectListenerDetails = + Electron.OnBeforeRedirectListenerDetails + + type OnBeforeRequestListenerDetails = + Electron.OnBeforeRequestListenerDetails + + type OnBeforeSendHeadersListenerDetails = + Electron.OnBeforeSendHeadersListenerDetails + + type OnCompletedListenerDetails = + Electron.OnCompletedListenerDetails + + type OnErrorOccurredListenerDetails = + Electron.OnErrorOccurredListenerDetails + + type OnHeadersReceivedListenerDetails = + Electron.OnHeadersReceivedListenerDetails + + type OnResponseStartedListenerDetails = + Electron.OnResponseStartedListenerDetails + + type OnSendHeadersListenerDetails = + Electron.OnSendHeadersListenerDetails + + type OpenDevToolsOptions = + Electron.OpenDevToolsOptions + + type OpenDialogOptions = + Electron.OpenDialogOptions + + type OpenDialogReturnValue = + Electron.OpenDialogReturnValue + + type OpenDialogSyncOptions = + Electron.OpenDialogSyncOptions + + type OpenExternalOptions = + Electron.OpenExternalOptions + + type Options = + Electron.Options + + type PageFaviconUpdatedEvent = + Electron.PageFaviconUpdatedEvent + + type PageTitleUpdatedEvent = + Electron.PageTitleUpdatedEvent + + type Parameters = + Electron.Parameters + + type Payment = + Electron.Payment + + type PermissionCheckHandlerHandlerDetails = + Electron.PermissionCheckHandlerHandlerDetails + + type PermissionRequestHandlerHandlerDetails = + Electron.PermissionRequestHandlerHandlerDetails + + type PluginCrashedEvent = + Electron.PluginCrashedEvent + + type PopupOptions = + Electron.PopupOptions + + type PreconnectOptions = + Electron.PreconnectOptions + + type PrintToPDFOptions = + Electron.PrintToPDFOptions + + type Privileges = + Electron.Privileges + + type ProgressBarOptions = + Electron.ProgressBarOptions + + type Provider = + Electron.Provider + + type ReadBookmark = + Electron.ReadBookmark + + type RegistrationCompletedDetails = + Electron.RegistrationCompletedDetails + + type RelaunchOptions = + Electron.RelaunchOptions + + type RenderProcessGoneDetails = + Electron.RenderProcessGoneDetails + + type Request = + Electron.Request + + type ResizeOptions = + Electron.ResizeOptions + + type ResourceUsage = + Electron.ResourceUsage + + type Response = + Electron.Response + + type Result = + Electron.Result + + type SaveDialogOptions = + Electron.SaveDialogOptions + + type SaveDialogReturnValue = + Electron.SaveDialogReturnValue + + type SaveDialogSyncOptions = + Electron.SaveDialogSyncOptions + + type SelectHidDeviceDetails = + Electron.SelectHidDeviceDetails + + type Settings = + Electron.Settings + + type SourcesOptions = + Electron.SourcesOptions + + type SSLConfigConfig = + Electron.SSLConfigConfig + + type StartLoggingOptions = + Electron.StartLoggingOptions + + type SystemMemoryInfo = + Electron.SystemMemoryInfo + + type TitleOptions = + Electron.TitleOptions + + type ToBitmapOptions = + Electron.ToBitmapOptions + + type ToDataURLOptions = + Electron.ToDataURLOptions + + type ToPNGOptions = + Electron.ToPNGOptions + + type TouchBarButtonConstructorOptions = + Electron.TouchBarButtonConstructorOptions + + type TouchBarColorPickerConstructorOptions = + Electron.TouchBarColorPickerConstructorOptions + + type TouchBarConstructorOptions = + Electron.TouchBarConstructorOptions + + type TouchBarGroupConstructorOptions = + Electron.TouchBarGroupConstructorOptions + + type TouchBarLabelConstructorOptions = + Electron.TouchBarLabelConstructorOptions + + type TouchBarPopoverConstructorOptions = + Electron.TouchBarPopoverConstructorOptions + + type TouchBarScrubberConstructorOptions = + Electron.TouchBarScrubberConstructorOptions + + type TouchBarSegmentedControlConstructorOptions = + Electron.TouchBarSegmentedControlConstructorOptions + + type TouchBarSliderConstructorOptions = + Electron.TouchBarSliderConstructorOptions + + type TouchBarSpacerConstructorOptions = + Electron.TouchBarSpacerConstructorOptions + + type TraceBufferUsageReturnValue = + Electron.TraceBufferUsageReturnValue + + type UpdateTargetUrlEvent = + Electron.UpdateTargetUrlEvent + + type UploadProgress = + Electron.UploadProgress + + type VisibleOnAllWorkspacesOptions = + Electron.VisibleOnAllWorkspacesOptions + + type WebContentsPrintOptions = + Electron.WebContentsPrintOptions + + type WebviewTagPrintOptions = + Electron.WebviewTagPrintOptions + + type WillNavigateEvent = + Electron.WillNavigateEvent + + type EditFlags = + Electron.EditFlags + + type FoundInPageResult = + Electron.FoundInPageResult + + type LaunchItems = + Electron.LaunchItems + + type Margins = + Electron.Margins + + type MediaFlags = + Electron.MediaFlags + + type PageRanges = + Electron.PageRanges + + type Params = + Electron.Params + + type WebPreferences = + Electron.WebPreferences + + type DefaultFontFamily = + Electron.DefaultFontFamily + + type BluetoothDevice = + Electron.BluetoothDevice + + type Certificate = + Electron.Certificate + + type CertificatePrincipal = + Electron.CertificatePrincipal + + type Cookie = + Electron.Cookie + + type CPUUsage = + Electron.CPUUsage + + type CrashReport = + Electron.CrashReport + + type CustomScheme = + Electron.CustomScheme + + type DesktopCapturerSource = + Electron.DesktopCapturerSource + + type Display = + Electron.Display + + type Event = + Electron.Event + + type Extension = + Electron.Extension + + type ExtensionInfo = + Electron.ExtensionInfo + + type FileFilter = + Electron.FileFilter + + type FilePathWithHeaders = + Electron.FilePathWithHeaders + + type GPUFeatureStatus = + Electron.GPUFeatureStatus + + type HIDDevice = + Electron.HIDDevice + + type InputEvent = + Electron.InputEvent + + type IOCounters = + Electron.IOCounters + + type IpcMainEvent = + Electron.IpcMainEvent + + type IpcMainInvokeEvent = + Electron.IpcMainInvokeEvent + + type IpcRendererEvent = + Electron.IpcRendererEvent + + type JumpListCategory = + Electron.JumpListCategory + + type JumpListItem = + Electron.JumpListItem + + type KeyboardEvent = + Electron.KeyboardEvent + + type KeyboardInputEvent = + Electron.KeyboardInputEvent + + type MemoryInfo = + Electron.MemoryInfo + + type MemoryUsageDetails = + Electron.MemoryUsageDetails + + type MimeTypedBuffer = + Electron.MimeTypedBuffer + + type MouseInputEvent = + Electron.MouseInputEvent + + type MouseWheelInputEvent = + Electron.MouseWheelInputEvent + + type NewWindowWebContentsEvent = + Electron.NewWindowWebContentsEvent + + type NotificationAction = + Electron.NotificationAction + + type NotificationResponse = + Electron.NotificationResponse + + type OverlayOptions = + Electron.OverlayOptions + + type Point = + Electron.Point + + type PostBody = + Electron.PostBody + + type PrinterInfo = + Electron.PrinterInfo + + type ProcessMemoryInfo = + Electron.ProcessMemoryInfo + + type ProcessMetric = + Electron.ProcessMetric + + type Product = + Electron.Product + + type ProtocolRequest = + Electron.ProtocolRequest + + type ProtocolResponse = + Electron.ProtocolResponse + + type ProtocolResponseUploadData = + Electron.ProtocolResponseUploadData + + type Rectangle = + Electron.Rectangle + + type Referrer = + Electron.Referrer + + type ScrubberItem = + Electron.ScrubberItem + + type SegmentedControlSegment = + Electron.SegmentedControlSegment + + type SerialPort = + Electron.SerialPort + + type ServiceWorkerInfo = + Electron.ServiceWorkerInfo + + type SharedWorkerInfo = + Electron.SharedWorkerInfo + + type SharingItem = + Electron.SharingItem + + type ShortcutDetails = + Electron.ShortcutDetails + + type Size = + Electron.Size + + type Task = + Electron.Task + + type ThumbarButton = + Electron.ThumbarButton + + type TraceCategoriesAndOptions = + Electron.TraceCategoriesAndOptions + + type TraceConfig = + Electron.TraceConfig + + type Transaction = + Electron.Transaction + + type UploadData = + Electron.UploadData + + type UploadFile = + Electron.UploadFile + + type UploadRawData = + Electron.UploadRawData + + type UserDefaultTypes = + Electron.UserDefaultTypes + + type WebSource = + Electron.WebSource + + module Renderer = + + type [] IExports = + abstract BrowserWindowProxy: BrowserWindowProxyStatic + abstract contextBridge: ContextBridge + abstract ipcRenderer: IpcRenderer + abstract webFrame: WebFrame + abstract webviewTag: WebviewTag + + type [] BrowserWindowProxy = + inherit Electron.BrowserWindowProxy + + type [] BrowserWindowProxyStatic = + [] abstract Create: unit -> BrowserWindowProxy + + type AboutPanelOptionsOptions = + Electron.AboutPanelOptionsOptions + + type AddRepresentationOptions = + Electron.AddRepresentationOptions + + type AnimationSettings = + Electron.AnimationSettings + + type AppDetailsOptions = + Electron.AppDetailsOptions + + type ApplicationInfoForProtocolReturnValue = + Electron.ApplicationInfoForProtocolReturnValue + + type AuthenticationResponseDetails = + Electron.AuthenticationResponseDetails + + type AuthInfo = + Electron.AuthInfo + + type AutoResizeOptions = + Electron.AutoResizeOptions + + type BeforeSendResponse = + Electron.BeforeSendResponse + + type BitmapOptions = + Electron.BitmapOptions + + type BlinkMemoryInfo = + Electron.BlinkMemoryInfo + + type BrowserViewConstructorOptions = + Electron.BrowserViewConstructorOptions + + type BrowserWindowConstructorOptions = + Electron.BrowserWindowConstructorOptions + + type CertificateTrustDialogOptions = + Electron.CertificateTrustDialogOptions + + type ClearStorageDataOptions = + Electron.ClearStorageDataOptions + + type ClientRequestConstructorOptions = + Electron.ClientRequestConstructorOptions + + type Config = + Electron.Config + + type ConsoleMessageEvent = + Electron.ConsoleMessageEvent + + type ContextMenuEvent = + Electron.ContextMenuEvent + + type ContextMenuParams = + Electron.ContextMenuParams + + type CookiesGetFilter = + Electron.CookiesGetFilter + + type CookiesSetDetails = + Electron.CookiesSetDetails + + type CrashReporterStartOptions = + Electron.CrashReporterStartOptions + + type CreateFromBitmapOptions = + Electron.CreateFromBitmapOptions + + type CreateFromBufferOptions = + Electron.CreateFromBufferOptions + + type CreateInterruptedDownloadOptions = + Electron.CreateInterruptedDownloadOptions + + type Data = + Electron.Data + + type Details = + Electron.Details + + type DevicePermissionHandlerHandlerDetails = + Electron.DevicePermissionHandlerHandlerDetails + + type DidChangeThemeColorEvent = + Electron.DidChangeThemeColorEvent + + type DidCreateWindowDetails = + Electron.DidCreateWindowDetails + + type DidFailLoadEvent = + Electron.DidFailLoadEvent + + type DidFrameFinishLoadEvent = + Electron.DidFrameFinishLoadEvent + + type DidFrameNavigateEvent = + Electron.DidFrameNavigateEvent + + type DidNavigateEvent = + Electron.DidNavigateEvent + + type DidNavigateInPageEvent = + Electron.DidNavigateInPageEvent + + type DidStartNavigationEvent = + Electron.DidStartNavigationEvent + + type DisplayBalloonOptions = + Electron.DisplayBalloonOptions + + type EnableNetworkEmulationOptions = + Electron.EnableNetworkEmulationOptions + + type FeedURLOptions = + Electron.FeedURLOptions + + type FileIconOptions = + Electron.FileIconOptions + + type Filter = + Electron.Filter + + type FindInPageOptions = + Electron.FindInPageOptions + + type FocusOptions = + Electron.FocusOptions + + type FoundInPageEvent = + Electron.FoundInPageEvent + + type FromPartitionOptions = + Electron.FromPartitionOptions + + type HandlerDetails = + Electron.HandlerDetails + + type HeadersReceivedResponse = + Electron.HeadersReceivedResponse + + type HeapStatistics = + Electron.HeapStatistics + + type HidDeviceAddedDetails = + Electron.HidDeviceAddedDetails + + type HidDeviceRemovedDetails = + Electron.HidDeviceRemovedDetails + + type IgnoreMouseEventsOptions = + Electron.IgnoreMouseEventsOptions + + type ImportCertificateOptions = + Electron.ImportCertificateOptions + + type Info = + Electron.Info + + type Input = + Electron.Input + + type InsertCSSOptions = + Electron.InsertCSSOptions + + type IpcMessageEvent = + Electron.IpcMessageEvent + + type Item = + Electron.Item + + type JumpListSettings = + Electron.JumpListSettings + + type LoadCommitEvent = + Electron.LoadCommitEvent + + type LoadExtensionOptions = + Electron.LoadExtensionOptions + + type LoadFileOptions = + Electron.LoadFileOptions + + type LoadURLOptions = + Electron.LoadURLOptions + + type LoginItemSettings = + Electron.LoginItemSettings + + type LoginItemSettingsOptions = + Electron.LoginItemSettingsOptions + + type MenuItemConstructorOptions = + Electron.MenuItemConstructorOptions + + type MessageBoxOptions = + Electron.MessageBoxOptions + + type MessageBoxReturnValue = + Electron.MessageBoxReturnValue + + type MessageBoxSyncOptions = + Electron.MessageBoxSyncOptions + + type MessageDetails = + Electron.MessageDetails + + type MessageEvent = + Electron.MessageEvent + + type MoveToApplicationsFolderOptions = + Electron.MoveToApplicationsFolderOptions + + type NewWindowEvent = + Electron.NewWindowEvent + + type NotificationConstructorOptions = + Electron.NotificationConstructorOptions + + type OnBeforeRedirectListenerDetails = + Electron.OnBeforeRedirectListenerDetails + + type OnBeforeRequestListenerDetails = + Electron.OnBeforeRequestListenerDetails + + type OnBeforeSendHeadersListenerDetails = + Electron.OnBeforeSendHeadersListenerDetails + + type OnCompletedListenerDetails = + Electron.OnCompletedListenerDetails + + type OnErrorOccurredListenerDetails = + Electron.OnErrorOccurredListenerDetails + + type OnHeadersReceivedListenerDetails = + Electron.OnHeadersReceivedListenerDetails + + type OnResponseStartedListenerDetails = + Electron.OnResponseStartedListenerDetails + + type OnSendHeadersListenerDetails = + Electron.OnSendHeadersListenerDetails + + type OpenDevToolsOptions = + Electron.OpenDevToolsOptions + + type OpenDialogOptions = + Electron.OpenDialogOptions + + type OpenDialogReturnValue = + Electron.OpenDialogReturnValue + + type OpenDialogSyncOptions = + Electron.OpenDialogSyncOptions + + type OpenExternalOptions = + Electron.OpenExternalOptions + + type Options = + Electron.Options + + type PageFaviconUpdatedEvent = + Electron.PageFaviconUpdatedEvent + + type PageTitleUpdatedEvent = + Electron.PageTitleUpdatedEvent + + type Parameters = + Electron.Parameters + + type Payment = + Electron.Payment + + type PermissionCheckHandlerHandlerDetails = + Electron.PermissionCheckHandlerHandlerDetails + + type PermissionRequestHandlerHandlerDetails = + Electron.PermissionRequestHandlerHandlerDetails + + type PluginCrashedEvent = + Electron.PluginCrashedEvent + + type PopupOptions = + Electron.PopupOptions + + type PreconnectOptions = + Electron.PreconnectOptions + + type PrintToPDFOptions = + Electron.PrintToPDFOptions + + type Privileges = + Electron.Privileges + + type ProgressBarOptions = + Electron.ProgressBarOptions + + type Provider = + Electron.Provider + + type ReadBookmark = + Electron.ReadBookmark + + type RegistrationCompletedDetails = + Electron.RegistrationCompletedDetails + + type RelaunchOptions = + Electron.RelaunchOptions + + type RenderProcessGoneDetails = + Electron.RenderProcessGoneDetails + + type Request = + Electron.Request + + type ResizeOptions = + Electron.ResizeOptions + + type ResourceUsage = + Electron.ResourceUsage + + type Response = + Electron.Response + + type Result = + Electron.Result + + type SaveDialogOptions = + Electron.SaveDialogOptions + + type SaveDialogReturnValue = + Electron.SaveDialogReturnValue + + type SaveDialogSyncOptions = + Electron.SaveDialogSyncOptions + + type SelectHidDeviceDetails = + Electron.SelectHidDeviceDetails + + type Settings = + Electron.Settings + + type SourcesOptions = + Electron.SourcesOptions + + type SSLConfigConfig = + Electron.SSLConfigConfig + + type StartLoggingOptions = + Electron.StartLoggingOptions + + type SystemMemoryInfo = + Electron.SystemMemoryInfo + + type TitleOptions = + Electron.TitleOptions + + type ToBitmapOptions = + Electron.ToBitmapOptions + + type ToDataURLOptions = + Electron.ToDataURLOptions + + type ToPNGOptions = + Electron.ToPNGOptions + + type TouchBarButtonConstructorOptions = + Electron.TouchBarButtonConstructorOptions + + type TouchBarColorPickerConstructorOptions = + Electron.TouchBarColorPickerConstructorOptions + + type TouchBarConstructorOptions = + Electron.TouchBarConstructorOptions + + type TouchBarGroupConstructorOptions = + Electron.TouchBarGroupConstructorOptions + + type TouchBarLabelConstructorOptions = + Electron.TouchBarLabelConstructorOptions + + type TouchBarPopoverConstructorOptions = + Electron.TouchBarPopoverConstructorOptions + + type TouchBarScrubberConstructorOptions = + Electron.TouchBarScrubberConstructorOptions + + type TouchBarSegmentedControlConstructorOptions = + Electron.TouchBarSegmentedControlConstructorOptions + + type TouchBarSliderConstructorOptions = + Electron.TouchBarSliderConstructorOptions + + type TouchBarSpacerConstructorOptions = + Electron.TouchBarSpacerConstructorOptions + + type TraceBufferUsageReturnValue = + Electron.TraceBufferUsageReturnValue + + type UpdateTargetUrlEvent = + Electron.UpdateTargetUrlEvent + + type UploadProgress = + Electron.UploadProgress + + type VisibleOnAllWorkspacesOptions = + Electron.VisibleOnAllWorkspacesOptions + + type WebContentsPrintOptions = + Electron.WebContentsPrintOptions + + type WebviewTagPrintOptions = + Electron.WebviewTagPrintOptions + + type WillNavigateEvent = + Electron.WillNavigateEvent + + type EditFlags = + Electron.EditFlags + + type FoundInPageResult = + Electron.FoundInPageResult + + type LaunchItems = + Electron.LaunchItems + + type Margins = + Electron.Margins + + type MediaFlags = + Electron.MediaFlags + + type PageRanges = + Electron.PageRanges + + type Params = + Electron.Params + + type WebPreferences = + Electron.WebPreferences + + type DefaultFontFamily = + Electron.DefaultFontFamily + + type BluetoothDevice = + Electron.BluetoothDevice + + type Certificate = + Electron.Certificate + + type CertificatePrincipal = + Electron.CertificatePrincipal + + type Cookie = + Electron.Cookie + + type CPUUsage = + Electron.CPUUsage + + type CrashReport = + Electron.CrashReport + + type CustomScheme = + Electron.CustomScheme + + type DesktopCapturerSource = + Electron.DesktopCapturerSource + + type Display = + Electron.Display + + type Event = + Electron.Event + + type Extension = + Electron.Extension + + type ExtensionInfo = + Electron.ExtensionInfo + + type FileFilter = + Electron.FileFilter + + type FilePathWithHeaders = + Electron.FilePathWithHeaders + + type GPUFeatureStatus = + Electron.GPUFeatureStatus + + type HIDDevice = + Electron.HIDDevice + + type InputEvent = + Electron.InputEvent + + type IOCounters = + Electron.IOCounters + + type IpcMainEvent = + Electron.IpcMainEvent + + type IpcMainInvokeEvent = + Electron.IpcMainInvokeEvent + + type IpcRendererEvent = + Electron.IpcRendererEvent + + type JumpListCategory = + Electron.JumpListCategory + + type JumpListItem = + Electron.JumpListItem + + type KeyboardEvent = + Electron.KeyboardEvent + + type KeyboardInputEvent = + Electron.KeyboardInputEvent + + type MemoryInfo = + Electron.MemoryInfo + + type MemoryUsageDetails = + Electron.MemoryUsageDetails + + type MimeTypedBuffer = + Electron.MimeTypedBuffer + + type MouseInputEvent = + Electron.MouseInputEvent + + type MouseWheelInputEvent = + Electron.MouseWheelInputEvent + + type NewWindowWebContentsEvent = + Electron.NewWindowWebContentsEvent + + type NotificationAction = + Electron.NotificationAction + + type NotificationResponse = + Electron.NotificationResponse + + type OverlayOptions = + Electron.OverlayOptions + + type Point = + Electron.Point + + type PostBody = + Electron.PostBody + + type PrinterInfo = + Electron.PrinterInfo + + type ProcessMemoryInfo = + Electron.ProcessMemoryInfo + + type ProcessMetric = + Electron.ProcessMetric + + type Product = + Electron.Product + + type ProtocolRequest = + Electron.ProtocolRequest + + type ProtocolResponse = + Electron.ProtocolResponse + + type ProtocolResponseUploadData = + Electron.ProtocolResponseUploadData + + type Rectangle = + Electron.Rectangle + + type Referrer = + Electron.Referrer + + type ScrubberItem = + Electron.ScrubberItem + + type SegmentedControlSegment = + Electron.SegmentedControlSegment + + type SerialPort = + Electron.SerialPort + + type ServiceWorkerInfo = + Electron.ServiceWorkerInfo + + type SharedWorkerInfo = + Electron.SharedWorkerInfo + + type SharingItem = + Electron.SharingItem + + type ShortcutDetails = + Electron.ShortcutDetails + + type Size = + Electron.Size + + type Task = + Electron.Task + + type ThumbarButton = + Electron.ThumbarButton + + type TraceCategoriesAndOptions = + Electron.TraceCategoriesAndOptions + + type TraceConfig = + Electron.TraceConfig + + type Transaction = + Electron.Transaction + + type UploadData = + Electron.UploadData + + type UploadFile = + Electron.UploadFile + + type UploadRawData = + Electron.UploadRawData + + type UserDefaultTypes = + Electron.UserDefaultTypes + + type WebSource = + Electron.WebSource + + type nativeImage = + NativeImage + + type session = + Session + + type webContents = + WebContents + + type webFrameMain = + WebFrameMain + + type [] [] AppGetGPUInfo = + | Basic + | Complete + + type [] [] AppGetPath = + | Home + | AppData + | UserData + | Cache + | Temp + | Exe + | Module + | Desktop + | Documents + | Downloads + | Music + | Pictures + | Videos + | Recent + | Logs + | CrashDumps + + type [] [] AppSetActivationPolicy = + | Regular + | Accessory + | Prohibited + + type [] [] BrowserWindowSetAlwaysOnTop = + | Normal + | Floating + | [] TornOffMenu + | [] ModalPanel + | [] MainMenu + | Status + | [] PopUpMenu + | [] ScreenSaver + + type [] [] BrowserWindowSetVibrancy = + | [] AppearanceBased + | Light + | Dark + | Titlebar + | Selection + | Menu + | Popover + | Sidebar + | [] MediumLight + | [] UltraDark + | Header + | Sheet + | Window + | Hud + | [] FullscreenUi + | Tooltip + | Content + | [] UnderWindow + | [] UnderPage + + type [] [] ClipboardAvailableFormats = + | Selection + | Clipboard + + type [] [] CookieSameSite = + | Unspecified + | No_restriction + | Lax + | Strict + + type [] [] CookiesOn_changed = + | Explicit + | Overwrite + | Expired + | Evicted + | [] ExpiredOverwrite + + type [] [] DisplayAccelerometerSupport = + | Available + | Unavailable + | Unknown + + type [] [] DockBounce = + | Critical + | Informational + + type [] [] DownloadItemOn_done = + | Completed + | Cancelled + | Interrupted + + type [] [] DownloadItemOn_updated = + | Progressing + | Interrupted + + type [] [] DownloadItemGetState = + | Progressing + | Completed + | Cancelled + | Interrupted + + type [] [] InputEventModifiersArray = + | Shift + | Control + | Ctrl + | Alt + | Meta + | Command + | Cmd + | IsKeypad + | IsAutoRepeat + | LeftButtonDown + | MiddleButtonDown + | RightButtonDown + | CapsLock + | NumLock + | Left + | Right + + type [] [] JumpListCategoryType = + | Tasks + | Frequent + | Recent + | Custom + + type [] [] JumpListItemType = + | Task + | Separator + | File + + type [] [] KeyboardInputEventType = + | KeyDown + | KeyUp + | Char + + type [] [] MenuItemRole = + | Undo + | Redo + | Cut + | Copy + | Paste + | PasteAndMatchStyle + | Delete + | SelectAll + | Reload + | ForceReload + | ToggleDevTools + | ResetZoom + | ZoomIn + | ZoomOut + | ToggleSpellChecker + | Togglefullscreen + | Window + | Minimize + | Close + | Help + | About + | Services + | Hide + | HideOthers + | Unhide + | Quit + | StartSpeaking + | StopSpeaking + | Zoom + | Front + | AppMenu + | FileMenu + | EditMenu + | ViewMenu + | ShareMenu + | RecentDocuments + | ToggleTabBar + | SelectNextTab + | SelectPreviousTab + | MergeAllWindows + | ClearRecentDocuments + | MoveTabToNewWindow + | WindowMenu + + type [] [] MenuItemType = + | Normal + | Separator + | Submenu + | Checkbox + | Radio + + type [] [] MouseInputEventButton = + | Left + | Middle + | Right + + type [] [] MouseInputEventType = + | MouseDown + | MouseUp + | MouseEnter + | MouseLeave + | ContextMenu + | MouseWheel + | MouseMove + + type [] [] NativeThemeThemeSource = + | System + | Light + | Dark + + type [] [] NotificationTimeoutType = + | Default + | Never + + type [] [] NotificationUrgency = + | Normal + | Critical + | Low + + type [] [] PowerMonitorGetSystemIdleState = + | Active + | Idle + | Locked + | Unknown + + type [] [] PowerSaveBlockerStart = + | [] PreventAppSuspension + | [] PreventDisplaySleep + + type [] [] ProcessMetricIntegrityLevel = + | Untrusted + | Low + | Medium + | High + | Unknown + + type [] [] ProcessMetricType = + | [] Browser + | [] Tab + | [] Utility + | [] Zygote + | [] ``Sandbox helper`` + | [] GPU + | [] ``Pepper Plugin`` + | [] ``Pepper Plugin Broker`` + | [] Unknown + + type [] [] ReferrerPolicy = + | Default + | [] UnsafeUrl + | [] NoReferrerWhenDowngrade + | [] NoReferrer + | Origin + | [] StrictOriginWhenCrossOrigin + | [] SameOrigin + | [] StrictOrigin + + type [] [] SessionSetPermissionRequestHandler = + | [] ClipboardRead + | Media + | [] DisplayCapture + | MediaKeySystem + | Geolocation + | Notifications + | Midi + | MidiSysex + | PointerLock + | Fullscreen + | OpenExternal + | Unknown + + type [] [] ShellWriteShortcutLink = + | Create + | Update + | Replace + + type [] [] SystemPreferencesAskForMediaAccess = + | Microphone + | Camera + + type [] [] SystemPreferencesGetAppLevelAppearance = + | Dark + | Light + | Unknown + + type [] [] SystemPreferencesGetColor = + | [] N3dDarkShadow + | [] N3dFace + | [] N3dHighlight + | [] N3dLight + | [] N3dShadow + | [] ActiveBorder + | [] ActiveCaption + | [] ActiveCaptionGradient + | [] AppWorkspace + | [] ButtonText + | [] CaptionText + | Desktop + | [] DisabledText + | Highlight + | [] HighlightText + | Hotlight + | [] InactiveBorder + | [] InactiveCaption + | [] InactiveCaptionGradient + | [] InactiveCaptionText + | [] InfoBackground + | [] InfoText + | Menu + | [] MenuHighlight + | Menubar + | [] MenuText + | Scrollbar + | Window + | [] WindowFrame + | [] WindowText + | [] AlternateSelectedControlText + | [] ControlBackground + | Control + | [] ControlText + | [] DisabledControlText + | [] FindHighlight + | Grid + | [] HeaderText + | Highlight1 + | [] KeyboardFocusIndicator + | Label + | Link + | [] PlaceholderText + | [] QuaternaryLabel + | [] ScrubberTexturedBackground + | [] SecondaryLabel + | [] SelectedContentBackground + | [] SelectedControl + | [] SelectedControlText + | [] SelectedMenuItemText + | [] SelectedTextBackground + | [] SelectedText + | Separator + | Shadow + | [] TertiaryLabel + | [] TextBackground + | Text + | [] UnderPageBackground + | [] UnemphasizedSelectedContentBackground + | [] UnemphasizedSelectedTextBackground + | [] UnemphasizedSelectedText + | [] WindowBackground + | [] WindowFrameText + + type [] [] SystemPreferencesGetMediaAccessStatus = + | Microphone + | Camera + | Screen + + type [] [] SystemPreferencesGetMediaAccessStatus2 = + | [] NotDetermined + | Granted + | Denied + | Restricted + | Unknown + + type [] [] SystemPreferencesGetSystemColor = + | Blue + | Brown + | Gray + | Green + | Orange + | Pink + | Purple + | Red + | Yellow + + type [] [] SystemPreferencesSetAppLevelAppearance = + | Dark + | Light + + type [] [] SystemPreferencesSetUserDefault = + | String + | Boolean + | Integer + | Float + | Double + | Url + | Array + | Dictionary + + type [] [] TouchBarButtonIconPosition = + | Left + | Right + | Overlay + + type [] [] TouchBarScrubberMode = + | Fixed + | Free + + type [] [] TouchBarScrubberOverlayStyle = + | Background + | Outline + | None + + type [] [] TouchBarSegmentedControlMode = + | Single + | Multiple + | Buttons + + type [] [] TouchBarSpacerSize = + | Small + | Large + | Flexible + + type [] [] TraceConfigRecording_mode = + | [] RecordUntilFull + | [] RecordContinuously + | [] RecordAsMuchAsPossible + | [] TraceToConsole + + type [] [] TransactionTransactionState = + | Purchasing + | Purchased + | Failed + | Restored + | Deferred + + type [] [] WebContentsOn_newWindow = + | Default + | [] ForegroundTab + | [] BackgroundTab + | [] NewWindow + | [] SaveToDisk + | Other + + type [] [] WebContentsOn_zoomChanged = + | In + | Out + + type [] [] WebContentsGetType = + | BackgroundPage + | Window + | BrowserView + | Remote + | Webview + | Offscreen + + type [] [] WebContentsSavePage = + | [] HTMLOnly + | [] HTMLComplete + | [] MHTML + + type [] [] WebContentsSetWebRTCIPHandlingPolicy = + | Default + | Default_public_interface_only + | Default_public_and_private_interfaces + | Disable_non_proxied_udp + + type [] [] WebContentsStopFindInPage = + | ClearSelection + | KeepSelection + | ActivateSelection + + type [] [] BrowserWindowConstructorOptionsVisualEffectState = + | FollowWindow + | Active + | Inactive + + type [] [] BrowserWindowConstructorOptionsTitleBarStyle = + | Default + | Hidden + | HiddenInset + | CustomButtonsOnHover + + type [] [] ClientRequestConstructorOptionsCredentials = + | Include + | Omit + + type [] [] ClientRequestConstructorOptionsRedirect = + | Follow + | Error + | Manual + + type [] [] ConfigMode = + | Direct + | Auto_detect + | Pac_script + | Fixed_servers + | System + + type [] [] ContextMenuParamsMediaType = + | None + | Image + | Audio + | Video + | Canvas + | File + | Plugin + + type [] [] ContextMenuParamsMenuSourceType = + | None + | Mouse + | Keyboard + | Touch + | TouchMenu + | LongPress + | LongTap + | TouchHandle + | Stylus + | AdjustSelection + | AdjustSelectionReset + + type [] [] DetailsType = + | [] Utility + | [] Zygote + | [] ``Sandbox helper`` + | [] GPU + | [] ``Pepper Plugin`` + | [] ``Pepper Plugin Broker`` + | [] Unknown + + type [] [] DetailsReason = + | [] CleanExit + | [] AbnormalExit + | Killed + | Crashed + | Oom + | [] LaunchFailed + | [] IntegrityFailure + + type [] [] DevicePermissionHandlerHandlerDetailsDeviceType = + | Hid + | Serial + + type [] [] DisplayBalloonOptionsIconType = + | None + | Info + | Warning + | Error + | Custom + + type [] [] FeedURLOptionsServerType = + | Json + | Default + + type [] [] FileIconOptionsSize = + | Small + | Normal + | Large + + type [] [] MessageDetailsSource = + | Javascript + | Xml + | Network + | [] ConsoleApi + | Storage + | [] AppCache + | Rendering + | Security + | Deprecation + | Worker + | Violation + | Intervention + | Recommendation + | Other + + type [] [] MoveToApplicationsFolderOptionsConflictHandler = + | Exists + | ExistsAndRunning + + type [] [] OnBeforeRedirectListenerDetailsResourceType = + | MainFrame + | SubFrame + | Stylesheet + | Script + | Image + | Font + | Object + | Xhr + | Ping + | CspReport + | Media + | WebSocket + | Other + + type [] [] OpenDevToolsOptionsMode = + | Right + | Bottom + | Undocked + | Detach + + type [] [] OpenDialogOptionsPropertiesArray = + | OpenFile + | OpenDirectory + | MultiSelections + | ShowHiddenFiles + | CreateDirectory + | PromptToCreate + | NoResolveAliases + | TreatPackageAsDirectory + | DontAddToRecent + + type [] [] ParametersScreenPosition = + | Desktop + | Mobile + + type [] [] PermissionCheckHandlerHandlerDetailsMediaType = + | Video + | Audio + | Unknown + + type [] [] PermissionRequestHandlerHandlerDetailsMediaTypesArray = + | Video + | Audio + + type [] [] ProgressBarOptionsMode = + | None + | Normal + | Indeterminate + | Error + | Paused + + type [] [] SaveDialogOptionsPropertiesArray = + | ShowHiddenFiles + | CreateDirectory + | TreatPackageAsDirectory + | ShowOverwriteConfirmation + | DontAddToRecent + + type [] [] StartLoggingOptionsCaptureMode = + | Default + | IncludeSensitive + | Everything + + type [] [] TitleOptionsFontType = + | Monospaced + | MonospacedDigit + + type [] [] TouchBarSegmentedControlConstructorOptionsSegmentStyle = + | Automatic + | Rounded + | [] TexturedRounded + | [] RoundRect + | [] TexturedSquare + | Capsule + | [] SmallSquare + | Separated + + type [] [] WebContentsPrintOptionsDuplexMode = + | Simplex + | ShortEdge + | LongEdge + + type [] [] MarginsMarginType = + | Default + | None + | PrintableArea + | Custom + + type [] [] WebPreferencesAutoplayPolicy = + | [] NoUserGestureRequired + | [] UserGestureRequired + | [] DocumentUserActivationRequired + + type [] [] WebPreferencesV8CacheOptions = + | None + | Code + | BypassHeatCheck + | BypassHeatCheckAndEagerCompile +type ExceptError = System.Exception +type [] NodeRequireFunction = + [] abstract Invoke_electron: unit -> obj + [] abstract ``Invoke_electron/main``: unit -> obj + [] abstract ``Invoke_electron/common``: unit -> obj + [] abstract ``Invoke_electron/renderer``: unit -> obj + +type [] NodeRequire = + [] abstract Invoke_electron: unit -> obj + [] abstract ``Invoke_electron/main``: unit -> obj + [] abstract ``Invoke_electron/common``: unit -> obj + [] abstract ``Invoke_electron/renderer``: unit -> obj + +type [] File = + /// The real path to the file on the users filesystem + abstract path: string with get, set + +type [] Document = + [] abstract createElement_webview: unit -> Electron.WebviewTag + +module NodeJS = + type [] ReadableStream = + interface end + type [] EventEmitter<'self> = + abstract addListener: event: string * listener: (Event -> unit) -> 'self + abstract on: event: string * listener: (Event -> unit) -> 'self + abstract once: event: string * listener: (Event -> unit) -> 'self + abstract removeListener: event: string * listener: (Event -> unit) -> 'self + abstract removeAllListeners: ?event: string -> 'self + abstract setMaxListeners: n: int -> 'self + abstract getMaxListeners: unit -> int + abstract listeners: event: string -> (Event -> unit) [] + abstract emit: event: string * [] args: obj [] -> bool + abstract listenerCount: event: string -> int + abstract prependListener: event: string * listener: (Event -> unit) -> 'self + abstract prependOnceListener: event: string * listener: (Event -> unit) -> 'self + abstract eventNames: unit -> string [] + + type [] Process = + inherit EventEmitter + /// Emitted when Electron has loaded its internal initialization script and is + /// beginning to load the web page or the main script. + [] abstract on_loaded: listener: Function -> Process + [] abstract once_loaded: listener: Function -> Process + [] abstract addListener_loaded: listener: Function -> Process + [] abstract removeListener_loaded: listener: Function -> Process + /// Causes the main thread of the current process crash. + abstract crash: unit -> unit + /// + /// * allocated Integer - Size of all allocated objects in Kilobytes. + /// * marked Integer - Size of all marked objects in Kilobytes. + /// * total Integer - Total allocated space in Kilobytes. + /// + /// Returns an object with Blink memory information. It can be useful for debugging + /// rendering / DOM related memory issues. Note that all values are reported in + /// Kilobytes. + /// + abstract getBlinkMemoryInfo: unit -> Electron.BlinkMemoryInfo + abstract getCPUUsage: unit -> Electron.CPUUsage + /// + /// The number of milliseconds since epoch, or null if the information is + /// unavailable + /// + /// Indicates the creation time of the application. The time is represented as + /// number of milliseconds since epoch. It returns null if it is unable to get the + /// process creation time. + /// + abstract getCreationTime: unit -> float option + /// + /// * totalHeapSize Integer + /// * totalHeapSizeExecutable Integer + /// * totalPhysicalSize Integer + /// * totalAvailableSize Integer + /// * usedHeapSize Integer + /// * heapSizeLimit Integer + /// * mallocedMemory Integer + /// * peakMallocedMemory Integer + /// * doesZapGarbage Boolean + /// + /// Returns an object with V8 heap statistics. Note that all statistics are reported + /// in Kilobytes. + /// + abstract getHeapStatistics: unit -> Electron.HeapStatistics + abstract getIOCounters: unit -> Electron.IOCounters + /// + /// Resolves with a ProcessMemoryInfo + /// + /// Returns an object giving memory usage statistics about the current process. Note + /// that all statistics are reported in Kilobytes. This api should be called after + /// app ready. + /// + /// Chromium does not provide residentSet value for macOS. This is because macOS + /// performs in-memory compression of pages that haven't been recently used. As a + /// result the resident set size value is not what one would expect. private + /// memory is more representative of the actual pre-compression memory usage of the + /// process on macOS. + /// + abstract getProcessMemoryInfo: unit -> Promise + /// + /// * total Integer - The total amount of physical memory in Kilobytes available + /// to the system. + /// * free Integer - The total amount of memory not being used by applications or + /// disk cache. + /// * swapTotal Integer _Windows_ _Linux_ - The total amount of swap memory in + /// Kilobytes available to the system. + /// * swapFree Integer _Windows_ _Linux_ - The free amount of swap memory in + /// Kilobytes available to the system. + /// + /// Returns an object giving memory usage statistics about the entire system. Note + /// that all statistics are reported in Kilobytes. + /// + abstract getSystemMemoryInfo: unit -> Electron.SystemMemoryInfo + /// + /// The version of the host operating system. + /// + /// Example: + /// + /// **Note:** It returns the actual operating system version instead of kernel + /// version on macOS unlike os.release(). + /// + abstract getSystemVersion: unit -> string + /// Causes the main thread of the current process hang. + abstract hang: unit -> unit + /// + /// Sets the file descriptor soft limit to maxDescriptors or the OS hard limit, + /// whichever is lower for the current process. + /// + abstract setFdLimit: maxDescriptors: float -> unit + /// + /// Indicates whether the snapshot has been created successfully. + /// + /// Takes a V8 heap snapshot and saves it to filePath. + /// + abstract takeHeapSnapshot: filePath: string -> bool + /// A String representing Chrome's version string. + abstract chrome: string + /// + /// A String (optional) representing a globally unique ID of the current + /// JavaScript context. Each frame has its own JavaScript context. When + /// contextIsolation is enabled, the isolated world also has a separate JavaScript + /// context. This property is only available in the renderer process. + /// + abstract contextId: string option + /// + /// A Boolean that indicates whether the current renderer context has + /// contextIsolation enabled. It is undefined in the main process. + /// + abstract contextIsolated: bool + /// + /// A Boolean. When app is started by being passed as parameter to the default + /// app, this property is true in the main process, otherwise it is undefined. + /// + abstract defaultApp: bool + /// A String representing Electron's version string. + abstract electron: string + /// + /// A Boolean, true when the current renderer context is the "main" renderer + /// frame. If you want the ID of the current frame you should use + /// webFrame.routingId. + /// + abstract isMainFrame: bool + /// + /// A Boolean. For Mac App Store build, this property is true, for other builds + /// it is undefined. + /// + abstract mas: bool + /// + /// A Boolean that controls ASAR support inside your application. Setting this to + /// true will disable the support for asar archives in Node's built-in modules. + /// + abstract noAsar: bool with get, set + /// + /// A Boolean that controls whether or not deprecation warnings are printed to + /// stderr. Setting this to true will silence deprecation warnings. This + /// property is used instead of the --no-deprecation command line flag. + /// + abstract noDeprecation: bool with get, set + /// A String representing the path to the resources directory. + abstract resourcesPath: string + /// + /// A Boolean. When the renderer process is sandboxed, this property is true, + /// otherwise it is undefined. + /// + abstract sandboxed: bool + /// + /// A Boolean that controls whether or not deprecation warnings will be thrown as + /// exceptions. Setting this to true will throw errors for deprecations. This + /// property is used instead of the --throw-deprecation command line flag. + /// + abstract throwDeprecation: bool with get, set + /// + /// A Boolean that controls whether or not deprecations printed to stderr + /// include their stack trace. Setting this to true will print stack traces for + /// deprecations. This property is instead of the --trace-deprecation command line + /// flag. + /// + abstract traceDeprecation: bool with get, set + /// + /// A Boolean that controls whether or not process warnings printed to stderr + /// include their stack trace. Setting this to true will print stack traces for + /// process warnings (including deprecations). This property is instead of the + /// --trace-warnings command line flag. + /// + abstract traceProcessWarnings: bool with get, set + /// + /// A String representing the current process's type, can be: + /// + /// * browser - The main process + /// * renderer - A renderer process + /// * worker - In a web worker + /// + abstract ``type``: ProcessType + /// + /// A Boolean. If the app is running as a Windows Store app (appx), this property + /// is true, for otherwise it is undefined. + /// + abstract windowsStore: bool + + type [] ProcessVersions = + abstract electron: string + abstract chrome: string + + type [] [] ProcessType = + | Browser + | Renderer + | Worker \ No newline at end of file diff --git a/src/Renderer/Common/Helpers.fs b/src/Renderer/Common/Helpers.fs new file mode 100644 index 0000000..e1f9d25 --- /dev/null +++ b/src/Renderer/Common/Helpers.fs @@ -0,0 +1,277 @@ +(* + Helpers.fs + + Some miscellaneous fsharp only (no JS) utility functions. +*) + +module Helpers +open CommonTypes + + [] + module JsonHelpers = + open Fable.SimpleJson + + + type SavedInfo = + | CanvasOnly of CanvasState + | CanvasWithFileWaveInfo of CanvasState * SavedWaveInfo option * System.DateTime + | CanvasWithFileWaveInfoAndNewConns of CanvasState * SavedWaveInfo option * System.DateTime + + member self.getCanvas = + match self with + | CanvasOnly c -> c + | CanvasWithFileWaveInfo (c,_,_) -> c + | CanvasWithFileWaveInfoAndNewConns (c,_,_) -> c + + member self.getTimeStamp = + match self with + | CanvasOnly _ -> System.DateTime.MinValue + | CanvasWithFileWaveInfo (_,_,ts) -> ts + | CanvasWithFileWaveInfoAndNewConns (_,_,ts) -> ts + + member self.getWaveInfo = + match self with + | CanvasOnly _ -> None + | CanvasWithFileWaveInfo (_,waveInfo,_) -> waveInfo + | CanvasWithFileWaveInfoAndNewConns (_,waveInfo,_) -> waveInfo + + + + + let stateToJsonString (cState: CanvasState, waveInfo: SavedWaveInfo option) : string = + let time = System.DateTime.Now + //printfn "%A" cState + try + Json.serialize (CanvasWithFileWaveInfoAndNewConns (cState, waveInfo, time)) + with + | e -> + printfn "HELP: exception in SimpleJson.stringify %A" e + "Error in stringify" + + + let jsonStringToState (jsonString : string) = + Json.tryParseAs jsonString + |> (function + | Ok state -> Ok (CanvasOnly state) + | Error _ -> + match Json.tryParseAs jsonString with + | Ok state -> Ok state + | Error str -> + printfn "Error in Json parse of %s : %s" jsonString str + Error str) + + + +(*-----------------------------------General helpers-----------------------------------------*) + +/// Return a memoized version of funcToMemoize where. +/// Repeated calls with equivalent inputs return a stored result. +/// Inputs a, a' are deemed equivalent if keyFunc a = keyFunc a'. +/// Use this as well as LazyView etc, it has a different usage since it need not +/// have React output and comparison is via a key function. +let memoizeBy (keyFunc: 'a -> 'k) (funcToMemoize: 'a -> 'c) : 'a -> 'c = + let mutable lastKey: 'k option = None + let mutable lastValue: 'c option = None + fun (a: 'a) -> + let newKey = Some (keyFunc a) + if newKey = lastKey + then Option.get lastValue + else + lastKey <-newKey + let v = funcToMemoize a + lastValue <- Some v + v + + +// NB mapKeys and mapValues should probably be changed to use F# 6 Map.kets, Map.values + +/// Array of map keys +let inline mapKeys (map:Map<'a,'b>) = map |> Map.toArray |> Array.map fst + +/// Array of map values +let inline mapValues (map:Map<'a,'b>) = map |> Map.toArray |> Array.map snd + +/// Map a function over a pair of elements. +/// mapPair f (x,y) = f x, f y. +let inline mapPair (f: 'S -> 'T) ((p1,p2): 'S * 'S) = + f p1, f p2 + +/// Look up key in map, return defVal if key is not found +let inline mapFindWithDef (defVal: 'b) (key: 'a) (map:Map<'a,'b>) = + Option.defaultValue defVal (Map.tryFind key map) + +/// If key exists in map: (key:v) -> (key:update v), otherwise create new item +/// (key : update v) +let inline mapUpdateWithDef (defVal: 'b) (update: 'b -> 'b) (key: 'a) (map:Map<'a,'b>) = + let v = Option.defaultValue defVal (Map.tryFind key map) + Map.add key (update v) map + +/// Union of maps, common keys take m1 value +let inline mapUnion m1 m2 = + (m2, m1) + ||> Map.fold (fun m key value -> Map.add key value m ) + +/// create inverse map +let inline mapInverse (m:Map<'A,'B>) = + m + |> Map.toSeq + |> Seq.map (fun (a,b) -> b,a) + |> Map.ofSeq + +let shortPComp (comp:Component) = + match comp.Type with + | Custom sc -> sprintf "%s:Custom.%s.%A->%A" comp.Label sc.Name sc.InputLabels sc.OutputLabels + | _ -> sprintf "%s:%A" comp.Label comp.Type + +/// return initial n characters of a string +let sprintInitial n (s:string) = + s + |> Seq.truncate n + |> Seq.map string + |> String.concat "" + +let assertThat cond msg = + if not cond + then failwithf "what? assert failed: %s" msg + +/// Return the first error found in a list of results, or the list of Oks if +/// there are none. +let tryFindError (lst : Result<'a,'b> list) : Result<'a list, 'b> = + let isError el = match el with | Error _ -> true | Ok _ -> false + let extractOk el = match el with | Ok ok -> ok | Error _ -> failwith "what? Impossible case in tryFindError" + match List.tryFind isError lst with + | Some (Error err) -> Error err + | None -> List.map extractOk lst |> Ok + | _ -> failwith "what? Impossible case in tryFindError" + +/// Return 2^exponent. +let pow2 (exponent : int) : int = + 1 <<< exponent // TODO use bit-shift. + +/// Return 2^exponent, packed into an int64. +let pow2int64 (exponent : int) : int64 = + 1L <<< exponent + +/// Set an element of the list at the specified position. +/// This function is slow: O(n). Do not use unless necessary. +let listSet (lst : 'a list) (item : 'a) (idx : int) : 'a list = +#if ASSERTS + assertThat (idx >= 0 && idx < lst.Length) + <| sprintf "Index out of range in listSet. Idx: %d, list length: %d" idx lst.Length +#endif + let p1, p2 = List.splitAt idx lst + // p2 has always at least one element as idx < lst.Length. + // Remove the first element of p2. + let _, p2 = List.splitAt 1 p2 + p1 @ [item] @ p2 + +/// Crop a string to the specified length. +/// fromStart indicates whether you want the first characters or the last +/// characters. +let cropToLength (len : int) (fromStart : bool) (str : string) = + match str.Length <= len with + | true -> str + | false when fromStart -> str[..len-1] + "..." // From start. + | false -> "..." + str[str.Length - len..] // From end. + + +let getMemData (address: int64) (memData: Memory1) = +#if ASSERTS + assertThat (memData.AddressWidth > 63 || (1UL <<< memData.AddressWidth) > (uint64 address)) ( + sprintf "Inconsistent memory access: address %A, memData %A" address memData) +#endif + Map.tryFind address memData.Data + |> Option.defaultValue 0L + +//--------------------Helper Functions-------------------------------// +//-------------------------------------------------------------------// + +let getNetList ((comps,conns) : CanvasState) = + let id2X f = + comps + |> List.map f + |> Map.ofList + let id2Outs = id2X (fun (c:Component) -> ComponentId c.Id,c.OutputPorts) + let id2Ins = id2X (fun (c:Component) -> ComponentId c.Id,c.InputPorts) + let id2Comp = id2X (fun (c:Component) -> ComponentId c.Id,c) + + let getPortInts sel initV ports = + ports + |> List.map (fun port -> + match port.PortNumber with + | Some pn -> sel pn , initV + | _ -> failwithf "Missing port in list %A" ports) + |> Map.ofList + + let initNets = + comps + |> List.map ( fun comp -> + { + Id = ComponentId comp.Id + Type = comp.Type + Label = comp.Label + Inputs = getPortInts InputPortNumber None comp.InputPorts + Outputs = getPortInts OutputPortNumber [] comp.OutputPorts + }) + |> List.map (fun comp -> comp.Id,comp) + |> Map.ofList + + let getOutputPortNumber (p:Port) = + id2Outs[ComponentId p.HostId] + |> List.find (fun p1 -> p1.Id = p.Id) + |> (fun p -> match p.PortNumber with Some n -> n | None -> failwithf "Missing input port number on %A" p.HostId) + |> OutputPortNumber + + + let getInputPortNumber (p:Port) = + id2Ins[ComponentId p.HostId] + |> List.find (fun p1 -> p1.Id = p.Id) + |> (fun p -> match p.PortNumber with Some n -> n | None -> failwithf "Missing input port number on %A" p.HostId) + |> InputPortNumber + + let updateNComp compId updateFn (nets:NetList) = + Map.add compId (updateFn nets[compId]) nets + + let updateInputPorts pNum src (comp:NetListComponent) = + { comp with Inputs = Map.add pNum (Some src) comp.Inputs} + + let updateInputsComp compId pNum src nets = + let uFn = updateInputPorts pNum src + updateNComp compId uFn nets + + let updateOutputPorts pNum tgt (comp:NetListComponent) = + {comp with Outputs = Map.add pNum (tgt :: comp.Outputs[pNum]) comp.Outputs} + + let updateOutputsComp compId pNum tgt nets = + let uFn = updateOutputPorts pNum tgt + updateNComp compId uFn nets + + let target (conn:Connection) = + { + TargetCompId = ComponentId conn.Target.HostId + InputPort = getInputPortNumber conn.Target + TargetConnId = ConnectionId conn.Id + } + let source (conn:Connection) = + { + SourceCompId = ComponentId conn.Source.HostId + OutputPort = getOutputPortNumber conn.Source + SourceConnId = ConnectionId conn.Id + } + + let addConnectionsToNets (nets:Map) (conn:Connection) = + let tgt = target conn + let src = source conn + let tComp = id2Comp[tgt.TargetCompId] + let sComp = id2Comp[src.SourceCompId] + nets + |> updateOutputsComp (ComponentId sComp.Id) src.OutputPort tgt + |> updateInputsComp (ComponentId tComp.Id)tgt.InputPort src + + (initNets, conns) ||> List.fold addConnectionsToNets + + + + + + diff --git a/src/Renderer/Common/TimeHelpers.fs b/src/Renderer/Common/TimeHelpers.fs new file mode 100644 index 0000000..521a611 --- /dev/null +++ b/src/Renderer/Common/TimeHelpers.fs @@ -0,0 +1,356 @@ +(* +Functions to measure elapsed time and instrument the operation of update and view functions, displaying +results in various forms. +*) + +module TimeHelpers +open CommonTypes +open Helpers + +let checkPerformance m n startTimer stopTimer = + printfn "Checking performance with size = %d, iterations = %d" m n + let arrayBuffer() = + let buff = + [|0..m-1|] + |> Array.map (fun i -> (i+1) % m) + let mutable index = 0 + let mutable el = 0 + startTimer "Array" + while index < n do + index <- index + 1 + el <- buff[el] + el |> ignore + stopTimer "Array" + + let arrayBufferLookup() = + let buff = + [|0..m-1|] + |> Array.map (fun i -> (i+1) % m) + let mutable index = 0 + let mutable el = 0 + startTimer "ArrayBufferLookup" + while index < n / 2 do + index <- index + 1 + for i = 0 to (m-1)/2 do + el <- buff[el] + index + el |> ignore + stopTimer "ArrayBufferLookup" + + let mutableArrayBuffer() = + let buff = + [|0..m-1|] + |> Array.map (fun i -> (i+1) % m) + let mutable index = 0 + let mutable el = 0 + startTimer "Mutable Array" + while index < n do + index <- index + 1 + el <- if el+1 < m then el+1 else 0 + buff[el] <- index + buff |> ignore + stopTimer "Mutable Array" + + + let updateArrayBuffer() = + let buff = + [|0..m-1|] + |> Array.map (fun i -> (i+1) % m) + let mutable index = 0 + let mutable el = 0 + let mutable arr = buff + startTimer "Copy-update Array" + let z = (buff,[0..n]) ||> List.fold (fun buff i -> + let r = (Array.copy buff) + r[i % m] <- i + r) + z[0] |> ignore + stopTimer "Copy-update Array" + + let listBuffer() = + let buff = + [0..m-1] + |> List.map (fun i -> (i+1) % m) + let mutable index = 0 + let mutable el = 0 + startTimer "List" + while index < n do + index <- index + 1 + el <- buff[el] + el |> ignore + stopTimer "List" + + let dictBuffer() = + let dict = System.Collections.Generic.Dictionary() + [|0..m-1|] + |> Array.iter (fun i -> dict[i] <- (i+1) % m) + let mutable index = 0 + let mutable el = 0 + startTimer "Dict" + while index < n do + index <- index + 1 + el <- dict[el] + index |> ignore + stopTimer "Dict" + + let mapBuffer() = + let buff = + [|0..m-1|] + |> Array.map (fun i -> i,(i+1) % m) + |> Map.ofArray + let mutable index = 0 + let mutable el = 0 + startTimer "Map" + while index < n do + index <- index + 1 + el <- buff[el] + index |> ignore + stopTimer "Map" + + + + let updateMapBuffer() = + let buff = + [|0..m-1|] + |> Array.map (fun i -> i,(i+1) % m) + |> Map.ofArray + startTimer "UpdateMap" + let buf = (buff, [|0..n-1|]) ||> Array.fold (fun buff i -> Map.add (i % m) i buff) + stopTimer "UpdateMap" + buf.Count |> ignore + + let updateDictBuffer() = + let dict = System.Collections.Generic.Dictionary() + [|0..m-1|] + |> Array.iter (fun i -> dict[i] <- (i+1) % m) + startTimer "UpdateDict" + let dict = (dict, [|0..n-1|]) ||> Array.fold (fun dict i -> + let d = System.Collections.Generic.Dictionary(dict) + d) + stopTimer "UpdateDict" + + + arrayBuffer() + arrayBuffer() + arrayBufferLookup() + arrayBufferLookup() + mutableArrayBuffer() + mutableArrayBuffer() + updateArrayBuffer() + updateArrayBuffer() + listBuffer() + listBuffer() + mapBuffer() + mapBuffer() + dictBuffer() + dictBuffer() + updateMapBuffer() + updateMapBuffer() + updateDictBuffer() + +//-----------------Code to record and print execution time statistics-------// + +let timeNowInMicroS() = + System.DateTime.Now.Ticks + |> (fun t -> t /10L) + +type Stats = { + Min: float + Max: float + Av: float + Num: float + } + +/// add time t to st +let addTimeToStats (t:float) (st:Stats) = + { + Min = min st.Min t + Max = max st.Max t + Av = (st.Av*st.Num + t)/(st.Num+1.) + Num = st.Num + 1. + } + +/// execution time stats indexed by name in recordExecutionStats +let mutable executionStats = Map [] + +/// Run (f arg) recording its time in executionStats under name. +/// NB - this will run f multiple times if needed to estimate average speed more accurately. +/// If an execution time of 5ms for this function is too long reduce timeLimit. +/// The multiple time execution will not work, and will give lower than real results, if +/// f is memoised. In that case set timeLimit to 0. for only one execution. +let recordExecutionTimeStats (name: string) (f: 'a -> 'b) (arg: 'a) : 'b = + let timeLimit = 0. // time in ms to execute f for. + let t1 = timeNowInMicroS() + let execTime() = float (timeNowInMicroS() - t1) / 1000. + let res = f arg // do f + let mutable iterations = 1 + while execTime() < timeLimit do // do f multiple times if it is fast to get more accurate speed statistics + iterations <- iterations + 1 + f arg |> ignore // do f again + let t = execTime() / float iterations + executionStats <- + Map.tryFind name executionStats + |> Option.map (addTimeToStats t) + |> Option.defaultValue {Min=t;Max=t;Av=t;Num=1.} + |> (fun st -> Map.add name st executionStats) + res + +/// print +let printStats() = + executionStats + |> Map.toList + |> List.iter (fun (name,st) -> + printfn "%s time: min=%.3fms max=%.3fms av=%.3fms samples:%d" name st.Min st.Max st.Av (int st.Num)) + executionStats <- Map [] // reset stats + + +/// returns absolute time in ms, works under both .Net and Fable +let getTimeMs() = +#if FABLE_COMPILER + Fable.Core.JS.Constructors.Date.now() +#else + let start = System.DateTime.UtcNow; + float start.Ticks / float 10000 +#endif + +let getInterval (startTime:float) = + getTimeMs() - startTime + +/// Return time taken by thunk() +/// Run thunk() as many times as is needed +/// for total elapsed time in ms to be > limitMs. +/// Return average time of all runs. +/// To minimise cache effects run thunk() once before +/// starting to time. +let getTimeOfInMs (limitMs: float) (thunk: Unit -> Unit) = + thunk() + let startT = getTimeMs() + let mutable i = 0 + while getInterval startT < limitMs do + i <- i+1 + thunk() + getInterval startT / float i + +type AggregatedData = { + PrintInterval: float + LastPrintTime: float + Counts: Map + Times: Map + MinVals: Map + MaxVals: Map +} + +/// controls how time intervals are collected and displayed +type InstrumentationControl = + | ImmediatePrint of Threshold: float * UpdateThreshold: float + | Aggregate of AggregatedData + | Off + +/// initialise instrumentation parameter for immediate time printing +let immediate threshold updateThreshold = + ImmediatePrint(threshold,updateThreshold) + +/// initialse instrumentation parameter for aggregate time printing +let aggregate(printInterval: float ) = + Aggregate { + PrintInterval = printInterval + LastPrintTime = Fable.Core.JS.Constructors.Date.now() + Times = Map.empty + MinVals = Map.empty + MaxVals = Map.empty + Counts = Map.empty + } + +/// Parameter that controls how recorded times are processed. +let mutable instrumentation: InstrumentationControl = + //aggregate 10000. // for aggregate printing every 10s + immediate 20. 50. // for immediate printing + // Off // for no printing + +/// print out the current aggregate of recorded times if this is requried. +/// Return initialised aggregate totals after print +let printAgg (agg: AggregatedData) = + let now = Fable.Core.JS.Constructors.Date.now() + let getData name = + let num = mapFindWithDef 0 name agg.Counts + let numF = float num + if num = 0 then + 0.,"" + else + let tot = (mapFindWithDef 0. name agg.Times) + tot, + $"%8.2f{tot/numF}%8.1f{mapFindWithDef 0. name agg.MaxVals}\ + %8.1f{mapFindWithDef 0. name agg.MinVals}%8.1f{tot} %s{name}" + + let intv = now - agg.LastPrintTime + if intv < agg.PrintInterval then + agg // do nothing + else + let head = sprintf "Interval times in ms after %.1fs\n Av Max Min Total Name\n" (intv / 1000.) + let timeLines = + (mapKeys agg.Counts) + |> Seq.map getData + |> Seq.filter (fun (tot,_) -> tot > 10.) + |> Seq.sortBy fst + |> Seq.map snd + |> String.concat "\n" + printfn "%s" (head + timeLines) + { agg with + LastPrintTime = now + Counts = Map.empty + MaxVals = Map.empty + MinVals = Map.empty + Times=Map.empty} + +/// process a new time interval updating the aggregated data for future printout +let updateAgg (name:string) (time: float) (agg: AggregatedData) = + { agg with + Counts = mapUpdateWithDef 0 ((+) 1) name agg.Counts + Times = mapUpdateWithDef 0. ((+) time) name agg.Times + MaxVals = mapUpdateWithDef 0. (max time) name agg.MaxVals + MinVals = mapUpdateWithDef 1.0E10 (min time) name agg.MinVals + } + + +/// According to current settings, process and/or print a named time interval. +/// the interval is between intervalStartTime passed as arg 2, and the time at +/// which this function is called (all times obtained using getTimeMs). +let instrumentTime (intervalName: string) (intervalStartTime: float) = + match instrumentation with + | Off -> () + | ImmediatePrint(threshold,updateThreshold) -> + let interval = getInterval intervalStartTime + let threshold = + if intervalName.StartsWith "update" + then updateThreshold + else threshold + if interval > threshold then + printfn "%s" $"{intervalName}: %.1f{interval}ms" + | Aggregate agg -> + let interval = getTimeMs() - intervalStartTime + let agg = updateAgg intervalName interval agg + let agg = printAgg agg + instrumentation <- Aggregate agg + + + + + +/// print out a time interval +let private printInterval name startTime = + instrumentTime name startTime + +/// This function with its first two args should be put in a pipe after the code to be timed. +/// it will return its piped input, with the side effect of recording the time delay in the +/// function. Parameter start must be defined at the start of the code to be timed using getTimeMs. +let instrumentInterval name startTime output = + printInterval name startTime + output + +/// Record the elapsed time taken in execution of (func arg). +/// Return the result from (func arg). +let instrumentFunctionCall name func arg = + let startTime = getTimeMs() + func arg + |> instrumentInterval name + + diff --git a/src/Renderer/Common/WidthInferer.fs b/src/Renderer/Common/WidthInferer.fs new file mode 100644 index 0000000..5ee226c --- /dev/null +++ b/src/Renderer/Common/WidthInferer.fs @@ -0,0 +1,650 @@ +(* + Function to perform bus width inference on a canvas +*) + +module BusWidthInferer + +open CommonTypes +open Helpers + +// 1. Initialise Map for all connections, to None +// (None means width not inferred yet). +// 2. Extract Input Components. +// 3. Starting from all those input components, run the inference process: +// a. Case: component has all information about connections connected to it. +// (for example, an input node or an and gate. They know they expect bits). +// - Get the width of the incoming wires +// - If there is any inconsistence, return the error +// - Set the width of the outgoing wires +// - follow the wires you just set and repeat the inference process on the +// new components. +// b. Case: component does not have all the information for computing the +// width of outgoing wires yet. +// (for example, a mergeBus components with only one bus connected) +// - return + + +let mapKeys (map:Map<'a,'b>) = map |> Map.toSeq |> Seq.map fst |> List.ofSeq +let mapValues (map:Map<'a,'b>) = map |> Map.toSeq |> Seq.map snd |> List.ofSeq +let mapItems (map:Map<'a,'b>) = map |> Map.toSeq |> List.ofSeq + + +/// Extract the port number of a component port. Port numbers on Components +/// should always be populated (while they are always None for ports in +/// Connections). +let private extractComponentPortNumber port = + match port.PortNumber with + | None -> failwithf "what? extractComponentPortNumber should always be called with component ports: %A" port + | Some pNumber -> pNumber + + +let private assertInputsSize + (inputs : Map) + (expected : int) + (comp : Component) = +#if ASSERTS + assertThat (inputs.Count = expected) + <| sprintf "assertInputsSize failed for: %A" comp +#else + () +#endif + + + + +let private getOutputPortId (comp : Component) (idx : int) : OutputPortId = + match List.tryFind (fun p -> extractComponentPortNumber p = idx) comp.OutputPorts with + | None -> failwithf "what? getOutputPortId called with inexistent port idx (%d): %A " idx comp + | Some port -> OutputPortId port.Id + +/// Extract the widths of the connections to input ports of a component. +/// The values are returned in the the passed order. E.g. if portNumbers is +/// [0, 1, 2], the returned value will be [width0, width1, width2]. +let rec private getWidthsForPorts + (inputs : Map) + (portNumbers : InputPortNumber list) + : (int option) list = + match portNumbers with + | [] -> [] + | portNumber :: portNumbers' -> + match inputs.TryFind portNumber with + | None -> failwithf "what? getWidthForPorts received a not extistent port: %A %A" portNumber inputs + | Some (Some (width, _)) -> width :: getWidthsForPorts inputs portNumbers' + | Some None -> None :: getWidthsForPorts inputs portNumbers' + +/// Extract the ConnectionId of the connection connected to a certain input +/// port. Fail if such connection does not exist. +let private getConnectionIdForPort + (inputs : Map) + (portNumber : InputPortNumber) + : ConnectionId = + match inputs.TryFind portNumber with + | None -> failwithf "what? getConnectionIdForPort received a not extistent port: %A %A" portNumber inputs + | Some None -> failwithf "what? getConnectionIdForPort called with an unconnected port: %A %A" portNumber inputs + | Some (Some (_, connId)) -> connId + +let private makeWidthInferErrorEqual expected actual connectionsAffected = Error { + Msg = sprintf "Wrong wire width. Target port expects a %d bit(s) signal, but source port produces a %d bit(s) signal." expected actual + ConnectionsAffected = connectionsAffected +} + +let private makeWidthInferErrorAtLeast atLeast actual connectionsAffected = Error { + Msg = sprintf "Wrong wire width. Target port expects a signal with at least %d bits, but source port produces a %d bit(s) signal." atLeast actual + ConnectionsAffected = connectionsAffected +} + + +/// Add to the map the extra (virtual) connections formed from each set of similarlky named bus labels. +/// each unconnected bus label input is virtually connected to the (single) connection +/// that drives the set +let addVirtualBusLabelConnections + (compIdToComp: Map) + (inputPortsToConnectionIds: Map) : Map = + + let comps = mapValues compIdToComp + + let inputPort0Id (comp:Component) = InputPortId comp.InputPorts[0].Id + + let labelGroups = + comps + |> List.filter (fun (comp:Component) -> comp.Type=IOLabel) + |> List.groupBy (fun comp -> comp.Label) + + let createVirtualMappings (compLst:Component list) (connId: ConnectionId): (InputPortId*ConnectionId) list= + compLst + |> List.map (fun comp -> inputPort0Id comp,connId) + + let extraLabelConns = + labelGroups + |> List.collect (fun (name, labComps) -> + labComps + |> List.tryPick (fun comp -> Map.tryFind (inputPort0Id comp) inputPortsToConnectionIds) + |> Option.map (createVirtualMappings labComps) + |> Option.defaultValue []) + + inputPortsToConnectionIds + |> Map.toSeq + |> Seq.append (extraLabelConns |> Seq.ofList) + |> Map.ofSeq + + +/// For width inference, because IOLabel components join nets, +/// the single allowed input connection to a set of labels must +/// be replicated as an virtual input to all in the width inferrer and +/// simulation logic +let private makeOutputPortsOfLabels (components: Component list) : Map= + components + |> List.filter (function | { Type=IOLabel} -> true; | _ -> false) + |> List.groupBy (fun c -> c.Label) + |> List.map (fun (label, lst) -> + label, lst + |> List.map (fun comp -> getOutputPortId comp 0)) + |> Map.ofList + + +/// Given a component and a set of input connection widths, check these inputs +/// widths are as expected and try to calculate the width of the outgoing +/// connections. +/// Components can produce outputs as soon as they have enough info (e.g. +/// gates can output width 1 straight away, PushToBusFirst can output n + 1 as +/// soon as it finds out n, and so on). This is possible because +/// setConnectionsWidth will make sure that we do not re-explore an already set +/// connection. This should allow partially connected components to still work +/// if they have already enough info. +let private calculateOutputPortsWidth + (comp : Component) + (outputPortsOfBusLabels: Map) + (inputConnectionsWidth : Map) + : Result, WidthInferError> = + let getConnectionIdForPort = + InputPortNumber >> (getConnectionIdForPort inputConnectionsWidth) + match comp.Type with + | ROM _ | RAM _ | AsyncROM _ -> + failwithf "What? Legacy RAM component types should never occur" + | Input width | Constant1(width,_,_) | Constant(width,_)-> + // Expects no inputs, and has an outgoing wire of the given width. + assertInputsSize inputConnectionsWidth 0 comp + Ok <| Map.empty.Add (getOutputPortId comp 0, width) + + | Output width | Viewer width -> + assertInputsSize inputConnectionsWidth 1 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0] with + | [None] -> Ok Map.empty + | [Some n] -> if n = width then Ok Map.empty // Output node has no outputs. + else + makeWidthInferErrorEqual width n [getConnectionIdForPort 0] + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | IOLabel-> + match getWidthsForPorts inputConnectionsWidth ([InputPortNumber 0]) with + | [None] -> Ok <| Map.empty + | [Some n] -> + let outs = outputPortsOfBusLabels[comp.Label] + outs + |> List.map (fun out -> out,n) + |> Map.ofList |> Ok + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | BusSelection(width, lsBitNum) -> + assertInputsSize inputConnectionsWidth 1 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0] with + | [Some n] when n < width + lsBitNum -> makeWidthInferErrorAtLeast (lsBitNum + n) n [getConnectionIdForPort 0] + | [None] | [Some _ ] -> Ok <| Map.empty.Add (getOutputPortId comp 0, width) + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | BusCompare(width, compareVal) -> + assertInputsSize inputConnectionsWidth 1 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0] with + | [Some n] when n <> width -> makeWidthInferErrorEqual width n [getConnectionIdForPort 0] + | [None] | [Some _ ] -> Ok <| Map.empty.Add (getOutputPortId comp 0, 1) + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + + | Not -> + assertInputsSize inputConnectionsWidth 1 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0] with + | [None] | [Some 1] -> Ok <| Map.empty.Add (getOutputPortId comp 0, 1) + | [Some n] -> makeWidthInferErrorEqual 1 n [getConnectionIdForPort 0] + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | And | Or | Xor | Nand | Nor | Xnor -> + assertInputsSize inputConnectionsWidth 2 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0; InputPortNumber 1] with + | [Some n; _] when n <> 1 -> makeWidthInferErrorEqual 1 n [getConnectionIdForPort 0] + | [_; Some n] when n <> 1 -> makeWidthInferErrorEqual 1 n [getConnectionIdForPort 1] + | [None; _] | [_; None] + | [Some 1; Some 1] -> Ok <| Map.empty.Add (getOutputPortId comp 0, 1) + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | Mux2 -> + // Mux also allowes buses. + assertInputsSize inputConnectionsWidth 3 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0; InputPortNumber 1; InputPortNumber 2] with + | [Some n; Some m; Some 1] when n = m -> Ok <| Map.empty.Add (getOutputPortId comp 0, n) + | [Some n; Some m; _] when n <> m -> + // Two inputs have different widths, this is not allowed. + Error { + Msg = sprintf "Wrong wire width. The two inputs to a multiplexer are expected to have the same width, but top input has %d bits and bottom input has %d bits." n m + ConnectionsAffected = [getConnectionIdForPort 0; getConnectionIdForPort 1] + } + | [_; _; Some n] when n <> 1 -> makeWidthInferErrorEqual 1 n [getConnectionIdForPort 2] + | [Some n; None; _] + | [None; Some n; _] -> Ok <| Map.empty.Add (getOutputPortId comp 0, n) + | [_; _; _] -> Ok Map.empty // Keep on waiting. + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | Demux2 -> + // Demux also allowes buses. + assertInputsSize inputConnectionsWidth 2 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0; InputPortNumber 1] with + | [Some n; Some 1] | [Some n; None] -> + let out = Map.empty.Add (getOutputPortId comp 0, n) + let out = out.Add (getOutputPortId comp 1, n) + Ok out + | [_; Some n] when n <> 1 -> makeWidthInferErrorEqual 1 n [getConnectionIdForPort 1] + | [_; _] -> Ok Map.empty // Keep on waiting. + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | NbitsAdder numberOfBits -> + assertInputsSize inputConnectionsWidth 3 comp + let okOutMap = + let out = Map.empty.Add (getOutputPortId comp 0, numberOfBits) + let out = out.Add (getOutputPortId comp 1, 1) + Ok out + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0; InputPortNumber 1; InputPortNumber 2] with + | [Some n; _; _] when n <> 1 -> makeWidthInferErrorEqual 1 n [getConnectionIdForPort 0] + | [_; Some n; _] when n <> numberOfBits -> makeWidthInferErrorEqual numberOfBits n [getConnectionIdForPort 1] + | [_; _; Some n] when n <> numberOfBits -> makeWidthInferErrorEqual numberOfBits n [getConnectionIdForPort 2] + | [_; _; _] -> okOutMap + | x -> failwithf "what? Impossible case (%A) in calculateOutputPortsWidth for: %A" x comp.Type + | NbitsXor numberOfBits -> + assertInputsSize inputConnectionsWidth 2 comp + let okOutMap = + let out = Map.empty.Add (getOutputPortId comp 0, numberOfBits) + Ok out + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0; InputPortNumber 1] with + | [Some n; _] when n <> numberOfBits -> makeWidthInferErrorEqual 1 n [getConnectionIdForPort 0] + | [_; Some n] when n <> numberOfBits -> makeWidthInferErrorEqual numberOfBits n [getConnectionIdForPort 1] + | [_; _] -> okOutMap + | x -> failwithf "what? Impossible case (%A) in calculateOutputPortsWidth for: %A" x comp.Type + | Decode4 -> + assertInputsSize inputConnectionsWidth 2 comp + let okOutMap = + [0..3] + |> List.map (fun n -> getOutputPortId comp n, 1) + |> Map.ofList + |> Ok + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0; InputPortNumber 1] with + | [Some 2; Some 1] -> okOutMap + | [Some n; _] when n <> 2 -> makeWidthInferErrorEqual 2 n [getConnectionIdForPort 0] + | [_; Some n] when n <> 1 -> makeWidthInferErrorEqual 1 n [getConnectionIdForPort 1] + | [_; _] -> okOutMap + | x -> failwithf "what? Impossible case (%A) in calculateOutputPortsWidth for: %A" x comp.Type + | Custom custom -> + assertInputsSize inputConnectionsWidth custom.InputLabels.Length comp + let inputWidths = + [0..custom.InputLabels.Length - 1] + |> List.map InputPortNumber + |> getWidthsForPorts inputConnectionsWidth + // Make sure that input Widths match what expected. + let maybeError = + (inputWidths, custom.InputLabels) + ||> List.mapi2 (fun idx actual (_, expected) -> + match actual with + | None -> None // Cannot determine if it is ok yet. + | Some w when w = expected -> None // No error. + | Some w -> Some <| makeWidthInferErrorEqual expected w [getConnectionIdForPort idx] + ) + match List.tryFind (fun el -> el <> None) maybeError with + | Some (Some err) -> err + | None -> custom.OutputLabels + |> List.mapi (fun idx (_, w) -> getOutputPortId comp idx, w) + |> Map.ofList |> Ok + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | MergeWires -> + assertInputsSize inputConnectionsWidth 2 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0; InputPortNumber 1] with + | [Some n; _] when n < 1 -> makeWidthInferErrorAtLeast 1 n [getConnectionIdForPort 0] + | [_; Some m] when m < 1 -> makeWidthInferErrorAtLeast 1 m [getConnectionIdForPort 1] + | [None; _] | [_; None] -> Ok Map.empty // Keep on waiting. + | [Some n; Some m] -> Ok <| Map.empty.Add (getOutputPortId comp 0, n + m) + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | SplitWire topWireWidth -> + assertInputsSize inputConnectionsWidth 1 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0] with + | [None] -> Ok Map.empty // Keep on waiting. + | [Some n] when n < topWireWidth + 1 -> makeWidthInferErrorAtLeast (topWireWidth + 1) n [getConnectionIdForPort 0] + | [Some n] -> + let out = Map.empty.Add (getOutputPortId comp 0, topWireWidth) + let out = out.Add (getOutputPortId comp 1, n - topWireWidth) + Ok out + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | DFF -> + assertInputsSize inputConnectionsWidth 1 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0] with + | [None] | [Some 1] -> Ok <| Map.empty.Add (getOutputPortId comp 0, 1) + | [Some n] -> makeWidthInferErrorEqual 1 n [getConnectionIdForPort 0] + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | DFFE -> + assertInputsSize inputConnectionsWidth 2 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0; InputPortNumber 1] with + | [None; None] | [Some 1; None] | [None; Some 1] | [Some 1; Some 1] -> + Ok <| Map.empty.Add (getOutputPortId comp 0, 1) + | [Some n; _] when n <> 1 -> makeWidthInferErrorEqual 1 n [getConnectionIdForPort 0] + | [_; Some n] when n <> 1 -> makeWidthInferErrorEqual 1 n [getConnectionIdForPort 1] + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | Register width -> + assertInputsSize inputConnectionsWidth 1 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0] with + | [None] -> Ok <| Map.empty.Add (getOutputPortId comp 0, width) + | [Some n] when n = width -> Ok <| Map.empty.Add (getOutputPortId comp 0, width) + | [Some n] when n <> width -> makeWidthInferErrorEqual width n [getConnectionIdForPort 0] + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | RegisterE width -> + assertInputsSize inputConnectionsWidth 2 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0; InputPortNumber 1] with + | [Some n; Some 1] when n = width -> Ok <| Map.empty.Add (getOutputPortId comp 0, width) + | [Some n; _] when n <> width -> makeWidthInferErrorEqual width n [getConnectionIdForPort 0] + | [_; Some n] when n <> 1 -> makeWidthInferErrorEqual 1 n [getConnectionIdForPort 1] + | [_; _] -> Ok <| Map.empty.Add (getOutputPortId comp 0, width) + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | AsyncROM1 mem | ROM1 mem -> + assertInputsSize inputConnectionsWidth 1 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0] with + | [None] -> Ok <| Map.empty.Add (getOutputPortId comp 0, mem.WordWidth) + | [Some aw] when aw = mem.AddressWidth -> + Ok <| Map.empty.Add (getOutputPortId comp 0, mem.WordWidth) + | [Some aw] when aw <> mem.AddressWidth -> + makeWidthInferErrorEqual mem.AddressWidth aw [getConnectionIdForPort 0] + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + | RAM1 mem | AsyncRAM1 mem-> + assertInputsSize inputConnectionsWidth 3 comp + match getWidthsForPorts inputConnectionsWidth [InputPortNumber 0; InputPortNumber 1; InputPortNumber 2] with + | [Some addr; Some datain; Some write] when addr = mem.AddressWidth && + datain = mem.WordWidth && + write = 1 -> + Ok <| Map.empty.Add (getOutputPortId comp 0, mem.WordWidth) + | [Some addr; _; _] when addr <> mem.AddressWidth -> + makeWidthInferErrorEqual mem.AddressWidth addr [getConnectionIdForPort 0] + | [_; Some datain; _] when datain <> mem.WordWidth -> + makeWidthInferErrorEqual mem.WordWidth datain [getConnectionIdForPort 1] + | [_; _; Some write;] when write <> 1 -> + makeWidthInferErrorEqual 1 write [getConnectionIdForPort 2] + | [_; _; _] -> Ok <| Map.empty.Add (getOutputPortId comp 0, mem.WordWidth) + | _ -> failwithf "what? Impossible case in calculateOutputPortsWidth for: %A" comp.Type + +/// Find the connection connected to an input port. Return None if no such +/// connection exists. +let private findConnectionToInputPort + (inputPortIdsToConnectionIds : Map) + (portId : InputPortId) + : ConnectionId option = + inputPortIdsToConnectionIds.TryFind portId + +/// Find all the connections connected to an output port. +let private findConnectionsFromOutputPort + (outputPortIdsToConnections : Map) + (portId : OutputPortId) + : (Connection list) option = + outputPortIdsToConnections.TryFind portId + +/// Lookup the width of a connection in the connectionsWidth map or fail. +let getConnectionWidth + (connectionsWidth : ConnectionsWidth) + (connId : ConnectionId) + : int option = + match connectionsWidth.TryFind connId with + | None -> failwithf "what? getConnectionWidth received inexistent connectionId: %A" connId + | Some width -> width + +/// For each input port on a given component, obtain the width of the wire +/// connecting to it, and the ConnectionId of such wire. If there is no wire +/// connecting to the port, or the wire width is unknown, return None. +let private getInputPortsConnectionsWidth + (connectionsWidth : ConnectionsWidth) + (currNode : Component) + (inputPortIdsToConnectionIds : Map) + : Map = + currNode.InputPorts + |> List.map (fun inputPort -> + InputPortId inputPort.Id + |> findConnectionToInputPort inputPortIdsToConnectionIds + |> function + | Some connId -> + // If some connection is present, try to etract is width. + InputPortNumber <| extractComponentPortNumber inputPort, + Some (getConnectionWidth connectionsWidth connId, connId) + | None -> + // If no connection is present, just use None. + InputPortNumber <| extractComponentPortNumber inputPort, + None + ) + |> Map.ofList + +let private setConnectionWidth + (connectionId : ConnectionId) + (connectionWidth : int) + (connectionsWidth : ConnectionsWidth) = + connectionsWidth.Add (connectionId, Some connectionWidth) + +/// Set the width of a bunch of connections, and return the updated +/// connectionsWidth together with the list of connections that have had their +/// width value updated. +/// If the width for a connection is already set: +/// - if the value we are going to set is identical to the already set value: +/// connection already visited (loop). Do not return the connection. +/// - if the value is different, return an error. +let private setConnectionsWidth + (connections : Connection list) + (connWidth : int) + (connectionsWidth : ConnectionsWidth) + : Result = + (Ok (connectionsWidth, []), connections) + ||> List.fold (fun res conn -> + res |> Result.bind (fun (connectionsWidth, connectionsToReturn) -> + let connId = ConnectionId conn.Id + match getConnectionWidth connectionsWidth connId with + | None -> + // Width for the connection was never set. Set it and return + // the connection. + Ok (setConnectionWidth connId connWidth connectionsWidth, + conn :: connectionsToReturn) + | Some oldWidth when oldWidth = connWidth -> + // Width for the connection is already set. The old width + // matches the current width. Do not return the connection. + Ok (connectionsWidth, connectionsToReturn) + | Some oldWidth when oldWidth <> connWidth -> + // Width for the connection is already set, but the old width + // does not match the current width. + Error { + Msg = sprintf "Wire has been inferred to have two different widths: %d and %d. This is probably due to an error such as a combinatorial loop." oldWidth connWidth + ConnectionsAffected = [connId] + } + | _ -> failwithf "what? Impossible case in setConnectionsWidth." + ) + ) + +let private getComponentFromId + (compId : ComponentId) + (compIdsToComps : Map) + : Component = + match compIdsToComps.TryFind compId with + | None -> failwithf "what? getComponentFromId called with invalid componentId: %A" compId + | Some comp -> comp + +/// Given a node, try to infer the width of its outgoing connections, and +/// possibly recur on the nodes targeted by those connections. +let rec private infer + // Static maps. Necessary for fast lookups. + (( + (inputPortIdsToConnectionIds : Map), + (outputPortIdsToConnections : Map), + (compIdsToComps : Map), + (outputPortsOfBusLabels: Map) + ) as staticMaps) + (currNode : Component) + (connectionsWidth : ConnectionsWidth) + : Result = + let iterateChildren outgoingConnections connectionsWidth = + let children = + outgoingConnections + |> List.map (fun conn -> getComponentFromId (ComponentId conn.Target.HostId) compIdsToComps) + (Ok connectionsWidth, children) + ||> List.fold (fun connectionsWidthRes child -> + connectionsWidthRes + |> Result.bind (fun connectionsWidth -> + infer staticMaps child connectionsWidth + ) + ) + + getInputPortsConnectionsWidth connectionsWidth currNode inputPortIdsToConnectionIds + |> calculateOutputPortsWidth currNode outputPortsOfBusLabels + |> Result.bind (fun outputPortsWidths -> + // For each output in the map: + // - Get all connections that are connected to that port. + // - Set the width of the connection to the inferred value. If the + // connection has already been inferred, it must be because of a loop. + // If the value is different, return error. If the value is the same, + // just ignore the connection otherwise you would get stuck in the + // loop. + // - For the non-ingored connections, take recur infer on the + // Target.HostId. + (Ok connectionsWidth, outputPortsWidths) + ||> Map.fold (fun connectionsWidthRes outPortId connWidth -> + connectionsWidthRes + |> Result.bind (fun connectionsWidth -> + match findConnectionsFromOutputPort + outputPortIdsToConnections outPortId with + | None -> + // Unconnected port. Do not recur. + Ok connectionsWidth + | Some outgoingConnections -> + setConnectionsWidth outgoingConnections connWidth connectionsWidth + |> Result.bind (fun (connectionsWidth, updatedConnections) -> + iterateChildren updatedConnections connectionsWidth + ) + ) + ) + ) + +let private initialiseConnectionsWidth connections : ConnectionsWidth = + connections + |> List.map (fun (conn:Connection) -> ConnectionId conn.Id, None) + |> Map.ofList + +let private getAllInputNodes components : Component list = + components |> List.filter (fun comp -> match comp.Type with | Input _ -> true | _ -> false) + +/// For each connected Input port, map the connection that is connected to it. +/// Fail if there are multiple connections connected to the same input port. +/// Such scenario would mean that a wire is driven by multiple components. +let private mapInputPortIdsToConnectionIds + (connections : Connection list) + : Result, WidthInferError> = + (Ok Map.empty, connections) + ||> List.fold (fun mapRes conn -> + mapRes |> Result.bind (fun map -> + let inputPortId = InputPortId conn.Target.Id + let connId = ConnectionId conn.Id + match map.TryFind inputPortId with + | None -> Ok <| map.Add (inputPortId, connId) + | Some otherConnId -> Error { + Msg = "A wire must have precisely one driving component. If you want to merge two wires together, use a MergeWires component." + ConnectionsAffected = [connId; otherConnId] + } + ) + ) + +let private mapComponentIdsToComponents + (components : Component list) + : Map = + components + |> List.map (fun comp -> ComponentId comp.Id, comp) + |> Map.ofList + + + +/// return all Connections connected to an output port +let private mapOutputPortIdsToConnections + (connections : Connection list) + : Map = + connections + |> List.groupBy (fun conn -> OutputPortId conn.Source.Id) + |> Map.ofList + +/// Here each input port has asociated with the connection that drives it. +/// Normally that is the connection connected to the port. +/// However BusLabels are a special case because a set of similarly named labels +/// have outputs all connected together and driven by the single connection that goes to +/// one of the BusLabel inputs (there must be exactly one such). +/// In this function any input driven by a connection from a BusLabel output gets associated +/// with the Buslable set input connection, allowing correct width inference. +let private mapInputPortIdsToVirtualConnectionIds (conns: Connection list) (comps:Component list) = + let mapPortIdToConnId = mapInputPortIdsToConnectionIds conns + + let filteredComps = + comps + |> List.filter (fun (comp:Component) -> comp.Type=IOLabel) + + let targetPortIdToConId = + conns + |> List.map (fun conn -> InputPortId conn.Target.Id, ConnectionId conn.Id) + |> Map.ofList + + let getBusLabelConns (compLst: Component list) = + compLst + |> List.collect (fun comp -> + Map.tryFind (InputPortId comp.InputPorts[0].Id) targetPortIdToConId + |> function | None -> [] | Some cId -> [cId]) + + let mapLabels = + filteredComps + |> List.groupBy (fun comp -> comp.Label) + |> List.map (fun (lab,compLst) -> + match getBusLabelConns compLst with + | [cId] -> List.map (fun comp -> (InputPortId comp.InputPorts[0].Id, cId)) compLst |> Ok + | h when h.Length <> 1 -> Error { + Msg = sprintf "A Labelled wire must no more than one driving component. '%s' labels have %d drivers" lab h.Length + ConnectionsAffected = h + } + | _ -> Ok [] + ) + |> tryFindError + |> Result.map (List.concat >> Map.ofList) + + match mapLabels, mapPortIdToConnId with + | _, Error e | Error e, _ -> Error e + | Ok mapL, Ok map -> + comps + |> List.collect (fun comp -> comp.InputPorts) + |> List.map (fun p -> InputPortId p.Id) + |> List.collect ( fun pId -> + match Map.tryFind pId map, Map.tryFind pId mapL with + | None, None -> [] + | _, Some conn + | Some conn, None -> [pId, conn]) + |> Map.ofList + |> Ok + + +/// Return Inferred width of all connections or an error. +/// Width inference is done without mutable state. +/// It is to be run when component widths or circuit is changed, +/// Note that it does not matter (except for performance) if it is run too many times. +let inferConnectionsWidth + ((comps,conns) : CanvasState) + : Result = + let start = TimeHelpers.getTimeMs() + let connectionsWidth = initialiseConnectionsWidth conns // start with all as None + match mapInputPortIdsToVirtualConnectionIds conns comps with + | Error e -> Error e + | Ok inputPortIdsToVirtualConnectionIds' -> + let staticMapComponentIdsToComponents = mapComponentIdsToComponents comps + let staticMaps = ( + inputPortIdsToVirtualConnectionIds', + mapOutputPortIdsToConnections conns, + staticMapComponentIdsToComponents, + makeOutputPortsOfLabels comps + ) + // If this is too slow, one could start the process only from input and constant + // components. To do so, pass the (getAllInputNodes components) instead + // of components. (But this would not work for ckts with no inputs or constants). + (Ok connectionsWidth, comps) + ||> List.fold (fun connectionsWidthRes inputNode -> + connectionsWidthRes |> Result.bind (fun connectionsWidth -> + infer staticMaps inputNode connectionsWidth + ) + ) + |> TimeHelpers.instrumentInterval "widthInference" start diff --git a/src/Renderer/DrawBlock/BusWire.fs b/src/Renderer/DrawBlock/BusWire.fs new file mode 100644 index 0000000..30aa103 --- /dev/null +++ b/src/Renderer/DrawBlock/BusWire.fs @@ -0,0 +1,1553 @@ +(* +This module implements wires between symbol ports. Wires can be autorouted, or manually routed by dragging segments. +Moving symbols causes the corresponding wires to move. +Wires are read and written from Issie as lists of wire vertices, whatever teh internal representation is. +*) + + +module BusWire + +open CommonTypes +open Fable.React +open Fable.React.Props +open Elmish +open DrawHelpers + +//Static Vars +let minSegLen = 5. + +//------------------------------------------------------------------------// +//------------------------------BusWire Types-----------------------------// +//------------------------------------------------------------------------// + +/// +type Orientation = Horizontal | Vertical + +/// +type SnapPosition = High | Mid | Low + +/// +type Segment = + { + Id : SegmentId + Index: int + Start: XYPos + End: XYPos + Dir: Orientation + HostId: ConnectionId + /// List of x-coordinate values of segment jumps. Only used on horizontal segments. + JumpCoordinateList: list + Draggable : bool + } + + + +/// +type Wire = + { + Id: ConnectionId + InputPort: InputPortId + OutputPort: OutputPortId + Color: HighLightColor + Width: int + Segments: list + } + + with static member stickLength = 16.0 + + + +/// +type Model = + { + Symbol: Symbol.Model + WX: Map + FromVerticalToHorizontalSegmentIntersections: Map> + FromHorizontalToVerticalSegmentIntersections: Map> + CopiedWX: Map + SelectedSegment: SegmentId + LastMousePos: XYPos + ErrorWires: list + Notifications: Option + } + +//----------------------------Message Type-----------------------------------// + +/// +type Msg = + | Symbol of Symbol.Msg + | AddWire of (InputPortId * OutputPortId) + | BusWidths + | CopyWires of list + | DeleteWires of list + | SelectWires of list + | UpdateWires of list * XYPos + | DragWire of ConnectionId * MouseT + | ColorWires of list * HighLightColor + | ErrorWires of list + | ResetJumps of list + | MakeJumps of list + | ResetModel // For Issie Integration + | LoadConnections of list // For Issie Integration + +//-------------------------Debugging functions---------------------------------// +let ppSId (sId:SegmentId) = + sId + |> (fun (SegmentId x) -> x) + |> Seq.toList + |> (fun chars -> chars[0..2]) + |> List.map string + |> String.concat "" + +let ppS (seg:Segment) = + sprintf $"|{seg.Index}:{ppSId seg.Id}|" + +let ppWId (wId:ConnectionId) = + wId + |> (fun (ConnectionId x) -> x) + |> Seq.toList + |> (fun chars -> chars[0..2]) + |> List.map string + |> String.concat "" + +let ppMaps (model:Model) = + let mhv = model.FromHorizontalToVerticalSegmentIntersections + let mvh = model.FromVerticalToHorizontalSegmentIntersections + let m1 = + mhv + |> Map.toList + |> List.map (fun (sid,lst) -> + List.map (snd >> ppSId) lst + |> (fun segs -> sprintf $"""<{ppSId sid}->[{String.concat ";" segs}]>""")) + |> String.concat ";\n" + let m2 = + mvh + |> Map.toList + |> List.map (fun (sid,lst) -> + List.map (snd >> ppSId) lst + |> (fun segs -> sprintf $"""<{ppSId sid}->[{String.concat ";" segs}]>""")) + |> String.concat ";\n" + let jumps = + model.WX + |> Map.toList + |> List.map (fun (wId,w) -> + sprintf $"Wire: {w.Segments |> List.collect (fun seg -> seg.JumpCoordinateList |> List.map (fun (f, sid) -> ppSId sid))}") + + printfn $"\n------------------\nMapHV:\n {m1} \n MapVH\n{m2} \nJumps:\n {jumps}\n------------------\n" + + + +let ppSeg seg (model: Model) = + let cid,sid = seg + let wire = model.WX[cid] + let sg = List.find (fun (s:Segment) -> s.Id = sid ) wire.Segments + let pxy (xy: XYPos) = sprintf $"{(xy.X,xy.Y)}" + sprintf $"""[{ppSId sg.Id}: {pxy sg.Start}->{pxy sg.End}]-{match sg.Dir with | Vertical -> "V" | _ -> "H"}-{sg.Index}""" + +let pp segs (model: Model)= + segs + |> List.map ( fun seg -> + let cid,sid = seg + let wire = model.WX[cid] + match List.tryFind (fun (s:Segment) -> s.Id = sid ) wire.Segments with + | Some sg -> + let pxy (xy: XYPos) = sprintf $"{(xy.X,xy.Y)}" + sprintf $"""[{pxy sg.Start}->{pxy sg.End}]-{match sg.Dir with | Vertical -> "V" | _ -> "H"}-{sg.Index}""" + | None -> "XX") + |> String.concat ";" + +//-------------------------------Implementation code----------------------------// + +/// Wire to Connection +let segmentsToVertices (segList:Segment list) = + let firstCoord = (segList[0].Start.X, segList[0].Start.Y) + let verticesExceptFirst = List.mapi (fun i seg -> (seg.End.X,seg.End.Y)) segList + [firstCoord] @ verticesExceptFirst + + +/// Given the coordinates of two port locations that correspond +/// to the endpoints of a wire, this function returns a list of +/// wire vertices +let makeInitialWireVerticesList (portCoords : XYPos * XYPos) = + let xs, ys, Xt, Yt = snd(portCoords).X, snd(portCoords).Y, fst(portCoords).X, fst(portCoords).Y + + // adjust length of segments 0 and 6 - the sticks - so that when two ports are aligned and close you still get left-to-right routing. + let adjStick = + let d = List.max [ abs (xs - Xt) ; abs (ys - Yt) ; Wire.stickLength / 4.0 ] + if (Xt - xs > 0.0) then + min d (Wire.stickLength / 2.0) + else + Wire.stickLength / 2.0 + + // the simple case of a wire travelling from output to input in a left-to-right (positive X) direction + let leftToRight = + [ + {X = xs; Y = ys}; + {X = xs+adjStick; Y = ys}; + {X = xs+adjStick; Y = ys}; + {X = (xs+Xt)/2.0; Y = ys}; + {X = (xs+Xt)/2.0; Y = Yt}; + {X = Xt-adjStick; Y = Yt} + {X = Xt-adjStick; Y = Yt} + {X = Xt; Y = Yt} + ] + // the case of a wire travelling from output to input in a right-to-left (negative X) direction. Thus must bend back on itself. + let rightToLeft = + [ + {X = xs; Y = ys} + {X = xs+Wire.stickLength; Y = ys} + {X = xs+Wire.stickLength; Y = ys} + {X = xs+Wire.stickLength; Y = (ys+Yt)/2.0} + {X = Xt-Wire.stickLength; Y = (ys+Yt)/2.0} + {X = Xt-Wire.stickLength; Y = Yt} + {X = Xt-Wire.stickLength; Y = Yt} + {X = Xt; Y = Yt} + ] + + // the special case of a wire travelling right-to-left where the two ends are vertically almost identical. + // In this case we ad an offset to the main horizontal segment so it is more visible and can be easily re-routed manually. + let rightToLeftHorizontal = + [ + {X = xs; Y = ys} + {X = xs+Wire.stickLength; Y = ys} + {X = xs+Wire.stickLength; Y = ys} + {X = xs+Wire.stickLength; Y = ys + Wire.stickLength} + {X = Xt-Wire.stickLength; Y = ys + Wire.stickLength} + {X = Xt-Wire.stickLength; Y = Yt} + {X = Xt-Wire.stickLength; Y = Yt} + {X = Xt; Y = Yt} + ] + + if Xt - xs >= adjStick * 2.0 then + leftToRight, true + elif abs (ys - Yt) < 4.0 then + rightToLeftHorizontal, false + else + rightToLeft, false + +let inferDirectionfromVertices (xyVerticesList: XYPos list) = + if xyVerticesList.Length <> 8 then + failwithf $"Can't perform connection type inference except with 8 vertices: here given {xyVerticesList.Length} vertices" + let getDir (vs:XYPos) (ve:XYPos) = + match sign ((abs vs.X - abs ve.X)*(abs vs.X - abs ve.X) - (abs vs.Y - abs ve.Y)*(abs vs.Y - abs ve.Y)) with + | 1 -> Some Horizontal + | -1 -> Some Vertical + | _ -> None + let midS, midE = xyVerticesList[3], xyVerticesList[4] + let first,last = xyVerticesList[1], xyVerticesList[5] + let xDelta = abs last.X - abs first.X + match getDir midS midE, abs xDelta > 20.0, xDelta > 0.0 with + | Some Horizontal, _, _ when midE.X < midS.X -> Some Horizontal + | Some Vertical, _, _ -> Some Vertical + | _, true, true -> Some Vertical + | _, true, false -> Some Horizontal + | _, false, _ -> None + +/// this turns a list of vertices into a list of segments +let xyVerticesToSegments connId (isLeftToRight: bool) (xyVerticesList: XYPos list) = + + let dirs = + match isLeftToRight with + | true -> + // for 5 adjustable segments left-to-right + [Horizontal;Vertical;Horizontal;Vertical;Horizontal;Vertical;Horizontal] + | false -> + // for 3 adjustale segments right-to-left + [Horizontal;Horizontal;Vertical;Horizontal;Vertical;Horizontal;Horizontal] + + List.pairwise xyVerticesList + |> List.mapi ( + fun i ({X=startX; Y=startY},{X=endX; Y=endY}) -> + { + Id = SegmentId(JSHelpers.uuid()) + Index = i + Start = {X=startX;Y=startY}; + End = {X=endX;Y=endY}; + Dir = dirs[i] + HostId = connId; + JumpCoordinateList = []; + Draggable = + match i with + | 1 | 5 -> isLeftToRight + | 0 | 6 -> false + | _ -> true + }) + +/// Convert a (possibly legacy) issie Connection stored as a list of vertices to Wire +let issieVerticesToSegments + (connId) + (verticesList: list) = + let xyVerticesList = + verticesList + |> List.map (fun (x,y) -> {X=x;Y=y}) + + let makeSegmentsFromVertices (xyList: XYPos list) = + makeInitialWireVerticesList (xyList[0], xyList[xyList.Length - 1]) + |> (fun (vl, isLeftToRight) -> xyVerticesToSegments connId isLeftToRight vl) + + + // segments lists must must be length 7, in case legacy vertex list does not conform check this + // if there are problems reroute + //vertex lists are one element longer than segment lists + if xyVerticesList.Length <> 8 then + makeSegmentsFromVertices xyVerticesList + else + match inferDirectionfromVertices xyVerticesList with + | Some Vertical -> + printfn "Converting vertical" + xyVerticesToSegments connId true xyVerticesList + | Some Horizontal -> + printfn "Converting horizontal" + xyVerticesToSegments connId false xyVerticesList + | _ -> + // can't work out what vertices are, so default to auto-routing + printfn "Converting unknown" + makeSegmentsFromVertices xyVerticesList + + + +//----------------------interface to Issie-----------------------// +/// This function is given a ConnectionId and it +/// converts the corresponding BusWire.Wire type to a +/// Connection type, offering an interface +/// between our implementation and Issie. +let extractConnection (wModel : Model) (cId : ConnectionId) : Connection = + let conn = wModel.WX[cId] + let ConnectionId strId, InputPortId strInputPort, OutputPortId strOutputPort = conn.Id, conn.InputPort, conn.OutputPort + { + Id = strId + Source = { Symbol.getPort wModel.Symbol strOutputPort with PortNumber = None } // None for connections + Target = { Symbol.getPort wModel.Symbol strInputPort with PortNumber = None } // None for connections + Vertices = segmentsToVertices conn.Segments + } // We don't use vertices + +/// This function is given a list of ConnectionId and it +/// converts the corresponding BusWire.Wire(s) to a +/// list of Connectio, offering an interface +/// between our implementation and Issie. +let extractConnections (wModel : Model) : list = + wModel.WX + |> Map.toList + |> List.map (fun (key, _) -> extractConnection wModel key) + +/// Given three points p, q, r, the function returns true if +/// point q lies on line segment 'pr'. Otherwise it returns false. +let onSegment (p : XYPos) (q : XYPos) (r : XYPos) : bool = + ( + (q.X <= max (p.X) (r.X)) && + (q.X >= min (p.X) (r.X)) && + (q.Y <= max (p.Y) (r.Y)) && + (q.Y >= min (p.Y) (r.Y)) + ) + +/// Given three points p, q, r, the function returns: +/// - 0 if p, q and r are colinear; +/// - 1 if the path that you must follow when you start at p, you visit q and you end at r, is a CLOCKWISE path; +/// - 2 if the path that you must follow when you start at p, you visit q and you end at r, is a COUNTERCLOCKWISE path. +let orientation (p : XYPos) (q : XYPos) (r : XYPos) : int = + let result = (q.Y - p.Y) * (r.X - q.X) - (q.X - p.X) * (r.Y - q.Y) + + if (result = 0.0) then 0 // colinear + elif (result > 0.0) then 1 // clockwise + else 2 //counterclockwise + +///Returns the abs of an XYPos object +let getAbsXY (pos : XYPos) = + {X = abs pos.X; Y = abs pos.Y} + +/// Given two sets of two points: (p1, q1) and (p2, q2) +/// that define two segments, the function returns true +/// if these two segments intersect and false otherwise. +let segmentIntersectsSegment ((p1, q1) : (XYPos * XYPos)) ((p2, q2) : (XYPos * XYPos)) : bool = + // this is a terrible implementation + // determining intersection should be done by finding intersection point and comparing with coords + // since segments are always horizontal or vertical that is pretty easy. + // in addition the way that coordinates can be positive or negative but are absed when used is appalling + // the manual or auto route info per segment should be a separate field in Segmnet, not encoded in the sign of the coordinates + // that is needed when writing out or reading from Issie, but the write/read process can easily translate to a sane internal data structure in the draw blokc model + let p1,q1,p2,q2= getAbsXY p1, getAbsXY q1, getAbsXY p2, getAbsXY q2 + // Find the four orientations needed for general and + // special cases + let o1 = orientation (p1) (q1) (p2) + let o2 = orientation (p1) (q1) (q2) + let o3 = orientation (p2) (q2) (p1) + let o4 = orientation (p2) (q2) (q1) + + // General case + if (o1 <> o2 && o3 <> o4) + then true + + // Special Cases + // p1, q1 and p2 are colinear and p2 lies on segment p1q1 + elif (o1 = 0 && onSegment (p1) (p2) (q1)) + then true + + // p1, q1 and q2 are colinear and q2 lies on segment p1q1 + elif (o2 = 0 && onSegment (p1) (q2) (q1)) + then true + + // p2, q2 and p1 are colinear and p1 lies on segment p2q2 + elif (o3 = 0 && onSegment (p2) (p1) (q2)) + then true + + // p2, q2 and q1 are colinear and q1 lies on segment p2q2 + elif (o4 = 0 && onSegment (p2) (q1) (q2)) + then true + else false + + + +///Returns a segment with positive Start and End coordinates +let makeSegPos (seg : Segment) = + {seg with + Start = getAbsXY seg.Start + End = getAbsXY seg.End } + +/// Given two coordinates, this function returns the euclidean +/// distance between them. +let distanceBetweenTwoPoints (pos1 : XYPos) (pos2 : XYPos) : float = + sqrt ( (pos1.X - pos2.X)*(pos1.X - pos2.X) + (pos1.Y - pos2.Y)*(pos1.Y - pos2.Y) ) + + +/// Given the coordinates of two port locations that correspond +/// to the endpoints of a wire, this function returns a list of +/// Segment(s). +let makeInitialSegmentsList (hostId : ConnectionId) (portCoords : XYPos * XYPos) : list = + let xyPairs, isLeftToRight = makeInitialWireVerticesList portCoords + xyPairs + |> xyVerticesToSegments hostId isLeftToRight + + +/// This function renders the given +/// segment (i.e. creates a ReactElement +/// using the data stored inside it), +/// using the colour and width properties given. +let renderSegment (segment : Segment) (colour : string) (width : string) : ReactElement = + let wOpt = EEExtensions.String.tryParseWith System.Int32.TryParse width + let renderWidth = + match wOpt with + | Some 1 -> 1.5 + | Some n when n < int "8" -> 2.5 + | _ -> 3.5 + let halfWidth = (renderWidth/2.0) - (0.75) + let lineParameters = { defaultLine with Stroke = colour; StrokeWidth = string renderWidth } + let circleParameters = { defaultCircle with R = halfWidth; Stroke = colour; Fill = colour } + + if segment.Dir = Horizontal then + let pathParameters = { defaultPath with Stroke = colour; StrokeWidth = string renderWidth } + + let renderWireSubSegment (vertex1 : XYPos) (vertex2 : XYPos) : list = + let Xa, Ya, Xb, Yb = vertex1.X, vertex1.Y, vertex2.X, vertex2.Y + makeLine Xa Ya Xb Yb lineParameters + :: + makeCircle Xa Ya circleParameters + :: + [ + makeCircle Xb Yb circleParameters + ] + + let segmentJumpHorizontalSize = 9.0 + let segmentJumpVerticalSize = 6.0 + + let renderSingleSegmentJump (intersectionCoordinate : XYPos) : list = + let x, y = intersectionCoordinate.X, intersectionCoordinate.Y + + let startingPoint = {X = x - segmentJumpHorizontalSize/2.0; Y = y} + let startingControlPoint = {X = x - segmentJumpHorizontalSize/2.0; Y = y - segmentJumpVerticalSize} + let endingControlPoint = {X = x + segmentJumpHorizontalSize/2.0; Y = y - segmentJumpVerticalSize} + let endingPoint = {X = x + segmentJumpHorizontalSize/2.0; Y = y} + + makePath startingPoint startingControlPoint endingControlPoint endingPoint pathParameters + :: + makeCircle startingPoint.X startingPoint.Y circleParameters + :: + [ + makeCircle endingPoint.X endingPoint.Y circleParameters + ] + + let rec renderMultipleSegmentJumps (segmentJumpCoordinateList : list) (segmentJumpYCoordinate : float) : list = + + match segmentJumpCoordinateList with + + | [] -> [] + + + | [singleElement] -> + renderSingleSegmentJump {X = singleElement; Y = segmentJumpYCoordinate} + + + | firstElement :: secondElement :: tailList -> + + if (segment.Start.X > segment.End.X) then + renderSingleSegmentJump {X = firstElement; Y = segmentJumpYCoordinate} + @ + renderWireSubSegment {X = firstElement - segmentJumpHorizontalSize/2.0; Y = segmentJumpYCoordinate} {X = secondElement + segmentJumpHorizontalSize/2.0; Y = segmentJumpYCoordinate} + @ + renderMultipleSegmentJumps (secondElement :: tailList) (segmentJumpYCoordinate) + + else + renderSingleSegmentJump {X = firstElement; Y = segmentJumpYCoordinate} + @ + renderWireSubSegment {X = firstElement + segmentJumpHorizontalSize/2.0; Y = segmentJumpYCoordinate} {X = secondElement - segmentJumpHorizontalSize/2.0; Y = segmentJumpYCoordinate} + @ + renderMultipleSegmentJumps (secondElement :: tailList) (segmentJumpYCoordinate) + + + let completeWireSegmentRenderFunction (seg : Segment) : list = + + let jumpCoordinateList = + if (segment.Start.X > segment.End.X) then + seg.JumpCoordinateList + |> List.map fst + |> List.sortDescending + + else + seg.JumpCoordinateList + |> List.map fst + |> List.sort + + match jumpCoordinateList with + | [] -> renderWireSubSegment seg.Start seg.End + + | lst -> + let y = seg.Start.Y // SHOULD be equal to seg.End.Y since ONLY horizontal segments have jumps + let firstSegmentJumpCoordinate = lst[0] + let lastSegmentJumpCoordinate = lst[(List.length lst) - 1] + + if (segment.Start.X > segment.End.X) then + renderWireSubSegment seg.Start {X = firstSegmentJumpCoordinate + segmentJumpHorizontalSize/2.0; Y = y} + @ + renderMultipleSegmentJumps lst y + @ + renderWireSubSegment {X = lastSegmentJumpCoordinate - segmentJumpHorizontalSize/2.0; Y = y} seg.End + + else + renderWireSubSegment seg.Start {X = firstSegmentJumpCoordinate - segmentJumpHorizontalSize/2.0; Y = y} + @ + renderMultipleSegmentJumps lst y + @ + renderWireSubSegment {X = lastSegmentJumpCoordinate + segmentJumpHorizontalSize/2.0; Y = y} seg.End + + + let wireSegmentReactElementList = segment + |> completeWireSegmentRenderFunction + + g [] wireSegmentReactElementList + + else + let Xa, Ya, Xb, Yb = segment.Start.X, segment.Start.Y, segment.End.X, segment.End.Y + let segmentElements = + makeLine Xa Ya Xb Yb lineParameters + :: + makeCircle Xa Ya circleParameters + :: + [ + makeCircle Xb Yb circleParameters + ] + g [] segmentElements + +/// +type WireRenderProps = + { + key: string + Segments: list + ColorP: HighLightColor + StrokeWidthP: int + OutputPortLocation: XYPos + } + + +// ------------------------------redundant wire memoisation code------------------------------ +// this code is not used because React (via Function.Of) does this caching anyway - better tha it can be +// done here +let mutable cache:Map = Map.empty + +/// not used +let memoOf (f: WireRenderProps -> ReactElement, _, _) = + (fun props -> + match Map.tryFind props.key cache with + | None -> + let re = f props + cache <- Map.add props.key (props,re) cache + re + | Some (props',re) -> + if props' = props then re else + let re = f props + cache <- Map.add props.key (props,re) cache + re) +//------------------------------------------------------------------------------------------- + +let singleWireView = + FunctionComponent.Of( + fun (props: WireRenderProps) -> + let renderWireSegmentList : list = + props.Segments + |> List.map + ( + fun (segment : Segment) -> renderSegment segment (props.ColorP.Text()) (string props.StrokeWidthP) + //call a bunch of render helper functions to render the segment (*** DO NOT FORGET SEGMENT JUMPS ***) + ) + + let renderWireWidthText : ReactElement = + let textParameters = + { + TextAnchor = "left"; + FontSize = "12px"; + FontWeight = "Bold"; + FontFamily = "Verdana, Arial, Helvetica, sans-serif"; + Fill = props.ColorP.Text(); + UserSelect = UserSelectOptions.None; + DominantBaseline = "middle"; + } + let textString = if props.StrokeWidthP = 1 then "" else string props.StrokeWidthP //Only print width > 1 + makeText (props.OutputPortLocation.X+1.0) (props.OutputPortLocation.Y-7.0) (textString) textParameters + g [] ([ renderWireWidthText ] @ renderWireSegmentList) + + , "Wire" + , equalsButFunctions + ) + +/// +let MapToSortedList map : Wire list = + let listSelected = + Map.filter (fun id wire -> wire.Color = HighLightColor.Purple) map + |> Map.toList + |> List.map snd + let listErrorSelected = + Map.filter (fun id wire -> wire.Color = HighLightColor.Brown) map + |> Map.toList + |> List.map snd + let listErrorUnselected = + Map.filter (fun id wire -> wire.Color = HighLightColor.Red) map + |> Map.toList + |> List.map snd + let listUnSelected = + Map.filter (fun id wire -> wire.Color = HighLightColor.DarkSlateGrey) map + |> Map.toList + |> List.map snd + let listCopied = + Map.filter (fun id wire -> wire.Color = HighLightColor.Thistle) map + |> Map.toList + |> List.map snd + let listWaves = + Map.filter (fun id wire -> wire.Color = HighLightColor.Blue) map + |> Map.toList + |> List.map snd + + listUnSelected @ listErrorUnselected @ listErrorSelected @ listSelected @ listWaves @ listCopied + +let view (model : Model) (dispatch : Dispatch) = + let start = TimeHelpers.getTimeMs() + let wires1 = + model.WX + |> Map.toArray + |> Array.map snd + TimeHelpers.instrumentTime "WirePropsSort" start + let rStart = TimeHelpers.getTimeMs() + let wires = + wires1 + |> Array.map + ( + fun wire -> + let stringOutId = + match wire.OutputPort with + | OutputPortId stringId -> stringId + + let outputPortLocation = Symbol.getOnePortLocationNew model.Symbol stringOutId PortType.Output + let props = + { + key = match wire.Id with | ConnectionId s -> s + Segments = List.map makeSegPos wire.Segments + ColorP = wire.Color + StrokeWidthP = wire.Width + OutputPortLocation = outputPortLocation + } + singleWireView props) + TimeHelpers.instrumentInterval "WirePrepareProps" rStart () + let symbols = Symbol.view model.Symbol (Symbol >> dispatch) + + g [] [(g [] wires); symbols] + |> TimeHelpers.instrumentInterval "WireView" start + + + +/// This function is given two couples of +/// points that define two line segments and it returns: +/// - Some (x, y) if the two segments intersect; +/// - None if the do not. +let segmentIntersectsSegmentCoordinates ((p1, q1) : (XYPos * XYPos)) ((p2, q2) : (XYPos * XYPos)) : Option = + + if (segmentIntersectsSegment (p1, q1) (p2, q2)) then + let x1, y1, x2, y2 = abs p1.X, abs p1.Y, abs q1.X, abs q1.Y + let x3, y3, x4, y4 = abs p2.X, abs p2.Y, abs q2.X, abs q2.Y + let uA = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1)) + + let intersectionX = x1 + (uA * (x2-x1)) // if coordinates are wanted, maybe useful later + let intersectionY = y1 + (uA * (y2-y1)) + Some {X = intersectionX; Y = intersectionY} + + else None + +/// This funtion is given a bounding box and it returns the coordinates +/// of the top-left and the bottom-right corners of this bounding box. +let getTopLeftAndBottomRightCorner (box : BoundingBox) : XYPos * XYPos = + let {BoundingBox.X = x; BoundingBox.Y = y} = box + let {BoundingBox.H = h; BoundingBox.W = w} = box + let coords = [(x, y); (x, y+h); (x+w, y); (x+w, y+h)] + let topLeft = List.min coords + let bottomRight = List.max coords + + {X = fst(topLeft) ; Y = snd(topLeft)} , {X = fst(bottomRight) ; Y = snd(bottomRight)} + +/// This function is given a Segment and a BoundingBox +/// and it returns: +/// - (false, None) if the segment does not intersect the bounding box +/// - (true, None) if the segment is fully included inside the bounding box +/// - (true, Some coordinate) if the segment intersects the bounding box +let segmentIntersectsBoundingBoxCoordinates (segIn : Segment) (bb : BoundingBox) : bool * Option = + let seg = makeSegPos segIn + let ({X = x; Y = y} : XYPos), ({X = a; Y = b} : XYPos) = getTopLeftAndBottomRightCorner bb + let w , h = (a-x), (b-y) // a = x+w; b = y+h + let x1, y1, x2, y2 = seg.Start.X, seg.Start.Y, seg.End.X, seg.End.Y + + let segPointInBox = + ( + ( (x1 > x) && (x1 < (x+w)) ) && ( (y1 > y) && (y1 < (y+h)) ) + ) + || + ( + ( (x2 > x) && (x2 < (x+w)) ) && ( (y2 > y) && (y2 < (y+h)) ) + ) + + let left = segmentIntersectsSegmentCoordinates (seg.Start, seg.End) ({X=x; Y=y}, {X=x; Y=y+h}) + let right = segmentIntersectsSegmentCoordinates (seg.Start, seg.End) ({X=x+w; Y=y}, {X=x+w; Y=y+h}) + let top = segmentIntersectsSegmentCoordinates (seg.Start, seg.End) ({X=x; Y=y}, {X=x+w; Y=y}) + let bottom = segmentIntersectsSegmentCoordinates (seg.Start, seg.End) ({X=x; Y=y+h}, {X=x+w; Y=y+h}) + + let (intersectionList : list) = + [top; bottom; left; right] + |> List.choose id + + if intersectionList.Length = 0 then + if segPointInBox then + true, None + else + false, None + else + let intersection = + intersectionList + |> List.head + true, Some intersection + +/// This distance is given a point and a segment +/// and it returns the distance between them. +let distanceFromPointToSegment (point : XYPos) (segment : Segment) : float = + let x0, y0 = point.X, abs point.Y + let x1, y1, x2, y2 = abs segment.Start.X, abs segment.Start.Y, abs segment.End.X, abs segment.End.Y + + if (x1 = x2) then abs (x1 - x0) + elif (y1 = y2) then abs (y1 - y0) + else + let numer = abs ( (x2-x1)*(y1-y0) - (x1-x0)*(y2-y1) ) + let denom = sqrt ( (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) ) + numer/denom + +/// This function takes the current state of the model and the +/// IDs of the wires to be rerouted (i.e. updated) as inputs, +/// it REROUTES ALL THE GIVEN WIRES using the default wire +/// shapes defined and it returns the model updated. +let routeGivenWiresBasedOnPortPositions (wiresToBeRouted : list) (model : Model) : Model = + let updatedWireMap = + wiresToBeRouted + |> List.map (fun id -> model.WX[id]) + |> List.map + ( + fun wire -> + let posTuple = Symbol.getTwoPortLocations (model.Symbol) (wire.InputPort) (wire.OutputPort) + (wire.Id, {wire with Segments = makeInitialSegmentsList wire.Id posTuple}) + ) + |> Map.ofList + + let newWX = + model.WX + |> Map.map (fun id wire -> if Map.containsKey id updatedWireMap then updatedWireMap[id] else wire) + + {model with WX = newWX} + +/// Given the current state of the BusWire model, +/// a ConnectionId and an BoundingBox, +/// this function returns a list of Segments of the +/// wire corresponding to the given id that intersect the bounding box. +let getIntersectingSegments (model:Model) (wireId:ConnectionId) (selectBox:BoundingBox) : list = + model.WX[wireId].Segments + |> List.filter (fun seg -> fst(segmentIntersectsBoundingBoxCoordinates seg selectBox)) + + +//Finds the closest segment in a wire to a point using euclidean distance +let getClosestSegment (model : Model) (wireId : ConnectionId) (pos : XYPos) : Segment = + model.WX[wireId].Segments + |> List.minBy ( + fun seg -> + distanceFromPointToSegment pos seg) + +/// Function called when a wire has been clicked, so no need to be an option +let getClickedSegment (model:Model) (wireId: ConnectionId) (pos: XYPos) : SegmentId = + let boundingBox = {X = pos.X - 5.0; Y = pos.Y - 5.0; H = 10.0; W = 10.0} + let intersectingSegments = getIntersectingSegments model wireId boundingBox + + //getIntersecting segments may not return anything at low resolutions as the mouse was not on any segment, but in range of the wire bbox + //In this case just return the segment closest to mouse position + //TODO - should it just do this anyway? + if List.isEmpty intersectingSegments + then (getClosestSegment model wireId pos).Id + else (List.head intersectingSegments).Id + +let checkSegmentAngle (seg:Segment) (name:string) = + match seg.Dir with + | Vertical -> abs (abs seg.Start.X - abs seg.End.X) < 0.000001 + | Horizontal -> abs (abs seg.Start.Y - abs seg.End.Y) < 0.000001 + |> (fun ok -> + if not ok then + printfn $"Weird segment '{name}':\n{seg}\n\n fails angle checking") + +let segPointsLeft seg = + abs seg.Start.X > abs seg.End.X && seg.Dir = Horizontal + +let segXDelta seg = abs seg.End.X - abs seg.Start.X + +/// change the middle X coordinate of the joined ends of two segments (seg0 is LH, seg1 is RH). +/// compensate for negative signs in coordinates using as value but preserving sign +/// xPos is asumed positive +let moveXJoinPos xPos seg0 seg1 = + let changeXKeepingSign (coord:XYPos) = + if coord.X < 0.0 then {coord with X = -xPos} + else {coord with X = xPos} + [ {seg0 with End = changeXKeepingSign seg0.End}; {seg1 with Start = changeXKeepingSign seg1.Start} ] + +let changeLengths isAtEnd seg0 seg1 = + let outerSeg, innerSeg = + if isAtEnd then seg1, seg0 else seg0, seg1 + let innerX = segXDelta innerSeg + let outerX = segXDelta outerSeg + + // should never happen, can't do anything + if seg0.Dir <> Horizontal || seg1.Dir <> Horizontal || outerX < 0.0 then [seg0 ; seg1] + elif innerX < 0.0 then + // the case where we need to shorten the first or last segment (seg0 here) + moveXJoinPos (if isAtEnd then seg1.End.X - Wire.stickLength else seg0.Start.X + Wire.stickLength) seg0 seg1 + else [ seg0; seg1] + + +/// Called for segments 1, 2, 3, 4, 5 - if they are vertical and move horizontally. +/// The function returns distance reduced if need be to prevent wires moving into components +/// approx equality test is safer tehn exact equality - but probably not needed. +let getSafeDistanceForMove (seg: Segment) (seg0:Segment) (seg6:Segment) (distance:float) = + let shrink = match seg.Index with | 1 | 2 | 4 | 5 -> 0.5 | _ -> 1.0 + match seg.Index with + | _ when seg.Dir = Horizontal -> + distance + | 3 when distance < 0.0 && abs (abs seg0.Start.Y - abs seg.Start.Y) > 0.0001 -> + distance + | 3 when distance > 0.0 && abs (abs seg6.Start.Y - abs seg.End.Y) > 0.0001 -> + distance + | 1 | 2 -> + let minDistance = seg0.Start.X + Wire.stickLength * shrink - abs seg.End.X + max minDistance distance + | 4 | 5 -> + let maxDistance = seg6.End.X - Wire.stickLength * shrink - abs seg.Start.X + min maxDistance distance + | 3 -> + let minDistance = abs seg0.Start.X + Wire.stickLength * shrink - abs seg.Start.X + let maxDistance = abs seg6.End.X - Wire.stickLength * shrink - abs seg.Start.X + distance + |> max minDistance + |> min maxDistance + + | _ -> + distance + + +/// Adjust wire so that two adjacent horizontal segments that are in opposite directions +/// get eliminated +let removeRedundantSegments (segs: Segment list) = + let setAbsX x (pos: XYPos) = + let x = if pos.X < 0.0 then - abs x else abs x + {pos with X = x} + let xDelta seg = abs seg.End.X - abs seg.Start.X + let setStartX x (seg:Segment) = {seg with Start = setAbsX x seg.Start} + let setEndX x (seg:Segment) = {seg with End = setAbsX x seg.End} + let adjust seg1 seg2 = + let xd1, xd2 = xDelta seg1, xDelta seg2 + if seg1.Dir = Horizontal && + seg2.Dir = Horizontal && + sign xd1 <> sign xd2 + then + if abs xd1 > abs xd2 then + [setEndX seg2.End.X seg1; setStartX seg2.End.X seg2] + else + [setEndX seg1.Start.X seg1; setStartX seg1.End.X seg2] + else + [seg1;seg2] + adjust segs[0] segs[1] @ segs[2..4] @ adjust segs[5] segs[6] + + +/// This function allows a wire segment to be moved a given amount in a direction perpedicular to +/// its orientation (Horizontal or Vertical). Used to manually adjust routing by mouse drag. +/// The moved segment is tagged by negating one of its coordinates so that it cannot be auto-routed +/// after the move, thus keeping the moved position. +let moveSegment (seg:Segment) (distance:float) (model:Model) = + let wire = model.WX[seg.HostId] + let index = seg.Index + if index <= 0 || index >= wire.Segments.Length - 1 then + failwithf $"Buswire segment index {index} out of range in moveSegment in wire length {wire.Segments.Length}" + let prevSeg = wire.Segments[index-1] + let nextSeg = wire.Segments[index+1] + if seg.Dir = prevSeg.Dir || seg.Dir = nextSeg.Dir then + wire + else + //runTestFable() + distance + |> getSafeDistanceForMove seg wire.Segments[0] wire.Segments[6] + |> (fun distance' -> + let newPrevEnd, newSegStart, newSegEnd, newNextStart = + match seg.Dir with + + | Vertical -> + {prevSeg.End with X = - (abs seg.Start.X + distance')}, + {seg.Start with X = - (abs seg.Start.X + distance')}, + {seg.End with X = - (abs seg.End.X + distance')}, + {nextSeg.Start with X = - (abs seg.End.X + distance')} + + | Horizontal -> + {prevSeg.End with Y = - (abs seg.Start.Y + distance')}, + {seg.Start with Y = - (abs seg.Start.Y + distance')}, + {seg.End with Y = - (abs seg.End.Y + distance')}, + {nextSeg.Start with Y = - (abs seg.End.Y + distance')} + + let newPrevSeg = {prevSeg with End = newPrevEnd} + let newSeg = {seg with Start = newSegStart;End = newSegEnd} + let newNextSeg = {nextSeg with Start = newNextStart} + + let newSegments = + wire.Segments[.. index-2] @ [newPrevSeg; newSeg; newNextSeg] @ wire.Segments[index+2 ..] + |> removeRedundantSegments + + {wire with Segments = newSegments}) + +/// Initialisatiton with no wires +let init () = + let symbols,_ = Symbol.init() + { + WX = Map.empty; + FromVerticalToHorizontalSegmentIntersections = Map.empty; + FromHorizontalToVerticalSegmentIntersections = Map.empty; + Symbol = symbols; + CopiedWX = Map.empty; + SelectedSegment = SegmentId(""); + LastMousePos = {X = 0.0; Y = 0.0}; + ErrorWires = [] + Notifications = None + } , Cmd.none + +///Returns the wires connected to a list of components given by componentIds +let getConnectedWires (wModel : Model) (compIds : list) = + let inputPorts, outputPorts = Symbol.getPortLocations wModel.Symbol compIds + + wModel.WX + |> Map.toList + |> List.map snd + |> List.filter (fun wire -> Map.containsKey wire.InputPort inputPorts || Map.containsKey wire.OutputPort outputPorts) + |> List.map (fun wire -> wire.Id) + |> List.distinct + +///Returns a tuple of: wires connected to inputs ONLY, wires connected to outputs ONLY, wires connected to both inputs and outputs +let filterWiresByCompMoved (wModel : Model) (compIds : list) = + let inputPorts, outputPorts = Symbol.getPortLocations wModel.Symbol compIds + let lst = + wModel.WX + |> Map.toList + |> List.map snd + + let inputWires = + lst + |> List.filter (fun wire -> Map.containsKey wire.InputPort inputPorts) + |> List.map (fun wire -> wire.Id) + |> List.distinct + + let outputWires = + lst + |> List.filter (fun wire -> Map.containsKey wire.OutputPort outputPorts) + |> List.map (fun wire -> wire.Id) + |> List.distinct + + let fullyConnected = + lst + |> List.filter (fun wire -> Map.containsKey wire.InputPort inputPorts && Map.containsKey wire.OutputPort outputPorts) + |> List.map (fun wire -> wire.Id) + |> List.distinct + + (inputWires, outputWires, fullyConnected) + +//Returns a newly autorouted wire given a model and wire +let autorouteWire (model : Model) (wire : Wire) : Wire = + let posTuple = Symbol.getTwoPortLocations (model.Symbol) (wire.InputPort) (wire.OutputPort) + {wire with Segments = makeInitialSegmentsList wire.Id posTuple} + +/// reverse segment order, and Start, End coordinates, so list can be processed from input to output +/// this function is self-inverse +let revSegments (segs:Segment list) = + List.rev segs + |> List.map (fun seg -> {seg with Start = seg.End; End = seg.Start}) + +// +// ==================================================================================================================== +// +// WIRE SEGMENTS FOR ROUTING +// +// +// Segments, going from Start (output port) to End (input port) coords, are summarised as: +// H => Horizontal (incr X) +// V => Vertical (incr Y) +// 0 => zero length segment (never used) +// +// segment qualifiers: +// F => min length (next to output or input, cannot be shortened) +// +// "Simple" case where output.X < input.X and 3 segment autoroute is possible +// S0.FH S1.0V S2.H S3.V S4.H S5.0V S6.FH +// +// "Complex" case where output.X > input.X and wire ends back for 5 segment autoroute +// S0.FH S1.V S2.H S3.V S4.H S5.0V S6.FH (not sure if H and V are correct here) +// +// To determine adjustment on End change we just reverse the segment and apply the Start change algorithm +// Adjustment => reverse list of segments, swap Start and End, and alter the sign of all coordinates +// For simplicity, due to the encoding of manual changes into coordinates by negating them (yuk!) +// we do not alter coordinate sign. Instead we invert all numeric comparisons. +// There are no constants used in the algorithm (if there were, they would need to be negated) +// +// ====================================================================================================================== + + +let inline addPosPos (pos1: XYPos) (pos:XYPos) = + {X = pos1.X + pos.X; Y = pos1.Y + pos.Y} + + +let inline moveEnd (mover: XYPos -> XYPos) (n:int) = + List.mapi (fun i (seg:Segment) -> if i = n then {seg with End = mover seg.End} else seg) + + +let inline moveStart (mover: XYPos -> XYPos) (n:int) = + List.mapi (fun i (seg:Segment) -> if i = n then {seg with Start = mover seg.Start} else seg) + +let inline moveAll (mover: XYPos -> XYPos) (n : int) = + List.mapi (fun i (seg:Segment) -> if i = n then {seg with Start = mover seg.Start; End = mover seg.End} else seg) + +let transformXY tX tY (pos: XYPos) = + {pos with X = tX pos.X; Y = tY pos.Y} + +let transformSeg tX tY (seg: Segment) = + let trans = transformXY tX tY + {seg with Start = trans seg.Start; End = trans seg.End } + +let topology (pos1: XYPos) (pos2:XYPos) = + sign (abs pos1.X - abs pos2.X), sign (abs pos1.Y - abs pos2.Y) + +/// Returns None if full autoroute is required or Some segments with initial part of the segment list autorouted +/// up till the first dragged (manually routed) segment. +/// ReverseFun must equal not or id. not => the segments go from input to output (reverse of normal). +/// This allows the same code to work on both ends of the wire, with segment reversal done outside this +/// function to implement input -> output direction. +let partialAutoRoute (segs: Segment list) (newPortPos: XYPos) = + let wirePos = segs[0].End + let portPos = segs[0].Start + let newWirePos = {newPortPos with X = newPortPos.X + (abs wirePos.X - portPos.X) } + let (diff:XYPos) = {X=newPortPos.X-portPos.X; Y= newPortPos.Y - portPos.Y} + let lastAutoIndex = + let isNegative (pos:XYPos) = pos.X < 0.0 || pos.Y < 0.0 + let isAutoSeg seg = + not (isNegative seg.Start || isNegative seg.End) + segs + |> List.takeWhile isAutoSeg + |> List.length + |> (fun n -> if n > 5 then None else Some (n + 1)) + let scaleBeforeSegmentEnd segIndex = + let seg = segs[segIndex] + let fixedPt = getAbsXY seg.End + let scale x fx nx wx = + if nx = fx then x else ((abs x - fx)*(nx-fx)/(abs wx - fx) + fx) * float (sign x) + let startPos = if segIndex = 1 then portPos else wirePos + let newStartPos = if segIndex = 1 then newPortPos else newWirePos + let scaleX x = scale x fixedPt.X newStartPos.X startPos.X + let scaleY y = scale y fixedPt.Y newStartPos.Y startPos.Y + match List.splitAt (segIndex+1) segs, segIndex with + | ((scaledSegs), otherSegs), 1 -> + Some ((List.map (transformSeg scaleX scaleY) scaledSegs) @ otherSegs) + | ((firstSeg :: scaledSegs), otherSegs), _ -> + Some ((moveAll (addPosPos diff) 0 [firstSeg] @ List.map (transformSeg scaleX scaleY) scaledSegs) @ otherSegs) + | _ -> None + + let checkTopology index = + let finalPt = segs[6].Start + let oldTop x = topology (if index = 1 then portPos else wirePos) x + let newTop x = topology (if index = 1 then newPortPos else newWirePos) x + if oldTop finalPt <> newTop finalPt then + // always aandon manual routing + None + else + let manSegEndPt = segs[index].End + let oldT = oldTop manSegEndPt + let newT = newTop manSegEndPt + if oldT = newT then + Some index + else + None + lastAutoIndex + |> Option.bind checkTopology + |> Option.bind scaleBeforeSegmentEnd + + +///Returns the new positions keeping manual coordinates negative, and auto coordinates positive +let negXYPos (pos : XYPos) (diff : XYPos) : XYPos = + let newPos = Symbol.posAdd (getAbsXY pos) diff + if pos.X < 0. || pos.Y < 0. then {X = - newPos.X; Y = - newPos.Y} + else newPos + +///Moves a wire by a specified amount by adding a XYPos to each start and end point of each segment +let moveWire (wire : Wire) (diff : XYPos) = + {wire with + Segments = + wire.Segments + |> List.map (fun seg -> + {seg with + Start = negXYPos seg.Start diff + End = negXYPos seg.End diff + }) + } + +/// Re-routes a single wire in the model when its ports move. +/// Tries to preserve manual routing when this makes sense, otherwise re-routes with autoroute. +/// Partial routing from input end is done by reversing segments and and swapping Start/End +/// inout = true => reroute input (target) side of wire. +let updateWire (model : Model) (wire : Wire) (inOut : bool) = + let newPort = + match inOut with + | true -> Symbol.getInputPortLocation model.Symbol wire.InputPort + | false -> Symbol.getOutputPortLocation model.Symbol wire.OutputPort + if inOut then + partialAutoRoute (revSegments wire.Segments) newPort + |> Option.map revSegments + else + partialAutoRoute wire.Segments newPort + |> Option.map (fun segs -> {wire with Segments = segs}) + |> Option.defaultValue (autorouteWire model wire) + +let makeAllJumps (wiresWithNoJumps: ConnectionId list) (model: Model) = + let mutable newWX = model.WX + // Arrays are faster to check than lists + let wiresWithNoJumpsA = List.toArray wiresWithNoJumps + let changeJumps wid index jumps = + let jumps = List.sortDescending jumps + let changeSegment segs = + List.mapi (fun i x -> if i <> index then x else { x with JumpCoordinateList = jumps }) segs + + newWX <- Map.add wid { newWX[wid] with Segments = changeSegment newWX[wid].Segments } newWX + + let segs = + model.WX + |> Map.toArray + |> Array.mapi (fun i (wid, w) -> List.toArray w.Segments) + + for w1 in 0 .. segs.Length - 1 do + for h in segs[w1] do + if h.Dir = Horizontal then + // work out what jumps this segment should have + let mutable jumps: (float * SegmentId) list = [] + + if not (Array.contains h.HostId wiresWithNoJumpsA) then + for w2 in 0 .. segs.Length - 1 do + // everything inside the inner loop should be very highly optimised + // it is executed n^2 time where n is the number of segments (maybe 5000) + // the abs here are because segment coordinates my be negated to indicate manual routing + for v in segs[w2] do + if not (Array.contains v.HostId wiresWithNoJumpsA) then + match v.Dir with + | Vertical -> + let x, x1, x2 = abs v.Start.X, abs h.Start.X, abs h.End.X + let y, y1, y2 = abs h.Start.Y, abs v.Start.Y, abs v.End.Y + let xhi, xlo = max x1 x2, min x1 x2 + let yhi, ylo = max y1 y2, min y1 y2 + //printfn $"{[xlo;x;xhi]}, {[ylo;y;yhi]}" + if x < xhi - 5.0 && x > xlo + 5.0 && y < yhi - 5.0 && y > ylo + 5.0 then + //printfn "found a jump!" + jumps <- (x, v.Id) :: jumps + | _ -> () + // compare jumps with what segment now has, and change newWX if need be + // note that if no change is needed we do not update WX + // simple cases are done without sort for speed, proably not necessary! + // The jump list is sorted in model to enable easier rendering of segments + match jumps, h.JumpCoordinateList with + | [], [] -> () + | [ a ], [ b ] when a <> b -> changeJumps h.HostId h.Index jumps + | [], _ -> changeJumps h.HostId h.Index jumps + | _, [] -> // in this case we need to sort the jump list + changeJumps h.HostId h.Index (List.sort jumps) + | newJumps, oldJ -> + let newJ = List.sort newJumps + // oldJ is already sorted (we only ever write newJ back to model) + if newJ <> oldJ then changeJumps h.HostId h.Index newJumps else () + + { model with WX = newWX } + + +let updateWireSegmentJumps (wireList: list) (wModel: Model) : Model = + let startT = TimeHelpers.getTimeMs() + let model = makeAllJumps [] wModel + TimeHelpers.instrumentTime "UpdateJumps" startT + model + + + +/// This function updates the wire model by removing from the stored lists of intersections +/// all those generated by wireList wires. +/// intersetcions are stored in maps on the model and on the horizontal segments containing the jumps +let resetWireSegmentJumps (wireList : list) (wModel : Model) : Model = + makeAllJumps wireList wModel + + + + + + + + +/// Re-routes the wires in the model based on a list of components that have been altered. +/// If the wire input and output ports are both in the list of moved components, does not re-route wire but instead translates it. +/// Keeps manual wires manual (up to a point). +/// Otherwise it will auto-route wires connected to components that have moved +let updateWires (model : Model) (compIdList : ComponentId list) (diff : XYPos) = + + let (inputWires, outputWires, fullyConnected) = filterWiresByCompMoved model compIdList + + let newWires = + model.WX + |> Map.toList + |> List.map (fun (cId, wire) -> + if List.contains cId fullyConnected //Translate wires that are connected to moving components on both sides + then (cId, moveWire wire diff) + elif List.contains cId inputWires //Only route wires connected to ports that moved for efficiency + then (cId, updateWire model wire true) + elif List.contains cId outputWires + then (cId, updateWire model wire false) + else (cId, wire)) + |> Map.ofList + + {model with WX = newWires} + +/// +let update (msg : Msg) (model : Model) : Model*Cmd = + + match msg with + | Symbol sMsg -> + let sm,sCmd = Symbol.update sMsg model.Symbol + {model with Symbol=sm}, Cmd.map Symbol sCmd + + + | UpdateWires (componentIdList, diff) -> + updateWires model componentIdList diff, Cmd.none + + | AddWire ( (inputId, outputId) : (InputPortId * OutputPortId) ) -> + let portOnePos, portTwoPos = Symbol.getTwoPortLocations model.Symbol inputId outputId + let wireWidthFromSymbol = WireWidth.Configured 1 + let wireId = ConnectionId(JSHelpers.uuid()) + let segmentList = makeInitialSegmentsList wireId (portOnePos, portTwoPos) + + let newWire = + { + Id = wireId + InputPort = inputId + OutputPort = outputId + Color = HighLightColor.DarkSlateGrey + Width = 1 + Segments = segmentList + } + + let wireAddedMap = Map.add newWire.Id newWire model.WX + let newModel = updateWireSegmentJumps [wireId] {model with WX = wireAddedMap} + + newModel, Cmd.ofMsg BusWidths + + | BusWidths -> + + let processConWidths (connWidths: ConnectionsWidth) = + let addWireWidthFolder (wireMap: Map) _ wire = + let width = + match connWidths[wire.Id] with + | Some a -> a + | None -> wire.Width + let newColor = if wire.Color = Purple || wire.Color = Brown then Purple else DarkSlateGrey + wireMap.Add ( wire.Id, { wire with Width = width ; Color = newColor} ) + + let addSymbolWidthFolder (m: Map) (_: ConnectionId) (wire: Wire) = + let inPort = model.Symbol.Ports[match wire.InputPort with InputPortId ip -> ip] + let symId = ComponentId inPort.HostId + let symbol = m[symId] + + match symbol.Compo.Type with + | SplitWire n -> + match inPort.PortNumber with + | Some 0 -> {symbol with InWidth0 = Some wire.Width} + | x -> failwithf $"What? wire found with input port {x} other than 0 connecting to SplitWire" + |> (fun sym -> Map.add symId sym m) + | MergeWires -> + match inPort.PortNumber with + | Some 0 -> + Map.add symId {symbol with InWidth0 = Some wire.Width} m + | Some 1 -> + Map.add symId {symbol with InWidth1 = Some wire.Width} m + | x -> failwithf $"What? wire found with input port {x} other than 0 or 1 connecting to MergeWires" + | _ -> m + + let newWX = ((Map.empty, model.WX) ||> Map.fold addWireWidthFolder) + + let symbolsWithWidths = + (model.Symbol.Symbols, newWX) ||> Map.fold addSymbolWidthFolder + + { model with + WX = newWX; Notifications = None ; + ErrorWires=[]; + Symbol = {model.Symbol with Symbols = symbolsWithWidths}}, Cmd.none + + + + let canvasState = (Symbol.extractComponents model.Symbol, extractConnections model ) + + + match BusWidthInferer.inferConnectionsWidth canvasState with + | Ok connWidths -> + processConWidths connWidths + | Error e -> + { model with + Notifications = Some e.Msg }, Cmd.ofMsg (ErrorWires e.ConnectionsAffected) + + | CopyWires (connIds : list) -> + let copiedWires = Map.filter (fun connId _ -> List.contains connId connIds) model.WX + { model with CopiedWX = copiedWires }, Cmd.none + + | ErrorWires (connectionIds : list) -> + let newWX = + model.WX + |> Map.map + (fun id wire -> + if List.contains id connectionIds then + {wire with Color = HighLightColor.Red} + else if List.contains id model.ErrorWires then + {wire with Color = HighLightColor.DarkSlateGrey} + else wire + ) + + {model with WX = newWX ; ErrorWires = connectionIds}, Cmd.none + + | SelectWires (connectionIds : list) -> //selects all wires in connectionIds, and also deselects all other wires + let newWX = + model.WX + |> Map.map + (fun id wire -> + if List.contains id model.ErrorWires then + if List.contains id connectionIds then + {wire with Color = HighLightColor.Brown} + else + {wire with Color = HighLightColor.Red} + else if List.contains id connectionIds then + {wire with Color = HighLightColor.Purple} + else + {wire with Color = HighLightColor.DarkSlateGrey} + ) + + {model with WX = newWX}, Cmd.none + + | DeleteWires (connectionIds : list) -> + let newModel = resetWireSegmentJumps (connectionIds) (model) + let newWX = + newModel.WX + |> Map.filter (fun id wire -> not (List.contains id connectionIds)) + {newModel with WX = newWX}, Cmd.ofMsg BusWidths + + | DragWire (connId : ConnectionId, mMsg: MouseT) -> + match mMsg.Op with + | Down -> + let segId = getClickedSegment model connId mMsg.Pos + {model with SelectedSegment = segId }, Cmd.none + | Drag -> + let segId = model.SelectedSegment + let rec getSeg (segList: list) = + match segList with + | h::t -> if h.Id = segId then h else getSeg t + | _ -> failwithf "segment Id not found in segment list" + let seg = getSeg model.WX[connId].Segments + if seg.Draggable then + let distanceToMove = + match seg.Dir with + | Horizontal -> mMsg.Pos.Y - abs seg.Start.Y + | Vertical -> mMsg.Pos.X - abs seg.Start.X + + let newWire = moveSegment seg distanceToMove model + let newWX = Map.add seg.HostId newWire model.WX + + {model with WX = newWX}, Cmd.none + else + model, Cmd.none + + | _ -> model, Cmd.none + + + | ColorWires (connIds, color) -> // Just Changes the colour of the wires, Sheet calls pasteWires before this + let newWires = + (List.fold (fun prevWires cId -> + let oldWireOpt = Map.tryFind cId model.WX + match oldWireOpt with + | None -> + printfn "BusWire error: expected wire in ColorWires does not exist" + prevWires + | Some oldWire -> + Map.add cId { oldWire with Color = color } prevWires) model.WX connIds) + { model with WX = newWires }, Cmd.none + + | ResetJumps connIds -> + printfn $"resetting jumps on {connIds.Length} wires" + + let newModel = + model + |> resetWireSegmentJumps connIds + + newModel, Cmd.none + + | MakeJumps connIds -> + printfn $"making jumps on {connIds.Length} wires" + + let newModel = + model + |> updateWireSegmentJumps connIds + + newModel, Cmd.none + + | ResetModel -> { model with WX = Map.empty; ErrorWires = []; Notifications = None }, Cmd.none + + | LoadConnections conns -> // we assume components (and hence ports) are loaded before connections + let posMatchesVertex (pos:XYPos) (vertex: float*float) = + let epsilon = 0.00001 + abs (abs pos.X - abs (fst vertex)) < epsilon && + abs (abs pos.Y - abs (snd vertex)) < epsilon + |> (fun b -> if not b then printf $"Bad wire endpoint match on {pos} {vertex}"; b else b) + let newWX = + conns + |> List.map ( fun conn -> + let inputId = InputPortId conn.Target.Id + let outputId = OutputPortId conn.Source.Id + let connId = ConnectionId conn.Id + let segments = issieVerticesToSegments connId conn.Vertices + let makeWirePosMatchSymbol inOut (wire:Wire) = + match inOut with + | true -> posMatchesVertex + (Symbol.getInputPortLocation model.Symbol inputId) + (List.head conn.Vertices) + | false -> + posMatchesVertex + (Symbol.getOutputPortLocation model.Symbol outputId) + (List.last conn.Vertices) + |> (fun b -> + if b then + wire + else + let getS (connId:string) = + Map.tryFind connId model.Symbol.Ports + |> Option.map (fun port -> port.HostId) + |> Option.bind (fun symId -> Map.tryFind (ComponentId symId) model.Symbol.Symbols) + |> Option.map (fun sym -> sym.Compo.Label) + printfn $"Updating loaded wire from {getS conn.Source.Id}->{getS conn.Target.Id} of wire " + updateWire model wire inOut) + + + connId, + { Id = ConnectionId conn.Id + InputPort = inputId + OutputPort = outputId + Color = HighLightColor.DarkSlateGrey + Width = 1 + Segments = segments} + |> makeWirePosMatchSymbol false + |> makeWirePosMatchSymbol true + ) + |> Map.ofList + + let connIds = + conns + |> List.map (fun conn -> ConnectionId conn.Id) + + { model with WX = newWX }, Cmd.ofMsg (MakeJumps connIds) + +//---------------Other interface functions--------------------// + +/// +let wireIntersectsBoundingBox (w : Wire) (bb : BoundingBox) = + let boolList = List.map (fun seg -> fst(segmentIntersectsBoundingBoxCoordinates seg bb)) w.Segments + List.contains true boolList + +/// +let getIntersectingWires (wModel : Model) (selectBox : BoundingBox) : list = + wModel.WX + |> Map.map (fun id wire -> wireIntersectsBoundingBox wire selectBox) + |> Map.filter (fun id boolVal -> boolVal) + |> Map.toList + |> List.map (fun (id,bool) -> id) + +///searches if the position of the cursor is on a wire in a model +///Where n is 5 pixels adjusted for top level zoom +let getWireIfClicked (wModel : Model) (pos : XYPos) (n : float) : ConnectionId Option = + let boundingBox = {BoundingBox.X = pos.X - n; Y = pos.Y - n; H = n*2.; W = n*2.} + let intersectingWires = getIntersectingWires (wModel : Model) boundingBox + List.tryHead intersectingWires + +/// +let pasteWires (wModel : Model) (newCompIds : list) : (Model * list) = + let oldCompIds = Symbol.getCopiedSymbols wModel.Symbol + + let pastedWires = + let createNewWire (oldWire : Wire) : list = + let newId = ConnectionId(JSHelpers.uuid()) + + match Symbol.getEquivalentCopiedPorts wModel.Symbol oldCompIds newCompIds (oldWire.InputPort, oldWire.OutputPort) with + | Some (newInputPort, newOutputPort) -> + + let portOnePos, portTwoPos = Symbol.getTwoPortLocations wModel.Symbol (InputPortId newInputPort) (OutputPortId newOutputPort) + let segmentList = makeInitialSegmentsList newId (portOnePos, portTwoPos) + [ + { + oldWire with + Id = newId; + InputPort = InputPortId newInputPort; + OutputPort = OutputPortId newOutputPort; + Segments = segmentList; + } + ] + | None -> [] + + wModel.CopiedWX + |> Map.toList + |> List.map snd + |> List.collect createNewWire + |> List.map (fun wire -> wire.Id, wire) + |> Map.ofList + + let newWireMap = Map.fold ( fun acc newKey newVal -> Map.add newKey newVal acc ) pastedWires wModel.WX + let pastedConnIds = + pastedWires + |> Map.toList + |> List.map fst + + { wModel with WX = newWireMap }, pastedConnIds + +/// +let getPortIdsOfWires (model: Model) (connIds: ConnectionId list) : (InputPortId list * OutputPortId list) = + (([], []), connIds) + ||> List.fold (fun (inputPorts, outputPorts) connId -> + (model.WX[connId].InputPort :: inputPorts, model.WX[connId].OutputPort :: outputPorts)) diff --git a/src/Renderer/DrawBlock/Sheet.fs b/src/Renderer/DrawBlock/Sheet.fs new file mode 100644 index 0000000..0edb8a6 --- /dev/null +++ b/src/Renderer/DrawBlock/Sheet.fs @@ -0,0 +1,1288 @@ +(* + This module coordinates the draw block user interface managing component selection, moving, auto-scrolling etc +*) + +module Sheet +open CommonTypes +open Fable.React +open Fable.React.Props +open Browser +open Elmish +open DrawHelpers + + +let mutable canvasDiv:Types.Element option = None + + +/// Used to keep mouse movement (AKA velocity) info as well as position +type XYPosMov = { + Pos: XYPos + Move: XYPos + } + +/// Used to keep track of what the mouse is on +type MouseOn = + | InputPort of CommonTypes.InputPortId * XYPos + | OutputPort of CommonTypes.OutputPortId * XYPos + | Component of CommonTypes.ComponentId + | Connection of CommonTypes.ConnectionId + | Canvas + +/// Keeps track of the current action that the user is doing +type CurrentAction = + | Selecting + | InitialiseMoving of CommonTypes.ComponentId // In case user clicks on a component and never drags the mouse then we'll have saved the component that the user clicked on to reset any multi-selection to that component only. + | MovingSymbols + | DragAndDrop + | MovingWire of CommonTypes.ConnectionId // Sends mouse messages on to BusWire + | ConnectingInput of CommonTypes.InputPortId // When trying to connect a wire from an input + | ConnectingOutput of CommonTypes.OutputPortId // When trying to connect a wire from an output + | Scrolling // For Automatic Scrolling by moving mouse to edge to screen + | Idle + // ------------------------------ Issie Actions ---------------------------- // + | InitialisedCreateComponent of ComponentType * string + +type UndoAction = + | MoveBackSymbol of CommonTypes.ComponentId List * XYPos + | UndoPaste of CommonTypes.ComponentId list + +/// Used for Snap-to-Grid, keeps track of mouse coordinates when the snapping started, and the amount to un-snap in the future. +type LastSnap = + { + Pos: float + SnapLength: float + } + +/// Used for Snap-to-Grid, keeps track of the last snap for each coordinate. None if no snapping has occurred. +type MouseSnapInfo = + { + XSnap: LastSnap Option + YSnap: LastSnap Option + } + +/// Keeps track of what cursor to show +type CursorType = + | Default + | ClickablePort + | NoCursor + | Spinner +with + member this.Text() = + match this with + | Default -> "default" + | ClickablePort -> "move" + | NoCursor -> "none" + | Spinner -> "wait" + +/// Keeps track of coordinates of visual snap-to-grid indicators. +type SnapIndicator = + { + XLine: float Option + YLine: float Option + } + +/// For Keyboard messages +type KeyboardMsg = + | CtrlS | CtrlC | CtrlV | CtrlZ | CtrlY | CtrlA | CtrlW | AltC | AltV | AltZ | AltShiftZ | ZoomIn | ZoomOut | DEL | ESC + +type Msg = + | Wire of BusWire.Msg + | KeyPress of KeyboardMsg + | ToggleGrid + | KeepZoomCentered of XYPos + | MouseMsg of MouseT + | UpdateBoundingBoxes + | UpdateSingleBoundingBox of ComponentId + | UpdateScrollPos of X: float * Y: float + | ManualKeyUp of string // For manual key-press checking, e.g. CtrlC + | ManualKeyDown of string // For manual key-press checking, e.g. CtrlC + | CheckAutomaticScrolling + | DoNothing + // ------------------- Issie Interface Messages ---------------------- + | InitialiseCreateComponent of ComponentType * string // Need to initialise for drag-and-drop + | FlushCommandStack + | ResetModel + | UpdateSelectedWires of ConnectionId list * bool + | ColourSelection of compIds : ComponentId list * connIds : ConnectionId list * colour : HighLightColor + | ToggleSelectionOpen + | ToggleSelectionClose + | ResetSelection + | SetWaveSimMode of bool + | ToggleNet of CanvasState //This message does nothing in sheet, but will be picked up by the update function + | SelectWires of ConnectionId list + | SetSpinner of bool + + +// ------------------ Helper Functions that need to be before the Model type --------------------------- // + +/// Creates a command to Symbol +let symbolCmd (msg: Symbol.Msg) = Cmd.ofMsg (Wire (BusWire.Symbol msg)) + +/// Creates a command to BusWire +let wireCmd (msg: BusWire.Msg) = Cmd.ofMsg (Wire msg) + + +type Model = { + Wire: BusWire.Model + BoundingBoxes: Map + LastValidBoundingBoxes: Map + SelectedComponents: CommonTypes.ComponentId List + SelectedWires: CommonTypes.ConnectionId list + NearbyComponents: CommonTypes.ComponentId list + ErrorComponents: CommonTypes.ComponentId list + DragToSelectBox: BoundingBox + ConnectPortsLine: XYPos * XYPos // Visual indicator for connecting ports, defines two vertices to draw a line in-between. + TargetPortId: string // Keeps track of if a target port has been found for connecting two wires in-between. + Action: CurrentAction + ShowGrid: bool // Always true at the moment, kept in-case we want an optional grid + Snap: MouseSnapInfo // For Snap-to-Grid + SnapIndicator: SnapIndicator // For Snap-to-Grid + CursorType: CursorType + LastValidPos: XYPos + CurrentKeyPresses: Set // For manual key-press checking, e.g. CtrlC + Zoom: float + TmpModel: Model Option + UndoList: Model List + RedoList: Model List + AutomaticScrolling: bool // True if mouse is near the edge of the screen and is currently scrolling. This improved performance for manual scrolling with mouse wheel (don't check for automatic scrolling if there is no reason to) + ScrollPos: XYPos // copies HTML canvas scrolling position: (canvas.scrollLeft,canvas.scrollTop) + LastMousePos: XYPos // For Symbol Movement + ScrollingLastMousePos: XYPosMov // For keeping track of mouse movement when scrolling. Can't use LastMousePos as it's used for moving symbols (won't be able to move and scroll symbols at same time) + LastMousePosForSnap: XYPos + MouseCounter: int + Toggle : bool + IsWaveSim : bool + PrevWireSelection : ConnectionId list + } with + + // ---------------------------------- Issie Interfacing functions ----------------------------- // + + /// Given a compType, return a label + member this.GenerateLabel (compType: ComponentType) : string = + Symbol.generateLabel this.Wire.Symbol compType + + /// Given a compId, return the corresponding component + member this.GetComponentById (compId: ComponentId) = + Symbol.extractComponent this.Wire.Symbol compId + + /// Change the label of Component specified by compId to lbl + member this.ChangeLabel (dispatch: Dispatch) (compId: ComponentId) (lbl: string) = + dispatch <| (Wire (BusWire.Symbol (Symbol.ChangeLabel (compId, lbl) ) ) ) + + /// Run Bus Width Inference check + member this.DoBusWidthInference dispatch = + dispatch <| (Wire (BusWire.BusWidths)) + + /// Given a compId and a width, update the width of the Component specified by compId + member this.ChangeWidth (dispatch: Dispatch) (compId: ComponentId) (width: int) = + dispatch <| (Wire (BusWire.Symbol (Symbol.ChangeNumberOfBits (compId, width) ) ) ) + this.DoBusWidthInference dispatch + + /// Given a compId and a LSB, update the LSB of the Component specified by compId + member this.ChangeLSB (dispatch: Dispatch) (compId: ComponentId) (lsb: int64) = + dispatch <| (Wire (BusWire.Symbol (Symbol.ChangeLsb (compId, lsb) ) ) ) + + /// Return Some string if Sheet / BusWire / Symbol has a notification, if there is none then return None + member this.GetNotifications = + // Currently only BusWire has notifications + this.Wire.Notifications + + /// Get the current canvas state in the form of (Component list * Connection list) + member this.GetCanvasState () = + let compList = Symbol.extractComponents this.Wire.Symbol + let connList = BusWire.extractConnections this.Wire + + compList, connList + + /// Clears the Undo and Redo stack of Sheet + member this.FlushCommandStack dispatch = + dispatch <| FlushCommandStack + + /// Clears the canvas, removes all components and connections + member this.ClearCanvas dispatch = + dispatch <| ResetModel + dispatch <| (Wire BusWire.ResetModel) + dispatch <| (Wire (BusWire.Symbol (Symbol.ResetModel ) ) ) + + /// Returns a list of selected components + member this.GetSelectedComponents = + this.SelectedComponents + |> List.map (Symbol.extractComponent this.Wire.Symbol) + + /// Returns a list of selected connections + member this.GetSelectedConnections = + this.SelectedWires + |> List.map (BusWire.extractConnection this.Wire) + + /// Returns a list of selected components and connections in the form of (Component list * Connection list) + member this.GetSelectedCanvasState = + this.GetSelectedComponents, this.GetSelectedConnections + + /// Given a list of connIds, select those connections + member this.SelectConnections dispatch on connIds = + dispatch <| UpdateSelectedWires (connIds, on) + + /// Update the memory of component specified by connId at location addr with data value + member this.WriteMemoryLine dispatch connId addr value = + dispatch <| (Wire (BusWire.Symbol (Symbol.WriteMemoryLine (connId, addr, value)))) + +// ---------------------------- CONSTANTS ----------------------------- // +let gridSize = 30.0 // Size of each square grid +let snapMargin = gridSize / 25.0 // How strongly snap-to-grid snaps to the grid, small value so that there is not excessive snapping when moving symbols +let unSnapMargin = gridSize / 5.0 // How much movement there needs to be for un-snapping + + +// ------------------------------------------- Helper Functions ------------------------------------------- // + +//Calculates the symmetric difference of two lists, returning a list of the given type +let symDiff lst1 lst2 = + let a = Set.ofList lst1 + let b = Set.ofList lst2 + (a - b) + (b - a) + |> Set.toList + +/// Calculates the change in coordinates of two XYPos +let posDiff (a: XYPos) (b: XYPos) = {X=a.X-b.X; Y=a.Y-b.Y} + +let getScreenEdgeCoords () = + let canvas = document.getElementById "Canvas" + let wholeApp = document.getElementById "WholeApp" + let rightSelection = document.getElementById "RightSelection" + let topMenu = document.getElementById "TopMenu" + let leftScreenEdge = canvas.scrollLeft + let rightScreenEdge = leftScreenEdge + wholeApp.clientWidth - rightSelection.offsetWidth + let topScreenEdge = canvas.scrollTop + let bottomScreenEdge = topScreenEdge + rightSelection.offsetHeight - topMenu.clientHeight + (leftScreenEdge, rightScreenEdge,topScreenEdge,bottomScreenEdge) + +/// Checks if pos is inside any of the bounding boxes of the components in boundingBoxes +let insideBox (boundingBoxes: Map) (pos: XYPos) : CommonTypes.ComponentId Option = + let insideOneBox _ boundingBox = + let {BoundingBox.X=xBox; Y=yBox; H=hBox; W=wBox} = boundingBox + pos.X >= xBox && pos.X <= xBox + wBox && pos.Y >= yBox && pos.Y <= yBox + hBox + + boundingBoxes + |> Map.tryFindKey insideOneBox // If there are multiple components overlapping (should not happen), return first one found + +/// return a BB equivalent to input but with (X,Y) = LH Top coord, (X+W,Y+H) = RH bottom coord +/// note that LH Top is lower end of the two screen coordinates +let standardiseBox (box:BoundingBox) = + let x = min box.X (box.X+box.W) + let y = min box.Y (box.Y+box.H) + let w = abs box.W + let h = abs box.H + { X=x; Y=y; W=w;H=h} + + +let transformScreenToPos (screenPos:XYPos) (scrollPos:XYPos) mag = + {X=(screenPos.X + scrollPos.X)/mag; + Y=(screenPos.Y + scrollPos.Y)/mag} + + +/// calculates the smallest bounding box that contains two BBs, in form with W,H > 0 +let boxUnion (box:BoundingBox) (box':BoundingBox) = + let maxX = max (box.X+box.W) (box'.X + box'.W) + let maxY = max (box.Y + box.H) (box'.Y + box'.H) + let minX = min box.X box'.X + let minY = min box.Y box'.Y + { + X = minX + Y = minY + W = maxX - minX + H = maxY - minY + } + +let symbolToBB (symbol:Symbol.Symbol) = + let co = symbol.Compo + {X= float co.X; Y=float co.Y; W=float (co.W); H=float (co.H)} + + +/// Inputs must also have W,H > 0. +/// Maybe this should include wires as well? +let symbolBBUnion (model:Model) = + let symbols = + model.Wire.Symbol.Symbols + |> Map.toList + match symbols with + | [] -> None + | (_,sym) :: rest -> + (symbolToBB sym, rest) + ||> List.fold (fun (box:BoundingBox) (_,sym) -> + boxUnion box (symbolToBB sym)) + |> Some + +let fitCircuitToWindowParas (model:Model) = + let maxMagnification = 2. + let boxOpt = symbolBBUnion model + let sBox = + match boxOpt with + | None -> {X=100.; Y=100.; W=100.; H=100.} // default if sheet is empty + | Some box -> + { + X = box.X + Y = box.Y + W = box.W + H = box.H + } + let boxEdge = max 30. ((max sBox.W sBox.H) * 0.05) + let lh,rh,top,bottom = getScreenEdgeCoords() + let wantedMag = min ((rh - lh)/(sBox.W+2.*boxEdge)) ((bottom-top)/(sBox.H+2.*boxEdge)) + let magToUse = min wantedMag maxMagnification + let xMiddle = (sBox.X + sBox.W/2.)*magToUse + let xScroll = xMiddle - (rh-lh)/2. + let yMiddle = (sBox.Y + (sBox.H)/2.)*magToUse + let yScroll = yMiddle - (bottom-top)/2. + + {|ScrollX=xScroll; ScrollY=yScroll; MagToUse=magToUse|} + + +let isBBoxAllVisible (bb: BoundingBox) = + let lh,rh,top,bottom = getScreenEdgeCoords() + let bbs = standardiseBox bb + lh < bb.Y && + top < bb.X && + bb.Y+bb.H < bottom && + bb.X+bb.W < rh + +/// could be made more efficient, since segments contain redundant info +let getWireBBox (wire: BusWire.Wire) (model: Model) = + let coords = + wire.Segments + |> List.collect (fun seg -> [seg.Start; seg.End]) + let xCoords = coords |> List.map (fun xy -> xy.X) + let yCoords = coords |> List.map (fun xy -> xy.Y) + let lh,rh = List.min xCoords, List.max xCoords + let top,bottom = List.min yCoords, List.max yCoords + {X=lh; Y = top; W = rh - lh; H = bottom - top} + + +let isAllVisible (model: Model)(conns: ConnectionId list) (comps: ComponentId list) = + let wVisible = + conns + |> List.map (fun cid -> Map.tryFind cid model.Wire.WX) + |> List.map (Option.map (fun wire -> getWireBBox wire model)) + |> List.map (Option.map isBBoxAllVisible) + |> List.map (Option.defaultValue true) + |> List.fold (&&) true + let cVisible = + comps + |> List.map (Symbol.getOneBoundingBox model.Wire.Symbol) + |> List.map isBBoxAllVisible + |> List.fold (&&) true + wVisible && cVisible + + + + + +/// Calculates if two bounding boxes intersect by comparing corner coordinates of each box +let boxesIntersect (box1: BoundingBox) (box2: BoundingBox) = + // Requires min and max since H & W can be negative, i.e. we don't know which corner is which automatically + // Boxes intersect if there is overlap in both x and y coordinates + min box1.X (box1.X + box1.W) < max box2.X (box2.X + box2.W) + && min box2.X (box2.X + box2.W) < max box1.X (box1.X + box1.W) + && min box1.Y (box1.Y + box1.H) < max box2.Y (box2.Y + box2.H) + && min box2.Y (box2.Y + box2.H) < max box1.Y (box1.Y + box1.H) + +/// Finds all components that touch a bounding box (which is usually the drag-to-select box) +let findIntersectingComponents (model: Model) (box1: BoundingBox) = + model.BoundingBoxes + |> Map.filter (fun _ boundingBox -> boxesIntersect boundingBox box1) + |> Map.toList + |> List.map fst + +let posAdd (pos : XYPos) (a : float, b : float) : XYPos = + {X = pos.X + a; Y = pos.Y + b} + +/// Finds all components (that are stored in the Sheet model) near pos +let findNearbyComponents (model: Model) (pos: XYPos) = + List.allPairs [-50.0 .. 10.0 .. 50.0] [-50.0 .. 10.0 .. 50.0] // Larger Increments -> More Efficient. But can miss small components then. + |> List.map ((fun x -> posAdd pos x) >> insideBox model.BoundingBoxes) + |> List.collect ((function | Some x -> [x] | _ -> [])) + +/// Checks if pos is inside any of the ports in portList +let mouseOnPort portList (pos: XYPos) (margin: float) = + let radius = 5.0 + + let insidePortCircle (pos: XYPos) (portLocation: XYPos): bool = + let distance = ((pos.X - portLocation.X) ** 2.0 + (pos.Y - portLocation.Y) ** 2.0) ** 0.5 + distance <= radius + margin + + + match List.tryFind (fun (_, portLocation) -> insidePortCircle pos portLocation) portList with // + 2.5 margin to make it a bit easier to click on, maybe it's due to the stroke width? + | Some (portId, portLocation) -> Some (portId, portLocation) + | None -> None + +/// Returns the ports of all model.NearbyComponents +let findNearbyPorts (model: Model) = + let inputPortsMap, outputPortsMap = Symbol.getPortLocations model.Wire.Symbol model.NearbyComponents + + (inputPortsMap, outputPortsMap) ||> (fun x y -> (Map.toList x), (Map.toList y)) + +/// Returns what is located at pos +/// Priority Order: InputPort -> OutputPort -> Component -> Wire -> Canvas +let mouseOn (model: Model) (pos: XYPos) : MouseOn = + let inputPorts, outputPorts = findNearbyPorts model + + //TODO FIX THIS - QUICK FIX TO MAKE WORK, NOT IDEAL + //The ports/wires are being loaded in the correct place but the detection is not working + //Something is wrong with the mouse coordinates somewhere, might be caused by zoom? not sure + //let pos = {X = posIn.X - 2.; Y = posIn.Y - 4.} + + match mouseOnPort inputPorts pos 2.5 with + | Some (portId, portLoc) -> InputPort (portId, portLoc) + | None -> + match mouseOnPort outputPorts pos 2.5 with + | Some (portId, portLoc) -> OutputPort (portId, portLoc) + | None -> + match insideBox model.BoundingBoxes pos with + | Some compId -> Component compId + | None -> + match BusWire.getWireIfClicked model.Wire pos (5./model.Zoom) with + | Some connId -> Connection connId + | None -> Canvas + +let notIntersectingComponents (model: Model) (box1: BoundingBox) (inputId: CommonTypes.ComponentId) = + model.BoundingBoxes + |> Map.filter (fun sId boundingBox -> boxesIntersect boundingBox box1 && inputId <> sId) + |> Map.isEmpty + +/// Update function to move symbols in model.SelectedComponents +let moveSymbols (model: Model) (mMsg: MouseT) = + let nextAction, isDragAndDrop = + match model.Action with + | DragAndDrop -> DragAndDrop, true + | _ -> MovingSymbols, false + + match model.SelectedComponents.Length with + | 1 -> // Attempt Snap-to-Grid if there is only one moving component + + /// Checks for snap-to-grid in one dimension (x-coordinates or y-coordinates) + /// Input / output is an anonymous record to deal with too many arguments otherwise + let checkForSnap1D (input: {| SnapInfo: LastSnap Option; Indicator: float Option; CurrMPos: float; LastMPos: float; Side1: float; Side2: float; PosDirection: float |}) = + + match input.SnapInfo with + | Some { Pos = oldPos; SnapLength = previousSnap } -> // Already snapped, see if mouse is far enough to un-snap + if abs (input.CurrMPos - oldPos) > unSnapMargin + then {| DeltaPos = (input.CurrMPos - oldPos) - previousSnap; SnapInfo = None; Indicator = None |} // Un-snap + else {| DeltaPos = 0.0; SnapInfo = input.SnapInfo; Indicator = input.Indicator |} // Don't un-snap + | None -> // No snapping has occurred yet, check which side is closer to a grid and see if it should snap, also save which side it is + let margins = [ (input.Side1 % gridSize), input.Side1 + ((input.Side1 % gridSize) - gridSize), input.Side1 + (input.Side2 % gridSize), input.Side2 + ((input.Side2 % gridSize) - gridSize), input.Side2 ] + + let getMarginWithDirection (sortedMargins: (float*float)list) (dir: float) = + if abs(fst(sortedMargins[0]) - fst(sortedMargins[1])) < 0.1 then + //printfn "HERE" + //printfn "%A" dir + if dir > 0. then + // printf "HERE1" + sortedMargins[0] + else sortedMargins[1] + else + sortedMargins[0] + + let sortedMargins = List.rev (List.sortByDescending (fun (margin, _) -> abs margin) margins) + + //printfn "%A" sortedMargins + + match getMarginWithDirection sortedMargins input.PosDirection with // abs since there negative margins as well (e.g. snap left) + | margin, side when abs margin < snapMargin && not model.AutomaticScrolling -> // disable snap if autoscrolling + // Snap to grid and save info for future un-snapping + {| DeltaPos = -margin + SnapInfo = Some {Pos = input.CurrMPos; SnapLength = -margin - (input.CurrMPos - input.LastMPos)} // Offset with (CurrMPos - LastMPos), so that the symbol stays aligned with the mouse after un-snapping + Indicator = Some (side - margin) |} + | _ -> // Don't do any snap-to-grid + {| DeltaPos = (input.CurrMPos - input.LastMPos) + SnapInfo = None + Indicator = None |} + + let compId = model.SelectedComponents.Head + let boundingBox = model.BoundingBoxes[compId] + let x1, x2, y1, y2 = boundingBox.X, boundingBox.X + boundingBox.W, boundingBox.Y, boundingBox.Y + boundingBox.H + + // printfn "%A" mMsg.Pos.X + // printfn "%A" model.LastMousePos.X + + let snapX = checkForSnap1D {| SnapInfo = model.Snap.XSnap + Indicator = model.SnapIndicator.XLine + CurrMPos = mMsg.Pos.X + LastMPos = model.LastMousePos.X + Side1 = x1 + Side2 = x2 + PosDirection = (mMsg.Pos.X - model.LastMousePosForSnap.X) |} + + let snapY = checkForSnap1D {| SnapInfo = model.Snap.YSnap + Indicator = model.SnapIndicator.YLine + CurrMPos = mMsg.Pos.Y + LastMPos = model.LastMousePos.Y + Side1 = y1 + Side2 = y2 + PosDirection = (mMsg.Pos.Y - model.LastMousePosForSnap.Y) |} + + let errorComponents = + if notIntersectingComponents model boundingBox compId then [] else [compId] + + let updateLastMousePosForSnap , updateMouseCounter = + if model.MouseCounter > 5 then + mMsg.Pos , 0 + else + model.LastMousePos , model.MouseCounter + 1 + {model with + Action = nextAction + LastMousePos = mMsg.Pos + ScrollingLastMousePos = {Pos=mMsg.Pos;Move=mMsg.Movement} + ErrorComponents = errorComponents + Snap = {XSnap = snapX.SnapInfo; YSnap = snapY.SnapInfo} + SnapIndicator = {XLine = snapX.Indicator; YLine = snapY.Indicator} + MouseCounter = updateMouseCounter + LastMousePosForSnap = updateLastMousePosForSnap}, + Cmd.batch [ symbolCmd (Symbol.MoveSymbols (model.SelectedComponents, {X = snapX.DeltaPos; Y = snapY.DeltaPos})) + Cmd.ofMsg (UpdateSingleBoundingBox model.SelectedComponents.Head) + symbolCmd (Symbol.ErrorSymbols (errorComponents,model.SelectedComponents,isDragAndDrop)) + Cmd.ofMsg CheckAutomaticScrolling + wireCmd (BusWire.UpdateWires (model.SelectedComponents, posDiff mMsg.Pos model.LastMousePos))] + | _ -> // Moving multiple symbols -> don't do snap-to-grid + let errorComponents = + model.SelectedComponents + |> List.filter (fun sId -> not (notIntersectingComponents model model.BoundingBoxes[sId] sId)) + {model with Action = nextAction ; LastMousePos = mMsg.Pos; ScrollingLastMousePos = {Pos=mMsg.Pos;Move=mMsg.Movement}; ErrorComponents = errorComponents }, + Cmd.batch [ symbolCmd (Symbol.MoveSymbols (model.SelectedComponents, posDiff mMsg.Pos model.LastMousePos)) + symbolCmd (Symbol.ErrorSymbols (errorComponents,model.SelectedComponents,isDragAndDrop)) + Cmd.ofMsg UpdateBoundingBoxes + Cmd.ofMsg CheckAutomaticScrolling + wireCmd (BusWire.UpdateWires (model.SelectedComponents, posDiff mMsg.Pos model.LastMousePos))] + +// ----------------------------------------- Mouse Update Helper Functions ----------------------------------------- // +// (Kept in separate functions since Update function got too long otherwise) + +let appendUndoList (undoList: Model List) (model_in: Model): Model List = + let rec removeLast lst = + match lst with + | _ :: lst when List.isEmpty lst -> [] + | hd :: lst -> hd :: (removeLast lst) + | [] -> [] + + match List.length undoList with + | n when n < 500 -> model_in :: undoList + | _ -> model_in :: (removeLast undoList) + + +/// Mouse Down Update, Can have clicked on: InputPort / OutputPort / Component / Wire / Canvas. Do correct action for each. +let mDownUpdate (model: Model) (mMsg: MouseT) : Model * Cmd = + let newModel = + match model.TmpModel with + | None -> model + | Some newModel -> newModel + + match model.Action with + | DragAndDrop -> + let errorComponents = + model.SelectedComponents + |> List.filter (fun sId -> not (notIntersectingComponents model model.BoundingBoxes[sId] sId)) + + match List.isEmpty errorComponents with + | false -> model, Cmd.none + | true -> + {model with + BoundingBoxes = Symbol.getBoundingBoxes model.Wire.Symbol // TODO: Improve here in group stage when we are concerned with efficiency + Action = Idle + Snap = {XSnap = None; YSnap = None} + SnapIndicator = {XLine = None; YLine = None} + UndoList = appendUndoList model.UndoList newModel + RedoList = [] + AutomaticScrolling = false + }, + Cmd.batch [ symbolCmd (Symbol.SelectSymbols model.SelectedComponents) + wireCmd (BusWire.SelectWires model.SelectedWires) ] + | _ -> + match (mouseOn model mMsg.Pos) with + | InputPort (portId, portLoc) -> + {model with Action = ConnectingInput portId; ConnectPortsLine = portLoc, mMsg.Pos; TmpModel=Some model}, + symbolCmd Symbol.ShowAllOutputPorts + | OutputPort (portId, portLoc) -> + {model with Action = ConnectingOutput portId; ConnectPortsLine = portLoc, mMsg.Pos; TmpModel=Some model}, + symbolCmd Symbol.ShowAllInputPorts + | Component compId -> + let msg, action = + if model.IsWaveSim then + ToggleNet ([Symbol.extractComponent model.Wire.Symbol compId], []), Idle + else DoNothing, InitialiseMoving compId + + if model.Toggle + then + let newComponents = + if List.contains compId model.SelectedComponents + then List.filter (fun cId -> cId <> compId) model.SelectedComponents // If component selected was already in the list, remove it + else compId :: model.SelectedComponents // If user clicked on a new component add it to the selected list + + {model with SelectedComponents = newComponents; LastValidPos = mMsg.Pos ; LastValidBoundingBoxes=model.BoundingBoxes ; Action = action; LastMousePos = mMsg.Pos; TmpModel = Some model; PrevWireSelection = model.SelectedWires}, + Cmd.batch [symbolCmd (Symbol.SelectSymbols newComponents); Cmd.ofMsg msg] + else + let newComponents, newWires = + if List.contains compId model.SelectedComponents + then model.SelectedComponents, model.SelectedWires // Keep selection for symbol movement + else [compId], [] // If user clicked on a new component, select that one instead + {model with SelectedComponents = newComponents; LastValidPos = mMsg.Pos ; LastValidBoundingBoxes=model.BoundingBoxes ; SelectedWires = newWires; Action = action; LastMousePos = mMsg.Pos; TmpModel = Some model}, + Cmd.batch [ symbolCmd (Symbol.SelectSymbols newComponents) + wireCmd (BusWire.SelectWires newWires) + Cmd.ofMsg msg] + + | Connection connId -> + let msg = + if model.IsWaveSim then + ToggleNet ([], [BusWire.extractConnection model.Wire connId]) + else DoNothing + + if model.Toggle + then + let newWires = + if List.contains connId model.SelectedWires + then List.filter (fun cId -> cId <> connId) model.SelectedWires // If component selected was already in the list, remove it + else connId :: model.SelectedWires // If user clicked on a new component add it to the selected list + + { model with SelectedWires = newWires; Action = Idle; TmpModel = Some model; PrevWireSelection = model.SelectedWires}, + Cmd.batch [wireCmd (BusWire.SelectWires newWires); Cmd.ofMsg msg] + else + { model with SelectedComponents = []; SelectedWires = [ connId ]; Action = MovingWire connId; TmpModel=Some model}, + Cmd.batch [ symbolCmd (Symbol.SelectSymbols []) + wireCmd (BusWire.SelectWires [ connId ]) + wireCmd (BusWire.DragWire (connId, mMsg)) + wireCmd (BusWire.ResetJumps [ connId ] ) + Cmd.ofMsg msg] + | Canvas -> + let newComponents, newWires = + if model.Toggle + then model.SelectedComponents, model.SelectedWires //do not deselect if in toggle mode + else [], [] + // Start Creating Selection Box and Reset Selected Components + let initialiseSelection = {model.DragToSelectBox with X=mMsg.Pos.X; Y=mMsg.Pos.Y} + {model with DragToSelectBox = initialiseSelection; Action = Selecting; SelectedComponents = newComponents; SelectedWires = newWires }, + Cmd.batch [ symbolCmd (Symbol.SelectSymbols newComponents) + wireCmd (BusWire.SelectWires newWires) ] + +/// Mouse Drag Update, can be: drag-to-selecting, moving symbols, connecting wire between ports. +let mDragUpdate (model: Model) (mMsg: MouseT) : Model * Cmd = + match model.Action with + | MovingWire connId -> model, wireCmd (BusWire.DragWire (connId, mMsg)) + | Selecting -> + let initialX = model.DragToSelectBox.X + let initialY = model.DragToSelectBox.Y + let newDragToSelectBox = {model.DragToSelectBox with W = (mMsg.Pos.X - initialX); H = (mMsg.Pos.Y - initialY)} + {model with DragToSelectBox = newDragToSelectBox + ScrollingLastMousePos = {Pos=mMsg.Pos;Move=mMsg.Movement} + LastMousePos = mMsg.Pos + }, Cmd.ofMsg CheckAutomaticScrolling + | InitialiseMoving _ -> + let movingWires = BusWire.getConnectedWires model.Wire model.SelectedComponents + let newModel, cmd = moveSymbols model mMsg + newModel, Cmd.batch [ cmd; wireCmd (BusWire.ResetJumps movingWires) ] + | MovingSymbols | DragAndDrop -> + moveSymbols model mMsg + | ConnectingInput _ -> + let nearbyComponents = findNearbyComponents model mMsg.Pos + let _, nearbyOutputPorts = findNearbyPorts model + + let targetPort, drawLineTarget = + match mouseOnPort nearbyOutputPorts mMsg.Pos 12.5 with + | Some (OutputPortId portId, portLoc) -> (portId, portLoc) // If found target, snap target of the line to the port + | None -> ("", mMsg.Pos) + + { model with + NearbyComponents = nearbyComponents + ConnectPortsLine = (fst model.ConnectPortsLine, drawLineTarget) + TargetPortId = targetPort + LastMousePos = mMsg.Pos + ScrollingLastMousePos = {Pos=mMsg.Pos;Move=mMsg.Movement}} + , Cmd.ofMsg CheckAutomaticScrolling + | ConnectingOutput _ -> + let nearbyComponents = findNearbyComponents model mMsg.Pos + let nearbyInputPorts, _ = findNearbyPorts model + + let targetPort, drawLineTarget = + match mouseOnPort nearbyInputPorts mMsg.Pos 12.5 with + | Some (InputPortId portId, portLoc) -> (portId, portLoc) // If found target, snap target of the line to the port + | None -> ("", mMsg.Pos) + + { model with + NearbyComponents = nearbyComponents + ConnectPortsLine = (fst model.ConnectPortsLine, drawLineTarget) + TargetPortId = targetPort + LastMousePos = mMsg.Pos + ScrollingLastMousePos = {Pos=mMsg.Pos;Move=mMsg.Movement} } + , Cmd.ofMsg CheckAutomaticScrolling + | _ -> model, Cmd.none + +/// Mouse Up Update, can have: finished drag-to-select, pressed on a component, finished symbol movement, connected a wire between ports +let mUpUpdate (model: Model) (mMsg: MouseT) : Model * Cmd = // mMsg is currently un-used, but kept for future possibilities + let newModel = + match model.TmpModel with + | None -> model + | Some newModel -> newModel + + match model.Action with + | MovingWire connId -> + { model with Action = Idle ; UndoList = appendUndoList model.UndoList newModel; RedoList = [] }, + Cmd.batch [ wireCmd (BusWire.DragWire (connId, mMsg)) + wireCmd (BusWire.MakeJumps [ connId ] ) ] + | Selecting -> + let newComponents = findIntersectingComponents model model.DragToSelectBox + let newWires = BusWire.getIntersectingWires model.Wire model.DragToSelectBox + let resetDragToSelectBox = {model.DragToSelectBox with H = 0.0; W = 0.0} + let selectComps, selectWires = + if model.Toggle + then + symDiff newComponents model.SelectedComponents, symDiff newWires model.SelectedWires + else newComponents, newWires + + { model with DragToSelectBox = resetDragToSelectBox; Action = Idle; SelectedComponents = selectComps; SelectedWires = selectWires; AutomaticScrolling = false }, + Cmd.batch [ symbolCmd (Symbol.SelectSymbols selectComps) + wireCmd (BusWire.SelectWires selectWires) ] + + | InitialiseMoving compId -> // If user clicked on a component and never moved it, then select that component instead. (resets multi-selection as well) + { model with Action = Idle; SelectedComponents = [ compId ]; SelectedWires = [] }, + Cmd.batch [ symbolCmd (Symbol.SelectSymbols [ compId ]) + wireCmd (BusWire.SelectWires []) ] + | MovingSymbols -> + // Reset Movement State in Model + match model.ErrorComponents with + | [] -> + let movingWires = BusWire.getConnectedWires model.Wire model.SelectedComponents + {model with + // BoundingBoxes = Symbol.getBoundingBoxes model.Wire.Symbol + Action = Idle + Snap = {XSnap = None; YSnap = None} + SnapIndicator = {XLine = None; YLine = None } + UndoList = appendUndoList model.UndoList newModel + RedoList = [] + AutomaticScrolling = false }, + wireCmd (BusWire.MakeJumps movingWires) + | _ -> + let movingWires = BusWire.getConnectedWires model.Wire model.SelectedComponents + {model with + BoundingBoxes = model.LastValidBoundingBoxes + Action = Idle + Snap = {XSnap = None; YSnap = None} + SnapIndicator = {XLine = None; YLine = None } + AutomaticScrolling = false }, + Cmd.batch [ symbolCmd (Symbol.MoveSymbols (model.SelectedComponents, (posDiff model.LastValidPos mMsg.Pos))) + symbolCmd (Symbol.SelectSymbols (model.SelectedComponents)) + wireCmd (BusWire.UpdateWires (model.SelectedComponents, posDiff model.LastValidPos mMsg.Pos)) + wireCmd (BusWire.MakeJumps movingWires) ] + | ConnectingInput inputPortId -> + let cmd, undoList ,redoList = + if model.TargetPortId <> "" // If a target has been found, connect a wire + then wireCmd (BusWire.AddWire (inputPortId, (OutputPortId model.TargetPortId))), + appendUndoList model.UndoList newModel, [] + else Cmd.none , model.UndoList , model.RedoList + {model with Action = Idle; TargetPortId = ""; UndoList = undoList ; RedoList = redoList ; AutomaticScrolling = false }, cmd + | ConnectingOutput outputPortId -> + let cmd , undoList , redoList = + if model.TargetPortId <> "" // If a target has been found, connect a wire + then wireCmd (BusWire.AddWire (InputPortId model.TargetPortId, outputPortId)), + appendUndoList model.UndoList newModel , [] + else Cmd.none , model.UndoList , model.RedoList + { model with Action = Idle; TargetPortId = ""; UndoList = undoList ; RedoList = redoList ; AutomaticScrolling = false }, cmd + | _ -> model, Cmd.none + +/// Mouse Move Update, looks for nearby components and looks if mouse is on a port +let mMoveUpdate (model: Model) (mMsg: MouseT) : Model * Cmd = + match model.Action with + | DragAndDrop -> moveSymbols model mMsg + | InitialisedCreateComponent (compType, lbl) -> + let labelTest = if lbl = "" then Symbol.generateLabel model.Wire.Symbol compType else lbl + let newSymbolModel, newCompId = Symbol.addSymbol model.Wire.Symbol mMsg.Pos compType labelTest + + { model with Wire = { model.Wire with Symbol = newSymbolModel } + Action = DragAndDrop + SelectedComponents = [ newCompId ] + SelectedWires = [] + LastMousePos = mMsg.Pos + ScrollingLastMousePos = {Pos=mMsg.Pos;Move=mMsg.Movement} }, + Cmd.batch [ Cmd.ofMsg UpdateBoundingBoxes + symbolCmd (Symbol.SelectSymbols []) + symbolCmd (Symbol.PasteSymbols [ newCompId ]) ] + | _ -> + let nearbyComponents = findNearbyComponents model mMsg.Pos // TODO Group Stage: Make this more efficient, update less often etc, make a counter? + + let newCursor = + match model.CursorType with + | Spinner -> Spinner + | _ -> + match mouseOn { model with NearbyComponents = nearbyComponents } mMsg.Pos with // model.NearbyComponents can be outdated e.g. if symbols have been deleted -> send with updated nearbyComponents. + | InputPort _ | OutputPort _ -> ClickablePort // Change cursor if on port + | _ -> Default + + { model with NearbyComponents = nearbyComponents; CursorType = newCursor; LastMousePos = mMsg.Pos; ScrollingLastMousePos = {Pos=mMsg.Pos;Move=mMsg.Movement} }, + symbolCmd (Symbol.ShowPorts nearbyComponents) // Show Ports of nearbyComponents + +let getScreenCentre (model : Model) : XYPos = + let canvas = document.getElementById "Canvas" + { + X = (canvas.scrollLeft + canvas.clientWidth / 2.0) / model.Zoom + Y = (canvas.scrollTop + canvas.clientHeight / 2.0) / model.Zoom + } + +/// Update Function +let update (msg : Msg) (model : Model): Model*Cmd = + match msg with + | Wire wMsg -> + let wModel, wCmd = BusWire.update wMsg model.Wire + { model with Wire = wModel }, Cmd.map Wire wCmd + | ToggleGrid -> + {model with ShowGrid = not model.ShowGrid}, Cmd.none + | KeyPress DEL -> + let wiresConnectedToComponents = BusWire.getConnectedWires model.Wire model.SelectedComponents + // Ensure there are no duplicate deletions by using a Set + let wireUnion = + Set.union (Set.ofList wiresConnectedToComponents) (Set.ofList model.SelectedWires) + |> Set.toList + + // let inputPorts, outputPorts = BusWire.getPortIdsOfWires model.Wire wireUnion + { model with SelectedComponents = []; SelectedWires = []; UndoList = appendUndoList model.UndoList model ; RedoList = [] }, + Cmd.batch [ wireCmd (BusWire.DeleteWires wireUnion) // Delete Wires before components so nothing bad happens + symbolCmd (Symbol.DeleteSymbols model.SelectedComponents) + Cmd.ofMsg UpdateBoundingBoxes ] + | KeyPress CtrlS -> // For Demo, Add a new square in upper left corner + { model with BoundingBoxes = Symbol.getBoundingBoxes model.Wire.Symbol; UndoList = appendUndoList model.UndoList model ; RedoList = []}, + Cmd.batch [ symbolCmd (Symbol.AddSymbol ({X = 50.0; Y = 50.0}, And, "test 1")); Cmd.ofMsg UpdateBoundingBoxes ] // Need to update bounding boxes after adding a symbol. + | KeyPress AltShiftZ -> + TimeHelpers.printStats() + model, Cmd.none + | KeyPress CtrlC -> + model, + Cmd.batch [ + symbolCmd (Symbol.CopySymbols model.SelectedComponents) // Better to have Symbol keep track of clipboard as symbols can get deleted before pasting. + wireCmd (BusWire.CopyWires model.SelectedWires) + ] + | KeyPress CtrlV -> + let newSymbolModel, pastedCompIds = Symbol.pasteSymbols model.Wire.Symbol model.LastMousePos // Symbol has Copied Symbols stored + let newBusWireModel, pastedConnIds = BusWire.pasteWires { model.Wire with Symbol = newSymbolModel } pastedCompIds + + { model with Wire = newBusWireModel + SelectedComponents = pastedCompIds + SelectedWires = pastedConnIds + TmpModel = Some model + Action = DragAndDrop }, + Cmd.batch [ Cmd.ofMsg UpdateBoundingBoxes + symbolCmd (Symbol.SelectSymbols []) // Select to unhighlight all other symbols + symbolCmd (Symbol.PasteSymbols pastedCompIds) + wireCmd (BusWire.SelectWires []) + wireCmd (BusWire.ColorWires (pastedConnIds, HighLightColor.Thistle)) ] + | KeyPress ESC -> // Cancel Pasting Symbols, and other possible actions in the future + match model.Action with + | DragAndDrop -> + { model with SelectedComponents = [] + SelectedWires = [] + Snap = {XSnap = None; YSnap = None} + SnapIndicator = {XLine = None; YLine = None } + Action = Idle }, + Cmd.batch [ symbolCmd (Symbol.DeleteSymbols model.SelectedComponents) + wireCmd (BusWire.DeleteWires model.SelectedWires) + Cmd.ofMsg UpdateBoundingBoxes ] + | _ -> model, Cmd.none + | KeyPress CtrlZ -> + match model.UndoList with + | [] -> model , Cmd.none + | prevModel :: lst -> + let symModel = { prevModel.Wire.Symbol with CopiedSymbols = model.Wire.Symbol.CopiedSymbols } + let wireModel = { prevModel.Wire with CopiedWX = model.Wire.CopiedWX ; Symbol = symModel} + { prevModel with Wire = wireModel ; UndoList = lst ; RedoList = model :: model.RedoList ; CurrentKeyPresses = Set.empty } , Cmd.none + | KeyPress CtrlY -> + match model.RedoList with + | [] -> model , Cmd.none + | newModel :: lst -> { newModel with UndoList = model :: model.UndoList ; RedoList = lst} , Cmd.none + | KeyPress CtrlA -> + let symbols = model.Wire.Symbol.Symbols |> Map.toList |> List.map fst + let wires = model.Wire.WX |> Map.toList |> List.map fst + { model with + SelectedComponents = symbols + SelectedWires = wires + } , Cmd.batch [ symbolCmd (Symbol.SelectSymbols symbols) + wireCmd (BusWire.SelectWires wires) ] + | KeyPress CtrlW -> + match canvasDiv with + | None -> model, Cmd.none + | Some el -> + let paras = fitCircuitToWindowParas model + el.scrollTop <- paras.ScrollY + el.scrollLeft <- paras.ScrollX + { model with Zoom = paras.MagToUse}, Cmd.ofMsg (UpdateScrollPos (el.scrollLeft, el.scrollTop)) + | ToggleSelectionOpen -> + //if List.isEmpty model.SelectedComponents && List.isEmpty model.SelectedWires then + // model, Cmd.none + //else + {model with Toggle = true}, Cmd.none + | ToggleSelectionClose -> + {model with Toggle = false}, Cmd.none + + | MouseMsg mMsg -> // Mouse Update Functions can be found above, update function got very messy otherwise + //printf "%A" mMsg + match mMsg.Op with + | Down -> mDownUpdate model mMsg + | Drag -> mDragUpdate model mMsg + | Up -> mUpUpdate model mMsg + | Move -> mMoveUpdate model mMsg + | UpdateBoundingBoxes -> { model with BoundingBoxes = Symbol.getBoundingBoxes model.Wire.Symbol }, Cmd.none + | UpdateSingleBoundingBox compId -> + match Map.containsKey compId model.BoundingBoxes with + | true -> {model with BoundingBoxes = model.BoundingBoxes.Add (compId, (Symbol.getOneBoundingBox model.Wire.Symbol compId))}, Cmd.none + | false -> model, Cmd.none + | UpdateScrollPos (scrollX, scrollY) -> + let scrollDif = posDiff { X = scrollX; Y = scrollY } model.ScrollPos + let newLastScrollingPos = + { + Pos = + { + X = model.ScrollingLastMousePos.Pos.X + scrollDif.X / model.Zoom + Y = model.ScrollingLastMousePos.Pos.Y + scrollDif.Y / model.Zoom + } + Move = model.ScrollingLastMousePos.Move + } + let cmd = + if model.AutomaticScrolling then + Cmd.ofMsg CheckAutomaticScrolling // Also check if there is automatic scrolling to continue + else + Cmd.none + { model with ScrollPos = { X = scrollX; Y = scrollY }; ScrollingLastMousePos = newLastScrollingPos }, cmd + | KeyPress ZoomIn -> + { model with Zoom = model.Zoom + 0.05 }, Cmd.ofMsg (KeepZoomCentered model.LastMousePos) + | KeyPress ZoomOut -> + let leftScreenEdge, rightScreenEdge,_,_ = getScreenEdgeCoords() + //Check if the new zoom will exceed the canvas width + let newZoom = + if rightScreenEdge - leftScreenEdge < (DrawHelpers.canvasUnscaledSize * (model.Zoom - 0.05)) then model.Zoom - 0.05 + else model.Zoom + + { model with Zoom = newZoom }, Cmd.ofMsg (KeepZoomCentered model.LastMousePos) + | KeepZoomCentered oldScreenCentre -> + let canvas = document.getElementById "Canvas" + let newScreenCentre = getScreenCentre model + let requiredOffset = posDiff oldScreenCentre newScreenCentre + + // Update screen so that the zoom is centred around the middle of the screen. + canvas.scrollLeft <- canvas.scrollLeft + requiredOffset.X * model.Zoom + canvas.scrollTop <- canvas.scrollTop + requiredOffset.Y * model.Zoom + + model, Cmd.none + | ManualKeyDown key -> // Needed for e.g. Ctrl + C and Ctrl + V as they are not picked up by Electron + let newPressedKeys = model.CurrentKeyPresses.Add (key.ToUpper()) // Make it fully upper case to remove CAPS dependency + let newCmd = + match Set.contains "CONTROL" newPressedKeys || Set.contains "META" newPressedKeys with + | true -> + if Set.contains "C" newPressedKeys then + Cmd.ofMsg (KeyPress CtrlC) + elif Set.contains "V" newPressedKeys then + Cmd.ofMsg (KeyPress CtrlV) + elif Set.contains "A" newPressedKeys then + Cmd.ofMsg (KeyPress CtrlA) + elif Set.contains "W" newPressedKeys then + Cmd.ofMsg (KeyPress CtrlW) + else + Cmd.none + | false -> Cmd.none + + { model with CurrentKeyPresses = newPressedKeys }, newCmd + | ManualKeyUp key -> { model with CurrentKeyPresses = model.CurrentKeyPresses.Remove (key.ToUpper()) }, Cmd.none + | CheckAutomaticScrolling -> + let canvas = document.getElementById "Canvas" + let wholeApp = document.getElementById "WholeApp" + let rightSelection = document.getElementById "RightSelection" + + let leftScreenEdge = canvas.scrollLeft + let rightScreenEdge = leftScreenEdge + wholeApp.clientWidth - rightSelection.clientWidth + let upperScreenEdge = canvas.scrollTop + let lowerScreenEdge = upperScreenEdge + canvas.clientHeight + let mPosX = model.ScrollingLastMousePos.Pos.X * model.Zoom // Un-compensate for zoom as we want raw distance from mouse to edge screen + let mPosY = model.ScrollingLastMousePos.Pos.Y * model.Zoom // Un-compensate for zoom as we want raw distance from mouse to edge screen + let mMovX = model.ScrollingLastMousePos.Move.X + let mMovY = model.ScrollingLastMousePos.Move.Y + /// no scrolling if too far from edge, or if moving away from edge + let checkForAutomaticScrolling1D (edge: float) (mPos: float) (mMov: float) = + let scrollMargin = 100.0 + let scrollSpeed = 10.0 + let edgeDistance = abs (edge - mPos) + + if edgeDistance < scrollMargin && mMov >= -0.0000001 // just in case there are FP rounding errors + then scrollSpeed * (scrollMargin - edgeDistance) / scrollMargin // Speed should be faster the closer the mouse is to the screen edge + else 0.0 + + canvas.scrollLeft <- canvas.scrollLeft - (checkForAutomaticScrolling1D leftScreenEdge mPosX -mMovX) // Check left-screen edge + canvas.scrollLeft <- canvas.scrollLeft + (checkForAutomaticScrolling1D rightScreenEdge mPosX mMovX) // Check right-screen edge + canvas.scrollTop <- canvas.scrollTop - (checkForAutomaticScrolling1D upperScreenEdge mPosY -mMovY) // Check upper-screen edge + canvas.scrollTop <- canvas.scrollTop + (checkForAutomaticScrolling1D lowerScreenEdge mPosY mMovY) // Check lower-screen edge + let xDiff = canvas.scrollLeft - leftScreenEdge + let yDiff = canvas.scrollTop - upperScreenEdge + + if xDiff <> 0.0 || yDiff <> 0.0 then // Did any automatic scrolling happen? + let newMPos = { X = model.LastMousePos.X + xDiff / model.Zoom ; Y = model.LastMousePos.Y + yDiff / model.Zoom } + // Need to update mouse movement as well since the scrolling moves the mouse relative to the canvas, but no actual mouse movement will be detected. + // E.g. a moving symbol should stick to the mouse as the automatic scrolling happens and not lag behind. + let outputModel, outputCmd = + match model.Action with + | DragAndDrop -> + mMoveUpdate { model with AutomaticScrolling = true } { Pos = newMPos; Op = Move; Movement = {X=0.;Y=0.}} + | MovingSymbols | ConnectingInput _ | ConnectingOutput _ | Selecting -> + mDragUpdate { model with AutomaticScrolling = true } { Pos = newMPos; Op = Drag; Movement = {X=0.;Y=0.}} + | _ -> + { model with AutomaticScrolling = true }, Cmd.none + + // Don't want to go into an infinite loop (program would crash), don't check for automatic scrolling immediately (let it be handled by OnScroll listener). + let filteredOutputCmd = Cmd.map (fun msg -> if msg <> CheckAutomaticScrolling then msg else DoNothing) outputCmd + // keep model ScrollPos uptodate with real scrolling position + let outputModel = {outputModel with ScrollPos = {X = canvas.scrollLeft; Y = canvas.scrollTop}} + + outputModel, filteredOutputCmd + else + { model with AutomaticScrolling = false}, Cmd.none + + // ---------------------------- Issie Messages ---------------------------- // + + | InitialiseCreateComponent (compType, lbl) -> + { model with Action = (InitialisedCreateComponent (compType, lbl)) ; TmpModel = Some model}, Cmd.none + | FlushCommandStack -> { model with UndoList = []; RedoList = []; TmpModel = None }, Cmd.none + | ResetModel -> + { model with + BoundingBoxes = Map.empty + LastValidBoundingBoxes = Map.empty + SelectedComponents = [] + SelectedWires = [] + NearbyComponents = [] + ErrorComponents = [] + DragToSelectBox = {X=0.0; Y=0.0; H=0.0; W=0.0} + ConnectPortsLine = {X=0.0; Y=0.0}, {X=0.0; Y=0.0} + TargetPortId = "" + Action = Idle + LastMousePos = { X = 0.0; Y = 0.0 } + Snap = { XSnap = None; YSnap = None} + SnapIndicator = { XLine = None; YLine = None } + //ScrollPos = { X = 0.0; Y = 0.0 } Fix for scroll bug on changing sheets + LastValidPos = { X = 0.0; Y = 0.0 } + CurrentKeyPresses = Set.empty + UndoList = [] + RedoList = [] + TmpModel = None + Zoom = 1.0 + AutomaticScrolling = false + ScrollingLastMousePos = {Pos={ X = 0.0; Y = 0.0 };Move={X=0.0; Y=0.0}} + MouseCounter = 0 + LastMousePosForSnap = { X = 0.0; Y = 0.0 } + }, Cmd.none + | UpdateSelectedWires (connIds, on) -> + let oldWires = model.SelectedWires + let newWires = + if on then oldWires @ connIds + else List.filter (fun conId -> List.contains conId connIds |> not) oldWires + {model with SelectedWires = newWires}, wireCmd (BusWire.SelectWires newWires) + | ColourSelection (compIds, connIds, colour) -> + {model with SelectedComponents = compIds; SelectedWires = connIds}, + Cmd.batch [ + symbolCmd (Symbol.ColorSymbols (compIds, colour)) // Better to have Symbol keep track of clipboard as symbols can get deleted before pasting. + wireCmd (BusWire.ColorWires (connIds, colour)) + ] + | ResetSelection -> + {model with SelectedComponents = []; SelectedWires = []}, + Cmd.batch [ + symbolCmd (Symbol.SelectSymbols []) // Better to have Symbol keep track of clipboard as symbols can get deleted before pasting. + wireCmd (BusWire.SelectWires []) + ] + | SetWaveSimMode mode -> + {model with IsWaveSim = mode}, Cmd.none + | SelectWires cIds -> + //If any of the cIds of the netgroup given are inside the previous selection (not current as this will always be true) + //then deselect (remove from the selected list) any wires from the selected list that are in that cId list + //otherwise add the cId list to the selectedwires model + let newWires = + if List.exists (fun cId -> List.contains cId model.PrevWireSelection) cIds then + List.filter (fun cId -> List.contains cId cIds |> not) model.PrevWireSelection + else + List.append cIds model.PrevWireSelection + {model with SelectedWires = newWires}, Cmd.batch [Cmd.ofMsg (ColourSelection([], newWires, HighLightColor.Blue)); wireCmd (BusWire.SelectWires newWires)] + | SetSpinner isOn -> + if isOn then {model with CursorType = Spinner}, Cmd.none + else {model with CursorType = Default}, Cmd.none + + | ToggleNet _ | DoNothing | _ -> model, Cmd.none + + +/// This function zooms an SVG canvas by transforming its content and altering its size. +/// Currently the zoom expands based on top left corner. +let displaySvgWithZoom (model: Model) (headerHeight: float) (style: CSSProp list) (svgReact: ReactElement List) (dispatch: Dispatch)= + // Hacky way to get keypresses such as Ctrl+C to work since Electron does not pick them up. + document.onkeydown <- (fun key -> + if key.which = 32.0 then// Check for spacebar + key.preventDefault() // Disable scrolling with spacebar + dispatch <| (ManualKeyDown key.key) + else + dispatch <| (ManualKeyDown key.key) ) + document.onkeyup <- (fun key -> dispatch <| (ManualKeyUp key.key)) + + let sizeInPixels = sprintf "%.2fpx" ((DrawHelpers.canvasUnscaledSize * model.Zoom)) + + /// Is the mouse button currently down? + let mDown (ev:Types.MouseEvent) = ev.buttons <> 0. + + /// Dispatch a MouseMsg (compensated for zoom) + let mouseOp op (ev:Types.MouseEvent) = + //printfn "%s" $"Op:{ev.movementX},{ev.movementY}" + dispatch <| MouseMsg { + Op = op ; + Movement = {X= ev.movementX;Y=ev.movementY} + Pos = { + X = (ev.pageX + model.ScrollPos.X) / model.Zoom ; + Y = (ev.pageY - headerHeight + model.ScrollPos.Y) / model.Zoom} + } + // dispatch <| MouseMsg {Op = op ; Pos = { X = (ev.pageX + model.ScrollPos.X) / model.Zoom ; Y = (ev.pageY - topMenuBarHeight + model.ScrollPos.Y) / model.Zoom }} + let scrollUpdate () = + let canvas = document.getElementById "Canvas" + dispatch <| UpdateScrollPos (canvas.scrollLeft, canvas.scrollTop) // Add the new scroll offset to the model + let wheelUpdate (ev: Types.WheelEvent) = + if Set.contains "CONTROL" model.CurrentKeyPresses then + // ev.preventDefault() + if ev.deltaY > 0.0 then // Wheel Down + dispatch <| KeyPress ZoomOut + else + dispatch <| KeyPress ZoomIn + else () // Scroll normally if Ctrl is not held down + let cursorText = model.CursorType.Text() + + div [ HTMLAttr.Id "Canvas" + Key cursorText // force cursor change to be rendered + Style (CSSProp.Cursor cursorText :: style) + OnMouseDown (fun ev -> (mouseOp Down ev)) + OnMouseUp (fun ev -> (mouseOp Up ev)) + OnMouseMove (fun ev -> mouseOp (if mDown ev then Drag else Move) ev) + OnScroll (fun _ -> scrollUpdate ()) + Ref (fun el -> + canvasDiv <- Some el + if not (isNull el) then + // in case this element is newly created, set scroll position from model + el.scrollLeft <- model.ScrollPos.X + el.scrollTop <- model.ScrollPos.Y) + OnWheel wheelUpdate + ] + [ + svg + [ Style + [ + Height sizeInPixels + Width sizeInPixels + ] + ] + [ g // group list of elements with list of attributes + [ Style [Transform (sprintf "scale(%f)" model.Zoom)]] // top-level transform style attribute for zoom + svgReact // the application code + ] + ] + +/// View function, displays symbols / wires and possibly also a grid / drag-to-select box / connecting ports line / snap-to-grid visualisation +let view (model:Model) (headerHeight: float) (style) (dispatch : Msg -> unit) = + let start = TimeHelpers.getTimeMs() + let wDispatch wMsg = dispatch (Wire wMsg) + let wireSvg = BusWire.view model.Wire wDispatch + + let wholeCanvas = $"{max 100.0 (100.0 / model.Zoom)}" + "%" + let grid = + svg [ SVGAttr.Width wholeCanvas; SVGAttr.Height wholeCanvas; SVGAttr.XmlSpace "http://www.w3.org/2000/svg" ] [ + defs [] [ + pattern [ + Id "Grid" + SVGAttr.Width $"{gridSize}" + SVGAttr.Height $"{gridSize}" + SVGAttr.PatternUnits "userSpaceOnUse" + ] [ + path [ + SVGAttr.D $"M {gridSize} 0 L 0 0 0 {gridSize}" + SVGAttr.Fill "None" + SVGAttr.Stroke "Gray" + SVGAttr.StrokeWidth "0.5" + ] [] + ] + ] + rect [SVGAttr.Width wholeCanvas; SVGAttr.Height wholeCanvas; SVGAttr.Fill "url(#Grid)"] [] + ] + + let dragToSelectBox = + let {BoundingBox.X=fX; Y=fY; H=fH; W=fW} = model.DragToSelectBox + let polygonPoints = $"{fX},{fY} {fX+fW},{fY} {fX+fW},{fY+fH} {fX},{fY+fH}" + let selectionBox = { defaultPolygon with Stroke = "Black"; StrokeWidth = "0.1px"; Fill = "Blue"; FillOpacity = 0.05 } + + makePolygon polygonPoints selectionBox + + let snapIndicatorLine = { defaultLine with Stroke = "Red"; StrokeWidth = "0.5px"; StrokeDashArray = "5, 5" } + + let connectingPortsWire = + let connectPortsLine = { defaultLine with Stroke = "Green"; StrokeWidth = "2.0px"; StrokeDashArray = "5, 5" } + let {XYPos.X = x1; Y = y1}, {XYPos.X = x2; Y = y2} = model.ConnectPortsLine + [ makeLine x1 y1 x2 y2 connectPortsLine + makeCircle x2 y2 { portCircle with Fill = "Green" } + ] + + let snapIndicatorLineX = + match model.SnapIndicator.XLine with + | Some xPos -> + [ makeLine xPos 0.0 xPos wholeCanvas snapIndicatorLine ] + | None -> + [] + + let snapIndicatorLineY = + match model.SnapIndicator.YLine with + | Some yPos -> + [ makeLine 0.0 yPos wholeCanvas yPos snapIndicatorLine ] + | None -> + [] + + let displayElements = + if model.ShowGrid + then [ grid; wireSvg ] + else [ wireSvg ] + + match model.Action with // Display differently depending on what state Sheet is in + | Selecting -> + displaySvgWithZoom model headerHeight style ( displayElements @ [ dragToSelectBox ] ) dispatch + | ConnectingInput _ | ConnectingOutput _ -> + displaySvgWithZoom model headerHeight style ( displayElements @ connectingPortsWire ) dispatch + | MovingSymbols | DragAndDrop -> + displaySvgWithZoom model headerHeight style ( displayElements @ snapIndicatorLineX @ snapIndicatorLineY ) dispatch + | _ -> + displaySvgWithZoom model headerHeight style displayElements dispatch + |> TimeHelpers.instrumentInterval "SheetView" start + +/// Init function +let init () = + let wireModel, cmds = (BusWire.init ()) + let boundingBoxes = Symbol.getBoundingBoxes wireModel.Symbol + + { + Wire = wireModel + BoundingBoxes = boundingBoxes + LastValidBoundingBoxes = boundingBoxes + SelectedComponents = [] + SelectedWires = [] + NearbyComponents = [] + ErrorComponents = [] + DragToSelectBox = {X=0.0; Y=0.0; H=0.0; W=0.0} + ConnectPortsLine = {X=0.0; Y=0.0}, {X=0.0; Y=0.0} + TargetPortId = "" + Action = Idle + ShowGrid = true + LastMousePos = { X = 0.0; Y = 0.0 } + Snap = { XSnap = None; YSnap = None} + SnapIndicator = { XLine = None; YLine = None } + CursorType = Default + ScrollPos = { X = 0.0; Y = 0.0 } + LastValidPos = { X = 0.0; Y = 0.0 } + CurrentKeyPresses = Set.empty + UndoList = [] + RedoList = [] + TmpModel = None + Zoom = 1.0 + AutomaticScrolling = false + ScrollingLastMousePos = {Pos={ X = 0.0; Y = 0.0 }; Move={X = 0.0; Y =0.0}} + MouseCounter = 0 + LastMousePosForSnap = { X = 0.0; Y = 0.0 } + Toggle = false + IsWaveSim = false + PrevWireSelection = [] + }, Cmd.none diff --git a/src/Renderer/DrawBlock/Symbol.fs b/src/Renderer/DrawBlock/Symbol.fs new file mode 100644 index 0000000..3b077f3 --- /dev/null +++ b/src/Renderer/DrawBlock/Symbol.fs @@ -0,0 +1,1053 @@ +(* +This module draws schematics component symbols. Each symbol is associated with a unique Issie component. +*) + +module Symbol +open Fable.React +open Fable.React.Props +open Elmish +open DrawHelpers +open CommonTypes +open System.Text.RegularExpressions + + +/// --------- STATIC VARIABLES --------- /// + +let GridSize = 30 + +/// ---------- SYMBOL TYPES ---------- /// +type Symbol = + { + Pos: XYPos + InWidth0: int option + InWidth1: int option + Id : ComponentId + Compo : Component + Colour: string + ShowInputPorts: bool + ShowOutputPorts: bool + Opacity: float + Moving: bool + } + +type Model = { + Symbols: Map + CopiedSymbols: Map + Ports: Map // string since it's for both input and output ports + + InputPortsConnected: Set // we can use a set since we only care if an input port + // is connected or not (if so it is included) in the set + + OutputPortsConnected: Map // map of output port id to number of wires connected to that port + } + +//----------------------------Message Type-----------------------------------// + + +type Msg = + | MouseMsg of MouseT + | AddSymbol of pos:XYPos * compType:ComponentType * lbl: string + | CopySymbols of ComponentId list + | DeleteSymbols of sIds:ComponentId list + | ShowAllInputPorts | ShowAllOutputPorts | DeleteAllPorts + | MoveSymbols of compList: ComponentId list * move: XYPos + | ShowPorts of ComponentId list + | SelectSymbols of ComponentId list// Issie interface + | SymbolsHaveError of sIds: ComponentId list + | ChangeLabel of sId : ComponentId * newLabel : string + | PasteSymbols of sIds: ComponentId list + | ColorSymbols of compList : ComponentId list * colour : HighLightColor + | ErrorSymbols of errorIds: ComponentId list * selectIds: ComponentId list * isDragAndDrop: bool + | ChangeNumberOfBits of compId:ComponentId * NewBits:int + | ChangeLsb of compId: ComponentId * NewBits:int64 + | ChangeConstant of compId: ComponentId * NewBits:int64 * NewText:string + | ResetModel // For Issie Integration + | LoadComponents of Component list // For Issie Integration + | WriteMemoryLine of ComponentId * int64 * int64 // For Issie Integration + | WriteMemoryType of ComponentId * ComponentType + +//---------------------------------helper types and functions----------------// + +let posDiff (a:XYPos) (b:XYPos) = + {X=a.X-b.X; Y=a.Y-b.Y} + +let posAdd (a:XYPos) (b:XYPos) = + {X=a.X+b.X; Y=a.Y+b.Y} + +let posOf x y = {X=x;Y=y} + + +// ----- helper functions for titles ----- // + +///Insert titles compatible with greater than 1 buswidth +let title t (n) = + if n = 1 then t else t + "(" + string(n-1) + "..0)" + +///Insert titles for bus select +let bustitle wob lsb = + if wob <> 1 then"(" + string(wob + lsb - 1) + ".." + string(lsb) + ")" else string(lsb) + +///Decodes the component type into component labels +let prefix compType = + match compType with + | Not | And | Or | Xor | Nand | Nor | Xnor -> "G" + | Mux2 -> "MUX" + | Demux2 -> "DM" + | NbitsAdder _ -> "A" + | NbitsXor _ -> "XOR" + | DFF | DFFE -> "FF" + | Register _ | RegisterE _ -> "REG" + | AsyncROM1 _ -> "AROM" + | ROM1 _ -> "ROM" + | RAM1 _ -> "RAM" + | AsyncRAM1 _ -> "ARAM" + | Custom c -> + c.Name + (if c.Name |> Seq.last |> System.Char.IsDigit then "." else "") + | Constant1 _ -> "C" + | BusCompare _ -> "EQ" + | Decode4 -> "DEC" + | BusSelection _ -> "SEL" + | _ -> "" + + +//-----------------------------Skeleton Model Type for symbols----------------// + +// Text to be put inside different Symbols depending on their ComponentType +let gateDecoderType (comp:Component) = + match comp.Type with + | And | Nand-> "&" + | Or | Nor-> "≥1" + | Xor | Xnor -> "=1" + | Not -> "1" + | Decode4 -> "Decode" + | NbitsAdder n -> title "Adder" n + | Register n | RegisterE n-> title "Register" n + | AsyncROM1 _ -> "Async-ROM" + | ROM1 _ -> "Sync-ROM" + | RAM1 _ -> "Sync-RAM" + | AsyncRAM1 _ -> "Async-RAM" + | DFF -> "DFF" + | DFFE -> "DFFE" + | NbitsXor (x)-> title "N-bits-Xor" x + | Custom x -> x.Name + | _ -> "" + +// Input and Output names of the ports depending on their ComponentType +let portDecName (comp:Component) = //(input port names, output port names) + match comp.Type with + | Decode4 -> (["Sel";"Data"],["0"; "1";"2"; "3"]) + | NbitsAdder _ -> (["Cin";"A";"B"],["Sum "; "Cout"]) + | Register _ -> (["D"],["Q"]) + | RegisterE _ -> (["D"; "EN"],["Q"]) + | ROM1 _ |AsyncROM1 _ -> (["Addr"],["Dout"]) + | RAM1 _ -> (["Addr"; "Din";"Wen" ],["Dout"]) + | AsyncRAM1 _ -> (["Addr"; "Din";"Wen" ],["Dout"]) + | DFF -> (["D"],["Q"]) + | DFFE -> (["D";"EN"],["Q"]) + | Mux2 -> (["0"; "1";"SEL"],["OUT"]) + | Demux2 -> (["IN" ; "SEL"],["0"; "1"]) + | NbitsXor _ -> (["P"; "Q"], ["Out"]) + | Custom x -> (List.map fst x.InputLabels), (List.map fst x.OutputLabels) + |_ -> ([],[]) + // |Mux4 -> (["0"; "1"; "2"; "3" ;"SEL"],["OUT"]) + // |Demux4 -> (["IN"; "SEL"],["0"; "1";"2"; "3";]) + // |Demux8 -> (["IN"; "SEL"],["0"; "1"; "2" ; "3" ; "4" ; "5" ; "6" ; "7"]) + // |Mux8 -> (["0"; "1"; "2" ; "3" ; "4" ; "5" ; "6" ; "7";"SEL"],["OUT"]) + // |_ -> ([],[]) + // EXTENSION: Extra Components made that are not currently in Issie. Can be extended later by using this code as it is . + +/// Genererates a list of ports: +let portLists numOfPorts hostID portType = + if numOfPorts < 1 + then [] + else + [0..(numOfPorts-1)] + |> List.collect (fun x -> + [{ + Id = JSHelpers.uuid () + PortNumber = Some x + PortType = portType + HostId = hostID + }]) + + +//-----------------------Skeleton Message type for symbols---------------------// + +///Rounds an integer to any given number. The first parameter is the number to round to, the second parameter is the input number that will be rounded +let roundToN (n : int) (x : int) = + x + abs((x % n) - n) + +let customToLength (lst : (string * int) list) = + let labelList = List.map (fst >> String.length) lst + if List.isEmpty labelList then 0 //if a component has no inputs or outputs list max will fail + else List.max labelList + +// helper function to initialise each type of component +let makeComp (pos: XYPos) (comptype: ComponentType) (id:string) (label:string) : Component = + + // function that helps avoid dublicate code by initialising parameters that are the same for all component types and takes as argument the others + let makeComponent (n, nout, h, w) label : Component= + { + Id = id + Type = comptype + Label = label + InputPorts = portLists n id PortType.Input + OutputPorts = portLists nout id PortType.Output + X = int (pos.X - float w / 2.0) + Y = int (pos.Y - float h / 2.0) + H = h + W = w + } + + // match statement for each component type. the output is a 4-tuple that is used as an input to makecomponent (see below) + // 4-tuple of the form ( number of input ports, number of output ports, Height, Width) + let args = + match comptype with + | ROM _ | RAM _ | AsyncROM _ -> + failwithf "What? Legacy RAM component types should never occur" + | And | Nand | Or | Nor | Xnor | Xor -> (2 , 1, 2*GridSize , 2*GridSize) + | Not -> ( 1 , 1, 2*GridSize , 2*GridSize) + | ComponentType.Input (a) -> ( 0 , 1, GridSize , 2*GridSize) + | ComponentType.Output (a) -> ( 1 , 0, GridSize , 2*GridSize) + | ComponentType.Viewer a -> ( 1 , 0, GridSize , GridSize) + | ComponentType.IOLabel ->( 1 , 1, GridSize , 2*GridSize) + | Decode4 ->( 2 , 4 , 4*GridSize , 3*GridSize) + | Constant1 (a, b,_) | Constant(a, b) -> ( 0 , 1, GridSize , 2*GridSize) + | MergeWires -> ( 2 , 1, 2*GridSize , 2*GridSize) + | SplitWire (a) ->( 1 , 2 , 2*GridSize , 2*GridSize) + | Mux2 -> ( 3 , 1, 3*GridSize , 2*GridSize) + // EXTENSION: | Mux4 -> ( 5 , 1, 5*GridSize , 2*GridSize) + // EXTENSION: | Mux8 -> ( 9 , 1, 7*GridSize , 2*GridSize) + | Demux2 ->( 2 , 2, 3*GridSize , 2*GridSize) + // EXTENSION: | Demux4 -> ( 2 , 4, 150 , 50) + // EXTENSION: | Demux8 -> ( 2 , 8, 200 , 50) + | BusSelection (a, b) -> ( 1 , 1, GridSize, 2*GridSize) + | BusCompare (a, b) -> ( 1 , 1, GridSize , 2*GridSize) + | DFF -> ( 1 , 1, 3*GridSize , 3*GridSize) + | DFFE -> ( 2 , 1, 3*GridSize , 3*GridSize) + | Register (a) -> ( 1 , 1, 3*GridSize , 4*GridSize ) + | RegisterE (a) -> ( 2 , 1, 3*GridSize , 4*GridSize) + | AsyncROM1 (a) -> ( 1 , 1, 3*GridSize , 4*GridSize) + | ROM1 (a) -> ( 1 , 1, 3*GridSize , 4*GridSize) + | RAM1 (a) | AsyncRAM1 a -> ( 3 , 1, 3*GridSize , 4*GridSize) + | NbitsXor (n) -> ( 2 , 1, 3*GridSize , 4*GridSize) + | NbitsAdder (n) -> ( 3 , 2, 3*GridSize , 4*GridSize) + | Custom x -> + let h = GridSize + GridSize * (List.max [List.length x.InputLabels; List.length x.OutputLabels]) + let maxInLength, maxOutLength = customToLength x.InputLabels, customToLength x.OutputLabels + let maxW = maxInLength + maxOutLength + label.Length + let scaledW = roundToN GridSize (maxW * GridSize / 5) //Divide by 5 is just abitrary as otherwise the symbols would be too wide + let w = max scaledW (GridSize * 4) //Ensures a minimum width if the labels are very small + ( List.length x.InputLabels, List.length x.OutputLabels, h , w) + + makeComponent args label + +// Function to generate a new symbol +let createNewSymbol (pos: XYPos) (comptype: ComponentType) (label:string) = + let id = JSHelpers.uuid () + let comp = makeComp pos comptype id label + { + Pos = { X = pos.X - float comp.W / 2.0; Y = pos.Y - float comp.H / 2.0 } + ShowInputPorts = false + ShowOutputPorts = false + InWidth0 = None // set by BusWire + InWidth1 = None + Colour = "lightgrey" + Id = ComponentId id + Compo = comp + Opacity = 1.0 + Moving = false + } + +// Function to add ports to port model +let addToPortModel (model: Model) (sym: Symbol) = + let addOnePort (currentPorts: Map) (port: Port) = + Map.add port.Id port currentPorts + + let addedInputPorts = (model.Ports, sym.Compo.InputPorts) ||> List.fold addOnePort + (addedInputPorts, sym.Compo.OutputPorts) ||> List.fold addOnePort + +//-----------------------------------------GET PORT POSITION--------------------------------------------------- +// Function that calculates the positions of the ports + +/// hack so that bounding box of splitwire, mergewires can be smaller height relative to ports +let inline getPortPosEdgeGap (ct: ComponentType) = + match ct with + | MergeWires | SplitWire _ -> 0.25 + | _ -> 1.0 + +let getPortPos (comp: Component) (port:Port) = + let (ports, posX) = + if port.PortType = (PortType.Input) then + (comp.InputPorts, 0.0) + else + (comp.OutputPorts, float( comp.W )) + let index = float( List.findIndex (fun (p:Port) -> p = port) ports ) + let gap = getPortPosEdgeGap comp.Type + let posY = (float(comp.H))* (( index + gap )/( float( ports.Length ) + 2.0*gap - 1.0)) // the ports are created so that they are equidistant + {X = posX; Y = posY} +let getPortPosModel (model: Model) (port:Port) = + getPortPos (Map.find (ComponentId port.HostId) model.Symbols).Compo port + + +//-----------------------------------------DRAWING HELPERS --------------------------------------------------- +// Text adding function with many parameters (such as bold, position and text) +let private addText posX posY name txtPos weight size= + let text = + {defaultText with TextAnchor = txtPos; FontWeight = weight; FontSize = size} + [makeText posX posY name text] + +// Generate circles +let private portCircles x y = + [makeCircle x y portCircle] +// Define the name of each port +let private portText x y name portType= + let xPos = + if portType = PortType.Output + then x - 5. + else x + 5. + let test = if portType = PortType.Output then "end" else "start" + (addText xPos (y - 7.0) name test "normal" "12px") + +// Print the name of each port +let private drawPortsText (portList: Port List) (listOfNames: string List) (comp: Component)= + if listOfNames.Length < 1 + then [] + else + [0..(portList.Length-1)] + |> List.map2 (fun name x -> (portText (getPortPos comp portList[x]).X (getPortPos comp portList[x]).Y name (portList.Head.PortType))) listOfNames + |> List.collect id + +// Function to draw ports using getPortPos. The ports are equidistant +let private drawPorts (portList: Port List) (printPorts:bool) (comp: Component)= + if (portList.Length) < 1 + then [] + else + if printPorts + then [0..(portList.Length-1)] |> List.collect (fun x -> (portCircles (getPortPos comp portList[x]).X (getPortPos comp portList[x]).Y)) + else [] + +//------------------------------HELPER FUNCTIONS FOR DRAWING SYMBOLS------------------------------------- +let private createPolygon points colour opacity = + [makePolygon points {defaultPolygon with Fill = colour; FillOpacity = opacity}] + +let createBiColorPolygon points colour strokeColor opacity strokeWidth= + if strokeColor <> "black" then + [makePolygon points {defaultPolygon with Fill = colour; Stroke = strokeColor; FillOpacity = opacity; StrokeWidth=strokeWidth}] + else + [makePolygon points {defaultPolygon with Fill = colour; FillOpacity = opacity; StrokeWidth = strokeWidth}] + +let addInvertor posX posY colour opacity = + let points = (sprintf "%i,%i %i,%i %i,%i" posX (posY) (posX+9) (posY) posX (posY-8)) + createPolygon points colour opacity + +let addClock posX posY colour opacity = + let points = (sprintf "%i,%i %i,%i %i,%i" posX (posY-1) (posX+8) (posY-7) posX (posY-13)) + createPolygon points colour opacity + |> List.append (addText (float(posX+10)) (float(posY-13)) " clk" "start" "normal" "12px") + +let addHorizontalLine posX1 posX2 posY opacity = // TODO: Line instead of polygon? + let points = (sprintf "%i,%f %i,%f" posX1 posY posX2 posY) + createPolygon points "lightgray" opacity + +let outlineColor (color:string) = + match color.ToLower() with + | "lightgray" | "lightgrey" -> "black" + | c -> + printfn $"color={color}" + c + +let addHorizontalColorLine posX1 posX2 posY opacity (color:string) = // TODO: Line instead of polygon? + let points = (sprintf "%i,%f %i,%f" posX1 posY posX2 posY) + let olColor = outlineColor color + [makePolygon points {defaultPolygon with Fill = "olcolor"; Stroke=olColor; StrokeWidth = "2.0"; FillOpacity = opacity}] + + + +/// --------------------------------------- SYMBOL DRAWING ------------------------------------------------------ /// + +let compSymbol (symbol:Symbol) (comp:Component) (colour:string) (showInputPorts:bool) (showOutputPorts:bool) (opacity: float)= + let h = comp.H + let w = comp.W + let halfW = comp.W/2 + let halfH = (comp.H)/2 + + let mergeSplitLine posX1 posX2 posY msb lsb = + let text = + match msb = lsb, msb >= lsb with + | _, false -> "" + | true, _ -> sprintf $"({msb})" + | false, _ -> sprintf $"({msb}:{lsb})" + addHorizontalColorLine posX1 posX2 (posY*float(h)) opacity colour @ + addText (float (posX1 + posX2)/2.0) (posY*float(h)-11.0) text "middle" "bold" "9px" + + + + let points = // Points that specify each symbol + match comp.Type with + | Input _ -> (sprintf "%i,%i %i,%i %f,%i %i,%i %f,%i" 0 0 0 h (float(w)*(0.66)) h w halfH (float(w)*(0.66)) 0) + | Constant1 _ -> (sprintf "%i,%i %i,%i %i,%i" 0 comp.H halfW halfH 0 0) + | IOLabel -> (sprintf "%f,%i %i,%i %f,%i %f,%i %i,%i %f,%i" (float(w)*(0.33)) 0 0 halfH (float(w)*(0.33)) h (float(w)*(0.66)) h w halfH (float(w)*(0.66)) 0) + | Output _ -> (sprintf "%f,%i %i,%i %f,%i %i,%i %i,%i" (float(w)*(0.2)) 0 0 halfH (float(w)*(0.2)) h w h w 0) + | Viewer _ -> (sprintf "%f,%i %i,%i %f,%i %i,%i %i,%i" (float(w)*(0.2)) 0 0 halfH (float(w)*(0.2)) h w h w 0) + | MergeWires -> (sprintf "%i,%f %i,%f " halfW ((1.0/6.0)*float(h)) halfW ((5.0/6.0)*float(h))) + | SplitWire _ -> (sprintf "%i,%f %i,%f " halfW ((1.0/6.0)*float(h)) halfW ((5.0/6.0)*float(h))) + | Demux2 -> (sprintf "%i,%f %i,%f %i,%i %i,%i" 0 (float(h)*0.2) 0 (float(h)*0.8) w h w 0) + | Mux2 -> (sprintf "%i,%i %i,%f %i,%f %i,%i" 0 0 w (float(h)*0.2) w (float(h)*0.8) 0 h ) + // EXTENSION: |Mux4|Mux8 ->(sprintf "%i,%i %i,%f %i,%f %i,%i" 0 0 w (float(h)*0.2) w (float(h)*0.8) 0 h ) + // EXTENSION: | Demux4 |Demux8 -> (sprintf "%i,%f %i,%f %i,%i %i,%i" 0 (float(h)*0.2) 0 (float(h)*0.8) w h w 0) + | BusSelection _ |BusCompare _ -> (sprintf "%i,%i %i,%i %f,%i %f,%f %i,%f %i,%f %f,%f %f,%i ")0 0 0 h (0.6*float(w)) h (0.8*float(w)) (0.7*float(h)) w (0.7*float(h)) w (0.3*float(h)) (0.8*float(w)) (0.3*float(h)) (0.6*float(w)) 0 + | _ -> (sprintf "%i,%i %i,%i %i,%i %i,%i" 0 (comp.H) comp.W (comp.H) comp.W 0 0 0) + let additions = // Helper function to add certain characteristics on specific symbols (inverter, enables, clocks) + match comp.Type with + | Constant1 (_,_,txt) -> (addHorizontalLine halfW w (float(halfH)) opacity @ addText (float (halfW)-5.0) (float(h)-8.0) txt "middle" "normal" "12px") + | Nand | Nor | Xnor |Not -> (addInvertor w halfH colour opacity) + | MergeWires -> + let lo, hi = + match symbol.InWidth0, symbol.InWidth1 with + | Some n, Some m -> n, m + | _ -> -1,-1 + let msb = hi + lo - 1 + let midb = lo + let midt = lo - 1 + mergeSplitLine 0 halfW (1.0/6.0) midt 0 @ + mergeSplitLine 0 halfW (5.0/6.0) msb midb @ + mergeSplitLine halfW w 0.5 msb 0 + | SplitWire mid -> + let msb, mid' = match symbol.InWidth0 with | Some n -> n - 1, mid | _ -> -100, -50 + let midb = mid' + let midt = mid'-1 + mergeSplitLine halfW w (1.0/6.0) midt 0 @ + mergeSplitLine halfW w (5.0/6.0) msb midb @ + mergeSplitLine 0 halfW 0.5 msb 0 + | DFF |DFFE -> (addClock 0 h colour opacity) + | Register _ |RegisterE _ -> (addClock 0 h colour opacity) + | ROM1 _ |RAM1 _ | AsyncRAM1 _ -> (addClock 0 h colour opacity) + | BusSelection(x,y) -> (addText (float(w/2)-5.0) ((float(h)/2.7)-2.0) (bustitle x y) "middle" "normal" "12px") + | BusCompare (_,y) -> (addText (float(w/2)-6.0) (float(h)/2.7-1.0) ("=" + NumberHelpers.hex(int y)) "middle" "bold" "10px") + | Input (x) -> (addText (float(w/2)-5.0) ((float(h)/2.7)-3.0) (title "" x) "middle" "normal" "12px") + | Output (x) -> (addText (float(w/2)) ((float(h)/2.7)-3.0) (title "" x) "middle" "normal" "12px") + | Viewer (x) -> (addText (float(w/2)) ((float(h)/2.7)-1.25) (title "" x) "middle" "normal" "9px") + | _ -> [] + + let olColour, strokeWidth = + match comp.Type with + | SplitWire _ | MergeWires -> outlineColor colour, "2.0" + | _ -> "black", "1.0" + + // Put everything together + + (drawPorts comp.OutputPorts showOutputPorts comp) + |> List.append (drawPorts comp.InputPorts showInputPorts comp) + |> List.append (drawPortsText comp.InputPorts (fst(portDecName comp)) comp) + |> List.append (drawPortsText comp.OutputPorts (snd(portDecName comp)) comp) + |> List.append (addText (float halfW) (+5.0) (gateDecoderType comp) "middle" "bold" "14px") + |> List.append (addText (float halfW) (-20.0) comp.Label "middle" "normal" "16px") + |> List.append (additions) + |> List.append (createBiColorPolygon points colour olColour opacity strokeWidth) + +let init () = + { Symbols = Map.empty; CopiedSymbols = Map.empty; Ports = Map.empty ; InputPortsConnected= Set.empty ; OutputPortsConnected = Map.empty}, Cmd.none + +//----------------------------View Function for Symbols----------------------------// +type private RenderSymbolProps = + { + Symbol : Symbol + Dispatch : Dispatch + key: string + } + +/// View for one symbol. Using FunctionComponent.Of to improve efficiency (not printing all symbols but only those that are changing) +let private renderSymbol = + + FunctionComponent.Of( + fun (props : RenderSymbolProps) -> + let symbol = props.Symbol + let ({X=fX; Y=fY}:XYPos) = symbol.Pos + g ([ Style [ Transform(sprintf "translate(%fpx, %fpx)" fX fY) ] ]) (compSymbol props.Symbol props.Symbol.Compo symbol.Colour symbol.ShowInputPorts symbol.ShowOutputPorts symbol.Opacity) + + , "Symbol" + , equalsButFunctions + ) + +/// View function for symbol layer of SVG +let MapsIntoLists map = + let listMoving = + Map.filter (fun _ sym -> not sym.Moving) map + |>Map.toList + |>List.map snd + let listNotMoving = + Map.filter (fun _ sym -> sym.Moving) map + |>Map.toList + |>List.map snd + listMoving @ listNotMoving + + +let view (model : Model) (dispatch : Msg -> unit) = + let start = TimeHelpers.getTimeMs() + model.Symbols + |> MapsIntoLists + |> List.map (fun ({Id = ComponentId id} as symbol) -> + renderSymbol + { + Symbol = symbol + Dispatch = dispatch + key = id + } + ) + |> ofList + |> TimeHelpers.instrumentInterval "SymbolView" start + +//------------------------GET BOUNDING BOXES FUNCS--------------------------------used by sheet. +// Function that returns the bounding box of a symbol. It is defined by the height and the width as well as the x,y position of the symbol +let getBoundingBoxofSymbol (sym:Symbol): BoundingBox = + {X = float(sym.Pos.X) ; Y = float(sym.Pos.Y) ; H = float(sym.Compo.H) ; W = float(sym.Compo.W)} + +let getBoundingBoxes (symModel: Model): Map = + Map.map (fun sId (sym:Symbol) -> (getBoundingBoxofSymbol sym)) symModel.Symbols + +let getOneBoundingBox (symModel: Model) (compid: ComponentId ): BoundingBox = + let symb = Map.find compid symModel.Symbols + getBoundingBoxofSymbol symb + + +//--------------------- GETTING PORTS AND THEIR LOCATIONS INTERFACE FUNCTIONS------------------------------- +// Helpers +let getSymbolPos (symbolModel: Model) compId = + let symbol = Map.find compId symbolModel.Symbols + symbol.Pos + +/// This is quite slow, because it gets the whole maps. +/// It is used in getInputPortLocation for a single port!! +/// Bad +let getInputPortsPositionMap (model: Model) (symbols: Symbol list) = + symbols + |> List.collect (fun sym -> List.map (fun p -> sym,p) sym.Compo.InputPorts) + |> List.map (fun (sym,port) -> (InputPortId port.Id, posAdd (getPortPosModel model port) (sym.Pos))) + |> Map.ofList + +/// This is quite slow, because it gets the whole maps. +/// It is used in getOutputPortLocation for a single port!! +/// Bad +let getOutputPortsPositionMap (model: Model) (symbols: Symbol list) = //These function add the coordinates of the symbol too + symbols + |> List.collect (fun sym -> List.map (fun p -> sym,p) sym.Compo.OutputPorts) + |> List.map (fun (sym,port) -> (OutputPortId port.Id , posAdd (getPortPosModel model port) (sym.Pos))) + |> Map.ofList + +///Returns the port object associated with a given portId +let getPort (symModel: Model) (portId: string) = + symModel.Ports[portId] + +///Returns all the port locations of the given components +let getPortLocations (symbolModel: Model) (sIds: ComponentId list) = + let getSymbols = + symbolModel.Symbols + |> Map.filter (fun sId sym -> List.contains sId sIds) + |> Map.toList + |> List.map snd + + let getInputPortMap = getInputPortsPositionMap symbolModel getSymbols + let getOutputPortMap = getOutputPortsPositionMap symbolModel getSymbols + + getInputPortMap , getOutputPortMap + +///Returns the location of an input portId +let getInputPortLocation (model:Model) (portId: InputPortId) = + let allSymbols = + model.Symbols + |> Map.toList + |> List.map snd + + getInputPortsPositionMap model allSymbols + |> Map.find (portId) + + +//Returns the location of an output portId +let getOutputPortLocation (model:Model) (portId : OutputPortId) = + let allSymbols = + model.Symbols + |> Map.toList + |> List.map snd + + getOutputPortsPositionMap model allSymbols + |> Map.find (portId) + +///Returns the location of a given portId +let getOnePortLocation (symModel: Model) (portId : string) (pType: PortType)= + match pType with + | PortType.Input -> + getInputPortLocation symModel (InputPortId portId) + | PortType.Output -> + getOutputPortLocation symModel (OutputPortId portId) + +/// Returns the location of a given portId, with better efficiency +/// This is still slow, the ports should be looked up from a map of ports +let getOnePortLocationNew (symModel: Model) (portId : string) (pType: PortType) : XYPos= + symModel.Symbols + |> Map.pick (fun key sym -> + let comp = sym.Compo + if pType = PortType.Input then + List.tryFind (fun (po:Port) -> po.Id = portId) comp.InputPorts + else + List.tryFind (fun (po:Port) -> po.Id = portId) comp.OutputPorts + |> Option.map (fun port -> posAdd (getPortPosModel symModel port) (sym.Pos))) + + +/// Returns the locations of a given input portId and output portId +let getTwoPortLocations (symModel: Model) (inPortId: InputPortId ) (outPortId: OutputPortId) = + match inPortId, outPortId with + | InputPortId inputId, OutputPortId outputId -> + (getOnePortLocationNew symModel inputId PortType.Input, getOnePortLocationNew symModel outputId PortType.Output) + +/// Interface function to get componentIds of the copied symbols +let getCopiedSymbols (symModel: Model) : (ComponentId list) = + symModel.CopiedSymbols + |> Map.toList + |> List.map fst + +/// Function to filter out terminal non-letter characters. +/// Modified to capitalise labels +let filterString (string: string) = + string.ToUpper() + |> Seq.rev + |> Seq.skipWhile System.Char.IsDigit + |> Seq.rev + |> Seq.map System.Char.ToString + |> String.concat "" + +///Returns the number of the component label (i.e. the number 1 from IN1 or ADDER16.1) +let regex (str : string) = + let index = Regex.Match(str, @"\d+$") + match index with + | null -> 0 + | _ -> int index.Value + +let getCompList compType listSymbols = + match compType with + | Not | And | Or | Xor | Nand | Nor | Xnor -> + listSymbols + |> List.filter (fun sym -> + (sym.Compo.Type = Not || sym.Compo.Type = And + || sym.Compo.Type = Or || sym.Compo.Type = Xor + || sym.Compo.Type = Nand || sym.Compo.Type = Nor + || sym.Compo.Type = Xnor) + ) + | DFF | DFFE -> + listSymbols + |> List.filter (fun sym -> + (sym.Compo.Type = DFF || sym.Compo.Type = DFFE)) + //The following components require this pattern matching in order to correctly identify all of the components in the circuit of that type + //Normally this is because they are defined by a width as well as a type + | Register _ | RegisterE _ -> + listSymbols + |> List.filter (fun sym -> + match sym.Compo.Type with + | Register _ | RegisterE _ -> true + | _ -> false) + | Constant1 _ -> + listSymbols + |> List.filter (fun sym -> + match sym.Compo.Type with + | Constant1 _ -> true + | _ -> false) + | Input _ -> + listSymbols + |> List.filter (fun sym -> + match sym.Compo.Type with + | Input _ -> true + | _ -> false) + | Output _ -> + listSymbols + |> List.filter (fun sym -> + match sym.Compo.Type with + | Output _ -> true + | _ -> false) + | Viewer _ -> + listSymbols + |> List.filter (fun sym -> + match sym.Compo.Type with + | Viewer _ -> true + | _ -> false) + | BusSelection _ -> + listSymbols + |> List.filter (fun sym -> + match sym.Compo.Type with + | BusSelection _ -> true + | _ -> false) + | BusCompare _ -> + listSymbols + |> List.filter (fun sym -> + match sym.Compo.Type with + | BusCompare _ -> true + | _ -> false) + | NbitsAdder _ -> + listSymbols + |> List.filter (fun sym -> + match sym.Compo.Type with + | NbitsAdder _ -> true + | _ -> false) + | NbitsXor _ -> + listSymbols + |> List.filter (fun sym -> + match sym.Compo.Type with + | NbitsXor _ -> true + | _ -> false) + | AsyncROM1 _ -> + listSymbols + |> List.filter (fun sym -> + match sym.Compo.Type with + | AsyncROM1 _ -> true + | _ -> false) + | ROM1 _ -> + listSymbols + |> List.filter (fun sym -> + match sym.Compo.Type with + | ROM1 _ -> true + | _ -> false) + | RAM1 _ -> + listSymbols + |> List.filter (fun sym -> + match sym.Compo.Type with + | RAM1 _ -> true + | _ -> false) + | AsyncRAM1 _ -> + listSymbols + |> List.filter (fun sym -> + match sym.Compo.Type with + | AsyncRAM1 _ -> true + | _ -> false) + + | _ -> + listSymbols + |> List.filter (fun sym -> sym.Compo.Type = compType) + +let getIndex listSymbols compType = + let symbolList = + getCompList compType listSymbols + + match compType with + | MergeWires | SplitWire _ -> "" + | _ -> + if List.isEmpty symbolList then 1 + else symbolList + |> List.map (fun sym -> regex sym.Compo.Label) + |> List.max + |> (+) 1 + |> string + +///Generates the number to be put in the title of symbols +let labelGenNumber (model: Model) (compType: ComponentType) (label : string) = + let listSymbols = List.map snd (Map.toList model.Symbols) + match compType with + | IOLabel -> label + | _ -> filterString label + (getIndex listSymbols compType) + +///Generates the label for a component type +let generateLabel (model: Model) (compType: ComponentType) : string = + labelGenNumber model compType (prefix compType) + +/// Interface function to paste symbols. Is a function instead of a message because we want an output +/// Currently drag-and-drop +let pasteSymbols (symModel: Model) (mPos: XYPos) : (Model * ComponentId list) = + let createNewSymbol (basePos: XYPos) ((currSymbolModel, pastedIdsList) : Model * ComponentId List) (oldSymbol: Symbol): Model * ComponentId List = + let newId = JSHelpers.uuid() + let posDiff = posDiff oldSymbol.Pos basePos + let newPos = posAdd posDiff mPos + + let pastedSymbol = + { oldSymbol with + Id = ComponentId newId + Compo = makeComp newPos oldSymbol.Compo.Type newId (labelGenNumber { symModel with Symbols = currSymbolModel.Symbols } oldSymbol.Compo.Type oldSymbol.Compo.Label) // TODO: Change label later + Pos = newPos + ShowInputPorts = false + ShowOutputPorts = false } + + let newSymbolMap = currSymbolModel.Symbols.Add ((ComponentId newId), pastedSymbol) // List needs to be in this order + let newPorts = addToPortModel currSymbolModel pastedSymbol + { currSymbolModel with Symbols = newSymbolMap; Ports = newPorts }, pastedIdsList @ [ pastedSymbol.Id ] + + let oldSymbolsList = + symModel.CopiedSymbols + |> Map.toList + |> List.map snd + + match List.sortBy (fun sym -> sym.Pos.X) oldSymbolsList with + | baseSymbol :: _ -> + let basePos = posAdd baseSymbol.Pos { X = (float baseSymbol.Compo.W) / 2.0; Y = (float baseSymbol.Compo.H) / 2.0 } + + ((symModel, []), oldSymbolsList) ||> List.fold (createNewSymbol basePos) + | [] -> symModel, [] + + +/// Given two componentId list of same length and input / output ports that are in list 1, return the equivalent ports in list 2. +/// ComponentIds at same index in both list 1 and list 2 need to be of the same ComponentType +/// CompIds1 need to be in model.CopiedSymbols +let getEquivalentCopiedPorts (model: Model) (copiedIds) (pastedIds) (InputPortId copiedInputPort, OutputPortId copiedOutputPort) = + let findEquivalentPorts compId1 compId2 = + let copiedComponent = model.CopiedSymbols[compId1].Compo + let pastedComponent = model.Symbols[compId2].Compo // TODO: These can be different for an output gate for some reason. + + let tryFindEquivalentPort (copiedPorts: Port list) (pastedPorts: Port list) targetPort = + if copiedPorts.Length = 0 || pastedPorts.Length = 0 + then None + else + match List.tryFindIndex ( fun (port: Port) -> port.Id = targetPort ) copiedPorts with + | Some portIndex -> + + Some pastedPorts[portIndex].Id // Get the equivalent port in pastedPorts. Assumes ports at the same index are the same (should be the case unless copy pasting went wrong). + | _ -> None + + let pastedInputPortId = tryFindEquivalentPort copiedComponent.InputPorts pastedComponent.InputPorts copiedInputPort + let pastedOutputPortId = tryFindEquivalentPort copiedComponent.OutputPorts pastedComponent.OutputPorts copiedOutputPort + + pastedInputPortId, pastedOutputPortId + + let foundPastedPorts = + List.zip copiedIds pastedIds + |> List.map (fun (compId1, compId2) -> findEquivalentPorts compId1 compId2) + + let foundPastedInputPort = List.collect (function | Some a, _ -> [a] | _ -> []) foundPastedPorts + let foundPastedOutputPort = List.collect (function | _, Some b -> [b] | _ -> []) foundPastedPorts + + match foundPastedInputPort, foundPastedOutputPort with + | [pastedInputPort], [pastedOutputPort] -> Some (pastedInputPort, pastedOutputPort) + | _ -> None // If either of source or target component of the wire was not copied then we discard the wire + + +/// Given a model return a model with a new Symbol and also the component id +let addSymbol (model: Model) pos compType lbl = + let newSym = createNewSymbol pos compType lbl + let newPorts = addToPortModel model newSym + let newSymModel = Map.add newSym.Id newSym model.Symbols + { model with Symbols = newSymModel; Ports = newPorts }, newSym.Id + +// Helper function to change the number of bits expected in a port of each component type +let changeNumberOfBitsf (symModel:Model) (compId:ComponentId) (newBits : int) = + + let symbol = Map.find compId symModel.Symbols + let newcompotype = + match symbol.Compo.Type with + | Input _ -> Input newBits + | Output _ -> Output newBits + | Viewer _ -> Viewer newBits + | NbitsAdder _ -> NbitsAdder newBits + | NbitsXor _ -> NbitsXor newBits + | Register _ -> Register newBits + | RegisterE _ -> RegisterE newBits + | SplitWire _ -> SplitWire newBits + | BusSelection (_,b) -> BusSelection (newBits,b) + | BusCompare (_,b) -> BusCompare (newBits,b) + | Constant1 (_,b,txt) -> Constant1 (newBits,b,txt) + | c -> c + + let newcompo = {symbol.Compo with Type = newcompotype} + {symbol with Compo = newcompo} + +// Helper function to change the number of bits expected in the LSB port of BusSelection and BusCompare +let changeLsbf (symModel:Model) (compId:ComponentId) (newLsb:int64) = + let symbol = Map.find compId symModel.Symbols + let newcompotype = + match symbol.Compo.Type with + | BusSelection (w, _) -> BusSelection (w, int32(newLsb)) + | BusCompare (w, _) -> BusCompare (w, uint32(newLsb)) + | Constant1(w, _,txt) -> Constant1 (w, newLsb,txt) + | _ -> failwithf "this shouldnt happen, incorrect call of message changeLsb" + let newcompo = {symbol.Compo with Type = newcompotype} + {symbol with Compo = newcompo} + +let changeConstantf (symModel:Model) (compId:ComponentId) (constantVal:int64) (constantText: string) = + let symbol = Map.find compId symModel.Symbols + let newcompotype = + match symbol.Compo.Type with + | Constant1 (w, _, _) -> Constant1 (w, constantVal,constantText) + | _ -> failwithf "this shouldnt happen, incorrect call of message changeLsb" + let newcompo = {symbol.Compo with Type = newcompotype} + printfn "Changing symbol to: %A" newcompotype + {symbol with Compo = newcompo} + +/// update function which displays symbols +let update (msg : Msg) (model : Model): Model*Cmd<'a> = + match msg with + | DeleteSymbols compList -> + let newSymbols = List.fold (fun prevModel sId -> Map.remove sId prevModel) model.Symbols compList + { model with Symbols = newSymbols }, Cmd.none //filters out symbol with a specified id + + | AddSymbol (pos,compType, lbl) -> + let (newModel, _) = addSymbol model pos compType lbl + newModel, Cmd.none + + | CopySymbols compIds -> + let copiedSymbols = Map.filter (fun compId _ -> List.contains compId compIds) model.Symbols + { model with CopiedSymbols = copiedSymbols }, Cmd.none + + | ShowAllInputPorts -> + { model with Symbols = Map.map (fun _ sym -> {sym with ShowInputPorts = true; ShowOutputPorts = false}) model.Symbols }, + Cmd.none + + | ShowAllOutputPorts -> + {model with Symbols = Map.map (fun _ sym -> {sym with ShowInputPorts = false; ShowOutputPorts = true}) model.Symbols }, + Cmd.none + + | DeleteAllPorts -> + { model with Symbols = Map.map (fun _ sym -> {sym with ShowInputPorts = false; ShowOutputPorts = false}) model.Symbols }, + Cmd.none //demo + + | ShowPorts compList -> //show ports of one component (shown in demo for a random component, sheet gives list in group phace) find showPorts in other interfaces (above) + let resetSymbols = Map.map (fun _ sym -> {sym with ShowInputPorts = false; ShowOutputPorts = false}) model.Symbols + let newSymbols = + (List.fold (fun prevSymbols sId -> Map.add sId {resetSymbols[sId] with ShowInputPorts = true; ShowOutputPorts = true} prevSymbols) resetSymbols compList) + { model with Symbols = newSymbols }, Cmd.none + + | MoveSymbols (compList, move) -> + let resetSymbols = Map.map (fun _ sym -> { sym with Moving = false}) model.Symbols + let newSymbols = + (List.fold (fun prevSymbols sId -> + let (newCompo: Component) = {model.Symbols[sId].Compo with X = int (model.Symbols[sId].Pos.X + move.X);Y = int (model.Symbols[sId].Pos.Y + move.Y )} + Map.add sId {model.Symbols[sId] with Moving = true; Pos = {X = (model.Symbols[sId].Pos.X + move.X);Y = (model.Symbols[sId].Pos.Y + move.Y)} ; Compo = newCompo} prevSymbols) resetSymbols compList) + { model with Symbols = newSymbols }, Cmd.none + + | SymbolsHaveError compList -> + let resetSymbols = Map.map (fun _ sym -> {sym with Colour = "Lightgray"}) model.Symbols + let newSymbols = + (List.fold (fun prevSymbols sId -> Map.add sId {resetSymbols[sId] with Colour = "Red"} prevSymbols) resetSymbols compList) + { model with Symbols = newSymbols }, Cmd.none + + | SelectSymbols compList -> //select a symbol (shown in demo for a random component, sheet gives list in group phase) + let resetSymbols = Map.map (fun _ sym -> { sym with Colour = "Lightgray"; Opacity = 1.0 }) model.Symbols + let newSymbols = + (List.fold (fun prevSymbols sId -> Map.add sId {resetSymbols[sId] with Colour = "lightgreen"} prevSymbols) resetSymbols compList) + { model with Symbols = newSymbols }, Cmd.none + + | ErrorSymbols (errorCompList,selectCompList,isDragAndDrop) -> + let resetSymbols = Map.map (fun _ sym -> { sym with Colour = "Lightgray"; Opacity = 1.0 }) model.Symbols + let selectSymbols = + List.fold (fun prevSymbols sId -> + if not isDragAndDrop then + Map.add sId {resetSymbols[sId] with Colour = "lightgreen"} prevSymbols + else + Map.add sId { resetSymbols[sId] with Opacity = 0.2 } prevSymbols + ) resetSymbols selectCompList + let newSymbols = + (List.fold (fun prevSymbols sId -> Map.add sId {resetSymbols[sId] with Colour = "Red"} prevSymbols) selectSymbols errorCompList) + { model with Symbols = newSymbols }, Cmd.none + + | MouseMsg _ -> model, Cmd.none // allow unused mouse messags + + | ChangeLabel (sId, newLabel) -> + let tempsym = Map.find sId model.Symbols + let newcompo = {tempsym.Compo with Label = newLabel} + let addsym = {tempsym with Compo = newcompo} + { model with Symbols = Map.add sId addsym model.Symbols }, Cmd.none + + | PasteSymbols compList -> + let newSymbols = + (List.fold (fun prevSymbols sId -> Map.add sId { model.Symbols[sId] with Opacity = 0.4 } prevSymbols) model.Symbols compList) + { model with Symbols = newSymbols }, Cmd.none + + | ColorSymbols (compList, colour) -> + let newSymbols = + Map.map (fun sId sym -> if List.contains sId compList then {sym with Colour = string colour} else sym) model.Symbols + { model with Symbols = newSymbols }, Cmd.none + + | ChangeNumberOfBits (compId, newBits) -> + let newsymbol = changeNumberOfBitsf model compId newBits + let symbolswithoutone = model.Symbols.Remove compId + let newSymbolsWithChangedSymbol = symbolswithoutone.Add (compId, newsymbol) + { model with Symbols = newSymbolsWithChangedSymbol }, Cmd.none + + | ChangeLsb (compId, newLsb) -> + let newsymbol = changeLsbf model compId newLsb + let symbolswithoutone = model.Symbols.Remove compId + let newSymbolsWithChangedSymbol = symbolswithoutone.Add (compId, newsymbol) + { model with Symbols = newSymbolsWithChangedSymbol }, Cmd.none + + | ChangeConstant (compId, newVal, newText) -> + let newsymbol = changeConstantf model compId newVal newText + let symbolswithoutone = model.Symbols.Remove compId + let newSymbolsWithChangedSymbol = symbolswithoutone.Add (compId, newsymbol) + { model with Symbols = newSymbolsWithChangedSymbol }, Cmd.none + + | ResetModel -> { model with Symbols = Map.empty; Ports = Map.empty }, Cmd.none + + | LoadComponents comps -> + let compIdsWithSymbols = + comps + |> List.map ( fun comp -> ( + let xyPos = {X = float comp.X; Y = float comp.Y} + let (h,w) = + if comp.H = -1 && comp.W = -1 then + let comp' = makeComp xyPos comp.Type comp.Id comp.Label + comp'.H,comp'.W + else + comp.H, comp.W + ComponentId comp.Id, + { Pos = xyPos + ShowInputPorts = false //do not show input ports initially + ShowOutputPorts = false //do not show output ports initially + Colour = "lightgrey" // initial color + Id = ComponentId comp.Id + Compo = {comp with H=h ; W = w} + Opacity = 1.0 + Moving = false + InWidth0 = None + InWidth1 = None + } + )) + let symbolList = + compIdsWithSymbols + |> List.map snd + + let symbolMap = + compIdsWithSymbols + |> Map.ofList + + let folder currModel sym = + { currModel with Ports = addToPortModel currModel sym } + + let newModel = ( model, symbolList ) ||> List.fold folder + { newModel with Symbols = symbolMap }, Cmd.none + + | WriteMemoryLine (compId, addr, value) -> + let symbol = model.Symbols[compId] + let comp = symbol.Compo + + let newCompType = + match comp.Type with + | RAM1 mem -> RAM1 { mem with Data = Map.add addr value mem.Data } + | AsyncRAM1 mem -> AsyncRAM1 { mem with Data = Map.add addr value mem.Data } + | ROM1 mem -> ROM1 { mem with Data = Map.add addr value mem.Data } + | AsyncROM1 mem -> AsyncROM1 { mem with Data = Map.add addr value mem.Data } + | _ -> comp.Type + + let newComp = { comp with Type = newCompType } + + let newSymbols = Map.add compId { symbol with Compo = newComp } model.Symbols + + { model with Symbols = newSymbols }, Cmd.none + | WriteMemoryType (compId, memory) -> + let symbol = model.Symbols[compId] + let comp = symbol.Compo + let newCompType = + match comp.Type with + | RAM1 mem | AsyncRAM1 mem -> memory + | ROM1 mem -> memory + | AsyncROM1 mem -> memory + | _ -> + printfn $"Warning: improper use of WriteMemoryType on {comp} ignored" + comp.Type + + let newComp = { comp with Type = newCompType } + + let newSymbols = Map.add compId { symbol with Compo = newComp } model.Symbols + + { model with Symbols = newSymbols }, Cmd.none + +// ----------------------interface to Issie----------------------------- // +let extractComponent (symModel: Model) (sId:ComponentId) : Component = + symModel.Symbols[sId].Compo + +let extractComponents (symModel: Model) : Component list = + symModel.Symbols + |> Map.toList + |> List.map (fun (key, _) -> extractComponent symModel key) diff --git a/src/Renderer/Interface/Extractor.fs b/src/Renderer/Interface/Extractor.fs new file mode 100644 index 0000000..a532e28 --- /dev/null +++ b/src/Renderer/Interface/Extractor.fs @@ -0,0 +1,82 @@ +module Extractor +open CommonTypes + + + + +/// Transform the CanvasState into an f# data structure, with layout data removed (for checking electrically significant changes). +/// Components and connections are sorted to make them order-invariant - selecting components alters order. +/// This is currently not properly used because the save and autosave logic is not yet properly re-implemented +/// after change to new draw block. +let extractReducedState (state : CanvasState) : CanvasState = + let (components : Component list), (connections : Connection list) = state + let comps = + components + |> List.map (fun comp -> {comp with H=0;W=0;X=0;Y=0}) + |> List.sortBy (fun comp -> comp.Id) + + let conns = + connections + |> List.map (fun conn -> {conn with Vertices = []}) + |> List.sortBy (fun conn -> conn.Id) + comps, conns + +/// Are two lists of vertices identical +let verticesAreSame tolerance (conns1:(float*float) list) (conns2: (float*float) list) = + let sq x = x*x + conns1.Length = conns2.Length && + List.zip conns1 conns2 + |> List.map (fun ((x1,y1),(x2,y2)) -> sq(x1-x2) + sq(y1-y2)) + |> List.sum + |> (fun d -> d < tolerance) + +/// Are two lists of connections identical +let compareConns tolerance conns1 conns2 = + let connIdA (conns:Connection List) = + conns + |> Array.ofList + |> Array.sortBy (fun conn -> conn.Id) + let connsA1 = connIdA conns1 + let connsA2 = connIdA conns2 + connsA1.Length = connsA2.Length && + Array.forall2 (fun c1 c2 -> + verticesAreSame tolerance c1.Vertices c2.Vertices) connsA1 connsA2 + +/// Are two lists of components identical +let compareComps tolerance comps1 comps2 = + let isClose a b = float ((a-b)*(a-b)) < tolerance + let compIdA (comps:Component List) = + comps + |> Array.ofList + |> Array.sortBy (fun comp -> comp.Id) + let compsA1 = compIdA comps1 + let compsA2 = compIdA comps2 + compsA1.Length = compsA2.Length && + Array.forall2 (fun (c1: Component) (c2:Component) -> isClose c1.X c2.X && isClose c1.Y c2.Y) compsA1 compsA2 + +/// Robust comparison of two schematics. Tolerance determines how similar +/// counts as equal. +/// cannot use equality because float vertices may not be identical +/// use to detemine whether schematic needs to be saved +/// NB for electrical circuit comparison use extractReducedState. +let compareCanvas + (tolerance: float) + ((comps1,conns1):CanvasState) + ((comps2,conns2):CanvasState) = + let reduce comps = + comps + |> List.toArray + |> Array.map (fun comp -> {comp with H=0;W=0;X=0;Y=0}) + |> Array.sortBy (fun comp -> comp.Id) + let compsOk = reduce comps1 = reduce comps2 + let compsSamePos = compareComps tolerance comps1 comps2 + let connsOk = compareConns tolerance conns1 conns2 + compsOk && compsSamePos && connsOk + +/// Compare the name and IOs of two sheets as loadedcomponents +/// For backups, if these chnage something major has happened +let compareIOs (ldc1:LoadedComponent) (ldc2:LoadedComponent) = + Set(ldc1.InputLabels) = Set(ldc2.InputLabels) && ldc1.Name = ldc2.Name + + + diff --git a/src/Renderer/Interface/FilesIO.fs b/src/Renderer/Interface/FilesIO.fs new file mode 100644 index 0000000..668743b --- /dev/null +++ b/src/Renderer/Interface/FilesIO.fs @@ -0,0 +1,635 @@ +(* + FilesIO.fs + + Utility functions to interact with files. +*) + +module FilesIO +open Fulma +open Fable.React.Props +open Helpers +open CommonTypes +open Fable.Core +open Fable.Core.JsInterop +open Fable.Import +open ElectronAPI + +open Node +open EEExtensions +open Fable.SimpleJson +open JSHelpers + + +[] +let staticDir() :string = jsNative + +/// absolute path to repo directory ./static +/// NB this path is not fixed (even as relative path) between +/// production and dev builds, so this must be used to access static +/// assets. +let staticFileDirectory = staticDir() + + +let pathJoin args = path.join args +let baseName filePath = path.basename filePath + + +let dirName filePath = path.dirname filePath +let ensureDirectory dPath = + if (not <| fs.existsSync (U2.Case1 dPath)) then + fs.mkdirSync(dPath); + +let pathWithoutExtension filePath = + let ext = path.extname filePath + filePath + |> Seq.rev + |> Seq.skip ext.Length + |> Seq.rev + |> String.ofSeq + +let baseNameWithoutExtension = + pathWithoutExtension >> baseName + +let fileNameIsBad name = + name + |> Seq.filter (fun ch -> not (ch = ' ' || System.Char.IsLetter ch || System.Char.IsDigit ch)) + |> Seq.isEmpty + |> not + +let filePathIsBad = + baseNameWithoutExtension >> fileNameIsBad + +let fileExistsWithExtn extn folderPath baseName = + let path = path.join [| folderPath; baseName + extn |] + fs.existsSync (U2.Case1 path) + +/// Write base64 encoded data to file. +/// Create file if it does not exist. +let writeFileBase64 path data = + let options = createObj ["encoding" ==> "base64"] |> Some + try + fs.writeFileSync(path, data, options) + Ok () + with + | e -> Result.Error $"Error '{e.Message}' writing file '{path}'" + +/// Write utf8 encoded data to file. +/// Create file if it does not exist. +let writeFile path data = + try + let options = createObj ["encoding" ==> "utf8"] |> Some + fs.writeFileSync(path, data, options) + Ok () + with + | e -> Result.Error $"Error '{e.Message}' writing file '{path}'" + + +let readFilesFromDirectory (path:string) : string list = + if fs.existsSync (U2.Case1 path) then + try + fs.readdirSync(U2.Case1 path) + |> Seq.toList + with + | _ -> [] + else + [] + +let hasExtn extn fName = + (String.toLower fName).EndsWith (String.toLower extn) + + +let readFilesFromDirectoryWithExtn (path:string) (extn:string) : string list = + readFilesFromDirectory path + |> List.filter (fun name -> hasExtn extn name) + +let removeExtn extn fName = + if hasExtn extn fName + then Some fName[0..(fName.Length - extn.Length - 1)] + else None + +/// returns the list of backup files in descending chronological order. +let backupFileData (path:string) (baseName: string) = + readFilesFromDirectory path + |> List.filter (fun fn -> String.startsWith (baseName + "-") fn) + |> List.map (fun fn -> + String.splitString [|"-"|] fn + |> Array.tryItem 1 + |> Option.bind (String.tryParseWith System.Int32.TryParse) + |> fun n -> n,fn) + |> List.sortDescending + + + +/// returns the sequence number and name of the most recent (highest sequence number) backup file +let latestBackupFileData (path:string) (baseName: string) = + backupFileData path baseName + |> List.tryHead + |> Option.bind (function + | None,_ -> None + | Some n, fn -> Some(n, fn)) + + + +/// read canvas state from file found on filePath (which includes .dgm suffix etc). +/// return Error if file does not exist or cannot be parsed. +let private tryLoadStateFromPath (filePath: string) = + if not (fs.existsSync (U2.Case1 filePath)) then + Result.Error <| sprintf "Can't read file from %s because it does not seem to exist!" filePath + else + try + Ok (fs.readFileSync(filePath, "utf8")) + with + | e -> Result.Error $"Error {e.Message} reading file '{filePath}'" + + |> Result.map jsonStringToState + |> ( function + | Error msg -> Result.Error <| sprintf "could not convert file '%s' to a valid issie design sheet. Details: %s" filePath msg + | Ok res -> Ok res) + +let makeData aWidth dWidth makeFun = + let truncate n = + match dWidth with + | 64 -> n + | w -> ((1UL <<< w) - 1UL) &&& n + |> int64 + let a = aWidth / 2 + let inp = [|0..(1 <<< a) - 1|] + Array.allPairs inp inp + |> Array.map (fun (x,y) -> int64 ((int64 x <<< a) + int64 y), truncate (uint64 (makeFun x y))) + |> Map.ofArray + + + +let makeFixedROM addr data mem = + let signExtend w n = + if n &&& (1 <<< (w - 1)) <> 0 then + ((-1 <<< w) ||| n) &&& 0xFFFFFFFF + else + n + + match mem.Init, addr, data with + | UnsignedMultiplier, a, d when a % 2 = 0 && a <= 16 -> + Ok <| makeData a d (fun (x:int) (y:int) -> (x * y) % (1 <<< d)) + | SignedMultiplier, a, d when a % 2 = 0 && a <= 16 -> + let w = a / 2 + Ok <| makeData a d (fun (x:int) (y:int) -> (signExtend w x * signExtend w y) &&& ((1 <<< d) - 1)) + | FromData,_, _ -> Ok mem.Data + | _ -> failwithf $"addr={addr}, data={data}, int={mem.Init} not allowed in makeFixedROM" + +let jsonStringToMem (jsonString : string) = + Json.tryParseAs> jsonString + + + + +/// get sheet I/O labels in correct order based on position of components +let getOrderedCompLabels compType ((comps,_): CanvasState) = + comps + |> List.collect (fun comp -> + let sortKey = comp.Y,comp.X + match comp.Type, compType with + | Input n, Input _ -> [sortKey,(comp.Label, n)] + | Output n, Output _ -> [sortKey, (comp.Label,n)] + | _ -> []) + |> List.sortBy fst + |> List.map snd + + +/// Extract the labels and bus widths of the inputs and outputs nodes as a signature. +/// Form is inputs,outputs +let parseDiagramSignature canvasState + : (string * int) list * (string * int) list = + let inputs = getOrderedCompLabels (Input 0) canvasState + let outputs = getOrderedCompLabels (Output 0) canvasState + inputs, outputs + +let getBaseNameNoExtension filePath = + let name = baseName filePath + match name.Split '.' |> Seq.toList with + | [] -> failwithf "what? split at . in a filename should never return empty list" + | [name] -> name // No dots found. + | firstSplit :: splits -> + // Quite ugly but works. + let rest = + ("", [0..splits.Length - 2]) ||> List.fold (fun baseName i -> + name + "." + splits[i] + ) + firstSplit + rest + +let private projectFileFilters = + createObj !![ + "name" ==> "ISSIE project file" + "extensions" ==> ResizeArray [ "dprj" ] + ] + |> unbox + |> Array.singleton + +let private ramFileFilters = + createObj !![ + "name" ==> "Memory contents File" + "extensions" ==> ResizeArray [ "ram" ] + ] + |> unbox + |> Array.singleton + +let private projectFilters = + createObj !![ + "name" ==> "ISSIE project" + "extensions" ==> ResizeArray [ "" ] + ] + |> unbox + |> Array.singleton + +let mutable firstProject = true // should really put this in model... + +/// Ask the user to choose a project file, with a dialog window. +/// Return the folder containing the chosen project file. +/// Return None if the user exits withouth selecting a path. +let askForExistingProjectPath () : string option = + let options = createEmpty + options.filters <- Some (projectFileFilters |> ResizeArray) + if firstProject then + options.defaultPath <- Some <| electronRemote.app.getPath ElectronAPI.Electron.AppGetPath.Documents + let w = electronRemote.getCurrentWindow() + electronRemote.dialog.showOpenDialogSync(w,options) + |> Option.map (fun fileName -> firstProject <- false; fileName) + |> Option.bind ( + Seq.toList + >> function + | [] -> Option.None + | p :: _ -> Some <| path.dirname p + ) + + + +/// Ask the user a new project path, with a dialog window. +/// Return None if the user exits withouth selecting a path. +let rec askForNewProjectPath () : string option = + let options = createEmpty + options.filters <- Some (projectFilters |> ResizeArray) + options.title <- Some "Enter new ISSIE project directory and name" + options.nameFieldLabel <- Some "New project name" + options.buttonLabel <- Some "Create Project" + options.properties <- Some [| + SaveDialogOptionsPropertiesArray.CreateDirectory + SaveDialogOptionsPropertiesArray.ShowOverwriteConfirmation + |] + match electronRemote.getCurrentWindow() with + | w -> + electronRemote.dialog.showSaveDialogSync(options) + |> Option.bind (fun dPath -> + let dir = dirName dPath + let files = fs.readdirSync <| U2.Case1 dir + if Seq.exists (fun (fn:string) -> fn.EndsWith ".dprj") files + then + electronRemote.dialog.showErrorBox( + "Invalid project directory", + "You are trying to create a new Issie project inside an existing project directory. \ + This is not allowed, please choose a different directory") + askForNewProjectPath() + + else + Some dPath) + + + + + +let tryCreateFolder (path : string) = + if Seq.exists (fun (ch:char) -> (not (System.Char.IsLetterOrDigit ch || ch = '_'))) (baseName path) then + Result.Error <| "File or project names must contain only letters, digits, or underscores" + else + try + Result.Ok <| fs.mkdirSync path + with + | ex -> Result.Error <| $"Can't create folder '{path}': {ex.Message}" + + +/// Asyncronously remove file. +/// ignore if file does not exist +let removeFileWithExtn extn folderPath baseName = + let path = path.join [| folderPath; baseName + extn |] + if fs.existsSync (U2.Case1 path) then + try + fs.unlink (U2.Case1 path, ignore) // Asynchronous. + with + | _ -> () + else + () + +let renameFile extn folderPath baseName newBaseName = + let oldPath = path.join [| folderPath; baseName + extn |] + let newPath = path.join [| folderPath; newBaseName + extn |] + if fs.existsSync <| U2.Case1 oldPath then + try + Ok <| fs.renameSync (oldPath, newPath) // synchronous. + with + | e -> Error $"Rename of '{baseName}' in '{folderPath}' failed" + elif extn = ".dgm" then + Error $"Error: The file '{baseName}{extn} appears to have been removed" + else + Ok () + +let removeFile (folderPath:string) (baseName:string) = removeFileWithExtn ".dgm" folderPath baseName + +let removeAutoFile folderPath baseName = + let path = path.join [| folderPath; baseName + ".dgmauto" |] + fs.unlink (U2.Case1 path, ignore) // Asynchronous. + +let readMemDefnLine (addressWidth:int) (wordWidth: int) (lineNo: int) (s:string) = + let nums = String.splitRemoveEmptyEntries [|' ';'\t';',';';';'"'|] s + match nums with + | [|addr;data|] -> + let addrNum = NumberHelpers.strToIntCheckWidth addressWidth addr + let dataNum = NumberHelpers.strToIntCheckWidth wordWidth data + match addrNum,dataNum with + | Ok a, Ok d -> Ok (a,d) + | Error aErr,_ -> Error $"Line {lineNo}:'%s{s}' has invalid address ({addr}). {aErr}" + | _, Error dErr -> Error $"Line '%s{s}' has invalid data item ({data}). {dErr}" + | x -> Error $"Line {lineNo}:'%s{s}' has {x.Length} items: valid lines consist of two numbers" + +let readMemLines (addressWidth:int) (wordWidth: int) (lines: string array) = + let parse = + Array.map String.trim lines + |> Array.filter ((<>) "") + |> Array.mapi (readMemDefnLine addressWidth wordWidth) + match Array.tryFind (function | Error _ -> true | _ -> false) parse with + | None -> + let defs = (Array.map (function |Ok x -> x | _ -> failwithf "What?") parse) + Array.iter (fun (a,b) -> printfn "a=%d, b=%d" a b) defs + let repeats = + Array.groupBy fst defs + |> Array.filter (fun (num, vals) -> vals.Length > 1) + if repeats <> [||] then + repeats + |> Array.map fst + |> fun aLst -> Error $"Memory addresses %A{aLst} are repeated" + else + Ok defs + + | Some (Error firstErr) -> + Error firstErr + | _ -> failwithf "What? can't happen" + +let readMemDefns (addressWidth:int) (wordWidth: int) (fPath: string) = + fs.readFileSync(fPath, "utf8") + |> String.splitRemoveEmptyEntries [|'\n';'\r'|] + |> readMemLines addressWidth wordWidth + |> Result.map Map.ofArray + + + + +let writeMemDefns (fPath: string) (mem: Memory1) = + try + Map.toArray mem.Data + |> Array.sortBy fst + |> Array.map (fun (a,b) -> $"{NumberHelpers.hex64 a}\t{NumberHelpers.hex64 b}") + |> String.concat "\n" + |> writeFile fPath + |> Ok + with + | e -> Error $"Error writing file '{fPath}': {e.Message}" + +let initialiseMem (mem: Memory1) (projectPath:string) = + let memResult = + match mem.Init with + | UnsignedMultiplier + | SignedMultiplier -> + makeFixedROM mem.AddressWidth mem.WordWidth mem + + | ToFile name -> + let fPath = pathJoin [| projectPath; name + ".ram"|] + writeMemDefns fPath mem + |> Result.map ( fun _ -> mem.Data) + + | FromFile name -> + let fPath = pathJoin [| projectPath; name + ".ram"|] + readMemDefns mem.AddressWidth mem.WordWidth fPath + + | FromData -> + Ok mem.Data + | ToFileBadName s -> + failwithf "What? Can't have a bad file name when initialising memory" + + memResult + |> Result.map (fun data -> {mem with Data = data}) + + + + + +/// Save a PNG file (encoded base64, as from draw2d) +/// Overwrite existing file if needed +let savePngFile folderPath baseName png = // TODO: catch error? + let path = pathJoin [| folderPath; baseName + ".png" |] + writeFileBase64 path png + +let formatSavedState (canvas,wave) = + CanvasWithFileWaveInfo(canvas,wave,System.DateTime.Now) + + + +/// Save state to normal file. Automatically add the .dgm suffix. +let saveStateToFile folderPath baseName state = // TODO: catch error? + let path = pathJoin [| folderPath; baseName + ".dgm" |] + let data = stateToJsonString state + writeFile path data + +/// Create new empty diagram file. Automatically add the .dgm suffix. +let createEmptyDgmFile folderPath baseName = + saveStateToFile folderPath baseName (([],[]), None) + +let stripVertices (conn: Connection) = + {conn with Vertices = []} + +let magnifySheet magnification (comp: Component) = + {comp with + X = int <| round (magnification * float (comp.X + comp.W / 2 )); + Y = int <| round (magnification * float (comp.Y + comp.H/2)) + H = -1 // overwritten correctly by Sheet based on componnet type + W = -1 // as above + } + + +/// Update from old component types to new +/// The standard way to add functionality to an existing component is to create a new +/// component type, keeping the old type. Then on reading sheets from disk both new and old +/// will be correctly read. This function will be called on load and will convert from the old +/// type to the new one so that the rest of issie need only process new types, but compatibility +/// with saved old types remains. +let getLatestComp (comp: Component) = + let updateMem (mem:Memory) : Memory1 = + { + Init = FromData + Data = mem.Data + AddressWidth = mem.AddressWidth + WordWidth = mem.WordWidth + } + match comp.Type with + | RAM mem -> {comp with Type = RAM1 (updateMem mem)} + | ROM mem -> {comp with Type = ROM1 (updateMem mem)} + | AsyncROM mem -> { comp with Type = AsyncROM1 (updateMem mem)} + | Constant(width,cVal) -> {comp with Type = Constant1(width, cVal, $"%d{cVal}")} + | _ -> comp + +/// Interface function that can read old-style circuits (without wire vertices) +/// as well as new circuits with vertices. Old circuits have an expansion parameter +/// since new symbols are larger (in units) than old ones. +let getLatestCanvas state = + let oldCircuitMagnification = 1.25 + let stripConns canvas = + let (comps,conns) = canvas + let noVertexConns = List.map stripVertices conns + let expandedComps = List.map (magnifySheet oldCircuitMagnification) comps + expandedComps, noVertexConns + let comps,conns = + match state with + | CanvasOnly canvas -> stripConns canvas + | CanvasWithFileWaveInfo(canvas, _, _) -> stripConns canvas + | CanvasWithFileWaveInfoAndNewConns(canvas, _, _) -> canvas + List.map getLatestComp comps, conns + + +let checkMemoryContents (projectPath:string) (comp: Component) : Component = + match comp.Type with + | RAM1 mem | ROM1 mem | AsyncROM1 mem | AsyncRAM1 mem when not (String.endsWith "backup" (String.toLower projectPath))-> + match mem.Init with + | FromFile fName -> + let fPath = pathJoin [|projectPath ; (fName + ".ram")|] + let memData = readMemDefns mem.AddressWidth mem.WordWidth fPath + match memData with + | Ok memDat -> + if memDat <> mem.Data then + printfn "%s" $"Warning! RAM file {fPath} has changed so component {comp.Label} is now different" + let mem = {mem with Data = memDat} + {comp with Type = getMemType comp.Type mem} + | Error msg -> + printfn $"Error relaoding component {comp.Label} from its file {fPath}:\n{msg}" + comp // ignore errors for now + | _ -> comp + | _ -> comp + +/// load a component from its canvas and other elements +let makeLoadedComponentFromCanvasData (canvas: CanvasState) filePath timeStamp waveInfo = + let projectPath = path.dirname filePath + let inputs, outputs = parseDiagramSignature canvas + let comps,conns = canvas + let comps' = List.map (checkMemoryContents projectPath) comps + let canvas = comps',conns + let ramChanges = + List.zip comps' comps + |> List.filter (fun (c1,c2) -> c1.Type <> c2.Type) + |> List.map fst + let ldc = + { + Name = getBaseNameNoExtension filePath + TimeStamp = timeStamp + WaveInfo = waveInfo + FilePath = filePath + CanvasState = canvas + InputLabels = inputs + OutputLabels = outputs + } + ldc, ramChanges + + +/// Make a loadedComponent from the file read from filePath. +/// Return the component, or an Error string. +let tryLoadComponentFromPath filePath : Result = + match tryLoadStateFromPath filePath with + | Result.Error msg + | Ok (Result.Error msg) -> + Error <| sprintf "Can't load component %s because of Error: %s" (getBaseNameNoExtension filePath) msg + | Ok (Ok state) -> + makeLoadedComponentFromCanvasData + (getLatestCanvas state) + filePath + state.getTimeStamp + state.getWaveInfo + |> fst // ignore ram change info, they will always be loaded + |> Result.Ok + + + +type LoadStatus = + | Resolve of LoadedComponent * LoadedComponent + | OkComp of LoadedComponent + | OkAuto of LoadedComponent + + +/// load all files in folderpath. Return Ok list of LoadStatus or a single Error. +let loadAllComponentFiles (folderPath:string) = + let x = + try + Ok <| fs.readdirSync (U2.Case1 folderPath) + with + | e -> Error <| sprintf "Error reading Issie project directory at '%s: %A" folderPath e + match x with + | Error msg -> Error msg + | Ok x -> + x + |> Seq.toList + |> List.filter (path.extname >> ((=) ".dgm")) + |> List.map (fun fileName -> + if fileNameIsBad (pathWithoutExtension fileName) + then + Error <| sprintf @"Can't load file name '%s' from project '%s' because it contains incorrect characters.\n \ + File names used as sheets must contain only alphanumeric and space characters before the '.dgm' extension" fileName folderPath + else + let filePath = path.join [| folderPath; fileName |] + let ldComp = filePath |> tryLoadComponentFromPath + let autoComp = filePath + "auto" |> tryLoadComponentFromPath + match (ldComp, autoComp) with + | Ok ldComp, Ok autoComp when ldComp.TimeStamp < autoComp.TimeStamp -> + Resolve(ldComp,autoComp) |> Ok + | Ok ldComp, _ -> + OkComp ldComp |> Ok + | Error _, Ok autoComp -> + OkAuto autoComp |> Ok + | Error msg, _ -> Error msg + ) + |> tryFindError + +/// Ask the user a new project path, with a dialog window. +/// Return None if the user exits withouth selecting a path. +let rec askForNewFile (projectPath: string) : string option = + let options = createEmpty + options.filters <- Some (ramFileFilters |> ResizeArray) + options.defaultPath <- Some projectPath + options.title <- Some "Enter new file name" + options.nameFieldLabel <- Some "New file name" + options.buttonLabel <- Some "Save memory content to file" + options.properties <- Some [| + SaveDialogOptionsPropertiesArray.ShowOverwriteConfirmation + |] + match electronRemote.getCurrentWindow() with + | w -> + electronRemote.dialog.showSaveDialogSync(options) + +let saveAllProjectFilesFromLoadedComponentsToDisk (proj: Project) = + proj.LoadedComponents + |> List.iter (fun ldc -> + let name = ldc.Name + let state = ldc.CanvasState + let waveInfo = ldc.WaveInfo + saveStateToFile proj.ProjectPath name (state,waveInfo) |> ignore + removeFileWithExtn ".dgmauto" proj.ProjectPath name) + +let openWriteDialogAndWriteMemory mem path = + match askForNewFile path with + | None -> + None + | Some fpath -> + let fpath' = + if not (String.contains "." fpath) then + fpath + ".ram" + else + fpath + writeMemDefns fpath' mem |> ignore + Some fpath' + + + + + diff --git a/src/Renderer/Interface/JSHelpers.fs b/src/Renderer/Interface/JSHelpers.fs new file mode 100644 index 0000000..4be7b5c --- /dev/null +++ b/src/Renderer/Interface/JSHelpers.fs @@ -0,0 +1,135 @@ +(* + JSHelpers.fs + Some utility functions that rely on Node/JS functionality +*) + +module JSHelpers + +open Browser.Types +open Fable.Core +open Fable.Core.JsInterop +open ElectronAPI +open Fable.React + +/// Fix to access the deprecated @electron.remote module. +/// This must be enabled from main.fs +/// NB the interface used here is not precisely correct, because it +/// exposes the original electron-remote API. The @electron.remote API is +/// a bit reduced, but with some extra code to control access. +/// electronRemote replaces electron.remote and renderer.remote in old interface +[] +let electronRemote : Electron.Remote = jsNative + + +[] +let jsType (var: obj) : unit = jsNative + +[] +let log msg : unit = jsNative + +let logString msg : unit = + log <| sprintf "%A" msg + +let logChain msg = + logString msg + msg + +[] +let alert msg : unit = jsNative + +[] +let isNull (obj : obj) : bool = jsNative + +[] +let startTimer (label : string) : unit = jsNative + +[] +let stopAndLogTimer (label : string) : unit = jsNative + +/// Assert js object is not null, and return it. +let assertNotNull obj msg = +#if ASSERTS + Helpers.assertThat (not <| isNull obj) ("(assertNotNull) " + msg) +#endif + obj + +/// Access nested fields of a js object, failing if at any point of the chain +/// the requested field is null. +/// Should be used when the fields are guaranteed to exist. +/// For example ["a"; "b"; "c"] is equivalent to the jsCode `obj.a.b.c`, but +/// with checks against null at every layer. +let rec getFailIfNull jsObj (fields : string list) = + assertNotNull jsObj "jsObj is null in getFailIfNull" |> ignore + match fields with + | [lastField] -> + assertNotNull jsObj?(lastField) <| sprintf "jsObj.%s is null in getFailIfNull" lastField + | nextField :: fields' -> + let jsObj' = assertNotNull jsObj?(nextField) <| sprintf "jsObj.%s is null in getFailIfNull" nextField + getFailIfNull jsObj' fields' + | [] -> failwithf "what? getFailIfNull called with no fields to get" + +/// Transforms a js list of jsType into an f# list of jsType. +/// If jsList is not a js list, fail. +let jsListToFSharpList jsList = + let len = getFailIfNull jsList ["length"] + [0..len - 1] |> List.map (fun i -> jsList?(i)) + +[] +let emptyJsList () = jsNative + +let fshaprListToJsList (list : 'a list) = + let jsList = emptyJsList () + list |> List.map (fun el -> jsList?push(el)) |> ignore + jsList + +/// Get the value for a change event in an input textbox. +let getTextEventValue (event: Browser.Types.Event) = + getFailIfNull event.currentTarget ["value"] |> unbox + +// Due to the way FABLE embeds integers in floats, with type erasure at runtime, +// values that need to be int in F# code must be explicitly converted +// to int as here. Otherwise obscure bugs can happen where a JS apparent integer +// turns into an F# integer value that is not precisely equal to +// the real F# integer. + +/// Get the value for a change event in an input number box, +/// making sure it is an F# integer (JS integer values may not be precise) +let getIntEventValue (event: Browser.Types.Event) = + getFailIfNull event.currentTarget ["value"] |> unbox |> int + +let getInt64EventValue( event: Browser.Types.Event) = + let boxText = getFailIfNull event ["target";"value"] |> unbox + let (ok,n) = System.Int64.TryParse boxText + if not ok then 0L else n + + +/// Get the value for a blur event in an input textbox. +let getTextFocusEventValue (event: FocusEvent) = + getFailIfNull event ["target";"value"] |> unbox + +#if (ASSERTS || DEBUG) +let mutable debugLevel = 1 +#else +let mutable debugLevel = 0 +#endif + +/// trace UI execution: "view" - mark view function. "update" print update messages. +let mutable debugTraceUI: string Set = Set [] + +/// Call debugAction() and print its result if debugTraceUI mutable contains string traceCode +let traceIf traceCode debugAction = + if Set.contains traceCode debugTraceUI then printfn <| debugAction() + +/// Hack to provide a constant global variable +/// set from command line arguments of main process. +/// 0 => production. 1 => dev. 2 => debug. +let setDebugLevel() = + let hasSwitch swName = electronRemote.app.commandLine.hasSwitch swName + if hasSwitch "debug" || hasSwitch "-d" then + debugLevel <- 2 + elif hasSwitch "w" then + debugLevel <- 1 + +/// return a v4 (random) universally unique identifier (UUID) +let uuid():string = import "v4" "uuid" + diff --git a/src/Renderer/Interface/Version.fs b/src/Renderer/Interface/Version.fs new file mode 100644 index 0000000..937d309 --- /dev/null +++ b/src/Renderer/Interface/Version.fs @@ -0,0 +1,18 @@ +module Version +let VERSION = [ 2 ; 4 ; 4 ] + +// The first 12 white-space separated words in this file must be in the above format - note that spaces are required. +// This works as valid F# data for displaying the code version and can also be read programmatically from the master branch github file + +let VersionString = + if List.length VERSION <> 3 then failwithf "Badly formatted version %A (VERSION must be list of 3 integers)" VERSION + VERSION + |> List.map (fun (i:int)-> i.ToString()) |> String.concat "." + |> fun s -> "v" + s + + + + + + + diff --git a/src/Renderer/Renderer.fs b/src/Renderer/Renderer.fs new file mode 100644 index 0000000..2ad08b1 --- /dev/null +++ b/src/Renderer/Renderer.fs @@ -0,0 +1,254 @@ +(* +Top-level renderer that initialises the app and runs the elmish loop +The electron built-in menus, and key presses,have actions which are +are implemented here using elmish subscriptions +*) + +module Renderer + +open Elmish +open Elmish.React +open Elmish.Debug +open Elmish.HMR +open Fable.Core +open Fable.Core.JsInterop +open ElectronAPI +open ModelType +open Fable.SimpleJson +open JSHelpers + + +let isMac = Node.Api.``process``.platform = Node.Base.Darwin + +let testMaps() = + let modMap = + [0..1000] + |> List.map (fun n -> n, (n*256+1) % 1001) + |> Map.ofList + + + let iterMap count = + let mutable x: int = 1 + let mutable i:int = 0 + while i < count do + x <- modMap[x] + i <- i + 1 + + let count = 1000000 + let start = TimeHelpers.getTimeMs() + let result = iterMap count + let interval = TimeHelpers.getTimeMs() - start + printfn "%d iterations of iterMap took %.1fms" count interval + + +(**************************************************************************************************** +* +* MENU HELPER FUNCTIONS +* +****************************************************************************************************) + +let menuSeparator = + let sep = createEmpty + sep.``type`` <- Some MenuItemType.Separator + sep + +// Set up window close interlock using IPC from/to main process +let attachExitHandler dispatch = + // set up callback called when attempt is made to close main window + renderer.ipcRenderer.on ("closingWindow", (fun (event: Event)-> + // send a message which will process the request to exit + dispatch <| MenuAction(MenuExit,dispatch) + )) |> ignore + + +/// Make action menu item from name, opt key to trigger, and action. +let makeItem (label : string) (accelerator : string option) (iAction : KeyboardEvent -> unit) = + let item = createEmpty + item.label <- Some label + item.accelerator <- accelerator + item.click <- Some (fun _ _ keyEvent -> iAction keyEvent) + item + +/// Make role menu from name, opt key to trigger, and action. +let makeRoleItem label accelerator role = + let item = makeItem label accelerator (fun _ -> ()) + item.role <- Some role + item + +/// make conditional menu item from condition, name, opt key to trigger, and role +let makeCondRoleItem cond label accelerator role = + let item = makeItem label accelerator (fun _ -> ()) + item.role <- Some role + item.visible <- Some cond + item + +/// make conditional menu item from condition, name, opt key to trigger, and action +let makeCondItem cond label accelerator action = + let item = makeItem label accelerator action + item.visible <- Some cond + item + + +let makeElmItem (label:string) (accelerator : string) (action : unit -> unit) = + jsOptions <| fun item -> + item.label <- Some label + item.accelerator <- Some accelerator + item.click <- Some (fun _ _ _ -> action()) + + +/// Make a new menu from a a list of menu items +let makeMenu (topLevel: bool) (name : string) (table : MenuItemConstructorOptions list) = + let subMenu = createEmpty + subMenu.``type`` <- Some (if topLevel then MenuItemType.Normal else MenuItemType.Submenu) + subMenu.label <-Some name + subMenu.submenu <- Some (U2.Case1 (table |> ResizeArray)) + subMenu + +let displayPerformance n m = TimeHelpers.checkPerformance n m JSHelpers.startTimer JSHelpers.stopAndLogTimer + + + + + + + +let fileMenu (dispatch) = + makeMenu false "Sheet" [ + makeItem "New Sheet" (Some "CmdOrCtrl+N") (fun ev -> dispatch (MenuAction(MenuNewFile,dispatch))) + makeItem "Save Sheet" (Some "CmdOrCtrl+S") (fun ev -> dispatch (MenuAction(MenuSaveFile,dispatch))) + //makeItem "Print Sheet" (Some "CmdOrCtrl+P") (fun ev -> dispatch (MenuAction(MenuPrint,dispatch))) + makeItem "Write design as Verilog" None (fun ev -> dispatch (MenuAction(MenuVerilogOutput,dispatch))) + makeItem "Exit Issie" None (fun ev -> dispatch (MenuAction(MenuExit,dispatch))) + makeItem ("About Issie " + Version.VersionString) None (fun ev -> PopupView.viewInfoPopup dispatch) + makeCondRoleItem (JSHelpers.debugLevel <> 0 && not isMac) "Hard Restart app" None MenuItemRole.ForceReload + makeCondItem (JSHelpers.debugLevel <> 0 && not isMac) "Trace all" None (fun _ -> + JSHelpers.debugTraceUI <- Set.ofList ["update";"view"]) + makeCondItem (JSHelpers.debugLevel <> 0 && not isMac) "Trace off" None (fun _ -> + JSHelpers.debugTraceUI <- Set.ofList []) + makeCondItem (JSHelpers.debugLevel <> 0 && not isMac) "Run performance check" None (fun _ -> + testMaps() + displayPerformance 100 4000000) + ] + + +let viewMenu dispatch = + let sheetDispatch sMsg = dispatch (Sheet sMsg) + let dispatch = Sheet.KeyPress >> sheetDispatch + + let devToolsKey = if isMac then "Alt+Command+I" else "Ctrl+Shift+I" + makeMenu false "View" [ + makeRoleItem "Toggle Fullscreen" (Some "F11") MenuItemRole.Togglefullscreen + makeItem "Toggle Grid" None (fun ev -> sheetDispatch Sheet.Msg.ToggleGrid) + menuSeparator + makeRoleItem "Zoom In" (Some "CmdOrCtrl+Shift+Plus") MenuItemRole.ZoomIn + makeRoleItem "Zoom Out" (Some "CmdOrCtrl+Shift+-") MenuItemRole.ZoomOut + makeRoleItem "Reset Zoom" (Some "CmdOrCtrl+0") MenuItemRole.ResetZoom + menuSeparator + makeItem "Diagram Zoom In" (Some "Shift+Plus") (fun ev -> dispatch Sheet.KeyboardMsg.ZoomIn) + makeItem "Diagram Zoom Out" (Some "Shift+-") (fun ev -> dispatch Sheet.KeyboardMsg.ZoomOut) + makeItem "Diagram Zoom to Fit" (Some "CmdOrCtrl+W") (fun ev -> dispatch Sheet.KeyboardMsg.CtrlW) + menuSeparator + makeCondItem (JSHelpers.debugLevel <> 0) "Toggle Dev Tools" (Some devToolsKey) (fun _ -> + renderer.ipcRenderer.send("toggle-dev-tools", [||]) |> ignore) + ] + + +// Editor Keybindings (also items on Edit menu) +// Use Elmish subscriptions to attach external source of events such as keyboard +// shortcuts. According to electron documentation, the way to configure keyboard +// shortcuts is by creating a menu. +let editMenu dispatch = + let sheetDispatch sMsg = dispatch (Sheet sMsg) + let dispatch = Sheet.KeyPress >> sheetDispatch + + jsOptions <| fun invisibleMenu -> + invisibleMenu.``type`` <- Some MenuItemType.Submenu + invisibleMenu.label <- Some "Edit" + invisibleMenu.visible <- Some true + invisibleMenu.submenu <- + [| // makeElmItem "Save Sheet" "CmdOrCtrl+S" (fun () -> ()) + makeElmItem "Copy" "CmdOrCtrl+C" (fun () -> dispatch Sheet.KeyboardMsg.CtrlC) + makeElmItem "Paste" "CmdOrCtrl+V" (fun () -> dispatch Sheet.KeyboardMsg.CtrlV) + makeElmItem "Select All" "CmdOrCtrl+A" (fun () -> dispatch Sheet.KeyboardMsg.CtrlA) + makeElmItem "Delete" (if isMac then "Backspace" else "delete") (fun () -> dispatch Sheet.KeyboardMsg.DEL) + makeElmItem "Undo" "CmdOrCtrl+Z" (fun () -> dispatch Sheet.KeyboardMsg.CtrlZ) + makeElmItem "Redo" "CmdOrCtrl+Y" (fun () -> dispatch Sheet.KeyboardMsg.CtrlY) + makeElmItem "Cancel" "ESC" (fun () -> dispatch Sheet.KeyboardMsg.ESC)|] + |> ResizeArray + |> U2.Case1 + |> Some + +let attachMenusAndKeyShortcuts dispatch = + //setupExitInterlock dispatch + let sub dispatch = + let menu:Menu = + [| + + fileMenu dispatch + + editMenu dispatch + + viewMenu dispatch + |] + |> Array.map U2.Case1 + |> electronRemote.Menu.buildFromTemplate //Help? How do we call buildfromtemplate + menu.items[0].visible <- true + dispatch <| Msg.ExecFuncInMessage((fun _ _ -> + electronRemote.app.applicationMenu <- Some menu), dispatch) + attachExitHandler dispatch + + Cmd.ofSub sub + +// This setup is useful to add other pages, in case they are needed. + +type Model = ModelType.Model + +type Messages = ModelType.Msg + +// -- Init Model + +let init() = + JSHelpers.setDebugLevel() + DiagramMainView.init(), Cmd.none + + +// -- Create View + +let view model dispatch = DiagramMainView.displayView model dispatch + +// -- Update Model + +let update msg model = Update.update msg model + +printfn "Starting renderer..." + +let view' model dispatch = + let start = TimeHelpers.getTimeMs() + view model dispatch + |> TimeHelpers.instrumentInterval "View" start + +let mutable firstPress = true + +///Used to listen for pressing down of Ctrl for selection toggle +let keyPressListener initial = + let subDown dispatch = + Browser.Dom.document.addEventListener("keydown", fun e -> + let ke: KeyboardEvent = downcast e + if (jsToBool ke.ctrlKey || jsToBool ke.metaKey) && firstPress then + firstPress <- false + dispatch <| Sheet(Sheet.ToggleSelectionOpen) + else + ()) + let subUp dispatch = + Browser.Dom.document.addEventListener("keyup", fun e -> + firstPress <- true + dispatch <| Sheet(Sheet.ToggleSelectionClose)) + Cmd.batch [Cmd.ofSub subDown; Cmd.ofSub subUp] + + + +Program.mkProgram init update view' +|> Program.withReactBatched "app" +|> Program.withSubscription attachMenusAndKeyShortcuts +|> Program.withSubscription keyPressListener +|> Program.run diff --git a/src/Renderer/Renderer.fsproj b/src/Renderer/Renderer.fsproj new file mode 100644 index 0000000..fa3f1da --- /dev/null +++ b/src/Renderer/Renderer.fsproj @@ -0,0 +1,71 @@ + + + netcoreapp3.1 + win-x64;linux-x64 + + + + TRACE + + + TRACE + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Renderer/Simulator/Builder.fs b/src/Renderer/Simulator/Builder.fs new file mode 100644 index 0000000..5c6d69f --- /dev/null +++ b/src/Renderer/Simulator/Builder.fs @@ -0,0 +1,240 @@ +(* + Builder.fs + + This module collects functions to build a SimulationGraph, starting from + a CanvasState. It also runs all the checks contained in Analyser to validate + the graph is correct (and can be built in the first place). +*) + +module SimulationBuilder + +open Helpers +open NumberHelpers +open CommonTypes +open SimulatorTypes +open CanvasStateAnalyser + +/// Assert that the FData only contain a single bit, and return such bit. +let inline extractBit (fd: FData) : uint32 = +#if ASSERTS + assertThat (fd.Width = 1) + <| sprintf "extractBit called with wireData: %A" fd +#endif + match fd.Dat with | Word n -> n | BigWord _ -> failwithf "Can't extract 1 bit from BigWord data {wireData}" + +let inline packBit (bit: uint32) : FData = if bit = 0u then {Dat=Word 0u; Width = 1} else {Dat = Word 1u; Width = 1} + + +/// This function should only be called on Component ports, never on Connection +/// ports: ports in Components should always have Some portNumber, ports in +/// Connections should have None. +let private getPortNumberOrFail port = + match port with + | None -> failwithf "what? Component ports should always have a portNumber" + | Some p -> p + + +/// Extract the values of the inputs of a SimulationComponent. +/// If any of these inputs is missing, return None. +/// The values are returned in the the passed order. E.g. if portNumbers is +/// [0, 1, 2], the returned value will be [bit0, bit1, bit2]. +let rec private getValuesForPorts + (inputs : Map) + (portNumbers : InputPortNumber list) + : (WireData list) option = + match portNumbers with + | [] -> Some [] + | portNumber :: portNumbers' -> + match inputs.TryFind portNumber with + | None -> None + | Some wireData -> + match getValuesForPorts inputs portNumbers' with + | None -> None + | Some values -> Some <| wireData :: values + + + + + +/// Given a component type, return a function takes a ReducerInput and +/// transform it into a ReducerOuptut. +/// The ReducerOutput should have Outputs set to None if there are not enough +/// ReducerInput.Inputs to calculate the outputs. +/// For custom components, return a fake version of the reducer, that has to be +/// replaced when resolving the dependencies. +/// TODO: some components reducers are quite similar, for example Register and +/// RegisterE and DFF and DFFE. It is probably a good idea to merge them +/// together to avoid duplicated logic. +let private getReducer (componentType : ComponentType) : ReducerInput -> ReducerOutput = + fun _ -> failwithf "Reducer function is legacy code and should never be called!" + + + +/// Build a map that, for each source port in the connections, keeps track of +/// the ports it targets. +/// It makes no sense to extract the PortNumber in this function as it is always +/// set to None for ports in connections. +let private buildSourceToTargetPortMap + (connections : Connection list) + : Map = + (Map.empty, connections) ||> List.fold (fun map conn -> + let key = OutputPortId conn.Source.Id + let target = ComponentId conn.Target.HostId, InputPortId conn.Target.Id + // Append the new target to the list associated with the key. + let newValue = + match map.TryFind key with + | None -> [target] + | Some oldValue -> target :: oldValue + map.Add (key, newValue) + ) + +/// For each input port in each component, map it to its port number. +let private mapInputPortIdToPortNumber + (components : Component list) + : Map = + (Map.empty, components) ||> List.fold (fun map comp -> + (map, comp.InputPorts) ||> List.fold (fun map port -> + map.Add (InputPortId port.Id, + InputPortNumber (getPortNumberOrFail port.PortNumber)) + ) + ) + +/// Get the default state for a component. +/// Note that custom components are stateless, even though they may contain +/// stateful components. The state of such stateful components is maintained +/// in the CustomSimulationGraph. +/// ROMs are stateless (they are only defined by their initial content). +let private getDefaultState compType = + match compType with + | ROM _ | RAM _ | AsyncROM _ -> + failwithf "What? Legacy RAM component types should never occur" + | Input _ | Output _ | IOLabel | BusSelection _ | BusCompare _ | Not | And | Or | Xor | Nand | Nor | Xnor | Mux2 | Decode4 + | Demux2 | NbitsAdder _ |NbitsXor _ | Custom _ | MergeWires | SplitWire _ | ROM1 _ | Viewer _ -> NoState + | Constant1 _ | Constant _ -> NoState + | AsyncROM1 _ -> NoState + | DFF | DFFE -> DffState 0u + | Register w | RegisterE w -> RegisterState <| convertIntToFastData w 0u + | RAM1 memory | AsyncRAM1 memory -> RamState memory // The RamState content may change during + // the simulation. + +/// Build a simulation component. +let private buildSimulationComponent + (sourceToTargetPort : Map) + (portIdToPortNumber : Map) + (comp : Component) + : SimulationComponent = + // Remove portIds and use portNumbers instead. + let mapPortIdsToPortNumbers + (targets : (ComponentId * InputPortId) list) + : (ComponentId * InputPortNumber) list = + targets |> List.map (fun (compId, portId) -> + match portIdToPortNumber.TryFind <| portId with + | None -> failwithf "what? Input port with portId %A has no portNumber associated" portId + | Some portNumber -> compId, portNumber + ) + // For each output port, find out which other components and ports are + // connected to it. + let outputs = + comp.OutputPorts + |> List.collect (fun port -> + match sourceToTargetPort.TryFind <| OutputPortId port.Id with + | None when comp.Type=IOLabel -> [] // IOLabels are allowed to be connected to nothing + | None -> failwithf "what? Unconnected output port %s in comp %s" port.Id comp.Id + | Some targets -> [ + OutputPortNumber <| getPortNumberOrFail port.PortNumber, + mapPortIdsToPortNumbers targets + ] + ) + |> Map.ofList + + + + // The inputs will be set during the simulation, we just need to initialise + // the ones for Output nodes, see below. + let inputs = + match comp.Type with + | Output width -> + // Initialise all outputs to zero. This is necessary because upon + // starting the simulation we need to feed all zeros. To do so, we + // need to feed all simulation inputs set to zero and a global clock + // tick. The problem is that both operations expect all outputs to + // be set as result, but they don't necessarily set all the outputs + // themselves. Therefore there is not an order you can run them in + // that will always work. Presetting the outputs solves the problem + // and the value does not matter as all outputs will be set again + // in that initialization process. + Map.empty.Add (InputPortNumber 0, List.replicate width Zero) + | _ -> Map.empty + { + Id = ComponentId comp.Id + Type = comp.Type + Label = ComponentLabel comp.Label + Inputs = inputs + Outputs = outputs + OutputsPropagated = Array.replicate 0 false // default for non-clocked components + CustomSimulationGraph = None // Custom components will be augumented by the DependencyMerger. + State = getDefaultState comp.Type + Reducer = getReducer comp.Type + } + +let getLabelConnections (comps:Component list) (conns: Connection list) = + let labels = + comps + |> List.filter (fun co -> co.Type = IOLabel) + + let compIdMap = + labels + |> List.map (fun co -> ComponentId co.Id, co) + |> Map.ofList + + let getComp n = compIdMap[n] + + let targetMap = + conns + |> List.map (fun conn -> ComponentId conn.Target.HostId, conn) + |> Map.ofList + + let getConnection (compTarget:Component) = targetMap[ComponentId compTarget.Id] + + let copyConnection (conn: Connection) (compTarget:Component) (tagNum:int) = + {conn with Target = compTarget.InputPorts[0]; Id = sprintf "iolab%d" tagNum + conn.Id} + + let getDriverConnection (comps: Component list) = + comps + |> List.tryFind (fun co -> (Map.tryFind (ComponentId co.Id) targetMap) <> None) + |> function + | None -> failwithf "What? component cannot be found in %A" targetMap + | Some comp -> targetMap[ComponentId comp.Id] + + labels + |> List.groupBy (fun co -> co.Label) + |> List.collect (fun (lab,lst) -> + let dConn = getDriverConnection lst + lst + |> List.filter (fun co -> co.Id <> dConn.Target.HostId) + |> List.indexed + |> List.map (fun (i, co) -> copyConnection dConn co i)) + + + +/// Transforms a canvas state into a simulation graph. +let private buildSimulationGraph (canvasState : CanvasState) : (SimulationGraph) = + let components, connections' = canvasState + let labConns = getLabelConnections components connections' + let connections = labConns @ connections' + let sourceToTargetPort = buildSourceToTargetPortMap connections + let portIdToPortNumber = mapInputPortIdToPortNumber components + let mapper = buildSimulationComponent sourceToTargetPort portIdToPortNumber + components + |> List.map (fun comp -> ComponentId comp.Id, mapper comp) + |> Map.ofList + |> (fun m -> m) + +/// Validate a diagram and generate its simulation graph. +let runCanvasStateChecksAndBuildGraph + (canvasState : CanvasState) + (loadedComponents: LoadedComponent list) + : Result = + match analyseState canvasState loadedComponents with + | Some err -> Error err + | None -> Ok <| buildSimulationGraph canvasState diff --git a/src/Renderer/Simulator/CanvasStateAnalyser.fs b/src/Renderer/Simulator/CanvasStateAnalyser.fs new file mode 100644 index 0000000..a36f0d7 --- /dev/null +++ b/src/Renderer/Simulator/CanvasStateAnalyser.fs @@ -0,0 +1,477 @@ +(* + CanvasStateAnalyser.fs + + This module collects a series of functions that perform checks on + CanvasState and SimulationGraph. +*) + +module CanvasStateAnalyser + +open CommonTypes +open SimulatorTypes +open BusWidthInferer + +// -- Checks performed +// +// Ports constraints: +// - Source ports must be output ports. +// - Target ports must be input ports. +// - All ports have at least one connection that touches them. +// - Input ports have precisely one connection that touches them. +// - Custom components must have I/Os consistent with the sheet that defines them. +// +// Input/Output components in a simulationgraph must all have unique labels. +// +// All wire widths are consistent (rely on WidthInferer.fs). + +// IOLabel input and output ports are special. +// Input: each same label group must be driven just once. +// Output: relax normal restriction that all outputs must be connected + +/// Return all the Ids of all input ports across all components. +/// Return also the ComponentId which may be used in error messages. + +type MapData = + { + Connections : Connection list + Components : Component list + LabComp : Component list + LabGroup : Map + LabInputPorts: Port list + LabOutputPorts: Port list + LabTargetConns: Connection list + OtherTargetConns: Connection list + LabSourceConns: Connection list + OtherSourceConns: Connection list + OtherInputPorts: Port list + OtherOutputPorts: Port list + ToComp: Map + ToInputPort: Map + ToOutputPort: Map + } +let private getAllInputPortIds (components : Component list) : (InputPortId * ComponentId) list = + components |> List.collect + (fun comp -> comp.InputPorts |> List.map (fun port -> InputPortId port.Id, ComponentId comp.Id)) + +/// Return all the Ids of all ouput ports across all components. +/// Return also the ComponentId which may be used in error messages. +let private getAllOutputPortIds (components : Component list) : (OutputPortId * ComponentId) list = + components |> List.collect + (fun comp -> comp.OutputPorts |> List.map (fun port -> OutputPortId port.Id, ComponentId comp.Id)) + + +/// maps for use in various places +let private genMaps ((comps,conns):CanvasState) = + + + let labComps:Component list = List.filter (fun co -> co.Type = IOLabel) comps + + let idToComp = + comps + |> List.map (fun co -> ComponentId co.Id, co) + |> Map.ofList + + let targetIsLabel (c: Connection) = idToComp[ComponentId c.Target.HostId].Type = IOLabel + let sourceIsLabel (c: Connection) = idToComp[ComponentId c.Source.HostId].Type = IOLabel + let splitBy pred lst = + (([],[]), lst) ||> List.fold (fun (is, isNot) x -> + if pred x then (x :: is, isNot) else (is,x::isNot)) + + let labTargetConns,otherTargetConns = splitBy targetIsLabel conns + let labSourceConns, otherSourceConns = splitBy sourceIsLabel conns + + let normalise (p:Port) = {p with PortNumber=None} + let normaliseL (pL: Port list) = List.map normalise pL + + + let idToInputPort = + comps + |> List.collect (fun co -> co.InputPorts) + |> List.map (fun po -> InputPortId po.Id, normalise po) + |> Map.ofList + + let idToOutputPort = + comps + |> List.collect (fun co -> co.OutputPorts) + |> List.map (fun po -> OutputPortId po.Id, normalise po) + |> Map.ofList + + let otherInputPorts = + comps + |> List.filter (fun co -> co.Type <> IOLabel) + |> List.collect (fun co -> normaliseL co.InputPorts) + + let otherOutputPorts = + comps + |> List.filter (fun co -> co.Type <> IOLabel) + |> List.collect (fun co -> normaliseL co.OutputPorts) + + let labGroup = + List.groupBy (fun (co:Component) -> co.Label) labComps + |> Map.ofList + + let labInputPorts = + labComps + |> List.collect (fun co -> normaliseL co.InputPorts) + + let labOutputPorts = + labComps + |> List.collect (fun co -> normaliseL co.OutputPorts) + { + Connections = conns + Components = comps + LabComp = labComps + LabGroup = labGroup + OtherInputPorts = otherInputPorts + OtherOutputPorts = otherOutputPorts + LabInputPorts = labInputPorts + LabOutputPorts = labOutputPorts + ToComp = idToComp + ToInputPort = idToInputPort + ToOutputPort = idToOutputPort + LabTargetConns = labTargetConns + LabSourceConns = labSourceConns + OtherTargetConns = otherTargetConns + OtherSourceConns = otherSourceConns + } + + + +/// Check that: +/// 1- all source ports in connections are Output ports, +/// 2- all target ports in connections are Input ports, +/// 3- all input ports in a component are actually input ports, +/// 4- all output ports in a component are actually output ports, +/// 5- all ports on components have a port number, +/// 6- all ports on connection do not have a port number. +/// These conditions should always hold, unless there are bugs in the code (i.e. +/// no user behaviour should be able to trigger such errors). +/// The costruction of the Simulation graph assumes that these rules hold. +/// TODO: should they crash the program then? +let private checkPortTypesAreConsistent (canvasState : CanvasState) : SimulationError option = + let rec checkComponentPorts (ports : Port list) (correctType : PortType) = + match ports with + | [] -> None + | port :: _ when port.PortNumber = None -> Some { + Msg = sprintf "%A port appears to not have a port number" correctType + InDependency = None + ComponentsAffected = [ComponentId port.HostId] + ConnectionsAffected = [] } + | port :: _ when port.PortType <> correctType -> Some { + Msg = sprintf "%A port %d appears to be an %A port" correctType (Option.get port.PortNumber) port.PortType + InDependency = None + ComponentsAffected = [ComponentId port.HostId] + ConnectionsAffected = [] } + | _ :: ports' -> + checkComponentPorts ports' correctType + /// Check conditions 3, 4, 5 + let rec checkComponentsPorts (components : Component list) = + match components with + | [] -> None + | comp :: components' -> + match checkComponentPorts comp.InputPorts PortType.Input, + checkComponentPorts comp.OutputPorts PortType.Output with + | Some err, _ | _, Some err -> Some err + | None, None -> checkComponentsPorts components' // Check next. + + let checkConnectionPort (port : Port) (correctType : PortType) (connId : string) = + match port.PortType = correctType, port.PortNumber with + | false, _ -> Some { + Msg = sprintf "%A port appears to be an %A port" correctType port.PortType + InDependency = None + ComponentsAffected = [ComponentId port.HostId] + ConnectionsAffected = [ConnectionId connId] } + | _, Some pNumber -> Some { + Msg = sprintf "%A port appears to have a port number: %d" correctType pNumber + InDependency = None + ComponentsAffected = [ComponentId port.HostId] + ConnectionsAffected = [ConnectionId connId] } + | true, None -> None // All right. + /// Check conditions 1, 2, 6 + let rec checkConnectionsPorts (connections : Connection list) = + match connections with + | [] -> None + | conn :: connections' -> + match checkConnectionPort conn.Source PortType.Output conn.Id, + checkConnectionPort conn.Target PortType.Input conn.Id with + | Some err, _ | _, Some err -> Some err + | None, None -> checkConnectionsPorts connections' // Check next. + + let components, connections = canvasState + match checkComponentsPorts components, + checkConnectionsPorts connections with + | Some err, _ | _, Some err -> Some err + | None, None -> None // All right. + +/// Apply condition on every element of the map (tailored to this specific +/// problem). +let private checkEvery + (counts : List<(Component list*Connection list)*int>) // 'a is either InputPortId or OutputPortId. + (cond : int -> bool) + (errMsg0, errMsg) + : SimulationError option = + (None, counts) ||> List.fold (fun maybeErr ((comps, conns), count) -> + match maybeErr with + | Some err -> Some err + | None -> + match cond count with + | true -> None + | false -> Some { + Msg = if count = 0 then sprintf errMsg0 else sprintf errMsg count + InDependency = None + ComponentsAffected = comps |> List.map (fun comp -> ComponentId comp.Id) + ConnectionsAffected = conns |> List.map (fun conn -> ConnectionId conn.Id) } + ) + + +/// Count the number of connections that target each port or group of label input ports +let private countPortsConnections + (conns : Connection list) + (connMap : Connection -> 'b) + (bins : 'b list) + (binMap : 'b -> Component list) = + let rec countPortsConnections' (conns : Connection list) (counts : Map<'b, int*Connection list>) = + match conns with + | [] -> counts |> Map.toList |> List.map (fun (key, (count, conns)) -> (binMap key, conns), count) + | conn :: conns' -> + let countsRes = + let key = connMap conn + + // Hacky fix + match Map.tryFind key counts with + | Some (binCount, binConns) -> counts.Add(key, (binCount + 1, conn :: binConns)) + | None -> counts + + countPortsConnections' conns' countsRes + countPortsConnections' conns (bins |> List.map (fun b -> b,(0,[])) |> Map.ofList) + + + +let private checkCounts (conns : Connection list) connMap bins binMap cond errMsg = + let totals = countPortsConnections conns connMap bins binMap + checkEvery totals cond errMsg + +let private checkConns (conns : Connection list) (m : MapData) : SimulationError option = + let compOfPort p = m.ToComp[ComponentId p.HostId] + conns + |> List.tryPick (fun conn -> + let s = compOfPort conn.Source + let t = compOfPort conn.Target + if s.Type = IOLabel && t.Type = IOLabel then + Some (s, t, conn) + else None) + |> Option.map (fun (s, t, conn) -> + (sprintf "You can't connect two Wire Labels with a wire. Delete the connecting wire. If you want to join two bus labels \ + you need only give them the same name - then they will form a single net.") + |> (fun errMsg -> { + Msg = errMsg + InDependency = None + ComponentsAffected = [ComponentId s.Id ; ComponentId t.Id] + ConnectionsAffected = [ConnectionId conn.Id] + } ) + ) + + + + +/// Check that: +/// - any port has at least one connection, +/// - any input port has precisely one connection. +/// These conditions may not hold due to user errors. +let private checkPortsAreConnectedProperly + (canvasState : CanvasState) = + let m = genMaps canvasState + let conns = m.Connections + let portMap (p:Port) = [m.ToComp[ComponentId p.HostId]] + let inPIdMap pid = m.ToInputPort[InputPortId pid] + let labMap (lab:string) = m.LabGroup[lab] + let l2Pid (lst: Port list) = lst |> List.map (fun x -> x.Id) + + [ + + checkCounts m.OtherTargetConns (fun conn -> conn.Target.Id) (l2Pid m.OtherInputPorts) (inPIdMap >> portMap) ((=) 1) ( + "Every component input port must be connected: but no connection was found", + "A component input port must have precisely one driving component, but %d \ + were found. If you want to merge wires together use a MergeWires component, not direct connection") + + checkCounts m.LabTargetConns (fun conn -> m.ToComp[ComponentId conn.Target.HostId].Label) (m.LabGroup |> Map.toList |> List.map fst) labMap ((=) 1) ( + "A set of labelled wires must be driven (on the input of one of the labels): but no such driver was found", + "A set of labelled wires must have precisely one driving component, but %d \ + were found. \ + If you are driving two labels from the same component delete one of them: \ + a set of labels with the same name are all connected together and only one \ + label in each same-name set must be driven.") + + checkCounts m.OtherSourceConns (fun conn -> conn.Source) m.OtherOutputPorts portMap ((<) 0) ( + "A component output port must have at least one connection. If the component output \ + is meant to be disconnected you can add a wire label to stop this error", "%d") + + + checkConns conns m + + + + ] |> List.tryPick id + + +/// Input/Output components in a simulationgraph all have unique labels. +let private checkIOLabels (canvasState : CanvasState) : SimulationError option = + let rec checkDuplicate (comps : Component list) (map : Map) (ioType : string) = + match comps with + | [] -> None + | comp :: comps' -> + match map.TryFind comp.Label with + | None -> checkDuplicate comps' map ioType + | Some compId when compId = comp.Id -> checkDuplicate comps' map ioType + | Some compId -> Some { + Msg = sprintf "Two %s components cannot have the same label: %s." ioType comp.Label + InDependency = None + ComponentsAffected = [comp.Id; compId] |> List.map ComponentId + ConnectionsAffected = [] + } + let toMap (comps : Component list) = + comps |> List.map (fun comp -> comp.Label, comp.Id) |> Map.ofList + let components, _ = canvasState + let inputs = + components + |> List.filter (fun comp -> match comp.Type with | Input _ -> true | _ -> false) + let outputs = + components + |> List.filter (fun comp -> match comp.Type with | Output _ -> true | _ -> false) + let labels = + components + |> List.filter (fun comp -> match comp.Type with | IOLabel _ -> true | _ -> false) + + match checkDuplicate inputs (toMap inputs) "Input", + checkDuplicate outputs (toMap outputs) "Output" with + | Some err, _| _, Some err -> Some err + | None, None -> None + + +type CustomComponentError = + | NoSheet of string + | BadInputs of ComponentSheet: string * InstLists: ((string*int) list)* CompLists: ((string*int) list) + | BadOutputs of ComponentSheet: string * InstLists: ((string*int) list)* CompLists: ((string*int) list) + +/// Check a single custom component for correct I/Os +let checkCustomComponentForOkIOs (c:Component) (args:CustomComponentType) (sheets: LoadedComponent list)= + let inouts = args.InputLabels,args.OutputLabels + let name = args.Name + let compare labs1 labs2 = + (labs1 |> Set) = (labs2 |> Set) + sheets + |> List.tryFind (fun sheet -> sheet.Name = name) + |> Option.map (fun sheet -> sheet, compare sheet.InputLabels args.InputLabels, compare sheet.OutputLabels args.OutputLabels) + |> function + | None -> Error ( c, NoSheet name) + | Some(_, true,true) -> Ok () + | Some(sheet,false,_) -> Error <| (c, BadInputs( name, sheet.InputLabels, args.InputLabels)) + | Some(sheet,true,false) -> Error <| (c, BadOutputs( name, sheet.OutputLabels, args.OutputLabels)) + + + +/// Custom components have I/Os which are the same (names) as the I/Os in the corresponding sheet +/// This can change if a sheet made into a custom component is edited +/// We do this check whenever a new sheet is opened +let checkCustomComponentsOk ((comps,_): CanvasState) (sheets: LoadedComponent list): SimulationError option = + let error (c:Component) msg = Some { + Msg = msg + InDependency = None + ComponentsAffected = [ComponentId c.Id] + ConnectionsAffected = [] + } + let disp portL = + portL + |> List.map fst + |> String.concat " , " + |> sprintf "%s" + comps + |> List.collect (function | {Type=Custom args} as c -> [checkCustomComponentForOkIOs c args sheets] | _ -> []) + |> Helpers.tryFindError + |> function | Ok _ -> None + | Error (c, NoSheet cName) -> + error c <| sprintf "Can't find a design sheet named %s for the custom component of this name" cName + | Error (c, BadInputs(cName, instIns, compIns)) -> + let instIns,compIns = disp instIns, disp compIns + error c <| sprintf "Sheet %s is used as a custom component. Instance In ports: %A are different from Component In ports: %A." cName instIns compIns + | Error (c, BadOutputs(cName, instOuts, compOuts)) -> + let instOus,compOuts = disp instOuts, disp compOuts + error c <| sprintf "Sheet %s is used as a custom component. Instance Out ports: %A are different from Component Out ports: %A." cName instOuts compOuts + + +/// Checks that all connections have consistent widths. +/// This function relies on the bus inferer, but also makes sure that all widths +/// can be inferred. +let private checkConnectionsWidths + (canvasState : CanvasState) + : SimulationError option = + let convertConnId (ConnectionId cId) = ConnectionId cId + let convertError (err : WidthInferError) : SimulationError = { + Msg = err.Msg + InDependency = None + ConnectionsAffected = err.ConnectionsAffected |> List.map convertConnId + ComponentsAffected = [] + } + match inferConnectionsWidth canvasState with + | Error err -> Some <| convertError err + | Ok connWidths -> + let faulty = connWidths |> Map.filter (fun _ width -> Option.isNone width) + match faulty.IsEmpty with + | true -> None // All good. + | _ -> Some { + Msg = "Could not infer all connections widths." + InDependency = None + ConnectionsAffected = + faulty |> Map.toList |> List.map (fun (cId, _) -> convertConnId cId) + ComponentsAffected = [] + } + + +/// check component labels are all unique and do not include protected values (CLK) +let checkComponentNamesAreOk ((comps,conns): CanvasState) = + let badNameErrors = + comps + |> List.filter (function | {Type = MergeWires _} | {Type = SplitWire _} | {Type = BusSelection _} -> false | _ -> true) + |> List.collect (fun comp -> + let label = comp.Label.ToUpper() + match label with + | "CLK" -> [comp, "Clk is not allowed as a name for a component or a Net. \ + Use the properties tab to give a different name to the highlighted component(s)."] + | "" -> [comp, "All components must have a unique alphanumeric name (e.g. 'G1'). An empty name is not allowed except for split and join and bus select.\ + Use the properties tab to give a non-empty name to the highlighted component(s)."] + | _ -> []) + |> List.groupBy snd + |> List.map (fun (msg, eLst) -> List.map fst eLst, msg) + let duplicateNameErrors = + comps + |> List.filter (function | {Type = IOLabel _ } | {Type = MergeWires _} | {Type=SplitWire _} | {Type = BusSelection _} -> false | _ -> true) + |> List.groupBy (fun comp -> comp.Label) + |> List.filter (fun (_, compL) -> List.length compL > 1) + |> List.map (fun (_, compL) -> compL, "Component names must be distinct. \ + Use the properties tab to give different names to the highlighted components") + List.tryHead (badNameErrors @ duplicateNameErrors) + |> Option.map (fun (comps,msg) -> + { + Msg = msg + InDependency = None + ConnectionsAffected = [] + ComponentsAffected = comps |> List.map (fun comp -> ComponentId comp.Id) + }) + + + +/// Analyse a CanvasState and return any error (or None). +let analyseState + (state : CanvasState) + (ldComps: LoadedComponent list) + : SimulationError option = + [ + checkPortTypesAreConsistent state + checkPortsAreConnectedProperly state + checkIOLabels state + checkCustomComponentsOk state ldComps + checkConnectionsWidths state + checkComponentNamesAreOk state + ] + |> List.tryFind Option.isSome + |> Option.flatten diff --git a/src/Renderer/Simulator/DependencyMerger.fs b/src/Renderer/Simulator/DependencyMerger.fs new file mode 100644 index 0000000..c7f8502 --- /dev/null +++ b/src/Renderer/Simulator/DependencyMerger.fs @@ -0,0 +1,319 @@ +(* + DependencyMerger.fs + + This module collects functions that allow to validate and merge all the + dependencies of a SimulationGraph. +*) + +module DependencyMerger + +open CommonTypes +open SimulatorTypes +open SimulationRunner +open SimulationBuilder +open Helpers + +/// Map a dependency name to its simulation graph. +type private DependencyMap = Map + +//======================// +// Analyse dependencies // +// =====================// + +/// Map every dependency name to its list of dependencies. +type private DependencyGraph = Map + +/// Get the name of all the dependency in a CanvasState. +let private getComponentDependencies (state : CanvasState) : string list = + let components, _ = state + components + |> List.filter (fun comp -> match comp.Type with | Custom _ -> true | _ -> false) + |> List.map (fun comp -> match comp.Type with | Custom c -> c.Name | _ -> failwith "what? Impossible, getComponentDependency") + +/// Try to get the canvasState for a dependency, or return error if none could +/// be found. +let private getDependencyState + (name : string) + (dependencies : LoadedComponent list) + : Result = + dependencies + |> List.tryFind (fun dep -> dep.Name = name) + |> function | Some dep -> Ok dep.CanvasState + | None -> Error { + Msg = sprintf "Could not resolve dependency: \"%s\". Make sure a dependency with such name exists in the current project." name + InDependency = None + ComponentsAffected = [] + ConnectionsAffected = [] + } + +/// Try to build a dependencyGraph for the dependencies, or return an error +/// if there are unknown unresolved dependencies. +let rec private buildDependencyGraph + (componentName : string) + (state : CanvasState) + (dependencies : LoadedComponent list) + (dependencyGraph : DependencyGraph) + : Result = + let rec iterateChildren children (dependencyGraph : DependencyGraph) = + match children with + | [] -> Ok dependencyGraph + | child :: children' -> + // Only analyse a child if it is not already in the dependencyGraph. + match dependencyGraph.TryFind child with + | Some _ -> iterateChildren children' dependencyGraph + | None -> + match getDependencyState child dependencies with + | Error err -> Error {err with InDependency = Some componentName} + | Ok childState -> + // Recur over child. + match buildDependencyGraph child childState + dependencies dependencyGraph with + | Error err -> Error err + | Ok dependencyGraph -> iterateChildren children' dependencyGraph + // We basically perform a dfs. + let children = getComponentDependencies state + let dependencyGraph = dependencyGraph.Add (componentName, children) + iterateChildren children dependencyGraph + +// Note: this cycle detection algorithm is similar to the one used in the +// analyser to spot cycles in combinatorial logic. Nonetheless, they are +// different enough that trying to make one general cycle detection algorithm +// would be quite a mess. + +type private DfsType = + // No cycle detected in the subtree. Return the new visited set and keep + // on exploring. + | NoCycle of Set + // Found a cycle and bactracking to record all components that form the + // cycle. Stop recording when the dependency name that closes the loop is + // reached. + | Backtracking of string list * string + // Done with backtracking. A cycle has been found and all the dependencies + // that form it have been recorded. + | Cycle of string list + +let rec private checkDependencyCycle + (currNode : string) + (depGraph : DependencyGraph) + (visited : Set) + (currStack : Set) + : DfsType = + let rec exploreChildren visited currStack children : DfsType = + match children with + | [] -> NoCycle visited + | child :: children' -> + match checkDependencyCycle child depGraph visited currStack with + | NoCycle visited -> + // Keep on exploring other children. + exploreChildren visited currStack children' + | Backtracking (cycle, cycleEnd) -> + match cycleEnd = currNode with + | true -> Cycle (currNode :: cycle) + | false -> Backtracking (currNode :: cycle, cycleEnd) + | Cycle cycle -> + Cycle cycle + + match currStack.Contains currNode, visited.Contains currNode with + | true, true -> + // Already visited in this subtree: cycle detected. + Backtracking ([currNode], currNode) + | false, true -> + // Already visited, and this node is part of no cycles. + NoCycle visited + | false, false -> + // New node. + let visited = visited.Add currNode + let currStack = currStack.Add currNode + match depGraph.TryFind currNode with + | None -> failwithf "what? Could not find dependency %s in cycle detection" currNode + | Some children -> children + |> exploreChildren visited currStack + | true, false -> + // A node in the stack must always be visited. + failwithf "what? Node never visited but in the stack, while detecting cycle: %s" currNode + +/// Validate and get simulation graph for all loaded dependencies. +let private buildDependencyMap + (loadedDependencies : LoadedComponent list) + : Result = + let dependenciesRes = + loadedDependencies + |> List.map (fun dep -> dep.Name, runCanvasStateChecksAndBuildGraph dep.CanvasState loadedDependencies) + // Check if any dependency has given an error. + let hasError (name, res) = match res with | Error _ -> true | Ok _ -> false + let extractOk (name, res) = match res with | Ok d -> name, d | Error e -> failwithf "what? Dependency %s expected to be Ok, but has error %A" name e + match List.tryFind hasError dependenciesRes with + | Some (name, Error err) -> + // Augument error saying that it happened in a dependency, so no + // irrelevant affected components or connections will be highlighted. + Error { err with InDependency = Some name; + ComponentsAffected = []; + ConnectionsAffected = [] } + | None -> + // All dependencies are Ok. + // Create a map from their name to their simulation graph. + dependenciesRes |> List.map extractOk |> Map.ofList |> Ok + | _ -> failwith "what? Impossible case in buildDependencyMap" + +/// Check if there are: +/// - unresolved dependencies +/// - loops in the dependencies +/// - errors in dependencies +/// If all dependencies are ok, return the dependencyMap. +/// Checks are only performed on the dependencies directly required by the +/// CanvasState passed. +let private checkDependenciesAndBuildMap + (currDiagramName : string) + (state : CanvasState) + (dependencies : LoadedComponent list) + : Result = + let rec prettyPrintCycle (cycle : string list) = + match cycle with + | [] -> "" + | [name] -> "\"" + name + "\"" + | name :: cycle' -> "\"" + name + "\" --> " + (prettyPrintCycle cycle') + match buildDependencyGraph currDiagramName state dependencies Map.empty with + | Error err -> Error err + | Ok dependencyGraph -> + match checkDependencyCycle currDiagramName dependencyGraph + Set.empty Set.empty with + | Backtracking _ -> // Impossible. + failwith "what? checkDependencyCycle finished while Backtracking" + | Cycle cycle -> +#if ASSERTS + assertThat (cycle.Length >= 2) + <| sprintf "Cycle must have at least 2 dependencies: %A" cycle +#endif + Error { + Msg = sprintf "Found a cycle in dependencies: %s." + <| prettyPrintCycle cycle + InDependency = None + ComponentsAffected = [] + ConnectionsAffected = [] + } + | NoCycle depsUsed -> + // Build dependency map for these dependencies. + dependencies + |> List.filter (fun dep -> depsUsed.Contains dep.Name) + |> buildDependencyMap + +//====================// +// Merge dependencies // +//====================// + +/// Convert the label of a port on a custom componetnt to its port number. +/// Assumes that all labels are unique, otherwise it is undefined behaviour. +let private labelToPortNumber label (labels : string list) = + match List.tryFindIndex ((=) label) labels with + | None -> failwithf "what? Label %s not present in %A" label labels + | Some pNumber -> pNumber + +/// Convert the portNumber of a custom componetnt to its port lablel. +let private portNumberToLabel (InputPortNumber pNumber) (inputLabels : string list) = +#if ASSERTS + assertThat (inputLabels.Length > pNumber) "portNumberToLabel" +#endif + inputLabels[pNumber] + +/// Extract simulation input values as map. +let private extractInputValuesAsMap graph graphInputs inputLabels : Map = + extractIncompleteSimulationIOs graphInputs graph + |> List.map ( + fun ((_, ComponentLabel compLabel, _), wireData) -> + InputPortNumber <| labelToPortNumber compLabel inputLabels, wireData) + |> Map.ofList + +/// Extract simulation output values as map. +let private extractOutputValuesAsMap graph graphOutputs outputLabels : Map = + extractSimulationIOs graphOutputs graph + |> List.map ( + fun ((_, ComponentLabel label, _), wireData) -> + OutputPortNumber <| labelToPortNumber label outputLabels, wireData) + |> Map.ofList + +/// Check that the outputs of a custom component have the same keys every time. +/// This should be the case as we always use the same extraction function, so +/// this function provides an extra guarantee that can probably be removed if +/// performance is a concern. +let private assertConsistentCustomOutputs + (outputs : Map) + (oldOutputs : Map) = +#if ASSERTS + outputs |> Map.map (fun pNumber _ -> + assertThat (Option.isSome <| oldOutputs.TryFind pNumber) + <| sprintf "assertConsistentCustomOutputs, old %A, new %A" oldOutputs outputs + ) |> ignore +#else + () +#endif + +/// Create the Reducer for a custom component. +/// Passing graphInputs and graphOutputs would not be strictly necessary, but it +/// is good for performance as so the Input and Output nodes don't have to be +/// searched every time. +let private makeCustomReducer + (custom : CustomComponentType) + (graphInputs : SimulationIO list) + (graphOutputs : SimulationIO list) + : ReducerInput -> ReducerOutput = + failwithf "Custom rducer should never be called" + +/// Recursively merge the simulationGraph with its dependencies (a dependecy can +/// have its own dependencies). +/// This function assumes there are no circular dependencies, otherwise it will +/// never terminate. +let rec private merger + (currGraph : SimulationGraph) + (dependencyMap : DependencyMap) + : SimulationGraph = + // For each custom component, replace the Reducer with one that: + // - when receiving an (InputPortNumber * Bit) entry (i.e. a new input), + // maps the InputPortNumber to the its label. + // - find the Input node in the dependency simulationGraph with that label. + // - feed the bit to that Input node. + // - extracts the outputs. + // - map the output labels to OutputPortNumbers, and this is the output of + // the reducer function. + // + // A dependency may have dependencies itself, so recursively call the merger + // as well. + let currGraphCopy = currGraph + (currGraph, currGraphCopy) + ||> Map.fold (fun currGraph compId comp -> + match comp.Type with + | Custom custom -> + let dependencyGraph = + match dependencyMap.TryFind custom.Name with + | None -> failwithf "what? Could not find dependency %s in dependencyMap" custom.Name + | Some dependencyGraph -> dependencyGraph + let dependencyGraph = merger dependencyGraph dependencyMap + // Augment the custom component with the initial + // CustomSimulationGraph and the Custom reducer (that allows to use + // and update the CustomSimulationGraph). + let graphInputs, graphOutputs = + getSimulationIOsFromGraph dependencyGraph + let newComp = { + comp with + CustomSimulationGraph = Some dependencyGraph + Reducer = fun _ -> failwithf "Reducer should never be used!" + } + currGraph.Add(compId, newComp) + | _ -> currGraph // Ignore non-custom components. + ) + +/// Try to resolve all the dependencies in a graph, and replace the reducer +/// of the custom components with a simulationgraph. +/// Return an error if there are problems with the dependencies. +/// For example, if the graph of an ALU refers to custom component such as +/// adders, replace them with the actual simulation graph for the adders. +let mergeDependencies + (currDiagramName : string) + (graph : SimulationGraph) + (state : CanvasState) + (loadedDependencies : LoadedComponent list) + : Result = + match checkDependenciesAndBuildMap currDiagramName state loadedDependencies with + | Error e -> Error e + | Ok dependencyMap -> + // Recursively replace the dependencies, in a top down fashion. + Ok <| merger graph dependencyMap diff --git a/src/Renderer/Simulator/FastCreate.fs b/src/Renderer/Simulator/FastCreate.fs new file mode 100644 index 0000000..250711d --- /dev/null +++ b/src/Renderer/Simulator/FastCreate.fs @@ -0,0 +1,544 @@ +module FastCreate +open CommonTypes +open TimeHelpers +open SimulatorTypes +open SynchronousUtils +open NumberHelpers + + +//------------------------------------------------------------------------------// +//------------Functions To Create Fast Simulation Data Structures---------------// +//------------------------------------------------------------------------------// + +//-----------------------------Fast Simulation Creation-------------------------// + +let inline assertThat cond msg = + if not cond + then failwithf "what? assert failed: %s" msg + +let makeStepArray (arr: 'T array) : StepArray<'T> = { Step = arr } + +let emptyGather = + { Labels = Map.empty + Simulation = Map.empty + CustomInputCompLinks = Map.empty + CustomOutputCompLinks = Map.empty + CustomOutputLookup = Map.empty + AllComps = Map.empty } + +let emptyFastSimulation () = + { ClockTick = 0 + MaxStepNum = -1 // this must be over-written + MaxArraySize = 600 // must be larger than max number of wavesim clocks + FGlobalInputComps = Array.empty + FConstantComps = Array.empty + FClockedComps = Array.empty + FOrderedComps = Array.empty + FIOActive = Map.empty + FIOLinks = [] + FComps = Map.empty + FSComps = Map.empty + FCustomOutputCompLookup = Map.empty + G = emptyGather } + +let getPathIds (cid, ap) = + let rec getPath ap = + match ap with + | [] -> [] + | cid :: rest -> (cid, List.rev rest) :: getPath rest + + getPath (List.rev ap) |> List.rev + + +let getFid (cid: ComponentId) (ap: ComponentId list) = + let ff (ComponentId Id) = Id + (cid, ap) + + +let getPortNumbers (sc: SimulationComponent) = + let ins,outs = + match sc.Type with + | Constant1 _ | Constant _ -> + 0,1 + | Input _ + | Output _ + | Viewer _ + | BusSelection _ + | BusCompare _ + | Not + | DFF + | Register _ + | IOLabel + | ROM1 _ + | AsyncROM1 _-> + 1,1 + | MergeWires + | NbitsXor _ + | RegisterE _ + | DFFE -> + 2,1 + | SplitWire _ -> + 1,2 + | Mux2 _ -> + 3,1 + | NbitsAdder _ -> + 3,2 + | AsyncRAM1 _ + | RAM1 _ -> + 2,1 + | Decode4 -> + 2,4 + | Demux2 -> + 2,2 + | Not | And | Or | Xor | Nand | Nor | Xnor -> 2,1 + | Custom _ -> failwithf "Custom components should not occur in fast simulation" + | AsyncROM _ | RAM _ | ROM _ -> failwithf "legacy component type is not supported" + + ins, outs + +let getOutputWidths (sc: SimulationComponent) (wa: int option array) = + + let putW0 w = wa[0] <- Some w + let putW1 w = wa[1] <- Some w + let putW2 w = wa[2] <- Some w + let putW3 w = wa[3] <- Some w + + match sc.Type with + | ROM _ | RAM _ | AsyncROM _ -> + failwithf "What? Legacy RAM component types should never occur" + | Input w + | Output w + | Viewer w + | Register w + | RegisterE w + | SplitWire w + | BusSelection (w, _) + | Constant1 (w, _,_) + | Constant (w,_) + | NbitsXor w -> putW0 w + | NbitsAdder w -> + putW0 w + putW1 1 + | Not + | And + | Or + | Xor + | Nand + | Nor + | Xnor + | BusCompare _ -> putW0 1 + | AsyncROM1 mem + | ROM1 mem + | RAM1 mem + | AsyncRAM1 mem -> putW0 mem.WordWidth + | Custom _ -> () + | DFF + | DFFE -> putW0 1 + | Decode4 -> + putW0 1 + putW1 1 + putW2 1 + putW3 1 + | Demux2 + | Mux2 + | IOLabel + | MergeWires -> () + + wa + + +/// create a FastComponent data structure with data arrays from a SimulationComponent. +/// numSteps is the number of past clocks data kept - arrays are managed as circular buffers. +let createFastComponent (numSteps: int) (sComp: SimulationComponent) (accessPath: ComponentId list) = + let inPortNum, outPortNum = getPortNumbers sComp + // dummy arrays wil be replaced by real ones when components are linked after being created + let ins = + [| 0 .. inPortNum - 1 |] + |> Array.map (fun n -> Array.create (numSteps + 1) emptyFastData) + |> Array.map makeStepArray + + let outs = + [| 0 .. outPortNum - 1 |] + |> Array.map (fun n -> Array.create (numSteps + 1) emptyFastData) + |> Array.map makeStepArray + + let inps = + let dat = + match accessPath, sComp.Type with + // top-level input needs special inputs because they can't be calculated + | [], Input width -> List.replicate width Zero + | _ -> [] + + [| 0 .. inPortNum - 1 |] + |> Array.map (fun i -> (Array.create (numSteps + 1) dat)) + + let state = + if couldBeSynchronousComponent sComp.Type then + Some(Array.create numSteps NoState) + else + None + + let fId = getFid sComp.Id accessPath + + let reduceIfHybrid sc ipn = + if isHybridComponent sc.Type then + [0..ipn] + |> List.sumBy (fun ipn -> + getHybridComponentAsyncOuts sc.Type (InputPortNumber ipn) + |> function | None | Some [] -> 0 | Some _ -> 1) + else ipn + + { OutputWidth = getOutputWidths sComp (Array.create outPortNum None) + State = Option.map makeStepArray state + SimComponent = sComp + fId = fId + cId = sComp.Id + FType = sComp.Type + AccessPath = accessPath + Touched = false + DrivenComponents = [] + NumMissingInputValues = reduceIfHybrid sComp inPortNum + InputLinks = ins + InputDrivers = Array.create inPortNum None + Outputs = outs + FullName = "" + VerilogOutputName = Array.create outPortNum "" + VerilogComponentName = "" + Active = + match sComp.Type with + | IOLabel _ -> false + | _ -> true } + +/// extends the simulation data arrays of the component to allow more steps +/// No longer used now arrays are circular? +let extendFastComponent (numSteps: int) (fc: FastComponent) = + let oldNumSteps = fc.Outputs[0].Step.Length + + + if numSteps + 1 <= oldNumSteps then + () // done + else + let extendArray (arr: StepArray<'T>) (dat: 'T) = + let oldArr = arr.Step + let a = + Array.init + (numSteps + 1) + (fun i -> + if i < Array.length oldArr then + oldArr[i] + else + dat) + + arr.Step <- a + + let inPortNum, outPortNum = getPortNumbers fc.SimComponent + + // Input inputs at top level are a special case not mapped to outputs. + // They must be separately extended. + match fc.FType, fc.AccessPath with + | Input _, [] -> extendArray fc.InputLinks[0] fc.InputLinks[0].Step[oldNumSteps - 1] + | _ -> () + + [| 0 .. outPortNum - 1 |] + |> Array.iter (fun n -> extendArray fc.Outputs[n] emptyFastData) + + Option.iter + (fun (stateArr: StepArray) -> + extendArray stateArr stateArr.Step[oldNumSteps - 1]) + fc.State + + +/// extends the simulation data arrays of all components to allow more steps +/// also truncates fast simulation to prevent memory overuse. +let extendFastSimulation (numSteps: int) (fs: FastSimulation) = + if numSteps + 1 < fs.MaxStepNum then + () + else + [| fs.FOrderedComps + fs.FConstantComps + Array.filter (fun fc -> not (isHybridComponent fc.FType)) fs.FClockedComps + fs.FGlobalInputComps |] + |> Array.iter (Array.iter (extendFastComponent numSteps)) + + fs.MaxStepNum <- numSteps + + +/// Create an initial flattened and expanded version of the simulation graph with inputs, non-ordered components, simulationgraph, etc +/// This must explore graph recursively extracting all the initial information. +/// Custom components are scanned and links added, one for each input and output +let rec private createFlattenedSimulation (ap: ComponentId list) (graph: SimulationGraph) = + let graphL = Map.toList graph + let allComps = + graphL + |> List.map (fun (cid,comp) -> (cid, ap),(comp, ap)) + let labels = List.map (fun (cid,comp) -> cid, ((fun (ComponentLabel s) -> s) comp.Label)) graphL + let topGather = + { + Labels = labels + AllCompsT = allComps + CustomInputCompLinksT = [] + CustomOutputCompLinksT = [] + } + let customComps = + graphL + |> List.collect ( fun (cid,comp) -> + match comp.Type, comp.CustomSimulationGraph with + | Custom ct, Some csg -> [cid, ct, csg] + | _ -> []) + let insideCustomGathers = + customComps + |> List.map (fun (cid, ct, csg) -> + let ap' = ap @ [ cid ] + let gatherT = createFlattenedSimulation ap' csg + let compsInCustomComp = Map.toList csg |> List.map snd + /// Function making links to custom component input or output components + /// For those component types selected by compSelectFun (inputs or ouputs): + /// Link label and width (which will also be the custom comp port label and width) + /// to the Id of the relevant Input or output component. + let getCustomNameIdsOf compSelectFun = + compsInCustomComp + |> List.filter (fun comp -> compSelectFun comp.Type) + |> List.map + (fun comp -> + (comp.Label, + match comp.Type with + | Input n -> n + | Output n -> n + | _ -> -1), + comp.Id) + + let outputs = getCustomNameIdsOf isOutput + /// maps Output component Id to corresponding Custom component Id & output port + let outLinks = + ct.OutputLabels + |> List.mapi + (fun i (lab, labOutWidth) -> + let out = + List.find (fun (k,v) -> k = (ComponentLabel lab, labOutWidth)) outputs + |> snd + (out, ap'), ((cid, ap), OutputPortNumber i)) + + let inputs = getCustomNameIdsOf isInput + /// maps Custom Component Id and input port number to corresponding Input Component Id + let inLinks = + ct.InputLabels + |> List.mapi + (fun i (lab, labOutWidth) -> + let inp = + List.find (fun (k,v) -> k = (ComponentLabel lab, labOutWidth)) inputs + |> snd + (((cid, ap), InputPortNumber i), (inp, ap'))) + { + CustomInputCompLinksT = inLinks @ gatherT.CustomInputCompLinksT + CustomOutputCompLinksT = outLinks @ gatherT.CustomOutputCompLinksT + Labels = labels @ gatherT.Labels + AllCompsT = gatherT.AllCompsT + }) + (topGather, insideCustomGathers) + ||> List.fold (fun total thisGather -> + { + CustomInputCompLinksT = thisGather.CustomInputCompLinksT @ total.CustomInputCompLinksT + CustomOutputCompLinksT = thisGather.CustomOutputCompLinksT @ total.CustomOutputCompLinksT + Labels = thisGather.Labels @ total.Labels + AllCompsT = thisGather.AllCompsT @ total.AllCompsT + + }) +/// convert the data in the flattened structure into maps for easy access +let gatherSimulation (graph: SimulationGraph) = + let startTime = getTimeMs() + createFlattenedSimulation [] graph + |> (fun g -> + { + Simulation = graph + CustomInputCompLinks = Map.ofList g.CustomInputCompLinksT + CustomOutputCompLinks = Map.ofList g.CustomOutputCompLinksT + Labels = Map.ofList g.Labels + AllComps = Map.ofList g.AllCompsT + CustomOutputLookup = Map.ofList (List.map (fun (k,v) -> v,k) g.CustomOutputCompLinksT) + }) + |> instrumentInterval "gatherGraph" startTime + + +let printGather (g: GatherData) = + printfn "%d components" g.AllComps.Count + + Map.iter + (fun (cid, ap) (comp: SimulationComponent, ap') -> printfn "%s (%A:%A): %A" (g.getFullName (cid, ap)) cid ap comp.Outputs) + g.AllComps + + Map.iter + (fun ((cid, ap),ipn) (cid', ap') -> printfn "inlink: %s -> %A" (g.getFullName (cid, ap)) (cid',ap')) + g.CustomInputCompLinks + + Map.iter + (fun (cid', ap') ((cid, ap),opn) -> printfn "outlink: %A -> %s" (cid',ap') (g.getFullName (cid, ap)) ) + g.CustomOutputCompLinks + +let rec createInitFastCompPhase (numSteps: int) (g: GatherData) (f: FastSimulation) = + let start = getTimeMs() + let makeFastComp cid = + let comp, ap = g.AllComps[cid] + let fc = createFastComponent numSteps comp ap + let fc = { fc with FullName = g.getFullName cid } + + let outs : StepArray array = + (if isOutput comp.Type then + let outs = + [| Array.create (numSteps + 1) emptyFastData |> makeStepArray |] + + outs + else + fc.Outputs) + + //printfn "***Making %A with %d outs" comp.Type outs.Length + { fc with Outputs = outs } + + let comps : Map = + (Map.empty, g.AllComps) + ||> Map.fold + (fun m cid (comp, ap) -> + if isCustom comp.Type then + m + else + Map.add (comp.Id, ap) (makeFastComp (comp.Id, ap)) m) + + let customOutLookup = + g.CustomOutputCompLinks + |> Map.toList + |> List.map (fun (a, b) -> b, a) + |> Map.ofList + instrumentTime "createInitFastCompPhase" start + { f with + FComps = comps + MaxStepNum = numSteps + FSComps = g.AllComps + FCustomOutputCompLookup = customOutLookup } + +/// has side effect of making IOLabels of same name (in the same graph) all use same output array +/// this means that an input to any one will produce an output on all, for no effort. +/// IOLabels without driven inputs that are thus not used are later on flagged inactive +/// they must not be reduced, and will not be included in the ordered component list +let private reLinkIOLabels (fs: FastSimulation) = + // Go through all the components driven by IOLabels and link them from the active label + // at this point exactly one out of every labelled set will be active, and contained in FIOActive + fs.FIOLinks + |> List.iter (fun ((fcDriven, InputPortNumber ipn), ioDriver) -> + let labKey = ioDriver.SimComponent.Label, ioDriver.AccessPath + let fcActiveDriver = fs.FIOActive[labKey] + fcDriven.InputLinks[ipn] <- fcActiveDriver.Outputs[0] + fcDriven.InputDrivers[ipn] <- Some (fcActiveDriver.fId, OutputPortNumber 0) + // DrivenComponents must only include asynchronous drive paths on hybrid components + // on clocked components, or combinational components, it can include all drive paths + match getHybridComponentAsyncOuts fcDriven.FType (InputPortNumber ipn) with + | None | Some (_ :: _) -> + fcActiveDriver.DrivenComponents <- fcDriven :: fcActiveDriver.DrivenComponents + | _ -> () + ioDriver.Outputs[0] <- fcActiveDriver.Outputs[0]) + +/// Use the Outputs links from the original SimulationComponents in gather to link together the data arrays +/// of the FastComponents. +/// InputLinks[i] array is set equal to the correct driving Outputs array so that Input i reads the data reduced by the +/// correct output of the component that drives it. +/// The main work is dealing with custom components which represent whole design sheets with recursively defined component graphs +/// The custom component itself is not linked, and does not exist as a FastComponent. Instead its CustomSimulationGraph Input and Output components +/// are linked to the components that connect the corresponding inputs and outputs of the custom component. +let linkFastComponents (g: GatherData) (f: FastSimulation) = + let start = getTimeMs() + let outer = List.rev >> List.tail >> List.rev + let sComps = g.AllComps + let fComps = f.FComps + let getSComp (cid, ap) = + let x = Map.tryFind (cid, ap) sComps + match x with + | None -> + failwithf $"Error in linkFastComponents: can't find\n---{cid}\n----{ap}\n" + | Some comp -> fst comp + let apOf fid = fComps[fid].AccessPath + /// This function recursively propagates a component output across Custom component boundaries to find the + /// + let rec getLinks ((cid, ap): FComponentId) (opn: OutputPortNumber) (ipnOpt: InputPortNumber option) = + let sComp = getSComp (cid, ap) + //printfn "Getting links: %A %A %A" sComp.Type opn ipnOpt + match isOutput sComp.Type, isCustom sComp.Type, ipnOpt with + | true, _, None when apOf (cid, ap) = [] -> [||] // no links in this case from global output + | true, _, None -> + //printfn "checking 1:%A %A" (g.getFullName(cid,ap)) (Map.map (fun k v -> g.getFullName k) g.CustomOutputCompLinks) + let fid, opn = g.CustomOutputCompLinks[cid, ap] +#if ASSERTS + assertThat (isCustom (fst sComps[fid]).Type) "What? this should be a custom component output" +#endif + getLinks fid opn None // go from inner output to CC output and recurse + | false, true, Some ipn -> + //printfn "checking 2:%A:IPN<%A>" (g.getFullName(cid,ap)) ipn + //printfn "CustomInCompLinks=\n%A" (Map.map (fun (vfid,vipn) fid -> + //sprintf "%A:%A -> %A\n" (g.getFullName vfid) vipn (g.getFullName fid) ) g.CustomInputCompLinks |> mapValues) + //printfn "Done" + [| g.CustomInputCompLinks[(cid, ap), ipn], opn, InputPortNumber 0 |] // go from CC input to inner input: must be valid + | _, false, Some ipn -> [| (cid, ap), opn, ipn |] // must be a valid link + | false, _, None -> + sComp.Outputs + |> Map.toArray + |> Array.filter (fun (opn', _) -> opn' = opn) + |> Array.collect + (fun (opn, lst) -> + lst + |> List.toArray + |> Array.collect (fun (cid, ipn) -> getLinks (cid, ap) opn (Some ipn))) + + | x -> failwithf "Unexpected link match: %A" x + + let mutable linkCheck : Map<(FComponentId * InputPortNumber), (FComponentId * OutputPortNumber)> = Map.empty + + f.FComps + |> Map.iter + (fun fDriverId fDriver -> + let outs = fDriver.Outputs + fDriver.Outputs + |> Array.iteri + (fun iOut _ -> + getLinks fDriverId (OutputPortNumber iOut) None + |> Array.map (fun (fid, _, ip) -> fid, iOut, ip) + |> Array.iter + (fun (fDrivenId, opn, (InputPortNumber ipn)) -> + let linked = + Map.tryFind (fDrivenId, InputPortNumber ipn) linkCheck + + match linked with + | None -> () + | Some (fid, opn) -> + failwithf "Multiple linkage: (previous driver was %A,%A)" (g.getFullName fid) opn + + linkCheck <- Map.add (fDrivenId, InputPortNumber ipn) (fDriverId, OutputPortNumber opn) linkCheck + let fDriven = f.FComps[fDrivenId] + let (_, ap) = fDrivenId + + // we have a link from fDriver to fDriven + + if isIOLabel fDriven.FType then + // fDriven is a driven label of a set of IOlabels + let labelKey = fDriven.SimComponent.Label, ap + if not (Map.containsKey labelKey f.FIOActive) then + // Make this then unique driven label in the fast simulation + f.FIOActive <- Map.add labelKey fDriven f.FIOActive + fDriven.Active <- true + + if isIOLabel fDriver.FType then + // we do not yet know which label will be active, so record all links from + // labels for later resolution + f.FIOLinks <- ((fDriven, InputPortNumber ipn), fDriver) :: f.FIOLinks + else + // if driver is not IO label make the link now + fDriven.InputLinks[ipn] <- fDriver.Outputs[opn] + // DrivenComponents must only include asynchronous drive paths on hybrid components + // on clocked components, or combinational components, it can include all drive paths + match getHybridComponentAsyncOuts fDriven.FType (InputPortNumber ipn) with + | None | Some (_ :: _) -> + fDriver.DrivenComponents <- fDriven :: fDriver.DrivenComponents + | _ -> () + + fDriven.InputDrivers[ipn] <- Some (fDriver.fId, OutputPortNumber opn) + ))) + reLinkIOLabels f + instrumentTime "linkFastComponents" start + f + diff --git a/src/Renderer/Simulator/FastReduce.fs b/src/Renderer/Simulator/FastReduce.fs new file mode 100644 index 0000000..5da67b6 --- /dev/null +++ b/src/Renderer/Simulator/FastReduce.fs @@ -0,0 +1,502 @@ +module FastReduce +open CommonTypes +open SimulatorTypes +open NumberHelpers + +//------------------------------------------------------------------------------// +//-----------------------------Fast Reduction of Components---------------------// +//------------------------------------------------------------------------------// + + + +//------------------------------------------------------------------------------// +// ----------Subfunctions used by fastReduce to evaluate a component-----------// +//------------------------------------------------------------------------------// + +let inline assertThat cond msg = + if not cond + then failwithf "what? assert failed: %s" msg + +/// Assert that the FData only contain a single bit, and return such bit. +let inline extractBit (fd: FData) : uint32 = +#if ASSERTS + assertThat (fd.Width = 1) + <| sprintf "extractBit called with wireData: %A" fd +#endif + match fd.Dat with | Word n -> n | BigWord _ -> failwithf $"Can't extract 1 bit from BigWord data {fd.Dat} of width {fd.Width}" + +let inline packBit (bit: uint32) : FData = if bit = 0u then {Dat=Word 0u; Width = 1} else {Dat = Word 1u; Width = 1} + + +/// Read the content of the memory at the specified address. +let private readMemory (mem: Memory1) (address: FData) : FData = + let intAddr = convertFastDataToInt64 address + let outDataInt = Helpers.getMemData (int64 intAddr) mem + convertInt64ToFastData mem.WordWidth outDataInt + +/// Write the content of the memory at the specified address. +let private writeMemory (mem: Memory1) (address: FastData) (data: FastData) : Memory1 = + let intAddr = int64 <| convertFastDataToInt64 address + let intData = int64 <| convertFastDataToInt64 data + + { mem with + Data = Map.add intAddr intData mem.Data } + +let private getRamStateMemory numSteps step (state: StepArray option) memory : Memory1 = + match state, numSteps with + | _, 1 -> memory + | Some arr, _ -> + match arr.Step[step] with + | RamState memory -> memory + | _ -> failwithf "What? getRamStateMemory called with invalid state" + | _ -> failwithf "what? getRamStateMemory called with an invalid state: %A" state + +let getRomStateMemory comp = + match comp.FType with + | ROM memory + | AsyncROM memory -> memory + | _ -> failwithf "What? getRomStateMemory called with invalid state" + + +let inline private bitNot bit = bit ^^^ 1u + +let inline private bitAnd bit0 bit1 = bit0 &&& bit1 + + +let inline private bitOr bit0 bit1 = bit0 ||| bit1 + + +let inline private bitXor bit0 bit1 = bit0 ^^^ bit1 + + +let inline private bitNand bit0 bit1 = bitAnd bit0 bit1 |> bitNot + +let inline private bitNor bit0 bit1 = bitOr bit0 bit1 |> bitNot + +let inline private bitXnor bit0 bit1 = bitXor bit0 bit1 |> bitNot + + + + +//---------------------------------------------------------------------------------------// +// ------------------------------MAIN COMPONENT SIMULATION FUNCTION----------------------// +//---------------------------------------------------------------------------------------// + + +/// Given a component, compute its outputs from its inputs, which must already be evaluated. +/// Outputs and inputs are both contained as time sequences in arrays. This function will calculate +/// simStep outputs from (previously calculated) simStep outputs and clocked (simStep-1) outputs. +/// Memory has state separate from simStep-1 output, for this the state is recalculated. +let fastReduce (maxArraySize: int) (numStep: int) (isClockedReduction: bool) (comp: FastComponent) : Unit = + let componentType = comp.FType + + //printfn "Reducing %A...%A %A (step %d) clocked=%A" comp.FType comp.ShortId comp.FullName numStep isClockedReduction + let n = comp.InputLinks.Length + + let simStep = numStep % maxArraySize + let simStepOld = if simStep = 0 then maxArraySize - 1 else simStep - 1 + + + /// get data feom input i of component + let inline ins i = +#if ASSERTS + assertThat (i < n) (sprintf "What? Invalid input port (%d:step%d) used by %s:%s (%A) reducer with %d Ins" + i simStep comp.FullName comp.ShortId componentType n) +#endif + let fd = comp.InputLinks[i].Step[simStep] + fd + + /// get last cycle data from output i (for clocked components) + let inline getLastCycleOut n = + let fd = + match comp.OutputWidth[n], numStep with + | None, _ -> failwithf "Can't reduce %A (%A) because outputwidth is not known" comp.FullName comp.FType + | Some w, 0 -> if w < 33 then {Dat=Word 0u; Width = w} else {Dat =BigWord (bigint 0); Width = w} + | Some w, _ -> comp.Outputs[n].Step[simStepOld] + fd + + /// get last cycle data from output i for component + let inline insOld i = +#if ASSERTS + assertThat + (i < n) + (sprintf + "What? Invalid input port (%d:step%d) used by %s (%A) reducer with %d Ins" + i + simStep + comp.FullName + componentType + n) +#endif + + let fd = + comp.GetInput(simStepOld) (InputPortNumber i) + fd + + /// Write current step output data for output port 0 + let inline put0 fd = + comp.PutOutput(simStep) (OutputPortNumber 0) fd + + /// Write current step output data for output port 1 + let inline put1 fd = + comp.PutOutput(simStep) (OutputPortNumber 1) fd + + /// Write current step output data for output port 2 + let inline put2 fd = + comp.PutOutput(simStep) (OutputPortNumber 2) fd + + /// Write current step output data for output port 3 + let inline put3 fd = + comp.PutOutput(simStep) (OutputPortNumber 3) fd + + /// Write current step output data for output port 4 + let inline put4 fd = + comp.PutOutput(simStep) (OutputPortNumber 4) fd + + /// Write current State (used only for RAMs, DFFs and registers use previous cycle output as state) + let inline putState state = + match comp.State with + | None -> failwithf "Attempt to put state into component %s without state array" comp.FullName + | Some stateArr -> stateArr.Step[simStep] <- state + + let inline putW num w = comp.OutputWidth[num] <- Some w + + /// implement a binary combinational operation + let inline getBinaryGateReducer (op: uint32 ->uint32 -> uint32) : Unit = + let bit0 = (ins 0).GetQUint32 + let bit1 = (ins 1).GetQUint32 + put0 <| {Width=1; Dat = Word (op bit1 bit0)} + + /// Error checking (not required in production code) check widths are consistent + let inline checkWidth width (bits: FData) = +#if ASSERTS + assertThat + (bits.Width = width) + (sprintf + "Input node reducer for (%A:%A - STEP %d) received wrong number of bits: expected %d but got %d" + comp.FullName + comp.FType + simStep + width + bits.Width) +#else + () +#endif + + // reduce the component in this match + match componentType with + | ROM _ | RAM _ | AsyncROM _ -> + failwithf "What? Legacy RAM component types should never occur" + | Input width -> + if comp.Active then + let bits = ins 0 + //printfn "Got input 0 = %A Links=<%A> len=%d" bits comp.InputLinks comp.InputLinks.Length + checkWidth width bits + //printfn "output array = %A" comp.Outputs + put0 bits + //printfn "Finished!" + + | Constant1 (width, cVal,_) | Constant (width,cVal)-> + put0 + <| convertInt64ToFastData width cVal + | Output width -> + let bits = ins 0 + //printfn "In output bits=%A, ins = %A" bits comp.InputLinks + checkWidth width bits + put0 bits + | Viewer width -> + let bits = ins 0 + //printfn "In output bits=%A, ins = %A" bits comp.InputLinks + checkWidth width bits + put0 bits + + | IOLabel -> + let bits = ins 0 + //let bits = comp.InputLinks[0][simStep] + //printfn "Reducing IOLabel %A" comp.SimComponent.Label + put0 bits + | Not -> + let bit = extractBit (ins 0) + put0 <| packBit (bitNot bit) + | BusSelection (width, lsb) -> + let bits = ins 0 +#if ASSERTS + assertThat + (bits.Width >= width + lsb) + (sprintf "Bus Selection received too few bits: expected at least %d but got %d" (width + lsb) bits.Width) +#endif + let outBits = getBits (lsb + width - 1) lsb bits + put0 outBits + | BusCompare (width, compareVal) -> + //printfn "Reducing compare %A" comp.SimComponent.Label + let bits = ins 0 +#if ASSERTS + assertThat + (bits.Width = width) + ($"Bus Compare {comp.FullName} received wrong number of bits: expecting {width} but got {bits.Width}") +#endif + let inputNum = convertFastDataToInt bits + + let outNum : FData = + if inputNum = compareVal then 1u else 0u + |> packBit + + + put0 outNum + | And -> getBinaryGateReducer bitAnd + | Or -> getBinaryGateReducer bitOr + | Xor -> getBinaryGateReducer bitXor + | Nand -> getBinaryGateReducer bitNand + | Nor -> getBinaryGateReducer bitNor + | Xnor -> getBinaryGateReducer bitXnor + | Mux2 -> + let bits0, bits1, bitSelect = ins 0, ins 1, ins 2 +#if ASSERT + assertThat (bits0.Width = bits1.Width) + <| sprintf "Mux2 %s received two inputs with different widths: (%A) <> (%A)" comp.FullName bits0 bits1 +#endif + let out = + if (extractBit bitSelect) = 0u then + bits0 + else + bits1 + + put0 out + putW 0 bits0.Width + | Demux2 -> + let bitsIn, bitSelect = ins 0, ins 1 + let zeros = convertIntToFastData bitsIn.Width 0u + + let out0, out1 = + if (extractBit bitSelect) = 0u then + bitsIn, zeros + else + zeros, bitsIn + + let w = bitsIn.Width + put0 out0 + put1 out1 + putW 0 w + putW 1 w + | NbitsAdder numberOfBits -> + let cin, A, B = ins 0, ins 1, ins 2 + + let sum, cout = + let cin = convertFastDataToInt cin + let w = A.Width + match A.Dat, B.Dat with + | BigWord a, BigWord b -> + let mask = bigIntMask w + let a = a &&& mask + let b = b &&& mask + let sumInt = if cin = 0u then a + b else a + b + bigint 1 + let sum = {Dat = BigWord (sumInt &&& bigIntMask w); Width = w} + let cout = if (sumInt >>> w) = bigint 0 then 0u else 1u + sum, packBit cout + | Word a, Word b -> + let mask = (1ul <<< w) - 1ul + if w = 32 then + // mask is not needed, but 64 bit adition is needed! + let sumInt = uint64 a + uint64 b + uint64 (cin &&& 1u) + let cout = uint32 (sumInt >>> w) &&& 1u + let sum = convertIntToFastData w (uint32 sumInt) + sum, packBit cout + else + let sumInt = (a &&& mask) + (b &&& mask) + (cin &&& 1u) + let cout = (sumInt >>> w) &&& 1u + let sum = convertIntToFastData w (sumInt &&& mask) + sum, packBit cout + + | a, b -> + failwithf $"Inconsistent inputs to NBitsAdder {comp.FullName} A={a},{A}; B={b},{B}" + + put0 sum + put1 cout + | NbitsXor numberOfBits -> + let A, B = ins 0, ins 1 + let outDat = + match A.Dat, B.Dat with + | BigWord a, BigWord b -> + BigWord (a ^^^ b) + | Word a, Word b -> + Word (a ^^^ b) + | a,b -> + failwithf $"Inconsistent inputs to NBitsXOr {comp.FullName} A={a},{A}; B={b},{B}" + + put0 {A with Dat = outDat} + | Decode4 -> + let select, data = ins 0, ins 1 + let selN = convertFastDataToInt select |> int + let dataN = convertFastDataToInt data |> int + + let outs = + [| 0 .. 3 |] + |> Array.map + (fun n -> + let outBit = if n = selN then dataN else 0 + convertIntToFastData 1 (uint32 outBit)) + + put0 outs[0] + put1 outs[1] + put2 outs[2] + put3 outs[3] + + | Custom c -> + // Custom components are removed + failwithf "what? Custom components are removed before the fast simulation: %A" c + | MergeWires -> + let bits0, bits1 = ins 0, ins 1 + // Little endian, bits coming from the top wire are the least + // significant. + let wOut = bits0.Width + bits1.Width + let outBits = + if wOut <= 32 then + match bits0.Dat, bits1.Dat with + | Word b0, Word b1 -> + (b1 <<< bits0.Width) ||| b0 + |> (fun n -> convertIntToFastData wOut n) + | _ -> failwithf $"inconsistent merge widths: {bits0},{bits1}" + else + let b0 = convertFastDataToBigint bits0 + let b1 = convertFastDataToBigint bits1 + (b1 <<< bits0.Width) ||| b0 + |> convertBigintToFastData wOut + put0 outBits + putW 0 outBits.Width + | SplitWire topWireWidth -> + let bits = ins 0 +#if ASSERTS + assertThat (bits.Width >= topWireWidth + 1) + <| sprintf "SplitWire received too little bits: expected at least %d but got %d" (topWireWidth + 1) bits.Width +#endif + let bits0, bits1 = + let bits1 = getBits (bits.Width - 1) topWireWidth bits + let bits0 = getBits (topWireWidth-1) 0 bits + bits0, bits1 + + + // Little endian, bits leaving from the top wire are the least + // significant. + put0 bits0 + put1 bits1 + putW 1 bits1.Width + | DFF -> + let d = extractBit (insOld 0) + put0 (packBit d) + | DFFE -> + let d, en = + extractBit (insOld 0), extractBit (insOld 1) + + if en = 1u then + put0 <| packBit d + else + put0 (getLastCycleOut 0) + + | Register width -> + let bits = insOld 0 +#if ASSERTS + assertThat (bits.Width = width) + <| sprintf "Register received data with wrong width: expected %d but got %A" width bits.Width +#endif + put0 bits + + | RegisterE width -> + let bits, enable = insOld 0, insOld 1 +#if ASSERTS + assertThat (bits.Width = width) + <| sprintf "RegisterE received data with wrong width: expected %d but got %A" width bits.Width +#endif + if (extractBit enable = 1u) then + put0 bits + else + put0 (getLastCycleOut 0) + | AsyncROM1 mem -> // Asynchronous ROM. + let addr = ins 0 +#if ASSERTS + assertThat (addr.Width = mem.AddressWidth) + <| sprintf "ROM received address with wrong width: expected %d but got %A" mem.AddressWidth addr +#endif + let outData = readMemory mem addr + put0 outData + | ROM1 mem -> // Synchronous ROM. + let addr = insOld 0 +#if ASSERTS + assertThat (addr.Width = mem.AddressWidth) + <| sprintf "ROM received address with wrong width: expected %d but got %A" mem.AddressWidth addr +#endif + let outData = readMemory mem addr + put0 outData + | RAM1 memory -> + let mem = + getRamStateMemory numStep (simStepOld) comp.State memory + + let address = insOld 0 +#if ASSERTS + assertThat (address.Width = mem.AddressWidth) + <| sprintf "RAM received address with wrong width: expected %d but got %A" mem.AddressWidth address +#endif + let dataIn = insOld 1 +#if ASSERTS + assertThat (dataIn.Width = mem.WordWidth) + <| sprintf "RAM received data-in with wrong width: expected %d but got %A" mem.WordWidth dataIn +#endif + let write = extractBit (insOld 2) + // If write flag is on, write the memory content. + let mem, dataOut = + match write with + | 0u -> + // Read memory address and return memory unchanged. + mem, readMemory mem address + | 1u -> + // Update memory and return old content. + // NB - this was previously new content - but that is inconsistent and less useful. + writeMemory mem address dataIn, readMemory mem address + | _ -> failwithf $"simulation error: invalid 1 bit write value {write}" + + putState (RamState mem) + put0 dataOut + // AsyncRAM1 component must be evaluated twice. Once (first) as clocked component + // to update state based on previous cycle. Then again as combinational component to update output + // + | AsyncRAM1 memory -> + if isClockedReduction then + // here we propagate the state to current timestep, doing a state change if need be. + let mem = + getRamStateMemory numStep (simStepOld) comp.State memory + + let address = insOld 0 +#if ASSERTS + assertThat (address.Width = mem.AddressWidth) + <| sprintf "RAM received address with wrong width: expected %d but got %A" mem.AddressWidth address +#endif + let dataIn = insOld 1 +#if ASSERTS + assertThat (dataIn.Width = mem.WordWidth) + <| sprintf "RAM received data-in with wrong width: expected %d but got %A" mem.WordWidth dataIn +#endif + let write = extractBit (insOld 2) + // If write flag is on, write the memory content. + let mem = + match write with + | 0u -> + // Read memory address and return memory unchanged. + mem + | 1u -> + // Update memory and return old content. + // NB - this was previously new content - but that is inconsistent and less useful. + writeMemory mem address dataIn + | _ -> failwithf $"simulation error: invalid 1 bit write value {write}" + putState (RamState mem) + else + // here we do the async read using current step address and state + // note that state will have been written for this step previously by clocked invocation of this component + let mem = + getRamStateMemory (numStep+1) simStep comp.State memory + + let address = ins 0 + let data = readMemory mem address + //printfn $"reading {data} from addr={address} with state = {RamState mem}" + put0 data + + + diff --git a/src/Renderer/Simulator/FastRun.fs b/src/Renderer/Simulator/FastRun.fs new file mode 100644 index 0000000..40f2236 --- /dev/null +++ b/src/Renderer/Simulator/FastRun.fs @@ -0,0 +1,491 @@ +module FastRun +open CommonTypes +open TimeHelpers +open SimulatorTypes +open SynchronousUtils +open NumberHelpers +open FastCreate +open FastReduce + + + +//-------------------------------------------------------------------------------------------------------// +//-----------Functions to Determine Component Reduction Order, and to Run the Fast Simulation------------// +//-------------------------------------------------------------------------------------------------------// + + +//--------------------------Determine Correct omponent Reduction Order-----------------------------------// + + +/// Invalid data is used as default to determine which inputs have been given data when ordering components +let private isValidData (fd: FastData) = fd <> emptyFastData + +/// True if the component is combinational +let inline isComb (comp: FastComponent) = + match comp.FType with + | Input _ when comp.AccessPath = [] -> false + | AsyncRAM1 _ -> true + | ct when couldBeSynchronousComponent ct -> false + | _ -> true + +/// True if all conditions are fulfiled for the component to be in the next batch to be reduced. +/// Used when ordering components. +let inline canBeReduced (fs: FastSimulation) (step: int) (fc: FastComponent) = + fc.NumMissingInputValues = 0 + && not fc.Touched + && fc.Active + && isComb fc + + +/// print function for debugging +let printComp (fs:FastSimulation) (step: int) (fc: FastComponent) = + let attr = + [ if isComb fc then "Co" else " " + if fc.Touched then "T" else "U" + if fc.Active then "Act" else "Inact" + " " + (fc.InputLinks + |> Array.map (fun (arr: StepArray) -> arr.Step.Length > 0 && isValidData arr.Step[step]) + |> Array.map + (function + | true -> "*" + | false -> "X") + |> String.concat "") ] + |> String.concat "" + + let ins = ( + fc.InputDrivers + |> Array.map ( Option.map (fun (fid,_) -> + let fc = fs.FComps[fid] + fc.FullName, fc.ShortId))) + + + sprintf "%25s %s %15s %A %A" fc.ShortId fc.FullName attr (canBeReduced fs step fc) ins + +/// print function for debugging +let private printComps (step: int) (fs: FastSimulation) = + + fs.FComps + |> mapValues + |> Array.map (fun fComp -> printComp fs step fComp) + |> String.concat "\n" + |> printfn "COMPONENTS\n----------------\n%s\n---------------" + + + + +/// Create arrays of components in corrected format for efficient reduction +/// Combinational components are ordered: clokced, constant, global input components are +/// separated. +let private orderCombinationalComponents (numSteps: int) (fs: FastSimulation) : FastSimulation = + let startTime = getTimeMs() + let mutable readyToReduce: FastComponent list = [] + let mutable orderedComps : FastComponent list = fs.FConstantComps |> Array.toList + + + let propagateEval (fc:FastComponent) = + fc.DrivenComponents + |> List.iter (fun fc' -> + fc'.NumMissingInputValues <- fc'.NumMissingInputValues - 1 + if canBeReduced fs 0 fc' then + readyToReduce <- fc' :: readyToReduce) + + let init fc = + fastReduce 0 0 false fc + fc.Touched <- true + propagateEval fc + + let initInput (fc: FastComponent) = + //printfn "Init input..." + fc.InputLinks[0].Step + |> Array.iteri + (fun i _ -> fc.InputLinks[0].Step[i] <- (convertIntToFastData (Option.defaultValue 1 fc.OutputWidth[0]) 0u)) + //printfn "Initialised input: %A" fc.InputLinks + fastReduce fs.MaxArraySize 0 false fc + fc.Touched <- true + propagateEval fc + + let initClockedOuts (fc: FastComponent) = + fc.Outputs + |> Array.iteri + (fun i vec -> + if not (isHybridComponent fc.FType) then + fc.Touched <- true + propagateEval fc + + match fc.FType, fc.OutputWidth[i] with + | RAM1 mem, Some w | AsyncRAM1 mem, Some w -> + match fc.State with + | Some arr -> arr.Step[0] <- RamState mem + | _ -> failwithf "Component %s does not have correct state vector" fc.FullName + + let initD = + match Map.tryFind 0L mem.Data with + | Some n -> convertInt64ToFastData w n + | _ -> convertIntToFastData w 0u + // change simulation semantics to output 0 in cycle 0 + vec.Step[0] <- convertIntToFastData w 0u + | RAM1 _, _ | AsyncRAM1 _, _-> + failwithf "What? Bad initial values for RAM %s output %d state <%A>" fc.FullName i fc.FType + | _, Some w -> vec.Step[0] <- convertIntToFastData w 0u + | _ -> failwithf "What? Can't find width for %s output %d" fc.FullName i) + /// print function for debugging + let pp (fL: FastComponent array) = + Array.map (fun fc -> sprintf "%A (%A)" fc.FullName fc.FType) fL + |> String.concat "," + //printComps 0 fs + //printfn "Ordering %d clocked outputs: " fs.FClockedComps.Length + fs.FClockedComps |> Array.iter initClockedOuts + //printfn "Ordering %d constants" fs.FConstantComps.Length + fs.FConstantComps |> Array.iter init + //printfn "Ordering %d global inputs" fs.FGlobalInputComps.Length + fs.FGlobalInputComps |> Array.iter initInput + //printfn "Loop init done" + printfn + "%d constant, %d input, %d clocked, %d ready to reduce from %d" + fs.FConstantComps.Length + fs.FGlobalInputComps.Length + fs.FClockedComps.Length + readyToReduce.Length + fs.FComps.Count + + while readyToReduce.Length <> 0 do + //printf "Adding %d combinational components %A" nextBatch.Length (pp nextBatch) + let readyL = readyToReduce + readyToReduce <- [] + readyL + |> List.iter (fun fc -> + fastReduce fs.MaxArraySize 0 false fc // this is always a combinational reduction + orderedComps <- fc :: orderedComps + fc.Touched <- true + propagateEval fc) + + let orderedSet = + orderedComps + |> List.toArray + |> Array.map (fun co -> co.fId) + |> Set + + + instrumentTime "orderCombinationalComponents" startTime + + { fs with + FOrderedComps = orderedComps |> Array.ofList |> Array.rev } + +/// Check all the active FastComponents to ensure everything is valid +/// Use data from initialisation to write any not-yet-written component output widths +let checkAndValidate (fs:FastSimulation) = + let start = getTimeMs() + let activeComps = + fs.FComps + |> mapValues + |> Array.filter (fun fc -> fc.Active) + let inSimulationComps = + [| + Array.filter (fun fc -> not (isHybridComponent fc.FType)) fs.FClockedComps + fs.FGlobalInputComps + fs.FOrderedComps + |] |> Array.concat + if (activeComps.Length <> inSimulationComps.Length) then + printf "Validation problem: %d active components, %d components in simulation" + activeComps.Length + inSimulationComps.Length + inSimulationComps + |> Array.iter (fun fc -> printfn "Simulation: %s\n" (printComp fs 0 fc)) + fs.FComps + |> Map.iter (fun fid fc -> printfn "FComps: %s\n" (printComp fs 0 fc)) + let possibleCycleComps = + Set (List.ofArray activeComps |> List.map (fun fc -> fc.SimComponent.Id)) - + Set (List.ofArray inSimulationComps |> List.map (fun fc -> fc.SimComponent.Id)) + |> Set.toList + Error { + Msg = sprintf $"Issie has discovered an asynchronous cyclic path in your circuit - probably through asynchronous RAM address and dout ports. This is not allowed.\ + This cycle detection is not precise, the components in red comprise this cycle and all components driven only from it" + InDependency = None + ComponentsAffected = possibleCycleComps + ConnectionsAffected = [] + } + + // check and add (if necessary) output widths + else + activeComps + |> Array.iter ( fun fc -> + fc.OutputWidth + |> Array.iteri ( fun i opn -> + let data = fc.Outputs[i].Step[0] + match data.Width, fc.OutputWidth[i] with + | n, Some m when n <> m -> + failwithf "Inconsistent simulation data %A data found on signal output width %d from %s:%d" data m fc.FullName i + | 0, _ -> + failwithf "Unexpected output data %A found on initialised component %s:%d" data fc.FullName i + | n, None -> + fc.OutputWidth[i] <- Some n + | _ -> () // Ok in this case + )) + instrumentTime "checkAndValidate" start + Ok fs + +let createFastArrays fs gather = + let getArrayOf pred fComps = + fComps + |> Map.filter (fun cid comp -> pred comp) + |> Map.toArray + |> Array.map snd + + { fs with + FGlobalInputComps = + fs.FComps + |> getArrayOf (fun fc -> isInput fc.FType && fc.AccessPath = []) + FConstantComps = + fs.FComps + |> getArrayOf + (fun fc -> + match fc.FType with + | Constant1 _ -> true + | _ -> false) + FClockedComps = + fs.FComps + |> getArrayOf (fun fc -> couldBeSynchronousComponent fc.FType) + FOrderedComps = Array.empty + FSComps = gather.AllComps + G = gather } + + +/// Create a fast simulation data structure, with all necessary arrays, and components +/// ordered for evaluation. +/// This function also creates the reducer functions for each component +/// similar to the reducer builder in Builder, but with inputs and outputs using the FastSimulation +/// mutable arrays +let buildFastSimulation (numberOfSteps: int) (graph: SimulationGraph) : Result = + let gather = gatherSimulation graph + let fs = + createInitFastCompPhase numberOfSteps gather (emptyFastSimulation ()) + |> linkFastComponents gather + gather + |> createFastArrays fs + |> orderCombinationalComponents numberOfSteps + |> checkAndValidate + + +//---------------------------------------------------------------------------------------------------// +//--------------------------------Code To Run The Simulation & Extract Results-----------------------// +//---------------------------------------------------------------------------------------------------// + + +/// sets up default no-change input values for the next step +let private propagateInputsFromLastStep (step: int) (fastSim: FastSimulation) = + if step > 0 then + fastSim.FGlobalInputComps + |> Array.iter + (fun fc -> + let vec = fc.Outputs[0] + vec.Step[step] <- vec.Step[step - 1]) + +/// advance the simulation one step +let private stepSimulation (fs: FastSimulation) = + let index = (fs.ClockTick + 1) % fs.MaxArraySize + propagateInputsFromLastStep index fs + Array.iter (fastReduce fs.MaxArraySize index true) fs.FClockedComps + Array.iter (fastReduce fs.MaxArraySize index false) fs.FOrderedComps + + fs.ClockTick <- fs.ClockTick + 1 + +/// sets the mutable simulation data for a given input at a given time step +let private setSimulationInput (cid: ComponentId) (fd: FData) (step: int) (fs: FastSimulation) = + match Map.tryFind (cid, []) fs.FComps with + | Some fc -> fc.Outputs[0].Step[step % fs.MaxArraySize] <- fd + | None -> failwithf "Can't find %A in FastSim" cid + +/// Re-evaluates the combinational logic for the given timestep - used if a combinational +/// input has changed +let private runCombinationalLogic (step: int) (fastSim: FastSimulation) = + fastSim.FOrderedComps + |> Array.iter (fastReduce fastSim.MaxArraySize (step % fastSim.MaxArraySize) false) + +/// Change an input and make simulation correct. N.B. step must be the latest +/// time-step since future steps are not rerun (TODO: perhaps they should be!) +let changeInput (cid: ComponentId) (wd: WireData) (step: int) (fastSim: FastSimulation) = + //printfn "wd=%A" wd + let fd = (wd |> wireToFast) + setSimulationInput cid fd step fastSim + //printfn $"Changing {fastSim.FComps[cid,[]].FullName} to {fd}" + runCombinationalLogic step fastSim + +let extractStatefulComponents (step: int) (fastSim: FastSimulation) = + fastSim.FClockedComps + |> Array.collect + (fun fc -> + match fc.AccessPath with + | [] -> + match fc.FType with + | DFF _ + | DFFE _ + | Register _ + | RegisterE _ -> [| fc, RegisterState fc.Outputs[0].Step[step % fastSim.MaxArraySize] |] + | ROM1 state -> [| fc, RamState state |] + | RAM1 _ | AsyncRAM1 _ -> + match fc.State + |> Option.map (fun state -> state.Step[step % fastSim.MaxArraySize]) with + | None -> failwithf "Missing RAM state for step %d of %s" step fc.FullName + | Some memState -> [| fc, memState |] + | _ -> failwithf "Unsupported state extraction from clocked component type %s %A" fc.FullName fc.FType + | _ -> [||]) + + +/// Run an existing fast simulation up to the given number of steps. This function will mutate the write-once data arrays +/// of simulation data and only simulate the new steps needed, so it may return immediately doing no work. +/// If the simulation data arrays are not large enough they are extended up to a limit. After that, they act as a circular buffer. +let runFastSimulation (numberOfSteps: int) (fs: FastSimulation) : Unit = + + let simStartTime = getTimeMs() + let stepsToDo = float (numberOfSteps - fs.ClockTick) + let numComponents = float fs.FComps.Count + + if numberOfSteps > fs.MaxStepNum then + if fs.MaxStepNum < fs.MaxArraySize then + let newMaxNum = + min + fs.MaxArraySize + (numberOfSteps + max 50 (int (float numberOfSteps * 1.5))) + + //printfn $"In Tick {fs.ClockTick} Creating simulation array length of {newMaxNum} steps" + extendFastSimulation newMaxNum fs + + let start = fs.ClockTick + 1 + + [ start .. numberOfSteps ] + |> List.iter + (fun n -> + //if n % (100 * (int (1. + 3000. / numComponents))) = 0 then printfn "Step %d" n + stepSimulation fs) + let sTime = getTimeMs() - simStartTime + if sTime > 50. then + printfn $"Simulation speed: {numComponents*stepsToDo/sTime} Component-Steps/ms ({int stepsToDo} steps, {int numComponents} components)" + +/// Run a fast simulation for a given number of steps building it from the graph +let runSimulationZeroInputs (steps: int) (graph: SimulationGraph) : Result = + let fsResult = buildFastSimulation steps graph + fsResult + |> Result.map (runFastSimulation steps) + |> ignore + fsResult + +/// Look up a simulation (not a FastSimulation) component or return None. +let rec findSimulationComponentOpt ((cid, ap): ComponentId * ComponentId list) (graph: SimulationGraph) = + match ap with + | [] -> Map.tryFind cid graph + | customCompId :: ap' -> + Map.tryFind customCompId graph + |> Option.bind + (fun graph -> + graph.CustomSimulationGraph + |> Option.bind (fun graph -> findSimulationComponentOpt (cid, ap') graph)) + +/// Look up a simulation component (not a FastComponent) +let findSimulationComponent ((cid, ap): ComponentId * ComponentId list) (sd: SimulationData) = + let fs = sd.FastSim + let graph = sd.Graph + + match findSimulationComponentOpt (cid, ap) graph with + | None -> failwithf "What? Can't find component %A in SimulationData" fs.FComps[cid, ap].FullName + | Some sComp -> sComp + + + +/// return output port data from simulation +let rec extractFastSimulationOutput + (fs: FastSimulation) + (step: int) + ((cid, ap): ComponentId * ComponentId list) + (opn: OutputPortNumber) : WireData = + + let (OutputPortNumber n) = opn + match Map.tryFind (cid, ap) fs.FComps with + | Some fc -> + //printfn $"Extracting port {opn} from {fc.FullName} in step {step}" + match Array.tryItem (step % fs.MaxArraySize) fc.Outputs[n].Step with + | None -> failwithf $"What? extracting output {n} in step {step} from {fc.FullName} failed with clockTick={fs.ClockTick}" + | Some fd -> fd + |> (fun fd -> + if fd.Width=0 then failwithf $"Can't find valid data in step {step}:index{step % fs.MaxArraySize} from {fc.FullName} with clockTick={fs.ClockTick}" + fd |> fastToWire) + | None -> + // if it is a custom component output extract from the corresponding Output FastComponent + match Map.tryFind ((cid, ap), opn) fs.G.CustomOutputLookup with + | Some (cid, ap) -> extractFastSimulationOutput fs step (cid, ap) (OutputPortNumber 0) + | None -> failwithf "What? extracting component data failed - can't find component from id" + +/// return state data from simulation +let rec extractFastSimulationState + (fs: FastSimulation) + (step: int) + ((cid, ap): ComponentId * ComponentId list) = + + match Map.tryFind (cid, ap) fs.FComps with + | Some fc -> + match fc.State with + | None -> + match fc.SimComponent.Type with + // asynch ROMs have no state: value is always the same + | AsyncROM1 romContents -> + RamState romContents + | _ -> + failwithf "What? extracting State in step %d from %s failed" step fc.FullName + | Some stepArr -> + match Array.tryItem (step% fs.MaxArraySize) stepArr.Step with + | Some state -> state + | None -> + failwithf $"What? Can't extract state in step {step} from {fc.FullName}" + | None -> + failwithf $"What? Can't find fast component {(cid,ap)}" + + + +/// Extract top-level inputs or outputs with names and wire widths. Used by legacy code. +let extractFastSimulationIOs + (simIOs: SimulationIO list) + (simulationData: SimulationData) + : (SimulationIO * WireData) list = + let fs = simulationData.FastSim + let inputs = simulationData.Inputs + + simIOs + |> List.map + (fun ((cid, label, width) as io) -> + let wd = extractFastSimulationOutput fs simulationData.ClockTickNumber (cid, []) (OutputPortNumber 0) + //printfn $"Extrcating: {io} --- {wd}" + io, wd) + +let getFLabel (fs:FastSimulation) (fId:FComponentId) = + let fc = fs.FComps[fId] + let (ComponentLabel name) = fc.SimComponent.Label + name, fc.FullName + +let extractFastSimulationWidth (fs:FastSimulation) (fid: FComponentId) (opn: OutputPortNumber) = + let (OutputPortNumber n) = opn + fs.FComps[fid].OutputWidth[n] + + + + + +/// Extract all Viewer components with names and wire widths. Used by legacy code. +let extractViewers + (simulationData: SimulationData) + : ((string*string) * int * WireData) list = + let fs = simulationData.FastSim + + let comps = + simulationData.FastSim.FComps + |> Map.map (fun fid fc -> fc.FType) + |> mapValues + + let viewers = + simulationData.FastSim.FComps + |> Map.filter (fun fid fc -> match fc.FType with |Viewer _ -> true | _ -> false) + viewers + |> Map.toList + |> List.map + (fun (fid,fc) -> + let width = Option.get fc.OutputWidth[0] + getFLabel fs fid, width, extractFastSimulationOutput fs simulationData.ClockTickNumber fid (OutputPortNumber 0)) diff --git a/src/Renderer/Simulator/NumberHelpers.fs b/src/Renderer/Simulator/NumberHelpers.fs new file mode 100644 index 0000000..3cad845 --- /dev/null +++ b/src/Renderer/Simulator/NumberHelpers.fs @@ -0,0 +1,216 @@ +(* + NumberHelpers.fs + + A collection of functions that allow to covert numbers into various + representations. +*) + +module NumberHelpers +open Helpers +open SimulatorTypes + +/// Convert an hex string into a binary string. +let private hexToBin (hStr : string) : string = + let rec convert h = + match h with + | [] -> "" + | c :: h' -> + let digit = + match c with + | '0' -> "0000" | '1' -> "0001" | '2' -> "0010" | '3' -> "0011" + | '4' -> "0100" | '5' -> "0101" | '6' -> "0110" | '7' -> "0111" + | '8' -> "1000" | '9' -> "1001" | 'a' -> "1010" | 'b' -> "1011" + | 'c' -> "1100" | 'd' -> "1101" | 'e' -> "1110" | 'f' -> "1111" + | c -> failwithf "Invalid char %c while converting hex %s to binary" c hStr + digit + (convert h') + let chars = hStr.ToLower() |> Seq.toList + match chars with + | [] -> "" + | c :: chars' -> + let firstDigit = // Avoid leading zeros. + match c with + | '0' -> "0" | '1' -> "1" | '2' -> "10" | '3' -> "11" + | '4' -> "100" | '5' -> "101" | '6' -> "110" | '7' -> "111" + | '8' -> "1000" | '9' -> "1001" | 'a' -> "1010" | 'b' -> "1011" + | 'c' -> "1100" | 'd' -> "1101" | 'e' -> "1110" | 'f' -> "1111" + | c -> failwithf "Invalid char %c while converting hex %s to binary" c hStr + firstDigit + (convert chars') + +let addZeros64 (width:int) (pFun:int64 -> string) (n: int64) = + let s = pFun n + let bits = + match s[1] with + | 'x' -> 4 + | 'b' -> 1 + | _ -> failwithf "Wrong use of addZeros64: s = %s" s + let extra = (width - (s.Length - 2)*bits) / bits + s[0..1] + String.replicate extra "0" + s[2..] + +let addZeros (width:int) (pFun:int -> string) (n: int) = + let s = pFun n + let bits = + match s[1] with + | 'x' -> 4 + | 'b' -> 1 + | _ -> failwithf "Wrong use of addZeros: s = %s" s + let extra = ((width - (s.Length - 2))*bits + (2<< "0" | One -> "1" + +/// Pad wireData with Zeros as the Most Significant Bits (e.g. at position N). +let private padToWidth width (bits : WireData) : WireData = + if bits.Length > width then List.truncate width bits + else bits @ List.replicate (width - bits.Length) Zero + +/// Convert an int into a Bit list with the provided width. The Least +/// Significant Bits are the one with low index (e.g. LSB is at position 0, MSB +/// is at position N). Little Endian. +/// If the number has more bits than width, then more bits will be returned. +let convertIntToWireData (width : int) (num : int64) : WireData = + let toBit = function | 0 -> Zero | 1 -> One | _ -> failwith "toBit only accepts 0 or 1" + let rec intToBinary (i : int64) = + match int i with + | 0 | 1 -> [toBit <| int i] + | _ -> let bit = toBit <| int (i % (int64 2)) + bit :: (intToBinary (i / (int64 2))) + if num >= 0L then + padToWidth width (intToBinary num) + else + padToWidth width (intToBinary (num &&& (1L <<< width) - 1L)) + +/// Convert a list of Bits into an int. The Least Significant Bits are the one +/// with low index (e.g. LSB is at position 0, MSB is at position N). +/// Little Endian. +let convertWireDataToInt (bits : WireData) : int64 = + let rec convert bits idx = + match bits with + | [] -> int64 0 + | Zero :: bits' -> convert bits' (idx + 1) + | One :: bits' -> pow2int64(idx) + convert bits' (idx + 1) + convert bits 0 + + +let convertInt64ToFastData (width:int) (n:int64) = + let n' = uint64 n + let dat = + if width > 32 then + let mask = bigIntMask width + BigWord (bigint n' &&& mask) + else + let mask = (1u <<< width) - 1u + Word (uint32 n' &&& mask) + {Dat=dat; Width = width} + +let convertIntToFastData (width:int) (n:uint32) = + if width <= 32 then + {Dat = Word n; Width = width} + else + {Dat = BigWord (bigint n); Width = width} + +let convertBigintToFastData (width:int) (b:bigint) = + {Dat = BigWord b; Width = width} + +let convertFastDataToInt64 (d:FastData) = + match d.Dat with + | Word n -> uint64 n + | BigWord n -> + if d.Width > 64 then + failwithf $"Can't convert a {d.Width} width bigint to int64" + uint64 n + +let convertFastDataToBigint (d:FastData) = + match d.Dat with + | Word n -> bigint n + | BigWord n -> n + +let convertFastDataToInt (d:FastData) = + match d.Dat with + | Word n -> n + | BigWord _ -> failwithf $"Can't convert {d.Dat} to integer" + +let convertFastDataToWireData bits = + bits |> convertFastDataToInt64 |> int64 |> convertIntToWireData bits.Width + +let emptyFastData = {Width=0; Dat=Word 0u} + + + + +/// Try to convert a string to an int, or return an error message if that was +/// not possible. +let strToInt (str : string) : Result = + try + Ok <| int64 str + with + | _ -> Error <| "Invalid number." + + (* + +let toInt = EEExtensions.Char.toInt + +/// convert a digit character: binary, decimal, or hexadecimal, to its numeric value +let cDigitInt (ch:char) = + match toInt ch with + | d when d >= int32 '0' && d <= int32 '9' -> Some(d - int32 '0') + | d when d >= toInt 'A' && d <= toInt 'Z' -> Some(d - toInt 'A' + 10) + | _ -> None + +let convertUInt64 (stringToConvert: string) = + let rec pow64 n = + let getRadixNum (radix:int) (ns: int option list) = + if Seq.forall (function | Some n -> n < radix && n >= 0 | None -> false) ns + then Some (List.sumBy (fun n -> uint64 n + )) + + let aInt = toInt 'A' + let s = EEExtensions.String.trim (EEExtensions.String.toUpper stringToConvert) + if EEExtensions.String.startsWith "0X" s then + let hexDigits = s[2..s.Length-1] + let convDigits = hexDigits |> List.map cDigitInt + if checkRadix 16 + +*) + +let private countBits (num : int64) : int = + (String.length <| bin64 num) - 2 + +/// Check a number is formed by at most bits. +let rec private checkWidth (width : int) (num : int64) : string option = + if num < 0L then + checkWidth width <| (-num) - 1L + else + let bitsCount = countBits num + match bitsCount <= width with + | true -> None + | false -> Some <| sprintf "Expected %d or less bits." width + +/// Convert a string to a number making sure that it has no more bits than +/// specified in width. +let strToIntCheckWidth (width : int) (str : string) : Result = + match str.Trim() with + | "" -> Ok 0L // special case + | str -> + strToInt str + |> Result.bind (fun num -> + match checkWidth width num with + | None -> Ok num + | Some err -> Error err + ) diff --git a/src/Renderer/Simulator/Runner.fs b/src/Renderer/Simulator/Runner.fs new file mode 100644 index 0000000..9f52b55 --- /dev/null +++ b/src/Renderer/Simulator/Runner.fs @@ -0,0 +1,384 @@ +(* + Runner.fs + + This module collects functions that allow to feed input into the simulation, + effectively allowing to run it. +*) + +module SimulationRunner + +open CommonTypes +open Helpers +open SimulatorTypes +open SynchronousUtils + +let mutable simTrace = None //Some ["adder40";"4bitbusmux20";"dff430"] + + + +// During simulation, a Component Reducer function will produce the output only +// when all of the expected inputs have a value. Once this happens, it will +// calculate its outputs and set them in the next simulationComponent(s). + +/// Function to determine what reducer inputs or outputs have changed. +let diffReducerInputsOrOutputs + (newIO : Map<'a, WireData>) + (oldIO : Map<'a, WireData>) + : Map<'a, WireData> = + // 'a type is either InputPortNumber or OutputPortNumber. + // New inputs/outputs either: + // - have more keys than old ones, + // - have the same keys as old ones, but their values have changed. +#if ASSERTS + assertThat (oldIO.Count <= newIO.Count) (sprintf "diffReducerInputsOrOutputs: (%A:%A)" oldIO newIO) +#endif + (Map.empty, newIO) + ||> Map.fold (fun diff portNumber wireData -> + match oldIO.TryFind portNumber with + | None -> diff.Add(portNumber, wireData) + | Some oldData when oldData <> wireData -> diff.Add(portNumber, wireData) + | Some oldData when oldData = wireData -> diff + | _ -> failwith "what? Impossible case in diffReducerInputsOrOutputs" + ) + +let traceReduction action (comp:SimulationComponent) (reducerInput:ReducerInput) (reducerOutput:ReducerOutput) = + match simTrace, comp with + | None,_ -> () + | Some traceLabs, {Label=ComponentLabel lab} when List.contains lab traceLabs -> + printfn "\n%s>>>>> %A \n\toutputs: %A \n\tinputs=%A \n\tnewState=%A" + action (shortPSComp comp) reducerOutput.Outputs reducerInput.Inputs reducerOutput.NewState + | _ -> () + + + + +/// Take the Input, and feed it to the Component with the specified Id. +/// This function should be used to feed combinational logic inputs, not to +/// trigger a clock tick. +/// If the Component is then ready to produce an output, propagate this output +/// by recursively feeding it as an input to the connected Components. +let rec private feedInput + (graph : SimulationGraph) + (compId : ComponentId) + (input : InputPortNumber * WireData) + : SimulationGraph = + // Extract component. + let comp = match graph.TryFind compId with + | None -> failwithf "what? Could not find component %A in simulationStep" compId + | Some c -> c + // Performance optimization: feed the reducer with the old inputs, to figure + // out what the old ouputs were. Use these old outputs to determine what + // outputs have changed by the new input, and only propagate those changes. + // An extra call to the reducer should be quite cheap compared to many saved + // recursions of the feedInput function. + let oldReducerInput = { + Inputs = comp.Inputs + CustomSimulationGraph = comp.CustomSimulationGraph + IsClockTick = No + } + let oldReducerOutput = comp.Reducer oldReducerInput + + // Add input to the simulation component. + let comp = { comp with Inputs = comp.Inputs.Add input } + let graph = graph.Add (comp.Id, comp) + // Prepare reducer Input. + let reducerInput = { + Inputs = comp.Inputs + CustomSimulationGraph = comp.CustomSimulationGraph + IsClockTick = No + } + // Try to reduce the component. + let reducerOutput = comp.Reducer reducerInput + // Check wether the reducer produced any outputs. + + traceReduction "comb-feedin" comp reducerInput reducerOutput + + match reducerOutput.Outputs with + | None -> graph // Keep on waiting for more inputs. + | Some outputMap -> + // Received enough inputs and produced an output. + + // Performance optimization, only propagate the outputs that changed. + let oldOutputMap = Option.defaultValue Map.empty oldReducerOutput.Outputs + let diffedOutputMap = diffReducerInputsOrOutputs outputMap oldOutputMap + + // Propagate each output produced. + let graph = feedReducerOutput comp graph diffedOutputMap + // Update the CustomSimulationGraph and return the new simulation graph. + let comp = { comp with CustomSimulationGraph = reducerOutput.NewCustomSimulationGraph } + graph.Add (comp.Id, comp) + +/// Propagate each output produced by a simulation component to all the +/// components connected to its output ports. +/// Return the updated simulationGraph. +and private feedReducerOutput + (comp : SimulationComponent) + (graph : SimulationGraph) + (outputMap : Map) + : SimulationGraph = + (graph, outputMap) ||> Map.fold (fun graph ((OutputPortNumber opNum) as outPortNumber) wireData -> + match Map.tryFind (OutputPortNumber opNum) comp.Outputs with + | None when comp.Type = IOLabel -> graph // special case, these components can generate output that is connected to nothing! + | None -> failwithf "what? Reducer produced inexistent output portNumber %A in component %A" outPortNumber comp + | Some targets -> + comp.OutputsPropagated[opNum] <- true // disable further propagation if clocked. + // Trigger simulation step with the newly produced input in + // every target. + (graph, targets) ||> List.fold (fun graph (nextCompId, nextPortNumber) -> + let graph = feedInput graph nextCompId (nextPortNumber, wireData) + graph + ) + ) + + +let clockedComps (graph:SimulationGraph) = + graph + |> Map.toArray + |> Array.filter (fun (_,comp) -> couldBeSynchronousComponent comp.Type) + |> Array.sortBy (fun (cid,comp) -> match comp.Type with Custom _ -> 0 | _ -> 1) + +let calculateStateChanges (graph : SimulationGraph) : SimulationGraph * OutputChange list = + let clockedCompsBeforeTick = clockedComps graph + // For each clocked component, feed the clock tick together with the inputs + // snapshotted just before the clock tick. + ((graph,[]), clockedCompsBeforeTick) ||> Array.fold (fun (graph,changes) (compId,comp) -> + let reducerInput = { + Inputs = comp.Inputs + CustomSimulationGraph = comp.CustomSimulationGraph + IsClockTick = Yes comp.State + } + // comp>Reducer recursively calls feedClockTick (and hence calculateStateChanges) if comp is a custom component + // in that case the recursive call does all the result of internal state change + // subgraph update for the Tick - propagateStateChanges will not do that + // The change in the subgraph is Ok here because it does not affect the evaluation of any other components at this + // level until the output changes are propagated. + // Note that the subgraphs may still need later changes as a result of the delayed processing of higher-level + // output changes. This change propagation must go through the whole design including subsheets again! + let reducerTickOutput = comp.Reducer reducerInput + traceReduction (sprintf "clockTick %A" reducerInput.IsClockTick) comp reducerInput reducerTickOutput + + match reducerTickOutput.Outputs with + | None -> failwithf "what? A clocked component should ALWAYS produce outputs after a clock tick: %A" comp + | Some outputMap -> + // Note that updating the CustomSimulationGraph is necessary since + // we may be dealing with custom clocked components, which means + // the feedClockTick operaion changes the graph of that custom + // component. + let comp = + { comp with + CustomSimulationGraph = reducerTickOutput.NewCustomSimulationGraph + OutputsPropagated = Array.replicate comp.Outputs.Count false + State = reducerTickOutput.NewState + } + let change = {CComp = comp; COutputs = outputMap} + Map.add comp.Id comp graph, (change :: changes) + // Feed the newly produced outputs into the combinational logic. + ) + +let propagateStateChanges (graph : SimulationGraph) (changes: OutputChange list) : SimulationGraph = + // For each output change recorded in changes, update graph as follows + // Update the inputs driven by the changed wires + // Recursively propagate changes through graph + // record outputs changed and do not propagate chnages that have already touched as result of propagation + (graph, changes) ||> List.fold (fun graph change -> + let comp = change.CComp + let outputMap = + change.COutputs // if output has already been propagated don't propagate it here + |> Map.filter (fun (OutputPortNumber n) wData -> + not <| comp.OutputsPropagated[n]) + if simTrace <> None then + printfn "|prop|----> %A (%A)" comp.Label outputMap + // Note that here we update component inputs in the graph as we propagate changes. + // component inputs in comp are not uptodate, but this does not matter, they are not used + let graph = feedReducerOutput comp graph outputMap + graph + ) + +let checkPropagation (graph : SimulationGraph) : SimulationGraph = + let ll (ComponentLabel s) = s + let customComps = + graph + |> Map.toList + |> List.collect (fun (cid,sc) -> + match sc.Type, sc.CustomSimulationGraph with + | Custom c, Some cGraph -> [{|Comp=sc;Type=c;Graph=cGraph|}] + |_ -> []) + + let findOutputComp label (cGraph: SimulationGraph) = + cGraph + |> Map.filter (fun cid comp -> (match comp.Type with Output _ -> true | _ -> false) && comp.Label=label) + |> Map.toList + |> (function | [comp] -> snd comp + | x -> failwithf "can't find output '%s' in graph: %d candidates: %A." (ll label) x.Length x) + let propagateCombinationalComponents graph = + (graph,graph) + ||> Map.fold (fun graph cid comp -> + let comp = graph[cid] + match comp.Type, couldBeSynchronousComponent comp.Type with + | _,true -> graph + | Input _,_ | Constant1 _, _-> graph + | _,false -> + let reducerInput = { + Inputs = comp.Inputs + CustomSimulationGraph = comp.CustomSimulationGraph + IsClockTick = No + } + // Try to reduce the component. + let reducerOutput = comp.Reducer reducerInput + // Check wether the reducer produced any outputs. + + traceReduction "final-feedin" comp reducerInput reducerOutput + + match reducerOutput.Outputs with + | None -> graph // Keep on waiting for more inputs. + | Some outputMap -> + //printfn "%s -> %A" (ll comp.Label) outputMap + // Received enough inputs and produced an output. + feedReducerOutput comp graph outputMap + ) + let checkCustomOutputs() = + customComps + |> List.map (fun cc -> + let outLabs = cc.Type.OutputLabels + outLabs + |> List.mapi (fun i (label,width) -> + let comp = findOutputComp (ComponentLabel label) cc.Graph + let propVal = comp.Inputs[InputPortNumber 0] + let propToList = cc.Comp.Outputs[OutputPortNumber i] + propToList + |> List.map (fun (cid, inPort) -> + let receiver = graph[cid] + let recVal = receiver.Inputs[inPort] + if propVal <> recVal then + printfn "***CustomOutput: %s on %s fails to propagate to %s\n \ + output=%A\n propagated input=%A" label (ll cc.Comp.Label) (ll receiver.Label) propVal recVal + 1 + else + //printfn "%s.%s -> %A" (ll cc.Comp.Label) label propVal + 0 + ) + ) + ) + checkCustomOutputs() + |> List.sumBy (List.sumBy List.sum) + |> (fun n -> + if n > 0 + then failwithf "*****Failing with %d Propagation errors*****" n + else + // printfn "Propagation checks OK for %d components and %d customs!" graph.Count customComps.Length) + ()) + propagateCombinationalComponents graph + +let feedClockTick (graph : SimulationGraph) : SimulationGraph = + calculateStateChanges graph + ||> propagateStateChanges + |> checkPropagation + +/// Feed zero to a simulation input. +/// This function is supposed to be used with Components of type Input. +let feedSimulationInput graph inputId wireData = + failwithf "this function should never be called" + +/// Feed in constant outputs so that they propagated to things connected to them +/// This function is supposed to be used with Components of type Constant +let rec feedSimulationConstants (graph:SimulationGraph) = + let comps = + graph + |> Map.toList + |> List.map snd + let getWireData (comp:SimulationComponent) = + match comp.Type with + | Constant1 (w,c,_) -> NumberHelpers.convertIntToWireData w (int64 c) + | _ -> failwithf "What? Problem with non-constant component used in feedSimulationConstants" + comps + |> List.filter (fun c -> match c.Type with | Custom cComp -> true| Constant1 _ -> true | _ -> false) + |> (fun cL -> + let feedConstant (graph:SimulationGraph) (comp:SimulationComponent) = + // graph gets updates each iteration of fold, but cL (and hence comp) does not + // we need to extract the Id from comp and look up the fold updated version in graph + let comp = graph[comp.Id] // refresh to get latest version of comp as updated by fold + match comp.Type with + | Constant1 _ -> + feedReducerOutput comp graph (Map.ofList [OutputPortNumber 0, getWireData comp]) + | Custom cComp -> + + Option.map feedSimulationConstants comp.CustomSimulationGraph + |> (fun graphOpt -> {comp with CustomSimulationGraph = graphOpt}) + |> (fun comp' -> Map.add comp.Id comp' graph) + | _ -> failwithf "What? other components are filtered out" + (graph, cL) ||> List.fold feedConstant) + +/// Feed zeros to all simulation inputs, and feed a single clock tick. +/// This way all combinational logic has been touched once and had produced its +/// outputs. +let InitialiseGraphWithZeros + (inputIds : SimulationIO list) + (graph : SimulationGraph) + : SimulationGraph = + // Feed a clock tick to initialize all of the nets that are after clocked + // components, which cannot be initialised by just feeding the inputs. + (*let graph = feedClockTick graph + // Feed zero to all simulation inputs. + (graph, inputIds) ||> List.fold (fun graph (inputId, _, width) -> + let data = List.replicate width Zero + feedSimulationInput graph inputId data + ) + |> feedSimulationConstants *) + graph + + +/// Given a list of IO nodes (i.e. Inputs or outputs) extract their value. +/// If they dont all have a value, an error is thrown. +let extractSimulationIOs + (simulationIOs : SimulationIO list) + (graph : SimulationGraph) + : (SimulationIO * WireData) list = + let extractWireData (inputs : Map) : WireData = + match inputs.TryFind <| InputPortNumber 0 with + | None -> failwith "what? IO bit not set" + | Some bit -> bit + ([], simulationIOs) ||> List.fold (fun result (ioId, ioLabel, width) -> + match graph.TryFind ioId with + | None -> failwithf "what? Could not find io node: %A" (ioId, ioLabel) + | Some comp -> ((ioId, ioLabel, width), extractWireData comp.Inputs) :: result + ) + +/// Simlar to extractSimulationIOs, but do not fail if a bit is not set, just +/// ignore it. +let extractIncompleteSimulationIOs + (simulationIOs : SimulationIO list) + (graph : SimulationGraph) + : (SimulationIO * WireData) list = + let extractWireData (inputs : Map) : WireData option = + inputs.TryFind <| InputPortNumber 0 + ([], simulationIOs) ||> List.fold (fun result (ioId, ioLabel, width) -> + match graph.TryFind ioId with + | None -> failwithf "what? Could not find io node: %A" (ioId, ioLabel, width) + | Some comp -> match extractWireData comp.Inputs with + | None -> result + | Some wireData -> ((ioId, ioLabel, width), wireData) :: result + ) + +/// Get ComponentIds, ComponentLabels and wire widths of all input and output +/// nodes. +let getSimulationIOs + (components : Component list) + : SimulationIO list * SimulationIO list = + (([], []), components) ||> List.fold (fun (inputs, outputs) comp -> + match comp.Type with + | Input w -> ((ComponentId comp.Id, ComponentLabel comp.Label, w) :: inputs, outputs) + | Output w -> (inputs, (ComponentId comp.Id, ComponentLabel comp.Label, w) :: outputs) + | _ -> (inputs, outputs) + ) + +/// Get ComponentIds, ComponentLabels and wire widths of all input and output +/// nodes in a simulationGraph. +let getSimulationIOsFromGraph + (graph : SimulationGraph) + : SimulationIO list * SimulationIO list = + (([], []), graph) ||> Map.fold (fun (inputs, outputs) compId comp -> + match comp.Type with + | Input w -> ((comp.Id, comp.Label, w) :: inputs, outputs) + | Output w -> (inputs, (comp.Id, comp.Label, w) :: outputs) + | _ -> (inputs, outputs) + ) diff --git a/src/Renderer/Simulator/SimulationGraphAnalyser.fs b/src/Renderer/Simulator/SimulationGraphAnalyser.fs new file mode 100644 index 0000000..1629eb9 --- /dev/null +++ b/src/Renderer/Simulator/SimulationGraphAnalyser.fs @@ -0,0 +1,226 @@ +(* + SimulationGraphAnalyser.fs + + This module collects functions to analyse a fully merged simulation graph. + Analyses performed: + - Combinatorial logic can have no loops. +*) + +module SimulationGraphAnalyser + +open CommonTypes +open SimulatorTypes +open SynchronousUtils + +type private DfsType = + // No cycle detected in the subtree. Return the new visited set and keep + // on exploring. + | NoCycle of Set + // Found a cycle and bactracking to record all components that form the + // cycle. Stop recording when the componentId that closes the loop is + // reached. + | Backtracking of ComponentId list * ComponentId + // Done with backtracking. A cycle has been found and all the components + // that form the cycle have been recorded. + | Cycle of ComponentId list + +/// Dfs function that spots combinatorial cycles in a graph. +/// visited and currStack also keep track of the port being explored as it makes +/// a difference (only) in the custom components. +let rec private dfs + (currNodeId : ComponentId) + (inputPortNumber : InputPortNumber) + (graph : SimulationGraph) + (visited : Set) + (currStack : Set) + getCombOuts + : DfsType = + let rec exploreChildren visited currStack children : DfsType = + match children with + | [] -> NoCycle visited + | (childId, childPNum) :: children' -> + match dfs childId childPNum graph visited currStack getCombOuts with + | NoCycle visited -> + // Keep on exploring other children. + exploreChildren visited currStack children' + | Backtracking (cycle, cycleEnd) -> + match cycleEnd = currNodeId with + | true -> Cycle cycle + | false -> Backtracking (currNodeId :: cycle, cycleEnd) + | Cycle cycle -> + Cycle cycle + + let currNode = getNodeOrFail graph currNodeId + // Ignore the info about port number unless node is custom node. + let inputPortNumber = + match currNode.Type with + | Custom _ -> Some inputPortNumber + | _ -> None + let curr = currNodeId, inputPortNumber + + // Combinational components may form cycles, hence proceed with + // the DFS. + match currStack.Contains curr, visited.Contains curr with + | true, true -> + // Already visited in this subtree: cycle detected. + Backtracking ([currNodeId], currNodeId) + | false, true -> + // Already visited, and this node is part of no cycles. + NoCycle visited + | false, false -> + // New node. + let visited = visited.Add curr + let currStack = currStack.Add curr + // Get all of the combinatorial outputs of the node using the function + // getCombinatorialOutputs (already partially applied). + getCombOuts currNode inputPortNumber + |> Map.toList + // Extract all the children for all the ports. + |> List.collect (fun (_, portChildren) -> portChildren) + |> exploreChildren visited currStack + | true, false -> + // A node in the stack must always be visited. + failwithf "what? Node never visited but in the stack, while detecting cycle: %A" currNodeId + +/// Calculate which connections are involved in a cycle. +let private calculateConnectionsAffected + (connections : Connection list) + (cycle : ComponentId list) + : ConnectionId list = + let rec findConnection connections (compIdFrom, compIdTo) : ConnectionId = + match connections with + | [] -> failwithf "what? Could not find connection among %A and %A" compIdFrom compIdTo + | conn :: connections' -> + match ComponentId conn.Source.HostId = compIdFrom, + ComponentId conn.Target.HostId = compIdTo with + | true, true -> ConnectionId conn.Id + | _ -> findConnection connections' (compIdFrom, compIdTo) + if cycle.Length < 2 then failwithf "what? Cycle with length less than 2: %A" cycle + // Find a connection among all pairs. + cycle + |> List.mapi (fun i compId -> (compId, cycle[(i + 1) % cycle.Length])) + |> List.map (findConnection connections) + +/// Check that the combinatorial logic contains no cycles, in a given graph. +/// If connections are passed, a possible error message will contain the +/// connections affected. +let private checkCombinatorialCycle + (graph : SimulationGraph) + (connectionsOpt : (Connection list) option) + (inDependency : string option) + getCombOuts + : SimulationError option = + let rec checkGraphForest nodeIdsAndPNums visited = + match nodeIdsAndPNums with + | [] -> None + | (nodeId, pNum) :: nodeIdsAndPNums' -> + match dfs nodeId pNum graph visited Set.empty getCombOuts with + | NoCycle visited -> checkGraphForest nodeIdsAndPNums' visited + | Cycle cycle -> + let connectionsAffected = + match connectionsOpt with + | None -> [] + | Some conns -> + try + calculateConnectionsAffected conns cycle + with + | e -> [] + Some { + Msg = "Cycle detected in combinatorial logic." + InDependency = inDependency + ComponentsAffected = cycle + ConnectionsAffected = connectionsAffected + } + | Backtracking (c, ce) -> failwithf "what? Dfs should never terminate while backtracking: %A" (c, ce) + + let visited = Set.empty + let allIdsAndPNums = graph |> Map.toList |> List.collect (fun (id, comp) -> + match comp.Type with + | Custom custom -> + // Explore ever input port of a custom component. + custom.InputLabels |> List.mapi (fun i _ -> id, InputPortNumber i) + | _ -> + // The input port number does not matter for non custom components, + // it will be ignored in the dfs. + [id, InputPortNumber 0] + ) + checkGraphForest allIdsAndPNums visited + +/// Recursively make sure that there are no combinatorial loops in any of the +/// dependencies of a graph, and in the graph itself. +/// Keep track of the alreadyChecked graphs in order to waste time uselessly as +/// the same component may be used multiple times. +let rec private recursivelyCheckCombinatorialCycles + (currGraph : SimulationGraph) + (connectionsOpt : (Connection list) option) + (dependencyName : string) + (alreadyChecked : Set) + getCombOuts + : Result, SimulationError> = + let rec iterateChildren + (alreadyChecked : Set) + (children : (ComponentId * SimulationComponent) list) = + match children with + | [] -> Ok alreadyChecked + | (_, child) :: children' -> + let childGraph = Option.get child.CustomSimulationGraph + let childName = getCustomName child.Type + recursivelyCheckCombinatorialCycles + childGraph None childName alreadyChecked getCombOuts + |> Result.bind (fun alreadyChecked -> + iterateChildren alreadyChecked children' + ) + + match alreadyChecked.Contains dependencyName with + | true -> Ok alreadyChecked // Already checked. + | false -> + // Add curr dependency to the already checked set. + let alreadyChecked = alreadyChecked.Add dependencyName + // Check all custom components in this graph. + currGraph + |> Map.filter (fun compId comp -> isCustom comp.Type) + |> Map.toList + |> iterateChildren alreadyChecked + |> Result.bind (fun alreadyChecked -> + // Children are fine. Check the current graph. + // connectionsOpt is populated only for the intial call to this + // function. In such case, we are not in a dependency, otherwise we + // are. + let inDependency = match connectionsOpt with + | None -> Some dependencyName + | Some _ -> None + checkCombinatorialCycle currGraph connectionsOpt + inDependency getCombOuts + |> function + | None -> Ok alreadyChecked + | Some err -> Error err + ) + +/// Analyse a SimulationGraph and return any error (or None). +/// The SimulationGraph should be fully merged with its dependency, so this +/// function has to be called after the dependency merger has finished. +/// This function assumes that there are no cyclic dependencies. +let analyseSimulationGraph + (diagramName : string) + (graph : SimulationGraph) + (connections : Connection list) + : SimulationError option = + match calculateCustomComponentsCombinatorialPaths diagramName graph with + | None -> + // It was not possible to infer combinatorial paths for custom + // components, probably due to a cyclic dependency. + // The dependency merger should have already errored if there were such + // problems. + failwithf "what? calculateCustomComponentsCombinatorialPaths returned None whithin analyseSimulationGraph. This should never happen" + | Some cccp -> + // cccp: custom components combinatorial paths. + // This is a map that lists all of the combinatorial paths from inputs + // to outputs for the needed custom components. + // The getCombinatorialOutputs function uses cccp to determine the + // combinatorial children of a node. + let getCombOuts = getCombinatorialOutputs cccp + recursivelyCheckCombinatorialCycles graph (Some connections) diagramName + Set.empty getCombOuts + |> function + | Ok _ -> None + | Error err -> Some err diff --git a/src/Renderer/Simulator/Simulator.fs b/src/Renderer/Simulator/Simulator.fs new file mode 100644 index 0000000..e8f9f93 --- /dev/null +++ b/src/Renderer/Simulator/Simulator.fs @@ -0,0 +1,98 @@ +(* + Simulator.fs + + This module collects all the APIs required for a simulation. +*) + +module Simulator + +open CommonTypes +open SimulatorTypes +open SynchronousUtils +open SimulationBuilder +open SimulationRunner +open DependencyMerger +open SimulationGraphAnalyser + +// Simulating a circuit has four phases (not precisely in order of execution): +// 1. Building a simulation graph made of SimulationComponents. +// 2. Merging all the necessary dependencies. +// 3. Analyse the graph to look for errors, such as unconnected ports, +// combinatorial loops, etc... +// 4. Setting the values of the input nodes of the graph to kickstart the +// simulation process. + +/// Builds the graph and simulates it with all inputs zeroed. + + +let rec prepareSimulation + (diagramName : string) + (canvasState : CanvasState) + (loadedDependencies : LoadedComponent list) + : Result = + + /// Tune for performance of initial zero-length simulation versus longer run. + /// Probably this is not critical. + let initMaxSteps = 10 + match runCanvasStateChecksAndBuildGraph canvasState loadedDependencies with + | Error err -> Error err + | Ok graph -> + match mergeDependencies diagramName graph + canvasState loadedDependencies with + | Error err -> Error err + | Ok graph -> + // Simulation graph is fully merged with dependencies. + // Perform checks on it. + let components, connections = canvasState + let inputs, outputs = getSimulationIOs components + match analyseSimulationGraph diagramName graph connections with + | Some err -> Error err + | None -> + try + match FastRun.buildFastSimulation initMaxSteps graph with + | Ok fs -> + Ok { + FastSim = fs + Graph = graph // NB graph is now not initialised with data + Inputs = inputs; + Outputs = outputs + IsSynchronous = hasSynchronousComponents graph + NumberBase = Hex + ClockTickNumber = 0 + } + | Error e -> Error e + with + | e -> + printfn "\nEXCEPTION:\n\n%A\n%A\n\n" e.Message e.StackTrace + Error { + Msg = sprintf "\nInternal ERROR in Issie fast simulation: %A\n\n%A\n" e.Message e.StackTrace + InDependency = None + ComponentsAffected = [] + ConnectionsAffected = [] + } + |> Result.map (fun sd -> + //Fast.compareFastWithGraph sd |> ignore + sd) + + + +/// Expose the feedSimulationInput function from SimulationRunner. +let feedSimulationInput = SimulationRunner.feedSimulationInput + +/// Expose the feedClockTick function from SimulationRunner. +let feedClockTick = SimulationRunner.feedClockTick + +/// Expose the extractSimulationIOs function from SimulationRunner. +let extractSimulationIOs = SimulationRunner.extractSimulationIOs + +/// Get some info and the state of all stateful components in a graph. +let extractStatefulComponents + (graph : SimulationGraph) + : SimulationComponent list = + graph + |> Map.toList + |> List.map snd + |> List.filter (fun comp -> comp.State <> NoState) + // TODO: recursively search custom components? + + diff --git a/src/Renderer/Simulator/SimulatorTypes.fs b/src/Renderer/Simulator/SimulatorTypes.fs new file mode 100644 index 0000000..7533b96 --- /dev/null +++ b/src/Renderer/Simulator/SimulatorTypes.fs @@ -0,0 +1,805 @@ +(* + Types.fs + + This module collects a series of types used in the simulator logic. +*) + +module rec SimulatorTypes +open Fable.Core +open CommonTypes + + + +/// Binary data used in simulation +type Bit = Zero | One + +/// Fixed width bus data used in simulation +/// TODO: refactor as int64 or bigint for efficiency +type WireData = Bit list + + +/// State (possibly none) remembered by component +/// from previous clock cycle. Combinational components +/// have no state. +type SimulationComponentState = + | NoState // For all stateless components. + | DffState of uint32 + | RegisterState of FastData + | RamState of Memory1 + +/// Message used to feed forward evaluation. Clock +/// tick => state changes to that in next cycle +type IsClockTick = + | No + | Yes of SimulationComponentState // Pass the state only for clock ticks. + + +/// Like Component but with additional dynamic info used by simulator +/// Clocked components have state data. +/// All components have optional data on inputs that propagates +/// During evaluation of combinational logic +/// Components require all inputs to have data before they can +/// generate output data +/// Note that reducer is a function that generates the outputs +/// TODO: make this equatable data? +type SimulationComponent = { + Id : ComponentId + Type : ComponentType + Label : ComponentLabel + // Mapping from each input port number to its value (it will be set + // during the simulation process). + // TODO: maybe using a list would improve performance? + Inputs : Map + // Mapping from each output port number to all of the ports and + // Components connected to that port. + Outputs : Map + // this is MUTABLE and used only during clock tick change propagation + // location n = true => the output (of a synchronous component) has been + // propagated in propagateStateChanges. Location n corresponds to + // OutputPortNumber n. + // not used except for synchronous components and custom components + OutputsPropagated: bool array + // This CustomSimulationGraph should only be Some when the component Type is + // Custom. A custom component keeps track of its internal state using this + // CustomSimulationGraph. This graph will be passed to the reducer and + // updated from the reducer return value. + CustomSimulationGraph : SimulationGraph option + // State for synchronous stateful components, like flip flops and memories. + // The state should only be changed when clock ticks are fed. Other changes + // will be ignored. + State : SimulationComponentState + // Function that takes the inputs and transforms them into the outputs, + // according to the behaviour of the component. + // The size of the Inputs map, must be as expected by the component, + // otherwhise the reducer will return None (i.e. keep on waiting for more + // inputs to arrive). + // The idea is similar to partial application, keep on providing inputs + // until the output can be evaluated. + // The reducer should fail if more inputs than expected are received. + // The reducer accepts a SimulationGraph for custom components only. + // The reducer accepts an IsClockTick flag that tells you if that is an + // update due to the global clock. + Reducer : ReducerInput -> ReducerOutput +} + +/// Map every ComponentId to its SimulationComponent. +and SimulationGraph = Map + +/// This drives the generation of component outputs +/// it is processed by the Reducer function. +and ReducerInput = { + Inputs: Map + CustomSimulationGraph: SimulationGraph option + IsClockTick: IsClockTick +} + +/// When all inputs are available the reducer function will generate +/// these outputs. For custom components the SimulationGraph contains +/// embedded state. +and ReducerOutput = { + Outputs: Map option + NewCustomSimulationGraph: SimulationGraph option + NewState: SimulationComponentState // Will be saved only after clock ticks. +} + +/// contains info needed to propagate wire value changes through a simulation. +and OutputChange = { + CComp: SimulationComponent + COutputs: Map + } + + +/// For every IO node, keep track of its Id, Label and wire width. +/// - Id: to feed values into the simulationGraph. +/// - Label: to display a nice form to the user. +/// - Width: to feed the right values into the simulation. +type SimulationIO = ComponentId * ComponentLabel * int + +/// - Top level data tracking a simulation +type SimulationData = { + FastSim: FastSimulation + Graph : SimulationGraph + // For each input/output, keep its Id and Label to easily access it. + Inputs : SimulationIO list + Outputs : SimulationIO list + // Whether the graph contains synchronous logic. + IsSynchronous : bool + // The base that should be used to display numbers in the simulation. + NumberBase : NumberBase + // Keep track of the number of clock ticks of the simulation. + ClockTickNumber : int +} + +/// - Documents an error found while simulating. +/// - Should never happen +type SimulationError = { + Msg : string + InDependency : string option + ComponentsAffected : ComponentId list + ConnectionsAffected : ConnectionId list +} + +/// Wrapper for Javascript (Diagram) component. Why here? + +[] +type JSComponent = | JSComponent of obj +/// Wrapper for Javascript (Diagram) connection. Why here? + +[] +type JSConnection = | JSConnection of obj +/// State retrieves directly from Diagram has Javascript objects +type JSCanvasState = JSComponent list * JSConnection list + + + +//----------------------------------------------------------------------------------------------// +//--------------------------------Fast Digital Bus Data Type------------------------------------// +//----------------------------------------------------------------------------------------------// +// data is stored differently according to its buswidth. +// We use all three options for efficiency +// Bit is more efficient than word for known boolean ops but it can be normalised to Word +// to make implementation of multiple bit components (that may carry one bit) simpler. +// BigWord is needed for > 32 bits, and much less efficient for < 32 bits. + +type FastBits = + | Word of dat:uint32 + | BigWord of dat:bigint + +type FastData = + { + Dat : FastBits + Width : int + } with + + member inline this.GetBigInt = // always possible + match this.Dat with + | Word n -> bigint n + | BigWord n -> n + + /// return Some uint32 representing data if possible else None + member inline this.GetUint32 = // not possible if too large + match this.Dat with + | Word n -> Some n + | BigWord n when this.Width <= 32 -> Some (uint32 n) + | _ -> None + /// can fail - for fast access to word data + member inline this.GetQUint32 = + match this.Dat with + | Word n -> n + | BigWord n when this.Width <= 32 -> uint32 n + | _ -> failwithf $"Can't turn {this} into a uint32" + + + + +//------------------------------------------------------------------------------// +//-------------------EXPERIMENTAL - new data structure to replace WireData------// +//------------------------------------------------------------------------------// + + +type BitInt = uint32 array + +let getBIBit (bits: BitInt) (pos:int) : uint32 = + bits[pos / 32] >>> (pos % 32) + +/// get a field of bits width 'width' offset by 'offset', return the field with 0 offset +let inline getUpperField (x:uint32) (width:int) (offset:int) : uint32 = + (x >>> offset) &&& ((1u <<< width) - 1u) + +/// get the lower 'width' bits, return then offset by 'offset' bits +let inline getLowerField (x:uint32) (width:int) (offset:int) : uint32 = + (x &&& ((1u <<< width) - 1u)) <<< offset + + +let getBIBitsInt (bits:BitInt) (msb: int) (lsb:int) : uint32 = + let width = msb - lsb + 1 + if width < 32 then + let lowerWord = bits[lsb / 32] + let offset = lsb % 32 + let lowerChunk = (lowerWord >>> offset) + if offset + width <= 32 then + // output from only one word + lowerChunk + else + // one word output from two words of source + let upperChunk = getLowerField bits[lsb / 32 + 1] (width - offset - 32) offset + lowerChunk ||| upperChunk + else + failwithf "Cannot extract bits {msb}..{lsb} as a single 32 bit word" + +let getBIBits (bits:BitInt) (msb: int) (lsb:int) : BitInt = + let lsw = lsb / 32 + let outWidth = msb - lsb + 1 + let msw = msb / 32 + let offset = lsb % 32 + if offset = 0 then + bits[msw..lsw] + else + let outWords = outWidth / 32 + 1 + Array.init outWords (fun n -> + match n with + | n when n + lsw = msw -> + getLowerField bits[msw] (outWidth - offset % 32) offset + | n -> + getLowerField bits[n + lsw + 1] (32 - offset) offset ||| + getUpperField bits[n + lsw] offset offset) + +let floatCarryBit = Seq.init 32 (fun _ -> 2.) |> Seq.reduce (*) + +let addBIBits (bits1:BitInt) (bits2:BitInt) (cin: uint32) : BitInt * uint32 = + let mutable tempCarry = if cin = 1u then floatCarryBit else 0. + let outs = + Array.init bits1.Length ( fun n -> + tempCarry <- float bits1[n] + float bits2[n] + (if tempCarry >= floatCarryBit then 1. else 0.) + uint32 tempCarry) + outs, (if tempCarry >= floatCarryBit then 1u else 0u) + +let binopBIBits (op: uint32 -> uint32 -> uint32) (bits1:BitInt) (bits2:BitInt) : BitInt = + Array.init bits1.Length (fun n -> + op bits1[n] bits2[n]) + +/// invert bits1: assuming that width is the bit width of bits1 +/// MS bits not used by bits1 are not inverted. +let invertBIBits (bits:BitInt) (width: int) = + let msw = width / 32 + Array.init bits.Length (fun n -> + let x = bits[n] + if n = msw then + x &&& ((1u <<< width % 32) - 1u) + else x ^^^ 0xFFFFFFFFu) + +/// append bits2 on MSB side of bits1 +let appendBIBits ((bits1:BitInt,width1:int)) ((bits2:BitInt, width2:int)) = + let outWidth = width1 + width2 + let outMSW = outWidth / 32 + let offset = width1 % 32 + let msw1 = width1 / 32 + if offset = 0 then + // we can do straight array append + Array.append bits1 bits2 + elif outMSW = width1 / 32 then + // the added bits can be put in the existing MSW of width1 + let out = Array.copy bits1 + out[outMSW] <- out[outMSW] ||| getLowerField bits2[0] width2 offset + out + else + Array.init (outMSW + 1) (fun n -> + match n with + | _ when n = outMSW -> + getLowerField bits2[n - msw1] (32 - offset) offset ||| + getUpperField bits2[n - msw1 + 1] (offset + outWidth - 32) offset + + | _ when n = width1 / 32 -> + getLowerField bits1[n - width1 % 32] (32 - offset) offset ||| + getUpperField bits2[n - width1 / 32 + 1] offset offset + | _ when n >= width1 / 32 -> + getLowerField bits2[n - width1 / 32] (32 - offset) offset ||| + getUpperField bits2[n - width1 / 32 + 1] offset offset + | _ -> + bits1[n]) + +let bigIntMaskA = + [|1..128|] + |> Array.map ( fun width -> (bigint 1 <<< width) - bigint 1) + +let bigIntBitMaskA = + [|0..128|] + |> Array.map ( fun width -> (bigint 1 <<< width)) + + +let bigIntMask width = + if width <= 128 then bigIntMaskA[width] else (bigint 1 <<< width) - bigint 1 + +let bigIntBitMask pos = + if pos <= 128 then bigIntBitMaskA[pos] else (bigint 1 <<< pos) + + + +let fastBit (n: uint32) = +#if ASSERTS + Helpers.assertThat (n < 2u) (sprintf "Can't convert %d to a single bit FastData" n) +#endif + { Dat = Word n; Width = 1} + + + + + + +let rec bitsToInt (lst: Bit list) = + match lst with + | [] -> 0u + | x :: rest -> + (if x = Zero then 0u else 1u) + + (bitsToInt rest)*2u + +let rec bitsToBig (lst: Bit list) = + match lst with + | [] -> bigint 0 + | x :: rest -> + (if x = Zero then bigint 0 else bigint 1) + + ((bitsToBig rest) <<< 1) + +/// convert Wiredata to FastData equivalent +let rec wireToFast (wd: WireData) = + let n = wd.Length + let dat = + if n <= 32 then + Word (bitsToInt wd) + else + BigWord (bitsToBig wd) + { Dat = dat; Width = n} + +/// convert FastData to WireData equivalent +let rec fastToWire (f: FastData) = + match f.Dat with + | Word x -> + [ 0 .. f.Width - 1 ] + |> List.map + (fun n -> + if (x &&& (1u <<< n)) = 0u then + Zero + else + One) + | BigWord x -> + [ 0 .. f.Width - 1 ] + |> List.map + (fun n -> + if (x &&& bigIntBitMask n) = bigint 0 then + Zero + else + One) + +let fastDataZero = {Dat=Word 0u; Width = 1} +let fastDataOne = {Dat=Word 1u; Width = 1} + +let rec b2s (b:bigint) = + let lsw = b &&& ((bigint 1 <<< 32) - bigint 1) + let hex = $"%08x{uint32 lsw}" + let msws = b >>> 32 + if msws <> bigint 0 then + b2s msws + hex + else + hex + + + + +/// Extract bit field (msb:lsb) from f. Bits are numbered little-endian from 0. +/// Note that for a single bit result the un-normalised version is used, so it will +/// be compatible with fast implementation of boolean logic. +let getBits (msb: int) (lsb: int) (f: FastData) = + let outW = msb - lsb + 1 +#if ASSERTS + Helpers.assertThat + (msb <= f.Width - 1 && lsb <= msb && lsb >= 0) + (sprintf "Bits selected out of range (%d:%d) from %A" msb lsb f) +#endif + match f.Dat with + | Word x -> + let bits = (x >>> lsb) &&& ((1u <<< (msb - lsb + 1)) - 1u) + {Dat = Word bits; Width = outW} + | BigWord x -> + let mask = bigIntMask (msb - lsb + 1) + let bits = (x >>> lsb) &&& mask + //printfn $"lsb={lsb},msb={msb},outW={outW}, mask={b2s mask}, x={b2s x},x/lsb = {b2s(x >>> lsb)} bits={b2s bits}, bits=%x{uint32 bits}" + let dat = + if outW <= 32 then + Word ((uint32 bits) &&& (1u <<< outW) - 1u) + else + BigWord (bits &&& bigIntMask outW) + { Dat = dat; Width = outW} + +let appendBits (fMS: FastData) (fLS: FastData) : FastData = + let ms = fMS.Dat + let ls = fMS.Dat + let w = fMS.Width + fLS.Width + let dat = + match ms, ls with + | Word x1, Word x2 when w <= 32 -> Word((x1 <<< fLS.Width) + x2) + | Word x1, Word x2 -> BigWord((bigint x1 <<< fLS.Width) + bigint x2) + | _ -> BigWord((fMS.GetBigInt <<< fLS.Width) ||| fLS.GetBigInt) + {Dat=dat;Width=w} + +//---------------------------------------------------------------------------------------// +//--------------------------------Fast Simulation Data Structure-------------------------// +//---------------------------------------------------------------------------------------// + +type FComponentId = ComponentId * ComponentId list + +type FData = FastData // for now... + +/// Wrapper to allow arrays to be resized for longer simulations while keeping the links between inputs +/// and outputs +type StepArray<'T> = { + // this field is mutable to allow resizing + mutable Step: 'T array + } + +type FastComponent = { + fId: FComponentId + cId: ComponentId + FType: ComponentType + State: StepArray option + mutable Active: bool + OutputWidth: int option array + InputLinks: StepArray array + InputDrivers: (FComponentId * OutputPortNumber) option array + Outputs: StepArray array + SimComponent: SimulationComponent + AccessPath: ComponentId list + FullName: string + // these fields are used only to determine component ordering for correct evaluation + mutable Touched: bool // legacy field + mutable DrivenComponents: FastComponent list + mutable NumMissingInputValues: int + // these fields are used only by the Verilog output code + mutable VerilogOutputName: string array + mutable VerilogComponentName: string + + } with + + member inline this.GetInput (epoch) (InputPortNumber n) = this.InputLinks[n].Step[epoch] + member this.ShortId = + let (ComponentId sid,ap) = this.fId + (EEExtensions.String.substringLength 0 5 sid) + member inline this.PutOutput (epoch) (OutputPortNumber n) dat = this.Outputs[n].Step[epoch] <- dat + member inline this.Id = this.SimComponent.Id + + + + +// The fast simulation components are similar to the issie components they are based on but with addition of arrays +// for direct lookup of inputs and fast access of outputs. The input arrays contain pointers to the output arrays the +// inputs are connected to, the InputPortNumber integer indexes this. +// In addition outputs are contained in a big array indexed by epoch (simulation time). This allows results for multiple +// steps to begin built efficiently and also allows clocked outputs for the next cycle to be constructed without overwriting +// previous outputs needed for that construction. +// +// For reasons of efficiency Issie's list-style WireData type is optimised by using integers as bit arrays. +// +// For ease of implementation Input and Output components are given a single output (input) port not present on issie. +// this allows sub-sheet I/Os to be linked as normal in the constructed graph via their respective Input and Output connections. +// +// Although keeping input and output connections in the new graph is slightly less efficient it makes things simpler because there is a +// 1-1 connection between components (except for custom components which are removed by the gathering process). +// Note that custom component info is still kept because each component in the graph has a path - the list of custom component ids +// between its graph and root. Following issie this does not include a custom component for the sheet being simulated, which is viewed as +// root. Since custom components have been removed this no longer complicates the simulation. + +type FastSimulation = { + // last step number (starting from 0) which is simulated. + mutable ClockTick: int + // The step number of the last step that can be simulated in the + // current simulation outputs + mutable MaxStepNum: int + // Maximum size of simulation arrays - after which they form a circular buffer + MaxArraySize: int + // top-level inputs to the simulation + FGlobalInputComps: FastComponent array + // constants + FConstantComps: FastComponent array + // clocked components + FClockedComps: FastComponent array + // Components that will be reduced in order allowing sequential reduction to implement simulation + FOrderedComps: FastComponent array + // which is the active component for each set of labels? + mutable FIOActive: Map + // list of deferred links driven from inactive IOlabls - at end of linkage the + // corresponding active IOLabel can be substituted as driver an dthe link made + mutable FIOLinks: ((FastComponent*InputPortNumber)*FastComponent) list + // Fast components: this array is longer than FOrderedComps because it contains + // IOlabel components that are redundant in the simulation + FComps: Map + FSComps: Map + // look up from output port of custom component to the relevant Output component + FCustomOutputCompLookup: Map<(ComponentId*ComponentId list)*OutputPortNumber, FComponentId> + // GatherData from which this simulation was made + G: GatherData + } with + member this.getSimulationData (step: int) ((cid,ap): FComponentId) (opn: OutputPortNumber) = + let (OutputPortNumber n) = opn + match Map.tryFind (cid,ap) this.FComps with + | Some fc -> fc.Outputs[n].Step[step] + | None -> + match Map.tryFind ((cid,ap), opn) this.FCustomOutputCompLookup with + | Some fid -> this.FComps[fid].Outputs[0].Step[step] + | None -> failwithf "What? can't find %A in the fast simulation data" (cid,ap) + +/// GatherTemp is the output type used to accumulate lists of data links when recursively exploring SimulationGraph +/// as first step in flattening it. +/// Each list of pairs is converted into a map at the end in the final GatherData structure +/// The cost of creating maps makes it important to use lists here as the intermediate structures +and GatherTemp = { + // Links Custom Component Id and input port number to corresponding Input + // Component Id (of an Input component which is not top-level) + CustomInputCompLinksT: ((FComponentId * InputPortNumber) * FComponentId) list + // Links (non-top-level) Output component Id to corresponding Custom Component Id & output port number + CustomOutputCompLinksT: (FComponentId * (FComponentId * OutputPortNumber)) list + // Shortcut to find the label of a component; notice that the access path is not needed here because + // Labels of the graph inside a custom component are identical for different instances of the component + Labels: (ComponentId * string) list + // This indexes the SimulationGraph components from Id and access path. Note that the same simulation + // component Id can appear with different access paths if a sheet is instantiated more than once. + // Each entry corresponds to a single FastComponent. + // Note that Custom components are not included in this list. + AllCompsT: ((ComponentId*ComponentId list) * (SimulationComponent * ComponentId list)) list // links to component and its path in the graph +} + +and GatherData = { + // Existing Issie data structure representing circuit for simulation - generated by runCanvasStateChecksAndBuildGraph + Simulation: SimulationGraph + // Maps Custom Component Id and input port number to corresponding Input + // Component Id (of an Input component which is not top-level) + CustomInputCompLinks: Map + // Maps (non-top-level) Output component Id to corresponding Custom Component Id & output port number + CustomOutputCompLinks: Map + // Maps custom component output to corresponding output FastComponent. + // Inverse of CustomOutputCompLinks + CustomOutputLookup: Map + // Shortcut to find the label of a component; notice that the access path is not needed here because + // Labels of the graph inside a custom component are identical for different instances of the component + Labels: Map + // This indexes the SimulationGraph components from Id and access path. Note that the same simulation + // component Id can appear with different access paths if a sheet is instantiated more than once. + // Each entry corresponds to a single FastComponent. + // Note that Custom components are not included in this list. + AllComps: Map // maps to component and its path in the graph + // List of component Input components that are driven externally to simulation + } with + + + member this.getFullName (cid,ap) = + List.map ( fun cid -> match Map.tryFind cid this.Labels with | Some lab -> lab | None -> "*" ) (ap @ [cid]) + |> String.concat "." + +type WaveformType = + | ViewerWaveform of bool + //| IOLabelWaveform - not yet + | NormalWaveform + +type WaveformSpec = { + WId: string // unique within one simulation run, mostly conserved across runs + WType: WaveformType + Conns: ConnectionId array // unique within design sheet (SheetId) + SheetId: ComponentId list // [] for top-level waveform: path to sheet + Driver: FComponentId*OutputPortNumber + DisplayName:string + Width: int + } + +//-------------------------------------------------------------------------------------// +//-------------------Helper functions for simulation types-----------------------------// +//-------------------------------------------------------------------------------------// + +let sprintSimComponent (sComp: SimulationComponent) = + sprintf "'%A': %20s" sComp.Label (sComp.Type.ToString() |> Helpers.sprintInitial 20) + +let shortPSComp (comp:SimulationComponent) = + let lab = match comp.Label with | ComponentLabel lab' -> lab' + match comp.Type with + | Custom sc -> sprintf "%s:Custom.(%s.%A->%A)" lab sc.Name sc.InputLabels sc.OutputLabels + | _ -> sprintf "%s:%A.{%A}" lab comp.Type comp.State + + +let printSimGraph (sg: SimulationGraph) = + printfn "%s" (String.concat "\n" (sg |> Map.toList |> List.map (fun (ComponentId id,comp) -> sprintSimComponent comp + id))) + +let tryGetCompLabel (compId: ComponentId) (sg: SimulationGraph) = + Map.tryPick (fun k v -> if k = compId then Some v else None) sg + |> Option.map (fun comp -> comp.Label) + |> Option.map (fun (ComponentLabel s) -> s) + |> Option.defaultValue "'Not in SimGraph'" + +let extractLabel (label: ComponentLabel) = + let (ComponentLabel name) = label + name + +//-------------------------------------------------------------------------------------// +//-------------------Helper functions for WaveformSpec---------------------------------// +//-------------------------------------------------------------------------------------// + +// NB - all the NetGroup functions assume a working netlist in which NO NET IS UNDRIVEN +// Every Net must be driven by exactly one componnet output port (NLSource). +// IOLabels are nout counted as drivers themselves; every group of same label IOlabels +// and all of their output nets +// makes a netgroup which must be driven by just one NLSource (connected to one of the IOLabel inputs). +// every net is therefore part of one netgroup which is either a single net, or a group of nets associated +// with a set of IOLabel connectors having a given common label. + +let mapKeys (map:Map<'a,'b>) = map |> Map.toSeq |> Seq.map fst |> Array.ofSeq +let mapValues (map:Map<'a,'b>) = map |> Map.toSeq |> Seq.map snd |> Array.ofSeq +let mapItems (map:Map<'a,'b>) = map |> Map.toSeq |> Array.ofSeq + +let private allNComps (netList:NetList) = + netList |> mapValues + +type NGrp = { + Driven: string list; + DriverLabel: string list + Driver: NLTarget list + } + +let makeAllNetGroups (netList:NetList) :NetGroup array= + + let comps = allNComps netList + + let labelConnectedNets: Map = + comps + |> Array.collect (fun comp -> + if comp.Type = IOLabel then [|comp.Label, comp.Outputs[OutputPortNumber 0]|] else [||]) + |> Array.groupBy (fun (label, _) -> label) + |> Array.map (fun (lab, labOutArr)-> lab, (labOutArr |> Array.map (snd))) + |> Map.ofArray + + let makeNetGroup (comp: NetListComponent) (opn: OutputPortNumber) (targets:NLTarget list) = + let connected = + targets + |> List.toArray + |> Array.collect (fun target -> + let comp = netList[target.TargetCompId] + if comp.Type = IOLabel then labelConnectedNets[comp.Label] else [||]) + {driverComp=comp; driverPort=opn; driverNet=targets; connectedNets=connected} + + + let allNetGroups = + comps + |> Array.collect (fun comp -> + match comp.Type with + | IOLabel -> [||] + | _ -> Map.map (makeNetGroup comp) comp.Outputs |> mapValues) + allNetGroups + +let getFastOutputWidth (fc: FastComponent) (opn: OutputPortNumber) = + let (OutputPortNumber n) = opn + fc.Outputs[n].Step[0].Width + +let getWaveformSpecFromFC (fc: FastComponent) = + let viewerName = extractLabel fc.SimComponent.Label + { + WId = viewerName // not unique yet - may need to be changed + WType = ViewerWaveform false + Conns = [||] // don't use connection nets for Viewer (yet) + SheetId = snd fc.fId + Driver = fc.fId, OutputPortNumber 0 + DisplayName = viewerName + Width = getFastOutputWidth fc (OutputPortNumber 0) + } + +let makeConnectionMap (ngs: NetGroup array) = + let connsOfNG (ng: NetGroup) = + ng.driverNet :: (List.ofArray ng.connectedNets) + |> List.map (List.map (fun tgt -> tgt.TargetConnId)) + |> List.concat + |> List.toArray + Array.map connsOfNG ngs + |> Array.collect(fun conns -> Array.map (fun conn -> conn,conns) conns) + |> Map.ofArray + + +let getFastDriver (fs: FastSimulation) (driverComp: NetListComponent) (driverPort: OutputPortNumber) = + match driverComp.Type with + | Custom _ -> + let customFId:FComponentId = driverComp.Id,[] + let customOutput = fs.FCustomOutputCompLookup[customFId,driverPort] +#if ASSERTS + Helpers.assertThat (Map.containsKey customOutput fs.FComps) + (sprintf "Help: can't find custom component output in fast Simulation") +#endif + customOutput, OutputPortNumber 0 + + | _ -> + (driverComp.Id,[]),driverPort + +let getWaveformSpecFromNetGroup + (fs: FastSimulation) + (connMap: Map) + (nameOf: NetGroup -> string) + (ng: NetGroup) = + let ngName = nameOf ng + let fId, opn = getFastDriver fs ng.driverComp ng.driverPort + let driverConn = ng.driverNet[0].TargetConnId + let conns = + Map.tryFind driverConn connMap + |> Option.defaultValue [||] + if conns = [||] then + printfn $"Warning: {ngName} has no connections" + { + WId = ngName // not unique yet - may need to be changed + WType = NormalWaveform + Conns = conns + SheetId = [] // all NetGroups are from top sheet at the moment + Driver = fId,opn + DisplayName = ngName + Width = getFastOutputWidth fs.FComps[fId] opn + } + +let standardOrderWaves prevDispNames isWanted (waves: Map) = + let prev' = + prevDispNames + |> Array.filter ( fun name -> Map.containsKey name waves && isWanted name) + let others = + waves + |> mapKeys + |> Array.filter (fun wn -> isWanted wn && not <| Array.contains wn prev') + |> Array.sortBy (fun name -> match waves[name].WType with | ViewerWaveform _ -> 0 | _ -> 1) + Array.append prev' others + +let getWaveformSpecifications + (netGroup2Label: SimulationData -> NetList -> NetGroup -> string) + (sd: SimulationData) + (rState: CanvasState) = + let comps,conns = rState + let compIds = comps |> List.map (fun comp -> comp.Id) + let fs = sd.FastSim + let fcL = mapValues fs.FComps + let viewers = + fcL + |> Array.filter (fun fc -> match fc.FType with Viewer _ -> true | _ -> false) + + + /// NetList is a simplified version of circuit with connections and layout info removed. + /// Component ports are connected directly + /// connection ids are preserved so we can reference connections on diagram + let netList = Helpers.getNetList rState + /// Netgroups are connected Nets: note the iolabel components can connect together multiple nets + /// on the schematic into a single NetGroup + /// Wave simulation allows every distinct NetGroup to be named and displayed + let netGroups = makeAllNetGroups netList + /// connMap maps each connection to the set of connected connections within the same sheet + let connMap = makeConnectionMap netGroups + /// work out a good human readable name for a Netgroup. Normally this is the label of the driver of the NetGroup. + /// Merge and Split and BusSelection components (as drivers) are removed, + /// replaced by corresponding selectors on busses. Names are tagged with labels or IO connectors + /// It is easy to change these names to make them more human readable. + let nameOf ng = netGroup2Label sd netList ng + + // findName (via netGroup2Label) will possibly not generate unique names for each netgroup + // Names are defined via waveSimModel.AllPorts which adds to each name + // an optional unique numeric suffic (.2 etc). These suffixes are stripped from names + // when they are displayed + // TODO: make sure suffixes are uniquely defines based on component ids (which will not change) + // display then in wave windows where needed to disambiguate waveforms. + // Allports is the single reference throughout simulation of a circuit that associates names with netgroups + + Array.append + (Array.map (getWaveformSpecFromNetGroup fs connMap nameOf) netGroups) + (Array.map getWaveformSpecFromFC viewers) + + |> Array.groupBy (fun wSpec -> wSpec.WId) + |> Array.map (fun (root,specs) -> + match specs with + | [|wSpec|] as oneSpec -> oneSpec + | specL -> specL |> Array.mapi (fun i wSpec -> {wSpec with WId = $"{wSpec.WId}!{i}"})) + |> Array.concat + |> Array.map (fun wSpec -> wSpec.WId,wSpec) + |> Map.ofArray + + + + + + + + + diff --git a/src/Renderer/Simulator/SynchronousUtils.fs b/src/Renderer/Simulator/SynchronousUtils.fs new file mode 100644 index 0000000..591729e --- /dev/null +++ b/src/Renderer/Simulator/SynchronousUtils.fs @@ -0,0 +1,290 @@ +(* + SynchronousUtils.fs + + Collection of functions that help to detect and deal with synchronous logic. +*) + +module SynchronousUtils + +open CommonTypes +open SimulatorTypes + +/// Tells wether a component is clocked or not. Note that Custom components may +/// be clocked (cannot tell without recursively analysing them), so they are +/// considered synchronous. +let couldBeSynchronousComponent compType : bool = + match compType with + | DFF | DFFE | Register _ | RegisterE _ | ROM1 _ | RAM1 _ | AsyncRAM1 _ | Custom _ -> true // We have to assume custom components are clocked as they may be. + | Input _ | Output _ | IOLabel | Constant1 _ | BusSelection _ | BusCompare _ | MergeWires | SplitWire _ | Not | And | Or | Xor + | Nand | Nor | Xnor | Mux2 | Demux2 | NbitsAdder _ | NbitsXor _ | Decode4 | AsyncROM1 _ | Viewer _ -> false + | _ -> failwithf $"Legacy components {compType} should never be read!" + +/// used to do asynchronous cycle checking on atomic components with non-trivial asynch paths. +/// should this, or something like it, also be used for in dependency cycle checking? +/// returns Some (async outputPortNumbers from inputPortNumber) if component is hybrid, otherwise None. +let getHybridComponentAsyncOuts compType inputPortNumber = + match compType, inputPortNumber with + | AsyncRAM1 _, InputPortNumber 0 -> Some [OutputPortNumber 0] + | AsyncRAM1 _, _ -> Some [] + | _ -> None + +let isHybridComponent compType = + getHybridComponentAsyncOuts compType (InputPortNumber 0) + |> Option.isSome + +/// Find out whether a simulation graph has some synchronous components. +let rec hasSynchronousComponents graph : bool = + graph + |> Map.map (fun compId comp -> + match comp.Type with + | DFF | DFFE | Register _ | RegisterE _ | ROM1 _ | RAM1 _ | AsyncRAM1 _ -> true + | Custom _ -> hasSynchronousComponents <| Option.get comp.CustomSimulationGraph + | Input _ | Output _ | IOLabel | BusSelection _ | BusCompare _ | MergeWires | SplitWire _ | Not | And | Or + | Xor | Nand | Nor | Xnor | Mux2 | Demux2 | NbitsAdder _ | NbitsXor _ | Decode4 | AsyncROM1 _ | Constant1 _ | Viewer _ -> false + | _ -> failwithf $"legacy components should never be read {comp.Type}" + ) + |> Map.tryPick (fun compId isSync -> if isSync then Some () else None) + |> function | Some _ -> true | None -> false + +let isInput = function | Input _ -> true | _ -> false +let isOutput = function | Output _ -> true | _ -> false +let isCustom = function | Custom _ -> true | _ -> false +let isIOLabel = function | IOLabel _ -> true | _ -> false + +let getCustomName = + function + | Custom custom -> custom.Name + | _ -> failwithf "what? getCustomName should only be called with custom components" +let getCustomComponentType = + function + | Custom custom -> custom + | _ -> failwithf "what? getCustomComponentType should only be called with custom components" + +let getNodeOrFail + (graph : SimulationGraph) + (id : ComponentId) + : SimulationComponent = + match graph.TryFind id with + | None -> failwithf "what? getNodeOrFail received invalid component id: %A" id + | Some comp -> comp + +/// For each graph identified by its name, keep a mapping from input ports and +/// what output ports can be reached. +type private CustomCompsCombPaths = + Map> + +/// Convert the label of a port on a custom component to its port number. +/// Assumes that all labels are unique, otherwise it is undefined behaviour. +let private labelToPortNumber label (labels : string list) = + match List.tryFindIndex ((=) label) labels with + | None -> failwithf "what? Label %s not present in %A" label labels + | Some pNumber -> pNumber + +/// Specific to custom components. +/// Given a map of combinatorial routes from inputs to outputs for every +/// simulation graph, perform a lookup to find the combinatorial routes from a +/// given input to the outputs. Then filter the outputs of the custom node to +/// only point to the combinatorial children (i.e. the ones connected to the +/// combinatorial outptus). +let private getCustomCombinatorialOutputs + (combRoutes : CustomCompsCombPaths) + (customNode : SimulationComponent) + (inputPortNumber : InputPortNumber) + : Map = + // Determine the outputs connected to the input port. + let combOutputs = + match combRoutes.TryFind <| getCustomName customNode.Type with + | None -> failwithf "what? getCustomCombinatorialOutputs 1" + | Some routes -> + match routes.TryFind inputPortNumber with + | None -> failwithf "what? getCustomCombinatorialOutputs 2" + | Some outputs -> outputs + // Filter only the children of the combinatorial outputs. + customNode.Outputs + |> Map.filter (fun outputPortNumber _ -> List.contains outputPortNumber combOutputs) + + +/// Given a map of combinatorial routes from inputs to outputs for every +/// simulation graph, perform a lookup to find the combinatorial routes from a +/// given input to the outputs. Then filter the outputs of the custom node to +/// only point to the combinatorial children (i.e. the ones connected to the +/// combinatorial outptus). +let getCombinatorialOutputs + (combRoutes : CustomCompsCombPaths) + (node : SimulationComponent) + (inputPortNumberOpt : InputPortNumber option) + : Map = + match node.Type with + | Custom _ -> + // Only extract the combinatorial outputs. When calling this function + // with a custom component an inputPortNumber is expected as well. + getCustomCombinatorialOutputs combRoutes node + <| Option.get inputPortNumberOpt + | AsyncRAM1 _ when inputPortNumberOpt = Some (InputPortNumber 0) -> + // special case of hybrid component + node.Outputs + | comp when couldBeSynchronousComponent comp -> + // Synchronous components, no combinatorial outputs. + Map.empty + | comp -> + // Combinatorial component, return all outpus. + node.Outputs + + +/// Start a dfs from the given node and input port number. Return the labels +/// of all output nodes that can be reached from there via a combinatorial path. +/// Note that the information about InputPortNumber is only used by custom +/// component. +let rec private dfs + (graph : SimulationGraph) + (combPaths : CustomCompsCombPaths) + (currId : ComponentId) + (inputPortNumber : InputPortNumber) + (visited: Set) + (outputsReached: ComponentLabel list) + : Set * ComponentLabel list = + let rec exploreChildren visited outputsReached children + : Set * ComponentLabel list = + match children with + | [] -> visited, outputsReached + | (childId, childInpPNum) :: children' -> + let visited, outputsReached = + dfs graph combPaths childId childInpPNum visited outputsReached + // Keep on exploring other children. + exploreChildren visited outputsReached children' + + let currNode = getNodeOrFail graph currId + // Ignore the info about port number unless node is custom node, or a hybrid component + let inputPortNumber = + match currNode.Type with + | Custom _ | AsyncRAM1 _ -> Some inputPortNumber + | _ -> None + + match visited.Contains (currId, inputPortNumber) with + | true -> visited, outputsReached // Ignore already visited nodes. + | false -> + let visited = visited.Add (currId, inputPortNumber) + match currNode.Type with + | Output _ -> + // Found a route to an output. Add its label to the list of + // combinatorial outputs. + visited, currNode.Label :: outputsReached + | _ -> + // Normal component. Get all of its combinatorial children. + getCombinatorialOutputs combPaths currNode inputPortNumber + |> Map.toList + // Extract all the children for all the ports. + |> List.collect (fun (_, portChildren) -> portChildren) + |> exploreChildren visited outputsReached + +/// For each input node in a simulation graph, determine all the output nodes it +/// can reach by just following combinatorial paths. +let private findCombinatorialPaths + (customComp : CustomComponentType) + (currGraph : SimulationGraph) + (combPaths : CustomCompsCombPaths) + : Map = + let labelToString (ComponentLabel label) = label + let labelsToStrings (labels) = List.map fst labels + let rec runDfs inputs = + match inputs with + | [] -> Map.empty + | (_, input) :: inputs' -> + let _, outputsReached = + dfs currGraph combPaths input.Id (InputPortNumber 0) Set.empty [] + let res = runDfs inputs' // Keep on exploring. + // Add results for the current inputs to the map. + // Need to transform form labels to port numbers. + let outputsPNums = + outputsReached + |> List.map (labelToString >> (fun out -> + labelToPortNumber out (labelsToStrings customComp.OutputLabels) + )) + res.Add ( + labelToPortNumber (labelToString input.Label) + (labelsToStrings customComp.InputLabels) + |> InputPortNumber, + outputsPNums |> List.map OutputPortNumber + ) + + currGraph + |> Map.filter (fun compId comp -> isInput comp.Type) + |> Map.toList + |> runDfs + +/// Calculate the combinatorial paths for each custom component in a simulation +/// graph. +let rec private exploreNestedComponents + (currGraph : SimulationGraph) + (currName : string) + (currStack : Set) + (result : CustomCompsCombPaths) + : CustomCompsCombPaths option = + let currStack = currStack.Add currName + + let rec iterateNestedComponents (res : CustomCompsCombPaths option) nested = + match nested with + | [] -> res + | (_, (nextGraph, customNode)) :: nested' when res.IsNone -> None + | (_, (nextGraph, customNode)) :: nested' when res.IsSome -> + let result = Option.get res + match calculateCustomCompCombPaths + nextGraph (getCustomName customNode) + (getCustomComponentType customNode) currStack result with + | None -> None + | Some result -> iterateNestedComponents (Some result) nested' + | _ -> failwithf "what? Impossible case in iterateNestedComponents" + + // Extract all custom components. + currGraph + |> Map.filter (fun compId comp -> isCustom comp.Type) + |> Map.map (fun compId comp -> Option.get comp.CustomSimulationGraph, + comp.Type) + |> Map.toList + |> iterateNestedComponents (Some result) + +/// Calculate the combinatorial paths for a custom component and add it to the +/// result map. +and private calculateCustomCompCombPaths + (currGraph : SimulationGraph) + (currName : string) + (customComp : CustomComponentType) + (currStack : Set) + (result : CustomCompsCombPaths) + : CustomCompsCombPaths option = + // Check if the current name is in the stack. If so, there is a circular + // dependency and return None. + // If the current graph has already an inferred value, return it + // immediately. + match currStack.Contains currName, result.ContainsKey currName with + | true, _ -> None // Cyclic dependency. + | false, true -> Some result // Already inferred. + | false, false -> + // New graph never explored. + // Infer the information for all the custom components first. If any + // nested custom component returns None, then return None here too. + match exploreNestedComponents currGraph currName currStack result with + | None -> None + | Some result -> + // All nested components are fine. Infer this graph and add it to + // the map. + result.Add (currName, findCombinatorialPaths customComp currGraph result) + |> Some + +/// For each dependecy in a simulation graph, create a map containing: +/// - key: name of the custom component. +/// - value: a map with: +/// - key: each InputPortNumber +/// - value: a list of OutputPortNumber combinatorially connected to the +/// input. +/// An input is considered combinatorially connected to an output if there is at +/// least one logic path connecting an input directly with the output. In other +/// words, there must be at least one route from the input to output that does +/// not encounter any synchronous component. +/// Return None if such information cannot be inferred, for example if there is +/// a circular dependency. +let calculateCustomComponentsCombinatorialPaths + (diagramName : string) + (graph : SimulationGraph) + : CustomCompsCombPaths option = + exploreNestedComponents graph diagramName Set.empty Map.empty diff --git a/src/Renderer/Simulator/Verilog.fs b/src/Renderer/Simulator/Verilog.fs new file mode 100644 index 0000000..793dca1 --- /dev/null +++ b/src/Renderer/Simulator/Verilog.fs @@ -0,0 +1,603 @@ +module Verilog + +open CommonTypes +open SimulatorTypes +open SynchronousUtils +open EEExtensions +open FastRun +open Helpers +open NumberHelpers + +type VMode = ForSynthesis | ForSimulation + + +/// take FullName and convert it into a verilog compatible form +/// this is not 1-1, so outputs may not be unique, that is OK +let verilogNameConvert (maxChars:int) (s: string) = + let maxIdentifierLength = 50 + + let baseName = + EEExtensions.String.split [| '(' |] s + |> Array.toList + |> function + | h :: _ -> h + | [] -> "x" + |> Seq.map (function | ch when System.Char.IsLetterOrDigit ch || ch = '_' -> string ch | _ -> "") + |> Seq.truncate maxChars + |> String.concat "" + + + let extraLength = baseName.Length - maxIdentifierLength + + if extraLength > 0 then + baseName[extraLength..] + |> Seq.map string + |> string + else + baseName + +/// simple way to assign to each component and component output a unique verilog compatible name. +/// outputs will become reg or wire signals in the Verilog +let writeVerilogNames (fs: FastSimulation) = + let getShortPath (path: ComponentId list) : string = + path + |> List.map (fun (ComponentId cid) -> cid) + |> (function | (t) -> t) + |> List.map (verilogNameConvert 1) + |> String.concat "" + + /// generate from a component a maybe non-unique name made from its Label and abbreviated path + let getBaseVerilogName fc = + let sc = fc.SimComponent + let fakeName s = $"%s{s}{String.substringLength 0 2 (match sc.Id with | ComponentId s -> s)}" + let cLabel = + match sc.Label , sc.Type with + | ComponentLabel "", SplitWire _ -> fakeName "Split" + | ComponentLabel "", MergeWires -> fakeName "Merge" + | ComponentLabel "", _ -> fakeName "Other" + | ComponentLabel lab,_ -> lab.ToUpper() + + match fc.fId with + | (_,[]) -> verilogNameConvert 20 cLabel + | (_,path) -> verilogNameConvert 20 cLabel + "$" + getShortPath path + + // keep array of components and base names in well defined order + let namesWithFC = + fs.FComps + |> Map.toArray + |> Array.sortBy (fun (fid,_) -> fid) + |> Array.map (fun (fid, fc) -> + getBaseVerilogName fc, fc) + /// if the set of names is not distinct add suffixes as needed to make it so + /// recursive to deal with unusual case where adding a suffix causes another clash + let rec disambiguate names: (string * FastComponent) array = + if Array.length (Array.distinctBy fst names) = names.Length + then + names + else + names + |> Array.groupBy fst + |> Array.collect (fun (name, groupA) -> + match groupA.Length with + | 1 -> groupA // if length 1 => unique and no suffix needed + | _ -> Array.mapi (fun i (vName,fc) -> $"{vName}${i}",fc) groupA) + |> disambiguate + + // write verilog names + disambiguate namesWithFC + |> Array.iter (fun (name, fc) -> + fc.VerilogComponentName <- name + fc.VerilogOutputName + |> Array.iteri + (fun portNum _ -> + let suffix = + if fc.VerilogOutputName.Length = 1 then + "" + else + $"$o{portNum}" + let outName = $"{fc.VerilogComponentName}{suffix}" + fc.VerilogOutputName[portNum] <- outName)) + + + + +let makeAsyncRomModule (moduleName: string) (mem: Memory1) = + let aMax = mem.AddressWidth - 1 + let dMax = mem.WordWidth - 1 + let numWords = 1 <<< mem.AddressWidth + + let romInits = + mem.Data + |> Map.toArray + |> Array.map (fun (a, d) -> sprintf $"rom[%d{a}] = %d{d};") + |> String.concat "\n" + + sprintf + $""" + + module %s{moduleName}(q, a); + output[%d{dMax}:0] q; + input [%d{aMax}:0] a; + reg [%d{dMax}:0] rom [%d{numWords - 1}:0]; + + assign q = rom[a]; + integer i; + initial + begin + for (i=0; i < {numWords}; i=i+1) + begin + rom[i] = 0; + end + + %s{romInits} + end + endmodule + """ + +let makeRomModule (moduleName: string) (mem: Memory1) = + let aMax = mem.AddressWidth - 1 + let dMax = mem.WordWidth - 1 + let numWords = 1 <<< mem.AddressWidth + + let romInits = + mem.Data + |> Map.toArray + |> Array.map (fun (a, d) -> sprintf $"rom[%d{a}] = %d{d};") + |> String.concat "\n" + + sprintf + $""" + + module %s{moduleName}(q, a, clk); + output reg [%d{dMax}:0] q; + input clk; + input [%d{aMax}:0] a; + reg [%d{dMax}:0] rom [%d{numWords - 1}:0]; + always @(posedge clk) q <= rom[a]; + integer i; + initial + begin + for (i=0; i < {numWords}; i=i+1) + begin + rom[i] = 0; + end + + %s{romInits} + end + endmodule + """ + +let makeRamModule (moduleName: string) (mem: Memory1) = + let aMax = mem.AddressWidth - 1 + let dMax = mem.WordWidth - 1 + let numWords = 1u <<< mem.AddressWidth + + let ramInits = + mem.Data + |> Map.toArray + |> (Array.map (fun (a, d) -> sprintf $"ram[%d{a}] = %d{d};")) + |> String.concat "\n" + + sprintf + $""" + + module %s{moduleName}(q, a, d, we, clk); + output reg [%d{dMax}:0] q; + input [%d{dMax}:0] d; + input [%d{aMax}:0] a; + input we, clk; + reg [%d{dMax}:0] ram [%d{numWords - 1u}:0]; + always @(posedge clk) begin + if (we) + ram[a] <= d; + q <= ram[a]; + end + + integer i; + initial + begin + for (i=0; i < {numWords}; i=i+1) + begin + ram[i] = 0; + end + + %s{ramInits} + end + endmodule + + """ + +let makeAsyncRamModule (moduleName: string) (mem: Memory1) = + let aMax = mem.AddressWidth - 1 + let dMax = mem.WordWidth - 1 + let numWords = 1u <<< mem.AddressWidth + + let ramInits = + mem.Data + |> Map.toArray + |> (Array.map (fun (a, d) -> sprintf $"ram[%d{a}] = %d{d};")) + |> String.concat "\n" + + sprintf + $""" + + module %s{moduleName}(q, a, d, we, clk); + output reg [%d{dMax}:0]; + output q [%d{dMax}:0]; + input [%d{dMax}:0] d; + input [%d{aMax}:0] a; + input we, clk; + reg [%d{dMax}:0] ram [%d{numWords - 1u}:0]; + always @(posedge clk) begin + if (we) + ram[a] <= d; + end + q <= ram[a]; + + + integer i; + initial + begin + for (i=0; i < {numWords}; i=i+1) + begin + ram[i] = 0; + end + + %s{ramInits} + end + endmodule + + """ + +/// get all the RAM and ROM modules used +/// NB at the moment each instance is made a separately named module, for simplicity +let getInstantiatedModules (fs: FastSimulation) = + fs.FComps + |> Map.toArray + |> Array.collect + (fun (fid, fc) -> + let name = fc.VerilogComponentName + + match fc.FType with + | RAM1 mem -> [| makeRamModule name mem |] + | AsyncRAM1 mem -> [| makeAsyncRamModule name mem |] + | ROM1 mem -> [| makeRomModule name mem |] + | AsyncROM1 mem -> [| makeAsyncRomModule name mem |] + | _ -> [||]) + +let removeHybridComps (fa: FastComponent array) = + Array.filter (fun fc -> not (isHybridComponent fc.FType)) fa + +let activeComps (fs: FastSimulation) = + [ fs.FClockedComps; removeHybridComps fs.FOrderedComps ] + |> Array.concat + +let makeAccessPathIndex (fs: FastSimulation) = + let apArr = + Array.append + [| [] |] + (activeComps fs + |> Array.map (fun fc -> fc.AccessPath)) + + apArr + |> Array.distinct + |> Array.sortBy (fun ap -> List.length ap) + |> Array.indexed + |> Array.map (fun (index, ap) -> ap, index) + |> Map.ofArray + + + + +/// generate an instance of a module named block +let getInstanceOf (block: string) (instanceName: string) (ports: string array) = + let portNames = ports |> String.concat "," + sprintf $"%s{block} %s{instanceName} (%s{portNames});\n" + +/// implement binary operator for two-input gate +let getVerilogBinaryOp cType op1 op2 = + let bin opS = sprintf "%s %s %s" op1 opS op2 + let not exp = sprintf "!(%s)" exp + + match cType with + | And -> bin "&&" + | Or -> bin "||" + | Nand -> not <| bin "&&" + | Nor -> not <| bin "||" + | Xor -> sprintf "((%s && !%s) || (!%s) && %s)" op1 op2 op1 op2 + | Xnor -> sprintf "!((%s && !%s) || (!%s) && %s)" op1 op2 op1 op2 + | _ -> failwithf "operator %A not defined" cType + +/// get valid Verilog constant for bus of given width (may be 1) +let makeBits w (c: uint64) = + let c = c &&& ((1UL <<< w) - 1UL) + sprintf $"%d{w}'h%x{c}" + +/// get output port name +let getVPortOut (fc: FastComponent) (OutputPortNumber opn) = fc.VerilogOutputName[opn] + + +/// Get string corresponding to output port name with its width prepended as a Verilog +/// slice. +/// All output ports are internal wire or reg definitions. +let getVPortOutWithSlice (fc: FastComponent) (opn: OutputPortNumber) = + let name = getVPortOut fc opn + let (OutputPortNumber n) = opn + let width = Option.get fc.OutputWidth[n] + + match width with + | 1 -> $"%s{name}" + | _ -> $" [%d{width - 1}:0] {name}" + +/// Get string corresponding to name of signal that drives component input port +let getVPortInput (fs: FastSimulation) (fc: FastComponent) (InputPortNumber ipn) : string = + let labBase = fc.FullName + + match fc.InputDrivers[ipn] with + | Some (fid, opn) -> getVPortOut fs.FComps[fid] opn + | None -> failwithf "Can't find input driver for %A port %d" fc.FullName ipn + + +/// Create fixed width verilog zero. +/// NB it seems this is not strictly needed, integer 0 works! +let getZeros width = + match width with + | 1 -> "1'b0" + | _ -> $"{width}'h0" + +/// what verilog declaration should the output signal have? +let fastOutputDefinition (vType:VMode) (fc: FastComponent) (opn: OutputPortNumber) = + let (OutputPortNumber n) = opn + let name = fc.VerilogOutputName[n] + let vDef = getVPortOutWithSlice fc opn + + match fc.FType, fc.AccessPath with + | Output n, [] -> $"output {vDef};\n" + | DFF, _ + | DFFE, _ -> $"reg {vDef} = 1'b0;\n" + | Input n, [] -> + match vType with + | ForSynthesis -> $"input {vDef};\n" + | ForSimulation -> $"reg {vDef} = {getZeros n};\n" + | Register n, _ + | RegisterE n, _ -> $"reg {vDef} = {getZeros n};\n" + | _ -> $"wire {vDef};\n" + +/// Translates from a component to its Verilog description +let getVerilogComponent (fs: FastSimulation) (fc: FastComponent) = + let ins i = getVPortInput fs fc (InputPortNumber i) + let outs i = getVPortOut fc (OutputPortNumber i) + let name = fc.VerilogComponentName + let idNum = + name + |> String.split [|'_'|] + |> Array.last + + + let outW i = + match fc.OutputWidth[i] with + | Some n when n > 64 -> failwithf "Sorry - Verilog output does not yet work for busses > 64 bit. Output failed" + | Some n -> n + | None -> failwithf "Can't find output width for output port %d of %A\n" i fc.FullName + + let inW i = + let (fid, OutputPortNumber opn) = + match fc.InputDrivers[i] with + | Some x -> x + | None -> failwithf "Can't find input driver for port %d of %s" i fc.FullName + + fs.FComps[fid].OutputWidth[opn] + |> function + | Some n -> n + | None -> failwithf "Can't find output width for output port %d of %A\n" opn fs.FComps[fid] + + + match fc.FType with + | Viewer _ -> "" + | Input _ when fc.AccessPath = [] + -> failwithf "What? cannot call getVerilogComponent to find code for global Input" + | Output _ + | Viewer _ + | IOLabel _ + | Input _ -> sprintf $"assign %s{outs 0} = %s{ins 0};\n" + + | Not -> sprintf "assign %s = ! %s;\n" (outs 0) (ins 0) + | And + | Or + | Xor + | Nand + | Nor + | Xnor + | Xor -> sprintf "assign %s = %s;\n" (outs 0) (getVerilogBinaryOp fc.FType (ins 0) (ins 1)) + | DFFE + | RegisterE _ -> $"always @(posedge clk) %s{outs 0} <= %s{ins 1} ? %s{ins 0} : %s{outs 0};\n" + | DFF + | Register _ -> $"always @(posedge clk) %s{outs 0} <= %s{ins 0};\n" + | Constant1 (w, c,_) + | Constant (w, c) + -> $"assign %s{outs 0} = %s{makeBits w (uint64 c)};\n" + | Decode4 -> + let w = outW 1 + + $"assign %s{outs 0} = (%s{ins 0} == 2'b00) ? %s{ins 1} : {makeBits w (uint64 0)};\n" + + $"assign %s{outs 1} = (%s{ins 0} == 2'b01) ? %s{ins 1} : {makeBits w (uint64 0)};\n" + + $"assign %s{outs 2} = (%s{ins 0} == 2'b10) ? %s{ins 1} : {makeBits w (uint64 0)};\n" + + $"assign %s{outs 3} = (%s{ins 0} == 2'b11) ? %s{ins 1} : {makeBits w (uint64 0)};\n" + | Demux2 -> + let w = outW 0 + + $"assign %s{outs 0} = %s{ins 1} ? {makeBits w (uint64 0)} : %s{ins 0};\n" + + $"assign %s{outs 1} = %s{ins 1} ? %s{ins 0} : {makeBits w (uint64 0)};\n" + | NbitsAdder n -> + let cin = ins 0 + let a = ins 1 + let b = ins 2 + let sum = outs 0 + let cout = outs 1 + $"assign {{%s{cout},%s{sum} }} = %s{a} + %s{b} + %s{cin};\n" + | NbitsXor n -> + let a = ins 0 + let b = ins 1 + let xor = outs 0 + $"assign {xor} = {a} ^ {b};\n" + | Mux2 -> $"assign %s{outs 0} = %s{ins 2} ? %s{ins 1} : %s{ins 0};\n" + | BusSelection (outW, lsb) -> + let sel = sprintf "[%d:%d]" (outW + lsb - 1) lsb + $"assign {outs 0} = {ins 0}{sel};\n" + | BusCompare (w, c) -> $"assign %s{outs 0} = %s{ins 0} == %s{makeBits w (uint64 (uint32 c))};\n" + | MergeWires -> $"assign {outs 0} = {{ {ins 0},{ins 1} }};\n" + | SplitWire _ -> + let lsbBits = outW 0 + let msbBits = outW 1 + + $"assign %s{outs 0} = %s{ins 0}[%d{lsbBits - 1}:0];\n" + + $"assign %s{outs 1} = %s{ins 0}[%d{msbBits + lsbBits - 1}:%d{msbBits}];\n" + | AsyncROM1 mem -> sprintf $"%s{name} I{idNum} (%s{outs 0}, %s{ins 0});\n" + | ROM1 mem -> $"%s{name} I{idNum} (%s{outs 0}, %s{ins 0}, clk);\n" + | RAM1 mem | AsyncRAM1 mem -> $"%s{name} I{idNum} (%s{outs 0}, %s{ins 0}, %s{ins 1}, %s{ins 2}, clk);\n" + | Custom _ -> failwithf "What? custom components cannot exist in fast Simulation data structure" + | AsyncROM _ | RAM _ | ROM _ -> + failwithf $"Invalid legacy component type '{fc.FType}'" + + +/// return the header of the main verilog module with hardware inputs and outputs in header. +let getMainHeader (vType:VMode) (fs: FastSimulation) = + Array.append + fs.FGlobalInputComps + (Array.filter (fun fc -> isOutput fc.FType && fc.AccessPath = []) fs.FOrderedComps) + |> Array.collect + (fun fc -> // NB - inputs are assigned zero and not included in module header + match fc.FType, fc.AccessPath with + | Output _, [] -> // NB - inputs are assigned zero in synthesis and not included in module header + [| fc.VerilogOutputName[0] |] + | Input _, [] when vType = ForSynthesis -> [| fc.VerilogOutputName[0] |] + | _ -> [||]) + |> Array.append (match vType with | ForSynthesis -> [|"clk"|] | ForSimulation -> [||]) + |> String.concat ",\n\t" + |> (fun header -> + let clock = match vType with ForSimulation -> "" | ForSynthesis -> "input clk;" + $"module main (\n\t{header});\n{clock}") + |> fun s -> [| s |] + +/// return the wire and reg definitions needed to make the verilog design work. +let getMainSignalDefinitions (vType: VMode) (fs: FastSimulation) = + fs.FComps + |> mapValues + |> Array.filter (fun fc -> fc.Active) + |> Array.collect + (fun fc -> + fc.Outputs + |> Array.mapi (fun i _ -> fastOutputDefinition vType fc (OutputPortNumber i))) + |> Array.sort + |> Array.append (match vType with | ForSimulation -> [| "reg clk;\n" |] | ForSynthesis -> [||]) + + +/// get the module definitions (one per RAM instance) that define RAMs used +/// TODO: make output more compact by using multiple instances of one module where possible. +/// NB. Initial statement is used to initialise RAM as per simulation: should work with Quartus. +/// NB - there is some inconsistency between this definition and current simulation, which will output +/// ram[0] contents in clock 0 on q. the simulation is incompatible with FPGA tools and should change so +/// that initial ram output is always 0. +let extractRamDefinitions (fs: FastSimulation) = + fs.FOrderedComps + |> Array.collect ( + (fun fc -> + match fc.FType with + | ROM1 mem + | RAM1 mem + | AsyncRAM1 mem + | AsyncROM1 mem -> [| fc.VerilogComponentName, fc.FType |] + | _ -> [||]) + ) + +/// get the verilog statements output from each component +let getMainHardware (fs: FastSimulation) = + let hardware = + [| fs.FClockedComps; fs.FOrderedComps |] + |> Array.concat + + Array.map (getVerilogComponent fs) hardware + +/// make a simple testbench which displays module outputs for the first 30 clock cycles +let getInitialSimulationBlock (vType:VMode) (fs: FastSimulation) = + + let inDefs = + fs.FGlobalInputComps + |> Array.map + (fun fc -> + let width = Option.get fc.OutputWidth[0] + let sigName = fc.VerilogOutputName[0] + $"assign {sigName} = {makeBits width 0uL};") + |> String.concat "\n" + + let outNames, (outFormat, outVars) = + fs.FComps + |> Map.toArray + |> Array.filter + (function + | _, { AccessPath = []; FType = Output _ } -> true + | _ -> false) + |> Array.map + (fun (_, fc) -> + let sigName = fc.VerilogOutputName[0] + + let hexWidth = + let w = Option.get fc.OutputWidth[0] + if w <= 0 then failwithf $"Unexpected width ({w})in verilog output for {fc.FullName}" + (w - 1) / 4 + 1 + + let (ComponentLabel heading) = fc.SimComponent.Label + let heading = fc.VerilogComponentName + let padding = max 0 (hexWidth - heading.Length) + let heading = (String.replicate padding " ") + heading + heading, (max hexWidth heading.Length, $"{sigName}")) + |> Array.unzip + |> (fun (a, b) -> a, Array.unzip b) + + let outNames = String.concat " " outNames + + let outFormat = + outFormat + |> Array.map (fun width -> "%" + $"{width}h") + |> String.concat " " + + let outVars = String.concat "," outVars + match vType with + | ForSynthesis -> [||] + | ForSimulation -> + [| $""" + initial + begin + {inDefs} + clk = 1'b0; + #10 + $display("{outNames}"); + while ($time < 300) + begin + $display("{outFormat}",{outVars}); + #5 clk = ~clk; + #5 clk = ~clk; + end + end + """ |] + + +/// Outputs a string which contains a single verilog file with the hardware in verilog form. +/// The top-level simulation moudle is called main - other modules may be included for RAM & ROM +/// this can be called any time after after buildFastSimulation has created the initial FastSimulation +/// data structure. +/// To simulate this you would need to set up clk as a clock input, and provide stimulus for other inputs if +/// there are any. +let getVerilog (vType: VMode) (fs: FastSimulation) = + // make sure we have Ok names to use for output + writeVerilogNames fs + + [| getInstantiatedModules fs + getMainHeader vType fs + getMainSignalDefinitions vType fs + getMainHardware fs + getInitialSimulationBlock vType fs + [| "endmodule\n" |] |] + |> Array.map (String.concat "") + |> String.concat "\n" + diff --git a/src/Renderer/UI/CatalogueView.fs b/src/Renderer/UI/CatalogueView.fs new file mode 100644 index 0000000..ef0f304 --- /dev/null +++ b/src/Renderer/UI/CatalogueView.fs @@ -0,0 +1,420 @@ +(* + CatalogueView.fs + + View for catalogue in the right tab. +*) + +module CatalogueView + +open Fulma +open Fulma.Extensions.Wikiki +open Fable.React +open Fable.React.Props +open DiagramStyle +open ModelType +open CommonTypes +open PopupView + + +let private menuItem styles label onClick = + Menu.Item.li + [ Menu.Item.IsActive false; Menu.Item.Props [ OnClick onClick; Style styles ] ] + [ str label ] + +let private createComponent compType label model dispatch = + Sheet (Sheet.InitialiseCreateComponent (compType, label)) |> dispatch + +// Anything requiring a standard label should be checked and updated with the correct number suffix in Symbol/Sheet, +// so give the label "" +let createCompStdLabel comp model dispatch = + createComponent comp "" model dispatch + + + +let private makeCustom styles model dispatch (loadedComponent: LoadedComponent) = + let canvas = loadedComponent.CanvasState + menuItem styles loadedComponent.Name (fun _ -> + let custom = Custom { + Name = loadedComponent.Name + InputLabels = FilesIO.getOrderedCompLabels (Input 0) canvas + OutputLabels = FilesIO.getOrderedCompLabels (Output 0) canvas + } + + Sheet (Sheet.InitialiseCreateComponent (custom, "")) |> dispatch + ) + +let private makeCustomList styles model dispatch = + match model.CurrentProj with + | None -> [] + | Some project -> + // Do no show the open component in the catalogue. + project.LoadedComponents + |> List.filter (fun comp -> comp.Name <> project.OpenFileName) + |> List.map (makeCustom styles model dispatch) + +let private createIOPopup hasInt typeStr compType (model:Model) dispatch = + let title = sprintf "Add %s node" typeStr + let beforeText = + fun _ -> str <| sprintf "How do you want to name your %s?" typeStr + let placeholder = "Component name" + let beforeInt = + fun _ -> str <| sprintf "How many bits should the %s node have?" typeStr + let intDefault = model.LastUsedDialogWidth + let body = + match hasInt with + | true -> dialogPopupBodyTextAndInt beforeText placeholder beforeInt intDefault dispatch + | false -> dialogPopupBodyOnlyText beforeText placeholder dispatch + let buttonText = "Add" + let buttonAction = + fun (dialogData : PopupDialogData) -> + // TODO: format text for only uppercase and allowed chars (-, not number start) + // TODO: repeat this throughout this file and selectedcomponentview (use functions) + let inputText = getText dialogData + let inputInt = getInt dialogData + createComponent (compType inputInt) (formatLabelFromType (compType inputInt) inputText) model dispatch + dispatch ClosePopup + let isDisabled = + fun (dialogData : PopupDialogData) -> + (getInt dialogData < 1) || (getText dialogData = "") + dialogPopup title body buttonText buttonAction isDisabled dispatch + +let private createNbitsAdderPopup (model:Model) dispatch = + let title = sprintf "Add N bits adder" + let beforeInt = + fun _ -> str "How many bits should each operand have?" + let intDefault = model.LastUsedDialogWidth + let body = dialogPopupBodyOnlyInt beforeInt intDefault dispatch + let buttonText = "Add" + let buttonAction = + fun (dialogData : PopupDialogData) -> + let inputInt = getInt dialogData + //printfn "creating adder %d" inputInt + createCompStdLabel (NbitsAdder inputInt) {model with LastUsedDialogWidth = inputInt} dispatch + dispatch ClosePopup + let isDisabled = + fun (dialogData : PopupDialogData) -> getInt dialogData < 1 + dialogPopup title body buttonText buttonAction isDisabled dispatch + + +let private createNbitsXorPopup (model:Model) dispatch = + let title = sprintf "Add N bits XOR gates" + let beforeInt = + fun _ -> str "How many bits should each operand have?" + let intDefault = model.LastUsedDialogWidth + let body = dialogPopupBodyOnlyInt beforeInt intDefault dispatch + let buttonText = "Add" + let buttonAction = + fun (dialogData : PopupDialogData) -> + let inputInt = getInt dialogData + //printfn "creating XOR %d" inputInt + createCompStdLabel (NbitsXor inputInt) {model with LastUsedDialogWidth = inputInt} dispatch + dispatch ClosePopup + let isDisabled = + fun (dialogData : PopupDialogData) -> getInt dialogData < 1 + dialogPopup title body buttonText buttonAction isDisabled dispatch + + +let private createSplitWirePopup model dispatch = + let title = sprintf "Add SplitWire node" + let beforeInt = + fun _ -> str "How many bits should go to the top (LSB) wire? The remaining bits will go to the bottom (MSB) wire." + let intDefault = 1 + let body = dialogPopupBodyOnlyInt beforeInt intDefault dispatch + let buttonText = "Add" + let buttonAction = + fun (dialogData : PopupDialogData) -> + let inputInt = getInt dialogData + createCompStdLabel (SplitWire inputInt) model dispatch + dispatch ClosePopup + let isDisabled = + fun (dialogData : PopupDialogData) -> getInt dialogData < 1 + dialogPopup title body buttonText buttonAction isDisabled dispatch + +/// two react text lines in red +let private twoErrorLines errMsg1 errMsg2 = + span [Style [Color Red]] [str errMsg1; br []; str errMsg2; br [] ] + +/// two line message giving constant value +let private constantValueMessage w (cVal:int64) = + let mask = + if w = 64 then + 0xffffffffffffffffUL + else + (1UL <<< w) - 1UL + let uVal = (uint64 cVal) &&& mask + let sVal = ((int64 uVal) <<< 64 - w) >>> 64 - w + let hVal = NumberHelpers.fillHex64 w (int64 uVal) + let line1 = $"Decimal value: %d{uVal} (%d{sVal} signed)" + let line2 = $"Hex value: %s{hVal}" + span [] [str line1; br [] ; str line2; br [] ] + +/// check constant parameters and return two react lines with +/// error message or value details +let parseConstant w cText = + if w < 1 || w > 64 then + twoErrorLines $"Constant width must be in the range 1..64" "", None + else + match NumberHelpers.strToIntCheckWidth w cText with + | Ok n -> + constantValueMessage w n, Some (Constant1 (w,n,cText)) + | Error msg -> + twoErrorLines msg "", None + +/// create react popup to set a constant +let private createConstantPopup model dispatch = + let title = sprintf "Add Constant" + let beforeInt = + fun _ -> str "How many bits has the wire carrying the constant?" + let intDefault = 1 + let parseConstantDialog dialog = + parseConstant + (Option.defaultValue intDefault dialog.Int) + (Option.defaultValue "" dialog.Text) + let beforeText = (fun d -> div [] [d |> parseConstantDialog |> fst; br [] ]) + let placeholder = "Value: decimal, 0x... hex, 0b... binary" + let body = dialogPopupBodyIntAndText beforeText placeholder beforeInt intDefault dispatch + let buttonText = "Add" + let buttonAction = + fun (dialogData : PopupDialogData) -> + let width = getInt dialogData + let text = Option.defaultValue "" dialogData.Text + let constant = + match NumberHelpers.strToIntCheckWidth width text with + | Ok n -> n + | Error _ -> 0L // should never happen? + let text' = if text = "" then "0" else text + createCompStdLabel (Constant1(width,constant,text')) model dispatch + dispatch ClosePopup + let isDisabled = parseConstantDialog >> snd >> Option.isNone + dialogPopup title body buttonText buttonAction isDisabled dispatch + +let private createBusSelectPopup model dispatch = + let title = sprintf "Add Bus Selection node" + let beforeInt2 = + fun _ -> str "Which input bit is the least significant output bit?" + let beforeInt = + fun _ -> str "How many bits width is the output bus?" + let intDefault = 1 + let intDefault2 = 0L + let body = dialogPopupBodyTwoInts (beforeInt,beforeInt2) (intDefault, int64 intDefault2) "60px" dispatch + let buttonText = "Add" + let buttonAction = + fun (dialogData : PopupDialogData) -> + let width = getInt dialogData + let lsb = int32 (getInt2 dialogData) + createCompStdLabel (BusSelection(width,lsb)) model dispatch + dispatch ClosePopup + let isDisabled = + fun (dialogData : PopupDialogData) -> getInt dialogData < 1 || getInt2 dialogData < 0L + dialogPopup title body buttonText buttonAction isDisabled dispatch + +let private createBusComparePopup (model:Model) dispatch = + let title = sprintf "Add Bus Compare node" + let beforeInt2 = + fun _ -> str "What is the decimal value to compare the input with?" + let beforeInt = + fun _ -> str "How many bits width is the input bus?" + let intDefault = model.LastUsedDialogWidth + let intDefault2 = 0L + let body = dialogPopupBodyTwoInts (beforeInt,beforeInt2) (intDefault, int64 intDefault2) "120px" dispatch + let buttonText = "Add" + let buttonAction = + fun (dialogData : PopupDialogData) -> + let width = getInt dialogData + let cVal = getInt2 dialogData + createCompStdLabel (BusCompare(width, uint32 cVal)) model dispatch + dispatch ClosePopup + let isDisabled = + fun (dialogData : PopupDialogData) -> + let w = getInt dialogData + let cVal = getInt2 dialogData |> uint32 + w > 32 || w < 1 || cVal > (1u <<< w) - 1u + dialogPopup title body buttonText buttonAction isDisabled dispatch + +let private createRegisterPopup regType (model:Model) dispatch = + let title = sprintf "Add Register" + let beforeInt = + fun _ -> str "How wide should the register be (in bits)?" + let intDefault = model.LastUsedDialogWidth + let body = dialogPopupBodyOnlyInt beforeInt intDefault dispatch + let buttonText = "Add" + let buttonAction = + fun (dialogData : PopupDialogData) -> + let inputInt = getInt dialogData + createCompStdLabel (regType inputInt) model dispatch + dispatch ClosePopup + let isDisabled = + fun (dialogData : PopupDialogData) -> getInt dialogData < 1 + dialogPopup title body buttonText buttonAction isDisabled dispatch + + + + + +let private createMemoryPopup memType model (dispatch: Msg -> Unit) = + let title = "Create memory" + let intDefault = model.LastUsedDialogWidth + let addError errorOpt (memSetup:(int*int*InitMemData*string option) option) : (int*int*InitMemData*string option) option = + match memSetup with + | Some (n1,n2,mem, _) -> + Some (n1,n2,mem,errorOpt) + | _ -> None + let body = dialogPopupBodyMemorySetup intDefault dispatch + let buttonText = "Add" + let buttonAction = + fun (dialogData : PopupDialogData) -> + let addressWidth, wordWidth, source, msgOpt = getMemorySetup dialogData intDefault + let initMem = { + AddressWidth = addressWidth + WordWidth = wordWidth + Init = source + Data = Map.empty + } + + let memory = FilesIO.initialiseMem initMem dialogData.ProjectPath + match memory with + | Ok mem -> + createCompStdLabel (memType mem) model dispatch + dispatch ClosePopup + | Error mess -> + dispatch <| SetPopupDialogMemorySetup (addError (Some mess) dialogData.MemorySetup) + let isDisabled = + fun (dialogData : PopupDialogData) -> + let addressWidth, wordWidth, source,_ = getMemorySetup dialogData 1 + let error = + match dialogData.MemorySetup with + | Some(_,_,ToFileBadName _,_) -> + Some "File name must be alphanumeric without prefix" + | None -> + Some "" + | Some (_,_,SignedMultiplier,_) + | Some(_,_,UnsignedMultiplier,_) -> + if addressWidth % 2 <> 0 then + Some "The address width must be even for a multiplier" + elif addressWidth > 16 then + Some "The maximum multiplier size is 8X8 - 16 address bits" + else None + | _ -> + None + match error with + | Some msg when msg <> "" -> + match dialogData.MemorySetup with + | Some (_,_,_,e) when e = Some msg -> () + | _ -> dispatch <| SetPopupDialogMemorySetup (addError (Some msg) dialogData.MemorySetup) + | _ -> () + addressWidth < 1 || wordWidth < 1 || error <> None + dialogPopup title body buttonText buttonAction isDisabled dispatch + +let private makeMenuGroup title menuList = + details [Open false] [ + summary [menuLabelStyle] [ str title ] + Menu.list [] menuList + ] + + +let mutable firstTip = true + +let mutable tippyNodes: Browser.Types.Element list = [] + +let private makeMenuGroupWithTip styles title tip menuList = + details [ + Open false; + HTMLAttr.ClassName $"{Tooltip.ClassName} {Tooltip.IsMultiline}" + Tooltip.dataTooltip tip + Style styles + ] [ + summary [menuLabelStyle] [ str title ] + Menu.list [] menuList + ] + +let compareModelsApprox (m1:Model) (m2:Model) = + + let m1r = reduceApprox m1 + let m2r = reduceApprox m2 + let b = m1r = m2r + //printfn "Model equality:%A" b + //if b = false then printfn "\n\n%A\n\n%A\n\n" m1r m2r + b + +let viewCatalogue model dispatch = + let viewCatOfModel = fun model -> + let styles = + match model.Sheet.Action with + | Sheet.InitialisedCreateComponent _ -> [Cursor "grabbing"] + | _ -> [] + + let catTip1 name func (tip:string) = + let react = menuItem styles name func + div [ HTMLAttr.ClassName $"{Tooltip.ClassName} {Tooltip.IsMultiline}" + Tooltip.dataTooltip tip + Style styles + ] + [ react ] + Menu.menu [Props [Class "py-1"; Style styles]] [ + // TODO + makeMenuGroup + "Input / Output" + [ catTip1 "Input" (fun _ -> createIOPopup true "input" Input model dispatch) "Input connection to current sheet: one or more bits" + catTip1 "Output" (fun _ -> createIOPopup true "output" Output model dispatch) "Output connection from current sheet: one or more bits" + catTip1 "Viewer" (fun _ -> createIOPopup true "viewer" Viewer model dispatch) "Viewer to expose value in simulation: works in subsheets" + catTip1 "Constant" (fun _ -> createConstantPopup model dispatch) "Define a one or more bit constant value, \ + e.g. 0 or 1 to drive an unused input" + catTip1 "Wire Label" (fun _ -> createIOPopup false "label" (fun _ -> IOLabel) model dispatch) "Labels with the same name connect \ + together wires or busses"] + makeMenuGroup + "Buses" + [ catTip1 "MergeWires" (fun _ -> createComponent MergeWires "" model dispatch) "Use Mergewire when you want to \ + join the bits of a two busses to make a wider bus" + catTip1 "SplitWire" (fun _ -> createSplitWirePopup model dispatch) "Use Splitwire when you want to split the \ + bits of a bus into two sets" + catTip1 "Bus Select" (fun _ -> createBusSelectPopup model dispatch) "Bus Select output connects to one or \ + more selected bits of its input" + catTip1 "Bus Compare" (fun _ -> createBusComparePopup model dispatch) "Bus compare outputs 1 if the input bus \ + matches a constant value" ] + makeMenuGroup + "Gates" + [ catTip1 "Not" (fun _ -> createCompStdLabel Not model dispatch) "Invertor: output is negation of input" + catTip1 "And" (fun _ -> createCompStdLabel And model dispatch) "Output is 1 if both the two inputs are 1" + catTip1 "Or" (fun _ -> createCompStdLabel Or model dispatch) "Output is 1 if either of the two inputs are 1" + catTip1 "Xor" (fun _ -> createCompStdLabel Xor model dispatch) "Output is 1 if the two inputs have different values" + catTip1 "Nand" (fun _ -> createCompStdLabel Nand model dispatch) "Output is 0 if both the two inputs are 1" + catTip1 "Nor" (fun _ -> createCompStdLabel Nor model dispatch) "Output is 0 if either of the two inputs are 1" + catTip1 "Xnor" (fun _ -> createCompStdLabel Xnor model dispatch) "Output is 1 if the two inputs have the same values"] + makeMenuGroup + "Mux / Demux" + [ catTip1 "Mux2" (fun _ -> createCompStdLabel Mux2 model dispatch) "Selects the one of its two input busses numbered by the value of the select input + to be the output. Adjusts bus width to match." + catTip1 "Demux2" (fun _ -> createCompStdLabel Demux2 model dispatch) "The output is equal to the input, the other is 0" + catTip1 "Decode4" (fun _ -> createCompStdLabel Decode4 model dispatch) "The output numbered by the binary value + of the 2 bit sel input is equal to Data, the others are 0"] + makeMenuGroup + "Arithmetic" + [ catTip1 "N bits adder" (fun _ -> createNbitsAdderPopup model dispatch) "N bit Binary adder with carry in to bit 0 and carry out from bit N-1" + catTip1 "N bits XOR" (fun _ -> createNbitsXorPopup model dispatch) "N bit XOR gates - use to make subtractor or comparator"] + + makeMenuGroup + "Flip Flops and Registers" + [ catTip1 "D-flip-flop" (fun _ -> createCompStdLabel DFF model dispatch) "D flip-flop - note that clock is assumed always connected to a global clock, \ + so ripple counters cannot be implemented in Issie" + catTip1 "D-flip-flop with enable" (fun _ -> createCompStdLabel DFFE model dispatch) "D flip-flop: output will remain unchanged when En is 0" + catTip1 "Register" (fun _ -> createRegisterPopup Register model dispatch) "N D flip-flops with inputs and outputs combined into single N bit busses" + catTip1 "Register with enable" (fun _ -> createRegisterPopup RegisterE model dispatch) "As register but outputs stay the same if En is 0"] + makeMenuGroup + "Memories" + [ catTip1 "ROM (asynchronous)" (fun _ -> createMemoryPopup AsyncROM1 model dispatch) "This is combinational: \ + the output is available in the same clock cycle that the address is presented" + catTip1 "ROM (synchronous)" (fun _ -> createMemoryPopup ROM1 model dispatch) "A ROM whose output contains \ + the addressed data in the clock cycle after the address is presented" + catTip1 "RAM (synchronous)" (fun _ -> createMemoryPopup RAM1 model dispatch) "A RAM whose output contains the addressed \ + data in the clock cycle after the address is presented" + catTip1 "RAM (async read)" (fun _ -> createMemoryPopup AsyncRAM1 model dispatch) "A RAM whose output contains the addressed \ + data in the same clock cycle as address is presented" ] + + makeMenuGroupWithTip styles + "This project" + "Every design sheet is available for use in other sheets as a custom component: \ + it can be added any number of times, each instance replicating the sheet logic" + (makeCustomList styles model dispatch) + ] + + (viewCatOfModel) model diff --git a/src/Renderer/UI/CustomCompPorts.fs b/src/Renderer/UI/CustomCompPorts.fs new file mode 100644 index 0000000..eb67be7 --- /dev/null +++ b/src/Renderer/UI/CustomCompPorts.fs @@ -0,0 +1,578 @@ +module CustomCompPorts + +(* +This module provides some functions that ensure consistency of instantiated custom components when changes are +made to ports in the underlying sheet. A dialog is presented which allows instantiated components ports to +be updated correctly, with best efforts attempt to keep existing connections to each instance where ports remain +the same or where it can safely be deduced how ports have been renamed. + +The code potentially makes changes to every sheet in the project in the model, and writes out these changes to disk. +*) + +open Fulma +open Fable.React +open Fable.React.Props + +open Helpers +open ModelType +open CommonTypes +open FilesIO +open Extractor +open PopupView + + + +let printSheetNames (model:Model) = + model.CurrentProj + |> Option.map (fun p -> + printf $"SHEETS:{p.LoadedComponents |> List.map (fun ldc -> ldc.Name)}--->{p.OpenFileName}") + |> ignore + +//--------------------------------------------------------------------------------------------// +//--------------------------------------------------------------------------------------------// +//-------------------------------New-style project update and saving--------------------------// +//--------------------------------------------------------------------------------------------// + + + +/// Save any changed sheets to disk in the project directory +let syncLoadedComponentsToDisk newProj oldProj = + let needToSave ldc' ldc = + (not <| compareCanvas 10. ldc'.CanvasState ldc.CanvasState) || + ldc'.WaveInfo <> ldc.WaveInfo + let saveToDisk ldc = + let state = ldc.CanvasState + let waveInfo = ldc.WaveInfo + saveStateToFile newProj.ProjectPath ldc.Name (state,waveInfo) + |> ignore + removeFileWithExtn ".dgmauto" oldProj.ProjectPath ldc.Name + + let nameOf sheet (ldc:LoadedComponent) = ldc.Name = sheet + let oldLDCs = oldProj.LoadedComponents + let newLDCs = newProj.LoadedComponents + let sheets = List.distinct (List.map (fun ldc -> ldc.Name) (oldLDCs @ newLDCs)) + let sheetMap = + sheets + |> List.map (fun sheet -> sheet, (List.tryFind (nameOf sheet) newLDCs, List.tryFind (nameOf sheet) oldLDCs)) + |> Map.ofList + sheetMap + |> Map.iter (fun name (optLdcNew, optLdcOld) -> + match optLdcNew,optLdcOld with + | Some ldcNew, Some ldcOld when needToSave ldcNew ldcOld -> + saveToDisk ldcOld + | Some _, Some _ -> () + | None, Some ldcOld -> + removeFileWithExtn ".dgm" oldProj.ProjectPath ldcOld.Name + | Some ldcNew, None -> + saveToDisk ldcNew + | None, None -> failwithf "What? Can't happen") + +/// Return new model with project updated as per update function. +/// If p.LoadedComponents data is changed, for each sheet that is different +/// the sheet will be saved to disk. +/// This function should be used consistently to keep disk and project data +/// correct. +let updateProjectFiles (saveToDisk:bool) (update: Project -> Project) (model: Model) = + match model.CurrentProj with + | None -> model // do nothing in this case + | Some p -> + let p' = update p + if saveToDisk then + syncLoadedComponentsToDisk p' p // write out to disk as needed + {model with CurrentProj = Some p'} + +//--------------------------------------------------------------------------------------------// +//--------------------------------------------------------------------------------------------// +//-------------------------------Custom Component Management----------------------------------// +//--------------------------------------------------------------------------------------------// + + +// Basic idea. When the I/Os of the current sheet are changed this may affect instances of the sheet embedded in other +// project sheets. Check for this whenever current sheet is saved (which will happen when Issie exits or the +// edited sheet is changed). Offer, in a dialog, to change all of the affected custom component instances to maintain +// compatibility. This will usually break the other sheets. +// all of this code uses the project data structure and (if needed) returns an updated structure. + +type IODirection = InputIO | OutputIO + + + +type Match = { + MLabel: string + MWidth: int + MDir: IODirection + } + +type PortChange = { + Direction: IODirection + Old: (string * int) option + New: (string * int) option + Message: string + } + +/// Names and widths of ports, ordered. Input ports, Output ports. +type Signature = (string*int) list * (string*int) list + +let getIOMatchFromSig (inputs, outputs) = + + let makeSig dir (ios: (string * int) list) = + ios + |> List.map (fun (name,num) -> {MLabel = name; MWidth = num ; MDir = dir}) + (makeSig InputIO inputs) @ + (makeSig OutputIO outputs) + + + + + +/// compare two I/O signature lists +let ioCompareSigs (sig1: Signature) (sig2: Signature) = + let map (sg: Signature) = + getIOMatchFromSig sg + |> List.map (fun m -> (m.MDir, m.MLabel), m) + |> Map.ofList + + let ioMap1 = sig1 |> map + let ioMap2 = sig2 |> map + let ioMap = mapUnion ioMap1 ioMap2 + let set1,set2 = set (mapKeys ioMap1), set (mapKeys ioMap2) + let common = Set.intersect set1 set2 + let diff1 = set1 - set2 + let diff2 = set2 - set1 + mapKeys ioMap + |> Seq.map + (fun m -> + let getDetails m (ioMap: Map) = + let ma = Map.tryFind m ioMap + let labWidth = ma |> Option.map (fun m -> m.MLabel, m.MWidth) + labWidth + + let newLW = getDetails m ioMap1 + let oldLW = getDetails m ioMap2 + let message = + match newLW, oldLW with + | Some (l1,w1), Some (l2,w2) when l1=l2 && w1=w2 -> "No Change" + | Some (l1,_), Some (l2,_) when l1 = l2 -> "Port width changed" + | None, Some _ -> "Port and old connections deleted" + | Some _, None -> "New Port will be added" + | _ -> failwithf $"What? never happens: {newLW} {oldLW}" + { + Message = message + Direction = fst m + New = newLW + Old = oldLW + }) + +let guessAtRenamedPorts (matches: PortChange seq) : PortChange array = + let matches = Seq.toList matches + let portsByWidthFiltered (ports: ((string*int) * PortChange) list) = + ports + |> List.groupBy (fst >> snd) + |> List.collect (function |(width, [item]) -> [width,item] | _ -> [] ) + |> Map.ofList + + let additions = + matches + |> List.collect (function | {New = Some (name,width); Old = None; Direction = dir } as m -> [(name,width), m] | _ -> []) + |> portsByWidthFiltered + + let deletions = + matches + |> List.collect (function | {Old = Some (name,width); New = None; Direction = dir } as m -> [(name,width), m] | _ -> []) + |> portsByWidthFiltered + + let guessedRenames, deletedMatches = + Set.intersect (Set (mapKeys additions)) (Set (mapKeys deletions)) + |> Set.toList + |> List.map (fun n -> + { + New = Some (fst additions[n]) + Old = Some (fst deletions[n]) + Direction = (additions[n] |> snd).Direction + Message = "This appears to be a renamed port, connections will be kept" + }, [snd additions[n]; snd deletions[n]]) + |> List.unzip + + let deletedMatches = List.concat deletedMatches + // the final result + Set matches - Set deletedMatches + |> Set.union (Set guessedRenames) + |> Set.toArray + + + + + + +let findInstancesOfCurrentSheet (project:Project) = + let thisSheet = project.OpenFileName + let ldcs = project.LoadedComponents + let getInstance (comp:Component) = + match comp.Type with + | Custom ({Name=thisSheet} as cType) -> Some (ComponentId comp.Id, cType) + | _ -> None + + let getSheetInstances (ldc:LoadedComponent) = + fst ldc.CanvasState + |> List.choose getInstance + + ldcs + |> List.collect (fun ldc -> + getSheetInstances ldc + |> List.map (fun ins -> ldc.Name, ins)) + + +type Deps = + | NoDependents + | OneSig of ((string * int) list * (string * int) list) * (string * (ComponentId * CustomComponentType)) list + | Mixed of (string * int) list + +let getDependentsInfo (p: Project) = + let instances = findInstancesOfCurrentSheet p + let gps = + instances + |> List.groupBy (fun (_, (_,{InputLabels=ips; OutputLabels=ops})) -> (ips |> List.sort), (ops |> List.sort)) + |> List.sortByDescending (fun (tag,items) -> items.Length) + + match gps with + | [] -> NoDependents // no dependencies - nothing to do + | [sg, items] -> OneSig(sg, items) // normal case, all dependencies have same signature + | _ -> // dependencies have mixed signatures + instances + |> List.groupBy fst + |> List.map (fun (tag, lst) -> tag, lst.Length) + |> Mixed + +let makePortName (nameWidth :(string*int) option) = + match nameWidth with + | None -> "" + | Some (name,w) -> $"%s{name}({w-1}:{0})" + |> str + +/// returns IO signature of current sheet, and all its instances in other sheets +let getDependents (model:Model) = + mapOverProject None model <| fun p -> + printfn "depcheck2a" + let sheetName = p.OpenFileName + let newSig = + p.LoadedComponents + |> List.find (fun ldc -> ldc.Name = sheetName) + |> (fun ldc -> parseDiagramSignature ldc.CanvasState) + printfn "depcheck2b" + let instances = + p.LoadedComponents + |> List.filter (fun ldc -> ldc.Name <> sheetName) + |> List.collect (fun ldc -> + fst ldc.CanvasState + |> List.collect ( + function + | {Type = Custom { Name=name; InputLabels=ins; OutputLabels=outs} + Id = cid} when name = sheetName-> [ldc.Name, cid, (ins,outs)] + | _ -> [])) + printfn "depcheck2c" + Some(newSig, instances) + +let dependencyDoesNotMatchSignature newSig oldSig = + let sortLists (a,b) = a, b // we now require signature order to match + sortLists newSig <> sortLists oldSig + + +/// check whether any instance dependent on current sheet has different signature from current +let getOutOfDateDependents (model:Model) = + match getDependents model with + | None + | Some(_, []) -> None + | Some (newSig, (_,_,sg) :: _otherInstances) as deps when + dependencyDoesNotMatchSignature newSig sg-> deps + | _ -> None + + +/// Return canvasState updated with bad connections that have lost either of their connecting components deleted +let deleteIncompleteConnections ((comps,conns): CanvasState) = + let arrayOfIds (pL: Port list) = + Array.ofList pL + |> Array.map (fun p -> p.Id) + let okPorts = + Array.ofList comps + |> Array.collect (fun comp -> + Array.append (arrayOfIds comp.InputPorts) (arrayOfIds comp.OutputPorts)) + |> Set + let conns' = List.filter (fun (conn:Connection) -> + Set.contains conn.Source.Id okPorts && + Set.contains conn.Target.Id okPorts) conns + if conns <> conns' then + printfn "%d Connections deleted" (conns.Length - conns'.Length) + comps,conns' + +// Updating custom component instances changes the input and output port specifications. +// The CanvasState inside the custom component is always looked up from the corresponding sheet +// and not contained in the instance. +// Inputs and outputs ports have separate lists but work in the same way. A custom component instance +// is defined in TWO records: comp: Component and ct: CustomComponentType. +// ct = match comp.Type with | Custom ct -> ct (where for a custom component instance this match always succeeds) +// ct.InputLabels: (string * int) list -- associates an input port name with the port width. The position in the Inputlabels list is the port number +// comp.InputPorts: Port list -- input port list contains the input ports, each port record contains .PortNumber its number and .Id its (unique) id. +// Input port numbers are contiguous set of integers starting from 0. +// NB output port numbers are similar, thus a number does not uniquely identify a port on a component. +// Port names are likely to be unique but (maybe) do not have to be for the same reason. + +/// Change the items x in lst where uPred x with x -> uFunc x. +/// Useful to replace one item of a list +let listUpdate (uPred: 'a -> bool) (uFunc: 'a -> 'a) (lst: 'a list) = + lst + |> List.map (fun item -> if uPred item then uFunc item else item) + +type PortInfo = (string * int) list * Port list + +/// Return updated custom component with ports changed as per change +/// If a port is deleted any corresponding connections must be deleted +/// to keep the CanvasState consistent. That is done elsewhere, since +/// deleting not fully connected connections is a straightforward operation +/// on CanvasState, as done by deleteIncompleteConnections +let changeInstance (comp:Component) (change: PortChange) = + + let updateInfo (dir: IODirection) (f: PortInfo -> PortInfo) (comp: Component)= + match dir with + | InputIO -> + let labels,ct = + match comp.Type with + | Custom ct -> ct.InputLabels,ct + | cType -> failwithf $"What? '{cType}' not allowed" + let ports = comp.InputPorts + let (labels,ports) = f (labels,ports) + {comp with InputPorts = ports; Type = Custom {ct with InputLabels = labels }} + | OutputIO -> + let labels,ct = + match comp.Type with + | Custom ct -> ct.OutputLabels,ct + | cType -> failwithf $"What? '{cType}' not allowed" + let ports = comp.OutputPorts + let (labels, ports) = f (labels,ports) + {comp with OutputPorts = ports; Type = Custom {ct with OutputLabels = labels }} + + /// To change a port width only InputLabels (or OutputLabels) need change + let changePortWidth (dir: IODirection) (name: string) (newWidth:int) (comp: Component) = + let upf = fun (labels,ports) -> + listUpdate (fun (s,_) -> s = name) (fun (s,_) -> (s,newWidth)) labels, ports + updateInfo dir upf comp + + /// To rename a port width only InputLabels (or OutputLabels) need change + let changePortName (dir: IODirection) (newName: string) (oldName:string) (comp: Component) = + let upf = fun (labels,ports) -> + listUpdate (fun (s,_) -> s = oldName) (fun (_,w) -> (newName,w)) labels, ports + updateInfo dir upf comp + + /// To add a port we add it to both lists, creating a new Port record with unique id, and using the next available port number + let addPort (dir: IODirection) (name:string) (width:int) (comp:Component) = + let upf = fun ((labels,ports):PortInfo) -> + let labels = labels @ [name,width] + let newPort:Port = + { + Id = JSHelpers.uuid () + PortNumber = Some ports.Length // next available number + HostId = comp.Id + PortType = match dir with | InputIO -> PortType.Input | OutputIO -> PortType.Output + } + let ports = ports @ [newPort] + labels,ports + updateInfo dir upf comp + + /// To delete a port we remove it from both lists but also must renumber all of the port records to keep numbers aligned + let deletePort (dir: IODirection) (name:string) (comp:Component) = + let upf = fun ((labels,ports):PortInfo) -> + // first get the port number of the label we will delete + let portNum = List.findIndex (fun (s,_) -> s = name) labels + // delete the label we do not want + let labels = List.filter (fun (s,_) -> s <> name) labels + // renumber the ports contiguously, preserving order + let ports = + List.filter (fun (port:Port) -> port.PortNumber <> Some portNum) ports + |> List.sortBy (fun port -> port.PortNumber) + |> List.mapi (fun i port -> {port with PortNumber = Some i}) + printfn $"deleteport:{labels.Length},{ports.Length}" + labels,ports + updateInfo dir upf comp + + let dir = change.Direction + match change.New, change.Old with + | x,y when x = y -> + comp // no change in this case + | Some (newName,width'), Some(oldName,width) when width'=width -> + // a guessed rename operation + changePortName dir newName oldName comp + | Some(name',newWidth), Some (name,oldWidth) when name=name' -> + changePortWidth dir name newWidth comp + | Some newC, Some oldC -> + failwithf $"What? Change with new={newC} and old = {oldC} should not be possible" + | Some(name,width), None -> + addPort dir name width comp + | None, Some(name,width) -> + deletePort dir name comp + | newC, oldC -> + failwithf $"What? Change with new={newC} and old = {oldC} should not be possible" + +/// Make changes to ccomponent cid on sheet converting old ports oldSig to new ports newSig +let updateInstance (newSig: Signature) (sheet:string,cid:string,oldSig:Signature) (p: Project) = + /// Assume that name and bit number changes have been made. Deal with any needed reordering. + let reorderInstancePorts (newSig: Signature) (comp: Component) = + let reorderPorts newNames oldNames (oldPorts: Port list) = + newNames + |> List.map (fun (name,_) -> List.findIndex (fun (name',_) -> name'=name) oldNames) + |> List.map (fun n -> oldPorts[n]) + |> List.mapi (fun i p -> {p with PortNumber = Some i}) + match comp.Type with + | Custom ct -> + if oldSig = newSig then + printfn "Order matches!" + comp + elif mapPair List.sort newSig = mapPair List.sort oldSig then + printfn $"Reordering {comp.Label}" + let oldSig = ct.InputLabels, ct.OutputLabels + let newIn,newOut = newSig + let oldIn,oldOut = oldSig + let newInPorts = reorderPorts newIn oldIn comp.InputPorts + let newOutPorts = reorderPorts newOut oldOut comp.OutputPorts + let ct' = {ct with InputLabels = fst newSig; OutputLabels = snd newSig} + {comp with Type = Custom ct'; InputPorts=newInPorts; OutputPorts=newOutPorts} + + else + printfn "What? Signatures do not match after changes are made" + comp + | _ -> comp // no change (should never happen?) +#if ASSERTS + assertThat + (sheet <> p.OpenFileName) + $"What? Instances to be changed in {sheet} must not be in custom \ + component sheet{p.OpenFileName}" +#endif + let ldc = + p.LoadedComponents + |> List.find (fun ldc -> ldc.Name = sheet) + let (comps,conns) = ldc.CanvasState + let comp = + comps |> List.find (fun comp -> comp.Id = cid) + let changes = + ioCompareSigs newSig oldSig + |> guessAtRenamedPorts + let comp' = + (comp, changes) + ||> Array.fold (fun comp change -> + let comp'' = changeInstance comp change + comp'' + ) + |> reorderInstancePorts newSig + let comps' = + comps + |> List.map (fun comp -> if comp.Id = cid then comp' else comp) + let ldc' = {ldc with CanvasState = deleteIncompleteConnections (comps',conns)} + let ldcLst = ldc' :: List.except [ldc] p.LoadedComponents + {p with LoadedComponents = ldcLst} + + + +/// dispatch message to change project in model, returning project +let updateDependents (newSig: Signature) (instances:(string*string*Signature) list) model dispatch = + match model.CurrentProj with + | None -> None + | Some p -> + (p,instances) + ||> List.fold (fun p instance -> updateInstance newSig instance p) + |> (fun p -> + dispatch <| SetProject p + Some p) + +let checkCanvasStateIsOk (model:Model) = + mapOverProject false model (fun p -> + let ldc = List.find (fun ldc -> ldc.Name = p.OpenFileName) p.LoadedComponents + let comps,conns = ldc.CanvasState + let ioNames = + comps + |> List.filter (fun comp -> match comp.Type with | Input _ | Output _ -> true | _ -> false) + |> List.map (fun comp -> comp.Label) + ioNames.Length = (List.distinct ioNames).Length + ) + +/// returns a popup function to show the dependents update dialog if this is needed +/// this dialog drives all subsequent work changing custom component instances +let optCurrentSheetDependentsPopup (model: Model) = + printfn "depcheck1" + let sheet = model.CurrentProj |> Option.map (fun p -> p.OpenFileName) + if not <| checkCanvasStateIsOk model then + None // do nothing if IOs are not currently valid. Can this ever happen? + else + printfn "depcheck2" + match getOutOfDateDependents model with + | None -> None + | Some (newSig, (((firstSheet,firstCid,firstSig) :: rest) as instances)) -> + let depSheets = + instances + |> List.map (fun (sheet,_,_) -> sheet) + |> List.distinct + |> String.concat "," + let changes = + ioCompareSigs newSig firstSig + |> guessAtRenamedPorts + let whatChanged = + match changes |> Array.exists (fun ch -> ch.Old <> ch.New) with + | false -> "the vertical order of inputs or outputs" + | true -> "the inputs or outputs" + let headCell heading = th [ ] [ str heading ] + let makeRow (change:PortChange) = + tr [] + [ + + td [] [str (if change.Direction = InputIO then "Input" else "Output")] + td [] [makePortName change.New] + td [] [makePortName change.Old] + td [] [str change.Message] + ] + let body = + div [Style [ MarginTop "15px" ] ] + [ + Heading.h5 [ Heading.Props [ Style [ MarginTop "15px" ] ] ] [str $"{sheet}"] + str $"You have changed the {whatChanged} of the current '{sheet}' sheet. " + br [] + str "This dialog will automatically update all dependent sheets to match this. " + br [] + str $"The '{sheet}' sheet is instantiated as a symbol {instances.Length} times in dependent sheets: '{depSheets}'. " + str $"If you do not automatically update the symbols you will need to delete and recreate each one." + br [] + str "If you automatically update symbols wires that no longer match will be autorouted correctly when you next load each sheet" + br [] + Table.table [ + Table.IsHoverable + Table.IsBordered + Table.IsNarrow + Table.Props [Style [ MarginTop "15px" ]]] + [ + thead [] [ tr [] (List.map headCell ["Type" ;"New port"; "Old port" ; "Change"]) ] + tbody [] (Array.map makeRow changes) + ] + ] + + let buttonAction isUpdate dispatch _ = + if isUpdate then + updateDependents newSig instances model dispatch + |> Option.map saveAllProjectFilesFromLoadedComponentsToDisk + |> ignore + dispatch <| ClosePopup + choicePopupFunc + "Update All Sheet Instances" + (fun _ -> body) + "Update all instances" + "Save the sheet without updating instances" + buttonAction + |> Some + + + | _ -> failwithf "What? Impossible" + + + + + + + + + + diff --git a/src/Renderer/UI/FileMenuView.fs b/src/Renderer/UI/FileMenuView.fs new file mode 100644 index 0000000..2ba0f64 --- /dev/null +++ b/src/Renderer/UI/FileMenuView.fs @@ -0,0 +1,1024 @@ +(* + FileMenuView.fs + + View for the top menu, and related functionalities: renamimg, loadimg, saving, deleting sheets +*) + +module FileMenuView + +open Fulma +open Fable.React +open Fable.React.Props + +open Helpers +open JSHelpers +open DiagramStyle +open ModelType +open CommonTypes +open FilesIO +open Extractor +open Notifications +open PopupView +open CustomCompPorts +open System +//--------------------------------------------------------------------------------------------// +//--------------------------------------------------------------------------------------------// +//---------------------Code for CanvasState comparison and FILE BACKUP------------------------// +//--------------------------------------------------------------------------------------------// + +/// Works out number of components and connections changed between two LoadedComponent circuits +/// a new ID => a change even if the circuit topology is identical. Layout differences do not +/// mean changes, as is implemented in the reduce functions which remove layout. +let quantifyChanges (ldc1:LoadedComponent) (ldc2:LoadedComponent) = + let comps1,conns1 = ldc1.CanvasState + let comps2,conns2 = ldc2.CanvasState + let reduceComp comp1 = + {comp1 with X=0;Y=0} + let reduceConn conn1 = + {conn1 with Vertices = []} + /// Counts the number of unequal items in the two lists. + /// Determine equality from whether reduce applied to each item is equal + let unmatched reduce lst1 lst2 = + let mapToSet = List.map reduce >> Set + let rL1, rL2 = mapToSet lst1, mapToSet lst2 + Set.union (Set.difference rL1 rL2) (Set.difference rL2 rL1) + |> Set.count + unmatched reduceComp comps1 comps2, unmatched reduceConn conns1 conns2 + +////------------------------------------------Backup facility-------------------------------------------// + +let writeComponentToFile comp = + let data = stateToJsonString (comp.CanvasState,comp.WaveInfo) + writeFile comp.FilePath data + +/// return an option containing sequence data and file name and directory of the latest +/// backup file for given component, if it exists. +let readLastBackup comp = + let path = pathWithoutExtension comp.FilePath + let baseN = baseName path + let backupDir = pathJoin [| dirName path ; "backup" |] + latestBackupFileData backupDir baseN + |> Option.map (fun (seq, fName) -> seq, fName, backupDir) + +/// Write Loadedcomponent comp to a backup file if there has been any change. +/// Overwrite the existing backup file only if it is a small, and recent, change. +/// Parameters determine thresholds of smallness and recency +/// return () - display an error if the write goes wrong. +let writeComponentToBackupFile (numCircuitChanges: int) (numHours:float) comp (dispatch: Msg -> Unit)= + let nSeq, backupFileName, backFilePath = + match readLastBackup comp with + | Some( n, fp, path) -> n+1,fp, path + | None -> 0, "", pathJoin [|comp.FilePath; "backup"|] + //printfn "seq=%d,name=%s,path=%s" nSeq backupFileName backFilePath + let wantToWrite, oldFile = + if backupFileName = "" then + true, None + else + let oldBackupFile = pathJoin [|backFilePath ; backupFileName|] + match tryLoadComponentFromPath (oldBackupFile) with + | Ok comp' -> + if not (compareIOs comp comp') then + true, None // need to save, to a new backup file + elif compareCanvas 10000. comp.CanvasState comp'.CanvasState then + false, None // no need for a new backup + else + let nComps,nConns = quantifyChanges comp' comp + let interval = comp.TimeStamp - comp'.TimeStamp + if interval.TotalHours > numHours || nComps + nConns > numCircuitChanges then + true, None + else + true, Some oldBackupFile + + | err -> + printfn "Error: writeComponentToBackup\n%A" err + true, None + if wantToWrite then + let timestamp = System.DateTime.Now + let backupPath = + // work out new path to write based on time. + let path = pathWithoutExtension comp.FilePath + let baseN = baseName path + let ds = EEExtensions.String.replaceChar '/' '-' (timestamp.ToShortDateString()) + let suffix = EEExtensions.String.replaceChar ' ' '-' (sprintf "%s-%02dh-%02dm" ds timestamp.Hour timestamp.Minute) + let backupDir = pathJoin [| dirName path ; "backup" |] + ensureDirectory <| pathJoin [| dirName path ; "backup" |] + pathJoin [| dirName path ; "backup" ; sprintf "%s-%03d-%s.dgm" baseN nSeq suffix |] + // write the new backup file + {comp with + TimeStamp = timestamp + FilePath = backupPath} + |> writeComponentToFile + |> displayAlertOnError dispatch + // if necessary delete the old backup file + match oldFile with + | Some oldPath when oldPath <> backupPath -> + if Node.Api.fs.existsSync (Fable.Core.U2.Case1 oldPath) then + Node.Api.fs.unlink (Fable.Core.U2.Case1 oldPath, ignore) // Asynchronous. + else + () + | _ -> () + +/// returns a WaveSimModel option if a file is loaded, otherwise None +let currWaveSimModel (model: Model) = + match getCurrFile model with + | Some fileName when Map.containsKey fileName (fst model.WaveSim) -> Some ((fst model.WaveSim)[fileName]) + | _ -> None + +let private displayFileErrorNotification err dispatch = + let note = errorFilesNotification err + dispatch <| SetFilesNotification note + +/// Send messages to change Diagram Canvas and specified sheet waveSim in model +let private loadStateIntoModel (compToSetup:LoadedComponent) waveSim ldComps model dispatch = + // it seems still need this, however code has been deleted! + //Sheet.checkForTopMenu () // A bit hacky, but need to call this once after everything has loaded to compensate mouse coordinates. + + let name = compToSetup.Name + let components, connections = compToSetup.CanvasState + //printfn "Loading..." + let msgs = + [ + SetHighlighted([], []) // Remove current highlights. + + // Clear the canvas. + Sheet Sheet.ResetModel + Sheet (Sheet.Wire BusWire.ResetModel) + Sheet (Sheet.Wire (BusWire.Symbol (Symbol.ResetModel ) ) ) + + // Finally load the new state in the canvas. + SetIsLoading true + //printfn "Check 1..." + + //Load components + Sheet (Sheet.Wire (BusWire.Symbol (Symbol.LoadComponents components ))) + Sheet Sheet.UpdateBoundingBoxes + + Sheet (Sheet.Wire (BusWire.LoadConnections connections)) + + Sheet Sheet.FlushCommandStack // Discard all undo/redo. + // Run the a connection widths inference. + //printfn "Check 4..." + + Sheet (Sheet.Wire (BusWire.BusWidths)) + // JSdispatch <| InferWidths() + //printfn "Check 5..." + // Set no unsaved changes. + + + JSDiagramMsg (SetHasUnsavedChanges false) + // set waveSim data + SetWaveSimModel(name, waveSim) + ( + { + ProjectPath = dirName compToSetup.FilePath + OpenFileName = compToSetup.Name + LoadedComponents = ldComps + } + |> SetProject) // this message actually changes the project in model + SetWaveSimIsOutOfDate true + SetIsLoading false + + //printfn "Check 6..." + ] + + //INFO - Currently the spinner will ALWAYS load after 'SetTopMenu x', probably it is the last command in a chain + //Ideally it should happen before this, but it is not currently doing this despite the async call + //This will set a spinner for both Open project and Change sheet which are the two most lengthly processes + dispatch <| (Sheet (Sheet.SetSpinner true)) + dispatch <| SendSeqMsgAsynch msgs + +/// Return LoadedComponents with sheet name updated according to setFun. +/// Do not update model. +let updateLoadedComponents name (setFun: LoadedComponent -> LoadedComponent) (lcLst: LoadedComponent list) (dispatch: (Msg -> Unit))= + let n = List.tryFindIndex (fun (lc: LoadedComponent) -> lc.Name = name) lcLst + match n with + | None -> + printf "In updateLoadedcomponents can't find name='%s' in components:%A" name lcLst + lcLst + | Some n -> + let oldLc = lcLst[n] + let newLc = setFun oldLc + writeComponentToBackupFile 0 1. oldLc dispatch + List.mapi (fun i x -> if i = n then newLc else x) lcLst + +/// return current project with current sheet updated from canvas if needed. +/// Do not update model. +let updateProjectFromCanvas (model:Model) (dispatch:Msg -> Unit) = + match model.Sheet.GetCanvasState() with + | ([], []) -> model.CurrentProj + | canvasState -> + canvasState + |> fun canvas -> + let inputs, outputs = parseDiagramSignature canvas + let setLc lc = + { lc with + CanvasState = canvas + InputLabels = inputs + OutputLabels = outputs + } + model.CurrentProj + |> Option.map (fun p -> + { + p with LoadedComponents = updateLoadedComponents p.OpenFileName setLc p.LoadedComponents dispatch + }) + + +/// extract SavedwaveInfo from model to be saved +let getSavedWave (model:Model) : SavedWaveInfo option = + match currWaveSimModel model with + | Some wSModel -> waveSimModel2SavedWaveInfo wSModel |> Some + | None -> None + +/// add waveInfo to model +let setSavedWave compIds (wave: SavedWaveInfo option) model : Model = + match wave, getCurrFile model with + | None, _ -> model + | Some waveInfo, Some fileName -> + { model with WaveSim = Map.add fileName (savedWaveInfo2WaveSimModel waveInfo) + (fst model.WaveSim), + snd model.WaveSim } + | Some waveInfo, _ -> model + +/// Save the sheet currently open, return the new sheet's Loadedcomponent if this has changed. +/// Do not change model. +/// update Symbol model with new RAM contents. +let saveOpenFileAction isAuto model (dispatch: Msg -> Unit)= + match model.Sheet.GetCanvasState (), model.CurrentProj with + | _, None -> None + | canvasState, Some project -> + // "DEBUG: Saving Sheet" + // printfn "DEBUG: %A" project.ProjectPath + // printfn "DEBUG: %A" project.OpenFileName + + let savedState = canvasState, getSavedWave model + if isAuto then + failwithf "Auto saving is no longer used" + None + else + saveStateToFile project.ProjectPath project.OpenFileName savedState + |> displayAlertOnError dispatch + removeFileWithExtn ".dgmauto" project.ProjectPath project.OpenFileName + let origLdComp = + project.LoadedComponents + |> List.find (fun lc -> lc.Name = project.OpenFileName) + let savedWaveSim = + Map.tryFind project.OpenFileName (fst model.WaveSim) + |> Option.map waveSimModel2SavedWaveInfo + let (newLdc, ramCheck) = makeLoadedComponentFromCanvasData canvasState origLdComp.FilePath DateTime.Now savedWaveSim + let newState = + canvasState + |> (fun (comps, conns) -> + comps + |> List.map (fun comp -> + match List.tryFind (fun (c:Component) -> c.Id=comp.Id) ramCheck with + | Some newRam -> + // TODO: create consistent helpers for messages + dispatch <| Sheet (Sheet.Wire (BusWire.Symbol (Symbol.WriteMemoryType (ComponentId comp.Id, newRam.Type)))) + newRam + | _ -> comp), conns) + writeComponentToBackupFile 4 1. newLdc dispatch + Some (newLdc,newState) + +/// save current open file, updating model etc, and returning the loaded component and the saved (unreduced) canvas state +let saveOpenFileActionWithModelUpdate (model: Model) (dispatch: Msg -> Unit) = + let opt = saveOpenFileAction false model dispatch + let ldcOpt = Option.map fst opt + let state = Option.map snd opt |> Option.defaultValue ([],[]) + match model.CurrentProj with + | None -> failwithf "What? Should never be able to save sheet when project=None" + | Some p -> + // update loaded components for saved file + updateLdCompsWithCompOpt ldcOpt p.LoadedComponents + |> (fun lc -> {p with LoadedComponents=lc}) + |> SetProject + |> dispatch + + SetHasUnsavedChanges false + |> JSDiagramMsg + |> dispatch + dispatch FinishUICmd + opt + +let private getFileInProject name project = project.LoadedComponents |> List.tryFind (fun comp -> comp.Name = name) + +let private isFileInProject name project = + getFileInProject name project + |> function + | None -> false + | Some _ -> true + +/// Create a new empty .dgm file and return corresponding loaded component. +let private createEmptyDiagramFile projectPath name = + createEmptyDgmFile projectPath name |> ignore + + { + Name = name + TimeStamp = System.DateTime.Now + WaveInfo = None + FilePath = pathJoin [| projectPath; name + ".dgm" |] + CanvasState = [],[] + InputLabels = [] + OutputLabels = [] + } + + +let createEmptyComponentAndFile (pPath:string) (sheetName: string): LoadedComponent = + createEmptyDgmFile pPath sheetName |> ignore + { + Name=sheetName + WaveInfo = None + TimeStamp = DateTime.Now + FilePath= pathJoin [|pPath; sprintf "%s.dgm" sheetName|] + CanvasState=([],[]) + InputLabels = [] + OutputLabels = [] + } + + +/// Load a new project as defined by parameters. +/// Ends any existing simulation +/// Closes WaveSim if this is being used +let setupProjectFromComponents (sheetName: string) (ldComps: LoadedComponent list) (model: Model) (dispatch: Msg->Unit)= + let compToSetup = + match ldComps with + | [] -> failwithf "setupProjectComponents must be called with at least one LoadedComponent" + | comps -> + // load sheetName + match comps |> List.tryFind (fun comp -> comp.Name = sheetName) with + | None -> failwithf "What? can't find sheet %s in loaded sheets %A" sheetName (comps |> List.map (fun c -> c.Name)) + | Some comp -> comp + match model.CurrentProj with + | None -> () + | Some p -> + dispatch EndSimulation // Message ends any running simulation. + // TODO: make each sheet wavesim remember the list of waveforms. + let waveSim = + compToSetup.WaveInfo + |> Option.map savedWaveInfo2WaveSimModel + |> Option.defaultValue (ModelType.initWS [||] Map.empty) + + // TODO + loadStateIntoModel compToSetup waveSim ldComps model dispatch + { + ProjectPath = dirName compToSetup.FilePath + OpenFileName = compToSetup.Name + LoadedComponents = ldComps + } + |> SetProject // this message actually changes the project in model + |> dispatch + +/// Open the specified file, saving the current file if needed. +/// Creates messages sufficient to do all necessary model and diagram change +/// Terminates a simulation if one is running +/// Closes waveadder if it is open +let private openFileInProject' saveCurrent name project (model:Model) dispatch = + printfn "open file" + printSheetNames model + let newModel = {model with CurrentProj = Some project} + printSheetNames newModel + match getFileInProject name project with + | None -> + log <| sprintf "Warning: openFileInProject could not find the component %s in the project" name + | Some lc -> + match updateProjectFromCanvas model dispatch with + | None -> failwithf "What? current project cannot be None at this point in openFileInProject" + | Some p -> + let updatedModel = {newModel with CurrentProj = Some p} + printSheetNames updatedModel + let ldcs = + if saveCurrent then + let opt = saveOpenFileAction false updatedModel dispatch + let ldcOpt = Option.map fst opt + let ldComps = updateLdCompsWithCompOpt ldcOpt project.LoadedComponents + ldComps + else + project.LoadedComponents + printSheetNames {newModel with CurrentProj = Some {Option.get newModel.CurrentProj with LoadedComponents = ldcs }} + setupProjectFromComponents name ldcs updatedModel dispatch + +let openFileInProject name project (model:Model) dispatch = + openFileInProject' true name project (model:Model) dispatch + dispatch FinishUICmd + + +/// return a react warning message if name if not valid for a sheet Add or Rename, or else None +let maybeWarning dialogText project = + let redText txt = Some <| div [ Style [ Color "red" ] ] [ str txt ] + if isFileInProject dialogText project then + redText "This sheet already exists." + elif dialogText.StartsWith " " || dialogText.EndsWith " " then + redText "The sheet name cannot start or end with a space." + elif String.exists ((=) '.') dialogText then + redText "The sheet name cannot contain a file suffix." + elif not <| String.forall (fun c -> Char.IsLetterOrDigit c || c = ' ' || c = '_') dialogText then + redText "The sheet name must contain only letters, digits, spaces or underscores" + elif ((dialogText |> Seq.tryItem 0) |> Option.map Char.IsDigit) = Some true then + redText "The name must not start with a digit" + else None + + +/// rename a sheet +let renameSheet oldName newName (model:Model) dispatch = + + let renameComps oldName newName (comps:Component list) : Component list = + comps + |> List.map (fun comp -> + match comp with + | {Type= Custom ({Name = compName} as customType)} when compName = oldName-> + {comp with Type = Custom {customType with Name = newName} } + | c -> c) + + let renameCustomComponents newName (ldComp:LoadedComponent) = + let state = ldComp.CanvasState + {ldComp with CanvasState = renameComps oldName newName (fst state), snd state} + + let renameSheetsInProject oldName newName proj = + {proj with + OpenFileName = if proj.OpenFileName = oldName then newName else proj.OpenFileName + LoadedComponents = + proj.LoadedComponents + |> List.map (fun ldComp -> + match ldComp with + | {Name = lcName} when lcName = oldName -> + {ldComp with Name=newName; FilePath = pathJoin [|(dirName ldComp.FilePath);newName + ".dgm"|] } + | _ -> + renameCustomComponents newName ldComp ) + } + match updateProjectFromCanvas model dispatch with + | None -> + failwithf "What? current project cannot be None at this point in renamesheet" + | Some p -> + let updatedModel = {model with CurrentProj = Some p} + let opt = saveOpenFileAction false updatedModel dispatch + let ldcOpt = Option.map fst opt + let ldComps = updateLdCompsWithCompOpt ldcOpt p.LoadedComponents + let reducedState = Option.map snd opt |> Option.defaultValue ([],[]) + //SetHasUnsavedChanges false + //|> JSDiagramMsg + //|> dispatch + [".dgm"] |> List.iter (fun extn -> + renameFile extn p.ProjectPath oldName newName + |> displayAlertOnError dispatch) + let proj' = renameSheetsInProject oldName newName p + setupProjectFromComponents proj'.OpenFileName proj'.LoadedComponents model dispatch + printfn "???Sheets after rename" + printSheetNames {model with CurrentProj = Some proj'} + // save all the other files + saveAllProjectFilesFromLoadedComponentsToDisk proj' + dispatch FinishUICmd + + +/// rename file +let renameFileInProject name project model dispatch = + match model.CurrentProj, getCurrentWSMod model with + | None,_ -> log "Warning: renameFileInProject called when no project is currently open" + | Some project, Some ws when ws.WSViewState<>WSClosed -> + displayFileErrorNotification "Sorry, you must close the wave simulator before renaming design sheets!" dispatch + switchToWaveEditor model dispatch + | Some project, _ -> + // Prepare dialog popup. + let title = "Rename sheet in project" + + let before = + fun (dialogData: PopupDialogData) -> + let dialogText = getText dialogData + + div [] + [ + str <| "Warning: the current sheet will be saved during this operation." + br [] + str <| "Names of existing components in other sheets that use the renamed sheet will still reflect the old sheet name."; + str <| " You may change names manually if you wish, operation does not depend on the name." + br []; br [] + str <| sprintf "Sheet %s will be renamed as %s:" name dialogText + br []; br [] + //str <| dialogText + ".dgm" + Option.defaultValue (div [] []) (maybeWarning dialogText project)] + + let placeholder = "New name for design sheet" + let body = dialogPopupBodyOnlyText before placeholder dispatch + let buttonText = "Rename" + + let buttonAction = + fun (dialogData: PopupDialogData) -> + // Create empty file. + let newName = (getText dialogData).ToLower() + // rename the file in the project. + dispatch(ExecFuncInMessage(renameSheet name newName, dispatch)) + dispatch ClosePopup + + let isDisabled = + fun (dialogData: PopupDialogData) -> + let dialogText = getText dialogData + (isFileInProject dialogText project) || (dialogText = "") + + dialogPopup title body buttonText buttonAction isDisabled dispatch + + + +/// Remove file. +let private removeFileInProject name project model dispatch = + match getCurrentWSMod model with + | Some ws when ws.WSViewState<>WSClosed -> + displayFileErrorNotification "Sorry, you must close the wave simulator before removing design sheets!" dispatch + switchToWaveEditor model dispatch + | _ -> + + removeFile project.ProjectPath name + // Remove the file from the dependencies and update project. + let newComponents = List.filter (fun (lc: LoadedComponent) -> lc.Name.ToLower() <> name.ToLower()) project.LoadedComponents + // Make sure there is at least one file in the project. + let project' = {project with LoadedComponents = newComponents} + match newComponents, name = project.OpenFileName with + | [],true -> + // reate a new empty file with default name main as sole file in project + let newComponents = [ (createEmptyDiagramFile project.ProjectPath "main") ] + let project' = {project' with LoadedComponents = newComponents; OpenFileName="main"} + openFileInProject' false newComponents[0].Name project' model dispatch + | [], false -> + failwithf "What? - this cannot happen" + | nc, true -> + // open one of the undeleted loadedcomponents + printfn $"remove sheet '{name}'" + printSheetNames {model with CurrentProj = Some project'} + openFileInProject' false project'.LoadedComponents[0].Name project' model dispatch + | nc, false -> + // nothing chnages except LoadedComponents + printfn $"remove sheet '{name}'" + printSheetNames {model with CurrentProj = Some project'} + //dispatch <| SetProject project' + dispatch FinishUICmd + + + +/// Create a new file in this project and open it automatically. +let addFileToProject model dispatch = + match model.CurrentProj with + | None -> log "Warning: addFileToProject called when no project is currently open" + | Some project -> + // Prepare dialog popup. + let title = "Add sheet to project" + + let before = + fun (dialogData: PopupDialogData) -> + let dialogText = getText dialogData + let warn = maybeWarning dialogText project + div [] + [ str "A new sheet will be created at:" + br [] + str <| pathJoin + [| project.ProjectPath + dialogText + ".dgm" |] + Option.defaultValue (div [] []) warn ] + + let placeholder = "Insert design sheet name" + let body = dialogPopupBodyOnlyText before placeholder dispatch + let buttonText = "Add" + let buttonAction = + fun (dialogData: PopupDialogData) -> + // Create empty file. + let name = (getText dialogData).ToLower() + createEmptyDgmFile project.ProjectPath name + |> displayAlertOnError dispatch + // Add the file to the project. + let newComponent = { + Name = name + TimeStamp = System.DateTime.Now + WaveInfo = None + FilePath = pathJoin [|project.ProjectPath; name + ".dgm"|] + CanvasState = [],[] + InputLabels = [] + OutputLabels = [] + } + let updatedProject = + { project with + LoadedComponents = newComponent :: project.LoadedComponents + OpenFileName = name } + + // Open the file, updating the project, saving current file + openFileInProject' true name updatedProject model dispatch + // Close the popup. + dispatch ClosePopup + dispatch FinishUICmd + + let isDisabled = + fun (dialogData: PopupDialogData) -> + let dialogText = getText dialogData + (isFileInProject dialogText project) || (dialogText = "") || (maybeWarning dialogText project <> None) + + dialogPopup title body buttonText buttonAction isDisabled dispatch + +/// Close current project, if any. +let forceCloseProject model dispatch = + dispatch (StartUICmd CloseProject) + let sheetDispatch sMsg = dispatch (Sheet sMsg) + dispatch EndSimulation // End any running simulation. + model.Sheet.ClearCanvas sheetDispatch + dispatch FinishUICmd + + + +/// force either save of current file before action, or abort (closeProject is special case of this) +let doActionWithSaveFileDialog (name: string) (nextAction: Msg) model dispatch _ = + let closeDialogButtons keepOpen _ = + if keepOpen then + dispatch ClosePopup + else + dispatch nextAction + + if model.SavedSheetIsOutOfDate then + choicePopup + $"{name}?" + (div [] [ str "The current sheet has unsaved changes."]) + "Go back to sheet" + $"{name} without saving changes" + closeDialogButtons + dispatch + else + dispatch nextAction + +/// Create a new project. +let private newProject model dispatch = + match askForNewProjectPath() with + | None -> () // User gave no path. + | Some path -> + match tryCreateFolder path with + | Error err -> + log err + displayFileErrorNotification err dispatch + | Ok _ -> + dispatch EndSimulation // End any running simulation. + // Create empty placeholder projectFile. + let projectFile = baseName path + ".dprj" + writeFile (pathJoin [| path; projectFile |]) "" + |> displayAlertOnError dispatch + // Create empty initial diagram file. + let initialComponent = createEmptyComponentAndFile path "main" + setupProjectFromComponents "main" [initialComponent] model dispatch + + + + + + + + + + +/// work out what to do opening a file +let rec resolveComponentOpenPopup + (pPath:string) + (components: LoadedComponent list) + (resolves: LoadStatus list) + (model: Model) + (dispatch: Msg -> Unit) = + let chooseWhichToOpen comps = + (List.maxBy (fun comp -> comp.TimeStamp) comps).Name + dispatch ClosePopup + match resolves with + | [] -> setupProjectFromComponents (chooseWhichToOpen components) components model dispatch + | Resolve (ldComp,autoComp) :: rLst -> + // ldComp, autocomp are from attemps to load saved file and its autosave version. + let compChanges, connChanges = quantifyChanges ldComp autoComp + let buttonAction autoSave _ = + let comp = {(if autoSave then autoComp else ldComp) with TimeStamp = DateTime.Now} + writeComponentToFile comp + |> displayAlertOnError dispatch + if compChanges + connChanges > 0 then + writeComponentToBackupFile 0 1. comp dispatch + resolveComponentOpenPopup pPath (comp :: components) rLst model dispatch + // special case when autosave data is most recent + let title = "Warning!" + let message, color = + match compChanges + connChanges with + | 0 -> + sprintf "There were layout but no circuit changes made in sheet %s after your last save. \ + There is an automatically saved version which is \ + more uptodate. Do you want to keep the newer AutoSaved version or \ + the older Saved version?" ldComp.Name, "green" + | n when n < 3 -> + sprintf "Warning: %d component and %d connection changes were made to sheet '%s' after your last Save. \ + There is an automatically saved version which is \ + more uptodate. Do you want to keep the newer AutoSaved version or \ + the older saved version?" compChanges connChanges ldComp.Name, "orange" + | n -> + sprintf "Warning: %d component and %d connection changes were made to sheet '%s' after your last Save. \ + There is an automatically saved version which is \ + more uptodate. Do you want to keep the newer AutoSaved version or \ + the older saved version? This is a large change so the option you do not choose \ + will be saved as file 'backup/%s.dgm'" compChanges connChanges ldComp.Name ldComp.Name, "red" + let body = + div [Style [Color color]] [str message] + choicePopup title body "Newer AutoSaved file" "Older Saved file" buttonAction dispatch + | OkAuto autoComp :: rLst -> + let errMsg = "Could not load saved project file '%s' - using autosave file instead" + displayFileErrorNotification errMsg dispatch + resolveComponentOpenPopup pPath (autoComp::components) rLst model dispatch + | OkComp comp ::rLst -> + resolveComponentOpenPopup pPath (comp::components) rLst model dispatch + + +/// open an existing project +let private openProject model dispatch = + //trying to force the spinner to load earlier + //doesn't really work right now + dispatch (Sheet (Sheet.SetSpinner true)) + match askForExistingProjectPath () with + | None -> () // User gave no path. + | Some path -> + dispatch (ExecFuncAsynch <| fun () -> + traceIf "project" (fun () -> "loading files") + match loadAllComponentFiles path with + | Error err -> + log err + displayFileErrorNotification err dispatch + | Ok componentsToResolve -> + traceIf "project" (fun () -> "resolving popups...") + + resolveComponentOpenPopup path [] componentsToResolve model dispatch + traceIf "project" (fun () -> "project successfully opened.") + + Elmish.Cmd.none) + + + + +/// Display the initial Open/Create Project menu at the beginning if no project +/// is open. +let viewNoProjectMenu model dispatch = + let menuItem label action = + Menu.Item.li + [ Menu.Item.IsActive false + Menu.Item.OnClick action ] [ str label ] + + let initialMenu = + Menu.menu [] + [ Menu.list [] + [ menuItem "New project" (fun _ -> newProject model dispatch) + menuItem "Open project" (fun _ -> openProject model dispatch) ] + ] + + match model.CurrentProj with + | Some _ -> div [] [] + | None -> unclosablePopup None initialMenu None [] dispatch + +//These two functions deal with the fact that there is a type error otherwise.. +let goBackToProject model dispatch _ = + dispatch (SetExitDialog false) + +let closeApp model dispatch _ = + dispatch CloseApp + + +type SheetTree = { + Node: string + Size: int + SubSheets: SheetTree list + } + + +/// get the subsheet tree for aa sheets +let getSheetTrees (p:Project) = + let ldcMap = + p.LoadedComponents + |> List.map (fun ldc -> ldc.Name,ldc) + |> Map.ofList + let rec subSheets (path: string list) (sheet: string) : SheetTree= + let ldc = Map.tryFind sheet ldcMap + match ldc with + | None -> {Node=sheet; Size = 1;SubSheets = []} + | Some ldc -> + let comps,_ = ldc.CanvasState + comps + |> List.collect (fun comp -> + match comp.Type with + | Custom ct when not <| List.contains ct.Name path -> + [subSheets (ct.Name :: path) ct.Name] + | _ -> + []) + |> (fun subs -> { + Node=sheet; + Size = List.sumBy (fun sub -> sub.Size) subs + 1; + SubSheets= subs + }) + p.LoadedComponents + |> List.map (fun ldc ->ldc.Name, subSheets [] ldc.Name) + |> Map.ofList + + + + + + + + + + +/// Display top menu. +let viewTopMenu model messagesFunc simulateButtonFunc dispatch = + let compIds = getComponentIds model + + messagesFunc model dispatch + + //printfn "FileView" + let style = Style [ Width "100%" ; BorderBottom "2px solid lightgray"] //leftSectionWidth model + let styleNoBorder = Style [Width "100%"] + let projectPath, fileName = + match model.CurrentProj with + | None -> "no open project", "no open sheet" + | Some project -> project.ProjectPath, project.OpenFileName + + let makeFileLine isSubSheet name project model = + let nameProps = + if isSubSheet then + [] else + [Props [Style [FontWeight "bold"]]] + Navbar.Item.div [ Navbar.Item.Props [ styleNoBorder ] ] + [ Level.level [ Level.Level.Props [ styleNoBorder ]] + [ Level.left nameProps [ Level.item [] [ str name ] ] + Level.right [ Props [ Style [ MarginLeft "20px" ] ] ] + [ Level.item [] + [ Button.button + [ Button.Size IsSmall + Button.IsOutlined + Button.Color IsPrimary + Button.Disabled(name = project.OpenFileName) + Button.OnClick(fun _ -> + dispatch (StartUICmd ChangeSheet) + printSheetNames model + dispatch <| ExecFuncInMessage( + (fun model dispatch -> + let p = Option.get model.CurrentProj + openFileInProject name p model dispatch), dispatch)) ] [ str "open" ] + ] + // Add option to rename? + Level.item [] [ + Button.button [ + Button.Size IsSmall + Button.IsOutlined + Button.Color IsInfo + Button.OnClick(fun _ -> + dispatch (StartUICmd RenameSheet) + renameFileInProject name project model dispatch) ] [ str "rename" ] + ] + Level.item [] + [ Button.button + [ Button.Size IsSmall + Button.IsOutlined + Button.Color IsDanger + Button.OnClick(fun _ -> + let title = "Delete sheet" + + let body = + div [] + [ str "Are you sure you want to delete the following design sheet?" + br [] + str <| pathJoin + [| project.ProjectPath + name + ".dgm" |] + br [] + str <| "This action is irreversible." ] + + let buttonText = "Delete" + + let buttonAction = + fun _ -> + dispatch (StartUICmd DeleteSheet) + dispatch <| ExecFuncInMessage(removeFileInProject name project,dispatch) + dispatch ClosePopup + confirmationPopup title body buttonText buttonAction dispatch) ] + [ str "delete" ] ] ] ] ] + + let fileTab model = + match model.CurrentProj with + | None -> Navbar.Item.div [] [] + | Some project -> + + let sTrees = getSheetTrees project + + let rec subSheetsOf path sh = + match Map.tryFind sh sTrees with + | Some tree -> tree.SubSheets + | None -> [] + |> List.collect (fun ssh -> + match List.contains ssh.Node path with + | true -> [] + | false -> ssh.Node :: subSheetsOf (ssh.Node :: path) ssh.Node) + |> List.distinct + + let allSubSheets = + mapKeys sTrees + |> Seq.collect (subSheetsOf []) + |> Set + let isSubSheet sh = Set.contains sh allSubSheets + + let projectFiles = + project.LoadedComponents + |> List.map (fun comp -> + let tree = sTrees[comp.Name] + makeFileLine (isSubSheet tree.Node) comp.Name project model , tree) + |> List.sortBy (fun (line,tree) -> isSubSheet tree.Node, tree.Node, -tree.Size, tree.Node.ToLower()) + |> List.map fst + Navbar.Item.div + [ Navbar.Item.HasDropdown + Navbar.Item.Props + [ OnClick(fun _ -> + printSheetNames model + if model.TopMenuOpenState = Files then Closed else Files + |> SetTopMenu + |> dispatch) ] ] + [ Navbar.Link.a [] [ str "Sheets" ] + Navbar.Dropdown.div + [ Navbar.Dropdown.Props + [ Style + [ Display + (if (let b = model.TopMenuOpenState = Files + b) then + DisplayOptions.Block + else + DisplayOptions.None) ] ] ] + ([ Navbar.Item.a [ Navbar.Item.Props [ OnClick(fun _ -> + dispatch (StartUICmd AddSheet) + addFileToProject model dispatch) ] ] + [ str "New Sheet" ] + Navbar.divider [] [] ] + @ projectFiles) ] + + div [ HTMLAttr.Id "TopMenu" + leftSectionWidth model + Style [ Position PositionOptions.Absolute + UserSelect UserSelectOptions.None + + ] + ] + [ Navbar.navbar + [ Navbar.Props + [ Style + [ Height "100%" + Width "100%" + BorderBottom "2px solid lightgray"] ] ] + [ Navbar.Brand.div + [ Props + [ Style + [ Height "100%" + Width "100%" ] ] ] + [ Navbar.Item.div + [ Navbar.Item.HasDropdown + Navbar.Item.Props + [ OnClick(fun _ -> + if model.TopMenuOpenState = Project then Closed else Project + |> SetTopMenu + |> dispatch) ] ] + [ Navbar.Link.a [] [ str "Project" ] + Navbar.Dropdown.div + [ Navbar.Dropdown.Props + [ Style + [ Display + (if model.TopMenuOpenState = Project then + DisplayOptions.Block + else + DisplayOptions.None) ] ] ] + [ Navbar.Item.a [ Navbar.Item.Props [ OnClick <| doActionWithSaveFileDialog "New project" (ExecFuncInMessage(newProject,dispatch)) model dispatch ] ] + [ str "New project" ] + Navbar.Item.a [ Navbar.Item.Props [ OnClick <| doActionWithSaveFileDialog "Open project" (ExecFuncInMessage(openProject,dispatch)) model dispatch ] ] + [ str "Open project" ] + Navbar.Item.a [ Navbar.Item.Props [ OnClick <| doActionWithSaveFileDialog "Close project" (ExecFuncInMessage(forceCloseProject,dispatch)) model dispatch ] ] + [ str "Close project" ] ] ] + + fileTab model + Navbar.Item.div [] + [ Navbar.Item.div [] + [ Breadcrumb.breadcrumb [ Breadcrumb.HasArrowSeparator ] + [ Breadcrumb.item [] [ str <| cropToLength 30 false projectPath ] + Breadcrumb.item [] [ span [ Style [ FontWeight "bold" ] ] [ str fileName ] ] ] ] ] + Navbar.Item.div [] + [ Navbar.Item.div [] + [ Button.button + ((if model.SavedSheetIsOutOfDate then + [] + else + [ Button.Color IsLight ]) @ + [ + Button.Color IsSuccess + + Button.OnClick(fun _ -> + dispatch (StartUICmd SaveSheet) + saveOpenFileActionWithModelUpdate model dispatch |> ignore + dispatch <| Sheet(Sheet.DoNothing) //To update the savedsheetisoutofdate send a sheet message + ) ]) [ str "Save" ] ] ] + Navbar.End.div [] + [ + Navbar.Item.div [] + [ simulateButtonFunc compIds model dispatch ] ] + Navbar.End.div [] + [ Navbar.Item.div [] + [ Button.button + [ Button.OnClick(fun _ -> PopupView.viewInfoPopup dispatch) + Button.Color IsInfo + ] + [ str "Info" ] + // add space padding on RH of navbar to improve top bar formatting + // this is a bit of a hack - but much easier than matching styles + Text.div + [Props [Style [PaddingRight "7000px"]]] [str ""] + ] ] ] ] ] diff --git a/src/Renderer/UI/MainView.fs b/src/Renderer/UI/MainView.fs new file mode 100644 index 0000000..b67f482 --- /dev/null +++ b/src/Renderer/UI/MainView.fs @@ -0,0 +1,299 @@ +module DiagramMainView +open Fulma + +open Fable.React +open Fable.React.Props + +open DiagramStyle +open ModelType +open FileMenuView +open WaveformSimulationView + +open Fable.Core +open Fable.Core.JsInterop + +//------------------Buttons overlaid on Draw2D Diagram----------------------------------// +//--------------------------------------------------------------------------------------// + +let viewOnDiagramButtons model dispatch = + let sheetDispatch sMsg = dispatch (Sheet sMsg) + let dispatch = Sheet.KeyPress >> sheetDispatch + + div [ canvasSmallMenuStyle ] [ + let canvasBut func label = + Button.button [ + Button.Props [ canvasSmallButtonStyle; OnClick func ] + Button.Modifiers [ + //Modifier.TextWeight TextWeight.Bold + Modifier.TextColor IsLight + Modifier.BackgroundColor IsSuccess + ] + ] + [ str label ] + canvasBut (fun _ -> dispatch Sheet.KeyboardMsg.CtrlZ ) "< undo" + canvasBut (fun _ -> dispatch Sheet.KeyboardMsg.CtrlY ) "redo >" + canvasBut (fun _ -> dispatch Sheet.KeyboardMsg.CtrlC ) "copy" + canvasBut (fun _ -> dispatch Sheet.KeyboardMsg.CtrlV ) "paste" + + ] + +// -- Init Model + + + +/// Initial value of model +let init() = { + LastChangeCheckTime = 0. + // Diagram = new Draw2dWrapper() + Sheet = fst (Sheet.init()) + WaveSimulationIsOutOfDate = true + IsLoading = false + LastDetailedSavedState = ([],[]) + LastSimulatedCanvasState = None + LastSelectedIds = [],[] + CurrentSelected = [],[] + SelectedComponent = None + LastUsedDialogWidth = 1 + CurrentStepSimulationStep = None + WaveSim = Map.empty, None + WaveSimSheet = "" + RightPaneTabVisible = Catalogue + CurrentProj = None + Hilighted = ([], []), [] + Clipboard = [], [] + LastCreatedComponent = None + SavedSheetIsOutOfDate = false + PopupViewFunc = None + PopupDialogData = { + ProjectPath = "" + Text = None + Int = None + Int2 = None + MemorySetup = None + MemoryEditorData = None + WaveSetup = None + Progress = None + } + Notifications = { + FromDiagram = None + FromSimulation = None + FromWaveSim = None + FromFiles = None + FromMemoryEditor = None + FromProperties = None + } + TopMenuOpenState = Closed + DividerDragMode = DragModeOff + WaveSimViewerWidth = rightSectionWidthViewerDefault + SimulationInProgress = None + ConnsOfSelectedWavesAreHighlighted= false + CheckWaveformScrollPosition = false + Pending = [] + UIState = None +} + + + +let makeSelectionChangeMsg (model:Model) (dispatch: Msg -> Unit) (ev: 'a) = + dispatch SelectionHasChanged + +// -- Create View + +/// Display the content of the right tab. +let private viewRightTab model dispatch = + match model.RightPaneTabVisible with + | Catalogue -> + div [ Style [Width "90%"; MarginLeft "5%"; MarginTop "15px" ] ] [ + Heading.h4 [] [ str "Catalogue" ] + div [ Style [ MarginBottom "15px" ] ] [ str "Click on a component to add it to the diagram. Hover on components for details." ] + CatalogueView.viewCatalogue model dispatch + ] + | Properties -> + div [ Style [Width "90%"; MarginLeft "5%"; MarginTop "15px" ] ] [ + Heading.h4 [] [ str "Component properties" ] + SelectedComponentView.viewSelectedComponent model dispatch + ] + + | Simulation -> + div [ Style [Width "90%"; MarginLeft "5%"; MarginTop "15px" ] ] [ + Heading.h4 [] [ str "Simulation" ] + SimulationView.viewSimulation model dispatch + ] + | WaveSim -> + div [ Style [Width "100%"; Height "calc(100% - 48px)"; MarginTop "15px" ] ] + ( WaveformSimulationView.viewWaveSim model dispatch ) + +/// determine whether moving the mouse drags the bar or not +let inline setDragMode (modeIsOn:bool) (model:Model) dispatch = + fun (ev: Browser.Types.MouseEvent) -> + makeSelectionChangeMsg model dispatch ev + //printfn "START X=%d, buttons=%d, mode=%A, width=%A, " (int ev.clientX) (int ev.buttons) model.DragMode model.ViewerWidth + match modeIsOn, model.DividerDragMode with + | true, DragModeOff -> + dispatch <| SetDragMode (DragModeOn (int ev.clientX)) + | false, DragModeOn _ -> + dispatch <| SetDragMode DragModeOff + | _ -> () + +/// Draggable vertivcal bar used to divide Wavesim window from Diagram window +let dividerbar (model:Model) dispatch = + let isDraggable = model.RightPaneTabVisible = WaveSim + let variableStyle = + if isDraggable then [ + BackgroundColor "grey" + Cursor "grab" + Width "10px" + + ] else [ + BackgroundColor "lightgrey" + Width "2px" + + ] + let commonStyle = [ + Height "100%" + Float FloatOptions.Left + ] + div [ + Style <| commonStyle @ variableStyle + OnMouseDown (setDragMode true model dispatch) + ] [] + +//---------------------------------------------------------------------------------------------------------// +//------------------------------------------VIEW FUNCTION--------------------------------------------------// +//---------------------------------------------------------------------------------------------------------// +/// Top-level application view: as react components that create a react virtual-DOM +let displayView model dispatch = + JSHelpers.traceIf "view" (fun _ -> "View Function...") + let windowX,windowY = + int Browser.Dom.self.innerWidth, int Browser.Dom.self.innerHeight + //let selectedComps, selectedconns = + // model.Diagram.GetSelected() + // |> Option.map extractState + // |> Option.defaultValue ([],[]) + + // TODO +// let sd = scrollData model +// let x' = sd.SheetLeft+sd.SheetX +// let y' = sd.SheetTop+sd.SheetY + let wsModelOpt = getCurrentWSMod model + + /// Feed changed viewer width from draggable bar back to Viewer parameters TODO + let inline setViewerWidthInWaveSim w = + match currWaveSimModel model with + | Some wSMod when w > maxUsedViewerWidth wSMod && wSMod.WSViewState = WSViewerOpen -> + match wsModelOpt with + | Some ws -> + let simProgressState = + {ws.SimParams with LastClkTime = ws.SimParams.LastClkTime + 10u} + dispatch <| InitiateWaveSimulation(WSViewerOpen, simProgressState) + | _ -> () + | _ -> () + + + /// used only to make the divider bar draggable + let inline processMouseMove (ev: Browser.Types.MouseEvent) = + //printfn "X=%d, buttons=%d, mode=%A, width=%A, " (int ev.clientX) (int ev.buttons) model.DragMode model.ViewerWidth + if ev.buttons = 1. then + dispatch SelectionHasChanged + match model.DividerDragMode, ev.buttons with + | DragModeOn pos , 1.-> + let newWidth = model.WaveSimViewerWidth - int ev.clientX + pos + let w = + newWidth + |> max minViewerWidth + |> min (windowX - minEditorWidth) + dispatch <| SetViewerWidth w + setViewerWidthInWaveSim w + dispatch <| SetDragMode (DragModeOn (int ev.clientX)) + | DragModeOn _, _ -> + dispatch <| SetDragMode DragModeOff + | DragModeOff, _-> () + + let headerHeight = getHeaderHeight + let sheetDispatch sMsg = dispatch (Sheet sMsg) + + // the whole app window + let cursorText = model.Sheet.CursorType.Text() + let topCursorText = match model.Sheet.CursorType with | Sheet.Spinner -> "wait" | _ -> "" + + div [ HTMLAttr.Id "WholeApp" + Key cursorText + OnMouseMove processMouseMove + Style [ + //CSSProp.Cursor cursorText + UserSelect UserSelectOptions.None + BorderTop "2px solid lightgray" + BorderBottom "2px solid lightgray" + Cursor topCursorText ] ] [ + // transient + FileMenuView.viewNoProjectMenu model dispatch + + PopupView.viewPopup model dispatch + // Top bar with buttons and menus: some subfunctions are fed in here as parameters because the + // main top bar function is early in compile order + FileMenuView.viewTopMenu model WaveSimHelpers.fileMenuViewActions WaveformSimulationView.WaveformButtonFunc dispatch + + if model.PopupDialogData.Progress = None then + Sheet.view model.Sheet headerHeight (canvasVisibleStyleList model) sheetDispatch + + // transient pop-ups + Notifications.viewNotifications model dispatch + // editing buttons overlaid bottom-left on canvas + if model.PopupDialogData.Progress <> None then + div [] [] + else + viewOnDiagramButtons model dispatch + + + //--------------------------------------------------------------------------------------// + //------------------------ left section for Sheet (NOT USED) ---------------------------// + // div [ leftSectionStyle model ] [ div [ Style [ Height "100%" ] ] [ Sheet.view model.Sheet sheetDispatch ] ] + + //--------------------------------------------------------------------------------------// + //---------------------------------right section----------------------------------------// + // right section has horizontal divider bar and tabs + div [ rightSectionStyle model ] + // vertical and draggable divider bar + [ dividerbar model dispatch + // tabs for different functions + div [ + HTMLAttr.Id "RightSelection" + Style [ Height "100%" ] + ] + [ Tabs.tabs [ Tabs.IsFullWidth; Tabs.IsBoxed; Tabs.CustomClass "rightSectionTabs" + Tabs.Props [Style [Margin 0] ] ] + + [ Tabs.tab // catalogue tab to add components + [ Tabs.Tab.IsActive (model.RightPaneTabVisible = Catalogue) ] + [ a [ OnClick (fun _ -> + if model.RightPaneTabVisible <> WaveSim + then + dispatch <| ChangeRightTab Catalogue ) ] [str "Catalogue" ] ] + + Tabs.tab // Properties tab to view/change component properties + [ Tabs.Tab.IsActive (model.RightPaneTabVisible = Properties) ] + [ a [ OnClick (fun _ -> + if model.RightPaneTabVisible <> WaveSim + then + dispatch <| ChangeRightTab Properties )] [str "Properties" ] ] + + (Tabs.tab // simulation tab to do combinational simulation + [ Tabs.Tab.IsActive (model.RightPaneTabVisible = Simulation) ] + [ a [ OnClick (fun _ -> + if model.RightPaneTabVisible <> WaveSim + then + dispatch <| ChangeRightTab Simulation ) + ] [str "Simulation"] ] ) + + // Optional wavesim tab. If present contains waveforms or waveform editor window + (match currWaveSimModel model with + | Some {WSViewState=WSClosed} -> + div [] [] + | _ -> + Tabs.tab // WaveSim tab - if wavesim exists + [ Tabs.Tab.IsActive (model.RightPaneTabVisible = WaveSim) ] + [ a [ OnClick (fun _ -> dispatch <| ChangeRightTab WaveSim ) ] + [ str "WaveSim" ] ] ) + ] + viewRightTab model dispatch ] ] ] + diff --git a/src/Renderer/UI/MemoryEditorView.fs b/src/Renderer/UI/MemoryEditorView.fs new file mode 100644 index 0000000..e1aabaa --- /dev/null +++ b/src/Renderer/UI/MemoryEditorView.fs @@ -0,0 +1,373 @@ +//(* +// MemoryEditorView.fs +// +// A simple Popup editor to view and change the content of a memory. +//*) +// +module MemoryEditorView + +open Fulma +open Fable.React +open Fable.React.Props + +open Helpers +open NumberHelpers +open JSHelpers +open CommonTypes +open ModelType +open PopupView +open Notifications + +let private popupExtraStyle = [ Width "65%"; Height "80%" ] +let private headerHeight = 60; +let private headerStyle = Style [ + Position PositionOptions.Fixed + MarginTop (string (-headerHeight-20) + "px") + PaddingTop "20px" + PaddingBottom "60px" + BackgroundColor "white" + Width "61%" + Height headerHeight + CSSProp.ZIndex 32 +] +let private bodyStyle = Style [ + MarginTop (string headerHeight + "px") +] + +let private showError msg dispatch : unit = + errorNotification msg CloseMemoryEditorNotification + |> SetMemoryEditorNotification |> dispatch + +let private closeError dispatch : unit = + CloseMemoryEditorNotification |> dispatch + +let private showRowWithAdrr memoryEditorData addr = + match memoryEditorData.Address with + | None -> true + | Some a when a = addr -> true + | _ -> false + +let viewNum numBase = + match numBase with | Hex -> hex64 | Dec -> dec64 | Bin -> bin64 | SDec -> sDec64 + +let viewFilledNum width numBase = + match numBase with | Hex -> fillHex64 width | Dec -> dec64 | Bin -> fillBin64 width | SDec -> sDec64 + +// let private baseToStr b = match b with | Hex -> "hex" | Dec -> "dec" | Bin -> "bin" + + +let mutable dynamicMem: Memory1 = { + Init = FromData; + WordWidth = 0; + AddressWidth = 0; + Data = Map.empty + } // Need to use a mutable dynamic memory and update it locally so that the shown values are correct since the model is not immediately updated + +let baseSelector numBase changeBase = + Level.item [ Level.Item.HasTextCentered ] [ + Field.div [ Field.HasAddonsCentered ] [ + Control.div [] [ Button.button [ + Button.Color (if numBase = Hex then IsPrimary else NoColor) + Button.OnClick (fun _ -> changeBase Hex) + ] [ str "hex" ] ] + Control.div [] [ Button.button [ + Button.Color (if numBase = Dec then IsPrimary else NoColor) + Button.OnClick (fun _ -> changeBase Dec) + ] [ str "dec" ] ] + Control.div [] [ Button.button [ + Button.Color (if numBase = Bin then IsPrimary else NoColor) + Button.OnClick (fun _ -> changeBase Bin) + ] [ str "bin" ] ] + ] + ] + +let changeBase memoryEditorData dispatch numBase = + { memoryEditorData with NumberBase = numBase } + |> Some |> SetPopupMemoryEditorData |> dispatch + +//========// +// Editor // +//========// +/// Function creating react input box for memory address for use in WaveSim code (could also be used here). +/// setMemoryAddress dispatches a message to set the memory address to that typed in the input box. +/// numberBase, addressWidth configure the view. +/// TODO: make box width variable according to memory width? +let reactMemoryAddressInputBox numberBase addressWidth setMemoryAddress dispatch = + Input.text [ + Input.Props [ Style [ MarginLeft "10px"; Width "80px" ] ] + Input.DefaultValue "" + Input.Placeholder <| viewNum numberBase (int64 0) + Input.OnChange (getTextEventValue >> fun text -> + match text with + | "" -> closeError dispatch + dispatch <| setMemoryAddress None + | t -> + match strToInt t with + | Error err -> showError err dispatch + | Ok addr -> + let addr = uint64 addr + let w = addressWidth + if w < 64 && addr >= (1UL <<< w) + then showError "Address out of bounds." dispatch + else closeError dispatch + dispatch <| setMemoryAddress (Some (int64 addr)) + + ) + ] + +let private makeEditorHeader memory isDiff memoryEditorData dispatch = + div [headerStyle; SpellCheck false] [ + Level.level [] ([ + Level.item [ Level.Item.HasTextCentered ] [ + str <| sprintf "Number of elements: %d" (pow2int64 memory.AddressWidth) + br [] + str <| sprintf "Word width: %d bit(s)" memory.WordWidth + ] + Level.item [ Level.Item.HasTextCentered ] [ + str <| "First Location Displayed" + Input.text [ + Input.Props [ Style [ MarginLeft "10px"; Width "80px" ] ] + Input.DefaultValue "" + Input.Placeholder <| viewNum memoryEditorData.NumberBase (int64 0) + Input.OnChange (getTextEventValue >> fun text -> + match text with + | "" -> closeError dispatch + { memoryEditorData with Address = None } + |> Some |> SetPopupMemoryEditorData |> dispatch + | t -> + match strToInt t with + | Error err -> showError err dispatch + | Ok addr -> + let addr = uint64 addr + let w = memory.AddressWidth + if w < 64 && addr >= (1UL <<< w) + then showError "Address out of bounds." dispatch + else closeError dispatch + { memoryEditorData with Address = Some (int64 addr) } + |> Some |> SetPopupMemoryEditorData |> dispatch + ) + ] + ] + baseSelector memoryEditorData.NumberBase (changeBase memoryEditorData dispatch) + ] @ (if isDiff // Add extra filter. + then [ + Level.item [ Level.Item.HasTextCentered ] [ + Checkbox.checkbox [] [ + Checkbox.input [ Props [ + Style [ MarginRight "5px" ] + Checked memoryEditorData.OnlyDiff + OnChange (fun _ -> + { memoryEditorData with OnlyDiff = not memoryEditorData.OnlyDiff } + |> Some |> SetPopupMemoryEditorData |> dispatch + ) + ] ] + str "Show only if changed" + ] + ] + ] + else [] + )) + ] + +let private makeEditorBody memory compId memoryEditorData model (dispatch: Msg -> unit) = + let sheetDispatch sMsg = dispatch (Sheet sMsg) + let source = memory.Init + let isReadOnly = + match source with + | SignedMultiplier + | UnsignedMultiplier -> + $"Fixed multiplier blocks cannot have initial value edited" + | FromFile fName -> + $"This memory takes initial values from {fName}.ram, edit the file to change them" + | ToFile fName-> + $"This memory is linked to File {fName}.ram, changes made here will be save dto that file" + | _ -> "" + let showRow = showRowWithAdrr memoryEditorData + let viewNumD = viewFilledNum memory.WordWidth memoryEditorData.NumberBase + let viewNumA = viewFilledNum memory.AddressWidth memoryEditorData.NumberBase + let numLocsToDisplay = 16UL + let maxLocAddr = ((1UL <<< memory.AddressWidth) - 1UL) + let startLoc, endLoc = + match memoryEditorData.Address with + | None -> 0UL, min maxLocAddr numLocsToDisplay + | Some a -> + let a = uint64 a + let maxDispLocWrapped = a + numLocsToDisplay - 1UL + let maxDispLoc = if maxDispLocWrapped > a then maxDispLocWrapped else uint64 (-1L) + a, min maxDispLoc maxLocAddr + //printfn "makeEditorBody called" + + //printfn "Making body with data=%A, dynamic %A" memory.Data dynamicMem + // let memory = dynamicMem + let makeRow isReadOnly (memData: Map) (addr: uint64) = + let addr = int64 addr + let content = // Need to keep the changes locally as well, since the model does not immediately get updated + Map.tryFind (int64 addr) memData + |> Option.defaultValue 0L + //printfn "load" + tr [ SpellCheck false; Style [ Display (if true then DisplayOptions.TableRow else DisplayOptions.None)] ] [ + td [] [ str <| viewNumA (int64 addr) ] + td [] [ + let handleInput (ev: Browser.Types.FocusEvent) = + let text = getTextEventValue ev + //printfn "change" + match strToIntCheckWidth memory.WordWidth text with + | Ok value -> + // Close error notification. + closeError dispatch + // Write new value. + let oldData = + let comp = model.Sheet.GetComponentById compId + comp.Type |> (function | (RAM1 d) | (ROM1 d) | (AsyncROM1 d) | (AsyncRAM1 d)-> d + | _ -> + printfn "Should not be here" + memory) + + dynamicMem <- { dynamicMem with Data = Map.add addr value dynamicMem.Data } + model.Sheet.WriteMemoryLine sheetDispatch compId addr value // Only update one row + + dispatch (ReloadSelectedComponent model.LastUsedDialogWidth) + //printfn "setting value=%d, addr=%d" value addr + | Error err -> + showError err dispatch + + Input.text [ + Input.Props [ + OnBlur handleInput ; + Key <| ( memoryEditorData.NumberBase.ToString() + (addr,content).ToString()) + ] + Input.Disabled isReadOnly + Input.DefaultValue <| viewNumD content + Input.Option.OnChange <| (getTextEventValue >> (fun text -> + match strToIntCheckWidth memory.WordWidth text with + | Error err -> showError err dispatch + | Ok _ -> closeError dispatch)) + ] + ] + ] + + div [bodyStyle] [ + str isReadOnly + br [] + Table.table [ Table.IsFullWidth ] [ + thead [] [ tr [] [ + th [] [str "Address"] + th [] [str "Content"] + ] ] + tbody [] ( [startLoc..endLoc] |> List.map (makeRow (isReadOnly <> "") memory.Data)) + ] + ] + +let private makeFoot editMode dispatch (model: Model)= + let action = + fun _ -> dispatch CloseMemoryEditorNotification + dispatch ClosePopup + // Diff mode is triggered by a simulationView, not by a + // selected component. + match editMode with + | Some (ToFile fName) -> + match model.CurrentProj, model.SelectedComponent with + | Some p, Some comp -> + let mem = + match comp.Type with + | RAM1 mem | ROM1 mem | AsyncROM1 mem | AsyncRAM1 mem -> mem + | _ -> failwithf $"Unexpected non-memory component {comp.Type}" + match FilesIO.initialiseMem mem p.ProjectPath with + | Error msg -> + let note = + errorNotification + "Error writing chnaged memory contents to {fName}.ram" + CloseMemoryEditorNotification + dispatch <| SetMemoryEditorNotification note + | _ -> () + dispatch (ReloadSelectedComponent model.LastUsedDialogWidth) + | p,comp -> failwithf "What? expecting component {comp} and project {p}" + | Some FromData -> + dispatch (ReloadSelectedComponent model.LastUsedDialogWidth) + | _ -> () + Level.level [ Level.Level.Props [ Style [ Width "100%" ] ] ] [ + Level.left [] [] + Level.right [] [ Level.item [] [ Button.button [ + Button.Color IsPrimary + Button.OnClick action + ] [ str "Done" ] ] ] + ] + +let private makeEditor memory compId model dispatch = + // printfn "makeEditor called" + dynamicMem <- // Need to use a mutable dynamic memory and update it locally so that the shown values are correct since the model is not immediately updated + match model.SelectedComponent with + | Some {Type=RAM1 mem} | Some {Type=ROM1 mem} |Some {Type = AsyncROM1 mem} | Some {Type = AsyncRAM1 mem} -> mem + | _ -> memory + fun memoryEditorData -> + div [] [ + makeEditorHeader dynamicMem false memoryEditorData dispatch + makeEditorBody dynamicMem compId memoryEditorData model dispatch + ] + +/// Open a popup to view and edit the content of a memory. +let openMemoryEditor memory compId model dispatch : unit = + // Build editor. + let title = "Memory editor" + let body = makeEditor memory compId model dispatch + let foot = makeFoot (Some memory.Init) dispatch model + showMemoryEditorPopup (Some title) body (Some foot) popupExtraStyle dispatch + +//=============// +// Diff viewer // +//=============// + +let private makeDiffViewerBody memory1 memory2 memoryEditorData = + let getData addr memData = + Map.tryFind addr memData + |> Option.defaultValue 0L + let viewNum = viewNum memoryEditorData.NumberBase + let makeRow content1 content2 addr = + let hasChanged = content1 <> content2 + let showRow addr = + showRowWithAdrr memoryEditorData addr && ( + not memoryEditorData.OnlyDiff || + memoryEditorData.OnlyDiff && hasChanged) + tr [ Style [ Display (if showRow addr then DisplayOptions.TableRow else DisplayOptions.None)] ] [ + td [] [ str <| viewNum (int64 addr) ] + td [ + Style [BackgroundColor (if hasChanged then "#ffc6d3" else "auto") ] + ] [ str <| viewNum content1 ] + td [ + Style [BackgroundColor (if hasChanged then "#baffd3" else "auto") ] + ] [ str <| viewNum content2 ] + ] + let addr = Option.defaultValue 0L memoryEditorData.Address + let addr2 = addr + 15L + + div [bodyStyle] [ + Table.table [ Table.IsFullWidth ] [ + thead [] [ tr [] [ + th [] [str "Address"] + th [] [str "Initial content"] + th [] [str "Current content"] + ] ] + tbody [] ( + [addr..addr2] |> List.map (fun a -> (makeRow (getData a memory1.Data) (getData a memory2.Data) a)) + ) + ] + ] + +let private makeDiffViewer memory1 memory2 dispatch = + fun memoryEditorData -> + div [] [ + makeEditorHeader memory1 true memoryEditorData dispatch + makeDiffViewerBody memory1 memory2 memoryEditorData + ] + +let openMemoryDiffViewer memory1 memory2 model dispatch : unit = +#if ASSERTS + assertThat (memory1.AddressWidth = memory2.AddressWidth && + memory1.WordWidth = memory2.WordWidth) + <| sprintf "Memories in diffViewer do not match: %A\n%A" memory1 memory2 +#endif + // Build editor. + let title = "Memory diff viewer" + let body = makeDiffViewer memory1 memory2 dispatch + let foot = makeFoot None dispatch model + showMemoryEditorPopup (Some title) body (Some foot) popupExtraStyle dispatch diff --git a/src/Renderer/UI/MessageType.fs b/src/Renderer/UI/MessageType.fs new file mode 100644 index 0000000..3981889 --- /dev/null +++ b/src/Renderer/UI/MessageType.fs @@ -0,0 +1,284 @@ +module MessageType1 + +open CommonTypes +open JSTypes +open SimulatorTypes +open Fable.React + +type RightTab = + | Properties + | Catalogue + | Simulation + | WaveSim + +type MemoryEditorData = { + OnlyDiff : bool // Only show diffs in Memory Diff Viewer. + Address : int64 option // Only show the specified memory address. + Start: int64 + NumberBase : NumberBase +} + +/// Possible fields that may (or may not) be used in a dialog popup. +type PopupDialogData = { + Text : string option; + Int : int option; + Int2: int option + MemorySetup : (int * int) option // AddressWidth, WordWidth. + MemoryEditorData : MemoryEditorData option // For memory editor and viewer. +} + +type TopMenu = | Closed | Project | Files + +//==========// +// Messages // +//==========// + +// Messages that will be sent from JS code. +type JSDiagramMsg = + | InitCanvas of JSCanvas // Has to be dispatched only once. + | SelectComponent of JSComponent + | UnselectComponent of unit + | InferWidths of unit + | SetHasUnsavedChanges of bool + +// Messages that will be triggered on key combinations. +type KeyboardShortcutMsg = + | CtrlS | AltC | AltV | AltZ | AltShiftZ | DEL + +//--------------------------------------------------------------- +//---------------------WaveSim types----------------------------- +//--------------------------------------------------------------- + +(* +WaveSim state. + +Principles: +1) at any time wavesim simulates a stored model.LastSimulatedCanvas circuit which is guaranteed working if it exists +2) pressing "simulate button" updates this circuit +3) wavesim has two views: editor and waveforms. each waveform is the signal on a NetGroup (set of connections from one driver to multiple inputs). +4) waveforms display view based on: selected waveforms, zoom, cursor position, etc +5) simulation is rerun automatically as needed to generate current display +6) editor view interfaces with current circuit, colouring selected nets green, and allowing selection on nets to determine +default selected waveforms. If current circuit has changed only driving components still on circuit can be used this way. +7) simulate button color determines status; if circuit has chnaged from that simulated it will be orange (errors) or green (OK to rerun simulation). +8) list of currently displayed ports is held in state and saved / restored with each sheet. LastSimulatedCanvas (and simulation data) are not saved/restored but +are recalculated when needed. List of possible to display ports used by waveadder + +Data structures for internal state + +SimParams: parameters that can be changed during simulation of one ckt that affect what is displayed. + +*) + + + +type WaveName = string + +type Wire = { + NBits: uint32 + BitData: bigint +} + +type StateSample = string array +type Sample = | Wire of Wire | StateSample of StateSample +type SimTime = Sample array +type Waveform = Sample array +type SVGCacheT = { + Top: ReactElement [] + Waves: Map + Bottom: ReactElement [] + } + +type SimParamsT = { + /// radix for numbers on SVG waveforms display + WaveViewerRadix: NumberBase + /// last clock cycle (index) of the generated SVG + LastClkTime: uint + /// position of cursor (0 = first cycle) + CursorTime: uint + /// width of one clock in SVG units + ClkSvgWidth: float + /// names of NetGroups selected in wave editor and displayed in wave viewer + DispNames: string array + /// current scrolling position of waveform svg (used to possibly extend svgs if scrolling off screen) + LastScrollPos: float option +} + + +type WSViewT = + | WSClosed + | WSInitEditorOpen + | WSEditorOpen + | WSViewerOpen + +type SimActionT = + | MakeSVGs of NetGroup array + | ChangeParameters of SimParamsT + + +type WaveSimModel = { + /// generate data using this 0 clock simulation, which comes from makeSimData + /// TODO: get rid of this and use only SimDataCache, since this is SimDataCache[0] + InitWaveSimGraph : SimulationData option + + /// parameters determining how and which viewer waves are displayed + SimParams: SimParamsT + + /// NetGroup names shown in the editor + AllWaveNames: string array + /// Map of all the nets that exist in the currently simulated design + AllNets: Map + + /// react SVG for each waveform, indexed by name + DispWaveSVGCache: SVGCacheT + /// Simulation output sample array of variable length + SimDataCache: SimulatorTypes.SimulationData array + + /// Hack to detect when cursor text box is empty and use 0. + /// TODO - get rid of this - it should not be needed + CursorBoxIsEmpty: bool + + WSViewState: WSViewT + + WSTransition: (SimParamsT * WSViewT) option + /// the circuit that is being simulated - the canvas may have changed + LastCanvasState: CanvasState option + } + +let setSimParams (setFn: SimParamsT -> SimParamsT) (wsm:WaveSimModel) = + {wsm with SimParams = setFn wsm.SimParams} + +let setDispNames names wsMod = + setSimParams (fun sp -> {sp with DispNames=names}) wsMod + +let setEditorView view wsModel = + {wsModel with WSViewState = view; WSTransition = None} + + + +let setEditorNextView nView simParas wsModel = + {wsModel with WSTransition = Some(simParas, nView)} + + + + + + +let inline getPort (ws:WaveSimModel) (name: string) = ws.AllNets.[name] + +let inline getDispName (ws:WaveSimModel) (port:NetGroup) = + Map.tryFindKey (fun k v -> v = port) ws.AllNets + |> Option.defaultValue "name not found" + + +let inline dispPorts (ws: WaveSimModel) = + ws.SimParams.DispNames + |> Array.map (fun name -> ws.AllNets.[name]) + +let inline AllPorts (ws: WaveSimModel) = + ws.AllWaveNames + +let initWS (allNames:string array) (allPorts: Map): WaveSimModel = + { + InitWaveSimGraph = None + AllNets = allPorts + AllWaveNames = allNames + SimDataCache = [||] + DispWaveSVGCache = { Top = [||]; Waves = Map.empty; Bottom = [||]} + SimParams = { + DispNames = [||] + ClkSvgWidth = 1.0 + CursorTime = 0u + WaveViewerRadix = Bin + LastClkTime = 9u + LastScrollPos = None + } + WSViewState = WSClosed + WSTransition =None + LastCanvasState = None + CursorBoxIsEmpty = false + } + + +type DiagEl = | Comp of Component | Conn of Connection + +type DragMode = DragModeOn of int | DragModeOff + +type IntMode = FirstInt | SecondInt + +type MenuCommand = + | MenuPrint + | MenuSaveFile + | MenuNewFile + | MenuZoom of float + + +/// Type for an open project which represents a complete design. +/// ProjectPath is directory containing project files. +/// OpenFileName is name of file from which current schematic sheet is loaded/saved, without extension or path +/// LoadedComponents contains the list of schematic sheets, each as a component, one per sheet. +type Project = { + /// directory which contains the project files + ProjectPath : string + /// name of open sheet (without extension) + OpenFileName : string + /// componnets have one-one correspondence with files + LoadedComponents : LoadedComponent list +} + + + +type Msg = + | JSDiagramMsg of JSDiagramMsg + | KeyboardShortcutMsg of KeyboardShortcutMsg + | StartSimulation of Result + | SetLastSavedCanvas of string * CanvasState + | SetCurrFileWSMod of WaveSimModel + | SetWSError of SimulationError option + | AddWaveSimFile of string * WaveSimModel + | SetSimulationGraph of SimulationGraph + | SetSimulationBase of NumberBase + | IncrementSimulationClockTick + | EndSimulation + | EndWaveSim + | ChangeRightTab of RightTab + | SetHighlighted of ComponentId list * ConnectionId list + | SetSelWavesHighlighted of ConnectionId array + | SetClipboard of CanvasState + | SetCreateComponent of Component + | SetProject of Project + | CloseProject + | ShowPopup of (PopupDialogData -> ReactElement) + | ClosePopup + | SetPopupDialogText of string option + | SetPopupDialogInt of int option + | SetPopupDialogTwoInts of (int option * IntMode) + | SetPopupDialogMemorySetup of (int * int) option + | SetPopupMemoryEditorData of MemoryEditorData option + | SetSelectedComponentMemoryLocation of int64 * int64 + | CloseDiagramNotification + | SetSimulationNotification of ((Msg -> unit) -> ReactElement) + | CloseSimulationNotification + | CloseWaveSimNotification + | SetFilesNotification of ((Msg -> unit) -> ReactElement) + | CloseFilesNotification + | SetMemoryEditorNotification of ((Msg -> unit) -> ReactElement) + | CloseMemoryEditorNotification + | SetPropertiesNotification of ((Msg -> unit) -> ReactElement) + | ClosePropertiesNotification + | SetTopMenu of TopMenu + | ReloadSelectedComponent of int + | SetDragMode of DragMode + | SetViewerWidth of int + | MenuAction of MenuCommand * (Msg -> unit) + | DiagramMouseEvent + | SelectionHasChanged + | SetWaveSimIsStale of bool + | SetIsLoading of bool + | SetWaveSimModel of Sheet: string * WSModel: WaveSimModel + | WaveSimulateNow + | InitiateWaveSimulation of (WSViewT * SimParamsT) + | SetLastSimulatedCanvasState of CanvasState option + // | StartNewWaveSimulation of CanvasState + | UpdateScrollPos of bool + | SetLastScrollPos of float option diff --git a/src/Renderer/UI/ModelType.fs b/src/Renderer/UI/ModelType.fs new file mode 100644 index 0000000..7b7d51e --- /dev/null +++ b/src/Renderer/UI/ModelType.fs @@ -0,0 +1,657 @@ +(* + ModelType.fs + + This module provides the type for the FRP UI. + It could be put next to CommonTypes but non-UI modules should be agnostic of + the FRP model and run independently of Fable +*) + +module rec ModelType + +open CommonTypes +open SimulatorTypes +open Fable.React + +type RightTab = + | Properties + | Catalogue + | Simulation + | WaveSim + +type MemoryEditorData = { + OnlyDiff : bool // Only show diffs in Memory Diff Viewer. + Address : int64 option // Only show the specified memory address. + Start: int64 + NumberBase : NumberBase +} + + +type SheetWave = { + // path to sheet from simulation graph root + Path: ComponentId list + Sheet: string + CSort: string + Label: string + } + + +type MoreWaveSetup = SheetWave list * Set + + +/// Possible fields that may (or may not) be used in a dialog popup. +type PopupDialogData = { + Text : string option; + Int : int option; + Int2: int64 option + ProjectPath: string + MemorySetup : (int * int * InitMemData * string option) option // AddressWidth, WordWidth. + MemoryEditorData : MemoryEditorData option // For memory editor and viewer. + WaveSetup: MoreWaveSetup option + Progress: PopupProgress option +} + +type TopMenu = | Closed | Project | Files + +//==========// +// Messages // +//==========// + + + +// Messages that will be triggered on key combinations. +type KeyboardShortcutMsg = + | CtrlS | AltC | AltV | AltZ | AltShiftZ | DEL + +type UICommandType = + | CloseProject + | ChangeSheet + | RenameSheet + | DeleteSheet + | AddSheet + | SaveSheet + | StartWaveSim + | ViewWaveSim + | CloseWaveSim + + +//--------------------------------------------------------------- +//---------------------WaveSim types----------------------------- +//--------------------------------------------------------------- + +(* +WaveSim state. + +Principles: +1) at any time wavesim simulates a stored model.LastSimulatedCanvas circuit which is guaranteed working if it exists +2) pressing "simulate button" updates this circuit +3) wavesim has two views: editor and waveforms. each waveform is the signal on a NetGroup (set of connections from one driver to multiple inputs). +4) waveforms display view based on: selected waveforms, zoom, cursor position, etc +5) simulation is rerun automatically as needed to generate current display +6) editor view interfaces with current circuit, colouring selected nets green, and allowing selection on nets to determine +default selected waveforms. If current circuit has changed only driving components still on circuit can be used this way. +7) simulate button color determines status; if circuit has chnaged from that simulated it will be orange (errors) or green (OK to rerun simulation). +8) list of currently displayed ports is held in state and saved / restored with each sheet. LastSimulatedCanvas (and simulation data) are not saved/restored but +are recalculated when needed. List of possible to display ports used by waveadder + +Data structures for internal state + +SimParams: parameters that can be changed during simulation of one ckt that affect what is displayed. + +*) + + + +type WaveName = string + +type Wire = { + NBits: uint32 + BitData: bigint +} + +type StateSample = string array +type Sample = | Wire of Wire | StateSample of StateSample +type SimTime = Sample array +type Waveform = Sample array +type SVGCacheT = { + Top: ReactElement [] + Waves: Map + Bottom: ReactElement [] + } + +type SimParamsT = { + // radix for numbers on SVG waveforms display + WaveViewerRadix: NumberBase + // last clock cycle (index) of the generated SVG + LastClkTime: uint + // position of cursor (0 = first cycle) + CursorTime: uint + // width of one clock in SVG units + ClkSvgWidth: float + // names of NetGroups selected in wave editor and displayed in wave viewer + DispNames: string array + // RAMs to be displayed + MoreWaves: ComponentId list list + // current scrolling position of waveform svg (used to possibly extend svgs if scrolling off screen) + MoreNames: MoreWaveData list + LastScrollPos: float option +} + + +type WSViewT = + | WSClosed + | WSInitEditorOpen + | WSEditorOpen + | WSViewerOpen + +type SimActionT = + | MakeSVGs of NetGroup array + | ChangeParameters of SimParamsT + + +type WaveSimModel = { + // generate data using this 0 clock simulation, which comes from makeSimData + // TODO: get rid of this and use only SimDataCache, since this is SimDataCache[0] + InitWaveSimGraph : SimulationData option + + // parameters determining how and which viewer waves are displayed + SimParams: SimParamsT + + // Waveform names and details shown in the editor + AllWaves: Map + + // react SVG for each waveform, indexed by name + DispWaveSVGCache: SVGCacheT + // Simulation output sample array of variable length + SimDataCache: SimulatorTypes.SimulationData array + + // Hack to detect when cursor text box is empty and use 0. + // TODO - get rid of this - it should not be needed + CursorBoxIsEmpty: bool + + WSViewState: WSViewT + + WSTransition: (SimParamsT * WSViewT) option + // the circuit that is being simulated - the canvas may have changed + LastCanvasState: CanvasState option + // the top-level sheet thsi is being simulated - the canvas may have changed + } + +let setSimParams (setFn: SimParamsT -> SimParamsT) (wsm:WaveSimModel) = + {wsm with SimParams = setFn wsm.SimParams} + +let setDispNames names wsMod = + setSimParams (fun sp -> {sp with DispNames=names}) wsMod + +let setEditorView view wsModel = + {wsModel with WSViewState = view; WSTransition = None} + +let setEditorNextView nView simParas wsModel = + {wsModel with WSTransition = Some(simParas, nView)} + +let inline getWave (ws:WaveSimModel) (name: string) = ws.AllWaves[name] + +let inline getDispName (ws:WaveSimModel) (wave:WaveformSpec) = + Map.tryFindKey (fun k v -> v = wave) ws.AllWaves + |> Option.defaultValue "name not found" + +let inline dispWaves (ws: WaveSimModel) = + ws.SimParams.DispNames + |> Array.map (fun name -> ws.AllWaves[name]) + +let inline AllPorts (ws: WaveSimModel) = + ws.AllWaves + +let initWS (allNames:string array) (allPorts: Map): WaveSimModel = + { + InitWaveSimGraph = None + AllWaves = Map.empty + SimDataCache = [||] + DispWaveSVGCache = { Top = [||]; Waves = Map.empty; Bottom = [||]} + SimParams = { + MoreNames = [] + DispNames = [||] + ClkSvgWidth = 1.0 + CursorTime = 0u + WaveViewerRadix = Bin + LastClkTime = 9u + LastScrollPos = None + MoreWaves = [] + } + WSViewState = WSClosed + WSTransition =None + LastCanvasState = None + CursorBoxIsEmpty = false + } + + + +type DiagEl = | Comp of Component | Conn of Connection + +type DragMode = DragModeOn of int | DragModeOff + +type IntMode = FirstInt | SecondInt + + + +type MenuCommand = + | MenuPrint + | MenuSaveFile + | MenuNewFile + | MenuExit + | MenuZoom of float + | MenuVerilogOutput + +type SimulationProgress = + { + InitialClock: int + FinalClock: int + ClocksPerChunk: int + } + +type PopupProgress = + { + Value: int + Max: int + Title: string + Speed: float + } + + + + +type Msg = + | ShowExitDialog + | Sheet of Sheet.Msg + | JSDiagramMsg of JSDiagramMsg + | KeyboardShortcutMsg of KeyboardShortcutMsg + | StartSimulation of Result + | SetWSMod of WaveSimModel + | UpdateWSModel of (WaveSimModel -> WaveSimModel) + | SetWSModAndSheet of (WaveSimModel*string) + | SetWSError of SimulationError option + | AddWaveSimFile of string * WaveSimModel + | SetSimulationGraph of SimulationGraph * FastSimulation + | SetSimulationBase of NumberBase + | IncrementSimulationClockTick of int + | EndSimulation + | EndWaveSim + | ChangeRightTab of RightTab + | SetHighlighted of ComponentId list * ConnectionId list + | SetSelWavesHighlighted of ConnectionId array + | SetClipboard of CanvasState + | SetCreateComponent of Component + | SetProject of Project + | UpdateProject of (Project -> Project) + | UpdateProjectWithoutSyncing of (Project->Project) + | ShowPopup of ((Msg -> Unit) -> PopupDialogData -> ReactElement) + | ClosePopup + | SetPopupDialogText of string option + | SetPopupDialogInt of int option + | SetPopupDialogTwoInts of (int64 option * IntMode * string option) + | SetPropertiesExtraDialogText of string option + | SetPopupDialogMemorySetup of (int * int * InitMemData * string option) option + | SetPopupMemoryEditorData of MemoryEditorData option + | SetPopupWaveSetup of MoreWaveSetup + | SetPopupProgress of PopupProgress option + | UpdatePopupProgress of (PopupProgress -> PopupProgress) + | SimulateWithProgressBar of SimulationProgress + | SetSelectedComponentMemoryLocation of int64 * int64 + | CloseDiagramNotification + | SetSimulationNotification of ((Msg -> unit) -> ReactElement) + | CloseSimulationNotification + | CloseWaveSimNotification + | SetFilesNotification of ((Msg -> unit) -> ReactElement) + | CloseFilesNotification + | SetMemoryEditorNotification of ((Msg -> unit) -> ReactElement) + | CloseMemoryEditorNotification + | SetPropertiesNotification of ((Msg -> unit) -> ReactElement) + | ClosePropertiesNotification + | SetTopMenu of TopMenu + | ReloadSelectedComponent of int + | SetDragMode of DragMode + | SetViewerWidth of int + | MenuAction of MenuCommand * (Msg -> unit) + | DiagramMouseEvent + | SelectionHasChanged + | SetWaveSimIsOutOfDate of bool + | SetIsLoading of bool + | SetWaveSimModel of Sheet: string * WSModel: WaveSimModel + | WaveSimulateNow + | InitiateWaveSimulation of (WSViewT * SimParamsT) + | SetLastSimulatedCanvasState of CanvasState option + | StartNewWaveSimulation of CanvasState + | UpdateScrollPos of bool + | SetLastScrollPos of float option + | SetRouterInteractive of bool + | CloseApp + | SetExitDialog of bool + | ExecutePendingMessages of int + | DoNothing + | StartUICmd of UICommandType + | FinishUICmd + | ExecCmd of Elmish.Cmd + | ExecFuncInMessage of (Model -> (Msg->Unit) -> Unit) * (Msg -> Unit) + | ExecFuncAsynch of (Unit -> Elmish.Cmd) + | ExecCmdAsynch of Elmish.Cmd + | SendSeqMsgAsynch of seq + + +//================================// +// Componenents loaded from files // +//================================// + +type Notifications = { + FromDiagram : ((Msg -> unit) -> Fable.React.ReactElement) option + FromSimulation : ((Msg -> unit) -> Fable.React.ReactElement) option + FromWaveSim : ((Msg -> unit) -> Fable.React.ReactElement) option + FromFiles : ((Msg -> unit) -> Fable.React.ReactElement) option + FromMemoryEditor : ((Msg -> unit) -> Fable.React.ReactElement) option + FromProperties : ((Msg -> unit) -> Fable.React.ReactElement) option +} + + + + + +type Model = { + // All the data for waveform simulation (separate for each sheet) + // TODO: remove the simulation error. + WaveSim : Map * (SimulationError option) + // which top-level sheet is used by wavesim + WaveSimSheet: string + + // Draw Canvas + Sheet: Sheet.Model + + // true during period when a sheet or project is loading + IsLoading: bool + + // if canvas is now different from that which is currently used by wave sim. + WaveSimulationIsOutOfDate: bool + + // last time check for changes was made + + LastChangeCheckTime: float + + // top-level canvas used for current wave simulation + LastSimulatedCanvasState: CanvasState option // reduced (without layout) canvas state + // used to determine whether current canvas has been saved (includes any change) + LastDetailedSavedState: CanvasState + // components and connections currently selected + + CurrentSelected: Component list * Connection list + // component ids and connection ids previously selected (used to detect changes) + LastSelectedIds: string list * string list + // last used bus width in bits - used as default in next component create dialog + LastUsedDialogWidth: int + // component currently selected in properties dialog + SelectedComponent : Component option // None if no component is selected. + // used during step simulation: simgraph for current clock tick + CurrentStepSimulationStep : Result option // None if no simulation is running. + // which of the tabbed panes is currentlky visible + RightPaneTabVisible : RightTab + // components and connections which are highlighted + Hilighted : (ComponentId list * ConnectionId list) * ConnectionId list + // Components and connections that have been selected and copied. + Clipboard : CanvasState + // Track the last added component + LastCreatedComponent : Component option + // used to enable "SAVE" button + SavedSheetIsOutOfDate : bool + // the project contains, as loadable components, the state of each of its sheets + CurrentProj : Project option + // function to create popup pane if present + PopupViewFunc : ((Msg -> Unit) -> PopupDialogData -> Fable.React.ReactElement) option + // data to populate popup (may not all be used) + PopupDialogData : PopupDialogData + // record containing functions that create react elements of notifications + Notifications : Notifications + // State of menus for sheets, projects etc + TopMenuOpenState : TopMenu + // used to determine whether mouse is currently dragging the divider, or used normally + DividerDragMode: DragMode + // viewer width in pixels altered by dragging the divider + WaveSimViewerWidth: int + // TODO - delete this, I think no longer needed + SimulationInProgress: SimActionT option + // if true highlight connections from wavesim editor + ConnsOfSelectedWavesAreHighlighted: bool + // true if wavesim scroll position needs checking + CheckWaveformScrollPosition: bool + // Contains a list of pending messages + Pending: Msg list + UIState: UICommandType Option +} + + + +let reduce (this: Model) = {| + RightTab = this.RightPaneTabVisible + Hilighted = this.Hilighted + Clipboard = this.Clipboard + SimulationIsStale = this.WaveSimulationIsOutOfDate + LastSimulatedCanvasState = this.LastSimulatedCanvasState + LastSelectedIds = this.LastSelectedIds + CurrentSelected = this.CurrentSelected + LastUsedDialogWidth = this.LastUsedDialogWidth + SelectedComponent= this.SelectedComponent + CreateComponent = this.LastCreatedComponent + HasUnsavedChanges = false + CurrProject = match this.PopupViewFunc with None -> false | _ -> true + PopupDialogData = this.PopupDialogData + TopMenu = this.TopMenuOpenState + DragMode = this.DividerDragMode + ViewerWidth = this.WaveSimViewerWidth + SimulationInProgress = this.SimulationInProgress + ConnsToBeHighlighted = this.ConnsOfSelectedWavesAreHighlighted + + |} + +let reduceApprox (this: Model) = {| + RightTab = this.RightPaneTabVisible + Clipboard = this.Clipboard + CurrProject = match this.PopupViewFunc with None -> false | _ -> true + SimulationIsStale = this.WaveSimulationIsOutOfDate + LastUsedDialogWidth = this.LastUsedDialogWidth + CreateComponent = this.LastCreatedComponent + HasUnsavedChanges = false + CurrProject = match this.PopupViewFunc with None -> false | _ -> true + PopupDialogData = this.PopupDialogData + DragMode = this.DividerDragMode + ViewerWidth = this.WaveSimViewerWidth + SimulationInProgress = this.SimulationInProgress + |} + +let mapOverProject defaultValue (model: Model) transform = + match model.CurrentProj with + | None -> defaultValue + | Some p -> transform p + + +let changeSimulationIsStale (b:bool) (m:Model) = + //printfn "Changing WaveSimulationIsStale to %A" b + { m with WaveSimulationIsOutOfDate = b} + + +let getComponentIds (model: Model) = + let extractIds ((comps,conns): Component list * Connection list) = + conns + |> List.map (fun comp -> ComponentId comp.Id) + + model.Sheet.GetCanvasState() + |> extractIds + |> Set.ofList + +//------------------------// +// Saving WaveSim Model // +//------------------------// + +/// get saveable record of waveform setup +let waveSimModel2SavedWaveInfo (wsMod: WaveSimModel) : SavedWaveInfo = + let pars = wsMod.SimParams + { + ClkWidth = pars.ClkSvgWidth + Cursor = pars.CursorTime + Radix = pars.WaveViewerRadix + LastClk = pars.LastClkTime + DisplayedPortIds = + wsMod.SimParams.DispNames + } + +/// setup current WaveSimModel from saved record +/// currently only the set of nets displayed by default and the radix is actually preserved +/// TODO: work out better idea for what should be preserved here. +/// NB - note that SavedWaveInfo can only be changed if code is added to make loading backwards compatible with +/// old designs +let savedWaveInfo2WaveSimModel (sWInfo: SavedWaveInfo) : WaveSimModel = + { + InitWaveSimGraph = None + SimDataCache = [||] + DispWaveSVGCache = {Top=[||]; Waves = Map.empty; Bottom = [||]} + AllWaves = Map.empty // will be reconstituted + SimParams = { + MoreNames = [] + DispNames = sWInfo.DisplayedPortIds // actually names not ids + ClkSvgWidth = 1.0 + CursorTime = 0u + WaveViewerRadix = sWInfo.Radix + LastClkTime = 9u + LastScrollPos = None + MoreWaves = [] + } + WSViewState =WSClosed + WSTransition =None + LastCanvasState = None + CursorBoxIsEmpty = false + + } + +let getSheetWaveSimOpt (model:Model) : WaveSimModel option = + model.CurrentProj + |> Option.bind (fun p -> Map.tryFind p.OpenFileName (fst model.WaveSim)) + + +let getSheetWaveSimErr (model:Model) = + model.CurrentProj + |> Option.map (fun p -> snd model.WaveSim) + |> Option.defaultValue None + +let getSheetWaveCanvasState (model:Model) = + getSheetWaveSimOpt model + |> Option.map (fun (ws:WaveSimModel) -> ws.LastCanvasState) + |> Option.defaultValue None + +let getSheetWaveNetList (model:Model) = + getSheetWaveCanvasState model + |> Option.map Helpers.getNetList + + +//----------------------Print functions-----------------------------// +//------------------------------------------------------------------// + + +let spComp (comp:Component) = + match comp.Type with + | Custom {Name=name; InputLabels=il; OutputLabels=ol} -> sprintf "Custom:%s(ins=%A:outs=%A)" name il il + | x -> sprintf "%A" x + +let spConn (conn:Connection) = + sprintf "Conn:%A" conn.Vertices + +let spState ((comps,conns):CanvasState) = + sprintf "Canvas<%A,%A>" (List.map spComp comps) (List.map spConn conns) + +let spCanvas (model : Model) = + model.Sheet.GetCanvasState() + |> spState + +let spComps comps = + sprintf "Comps%A" (List.map spComp comps) + +let spOpt f thingOpt = match thingOpt with |None -> "None" | Some x -> sprintf "Some %s" (f x) + +let spLdComp (ldc: LoadedComponent) = + sprintf "LDC<%s:%A:%s>" ldc.Name ldc.TimeStamp ((fst >>spComps) ldc.CanvasState) + +let spProj (p:Project) = + sprintf "PROJ||Sheet=%s\n%s||ENDP\n" p.OpenFileName (String.concat "\n" (List.map spLdComp p.LoadedComponents)) + +let pp model = + printf "\n%s\n%s" (spCanvas model) (spOpt spProj model.CurrentProj) + +let spMess msg = + match msg with + //| SetProject p -> sprintf "MSG<>ENDM" (spProj p) + //| SetLastSimulatedCanvasState canvasOpt-> sprintf "MSG>ENDM" (spOpt spState canvasOpt) + | x -> sprintf "MSG<<%20A>>ENDM" x + +let updateLdComps (name:string) (changeFun: LoadedComponent -> LoadedComponent) (ldComps: LoadedComponent list)= + ldComps + |> List.map (fun ldc -> if ldc.Name=name then changeFun ldc else ldc) + +let updateLdCompsWithCompOpt (newCompOpt:LoadedComponent option) (ldComps: LoadedComponent list) = + match newCompOpt with + | None -> ldComps // no update + | Some newComp -> + match List.tryFind (fun (ldc:LoadedComponent) -> ldc.Name = newComp.Name) ldComps with + | None -> newComp :: ldComps + | Some _ -> updateLdComps newComp.Name (fun _ -> newComp) ldComps + +let getCurrentWSMod(model: Model) = + let wsMap = fst model.WaveSim + Map.tryFind model.WaveSimSheet wsMap + +let getWSModelOrFail (model:Model) (errMsg: string) = + match getCurrentWSMod model with + | Some ws -> ws + | None -> failwithf "%s" errMsg + +let getCurrentWSModNextView(model:Model) = + getCurrentWSMod model + |> Option.bind (fun ws -> ws.WSTransition) + + +/// returns a string option representig the current file name if file is loaded, otherwise None +let getCurrFile (model: Model) = + match model.CurrentProj with + | Some proj -> Some proj.OpenFileName + | None -> None + +let getCurrSheets (model: Model) = + match model.CurrentProj with + | Some proj -> + proj.LoadedComponents + |> List.map (fun lc -> lc.Name) + |> Some + | None -> None + +let setWSMod (ws: WaveSimModel) (model: Model) = + match getCurrSheets model, model.WaveSimSheet with + | Some sheets, sheet when List.contains sheet sheets -> + { model with WaveSim = Map.add model.WaveSimSheet ws (fst model.WaveSim), + snd model.WaveSim } + | None,_ -> + printfn "\n\n******* What? trying to set wsmod when WaveSimSheet '%A' is not valid, project is closed" model.WaveSimSheet + model + | Some sheets, sheet -> + printfn "\n\n******* What? trying to set wsmod when WaveSimSheet '%A' is not valid, sheets=%A" model.WaveSimSheet sheets + model + + +let updateCurrentWSMod(updateFun: WaveSimModel -> WaveSimModel) (model: Model) = + match getCurrentWSMod model with + | None -> model // should this be an error? + | Some ws -> + let ws = updateFun ws + setWSMod ws model + + +let switchToWaveEditor (model:Model) dispatch = + match getCurrentWSMod model with + | None -> () + | Some ws when ws.WSViewState = WSClosed -> + printf "What? Can't switch to wave editor when wave sim is closed!" + | Some ws -> + dispatch <| SetWSMod {ws with WSViewState=WSViewT.WSEditorOpen} + dispatch <| ChangeRightTab WaveSim + \ No newline at end of file diff --git a/src/Renderer/UI/Notifications.fs b/src/Renderer/UI/Notifications.fs new file mode 100644 index 0000000..e42ea55 --- /dev/null +++ b/src/Renderer/UI/Notifications.fs @@ -0,0 +1,78 @@ +module Notifications + +//===============// +// Notifications // +//===============// + +open Fulma +open Fulma.Extensions.Wikiki + + +open Fable.React + +open DiagramStyle +open ModelType + +let errorNotification text closeMsg = + fun dispatch -> + let close = (fun _ -> dispatch closeMsg) + Notification.notification [ + Notification.Color IsDanger + Notification.Props [ notificationStyle ] + ] [ + Delete.delete [ Delete.OnClick close ] [] + str text + ] +let successNotification text closeMsg = + fun dispatch -> + let close = (fun _ -> dispatch closeMsg) + Notification.notification [ + Notification.Color Color.IsSuccess + Notification.Props [ notificationStyle ] + ] [ + Delete.delete [ Delete.OnClick close ] [] + str text + ] + +let errorPropsNotification text = errorNotification text ClosePropertiesNotification +let errorFilesNotification text = errorNotification text CloseFilesNotification +let successSimulationNotification text = successNotification text CloseSimulationNotification +let successPropertiesNotification text = successNotification text ClosePropertiesNotification + +let warningNotification text closeMsg = + fun dispatch -> + let close = (fun _ -> dispatch closeMsg) + Notification.notification [ + Notification.Color IsWarning + Notification.Props [ notificationStyle ] + ] [ + Delete.delete [ Delete.OnClick close ] [] + str text + ] + +let warningPropsNotification text = warningNotification text ClosePropertiesNotification +let warningSimNotification text = warningNotification text CloseSimulationNotification + +let displayAlertOnError (dispatch: Msg -> Unit) res = + match res with + | Error e -> + dispatch <| SetFilesNotification (errorFilesNotification e) + | _ -> () + +let viewNotifications model dispatch = + let sheetNotifications = + match model.Sheet.GetNotifications with + | Some msg -> Some <| errorNotification msg CloseDiagramNotification + | None -> None + + [ //model.Notifications.FromDiagram + sheetNotifications + model.Notifications.FromSimulation + model.Notifications.FromFiles + model.Notifications.FromMemoryEditor + model.Notifications.FromProperties ] + |> List.tryPick id + |> function + | Some notification -> notification dispatch + | None -> div [] [] + diff --git a/src/Renderer/UI/PopupView.fs b/src/Renderer/UI/PopupView.fs new file mode 100644 index 0000000..8b4102f --- /dev/null +++ b/src/Renderer/UI/PopupView.fs @@ -0,0 +1,774 @@ +(* + PopupView.fs + + This module provides a handy interface to create popups and notifications. + Popups and notifications appear similar, but are actually quite different: + - Model.Popup is a function that takes a STRING and produces a ReactElement. + - Model.Notifications are a functions that take DISPATCH and produce a + ReactElement. + This means that at the moment of creation, a popup must already have the + dispatch function, while the notification does not. This, in turn, means + that notifications can be created from messages dispatched by JS code. +*) + + +(* + +Popups must be careful in handling internal state because this cannot be updated by +dispatch as would be expected. + +viewpopup model -> +model.Popup model.PopupDialogData -> (PopupDialogData contains memory setup data (widths) but not memory component data) + +model.Popup <-- + unclosablePopup maybeTitle (body memoryEditorData) maybeFoot extraStyle + (from showMemoryEditorPopup maybeTitle body maybeFoot extraStyle dispatch) + + Here body contains the relevant state and is generated from: + + let openMemoryEditor memory compId model dispatch : unit = + .... + let body = makeEditor memory compId model dispatch + .... + showMemoryEditorPopup (Some title) body (Some foot) popupExtraStyle dispatch + + +Although showPopup + +*) + +module PopupView + +open Fulma +open Fulma.Extensions.Wikiki +open Fable.React +open Fable.React.Props + +open JSHelpers +open Helpers +open ModelType +open CommonTypes +open EEExtensions + + +//=======// +//HELPERS// +//=======// + +let openInBrowser url = + (fun _ -> Electron.Electron.electron.shell.openExternal url |> ignore) + +let extractLabelBase (text:string) : string = + text.ToUpper() + |> Seq.takeWhile (fun ch -> ch <> '(') + |> Seq.filter (fun ch -> System.Char.IsLetterOrDigit ch || ch = '_') + |> Seq.map (fun ch -> ch.ToString()) + |> String.concat "" + +let formatLabelAsBus (width:int) (text:string) = + let text' = extractLabelBase text + match width with + | 1 -> text' + | _ -> sprintf "%s(%d:%d)" (text'.ToUpper()) (width-1) 0 + + +let formatLabelFromType compType (text:string) = + let text' = extractLabelBase text + match compType with + | Input 1 | Output 1 -> text' + //| Input width | Output width -> sprintf "%s(%d:%d)" text' (width-1) 0 + | _ -> text' + + +let formatLabel (comp:Component) (text:string) = + formatLabelFromType comp.Type (text:string) + +// TODO: removed formatLabel for now +let setComponentLabel model (sheetDispatch) (comp:Component) (text:string) = + // let label = formatLabel comp text + let label = text.ToUpper() // TODO + + model.Sheet.ChangeLabel sheetDispatch (ComponentId comp.Id) label + //model.Diagram.EditComponentLabel comp.Id label + + + +//========// +// Popups // +//========// + +let getText (dialogData : PopupDialogData) = + Option.defaultValue "" dialogData.Text + +let getInt (dialogData : PopupDialogData) = + Option.defaultValue 1 dialogData.Int + +let getInt2 (dialogData : PopupDialogData) : int64 = + Option.defaultValue 0L dialogData.Int2 + +let getMemorySetup (dialogData : PopupDialogData) wordWidthDefault = + Option.defaultValue (4,wordWidthDefault,FromData,None) dialogData.MemorySetup + +let getMemoryEditor (dialogData : PopupDialogData) = + Option.defaultValue + { Address = None; OnlyDiff = false; NumberBase = Hex ; Start = 0L} + dialogData.MemoryEditorData + +/// Unclosable popup. +let unclosablePopup maybeTitle (body:ReactElement) (maybeFoot: ReactElement option) extraStyle = + fun dispatch -> + let propStyle extraStyle = Props [Style (UserSelect UserSelectOptions.None :: extraStyle)] + let head = + match maybeTitle with + | None -> div [] [] + | Some title -> Modal.Card.head [propStyle []] [ Modal.Card.title [] [ str title ] ] + let foot = + match maybeFoot with + | None -> div [] [] + | Some foot -> Modal.Card.foot [] [ foot ] + Modal.modal [ Modal.IsActive true ] [ + Modal.background [] [] + Modal.Card.card [Props [Style extraStyle]] [ + head + Modal.Card.body [Props [Style [UserSelect UserSelectOptions.None]]] [ body ] + foot + ] + ] + +let noDispatch (react: ReactElement) = + fun (_dispatch: Msg->Unit) -> react + +let mapNoDispatch (optReact: ReactElement option) = + Option.map noDispatch optReact + +let showMemoryEditorPopup maybeTitle body maybeFoot extraStyle dispatch = + fun _ dialogData-> + let memoryEditorData = getMemoryEditor dialogData + unclosablePopup maybeTitle (body memoryEditorData) maybeFoot extraStyle dispatch + |> ShowPopup |> dispatch + +let private buildPopup title body foot close extraStyle = + fun (dispatch:Msg->Unit) (dialogData : PopupDialogData) -> + Modal.modal [ Modal.IsActive true; Modal.CustomClass "modal1"] [ + Modal.background [ Props [ OnClick (close dispatch)]] [] + Modal.Card.card [ Props [ + Style ([ + OverflowY OverflowOptions.Auto + OverflowX OverflowOptions.Visible + UserSelect UserSelectOptions.None + ] @ extraStyle) + ] ] [ + Modal.Card.head [] [ + Modal.Card.title [] [ str title ] + Delete.delete [ Delete.OnClick (close dispatch) ] [] + ] + Modal.Card.body [Props [Style [ OverflowY OverflowOptions.Visible ;OverflowX OverflowOptions.Visible]]] [ body dispatch dialogData ] + Modal.Card.foot [] [ foot dispatch dialogData ] + ] + ] + + + +let showWaveSetupPopup maybeTitle (popupBody: MoreWaveSetup option ->ReactElement) maybeFoot extraStyle dispatch = + fun _ (dialogData:PopupDialogData)-> + printfn "starting morewavesetup popup function" + unclosablePopup maybeTitle (popupBody dialogData.WaveSetup) maybeFoot extraStyle dispatch + |> ShowPopup |> dispatch + + +/// Body and foot are functions that take a string of text and produce a +/// reactElement. The meaning of the input string to those functions is the +/// content of PopupDialogText (i.e. in a dialog popup, the string is the +/// current value of the input box.). +let private dynamicClosablePopup title (body:PopupDialogData -> ReactElement) (foot: PopupDialogData -> ReactElement) (extraStyle: CSSProp list) (dispatch: Msg->Unit) = + buildPopup title (fun _ -> body) (fun _ -> foot) (fun dispatch _ -> dispatch ClosePopup) extraStyle + |> ShowPopup |> dispatch + +/// As dynamicClosablePopup but accept functions of dispatch and return the popup function +let private dynamicClosablePopupFunc title body foot extraStyle = + buildPopup title body foot (fun dispatch _ -> dispatch ClosePopup) extraStyle + +/// Popup to track progress of some long operation. Progress is captured via two dialog integers, current and max number. +/// Typically the number is number of steps. +/// The popup display is controlled by model.PopupDialog integers. Progress model updates must change these. +let dynamicProgressPopupFunc title (cancel: (Msg -> Unit) -> Unit) = + let body (dispatch:Msg->Unit) (dialog:PopupDialogData) = + let n = Option.defaultValue 0 dialog.Int + Progress.progress + [ Progress.Color IsSuccess + Progress.Value n + Progress.Max (int (Option.defaultValue 100L (dialog.Int2))) ] + [ str $"{n}"] + + let foot (dispatch:Msg->Unit) (dialog:PopupDialogData) = + Level.level [ Level.Level.Props [ Style [ Width "100%" ] ] ] [ + Level.left [] [] + Level.right [] [ + Level.item [] [ + Button.button [ + Button.Color IsLight + Button.OnClick (fun _ -> + cancel dispatch + dispatch ClosePopup) + ] [ str "Cancel" ] + ] + ] + ] + + buildPopup title body foot (fun dispatch _ -> dispatch ClosePopup) [] + +/// Create a popup and add it to the page. Body and foot are static content. +/// Can be closed by the ClosePopup message. +let closablePopup title body foot extraStyle dispatch = + dynamicClosablePopup title (fun _ -> body) (fun _ -> foot) extraStyle dispatch + +/// As closablePopup but accept functions and return the popup function +/// Can be closed by the ClosePopup message. +let closablePopupFunc title (body:(Msg->Unit)->ReactElement) (foot:(Msg->Unit)->ReactElement) extraStyle = + dynamicClosablePopupFunc title (fun dispatch _ -> body dispatch) (fun dispatch _ -> foot dispatch) extraStyle + +/// Create the body of a dialog Popup with only text. +let dialogPopupBodyOnlyText before placeholder dispatch = + fun (dialogData : PopupDialogData) -> + div [] [ + before dialogData + Input.text [ + Input.Props [AutoFocus true; SpellCheck false] + Input.Placeholder placeholder + Input.OnChange (getTextEventValue >> Some >> SetPopupDialogText >> dispatch) + ] + ] + +/// Create the body of a dialog Popup with only an int. +let dialogPopupBodyOnlyInt beforeInt intDefault dispatch = + intDefault |> Some |> SetPopupDialogInt |> dispatch + fun (dialogData : PopupDialogData) -> + div [] [ + beforeInt dialogData + br [] + Input.number [ + Input.Props [Style [Width "60px"]; AutoFocus true] + Input.DefaultValue <| sprintf "%d" intDefault + Input.OnChange (getIntEventValue >> Some >> SetPopupDialogInt >> dispatch) + ] + ] +/// Create the body of a dialog Popup with two ints. +let dialogPopupBodyTwoInts (beforeInt1,beforeInt2) (intDefault1,intDefault2) (width2:string) dispatch = + + let setPopupTwoInts (whichInt:IntMode, optText) = + fun (n:int64) -> (Some n, whichInt, optText) |> SetPopupDialogTwoInts |> dispatch + + setPopupTwoInts (FirstInt,None) (int64 intDefault1) + setPopupTwoInts (SecondInt, None) intDefault2 + + fun (dialogData : PopupDialogData) -> + div [] [ + beforeInt1 dialogData + br [] + Input.number [ + Input.Props [Style [Width "60px"]; AutoFocus true] + Input.DefaultValue <| sprintf "%d" intDefault1 + Input.OnChange (getIntEventValue >> int64 >> setPopupTwoInts (FirstInt,None)) + ] + br [] + beforeInt2 dialogData + br [] + Input.text [ + Input.Props [Style [Width width2]; AutoFocus true] + Input.DefaultValue <| sprintf "%d" intDefault2 + Input.OnChange (fun ev -> + let text = getTextEventValue ev + let n = getInt64EventValue ev + setPopupTwoInts(SecondInt, Some text) n) + ] + ] + +/// Create the body of a dialog Popup with both text and int. +let dialogPopupBodyTextAndInt beforeText placeholder beforeInt intDefault dispatch = + intDefault |> Some |> SetPopupDialogInt |> dispatch + fun (dialogData : PopupDialogData) -> + div [] [ + beforeText dialogData + Input.text [ + Input.Props [AutoFocus true; SpellCheck false] + Input.Placeholder placeholder + Input.OnChange (getTextEventValue >> Some >> SetPopupDialogText >> dispatch) + ] + br [] + br [] + beforeInt dialogData + br [] + Input.number [ + Input.Props [Style [Width "60px"]] + Input.DefaultValue <| sprintf "%d" intDefault + Input.OnChange (getIntEventValue >> Some >> SetPopupDialogInt >> dispatch) + ] + ] + +/// Create the body of a dialog Popup with both text and int. +let dialogPopupBodyIntAndText beforeText placeholder beforeInt intDefault dispatch = + intDefault |> Some |> SetPopupDialogInt |> dispatch + fun (dialogData : PopupDialogData) -> + div [] [ + beforeInt dialogData + br [] + Input.number [ + Input.Props [Style [Width "60px"]] + Input.DefaultValue <| sprintf "%d" intDefault + Input.OnChange (getIntEventValue >> Some >> SetPopupDialogInt >> dispatch) + ] + br [] + br [] + beforeText dialogData + Input.text [ + Input.Props [AutoFocus true; SpellCheck false] + Input.Placeholder placeholder + Input.OnChange (getTextEventValue >> Some >> SetPopupDialogText >> dispatch) + ] + + ] + +let makeSourceMenu + (dialog: PopupDialogData) + (dispatch: Msg -> Unit) = + + let popupKey = + match dialog.MemorySetup with + | Some(_,_, key,_) -> key + | None -> + printfn "No memory setup" + FromData + + let onSelect key = + let n1,n2, _,_ = getMemorySetup dialog 1 + printfn $"Select {key}" + dispatch <| ModelType.SetPopupDialogMemorySetup (Some(n1,n2,key,None)) + + let files = + FilesIO.readFilesFromDirectoryWithExtn dialog.ProjectPath ".ram" + |> List.map (FilesIO.removeExtn ".ram" >> Option.get) + + let inputValidate text = + (text = "" || + List.exists ((=) text) files || + not (Seq.forall System.Char.IsLetterOrDigit (text)) || + not (System.Char.IsLetter (char text[0]))) + |> not + + let fileEntryBox = + let n1,n2, _,_ = getMemorySetup dialog 1 + match popupKey with + | ToFile fName | ToFileBadName fName -> + Input.text [ + Input.Props [Style [MarginLeft "2em"]] + Input.DefaultValue fName + Input.Placeholder "Enter file name" + Input.Color (if inputValidate fName then IsSuccess else IsDanger) + Input.OnChange + (getTextEventValue + >> (fun newName -> + let newKey = if inputValidate newName then ToFile newName else ToFileBadName newName + dispatch <| ModelType.SetPopupDialogMemorySetup (Some(n1,n2, newKey,None) ) ) ) + ] + | _ -> str "" + + + let existingFiles = + List.map FromFile files + + /// Create one item in the drop-down RAM source menu + let printSource inList key = + + let hSpace width = span [Style [Display DisplayOptions.InlineBlock; Width width]] [] + + let questionIcon = str "\u003F" + + let tip txt = + span [ + Style [Float FloatOptions.Right] + HTMLAttr.ClassName $"{Tooltip.ClassName} {Tooltip.IsMultiline}" + Tooltip.dataTooltip txt + ] + [ + Text.span [ + Modifiers [ + Modifier.TextWeight TextWeight.Bold + Modifier.TextColor IsLight + Modifier.BackgroundColor IsPrimary] + Props [ + Style [ + Display DisplayOptions.InlineBlock + Width "50px" + TextAlign TextAlignOptions.Center]] + ] [questionIcon] ] + + let (aWidth,dWidth,_,_) = getMemorySetup dialog 1 + + let multiplyTip mType = + tip ($"Dout = Addr[{aWidth-1}:{aWidth/2}] * Addr[{aWidth/2-1}:0]. \ + Multiplication is {mType}." + + (if dWidth < aWidth then + $"The result will be truncated to bits [{dWidth-1}:0] on Dout." + else + "")) + + match key with + | FromData -> [str "Enter data later"] + | SignedMultiplier -> [ + str "Signed multiply" + hSpace "30px" + multiplyTip "signed" + ] + | UnsignedMultiplier -> [ + str "Unsigned multiply "; + hSpace "30px" + multiplyTip "unsigned" + ] + | ToFile _ | ToFileBadName _ -> // not needed - direct write from properties is better + [ str "Enter data later - create a new file " ; if inList then str "" else fileEntryBox] + | FromFile s -> [str $"{s}.ram"] + + let sources = + [ + FromData + SignedMultiplier + UnsignedMultiplier + //ToFileBadName "" + ] @ existingFiles + + + let isActiveFile key = + match popupKey, key with + | ToFile _, ToFile _ -> true + | ToFileBadName _,ToFileBadName _ -> true + | popup, key -> key = popup + + let menuItem (key) = + let react = printSource true key + Menu.Item.li + [ Menu.Item.IsActive (isActiveFile key) + Menu.Item.OnClick (fun _ -> onSelect key) ] react + + Dropdown.dropdown [ Dropdown.IsUp; Dropdown.IsHoverable; ] + [ Dropdown.trigger [ ] + [ Button.button [Button.Color IsPrimary; Button.IsLight] (printSource false popupKey) ] + Dropdown.menu [Props [Style [Width "300px"] ]] + [ Dropdown.content [Props [Style [ZIndex 1000]] ] + [ Dropdown.Item.div [ ] [ + Menu.menu [] + [ Menu.list [] (List.map menuItem sources) ] + ] ] ] ] + + +/// Create the body of a memory dialog popup: asks for AddressWidth and +/// WordWidth, two integers. +let dialogPopupBodyMemorySetup intDefault dispatch = + + //Some (4, intDefault, FromData, None) + //|> SetPopupDialogMemorySetup |> dispatch + fun (dialogData : PopupDialogData) -> + let setup = + match dialogData.MemorySetup with + | None -> + let setup = getMemorySetup dialogData intDefault + dispatch <| SetPopupDialogMemorySetup (Some setup) + setup + | Some setup -> + setup + // needed in case getMemorySetup has delivered default values not yet stored + if dialogData.MemorySetup <> Some setup then + dispatch <| SetPopupDialogMemorySetup (Some setup) + let addressWidth, wordWidth, source, errorOpt = setup + let dataSetupMess = + match source with + | FromData -> $"You will be able to set up memory content later from the component Properties menu" + | FromFile x -> $"Memory content is fixed by the '{x}.ram' file in the project directory" + | ToFile x -> $"You will be able to set up memory content later from the component Properties menu, \ + it will be written to the '{x}.ram file in the project directory" + | ToFileBadName x -> "" + | _ -> "Memory initial data is determined by the requested multiplication" + div [] [ + str $"How many bits should be used to address the data in memory?" + br []; + str <| sprintf "%d bits yield %d memory locations." addressWidth (pow2int64 addressWidth) + br []; br [] + Input.number [ + Input.Props [Style [Width "60px"] ; AutoFocus true] + Input.DefaultValue (sprintf "%d" addressWidth) + Input.OnChange (getIntEventValue >> fun newAddrWidth -> + Some (newAddrWidth, wordWidth, source, None) + |> SetPopupDialogMemorySetup |> dispatch + ) + ] + br [] + br [] + str "How many bits should each memory word contain?" + br []; br []; + Input.number [ + Input.Props [Style [Width "60px"]] + Input.DefaultValue (sprintf "%d" wordWidth) + Input.OnChange (getIntEventValue >> fun newWordWidth -> + Some (addressWidth, newWordWidth, source, None) + |> SetPopupDialogMemorySetup |> dispatch + ) + ] + br [] + br [] + makeSourceMenu dialogData dispatch + br [] + br [] + str dataSetupMess + br [] + match errorOpt with + | Some msg -> div [Style [Color "red"]] [ str msg] + | _ -> br [] + + ] + +/// Popup with an input textbox and two buttons. +/// The text is reflected in Model.PopupDialogText. +let dialogPopup title body buttonText buttonAction isDisabled dispatch = + let foot = + fun (dialogData : PopupDialogData) -> + Level.level [ Level.Level.Props [ Style [ Width "100%" ] ] ] [ + Level.left [] [] + Level.right [] [ + Level.item [] [ + Button.button [ + Button.Color IsLight + Button.OnClick (fun _ -> + dispatch ClosePopup + dispatch FinishUICmd) //In case user presses cancel on 'rename sheet' popup + ] [ str "Cancel" ] + ] + Level.item [] [ + Button.button [ + Button.Disabled (isDisabled dialogData) + Button.Color IsPrimary + Button.OnClick (fun _ -> buttonAction dialogData) + ] [ str buttonText ] + ] + ] + ] + dynamicClosablePopup title body foot [] dispatch + +/// A static confirmation popup. +let confirmationPopup title body buttonText buttonAction dispatch = + let foot = + Level.level [ Level.Level.Props [ Style [ Width "100%" ] ] ] [ + Level.left [] [] + Level.right [] [ + Level.item [] [ + Button.button [ + Button.Color IsLight + Button.OnClick (fun _ -> dispatch ClosePopup) + ] [ str "Cancel" ] + ] + Level.item [] [ + Button.button [ + Button.Color IsPrimary + Button.OnClick buttonAction + ] [ str buttonText ] + ] + ] + ] + closablePopup title body foot [] dispatch + +/// A static choice dialog popup returning the popup function +let choicePopupFunc + title + (body:(Msg->Unit)->ReactElement) + buttonTrueText + buttonFalseText + (buttonAction: bool -> (Msg->Unit) -> Browser.Types.MouseEvent -> Unit) = + let foot dispatch = + Level.level [ Level.Level.Props [ Style [ Width "100%" ] ] ] [ + Level.left [] [] + Level.right [] [ + Level.item [] [ + Button.button [ + Button.Color IsLight + Button.OnClick (buttonAction false dispatch) + ] [ str buttonFalseText ] + ] + Level.item [] [ + Button.button [ + Button.Color IsPrimary + Button.OnClick (buttonAction true dispatch) + ] [ str buttonTrueText ] + ] + ] + ] + closablePopupFunc title body foot [] + +/// A static choice dialog popup. +let choicePopup title (body:ReactElement) buttonTrueText buttonFalseText (buttonAction: bool -> Browser.Types.MouseEvent -> Unit) dispatch = + let popup = choicePopupFunc title (fun _ -> body) buttonTrueText buttonFalseText (fun bool dispatch-> buttonAction bool) + dispatch <| ShowPopup popup + +/// a popup diaplysing a progress bar +let progressPopup (legend: Model -> PopupProgress -> ReactElement) (model: Model) (dispatch: Msg->Unit) = + let extraStyle = [] + let pp = Option.get model.PopupDialogData.Progress + let body _ _ = + div [] [ + legend model pp + Fulma.Progress.progress [Progress.Value pp.Value; Progress.Max pp.Max; Progress.Color Color.IsPrimary ] [] + ] + let foot _ _ = div [] [] + let close dispatch _ = + dispatch <| SetPopupProgress None + buildPopup pp.Title body foot close extraStyle dispatch model.PopupDialogData + + +let simulationLegend (model:Model) (pp: PopupProgress) = + match model.CurrentStepSimulationStep with + | Some (Ok simData) -> + let speed = pp.Speed + str <| $"simulation speed: %6.0f{speed} component-clocks / ms" + | _ -> div [] [] + + +/// Display popup, if any is present. +/// A progress popup, if present, overrides any other active popup. +let viewPopup model dispatch = + match model.PopupDialogData.Progress, model.PopupViewFunc with + | None, None -> div [] [] + | Some amount, _ -> + progressPopup simulationLegend model dispatch + | None, Some popup -> popup dispatch model.PopupDialogData + + + +let viewInfoPopup dispatch = + let makeH h = + Text.span [ Modifiers [ + Modifier.TextSize (Screen.Desktop, TextSize.Is6) + Modifier.TextWeight TextWeight.Bold + ] ] [str h; br []] + let styledSpan styles txt = span [Style styles] [str <| txt] + let bSpan txt = styledSpan [FontWeight "bold"] txt + let iSpan txt = styledSpan [FontStyle "italic"] txt + let tSpan txt = span [] [str txt] + + let title = "ISSIE: Interactive Schematic Simulator and Integrated Editor" + + let about = div [] [ + makeH "Version" + str Version.VersionString + br []; br [] + makeH "Acknowledgments" + str "ISSIE was created by Marco Selvatici (EIE 3rd year) as his BEng final year project. \ + The waveform viewer was created \ + by Edoardo Santi (EEE 3rd year) during Summer UROP work. The new schematic editor \ + was written as 2021 coursework by HLP students in EEE, \ + and particularly Team 4. The new editor was integrated and the application enhanced \ + by Jo Merrick (EIE 3rd year) for her BEng final year project." + br []; br [] + makeH "Technology" + Text.span [] [ + str "ISSIE is written in " + a [OnClick <| openInBrowser "https://fsharp.org/"] [str "F#"] + str " compiled to Javascript by " + a [OnClick <| openInBrowser "https://fable.io/"] [str "FABLE"] + str " and running under the " + a [OnClick <| openInBrowser "https://www.electronjs.org/"] [str "Electron"] + str " framework" + ] + ] + + let intro = div [] [ + str "Issie designs are made of one or more sheets. Each sheet contains components and Input and Output Connectors. \ + If you have a single sheet that is your complete design. Otherwise any \ + sheet can include as a single component the hardware defined in another sheet by adding a 'custom component' \ + from the My Project section of the Catalog. \ + Multiple copies of other sheets can be added in this way. \ + Top-level sheets which are not used as subsheets are bolded on the sheet menu." + br []; br [] + str "Issie has two types of simulation: The Simulation Tab is used mainly for combinational logic and simple clocked logic: \ + the top 'Waveforms >>' button works with clocked circuits and displays waveforms. Use whichever works for you." + br []; br []; + str "In Issie all clocked components use the same clock signal Clk. \ + Clk connections are not shown: all Clk ports are + automatically connected together. In the waveform display active clock edges, 1 per clock cycle, are indicated \ + by vertical lines through the waveforms. The clock waveform has two edges for each clock cycle and is not shown." + br [] ; br []; + button + [OnClick <| openInBrowser "https://github.com/tomcl/ISSIE"] + [ str "See the Issie Github Repo for more information"] + br [] ; br [] ] + + let bugReport = + let oTextList txtL = Content.content [] [Content.Ol.ol [] (List.map (fun txt -> li [] [str txt]) txtL)] + div [] [ + str + "If you think Issie is not working it is very helpful if you can give us details: we usually answer \ + and fix bugs, if they exist, very quickly. Before you contact us, look at the list below and answer as much \ + as possible to make your Bug Report (sometimes it is not all possible, send what you can)." + oTextList + [ + "Which version of Issie (Info tab, About Issie)" + "Which platform (Windows, Macos)" + "What did you do that led to unexpected behaviour?" + "What result did you expect?" + "What result did you get?" + "What project files caused this, the top-level sheet? Enclose project as zipped file \ + deleting the maybe large backup directory when you zip." + "If you can reproduce the bug yourself, try opening dev tools (Ctrl-Shift-I). You can do this after the bug happens. 2/3 \ + of problems result in error messages displayed there. Screenshot the error and its backtrace and send it." + "What precise actions (if you know them) led to the bug after loading this project" + ] + ] + let keyOf2 s1 s2 = span [] [bSpan s1; tSpan " + "; bSpan s2] + let keyOf3 s1 s2 s3 = span [] [bSpan s1; tSpan " + "; bSpan s2 ; tSpan " + "; bSpan s3] + let rule = hr [Style [MarginTop "0.5em"; MarginBottom "0.5em"]] + let keys = div [] [ + makeH "Keyboard & mouse gesture shortcuts - also available on top menus" + span [Style [FontStyle "Italic"]] [str "On Mac use Cmd instead of Ctrl."] + ul [] [ + li [] [rule; tSpan "Save: "; keyOf2 "Ctrl" "S"; rule] + li [] [tSpan "Select all: " ; keyOf2 "Ctrl" "A"] + li [] [tSpan "Copy selected diagram items: " ; keyOf2 "Ctrl" "C"] + li [] [tSpan "Paste diagram items: " ; keyOf2 "Ctrl" "V"; rule] + li [] [tSpan "Undo last diagram action: " ; keyOf2 "Ctrl" "Z"] + li [] [tSpan "Redo last diagram action: " ; keyOf2 "Ctrl" "Y"; rule] + li [] [tSpan "Zoom application in: " ; keyOf3 "Ctrl" "Shift" "="] + li [] [tSpan "Zoom application out: " ; keyOf3 "Ctrl" "Shift" "-"; rule] + li [] [tSpan "Zoom canvas in/out: " ; keyOf2 "Ctrl" "MouseWheel"] + li [] [tSpan "Zoom canvas in: " ; keyOf2 "Shift" "="] + li [] [tSpan "Zoom canvas out: " ; keyOf2 "Shift" "-"; rule] + li [] [tSpan "Zoom circuit to fit screen: " ; keyOf2 "Ctrl" "W"] + li [] [tSpan "Scroll: " ; bSpan "Two-finger scrolling on touchpad"] + ] ] + let body (dialogData:PopupDialogData) = + + let tab = dialogData.Int + + div [] [ + Tabs.tabs + [ Tabs.IsFullWidth + Tabs.IsBoxed ] + [ Tabs.tab [ Tabs.Tab.IsActive (tab = Some 0) ] + [ a [ OnClick (fun _ -> dispatch <| SetPopupDialogInt (Some 0)) ] + [ str "About Issie" ] ] + Tabs.tab [ Tabs.Tab.IsActive (tab = Some 2) ] + [ a [ OnClick (fun _ -> dispatch <| SetPopupDialogInt (Some 2)) ] + [ str "Introduction" ] ] + Tabs.tab [ Tabs.Tab.IsActive (tab = Some 1) ] + [ a [ OnClick (fun _ -> dispatch <| SetPopupDialogInt (Some 1)) ] + [ str "Keyboard Shortcuts" ] ] + Tabs.tab [ Tabs.Tab.IsActive (tab = Some 3) ] + [ a [ OnClick (fun _ -> dispatch <| SetPopupDialogInt (Some 3)) ] + [ str "Bug Reports" ] ] ] + + match tab with + | Some 0 -> about + | Some 1 -> keys + | Some 2 -> intro + | Some 3 -> bugReport + | _ -> dispatch <| SetPopupDialogInt (Some 0) + ] + + let foot _ = div [] [] + dynamicClosablePopup title body foot [Width 800] dispatch + diff --git a/src/Renderer/UI/SelectedComponentView.fs b/src/Renderer/UI/SelectedComponentView.fs new file mode 100644 index 0000000..4d292df --- /dev/null +++ b/src/Renderer/UI/SelectedComponentView.fs @@ -0,0 +1,416 @@ +(* + SelectedComponentView.fs + + View for the selected component in the right tab. +*) + +module SelectedComponentView + +open Fulma +open Fable.React +open Fable.React.Props + +open JSHelpers +open ModelType +open CommonTypes +open MemoryEditorView +open PopupView +open Notifications + +let private readOnlyFormField name body = + Field.div [] [ + Label.label [] [ str name ] + body + ] + +let private textFormField isRequired name defaultValue onChange = + Field.div [] [ + Label.label [] [ str name ] + Input.text [ + Input.Props [ SpellCheck false; Name name; AutoFocus true; Style [ Width "200px"]] + Input.DefaultValue defaultValue + Input.Type Input.Text + Input.Placeholder (if isRequired then "Name (required)" else "Name (optional)") + Input.OnChange (getTextEventValue >> onChange) + ] + ] + +let private textFormFieldSimple name defaultValue onChange = + Field.div [] [ + Label.label [] [ str name ] + Input.text [ + Input.Props [ SpellCheck false; Name name; AutoFocus true; Style [ Width "200px"]] + Input.DefaultValue defaultValue + Input.Type Input.Text + Input.OnChange (getTextEventValue >> onChange) + ] + ] + + +let private intFormField name (width:string) defaultValue minValue onChange = + Field.div [] [ + Label.label [] [ str name ] + Input.number [ + Input.Props [Style [Width width]; Min minValue] + Input.DefaultValue <| sprintf "%d" defaultValue + Input.OnChange (getIntEventValue >> onChange) + ] + ] + +let private int64FormField name (width:string) defaultValue minValue onChange = + Field.div [] [ + Label.label [] [ str name ] + Input.number [ + Input.Props [Style [Width width]; Min minValue] + Input.DefaultValue <| sprintf "%d" defaultValue + Input.OnChange (getInt64EventValue >> onChange) + ] + ] + +let private intFormFieldNoMin name defaultValue onChange = + Field.div [] [ + Label.label [] [ str name ] + Input.number [ + Input.Props [Style [Width "60px"]] + Input.DefaultValue <| sprintf "%d" defaultValue + Input.OnChange (getIntEventValue >> onChange) + ] + ] + +let private int64FormFieldNoMin name (defaultValue:int64) (currentText:string option) onChange = + Field.div [] [ + Label.label [] [ str name ] + Input.text [ + Input.Props [Style [Width "180px"]] + Input.DefaultValue <| Option.defaultValue $"{defaultValue}" currentText + Input.OnChange (getTextEventValue >> onChange) + ] + ] + + +let getInitSource (mem: Memory1) = + let a = mem.AddressWidth + match mem.Init with + | SignedMultiplier -> + $"Dout = (signed) addr({a-1}:{a/2}) * addr({a/2-1}:0)" + | UnsignedMultiplier -> + $"Dout = (unsigned) addr({a-1}:{a/2}) * addr({a/2-1}:0)" + | FromData -> + "See Memory Viewer" + | FromFile name | ToFile name | ToFileBadName name -> + $"From '{name}.ram' file" + + +let private makeMemoryInfo descr mem compId cType model dispatch = + let projectPath = (Option.get model.CurrentProj).ProjectPath + div [] [ + str descr + br []; br [] + str <| sprintf "Address width: %d bit(s)" mem.AddressWidth + br [] + str <| sprintf "Number of elements: %d" (1UL <<< mem.AddressWidth) + br [] + str <| sprintf "Word width: %d bit(s)" mem.WordWidth + br [] + str <| sprintf "%sData: %s" + (match cType with + | RAM1 _ | AsyncRAM1 _ -> "Initial " + | ROM1 _ | AsyncROM1 _ -> "" + | _ -> failwithf $"What - wrong component type ({cType} here") + (getInitSource mem) + br [] + //makeSourceMenu model (Option.get model.CurrentProj) mem dispatch + br []; br [] + Button.button [ + Button.Color IsPrimary + Button.OnClick (fun _ -> openMemoryEditor mem compId model dispatch) + ] [str "View/Edit memory content"] + br []; br []; + Button.button [ + Button.Color IsPrimary + Button.OnClick (fun _ -> + FilesIO.openWriteDialogAndWriteMemory mem projectPath + |> (function + | None -> () + | Some path -> + let note = successPropertiesNotification $"Memory content written to '{path}'" + dispatch <| SetPropertiesNotification note) + ) + ] [str "Write content to file"] + + ] + +let private makeNumberOfBitsField model (comp:Component) text dispatch = + let sheetDispatch sMsg = dispatch (Sheet sMsg) + + let title, width = + match comp.Type with + | Input w | Output w | NbitsAdder w | NbitsXor w | Register w | RegisterE w | Viewer w -> "Number of bits", w + | SplitWire w -> "Number of bits in the top (LSB) wire", w + | BusSelection( w, _) -> "Number of bits selected: width", w + | BusCompare( w, _) -> "Bus width", w + | Constant1(w, _,_) -> "Number of bits in the wire", w + | c -> failwithf "makeNumberOfBitsField called with invalid component: %A" c + intFormField title "60px" width 1 ( + fun newWidth -> + if newWidth < 1 + then + let props = errorPropsNotification "Invalid number of bits." + dispatch <| SetPropertiesNotification props + else + model.Sheet.ChangeWidth sheetDispatch (ComponentId comp.Id) newWidth + let text' = match comp.Type with | BusSelection _ -> text | _ -> formatLabelAsBus newWidth text + //SetComponentLabelFromText model comp text' // change the JS component label + let lastUsedWidth = + match comp.Type with + | SplitWire _ | BusSelection _ | Constant1 _ -> + model.LastUsedDialogWidth + | _ -> + newWidth + dispatch (ReloadSelectedComponent (lastUsedWidth)) // reload the new component + dispatch <| SetPopupDialogInt (Some newWidth) + dispatch ClosePropertiesNotification + ) + + + + + +let mockDispatchS msgFun msg = + match msg with + | Sheet (Sheet.Msg.Wire (BusWire.Msg.Symbol sMsg)) -> + msgFun msg + | _ -> () + + + +let msgToS = + BusWire.Msg.Symbol >> Sheet.Msg.Wire >> Msg.Sheet + +/// Return dialog fileds used by constant, or default values +let constantDialogWithDefault (w,cText) dialog = + let w = Option.defaultValue w dialog.Int + let cText = Option.defaultValue cText dialog.Text + w, cText + +/// Create react to chnage constant properties +let makeConstantDialog (model:Model) (comp: Component) (text:string) (dispatch: Msg -> Unit): ReactElement = + let symbolDispatch msg = dispatch <| msgToS msg + let wComp, txtComp = + match comp.Type with | Constant1( w,_,txt) -> w,txt | _ -> failwithf "What? impossible" + let w = Option.defaultValue wComp model.PopupDialogData.Int + let cText = Option.defaultValue txtComp model.PopupDialogData.Text + let reactMsg, compTOpt = CatalogueView.parseConstant w cText + match compTOpt with + | None -> () + | Some (Constant1(w,cVal,cText) as compT) -> + if compT <> comp.Type then + model.Sheet.ChangeWidth (Sheet >> dispatch) (ComponentId comp.Id) w + symbolDispatch <| Symbol.ChangeConstant (ComponentId comp.Id, cVal, cText) + dispatch (ReloadSelectedComponent w) + dispatch ClosePropertiesNotification + | _ -> failwithf "What? impossible" + + div [] [ + makeNumberOfBitsField model comp text dispatch + br [] + reactMsg + br [] + textFormFieldSimple + "Enter constant value in decimal, hex, or binary:" + cText + (fun txt -> + printfn $"Setting {txt}" + dispatch <| SetPopupDialogText (Some txt)) + + ] + +let private makeLsbBitNumberField model (comp:Component) dispatch = + let sheetDispatch sMsg = dispatch (Sheet sMsg) + let lsbPos, infoText = + match comp.Type with + | BusSelection(width,lsb) -> uint32 lsb, "Least Significant Bit number selected: lsb" + | BusCompare(width,cVal) -> cVal, "Compare with" + | _ -> failwithf "makeLsbBitNumberfield called from %A" comp.Type + + match comp.Type with + | BusCompare(width, _) -> + intFormField infoText "120px" (int lsbPos) 1 ( + fun cVal -> + if cVal < 0 || uint32 cVal > uint32 ((1 <<< width) - 1) + then + let note = errorPropsNotification <| sprintf "Invalid Comparison Value for bus of width %d" width + dispatch <| SetPropertiesNotification note + else + model.Sheet.ChangeLSB sheetDispatch (ComponentId comp.Id) (int64 cVal) + dispatch (ReloadSelectedComponent (width)) // reload the new component + dispatch ClosePropertiesNotification + ) + | BusSelection(width, _) -> + intFormField infoText "60px" (int lsbPos) 1 ( + fun newLsb -> + if newLsb < 0 + then + let note = errorPropsNotification "Invalid LSB bit position" + dispatch <| SetPropertiesNotification note + else + model.Sheet.ChangeLSB sheetDispatch (ComponentId comp.Id) (int64 newLsb) + dispatch (ReloadSelectedComponent (width)) // reload the new component + dispatch ClosePropertiesNotification + ) + | _ -> failwithf "What? invalid component for lsbpos in properties" + + + +let private makeDescription (comp:Component) model dispatch = + match comp.Type with + | ROM _ | RAM _ | AsyncROM _ -> + failwithf "What? Legacy RAM component types should never occur" + | Input _ -> str "Input." + | Constant1 _ | Constant _ -> str "Constant Wire." + | Output _ -> str "Output." + | Viewer _ -> str "Viewer." + | BusCompare _ -> str "The output is one if the bus unsigned binary value is equal to the integer specified. This will display in hex on the design sheet, and decimal in this dialog. Busses of greater than 32 bits are not supported" + | BusSelection _ -> div [] [ + str "Bus Selection." + br [] + str "The output is the subrange [width+lsb-1..lsb] of the input bits. If width = 1 this selects one bit. Error if the input has less than width + lsb bits." + br [] + br [] + str "Note that the output bit(s) are numbered from 0 even if the input range has LS bit number > 0. \ + The input bits connected are displayed in the schematic symbol" + ] + | IOLabel -> div [] [ + str "Label on Wire or Bus. Labels with the same name connect wires. Each label has input on left and output on right. \ + No output connection is required from a set of labels. Since a set represents one wire of bus, exactly one input connection is required. \ + Labels can be used:" + br [] ; + str "To name wires and document designs."; br [] + str "To join inputs and outputs without wires."; br [] + str "To prevent an unused output from giving an error." + ] + | Not | And | Or | Xor | Nand | Nor | Xnor -> + div [] [ str <| sprintf "%A gate." comp.Type ] + | Mux2 -> div [] [ str "Multiplexer with two inputs and one output." ] + | Demux2 -> div [] [ str "Demultiplexer with one input and two outputs." ] + | MergeWires -> div [] [ str "Merge two wires of width n and m into a single wire of width n+m." ] + | SplitWire _ -> div [] [ str "Split a wire of width n+m into two wires of width n and m."] + | NbitsAdder numberOfBits -> div [] [ str <| sprintf "%d bit(s) adder." numberOfBits ] + | NbitsXor numberOfBits -> div [] [ str <| sprintf "%d XOR gates with %d outputs." numberOfBits numberOfBits] + | Decode4 -> div [] [ str <| "4 bit decoder: Data is output on the Sel output, all other outputs are 0."] + | Custom custom -> + let styledSpan styles txt = span [Style styles] [str <| txt] + let boldSpan txt = styledSpan [FontWeight "bold"] txt + let italicSpan txt = styledSpan [FontStyle "italic"] txt + + let toHTMLList = + List.map (fun (label, width) -> li [] [str <| sprintf "%s: %d bit(s)" label width]) + div [] [ + boldSpan $"{custom.Name}" + span [] [str <| ": user defined (custom) component."] + br [] + br [] + p [ Style [ FontStyle "italic"; FontSize "12px"; LineHeight "1.1"]] [ + str <| $"Input or Output ports are displayed on the '{custom.Name}' symbol sorted by the \ + vertical position on the design sheet of the Input or Output components at the time the symbol is added."] + + span [Style [FontWeight "bold"; FontSize "15px"]] [str <| "Inputs"] + ul [] (toHTMLList custom.InputLabels) + br [] + span [Style [FontWeight "bold"; FontSize "15px"]] [str <| "Outputs"] + ul [] (toHTMLList custom.OutputLabels) + ] + | DFF -> div [] [ str "D-flip-flop. The component is implicitly connected to the global clock." ] + | DFFE -> div [] [ + str "D-flip-flop with enable. If the enable signal is high the state of + the D-flip-flop will be updated at the next clock cycle. + The component is implicitly connected to the global clock." ] + | Register _ -> div [] [ str "Register. The component is implicitly connected to the global clock." ] + | RegisterE _ -> + div [] [ str "Register with enable. If the enable signal is high the + state of the Register will be updated at the next clock + cycle. The component is implicitly connected to the global + clock." ] + | AsyncROM1 mem -> + let descr = "Asynchronous ROM: the output is updated as soon as the address changes." + makeMemoryInfo descr mem (ComponentId comp.Id) comp.Type model dispatch + | ROM1 mem -> + let descr = "Synchronous ROM: the output is updated only after a clock tick. The component is implicitly connected to the global clock." + makeMemoryInfo descr mem (ComponentId comp.Id) comp.Type model dispatch + | RAM1 mem -> + let descr = + "synchronous read and write RAM memory. + At every clock tick, the RAM can read and optionally write + the content of the memory location selected by the address. If the + write signal is high, the content of the selected memory location + is set to the value of data-in. In cycle 0 data-out is 0, otherwise + data-out is the contents of the memory location addressed in the + previous cycle, before any optional write. + The component is implicitly connected to the global clock." + makeMemoryInfo descr mem (ComponentId comp.Id) comp.Type model dispatch + | AsyncRAM1 mem -> + let descr = + "Asynchronous read, synchronous write RAM memory. + At every clock tick, optionally write + the content of the memory location selected by the address. If the + write signal is high, the content of the selected memory location + is set to the value of data-in. data-out is the contents of the memory + location addressed by the current cycle addres. + The component is implicitly connected to the global clock." + makeMemoryInfo descr mem (ComponentId comp.Id) comp.Type model dispatch + +let private makeExtraInfo model (comp:Component) text dispatch = + match comp.Type with + | Input _ | Output _ | NbitsAdder _ | NbitsXor _ | Viewer _ -> + makeNumberOfBitsField model comp text dispatch + | SplitWire _ -> + makeNumberOfBitsField model comp text dispatch + | Register _ | RegisterE _ -> + makeNumberOfBitsField model comp text dispatch + | BusSelection _ -> + div [] [ + makeNumberOfBitsField model comp text dispatch + makeLsbBitNumberField model comp dispatch + ] + | BusCompare _ -> + div [] [ + makeNumberOfBitsField model comp text dispatch + makeLsbBitNumberField model comp dispatch + ] + + | Constant1 _ -> + makeConstantDialog model comp text dispatch + | _ -> div [] [] + + +let viewSelectedComponent (model: ModelType.Model) dispatch = + let sheetDispatch sMsg = dispatch (Sheet sMsg) + let formatLabelText (txt: string) = + txt.ToUpper() + |> Seq.filter (function | ch when System.Char.IsLetterOrDigit ch -> true | '.' -> true | '_' -> true | _ -> false) + |> Seq.skipWhile (System.Char.IsLetter >> not) + |> (fun chars -> match Seq.length chars with | 0 -> None | _ -> Some (String.concat "" (Seq.map string chars))) + match model.Sheet.SelectedComponents with + | [ compId ] -> + let comp = Symbol.extractComponent model.Sheet.Wire.Symbol compId + div [Key comp.Id] [ + // let label' = extractLabelBase comp.Label + // TODO: normalise labels so they only contain allowed chars all uppercase + let label' = Option.defaultValue "L" (formatLabelText comp.Label) // No formatting atm + readOnlyFormField "Description" <| makeDescription comp model dispatch + makeExtraInfo model comp label' dispatch + let required = match comp.Type with | SplitWire _ | MergeWires | BusSelection _ -> false | _ -> true + textFormField required "Component Name" label' (fun text -> + // TODO: removed formatLabel for now + //setComponentLabel model sheetDispatch comp (formatLabel comp text) + match formatLabelText text with + | Some label -> + setComponentLabel model sheetDispatch comp label + dispatch <| SetPopupDialogText (Some label) + | None -> () + //updateNames model (fun _ _ -> model.WaveSim.Ports) |> StartWaveSim |> dispatch + dispatch (ReloadSelectedComponent model.LastUsedDialogWidth) // reload the new component + ) + ] + | _ -> div [] [ str "Select a component in the diagram to view or change its properties, for example number of bits." ] + diff --git a/src/Renderer/UI/SimulationView.fs b/src/Renderer/UI/SimulationView.fs new file mode 100644 index 0000000..8f70542 --- /dev/null +++ b/src/Renderer/UI/SimulationView.fs @@ -0,0 +1,627 @@ +//(* +// SimulationView.fs +// +// View for simulation in the right tab. +//*) +// +module SimulationView + +open Fulma +open Fulma.Extensions.Wikiki +open Fable.React +open Fable.React.Props + +open NumberHelpers +open Helpers +open TimeHelpers +open JSHelpers +open DiagramStyle +open Notifications +open PopupView +open MemoryEditorView +open ModelType +open CommonTypes +open SimulatorTypes +open Extractor +open Simulator + + + +/// save verilog file +/// TODO: the simulation error display here is shared with step simulation and also waveform simulation - +/// maybe it should be a subfunction. +let verilogOutput (vType: Verilog.VMode) (model: Model) (dispatch: Msg -> Unit) = + printfn "Verilog output" + match FileMenuView.updateProjectFromCanvas model dispatch, model.Sheet.GetCanvasState() with + | Some proj, state -> + match model.UIState with //TODO should this be its own UI operation? + | Some _ -> + () // do nothing if in middle of I/O operation + | None -> + prepareSimulation proj.OpenFileName (state) proj.LoadedComponents + |> (function + | Ok sim -> + let path = FilesIO.pathJoin [| proj.ProjectPath; proj.OpenFileName + ".v" |] + printfn "writing %s" proj.ProjectPath + try + FilesIO.writeFile path (Verilog.getVerilog vType sim.FastSim) + with + | e -> + printfn $"Error in Verilog output: {e.Message}" + Error e.Message + |> Notifications.displayAlertOnError dispatch + dispatch <| ChangeRightTab Simulation + let note = successSimulationNotification $"verilog output written to file {path}" + dispatch <| SetSimulationNotification note + | Error simError -> + printfn $"Error in simulation prevents verilog output {simError.Msg}" + dispatch <| ChangeRightTab Simulation + if simError.InDependency.IsNone then + // Highlight the affected components and connection only if + // the error is in the current diagram and not in a + // dependency. + (simError.ComponentsAffected, simError.ConnectionsAffected) + |> SetHighlighted |> dispatch + Error simError + |> StartSimulation + |> dispatch) + | _ -> () // do nothing if no project is loaded + +//----------------------------View level simulation helpers------------------------------------// + +type SimCache = { + Name: string + StoredState: CanvasState + StoredResult: Result + } + + + +let simCacheInit name = { + Name = name; + StoredState = ([],[]) // reduced canvas state from extractReducedState + StoredResult = Ok { + FastSim = FastCreate.emptyFastSimulation() + Graph = Map.empty + Inputs = [] + Outputs = [] + IsSynchronous=false + NumberBase = NumberBase.Hex + ClockTickNumber = 0 + } + } + +/// Used to store last canvas state and its simulation +let mutable simCache: SimCache = simCacheInit "" + +/// Start up a simulation, doing all necessary checks and generating simulation errors +/// if necesary. The code to do this is quite long so results are memoized. this is complicated because +/// we want the comparison (in the case nothing has chnaged) to be fast. +/// 1. If the current sheet changes we redo the simulation. +/// 2. While current sheet does not change we assume the other sheets +/// ( and so subsheet content) cannot change. +/// 3. Therefore we need only compare current sheet canvasState with its +/// initial value. This is compared using extractReducedState to make a copy that has geometry info removed +/// from components and connections. +let rec prepareSimulationMemoized + (diagramName : string) + (canvasState : CanvasState) + (loadedDependencies : LoadedComponent list) + : Result * CanvasState = + let rState = extractReducedState canvasState + if diagramName <> simCache.Name then + simCache <- simCacheInit diagramName + // recursive call having initialised the cache state on sheet change + prepareSimulationMemoized diagramName canvasState loadedDependencies + else + let isSame = rState = simCache.StoredState + if isSame then + simCache.StoredResult, rState + else + printfn "New simulation" + let simResult = prepareSimulation diagramName rState loadedDependencies + simCache <- { + Name = diagramName + StoredState = rState + StoredResult = simResult + } + simResult, rState + + +/// Start simulating the current Diagram. +/// Return SimulationData that can be used to extend the simulation +/// as needed, or error if simulation fails. +/// Note that simulation is only redone if current canvas changes. +let makeSimData model = + let start = TimeHelpers.getTimeMs() + match model.Sheet.GetCanvasState(), model.CurrentProj with + | _, None -> None + | canvasState, Some project -> + let otherComponents = + project.LoadedComponents + |> List.filter (fun comp -> comp.Name <> project.OpenFileName) + (canvasState, otherComponents) + ||> prepareSimulationMemoized project.OpenFileName + |> Some + |> TimeHelpers.instrumentInterval "MakeSimData" start + +let changeBase dispatch numBase = numBase |> SetSimulationBase |> dispatch + +/// A line that can be used for an input, an output, or a state. +let private splittedLine leftContent rightConent = + Level.level [Level.Level.Props [Style [MarginBottom "10px"]]] [ + Level.left [] [ + Level.item [] [ leftContent ] + ] + Level.right [] [ + Level.item [] [ rightConent ] + ] + ] + +/// Pretty print a label with its width. +let private makeIOLabel label width = + let label = cropToLength 15 true label + match width with + | 1 -> label + | w -> sprintf "%s (%d bits)" label w + +let private viewSimulationInputs + (numberBase : NumberBase) + (simulationData : SimulationData) + (inputs : (SimulationIO * WireData) list) + dispatch = + let simulationGraph = simulationData.Graph + let makeInputLine ((ComponentId inputId, ComponentLabel inputLabel, width), wireData) = +#if ASSERTS + assertThat (List.length wireData = width) + <| sprintf "Inconsistent wireData length in viewSimulationInput for %s: expected %d but got %A" inputLabel width wireData.Length +#endif + let valueHandle = + match wireData with + | [] -> failwith "what? Empty wireData while creating a line in simulation inputs." + | [bit] -> + // For simple bits, just have a Zero/One button. + Button.button [ + Button.Props [ simulationBitStyle ] + //Button.Color IsPrimary + (match bit with Zero -> Button.Color Color.IsGreyLighter | One -> Button.Color IsPrimary) + Button.IsHovered false + Button.OnClick (fun _ -> + let newBit = match bit with + | Zero -> One + | One -> Zero + let graph = simulationGraph + FastRun.changeInput (ComponentId inputId) [newBit] simulationData.ClockTickNumber simulationData.FastSim + dispatch <| SetSimulationGraph(graph, simulationData.FastSim) + ) + ] [ str <| bitToString bit ] + | bits -> + let defValue = viewNum numberBase <| convertWireDataToInt bits + Input.text [ + Input.Key (numberBase.ToString()) + Input.DefaultValue defValue + Input.Props [ + simulationNumberStyle + OnChange (getTextEventValue >> (fun text -> + match strToIntCheckWidth width text with + | Error err -> + let note = errorPropsNotification err + dispatch <| SetSimulationNotification note + | Ok num -> + let bits = convertIntToWireData width num + // Close simulation notifications. + CloseSimulationNotification |> dispatch + // Feed input. + let graph = simulationGraph + FastRun.changeInput (ComponentId inputId) bits simulationData.ClockTickNumber simulationData.FastSim + dispatch <| SetSimulationGraph(graph, simulationData.FastSim) + )) + ] + ] + splittedLine (str <| makeIOLabel inputLabel width) valueHandle + div [] <| List.map makeInputLine inputs + +let private staticBitButton bit = + Button.button [ + Button.Props [ simulationBitStyle ] + //Button.Color IsPrimary + (match bit with Zero -> Button.Color IsGreyLighter | One -> Button.Color IsPrimary) + Button.IsHovered false + Button.Disabled true + ] [ str <| bitToString bit ] + +let private staticNumberBox numBase bits = + let width = List.length bits + let value = viewFilledNum width numBase <| convertWireDataToInt bits + Input.text [ + Input.IsReadOnly true + Input.Value value + Input.Props [simulationNumberStyle] + ] + +let private viewSimulationOutputs numBase (simOutputs : (SimulationIO * WireData) list) = + let makeOutputLine ((ComponentId _, ComponentLabel outputLabel, width), wireData) = +#if ASSERTS + assertThat (List.length wireData = width) + <| sprintf "Inconsistent wireData length in viewSimulationOutput for %s: expcted %d but got %d" outputLabel width wireData.Length +#endif + let valueHandle = + match wireData with + | [] -> failwith "what? Empty wireData while creating a line in simulation output." + | [bit] -> staticBitButton bit + | bits -> staticNumberBox numBase bits + splittedLine (str <| makeIOLabel outputLabel width) valueHandle + div [] <| List.map makeOutputLine simOutputs + +let private viewViewers numBase (simViewers : ((string*string) * int * WireData) list) = + let makeViewerOutputLine ((label,fullName), width, wireData) = +#if ASSERTS + assertThat (List.length wireData = width) + <| sprintf "Inconsistent wireData length in viewViewer for %s: expcted %d but got %d" label width wireData.Length +#endif + let valueHandle = + match wireData with + | [] -> failwith "what? Empty wireData while creating a line in simulation output." + | [bit] -> staticBitButton bit + | bits -> staticNumberBox numBase bits + let addToolTip tip react = + div [ + HTMLAttr.ClassName $"{Tooltip.ClassName} has-tooltip-right" + Tooltip.dataTooltip tip + ] [react] + let line = + str <| makeIOLabel label width + |> (fun r -> if fullName <> "" then addToolTip fullName r else r) + splittedLine line valueHandle + div [] <| List.map makeViewerOutputLine simViewers + +let private viewStatefulComponents step comps numBase model dispatch = + let getWithDefault (lab:string) = if lab = "" then "no-label" else lab + let makeStateLine ((fc,state) : FastComponent*SimulationComponentState) = + let label = getWithDefault fc.FullName + match state with + | RegisterState fd when fd.Width = 1 -> + let bit = if fd = SimulatorTypes.fastDataZero then Zero else One + let label = sprintf "DFF: %s" <| label + [ splittedLine (str label) (staticBitButton bit) ] + | RegisterState bits -> + let label = sprintf "Register: %s (%d bits)" label bits.Width + [ splittedLine (str label) (staticNumberBox numBase (bits |> convertFastDataToWireData)) ] + | RamState mem -> + let label = sprintf "RAM: %s" <| label + let initialMem compType = match compType with RAM1 m | AsyncRAM1 m -> m | _ -> failwithf "what? viewStatefulComponents expected RAM component but got: %A" compType + let viewDiffBtn = + Button.button [ + Button.Props [ simulationBitStyle ] + Button.Color IsPrimary + Button.OnClick (fun _ -> + openMemoryDiffViewer (initialMem fc.FType) mem model dispatch + ) + ] [ str "View" ] + [ splittedLine (str label) viewDiffBtn ] + | _ -> [] + div [] (List.collect makeStateLine comps ) + +let viewSimulationError (simError : SimulationError) = + let error = + match simError.InDependency with + | None -> + div [] [ + str simError.Msg + br [] + str <| "Please fix the error and retry." + ] + | Some dep -> + div [] [ + str <| "Error found in dependency \"" + dep + "\":" + br [] + str simError.Msg + br [] + str <| "Please fix the error in the dependency and retry." + ] + div [] [ + Heading.h5 [ Heading.Props [ Style [ MarginTop "15px" ] ] ] [ str "Errors" ] + error + ] + +let private simulationClockChangePopup (simData: SimulationData) (dispatch: Msg -> Unit) (dialog:PopupDialogData) = + let step = simData.ClockTickNumber + div [] + [ + h6 [] [str $"This simulation contains {simData.FastSim.FComps.Count} components"] + (match dialog.Int with + | Some n when n > step -> + Text.p [ + Modifiers [Modifier.TextWeight TextWeight.Bold] + ] [str "Goto Tick:"] + | _ -> Text.p [ + Modifiers [ + Modifier.TextWeight TextWeight.Bold + Modifier.TextColor IsDanger] + ] [str $"The clock tick must be > {step}"]) + br [] + Input.number [ + Input.Props [AutoFocus true;Style [Width "100px"]] + Input.DefaultValue <| sprintf "%d" step + Input.OnChange (getIntEventValue >> Some >> SetPopupDialogInt >> dispatch) + ] + + ] + +let simulateWithTime steps simData = + let startTime = getTimeMs() + FastRun.runFastSimulation (steps + simData.ClockTickNumber) simData.FastSim + getTimeMs() - startTime + +let cmd block = + Elmish.Cmd.OfAsyncWith.perform block + +let doBatchOfMsgsAsynch (msgs: seq) = + msgs + |> Seq.map Elmish.Cmd.ofMsg + |> Elmish.Cmd.batch + |> ExecCmdAsynch + |> Elmish.Cmd.ofMsg + + + +let simulateWithProgressBar (simProg: SimulationProgress) (model:Model) = + match model.CurrentStepSimulationStep, model.PopupDialogData.Progress with + | Some (Ok simData), Some barData -> + let nComps = float simData.FastSim.FComps.Count + let oldClock = simData.FastSim.ClockTick + let clock = min simProg.FinalClock (simProg.ClocksPerChunk + oldClock) + let t1 = getTimeMs() + FastRun.runFastSimulation clock simData.FastSim + printfn $"clokctick after runFastSim{clock} from {oldClock} is {simData.FastSim.ClockTick}" + let t2 = getTimeMs() + let speed = if t2 = t1 then 0. else (float clock - float oldClock) * nComps / (t2 - t1) + let messages = + if clock - oldClock < simProg.ClocksPerChunk then [ + SetSimulationGraph(simData.Graph, simData.FastSim) + IncrementSimulationClockTick (clock - oldClock); + SetPopupProgress None ] + else [ + SetSimulationGraph(simData.Graph, simData.FastSim) + IncrementSimulationClockTick simProg.ClocksPerChunk + UpdatePopupProgress (fun barData -> {barData with Value = clock - simProg.InitialClock; Speed = speed}) + SimulateWithProgressBar simProg ] + model, doBatchOfMsgsAsynch messages + | _ -> + model, Elmish.Cmd.ofMsg (SetPopupProgress None) + + + +let simulationClockChangeAction dispatch simData (dialog:PopupDialogData) = + let clock = + match dialog.Int with + | None -> failwithf "What - must have some number from dialog" + | Some clock -> clock + let initClock = simData.ClockTickNumber + let steps = clock - initClock + let numComps = simData.FastSim.FComps.Count + let initChunk = min steps (20000/(numComps + 1)) + let initTime = getTimeMs() + let estimatedTime = (float steps / float initChunk) * (simulateWithTime initChunk simData + 0.0000001) + let chunkTime = min 2000. (estimatedTime / 5.) + let chunk = int <| float steps * chunkTime / estimatedTime + if steps > 2*initChunk && estimatedTime > 500. then + printfn "test1" + dispatch <| SetPopupProgress + (Some { + Speed = float (numComps * steps) / estimatedTime + Value=initChunk; + Max=steps; + Title= "running simulation..." + }) + [ + SetSimulationGraph(simData.Graph, simData.FastSim) + IncrementSimulationClockTick (initChunk) + ClosePopup + SimulateWithProgressBar { + FinalClock = clock; + InitialClock = initChunk + initClock; + ClocksPerChunk = chunk + } + ] + |> Seq.map Elmish.Cmd.ofMsg + |> Elmish.Cmd.batch + |> ExecCmdAsynch + |> dispatch + else + FastRun.runFastSimulation clock simData.FastSim + printfn $"test2 clock={clock}, clokcticknumber= {simData.ClockTickNumber}, {simData.FastSim.ClockTick}" + [ + SetSimulationGraph(simData.Graph, simData.FastSim) + IncrementSimulationClockTick (clock - simData.ClockTickNumber) + ClosePopup + ] + |> Seq.map Elmish.Cmd.ofMsg + |> Elmish.Cmd.batch + |> ExecCmdAsynch + |> dispatch + + + +let private viewSimulationData (step: int) (simData : SimulationData) model dispatch = + let hasMultiBitOutputs = + simData.Outputs |> List.filter (fun (_,_,w) -> w > 1) |> List.isEmpty |> not + let maybeBaseSelector = + match hasMultiBitOutputs with + | false -> div [] [] + | true -> baseSelector simData.NumberBase (changeBase dispatch) + let maybeClockTickBtn = + let step = simData.ClockTickNumber + match simData.IsSynchronous with + | false -> div [] [] + | true -> + div [] [ + Button.button [ + Button.Color IsSuccess + Button.OnClick (fun _ -> + let isDisabled (dialogData:PopupDialogData) = + match dialogData.Int with + | Some n -> n <= step + | None -> true + dialogPopup + "Advance Simulation" + (simulationClockChangePopup simData dispatch) + "Goto Tick" + (simulationClockChangeAction dispatch simData) + isDisabled + dispatch) + ] [ str "Goto" ] + str " " + str " " + Button.button [ + Button.Color IsSuccess + Button.OnClick (fun _ -> + if SimulationRunner.simTrace <> None then + printfn "*********************Incrementing clock from simulator button******************************" + printfn "-------------------------------------------------------------------------------------------" + //let graph = feedClockTick simData.Graph + FastRun.runFastSimulation (simData.ClockTickNumber+1) simData.FastSim + dispatch <| SetSimulationGraph(simData.Graph, simData.FastSim) + if SimulationRunner.simTrace <> None then + printfn "-------------------------------------------------------------------------------------------" + printfn "*******************************************************************************************" + IncrementSimulationClockTick 1 |> dispatch + ) + ] [ str <| sprintf "Clock Tick %d" simData.ClockTickNumber ] + ] + let maybeStatefulComponents() = + let stateful = + FastRun.extractStatefulComponents simData.ClockTickNumber simData.FastSim + |> Array.toList + match List.isEmpty stateful with + | true -> div [] [] + | false -> div [] [ + Heading.h5 [ Heading.Props [ Style [ MarginTop "15px" ] ] ] [ str "Stateful components" ] + viewStatefulComponents step stateful simData.NumberBase model dispatch + ] + let questionIcon = str "\u003F" + + let tip tipTxt txt = + span [ + // Style [Float FloatOptions.Left] + HTMLAttr.ClassName $"{Tooltip.ClassName} {Tooltip.IsMultiline}" + Tooltip.dataTooltip tipTxt + ] + [ + Text.span [ + Modifiers [ + Modifier.TextColor IsPrimary + ] + Props [ + Style [ + Display DisplayOptions.InlineBlock + Width "80px" + TextAlign TextAlignOptions.Center]] + ] [str txt] ] + div [] [ + splittedLine maybeBaseSelector maybeClockTickBtn + + Heading.h5 [ Heading.Props [ Style [ MarginTop "15px" ] ] ] [ str "Inputs" ] + viewSimulationInputs + simData.NumberBase + simData + (FastRun.extractFastSimulationIOs simData.Inputs simData) + dispatch + + + Heading.h5 [ + Heading.Props [ Style [ MarginTop "15px" ] ] + ] [ + str "Outputs &" + tip "Add Viewer components to any sheet in the simulation" "Viewers" + ] + viewViewers simData.NumberBase <| List.sort (FastRun.extractViewers simData) + viewSimulationOutputs simData.NumberBase + <| FastRun.extractFastSimulationIOs simData.Outputs simData + + maybeStatefulComponents() + ] + +let SetSimErrorFeedback (simError:SimulatorTypes.SimulationError) (model:Model) (dispatch: Msg -> Unit) = + let sheetDispatch sMsg = dispatch (Sheet sMsg) + let keyDispatch = Sheet.KeyPress >> sheetDispatch + if simError.InDependency.IsNone then + // Highlight the affected components and connection only if + // the error is in the current diagram and not in a + // dependency. + let (badComps,badConns) = (simError.ComponentsAffected, simError.ConnectionsAffected) + dispatch <| SetHighlighted (badComps,badConns) + if not (Sheet.isAllVisible model.Sheet badConns badComps) then + // make whole diagram visible if any of the errors are not visible + keyDispatch <| Sheet.KeyboardMsg.CtrlW + dispatch <| Sheet(Sheet.SetWaveSimMode false) + + +let viewSimulation model dispatch = + let state = model.Sheet.GetCanvasState () + // let JSState = model.Diagram.GetCanvasState () + let startSimulation () = + match state, model.CurrentProj with + | _, None -> failwith "what? Cannot start a simulation without a project" + | canvasState, Some project -> + let otherComponents = + project.LoadedComponents + |> List.filter (fun comp -> comp.Name <> project.OpenFileName) + simCache <- simCacheInit "" + (canvasState, otherComponents) + ||> prepareSimulationMemoized project.OpenFileName + |> function + | Ok (simData), state -> Ok simData + | Error simError, state -> + printfn $"ERROR:{simError}" + SetSimErrorFeedback simError model dispatch + Error simError + |> StartSimulation + |> dispatch + let sheetName = project.OpenFileName + match Map.tryFind sheetName (fst model.WaveSim) with + | Some wSModel -> + printfn "Closing wavesim..." + dispatch <| SetWSMod {wSModel with InitWaveSimGraph=None; WSViewState=WSClosed; WSTransition = None} + dispatch <| SetWaveSimIsOutOfDate true + | None -> () + match model.CurrentStepSimulationStep with + | None -> + let simRes = makeSimData model + let isSync = match simRes with | Some( Ok {IsSynchronous=true},_) | _ -> false + let buttonColor, buttonText = + match simRes with + | None -> IColor.IsWhite, "" + | Some (Ok _, _) -> IsSuccess, "Start Simulation" + | Some (Error _, _) -> IsWarning, "See Problems" + div [] [ + str "Simulate simple logic using this tab." + br [] + str (if isSync then "You can also use the Waveforms >> button to view waveforms" else "") + br []; br [] + Button.button + [ + Button.Color buttonColor; + Button.OnClick (fun _ -> startSimulation()) ; + ] + [ str buttonText ] + ] + | Some sim -> + let body = match sim with + | Error simError -> viewSimulationError simError + | Ok simData -> viewSimulationData simData.ClockTickNumber simData model dispatch + let endSimulation _ = + dispatch CloseSimulationNotification // Close error notifications. + dispatch <| Sheet (Sheet.ResetSelection) // Remove highlights. + dispatch EndSimulation // End simulation. + dispatch <| (JSDiagramMsg << InferWidths) () // Repaint connections. + div [] [ + Button.button + [ Button.Color IsDanger; Button.OnClick endSimulation ] + [ str "End simulation" ] + br []; br [] + str "The simulation uses the diagram as it was at the moment of + pressing the \"Start simulation\" button." + hr [] + body + ] diff --git a/src/Renderer/UI/Style.fs b/src/Renderer/UI/Style.fs new file mode 100644 index 0000000..03c9f51 --- /dev/null +++ b/src/Renderer/UI/Style.fs @@ -0,0 +1,237 @@ +module DiagramStyle + + +open ModelType +open Fable.React.Props + +let headerHeight = "72px" +let private headerHeightWithBorderOffset = "74px" +let private rightSectionWidthS = "400px" // Small right section. +let private rightSectionWidthL = "650px" // Large right section. +let minViewerWidth = 400 +let minEditorWidth = 400 + +let rightSectionWidthViewerDefault = 650 + +// Get +let getHeaderHeight = + headerHeight + |> String.filter (fun c -> (int(c) <= 57 && int(c) >= 48)) + |> float + +let rightSectionWidth (model:Model) = + match model.RightPaneTabVisible with + | RightTab.Properties | RightTab.Catalogue -> rightSectionWidthS + | RightTab.Simulation -> rightSectionWidthL + | RightTab.WaveSim -> sprintf "%dpx" model.WaveSimViewerWidth + +let leftSectionWidth model = Style [ + Width (sprintf "calc(100%s - %s - 10px)" "%" (rightSectionWidth model)) +] + +let navbarStyle model = Style [ + Width "100%" + Height headerHeight +] + +/// For making Sheet contained inside left section (don't want sheet behind right section tabs) NOT USED +let leftSectionStyle model = + let leftSectionWidth = leftSectionWidth model + Style [ + Position PositionOptions.Fixed + Left "0px" + Top "0px" + Height "100%" //(sprintf "calc(100%s - %s)" "%" headerHeight) // WindowSize - headerHeight + Width leftSectionWidth + OverflowX OverflowOptions.Hidden + OverflowY OverflowOptions.Hidden + BorderTop "2px solid lightgray" + UserSelect UserSelectOptions.None + ZIndex 31 + BackgroundColor "white" + //UserSelect UserSelectOptions.None +] + +let rightSectionStyle model = + let widthRightSec = rightSectionWidth model + Style [ + Position PositionOptions.Fixed + Right "0px" + Top "0px" + Height "100%" //(sprintf "calc(100%s - %s)" "%" headerHeight) // WindowSize - headerHeight + Width widthRightSec + OverflowX OverflowOptions.Hidden + OverflowY OverflowOptions.Scroll + BorderTop "2px solid lightgray" + UserSelect UserSelectOptions.None + ZIndex 31 + BackgroundColor "white" + //UserSelect UserSelectOptions.None +] + +let canvasVisibleStyle model = + let widthRightSec = rightSectionWidth model + Style [ + Display DisplayOptions.Block + Position PositionOptions.Absolute // Required to work. + OverflowX OverflowOptions.Scroll + OverflowY OverflowOptions.Scroll + Top headerHeight // Placed just under the header. + Left "0px" + Bottom "0px" + Right widthRightSec + BorderTop "2px solid lightgray" + ] + +// Used by Sheet +let canvasVisibleStyleList model = + let widthRightSec = rightSectionWidth model + [ + Display DisplayOptions.Block + Position PositionOptions.Absolute // Required to work. + OverflowX OverflowOptions.Scroll + OverflowY OverflowOptions.Scroll + Top headerHeight // Placed under header with offset for the border. // headerHeight // Placed just under the header. + Left "0px" + Bottom "0px" + Right widthRightSec + BorderTop "2px solid lightgray" + ] + +let canvasSmallMenuStyle = Style [ + Display DisplayOptions.Block + Position PositionOptions.Absolute // Required to work. + OverflowX OverflowOptions.Hidden + OverflowY OverflowOptions.Hidden + Left "10px" + Bottom "25px" + Right (sprintf "calc(100%s - 300px)" "%") + WhiteSpace WhiteSpaceOptions.Nowrap +] + +let canvasSmallButtonStyle = Style [ + MarginRight "5px" + BackgroundColor "white" + BorderRadius "4px" + BorderStyle "solid" + Outline "none" + Padding "4px" + Opacity 0.7 +] + +let notificationStyle = Style [ + ZIndex 100 // In front of everything. + Position PositionOptions.Absolute + UserSelect UserSelectOptions.None + Right "20px" + Bottom "20px" +] + +let simulationNumberStyle = Style [ + Width "320px" + Height "30px" +] + +let simulationBitStyle = Style [ + Width "100px" + Height "30px" + PaddingTop "3px" +] + +let menuLabelStyle = Style [ + Outline "none" + MarginTop "10px" + MarginBottom "10px" + Color "#7a7a7a" + FontSize "0.80em" + LetterSpacing "0.1em" + TextTransform "uppercase" +] + + + + + + + + + + +// Waveform simulator styles + +let clkLineWidth = 0.0125 +let transLen = 0.1 +let vPos = 0.0 +let zoomFactor = 1.3 +let maxZoom = 3.0 +let minZoom = 0.2 +let maxBusValGap = 3 +let busLabelTextSize = 0.6 // multiplied by signal height +let sigLineThick = 0.025; +let spacing = 0.4 +let sigHeight = 0.3 + +let vbWidth m = m.SimParams.ClkSvgWidth * (float m.SimParams.LastClkTime + 1.0) +let maxWavesColWidthFloat m = vbWidth m * 40.0 + 4.0 +let maxWavesColWidth m = string (maxWavesColWidthFloat m) + "px" +let waveCellWidth m = Width (maxWavesColWidth m) + +let widthAndVBwave (m : WaveSimModel) : IProp list = [ + Style [waveCellWidth m] + ViewBox ("0 0 " + string (vbWidth m) + " 0.7") +] + +let clkRulerStyle m : IProp list = + List.append (widthAndVBwave m) + [ Class "clkRulerSvg" + PreserveAspectRatio "none" ] + +let cursorLeftPx m cursor = + cursor * (m.ClkSvgWidth * 40.0 + 4.0 / (float m.LastClkTime + 1.0)) + +let cursRectStyle m = Style [ + Left (float m.CursorTime |> cursorLeftPx m |> string |> (fun w -> w + "px")) + Width (40.0 * (m.ClkSvgWidth - clkLineWidth)) +] + +let cursRectText m i : IProp list = [ + Class "clkNumStyle" + X (m.SimParams.ClkSvgWidth * (float i + 0.5)) + Y 0.5 +] + +let inWaveLabel nLabels xInd m : IProp list = [ + Class "busValueStyle" + X (xInd * m.ClkSvgWidth) + Y (spacing + sigHeight * 0.7 - 0.3 * sigHeight * (float nLabels - 1.0) / 2.0) + SVGAttr.FontSize (busLabelTextSize * sigHeight / float nLabels) +] + +let waveCellSvg m last : IProp list = + List.append (widthAndVBwave m) + [ match last with + | true -> Class "lastWaveCellSvg" + | false -> Class "waveCellSvg" + PreserveAspectRatio "none" ] + +let waveCell m : IHTMLProp list = [ + Class "rowHeight" + Style [waveCellWidth m] +] + +let lwaveCell m : IHTMLProp list = [ + Class "fullHeight" + Style [waveCellWidth m] +] + +let waveDiv= Style [ + Width "100%" + Height "100%" + Position PositionOptions.Relative + OverflowX OverflowOptions.Scroll +] + +let wavesTable m : IHTMLProp list = [ + Class "wavesColTableStyle" + Style [waveCellWidth m] +] diff --git a/src/Renderer/UI/Update.fs b/src/Renderer/UI/Update.fs new file mode 100644 index 0000000..e188d7a --- /dev/null +++ b/src/Renderer/UI/Update.fs @@ -0,0 +1,533 @@ +module Update + +open Elmish + +open Fulma +open Fable.React +open Fable.React.Props +open ElectronAPI +open SimulatorTypes +open ModelType +open CommonTypes +open Extractor +open CatalogueView +open PopupView +open FileMenuView +open WaveSimHelpers + + + +//---------------------------------------------------------------------------------------------// +//---------------------------------------------------------------------------------------------// +//---------------------------------- Update Model ---------------------------------------------// +//---------------------------------------------------------------------------------------------// + +/// subfunction used in model update function +let private getSimulationDataOrFail model msg = + match model.CurrentStepSimulationStep with + | None -> failwithf "what? Getting simulation data when no simulation is running: %s" msg + | Some sim -> + match sim with + | Error _ -> failwithf "what? Getting simulation data when could not start because of error: %s" msg + | Ok simData -> simData + + + +let verilogOutputPage sheet fPath = + div [] [ + str $"You can write sheet '{sheet}' (and its subsheets) in either simulation or synthesis format. The output will be written to:" + Text.div [ + Modifiers [ Modifier.TextWeight TextWeight.Bold] + Props [Style [TextAlign TextAlignOptions.Center; Padding "10px"; FontFamily "monospace"; FontSize "15px"]]] [str $"%s{Helpers.cropToLength 55 false fPath}.v"] + Columns.columns [ ] + [ Column.column [ ] + [ Panel.panel [ Panel.Color IsInfo ] + [ Panel.heading [ ] [ str "Simulation output"] + Panel.Block.div [] [ str "Simulation output will run on an online synthesis tool such as Icarus v10 to check that Issie's Verilog output is working"] + Panel.Block.div [] + [ Button.button + [ Button.Color IsSuccess + + Button.IsFullWidth + Button.OnClick <| openInBrowser "https://www.tutorialspoint.com/compile_verilog_online.php" + ] + [ str "Icarus v10 Verilog simulator"] + ] + ] + ] + Column.column [ ] + [ Panel.panel [ Panel.Color IsInfo ] + [ Panel.heading [ ] [ str "Synthesis output"] + Panel.Block.div [] [str "Synthesis output can be used as input to FPGA synthesis tools." ] + Panel.Block.div [] + [ Button.button + [ Button.Color IsSuccess + Button.IsFullWidth + Button.OnClick <| openInBrowser "https://github.com/edstott/issie-synth" + ] + [ str "Instructions for synthesis work-flow"] + ] + + ] ] ] ] + + +/// handle Menu actions that may need Model data +let getMenuView (act: MenuCommand) (model: Model) (dispatch: Msg -> Unit) = + match act with + | MenuSaveFile -> + FileMenuView.saveOpenFileActionWithModelUpdate model dispatch |> ignore + SetHasUnsavedChanges false + |> JSDiagramMsg |> dispatch + | MenuNewFile -> + FileMenuView.addFileToProject model dispatch + | MenuExit -> + FileMenuView.doActionWithSaveFileDialog "Exit ISSIE" CloseApp model dispatch () + | MenuVerilogOutput -> + mapOverProject () model (fun p -> + let sheet = p.OpenFileName + let fPath = FilesIO.pathJoin [|p.ProjectPath ; sheet|] + PopupView.choicePopup + "Verilog Output" + (verilogOutputPage sheet fPath) + "Write Synthesis Verilog" + "Write Simulation Verilog" + (fun forSim _ -> + match forSim with + | true -> SimulationView.verilogOutput Verilog.ForSynthesis model dispatch + | false -> SimulationView.verilogOutput Verilog.ForSimulation model dispatch + dispatch ClosePopup) + dispatch) + + | _ -> () + model + +/// get timestamp of current loaded component. +/// is this ever used? No. +let getCurrentTimeStamp model = + match model.CurrentProj with + | None -> System.DateTime.MinValue + | Some p -> + p.LoadedComponents + |> List.tryFind (fun lc -> lc.Name = p.OpenFileName) + |> function | Some lc -> lc.TimeStamp + | None -> failwithf "Project inconsistency: can't find component %s in %A" + p.OpenFileName ( p.LoadedComponents |> List.map (fun lc -> lc.Name)) + +/// Replace timestamp of current loaded component in model project by current time +/// Used in update function +let updateTimeStamp model = + let setTimeStamp (lc:LoadedComponent) = {lc with TimeStamp = System.DateTime.Now} + match model.CurrentProj with + | None -> model + | Some p -> + p.LoadedComponents + |> List.map (fun lc -> if lc.Name = p.OpenFileName then setTimeStamp lc else lc) + |> fun lcs -> { model with CurrentProj=Some {p with LoadedComponents = lcs}} + +//Finds if the current canvas is different from the saved canvas +// waits 50ms from last check + +let findChange (model : Model) : bool = + let last = model.LastChangeCheckTime // NB no check to reduce total findChange time implemented yet - TODO if needed + let start = TimeHelpers.getTimeMs() + + match model.CurrentProj with + | None -> false + | Some prj -> + //For better efficiency just check if the save button + let savedComponent = + prj.LoadedComponents + |> List.find (fun lc -> lc.Name = prj.OpenFileName) + let canv = savedComponent.CanvasState + let canv' = model.Sheet.GetCanvasState () + (canv <> canv') && not (compareCanvas 100. canv canv') + |> TimeHelpers.instrumentInterval "findChange" start + +/// Needed so that constant properties selection will work +/// Maybe good idea for other things too? +let resetDialogIfSelectionHasChanged newModel oldModel = + let newSelected = newModel.Sheet.SelectedComponents + if newSelected.Length = 1 && newSelected <> oldModel.Sheet.SelectedComponents then + {newModel with PopupDialogData = {newModel.PopupDialogData with Text = None ; Int = None}} + else newModel + +let updateComponentMemory (addr:int64) (data:int64) (compOpt: Component option) = + match compOpt with + | None -> None + | Some ({Type= (AsyncROM1 mem as ct)} as comp) + | Some ({Type = (ROM1 mem as ct)} as comp) + | Some ({Type= (AsyncRAM1 mem as ct)} as comp) + | Some ({Type= (RAM1 mem as ct)} as comp) -> + let update mem ct = + match ct with + | AsyncROM1 _ -> AsyncROM1 mem + | ROM1 _ -> ROM1 mem + | RAM1 _ -> RAM1 mem + | AsyncRAM1 _ -> AsyncRAM1 mem + | _ -> ct + let mem' = {mem with Data = mem.Data |> Map.add addr data} + Some {comp with Type= update mem' ct} + | _ -> compOpt + +let exitApp() = + // send message to main process to initiate window close and app shutdown + renderer.ipcRenderer.send("exit-the-app",[||]) + +///Tests physical equality on two objects +///Used because Msg type does not support structural equality +let isSameMsg = LanguagePrimitives.PhysicalEquality + +///Used to filter only drag messages for now, is there a better way to do this? +let matchMouseMsg (msg : Msg) : bool = + match msg with + | Sheet sMsg -> + match sMsg with + | Sheet.MouseMsg mMsg -> + match mMsg.Op with + | DrawHelpers.Drag -> true + | _ -> false + | _ -> false + | _ -> false + +///Returns None if no mouse drag message found, returns Some (lastMouseMsg, msgQueueWithoutMouseMsgs) if a drag message was found +let getLastMouseMsg msgQueue = + msgQueue + |> List.filter matchMouseMsg + |> function + | [] -> None + | lst -> Some lst.Head //First item in the list was the last to be added (most recent) + +let sheetMsg sMsg model = + let sModel, sCmd = Sheet.update sMsg model.Sheet + let newModel = { model with Sheet = sModel} + {newModel with SavedSheetIsOutOfDate = findChange newModel}, Cmd.map Sheet sCmd + + +//----------------------------------------------------------------------------------------------------------------// +//-----------------------------------------------UPDATE-----------------------------------------------------------// +//----------------------------------------------------------------------------------------------------------------// + +/// Main MVU model update function +let update (msg : Msg) oldModel = + let startUpdate = TimeHelpers.getTimeMs() + // number of top-level components in graph + // mostly, we only operate on top-level components + let getGraphSize g = + g + |> Option.map (fun sd -> sd.Graph |> Map.toList |> List.length) + |> Option.defaultValue -1 + + let sdlen = + getCurrentWSMod oldModel + |> Option.bind (fun ws -> ws.InitWaveSimGraph) + |> getGraphSize + + //Add the message to the pending queue if it is a mouse drag message + let model = + if matchMouseMsg msg then {oldModel with Pending = msg :: oldModel.Pending} + else oldModel + + //Check if the current message is stored as pending, if so execute all pending messages currently in the queue + let testMsg, cmd = + List.tryFind (fun x -> isSameMsg x msg) model.Pending + |> function + | Some _ -> + //Add any message recieved to the pending message queue + DoNothing, Cmd.ofMsg (ExecutePendingMessages (List.length model.Pending)) + | None -> + msg, Cmd.none + + // main message dispatch match expression + match testMsg with + | StartUICmd uiCmd -> + match model.UIState with + | None -> //if nothing is currently being processed, allow the ui command operation to take place + match uiCmd with + | CloseProject -> + {model with CurrentProj = None; UIState = Some uiCmd}, Cmd.none + | _ -> + {model with UIState = Some uiCmd}, Cmd.ofMsg (Sheet (Sheet.SetSpinner true)) + | _ -> model, Cmd.none //otherwise discard the message + | FinishUICmd _ -> + let popup = CustomCompPorts.optCurrentSheetDependentsPopup model + {model with UIState = None; PopupViewFunc = popup}, Cmd.ofMsg (Sheet (Sheet.SetSpinner false)) + (*| ShowExitDialog -> + match model.CurrentProj with + | Some p when model.SavedSheetIsOutOfDate -> + {model with ExitDialog = true}, Cmd.none + | _ -> // exit immediately since nothing to save + exitApp() + model, Cmd.none*) + | CloseApp -> + exitApp() + model, Cmd.none + (*| SetExitDialog status -> + {model with ExitDialog = status}, Cmd.none*) + | Sheet sMsg -> + match sMsg, model.PopupViewFunc with + | Sheet.ToggleNet canvas, _ -> + model, Cmd.ofMsg (Sheet (Sheet.SelectWires (getNetSelection canvas model))) + | Sheet.KeyPress _, Some _ -> + // do not allow keys to affect Sheet when popup is on. + model, Cmd.none + | _ -> sheetMsg sMsg model + // special mesages for mouse control of screen vertical dividing bar, active when Wavesim is selected as rightTab + | SetDragMode mode -> {model with DividerDragMode= mode}, Cmd.none + | SetViewerWidth w -> {model with WaveSimViewerWidth = w}, Cmd.none + | ReloadSelectedComponent width -> {model with LastUsedDialogWidth=width}, Cmd.none + | StartSimulation simData -> + { model with CurrentStepSimulationStep = Some simData }, + Cmd.batch [ + Cmd.ofMsg (Sheet (Sheet.SetWaveSimMode false)); + // hack to make sure wavesim highlighting is reset - but step simulation error highlighting is not. + // the state here clearly needs refactoring + if model.Sheet.IsWaveSim then Cmd.ofMsg (Sheet(Sheet.ResetSelection)) else Cmd.none + ] //Close wavesim + | SetWSMod wSMod -> + setWSMod wSMod model, Cmd.none + | UpdateWSModel updateFn -> + updateCurrentWSMod updateFn model, Cmd.none + | SetWSModAndSheet(ws,sheet) -> + match model.CurrentProj with + | None -> failwithf "What? SetWSModAndSheet: Can't set wavesim if no project is loaded" + | Some p -> + let sheets = p.LoadedComponents |> List.map (fun lc -> lc.Name) + match List.contains sheet sheets with + | false -> + failwithf "What? sheet %A can't be used in wavesim because it does not exist in project sheets %A" sheet sheets + | true -> + let model = + {model with WaveSimSheet = sheet} + |> setWSMod ws + model,Cmd.none + | SetWSError err -> + { model with WaveSim = fst model.WaveSim, err}, Cmd.none + | AddWaveSimFile (fileName, wSMod') -> + { model with WaveSim = Map.add fileName wSMod' (fst model.WaveSim), snd model.WaveSim}, Cmd.none + | SetSimulationGraph (graph, fastSim) -> + let simData = getSimulationDataOrFail model "SetSimulationGraph" + { model with CurrentStepSimulationStep = { simData with Graph = graph ; FastSim = fastSim} |> Ok |> Some }, Cmd.none + | SetSimulationBase numBase -> + let simData = getSimulationDataOrFail model "SetSimulationBase" + { model with CurrentStepSimulationStep = { simData with NumberBase = numBase } |> Ok |> Some }, Cmd.none + | IncrementSimulationClockTick n -> + let simData = getSimulationDataOrFail model "IncrementSimulationClockTick" + { model with CurrentStepSimulationStep = { simData with ClockTickNumber = simData.ClockTickNumber + n } |> Ok |> Some }, Cmd.none + | EndSimulation -> { model with CurrentStepSimulationStep = None }, Cmd.none + | EndWaveSim -> { model with WaveSim = (Map.empty, None) }, Cmd.none + | ChangeRightTab newTab -> + let inferMsg = JSDiagramMsg <| InferWidths() + let editCmds = [inferMsg; ClosePropertiesNotification] |> List.map Cmd.ofMsg + firstTip <- true + { model with RightPaneTabVisible = newTab }, + match newTab with + | Properties -> Cmd.batch <| editCmds + | Catalogue -> Cmd.batch <| editCmds + | Simulation -> Cmd.batch <| editCmds + | WaveSim -> Cmd.ofMsg (Sheet (Sheet.SetWaveSimMode true)) + + | SetHighlighted (componentIds, connectionIds) -> + let sModel, sCmd = Sheet.update (Sheet.ColourSelection (componentIds, connectionIds, HighLightColor.Red)) model.Sheet + {model with Sheet = sModel}, Cmd.map Sheet sCmd + | SetSelWavesHighlighted connIds -> + let wModel, wCmd = Sheet.update (Sheet.ColourSelection ([], Array.toList connIds, HighLightColor.Blue)) model.Sheet + {model with Sheet = wModel}, Cmd.map Sheet wCmd + | SetClipboard components -> { model with Clipboard = components }, Cmd.none + | SetCreateComponent pos -> { model with LastCreatedComponent = Some pos }, Cmd.none + | SetProject project -> + { model with + CurrentProj = Some project + PopupDialogData = {model.PopupDialogData with ProjectPath = project.ProjectPath} + }, Cmd.none + | UpdateProject update -> + CustomCompPorts.updateProjectFiles true update model, Cmd.none + | UpdateProjectWithoutSyncing update -> + CustomCompPorts.updateProjectFiles false update model,Cmd.none + | ShowPopup popup -> { model with PopupViewFunc = Some popup }, Cmd.none + | ClosePopup -> + let model' = + match getSheetWaveSimOpt model, model.PopupDialogData.WaveSetup with + | Some wsMod, Some(sheetWaves, paths) -> + setWSMod (setSimParams (fun sp -> {sp with MoreWaves = Set.toList paths}) wsMod) model + | _ -> model + { model' with + PopupViewFunc = None; + PopupDialogData = + { model.PopupDialogData with + Text = None; + Int = None; + Int2 = None; + MemorySetup = None; + MemoryEditorData = None; + }}, Cmd.none + | SetPopupDialogText text -> + { model with PopupDialogData = {model.PopupDialogData with Text = text} }, Cmd.none + | SetPopupDialogInt int -> + { model with PopupDialogData = {model.PopupDialogData with Int = int} }, Cmd.none + | SetPopupDialogTwoInts data -> + { model with PopupDialogData = + match data with + | n, FirstInt,_ -> {model.PopupDialogData with Int = Option.map int32 n} + | n, SecondInt, optText -> {model.PopupDialogData with Int2 = n} + }, Cmd.none + | SetPopupDialogMemorySetup m -> + { model with PopupDialogData = {model.PopupDialogData with MemorySetup = m} }, Cmd.none + | SetPopupWaveSetup m -> + { model with PopupDialogData = {model.PopupDialogData with WaveSetup = Some m} }, Cmd.none + | SetPopupMemoryEditorData m -> + { model with PopupDialogData = {model.PopupDialogData with MemoryEditorData = m} }, Cmd.none + | SetPopupProgress progOpt -> + { model with PopupDialogData = {model.PopupDialogData with Progress = progOpt} }, Cmd.none + | UpdatePopupProgress updateFn -> + { model with PopupDialogData = {model.PopupDialogData with Progress = Option.map updateFn model.PopupDialogData.Progress} }, Cmd.none + + | SimulateWithProgressBar simPars -> + SimulationView.simulateWithProgressBar simPars model + | SetSelectedComponentMemoryLocation (addr,data) -> + {model with SelectedComponent = updateComponentMemory addr data model.SelectedComponent}, Cmd.none + | CloseDiagramNotification -> + { model with Notifications = {model.Notifications with FromDiagram = None} }, Cmd.none + | SetSimulationNotification n -> + { model with Notifications = + { model.Notifications with FromSimulation = Some n} }, Cmd.none + | CloseSimulationNotification -> + { model with Notifications = {model.Notifications with FromSimulation = None} }, Cmd.none + | CloseWaveSimNotification -> + { model with Notifications = {model.Notifications with FromWaveSim = None} }, Cmd.none + | SetFilesNotification n -> + { model with Notifications = + { model.Notifications with FromFiles = Some n} }, Cmd.none + | CloseFilesNotification -> + { model with Notifications = {model.Notifications with FromFiles = None} }, Cmd.none + | SetMemoryEditorNotification n -> + { model with Notifications = + { model.Notifications with FromMemoryEditor = Some n} }, Cmd.none + | CloseMemoryEditorNotification -> + { model with Notifications = { model.Notifications with FromMemoryEditor = None} }, Cmd.none + | SetPropertiesNotification n -> + { model with Notifications = + { model.Notifications with FromProperties = Some n} }, Cmd.none + | ClosePropertiesNotification -> + { model with Notifications = { model.Notifications with FromProperties = None} }, Cmd.none + | SetTopMenu t -> + { model with TopMenuOpenState = t}, Cmd.none + | ExecFuncInMessage (f,dispatch)-> + (f model dispatch; model), Cmd.none + | ExecCmd cmd -> + model, cmd + | ExecFuncAsynch func -> + let cmd' = + Elmish.Cmd.OfAsyncImmediate.result (async { + //wavesim - 0 sleep will never update cursor in time, 100 will SOMETIMES be enough, 300 always works + //this number only seems to affect the wavesim spinner cursor, it does not help with open project/change sheet spinner cursor + do! (Async.Sleep 100) + if Set.contains "update" JSHelpers.debugTraceUI then + printfn "Starting ExecFuncAsynch payload" + let cmd = func () + return (ExecCmd cmd)}) + model, cmd' + | ExecCmdAsynch cmd -> + let cmd' = + Elmish.Cmd.OfAsyncImmediate.result (async { + //wavesim - 0 sleep will never update cursor in time, 100 will SOMETIMES be enough, 300 always works + //this number only seems to affect the wavesim spinner cursor. + do! (Async.Sleep 300) + return (ExecCmd cmd)}) + model, cmd' + | SendSeqMsgAsynch msgs -> + model, SimulationView.doBatchOfMsgsAsynch msgs + | MenuAction(act,dispatch) -> + getMenuView act model dispatch, Cmd.none + | DiagramMouseEvent -> model, Cmd.none + | SelectionHasChanged -> + match currWaveSimModel model with + | None | Some {WSViewState=WSClosed} -> model + | Some _ -> + { model with ConnsOfSelectedWavesAreHighlighted = true } + |> (fun m -> m, Cmd.none) + | SetWaveSimIsOutOfDate b -> + changeSimulationIsStale b model, Cmd.none + | SetIsLoading b -> + let cmd = if b then Cmd.none else Cmd.ofMsg (Sheet (Sheet.SetSpinner false)) //Turn off spinner after project/sheet is loaded + {model with IsLoading = b}, cmd + | InitiateWaveSimulation (view, paras) -> + updateCurrentWSMod (fun ws -> setEditorNextView view paras ws) model, Cmd.ofMsg FinishUICmd + //TODO + | WaveSimulateNow -> + // do the simulation for WaveSim and generate new SVGs + printfn "Starting...!" + match getCurrentWSMod model, getCurrentWSModNextView model with + | Some wsMod, Some (pars, nView) -> + let checkCursor = wsMod.SimParams.CursorTime <> pars.CursorTime + let pars' = adjustPars wsMod pars wsMod.SimParams.LastScrollPos + // does the actual simulation and SVG generation, if needed + let wsMod' = + simulateAndMakeWaves model wsMod pars' + |> (fun ws -> {ws with WSViewState=nView; WSTransition = None}) + |> setEditorView nView + model + |> setWSMod wsMod' + |> (fun model -> + {model with CheckWaveformScrollPosition=checkCursor}, + Cmd.ofMsg (Sheet(Sheet.SetSpinner false))) //turn off spinner after wavesim is loaded + | Some _, None -> + // This case may happen if WaveSimulateNow commands are stacked up due to + // repeated view function calls before the WaveSimNow trigger message is processed + // Only the first one will actually do anything. TODO: eliminate extra calls? + model, Cmd.none + | _ -> + failwith "SetSimInProgress dispatched when getCurrFileWSMod is None" + + | SetLastSimulatedCanvasState cS -> + { model with LastSimulatedCanvasState = cS }, Cmd.none + | UpdateScrollPos b -> + { model with CheckWaveformScrollPosition = b}, Cmd.none + | SetLastScrollPos posOpt -> + let updateParas (sp:SimParamsT) = {sp with LastScrollPos = posOpt} + updateCurrentWSMod (fun (ws:WaveSimModel) -> setSimParams updateParas ws) model, Cmd.none + | SetWaveSimModel( sheetName, wSModel) -> + let updateWaveSim sheetName wSModel model = + let sims,err = model.WaveSim + sims.Add(sheetName, wSModel), err + {model with WaveSim = updateWaveSim sheetName wSModel model}, Cmd.none + | ExecutePendingMessages n -> + if n = (List.length model.Pending) + then + getLastMouseMsg model.Pending + |> function + | None -> failwithf "shouldn't happen" + | Some mMsg -> + match mMsg with + | Sheet sMsg -> sheetMsg sMsg model + | _ -> failwithf "shouldn't happen " + + //ignore the exectue message + else + model, Cmd.none + | DoNothing -> //Acts as a placeholder to propergrate the ExecutePendingMessages message in a Cmd + model, cmd + | msg -> + model, Cmd.none + |> (fun (newModel,cmd) -> resetDialogIfSelectionHasChanged newModel oldModel,cmd) + |> (fun res -> + if JSHelpers.debugLevel > 0 then + TimeHelpers.instrumentInterval ( + let name = + match msg with + | SetWSMod _ -> "U(SetWSMod)" + | Sheet( Sheet.Msg.Wire (BusWire.Msg.Symbol _ )) -> "U(Sheet(Wire(Symbol)))" + | Sheet (Sheet.Msg.Wire (BusWire.UpdateWires _)) -> "U(Sheet(Wire(UpdateWires)))" + | SetWaveSimModel _ -> "U(SetWaveSimModel)" + | SetWSModAndSheet _ -> "U(SetWsModAndSheet)" + | StartSimulation _ -> "U(StartSimulation)" + | SetSimulationGraph _ -> "U(SetSimulationGraph)" + | SetPopupMemoryEditorData _ -> "U(SetPopupmemoryEditorData)" + | _ -> $"U(%.40A{msg})" + let debugMsg = Helpers.sprintInitial 40 name + if Set.contains "update" JSHelpers.debugTraceUI then + printfn "%s" debugMsg + debugMsg) startUpdate |> ignore + res) + + + diff --git a/src/Renderer/UI/WaveSimHelpers.fs b/src/Renderer/UI/WaveSimHelpers.fs new file mode 100644 index 0000000..5e9847e --- /dev/null +++ b/src/Renderer/UI/WaveSimHelpers.fs @@ -0,0 +1,1260 @@ +module WaveSimHelpers + +open Fable.React +open Fable.React.Props + +open Fulma +open TimeHelpers +open ModelType +open DiagramStyle +open CommonTypes +open FileMenuView +open Extractor +open SimulatorTypes + +let maxLastClk = 500u + +type WaveGapT = { + /// length of stable waveform in cycles + GapLen: int + /// starting cycle of stable waveform + GapStart: int + } + +//////////////////////// +/// Radix conversion /// +//////////////////////// + + +// TODO: Rationalise by deleting these and using instead the functions in Helpers. + +let private charList2String (charLst: char list) = + List.map string charLst + |> List.toSeq + |> String.concat "" + +let dec2bin (n:bigint) (nBits:uint32) = + [0u..nBits - 1u] + |> List.rev + |> List.map (fun bitNum -> if n &&& (1I <<< int bitNum) = 0I then '0' else '1') + +let dec2hex (n: bigint) (nBits: uint32): string = + let seqPad = + let times = (4 - int nBits % 4) % 4 + Seq.replicate times '0' + + let paddedBin = + dec2bin n nBits + |> Seq.append seqPad + |> Seq.toList + + let fourBit2HexDig = + let bit vec n = if (1 <<< n) &&& vec = 0 then '0' else '1' + let hexDigOf n = (sprintf "%x" n)[0] + [0..15] + |> List.map (fun dig -> + List.map (bit dig) [3..-1..0], hexDigOf dig) + |> Map.ofList + + [ 0 .. 4 .. List.length paddedBin - 4 ] + |> List.map (fun i -> fourBit2HexDig[ paddedBin[i..i + 3] ]) + |> charList2String + +let dec2sdec (n: bigint) (nBits: uint32) = + if (dec2bin n nBits)[0] = '1' + then n - bigint (2.0 ** (float nBits)) + else n + |> string + +/// convert number to number string of the chosen radix +let n2StringOfRadix (hasRadixPrefix: bool) (n: bigint) (nBits: uint32) (rad: NumberBase) = + let pref = + match rad with + | Bin -> "0b" + | Hex -> "0x" + | _ -> "" + match rad with + | Dec -> string n + | Bin -> dec2bin n nBits |> charList2String + | Hex -> dec2hex n nBits + | SDec -> dec2sdec n nBits + |> (fun numberRepStr -> (if hasRadixPrefix then pref else "") + numberRepStr) + + +///////////////////////////// +// General WaveSim Helpers // +///////////////////////////// + +/// Get an option of the reduced canvas state, with geometry eliminated, good for electrical +/// circuit comparisons +let getReducedCanvState model = extractReducedState <| model.Sheet.GetCanvasState () + +/// get NetList from WaveSimModel +let wsModel2netList wsModel = + match wsModel.LastCanvasState with + | Some canvState -> Helpers.getNetList canvState + | None -> Map.empty + +// Look up netgroup (= waveform) name from WaveData and netgroup +// If Netgroup is not in AllNetGroups return "ERROR" +let waveNameOf (ws:WaveSimModel) (wave: WaveformSpec) = + Map.tryFindKey (fun _ p -> p = wave) ws.AllWaves + |> Option.defaultValue "ERROR" + +let reactTickBoxRow name nameStyle ticked toggleFun = + tr + [ Class "rowHeight" + Style [ VerticalAlign "middle" ] ] + [ td + [ Class "wAcheckboxCol" + Class "rowHeight" + Style [ VerticalAlign "middle" ] ] + [ input + [ Type "checkbox" + Class "check" + Checked <| ticked + Style [ Float FloatOptions.Left ] + OnChange toggleFun ] ] + td [] [ label [Style nameStyle] [ str name] ] ] + +//////////////////////// + + + + + + + + +//-------------------------------------------------------------------------------------------------------// +//---------------------------------More wave Helpers-----------------------------------------------------// +//-------------------------------------------------------------------------------------------------------// + +/// get components on other sheets, and RAMs, formatted for setting up "more" waveform selection. +/// The output is used as data for the "more wave select" popup. +let getWaveSetup (ws:WaveSimModel) (model:Model): MoreWaveSetup = + /// get immediate subsheets of given sheet (sg,name,path) + let rec subSheets ((sg,name,label,path):SimulationGraph*string*ComponentLabel*ComponentId list) : (SimulationGraph*string*ComponentLabel*ComponentId list) list = + Map.toList sg + |> List.collect (fun (cId,comp) -> + match comp.Type with + | Custom custComp -> [Option.get comp.CustomSimulationGraph, custComp.Name, comp.Label, path @ [cId]] | _ -> []) + /// get all sheets rooted in (sg,name,path) + let rec allSheets ((sg,name,label,path): SimulationGraph * string *ComponentLabel* ComponentId list) = + match subSheets (sg,name,label,path) with + | [] -> [sg,name,label,path] + | sheets -> [sg,name,label,path] @ List.collect allSheets sheets + let mainSheet = ((Option.get ws.InitWaveSimGraph).Graph, model.WaveSimSheet,ComponentLabel "", []) + let sheets = allSheets mainSheet + let getSortOf path (comp:SimulationComponent) = + match comp.Type, path with + | RAM1 _,_ -> Some (4, "RAM") + | AsyncRAM1 _,_ -> Some(5,"ARAM") + | AsyncROM1 _,_ | ROM1 _,_ -> Some (6, "ROM") + | _,[] | _, [_] -> None + | Input _,_-> Some (1,"Input") + | Output _,_ -> Some (2, "Output") + | IOLabel,_ -> Some (3, "Bus Label") + | _ -> None + let sheetCol = + fun (sg, name, ComponentLabel label,path) -> + Map.toList sg + |> List.map (fun (cid,comp) -> getSortOf path comp, path @ [cid]) + |> List.sort + |> List.collect (function | (Some (i,ctyp),path) -> [{Label = label;Sheet=name; Path=path;CSort=ctyp}] | _ -> []) + sheets + |> List.collect sheetCol + |> (fun cols -> cols, (Set.ofList ws.SimParams.MoreWaves)) + +/// get component from graph subsheet with given name path +let rec getSimComp (sg:SimulationGraph) path = + match path with + | [] -> failwithf "What? Path cannot be [] looking up sim component in wave sim" + | [cid]-> sg[cid] + | h :: t -> + match sg[h].CustomSimulationGraph with + | Some sg -> getSimComp sg t + | None -> failwithf "What? A non-terminal part of a path must have a customSimulationgraph" + +/// get component from graph subsheet with given name path +let rec getSimCompOpt (sg:SimulationGraph) path = + match path with + | [] -> None + | [cid]-> Map.tryFind cid sg + | h :: t -> + match Map.tryFind h sg with + | Some {CustomSimulationGraph = Some sg} -> getSimCompOpt sg t + | Some x -> failwithf "What? Lookup of compnent in simulationgraph failed" + | None -> None + +/// Get the form data for RAM (and other extra) simulation setup +let reactMoreWaves ((sheets,ticks): MoreWaveSetup) (sg:SimulationGraph) (dispatch: Msg -> Unit) = + let makeTableCell r = td [Style [VerticalAlign Top]] [r] + let makeWaveReactList (swL:SheetWave list) = + swL + |> List.map (fun sw -> + let comp = getSimComp sg sw.Path + let ticked = Set.contains sw.Path ticks + let toggle _ = + let ticks = if ticked then Set.remove sw.Path ticks else Set.add sw.Path ticks + dispatch <| SetPopupWaveSetup(sheets,ticks) + let name = comp.Label |> function | ComponentLabel lab -> lab + (sw.Label+":"+name),ticked, comp, toggle) + |> (fun els -> + let isRamOrRom (comp: SimulationComponent) = + match comp.Type with | RAM1 _ | AsyncRAM1 _ | ROM1 _ | AsyncROM1 _ -> true | _ -> false + let uniques = + List.countBy (fun (name,ticked,comp, toggle) -> name) els + |> List.filter (fun (el,i)-> i = 1) + |> List.map fst + |> Set + List.filter (fun (name,ticked,comp, toggle) -> isRamOrRom comp && Set.contains name uniques) els) + |> List.map (fun (name, ticked, comp, toggle) -> reactTickBoxRow name [] ticked toggle) + + let makeReactCol (name, sheetWaves) = + let colBody = makeWaveReactList sheetWaves + if colBody <> [] then + table [Style [Display DisplayOptions.InlineBlock; VerticalAlign Top; PaddingLeft "5px"; PaddingRight "5px"]] + [tbody [Style [Display DisplayOptions.Inline]] <| [tr [] [th [ColSpan 2; Style [TextAlign TextAlignOptions.Center]] [str name]]] @ colBody] + else div [] [] + + let cols = + sheets + |> List.groupBy (fun {Sheet=name}->name) + |> List.map makeReactCol + |> List.map makeTableCell + if cols = [] then + str "There are no memories (RAM or ROM), in this design." + else + table [] [tbody [] [tr [] cols]] + +let formatMemory (mem:Memory1) = + let maxFilledGap = 2L + let sortedLocs = + Map.toList mem.Data + |> List.sort + |> List.filter (fun (a,d) -> d <> 0L) + let makeRamLoc (addr: int64) (dat:int64) = + let disp (v:int64) w = dec2hex (bigint v) (uint32 w) + sprintf "[0x%s]: 0x%s" (disp addr mem.AddressWidth) (disp dat mem.WordWidth) + let dispGap endG startG = + match endG - startG with + | x when x > maxFilledGap -> + [ "[...]: 0x0" ] + | _ -> + [startG..endG - 1L] + |> List.map (fun a -> makeRamLoc a 0L) + + let rec fillGaps curAddr lst = + match lst with + | [] -> dispGap ((1L <<< mem.AddressWidth) - 1L) curAddr + | (addr, dat) :: lst' -> dispGap addr curAddr @ [ makeRamLoc addr dat ] @ fillGaps (addr+1L) lst' + fillGaps 0L sortedLocs + + +/// return sample at current cursor position +let getCursorSampleFromGraph (wSMod: WaveSimModel) = + let n = int wSMod.SimParams.CursorTime + wSMod.SimDataCache[n].Graph + +/// get Ram contents as array to display. RAM contents is +/// determined on cursor sample from wSMod +let getRamInfoToDisplay wSMod (path: ComponentId list) = + let cursorStep = wSMod.SimParams.CursorTime + let sdOpt = Array.tryItem (int cursorStep) wSMod.SimDataCache + let apLst = path |> List.rev |> function | (h::rest) -> h :: (List.rev rest) | [] -> [] + match sdOpt, apLst with + | Some sd, (cid :: ap) -> + let state = FastRun.extractFastSimulationState sd.FastSim (int cursorStep) (cid,ap) + let lab = match sd.FastSim.FComps[cid,ap].SimComponent.Label with | ComponentLabel lab -> lab + match state with + | RamState dat -> + lab, formatMemory dat + | _ -> lab, [] + | _ -> "",[] + + + + + +//------------------------------------------------------------------------------------------------------// +//--------------------------------------NetGroup Helpers------------------------------------------------// +//------------------------------------------------------------------------------------------------------// + + + + + +/// Get NetGroup from targets which represents the group of nLTargets connected by IOLabels. +/// targets:list of inputs connected to a single driving component output (e.g. a connected Net). +/// Return the containing NetGroup, where Nets connected by IOLabels form single Netgroups. +let rec private getNetGroup (netList: NetList) targets = failwithf "this function is no longer implemented" + +/// returns a bool representing if the given NLTarget is present in the given NetList +let private isNetListTrgtInNetList (netList: NetList) (nlTrgt: NLTarget) = + Map.exists (fun _ (nlComp: NetListComponent) -> + Map.exists (fun _ nlTrgtLst -> List.contains nlTrgt nlTrgtLst) nlComp.Outputs) netList + + (* +/// get array of TrgtLstGroup with the non-existing NLTargets removed +let private getReloadableNetGroups (model: Model) (netList: NetList) = + match currWaveSimModel model with + | Some wSModel -> + dispWaves wSModel + |> Array.map (fun netGroup -> netGroup.driverNet) + |> Array.map (List.filter <| isNetListTrgtInNetList netList) + |> Array.filter ((<>) []) + |> Array.map (getNetGroup netList) + | None -> [||] *) + +/// advance SimulationData by 1 clock cycle +let private clkAdvance (sD: SimulationData) = + let sD = + if sD.ClockTickNumber = 0 then + // set up the initial fast simulation + {sD with FastSim = match FastRun.buildFastSimulation (int maxLastClk) sD.Graph with | Ok fs -> fs | Error e -> failwithf "fast simulation error"} + else + sD + //feedClockTick sD.Graph + //|> (fun graph -> + let newClock = sD.ClockTickNumber + 1 + FastRun.runFastSimulation newClock sD.FastSim + { sD with + Graph = sD.Graph + ClockTickNumber = newClock } + +/// array of SimData for the given number of cycles +let extractSimData simData nCycles = + (simData, [| 1u .. nCycles |]) + ||> Array.mapFold (fun s _ -> + let s' = clkAdvance s + (s',s')) + |> fst + +/// get NLSource option from ComponentId and InputPortNumber +let private drivingOutput (netList: NetList) compId inPortN = + netList[compId].Inputs[inPortN] + + + +/// get array of available NLSource in current canvas state +let availableNetGroups (model: Model) = + match getSheetWaveSimOpt model with + | None -> [||] + | Some waveSim -> + waveSim.LastCanvasState + |> Option.defaultValue ([],[]) + |> Helpers.getNetList + |> makeAllNetGroups + + + +/// get instantaneous value of a port +let private simWireData2Wire wireData = + wireData + |> List.mapFold (fun weight bit -> + match bit with + | SimulatorTypes.Bit.Zero -> bigint 0 + | SimulatorTypes.Bit.One -> weight + |> (fun r -> r, weight * (bigint 2))) (bigint 1) + |> fst + |> List.sum + +/// extract current value of the given array of SourceGroup +let getSimTime (waves: WaveformSpec array) (simData: SimulationData) = + let fs = simData.FastSim + let step = simData.ClockTickNumber + let topLevelComps = simData.FastSim.FComps + FastRun.runFastSimulation step fs + waves + |> Array.map (fun wave -> + try + let driver,opn = wave.Driver + let wD = FastRun.extractFastSimulationOutput fs step driver opn + Wire + { NBits = uint (List.length wD) + BitData = simWireData2Wire wD } + with + | e -> + printfn "Exception: %A" e.StackTrace + printSimGraph simData.Graph + failwithf "What? This error in getSimTime should not be possible" + + ) + + +/// get all values of waveforms +let getAllWaveSimDataBySample (wsMod: WaveSimModel) = + let waves = dispWaves wsMod + wsMod.SimDataCache + |> Array.map (getSimTime waves) + +/// get values of waveforms for one sample +let getWaveSimDataOneSample (wsMod: WaveSimModel) (sample:int) = + let waves = dispWaves wsMod + wsMod.SimDataCache[sample] + |> getSimTime waves + + + + +/// extend WaveSimModel.SimData by n cycles +let private appendSimData (model: Model) (wSModel: WaveSimModel) nCycles = + match wSModel.SimDataCache with + | [||] -> + SimulationView.makeSimData model + |> Option.map fst + |> ( Option.map (Result.map (fun sd -> extractSimData sd nCycles))) // TODO simulate this ncycles no init data + | dat -> + extractSimData (Array.last dat) nCycles + |> Array.append dat + |> Ok + |> Some + +/// get Connection list (1 or 0) from ConnectionId (as a string) +let private connId2Conn (sheet: Sheet.Model) (connId: ConnectionId) : Connection list = + match sheet.GetCanvasState() with + | (_, conns) -> + List.tryFind (fun (conn: Connection) -> ConnectionId conn.Id = connId) conns + |> function + | Some conn -> [ conn ] + | None -> [] + +/// get Ids of connections in a trgtLstGroup +let private wave2ConnIds (netGrp: NetGroup) = + Array.append [|netGrp.driverNet|] netGrp.connectedNets + |> Array.collect (fun net -> + List.toArray net + |> Array.map (fun net -> net.TargetConnId)) + + +/// select or deselect the connections of a given waveSpec +let selectWaveConns (model: Model) (on : bool) (wave: WaveformSpec) (dispatch: Msg -> unit) = + let sheetDispatch sMsg = dispatch (Sheet sMsg) + wave.Conns + |> Array.toList + |> model.Sheet.SelectConnections sheetDispatch on + +let selectExactConns (model: Model) (conns: ConnectionId array) (dispatch: Msg -> unit) = + let allConns = + snd <| model.Sheet.GetCanvasState() + |> List.map (fun conn -> ConnectionId conn.Id) + |> Set.ofList + let otherConns = allConns - Set.ofArray conns + let sheetDispatch sMsg = dispatch (Sheet sMsg) + model.Sheet.SelectConnections sheetDispatch true (conns |> Array.toList) + model.Sheet.SelectConnections sheetDispatch false (Set.toList otherConns) + + + + +/// returns labels of all custom component instances of sheet in lComp +let findInstancesOf sheet (lComp:LoadedComponent) = + lComp.CanvasState + |> fst + |> List.collect (function | {Type=(Custom {Name=sheet'})} as comp when sheet' = sheet-> [comp.Label] | _ -> []) + + +/// finds out if current sheet is used in some other sheet. +/// works recursively to find root sheet +/// returns current wavesim sheet if there is a cycle, or more than one path to a root +let getRootSheet (model:Model) = + match model with + | {CurrentProj = (Some ({LoadedComponents=lComps} as proj))} -> + let openSheet = model.WaveSimSheet + if List.tryFind (fun lc -> lc.Name = openSheet) proj.LoadedComponents = None + then failwithf "Can't find wavesim sheet in loadedcomponents" + let getParentData (sheet:string) = + lComps + |> List.filter (fun lComp -> lComp.Name <> sheet) // can't be own parent + |> List.collect (fun lComp -> + let parentName = lComp.Name + match findInstancesOf sheet lComp with + | [] -> [] //not a parent + | [_] -> [parentName] + | _ -> [openSheet]) // if more than one instance can't analyse + let rec findRoot (traversedSheets:string list) (sheet:string) = + if List.contains sheet traversedSheets then + openSheet + else + match getParentData sheet with + | [root] -> findRoot (sheet :: traversedSheets) root + | [] -> sheet + | _ -> openSheet + Some <| findRoot [] openSheet + | _ -> None // should never happen + +let getCustoms (cid:ComponentId,comp:SimulationComponent) = + match comp.Type with + | Custom c -> [cid, c.Name,comp] + | _ -> [] + +let simGraphOrFail (comp:SimulationComponent) = + match comp.CustomSimulationGraph with + | Some x -> x + | None -> failwithf "What? a Custom component %A appears to have no simulation graph" comp + +/// return a function which can extract the correct SimulationGraph from the current simulation +/// for the given sheet. The parameter is a sample SumulationGraph +let getSimGraph (sheet:string) (graph:SimulationGraph) = + let makeSelector cids = + (id, List.rev cids) + ||> List.fold (fun selFun cid -> + let func graph = simGraphOrFail (Map.find cid graph) + selFun >> func) + + + let rec getGraph (customs:ComponentId list) (thisSheet:string) (graph:SimulationGraph) : (SimulationGraph -> SimulationGraph) array = + if sheet = thisSheet + then + [|id|] + else + Map.toArray graph + |> Array.collect (getCustoms >> List.toArray) + |> Array.collect (fun (cid,sheet',comp) -> + if sheet' = sheet then + [|makeSelector (cid :: customs)|] + else + getGraph (cid :: customs) sheet' (Option.defaultValue (failwithf "What? %A should have a CustomSimulationGraph" comp) comp.CustomSimulationGraph)) + + getGraph [] sheet graph + |> function | [|f|] -> f | x -> failwithf "Wrong number of candidates %A to find %s in Simgraph" x sheet + + + + + +//--------------------------// +// Naming of waveforms // +//--------------------------// + +/// get common NLSource of list of NLTarget with the same source +let private nlTrgtLst2CommonNLSource (netList: NetList) (nlTrgtLst: NLTarget list) : NLSource option = + List.tryPick (fun (nlTrgt: NLTarget) -> + match Map.tryFind nlTrgt.TargetCompId netList with + | Some comp -> + match Map.tryFind nlTrgt.InputPort comp.Inputs with + | Some (Some src) -> Some src + | _ -> None + | None -> None ) nlTrgtLst + +/// get label without (x:x) part at the end +let private labelNoParenthesis (netList: NetList) compId = + let lbl = netList[compId].Label + match Seq.tryFindIndexBack ((=) '(') lbl with + | Some i -> lbl[0..i - 1] + | None -> lbl + +/// get integer from OutputPortInt +let private outPortInt2int outPortInt = + match outPortInt with + | OutputPortNumber pn -> pn + +/// get labels of Output and IOLabel components in nlTargetList +let net2outputsAndIOLabels (netList: NetList) (netLst: NLTarget list) = + let nlTrgt2Lbls st nlTrgt = + match Map.tryFind nlTrgt.TargetCompId netList with + | Some nlComp -> match nlComp.Type with + | IOLabel | Output _ -> List.append st [netList[nlTrgt.TargetCompId].Label] + | _ -> st + | None -> st + List.fold nlTrgt2Lbls [] netLst + |> List.distinct + +/// get labels of Output and IOLabel components in TargetListGroup +let netGroup2outputsAndIOLabels netList (netGrp: NetGroup) = + Array.append [|netGrp.driverNet|] netGrp.connectedNets + |> Array.toList + |> List.collect (net2outputsAndIOLabels netList) + |> List.distinct + + +let rec private removeSubSeq startC endC chars = + ((false,[]), chars) + ||> Seq.fold (fun (removing,res) ch -> + match removing,ch with + | true, ch when ch = endC -> false,res + | true, _ -> true, res + | false, ch when ch = startC -> true,res + |false, ch -> false, ch :: res) + |> snd + |> List.rev + |> List.map string + |> String.concat "" + + + + + +/// truncate names to remove redundant width specs +let private simplifyName name = + name + |> removeSubSeq '(' ')' + +/// get WaveLabel corresponding to a NLTarget list +let rec private findName (compIds: ComponentId Set) (sd: SimulationData) (net: NetList) netGrp nlTrgtList = + let graph = sd.Graph + let fs = sd.FastSim + match nlTrgtLst2CommonNLSource net nlTrgtList with + //nlTrgtLst is not connected to any driving components + | None -> { OutputsAndIOLabels = []; ComposingLabels = [] } + | Some nlSource -> + //TODO check if its ok to comment this? + if not (Set.contains nlSource.SourceCompId compIds) then + // printfn "DEBUG: In findname, if not \n nlSource = %A \n compIds = %A" nlSource compIds + // printfn "What? graph, net, netGrp, nltrgtList should all be consistent, compIds is deprecated" + // component is no longer in circuit due to changes + { OutputsAndIOLabels = []; ComposingLabels = [] } + else + let compLbl = labelNoParenthesis net nlSource.SourceCompId + let outPortInt = outPortInt2int nlSource.OutputPort + let drivingOutputName inPortN = + match drivingOutput net nlSource.SourceCompId inPortN with + | Some nlSource' -> + net[nlSource'.SourceCompId].Outputs[nlSource'.OutputPort] + |> findName compIds sd net netGrp + | None -> { OutputsAndIOLabels = []; ComposingLabels = [] } + let srcComp = net[nlSource.SourceCompId] + match net[nlSource.SourceCompId].Type with + | ROM _ | RAM _ | AsyncROM _ -> + failwithf "What? Legacy RAM component types should never occur" + + | Not | And | Or | Xor | Nand | Nor | Xnor | Decode4 | Mux2 | BusCompare _ -> + [ { LabName = compLbl; BitLimits = 0, 0 } ] + | Input w | Output w | Constant1(w, _,_) | Constant(w,_) | Viewer w -> + [ { LabName = compLbl; BitLimits = w - 1, 0 } ] + | Demux2 -> + [ { LabName = compLbl + "." + string outPortInt; BitLimits = 0, 0 } ] + | NbitsXor w -> + [ { LabName = compLbl; BitLimits = w - 1, 0 } ] + | NbitsAdder w -> + match outPortInt with + | 0 -> [ { LabName = compLbl + ".Sum"; BitLimits = w - 1, 0 } ] + | _ -> [ { LabName = compLbl + ".Cout"; BitLimits = w - 1, 0 } ] + | DFF | DFFE -> + [ { LabName = compLbl + ".Q"; BitLimits = 0, 0 } ] + | Register w | RegisterE w -> + [ { LabName = compLbl + ".Dout"; BitLimits = w-1, 0 } ] + | RAM1 mem | AsyncRAM1 mem | AsyncROM1 mem | ROM1 mem -> + [ { LabName = compLbl + ".Dout"; BitLimits = mem.WordWidth - 1, 0 } ] + | Custom c -> + [ { LabName = compLbl + "." + (fst c.OutputLabels[outPortInt]) + BitLimits = snd c.OutputLabels[outPortInt] - 1, 0 } ] + | MergeWires -> + List.append (drivingOutputName (InputPortNumber 1)).ComposingLabels + (drivingOutputName (InputPortNumber 0)).ComposingLabels + | SplitWire w -> + let mostsigBranch (_, b) = + match outPortInt with + | 0 -> b >= 16 - w + | 1 -> b < 16 - w + | _ -> failwith "SplitWire output port number greater than 1" + + let split { LabName = name; BitLimits = msb, lsb } st = + List.zip [ lsb .. msb ] [ st + msb - lsb .. -1 .. st ] + |> List.filter mostsigBranch + |> List.unzip + |> function + | [], _ -> None + | lst, _ -> Some { LabName = name + BitLimits = List.max lst, List.min lst } + + let updateState { LabName = _; BitLimits = msb, lsb } st = + st + msb - lsb + 1 + + (0, (drivingOutputName (InputPortNumber 0)).ComposingLabels) + ||> List.mapFold (fun st lstEl -> split lstEl st, updateState lstEl st) + |> fst + |> List.choose id + | BusSelection(w, oLSB) -> + let filtSelec { LabName = name; BitLimits = msb, lsb } st = + List.zip [ lsb .. msb ] [ st .. st + msb - lsb ] + |> List.filter (fun (_, b) -> oLSB <= b && b <= oLSB + w - 1) + |> List.unzip + |> function + | [], _ -> None + | lst, _ -> Some { LabName = name + BitLimits = List.max lst, List.min lst } + + let updateState { LabName = _; BitLimits = msb, lsb } st = + st + msb - lsb + 1 + + ((drivingOutputName (InputPortNumber 0)).ComposingLabels, 0) + ||> List.mapFoldBack (fun lstEl st -> filtSelec lstEl st, updateState lstEl st) + |> fst + |> List.choose id + |> List.rev + | IOLabel -> + let drivingComp = fs.FIOActive[ComponentLabel srcComp.Label,[]] + let ioLblWidth = FastRun.extractFastSimulationWidth fs (drivingComp.Id,[]) (OutputPortNumber 0) + match ioLblWidth with + | None -> + failwithf $"What? Can't find width for IOLabel {net[srcComp.Id].Label}$ " + | Some width -> + + [ { LabName = compLbl + BitLimits = width - 1, 0 } ] + + |> (fun composingLbls -> { OutputsAndIOLabels = netGroup2outputsAndIOLabels net netGrp + ComposingLabels = composingLbls }) + + +/// get string in the [x:x] format given the bit limits +let private bitLimsString (a, b) = + match (a, b) with + | (0, 0) -> "" + | (msb, lsb) when msb = lsb -> sprintf "[%d]" msb + | (msb, lsb) -> sprintf "[%d:%d]" msb lsb + +/// get the label of a waveform +let netGroup2Label compIds (sd:SimulationData) netList (netGrp: NetGroup) = + let start = getTimeMs() + let waveLbl = findName compIds sd netList netGrp netGrp.driverNet + //printfn "Finding label for %A\n%A\n\n" netGrp.driverComp.Label waveLbl.OutputsAndIOLabels + let tl = + match waveLbl.ComposingLabels with + | [ el ] -> el.LabName + bitLimsString el.BitLimits + | lst when List.length lst > 0 -> + let appendName st lblSeg = st + lblSeg.LabName + bitLimsString lblSeg.BitLimits + ", " + List.fold appendName "{" lst + |> (fun lbl -> lbl[0..String.length lbl - 3] + "}") + | _ -> "" + let appendName st name = st + name + ", " + match waveLbl.OutputsAndIOLabels with + | [] -> tl + | hdLbls -> + List.fold appendName "" hdLbls + |> (fun hd -> hd[0..String.length hd - 3] + " : " + tl) + |> simplifyName + |> instrumentInterval "netGroup2Label" start + + + + +// Required wSModel with correct simulation. +// Sets AllWaveNames and AllPorts from netlist derived from simulation +// filters +let setWSAllPorts (availablePorts: NetGroup array) (wSModel:WaveSimModel) : WaveSimModel = failwithf "not implemented" + +////////////////// +/// SVG shapes /// +////////////////// + +let makeLinePoints style (x1, y1) (x2, y2) = + line + (List.append style + [ X1 x1 + Y1 y1 + X2 x2 + Y2 y2 ]) [] + +let makeSvg style elements = svg style elements +let makeLine style = line style [] +let makeText style t = text style [ str t ] + +let backgroundSvg (model: WaveSimModel) = + let clkLine x = makeLinePoints [ Class "clkLineStyle" ] (x, vPos) (x, vPos + sigHeight + spacing) + [| 1u .. model.SimParams.LastClkTime + 1u |] + |> Array.map ((fun x -> float x * model.SimParams.ClkSvgWidth) >> clkLine) + +let button options func label = + Button.button (List.append options [ Button.OnClick func ]) [ str label ] + + + +//-----------------// +// Transitions // +//-----------------// + +/// get m x (n-1) array of integers representing when value change between clock cycles from m x n waveData +/// (1: change, 0 no change) +let transitions waveData = + let isDiff (ws1, ws2) = + let folder state e1 e2 = + match state, e1 = e2 with + | 0, true -> 0 + | _ -> 1 + match ws1, ws2 with + | Wire a, Wire b -> + if a.BitData = b.BitData then 0 else 1 + | StateSample a, StateSample b when Array.length a = Array.length b -> + (a, b) ||> Array.fold2 folder 0 + | _ -> 1 + + Array.transpose waveData + |> Array.map (Array.pairwise >> Array.map isDiff) + +/// get gaps - periods for which waveform is stable - from transition array +let makeGaps trans = + Array.append trans [| 1 |] + |> Array.mapFold (fun tot t -> tot, tot + t) 0 + |> fst + |> Array.indexed + |> Array.groupBy snd + |> Array.map (fun (_, gL) -> + let times = Array.map fst gL + { + GapLen = Array.max times - Array.min times + 1 + GapStart = Array.min times + }) + +/// get value positions of bus labels from the transition gaps (for one Waveform) +let private busLabelPositions (wSModel: WaveSimModel) (wave: Waveform) gaps = + let clkWidth = wSModel.SimParams.ClkSvgWidth + let nSpaces gap = + (float gap.GapLen * clkWidth / (float maxBusValGap + 1.) + 2.) + let busLabelXPosition g i = + float g.GapStart + float i * float g.GapLen / float (nSpaces g) + gaps + |> Array.map (fun (gap) -> + {| WaveValue = wave[gap.GapStart] + XPosArray = Array.map (busLabelXPosition gap) [| 1 .. int (nSpaces gap) - 1 |] |} ) + +/// get values position of bus labels +let private busLabels (wSModel: WaveSimModel) waveData = + (Array.transpose waveData, Array.map makeGaps (transitions waveData)) + ||> Array.map2 (busLabelPositions wSModel) + +/// get the labels of a waveform for a period in which the value doesn't change +let private busLabelRepeats wsMod (busLabelValAndPos: {| WaveValue: Sample; XPosArray: float [] |}) = + let addLabel nLabels xInd = makeText (inWaveLabel nLabels xInd wsMod) + match busLabelValAndPos.WaveValue with + | Wire w when w.NBits > 1u -> + Array.map (fun xInd -> + addLabel 1 xInd (n2StringOfRadix true w.BitData w.NBits wsMod.WaveViewerRadix)) busLabelValAndPos.XPosArray + | _ -> [||] + +//--------------------// +// WaveSim Actions // +//--------------------// + +/// get SVG of a single waveform for one clock cycle +let private makeClkSegment (clkW: float) (xInd: int) = + let top = spacing + let bot = top + sigHeight - sigLineThick + let left = float xInd * clkW + let right = left + float clkW + let mid = left + float clkW / 2. + + let makeSigLine = + makeLinePoints + [ Class "sigLineStyle" + Style [ Stroke("blue") ] ] + + let clkPoints = [ + (left, top) + (mid, top) + (mid, bot) + (right, bot) + (right, top) + ] + + clkPoints + |> List.pairwise + |> List.map (fun (p1,p2) -> makeSigLine p1 p2) + |> List.toArray + + + + +/// get SVG of a single waveform for one clock cycle +let private makeSegment (clkW: float) (xInd: int) (data: Sample) (trans: int * int) = + let top = spacing + let bot = top + sigHeight - sigLineThick + let left = float xInd * clkW + let right = left + float clkW + + let makeSigLine = + makeLinePoints + [ Class "sigLineStyle" + Style [ Stroke("blue") ] ] + + match data with + | Wire w when w.NBits = 1u -> + let y = + match w.BitData with + | n when n = bigint 1 -> top + | _ -> bot + let sigLine = makeSigLine (left, y) (right, y) + match snd trans with + | 1 -> [| makeSigLine (right, bot + sigLineThick / 2.0) (right, top - sigLineThick / 2.0) |] + | 0 -> [||] + | _ -> failwith "What? Transition has value other than 0 or 1" + |> Array.append [| sigLine |] + | _ -> + let leftInner = if fst trans = 1 then left + transLen else left + let rightInner = if snd trans = 1 then right - transLen else right + let cen = (top + bot) / 2.0 + + //make lines + let topL = makeSigLine (leftInner, top) (rightInner, top) + let botL = makeSigLine (leftInner, bot) (rightInner, bot) + let topLeft = makeSigLine (left, cen) (leftInner, top) + let botLeft = makeSigLine (left, cen) (leftInner, bot) + let topRight = makeSigLine (right, cen) (rightInner, top) + let botRight = makeSigLine (right, cen) (rightInner, bot) + + match trans with + | 1, 1 -> [| topLeft; botLeft; topRight; botRight |] + | 1, 0 -> [| topLeft; botLeft |] + | 0, 1 -> [| topRight; botRight |] + | 0, 0 -> [||] + | _ -> failwith "What? Transition has value other than 0 or 1" + |> Array.append [| topL; botL |] + + + + +/// SVG of the clock numbers above the waveforms +let clkRulerSvg (model: WaveSimModel) = + let makeClkRulLbl i = + match model.SimParams.ClkSvgWidth with + | clkW when clkW < 0.5 && i % 5 <> 0 -> [||] + | _ -> [| makeText (cursRectText model i) (string i) |] + [| 0 .. int model.SimParams.LastClkTime |] + |> Array.collect makeClkRulLbl + |> Array.append (backgroundSvg model) + |> makeSvg (clkRulerStyle model) + + +/// get SVG of a positive edge trigerred CLK waveform +let makeClkSvg (sampArr: Waveform) (wsMod): ReactElement [] = + [|0.. Array.length sampArr - 1|] + |> Array.map (makeClkSegment (wsMod.ClkWidth / 2.)) + |> Array.concat + + + +/// get SVG of the array of waveforms in wsMod +let waveSvg wsMod waveData = + let valueLabels = + busLabels wsMod waveData + |> Array.map (Array.collect (busLabelRepeats wsMod.SimParams)) + + let makeWaveSvg (sampArr: Waveform) (transArr: (int * int) []): ReactElement [] = + (sampArr, transArr) + ||> Array.mapi2 (makeSegment wsMod.SimParams.ClkSvgWidth) + |> Array.concat + + let padTrans t = + match Array.length t with + | 0 -> [| 1, 1 |] + | 1 -> + [| (1, t[0]) + (t[0], 1) |] + | _ -> + Array.pairwise t + |> (fun pairs -> + Array.concat + [ [| 1, fst pairs[0] |] + pairs + [| snd (Array.last pairs), 1 |] ]) + + transitions waveData + |> Array.map padTrans + |> Array.map2 makeWaveSvg (Array.transpose waveData) + |> Array.map2 Array.append valueLabels + + +/// Calculate and add the waveform SVGs to the current wsModel. +/// TODO: only recalculate as needed on DispWave change +let addSVGToWaveSimModel wSModel = + let waveData = + getAllWaveSimDataBySample wSModel + + let waveTableRow rowClass cellClass svgClass svgChildren = + tr rowClass [ td cellClass [ makeSvg svgClass svgChildren ] ] + let bgSvg = backgroundSvg wSModel + + let lastRow = [| waveTableRow [ Class "fullHeight" ] (lwaveCell wSModel) (waveCellSvg wSModel true) bgSvg |] + let firstRow = [| tr [ Class "rowHeight" ] [ td (waveCell wSModel) [ clkRulerSvg wSModel ] ] |] + + let midRows = + waveSvg wSModel waveData + |> Array.zip wSModel.SimParams.DispNames + |> Array.map (fun (name,wave) -> + let waveWithBg = Array.append bgSvg wave + let svg = waveTableRow [ Class "rowHeight" ] (waveCell wSModel) (waveCellSvg wSModel false) waveWithBg + name,svg) + |> Map.ofArray + let svgs = {Top = firstRow ; Waves = midRows; Bottom = lastRow } + {wSModel with DispWaveSVGCache = svgs} + + +/// add entry with key: current fileName and data: initWS to model.WaveSim +let initFileWS (model:Model) dispatch = + let netListOpt = getSheetWaveNetList model + match getCurrFile model,netListOpt with + | Some fileName, Some _netList -> + (fileName, initWS [||] Map.empty) + |> AddWaveSimFile + |> dispatch + | _ -> () + + + +/// get wave name labels from waveforms names +let makeLabels waveNames = + let makeLbl l = label [ Class "waveLbl" ] [ str l ] + Array.map makeLbl waveNames + + + + + +/// adjust parameters before feeding them into simulateAndMakeWaves +let adjustPars (wsMod: WaveSimModel) (pars: SimParamsT) rightLim = + let currPars = wsMod.SimParams + let defRightLim = + match dispWaves wsMod with + | [||] -> 600.0 + | _ -> maxWavesColWidthFloat wsMod + let rightLim = match rightLim with | Some x -> x | None -> defRightLim + let lastClkTime = + rightLim / (currPars.ClkSvgWidth * 40.0) + |> uint + |> max currPars.CursorTime + |> (+) 10u + |> max pars.LastClkTime + |> min maxLastClk + {pars with LastClkTime = lastClkTime} + +/// Update wavesim based on new parameters in par. +/// Update waveSimCache as needed with a new longer simulation to view new parameters. +/// Update DispWaveSVGCache with new wave SVGs and/or added SVGs as determined by new parameters. +/// Update the currentWaveSimModel entry with new parameters +let simulateAndMakeWaves (model: Model) (wsMod: WaveSimModel) + (par: SimParamsT) : WaveSimModel = + + let newData = + par.LastClkTime + 1u - uint (Array.length wsMod.SimDataCache) + |> appendSimData model wsMod + |> function | Some (Ok dat) -> dat + | None -> failwithf "No simulation data when Some are expected" + | Some (Error e) -> failwithf "%A" e + let par' = {par with DispNames = par.DispNames} + { wsMod with SimDataCache = newData + SimParams = par' } + |> addSVGToWaveSimModel + + + +//------------------------------------// +// Interaction with Model.Diagram // +//------------------------------------// + +/// is the given connection in the given NLTarget list +let private isConnInNLTrgtLst (connId: ConnectionId) (nlTrgtLst: NLTarget list) = + List.exists (fun nlTrgt -> nlTrgt.TargetConnId = connId) nlTrgtLst + +/// is the given component connected to the NLTarget list +let private isCompInNLTrgtLst (nlComponent: NetListComponent) (nlTrgtLst: NLTarget list) = + Map.exists (fun _ compNLTrgtLst -> compNLTrgtLst = nlTrgtLst) nlComponent.Outputs + || List.exists (fun nlTrgt -> nlTrgt.TargetCompId = nlComponent.Id) nlTrgtLst + +/// is the given NLTarget list selected by the given selection +let private isNLTrgtLstSelected (netList: NetList) ((comps, conns): CanvasState) (nlTrgtLst: NLTarget list) = + List.exists (fun (comp: Component) -> + match Map.tryFind (ComponentId comp.Id) netList with + | Some comp -> isCompInNLTrgtLst comp nlTrgtLst + | None -> false ) comps + || List.exists (fun (conn: Connection) -> + isConnInNLTrgtLst (ConnectionId conn.Id) nlTrgtLst) conns + +/// is the given waveform selected by the given selection +let private isNetGroupSelected (netList: NetList) ((comps, conns): CanvasState) (trgtLstGroup: NetGroup) = + Array.append [|trgtLstGroup.driverNet|] trgtLstGroup.connectedNets + |> Array.exists (isNLTrgtLstSelected netList (comps, conns)) + + +/// is the given waveform selected by the current diagram selection +let isWaveSelected (model:Model) (wSpec: WaveformSpec) = + match wSpec.WType, wSpec.Conns with + | ViewerWaveform selected,_ -> selected + | NormalWaveform, [||] -> false // can't select a wave with no connections (maybe this case does not exist) + | NormalWaveform, conns -> + model.Sheet.GetSelectedConnections + |> List.exists (fun conn -> ConnectionId conn.Id = wSpec.Conns[0]) + +//--------------------------------------------------// +// Functions fed into FileMenuView View function // +//--------------------------------------------------// + + + +let getAllWaves (waveSim:WaveSimModel) = + mapValues waveSim.AllWaves + +///Takes a connection and model, and returns the netgroup as a list of connectionIds associated with that connection +let getNetSelection (canvas : CanvasState) (model : Model) = + + let netList = + model.LastSimulatedCanvasState + |> Option.map Helpers.getNetList + |> Option.defaultValue (Map.empty) + + + let netGroups = makeAllNetGroups netList + + let selectedConnectionIds (ng:NetGroup) = + if isNetGroupSelected netList canvas ng then + wave2ConnIds ng + else [||] + + Array.collect selectedConnectionIds netGroups + |> Array.toList + +/// In wave simulation highlight nets which are ticked on viewer or editor +/// Nets can be highlighted or unhighlighted by clicking on nets, or tick-boxes +/// TODO: rewrite this code and SetSelWaveHighlighted message avoiding +/// loops and fixes for loops. +let highlightConnectionsFromWaves (model: Model) (dispatch: Msg -> Unit) = + match currWaveSimModel model with + | Some wSModel -> + let waves = + match wSModel.WSViewState with + | WSEditorOpen + | WSInitEditorOpen -> + mapValues wSModel.AllWaves + | WSViewerOpen -> + wSModel.SimParams.DispNames + |> Array.map (fun name -> wSModel.AllWaves[name]) + | WSClosed -> [||] + + + let selectedConnectionIds (wave: WaveformSpec) = + if isWaveSelected model wave then + wave.Conns + else [||] + + let selectedIds = Array.collect selectedConnectionIds waves + let wrongColorIds = + selectedIds + |> Array.map (fun cid -> Map.tryFind cid model.Sheet.Wire.WX) + |> Array.filter ((<>) None) + |> Array.map Option.get + |> Array.filter (fun wire -> wire.Color <> HighLightColor.Blue) + |> Array.map (fun wire -> wire.Id) + // break loop while ensuring that connections are colored if needed + // nasty fix + if wrongColorIds <> [||] then + dispatch <| SetSelWavesHighlighted selectedIds + | _ -> () + + + + + + +/// actions triggered whenever the fileMenuView function is executed +let fileMenuViewActions model dispatch = + match getCurrentWSMod model with + | None + | Some {WSViewState = WSClosed} -> () + | _ -> + highlightConnectionsFromWaves model dispatch + + + + + + + +//-----------------------// +// Auto-scroll functions // +//-----------------------// + +/// strings of the values displayed in the right column of the simulator +let cursorValueStrings (wSMod: WaveSimModel) = + let paras = wSMod.SimParams + + let makeCursVal sample = + match sample with + | Wire w when w.NBits > 1u -> [| n2StringOfRadix true w.BitData w.NBits paras.WaveViewerRadix |] + | Wire w -> [| string w.BitData |] + | StateSample s -> s + + match int paras.CursorTime < Array.length wSMod.SimDataCache with + | true -> Array.map makeCursVal (getWaveSimDataOneSample wSMod (int paras.CursorTime)) + | false -> [||] + +/// strings of the values displayed for a RAM +let ramValueStrings (wSMod: WaveSimModel) (ramName: string) = + let paras = wSMod.SimParams + + let makeRamVal sample = + match sample with + | Wire w when w.NBits > 1u -> [| n2StringOfRadix true w.BitData w.NBits paras.WaveViewerRadix |] + | Wire w -> [| string w.BitData |] + | StateSample s -> s + + match int paras.CursorTime < Array.length wSMod.SimDataCache with + | true -> Array.map makeRamVal (getWaveSimDataOneSample wSMod (int paras.CursorTime)) + | false -> [||] + +/// returns true when the cursor rectangle is in the visible section of the scrollable div +let isCursorVisible wSMod divWidth scrollPos = + let cursLeftPos = cursorLeftPx wSMod.SimParams <| float wSMod.SimParams.CursorTime + let cursMid = cursLeftPos + (wSMod.SimParams.ClkSvgWidth * 40.0 / 2.0) + let leftScreenLim = scrollPos + let rightScreenLim = leftScreenLim + divWidth + cursLeftPos >= cursMid && cursMid <= rightScreenLim + +/// returns horizontal scrolling position required so that the cursor becomes visible +let makeCursorVisiblePos wSMod divWidth = + let cursLeftPos = cursorLeftPx wSMod.SimParams <| float wSMod.SimParams.CursorTime + let cursMid = cursLeftPos + (wSMod.SimParams.ClkSvgWidth * 40.0 / 2.0) + cursMid - (divWidth / 2.0) + +//-------------------------------------// +// Functions to Manage Wave Editor // +//-------------------------------------// + +type SheetInfo = { + SheetName: ComponentId; + Canvas: CanvasState; + SheetGraph: SimulationGraph; + Instance: string * ComponentLabel + SheetPath: ComponentId list; + InstancePath: (string * ComponentLabel) list + NetL: NetList + } + +let rec getSubSheets + (sheets: ComponentId list) + (instances: (string * ComponentLabel) list) + (graph: SimulatorTypes.SimulationGraph) + (model:Model) : SheetInfo list = + mapValues graph + |> Array.toList + |> List.collect (fun sComp -> + let label = sComp.Label + match sComp.Type with + | Custom cusComp -> + let canvas = + match model.CurrentProj with + | Some {LoadedComponents= lst} -> + match List.tryFind (fun ldComp -> ldComp.Name = cusComp.Name) lst with + | None -> failwithf "Can't find canvas for sheet" + | Some ldComp -> ldComp.CanvasState + | _ -> failwithf "Can't find project" + match sComp.CustomSimulationGraph with + | None -> failwithf "Custom compnent without simulation graph? InstancePath=%A, Instance=%A" instances label + | Some sg -> + let thisSheet = + { + SheetPath = List.rev sheets + InstancePath = List.rev instances + SheetName = sComp.Id + Instance = cusComp.Name, sComp.Label + SheetGraph = sg + Canvas = canvas + NetL = Helpers.getNetList canvas + } + let otherSheets = getSubSheets (sComp.Id :: sheets) (thisSheet.Instance ::instances) graph model + thisSheet :: otherSheets + | _ -> []) + + + + diff --git a/src/Renderer/UI/WaveformSimulationView.fs b/src/Renderer/UI/WaveformSimulationView.fs new file mode 100644 index 0000000..0199411 --- /dev/null +++ b/src/Renderer/UI/WaveformSimulationView.fs @@ -0,0 +1,891 @@ +//(* +//WaveformSimulationView.fs +// +//View for waveform simulator in tab +//*) +// +module rec WaveformSimulationView +// +//(******************************************************************************************* +// +//Waveform simulation simulates the current sheet circuit and generates waveforms as react SVG elements +//on an SVG canvas. The waveform display changes interactively based on zoom and cursor movement buttons. +// +//In addition the SVG canvas is an element wider then the pane in which it is displayed, and uses HTML scrolling +//navigate. Zooming will recreate a new (wider) canvas as necessary so that the entire visible window contains valid +//waveforms. +// +//In addition the canvas consists only of those waveforms currently selected to be displayed, via a wave editor pane +//which displayed the names of all possible waveforms and allows them to be displayed or not. See waveeditor below +//for details. +// +//When the selected waveforms are changed the SVG canvas must also be recreated with new waveforms, although the +//simulation need not be advanced. +// +//Waveform simulation is initiated by the Waveforms >> button. This button is recreated by mainview a suitable color: +//green: a changed (or initial) circuit exists which can be (re-)simulated with waveform simulator +//orange: errors exist in circuit - no change to waveform simulation. +//white: circuit has not chnaged and is still the same as what is currently displaying waveforms +// +//The waveforms last simulated are thus displayed while the circuit can be updated, until the button is clicked. On +//this click, if the circuit has errors the old waveforms are replaced by an error message, otherwise a new simulation +//replaces the old simulation. +// +//Allowing simultaneous view (and interactive change as above) of old waveforms while letting the design be changed +//requires careful state management: +// +//model.LastSimulatedCanvasState - circuit last simulated +//model.Simulation - time = 0 SimGraph or simulation error for LastSimulatedCanvasState. A simulation can be extended by advancing the +//SimGraph one or more simulation steps. +// +//Wavesim specific parameters and temporary state are inside a WaveSimModel record accessed via a Map field in the model: +// +//WaveSim: Map +//accessed as: +//model.WaveSim[openSheetName]: WaveSimModel +// +//TODO: The WaveSimModel is only valid when a project is open and the Wavesim data in reality should be part of +//the current sheet LoadedComponent record, tus WaveSim record moves inside LoadedComponent record and no longer +//needs to be a Map. +// +//The WaveSimModel data is changed on opening a different sheet or saving / restoring a project in exactly the same way as the +//rest of the sheet data LoadedComponentData. The simulation parameters last used for each sheet are saved and restored. Inside +//WaveSim a subrecord WaveSim.WaveData contains transient information about the current simulation which is not saved across sheet +//changes. In addition the field SimDataCache is transient and replaced whenever LastSimulatedCanvasState changes. +// +//TODO: make SimDataCache a field of WaveData. Move WaveData from WaveSimModel to Model - so there is just one copy of it, not +//one per sheet. +// +//waveform Simulation State Changes +// +//(1) SimulateButtonFunc definition: +//waveforms >> button pressed with SimIsStale = true, makeSimData model returns (Ok simData), Canvas exists and contains canvasData +// +//--> startNewWaveSimulation: this updates model with +// SimIsStale = false, +// WaveSim data for current sheet (waveSim) all initialised, +// waveSim.WaveData initialised from simData and canvasData +// LastSimulatedCanvasState updated to equal the new circuit (?) +// +//*******************************************************************************************) +// +open Fulma +open Fable.React +open Fable.React.Props + + +open ModelType +open DiagramStyle +open CommonTypes +open WaveSimHelpers +open FileMenuView +open SimulatorTypes + + + +/// maximum width of the waveform simulator viewer +let maxUsedViewerWidth (wSMod: WaveSimModel) = + let strWidth s = + DrawHelpers.getTextWidthInPixels (s, "12px segoe ui") //not sure which font + let curLblColWidth = + match cursorValueStrings wSMod with + | [||] -> 0.0 + | cVS -> + Array.map (Array.map strWidth >> Array.max) cVS + |> Array.max + |> max 25.0 + let namesColWidth = + match wSMod.SimParams.DispNames with + | [||] -> 0.0 + | wN -> + Array.map strWidth wN + |> Array.max + |> max 100.0 + let svgWaveColWidth = + match dispWaves wSMod with + | [||] -> 600.0 + | _ -> maxWavesColWidthFloat wSMod + let checkBoxCol = 25.0 + let extraWidth = 45.0 + + curLblColWidth + namesColWidth + svgWaveColWidth + checkBoxCol + extraWidth |> int + + + + + + +/////////////////////// +//// WaveSim actions // +/////////////////////// + +/// change selection of a waveform's connections +let private changeWaveConnsSelect (selFun: WaveformSpec -> bool) (model:Model) (wSModel: WaveSimModel) name (dispatch: Msg -> unit) = + let wave = wSModel.AllWaves[name] + let on = selFun wave + match wave.WType with + | ViewerWaveform _ -> + let wSModel' = {wSModel with AllWaves = Map.add wave.WId {wave with WType = ViewerWaveform on} wSModel.AllWaves} + dispatch <| SetWSMod wSModel' + | NormalWaveform -> + selectWaveConns model (selFun wave) wave dispatch + +/// toggle selection of a waveform's connections +let private toggleWaveConnsSelect (model: Model) (wSMod: WaveSimModel) (name:string) (dispatch: Msg -> unit) = + changeWaveConnsSelect (fun wave -> isWaveSelected model wave |> not) model wSMod name dispatch + +/// stretch waveforms horizontally +let private changeViewerZoom compIds plus (m: Model) (wsModel: WaveSimModel) dispatch = + let rec adjustLastClk viewW wsModel = + let pars = wsModel.SimParams + if viewW * 1.4 < float (maxUsedViewerWidth wsModel) then + adjustLastClk viewW (setSimParams (fun sp -> {sp with LastClkTime = pars.LastClkTime + 2u}) wsModel) + else + printfn "New LastClk=%d" pars.LastClkTime + pars.LastClkTime + + let netList = wsModel2netList wsModel + let pars = wsModel.SimParams + let newClkW = + if plus then zoomFactor else 1.0 / zoomFactor + |> (*) pars.ClkSvgWidth + |> max minZoom + |> min maxZoom + let wSModNewClk = setSimParams (fun sp -> {sp with ClkSvgWidth=newClkW}) wsModel + let newPars = + match int (float m.WaveSimViewerWidth) > maxUsedViewerWidth wSModNewClk with + | true -> + { pars with + LastClkTime = adjustLastClk (float m.WaveSimViewerWidth) wSModNewClk + ClkSvgWidth = newClkW + } + | false -> + {pars with + ClkSvgWidth = newClkW + } + dispatch <| InitiateWaveSimulation(WSViewerOpen, newPars) + + +/// change cursor value +let private changeCursorPos (wSModel: WaveSimModel) dispatch newCursorPos = + let pars = wSModel.SimParams + let curs' = min maxLastClk newCursorPos + match 0u <= curs', curs' <= pars.LastClkTime with + | true, true -> + wSModel + |> setSimParams (fun sp -> {sp with CursorTime = curs' }) + |> SetWSMod |> dispatch + UpdateScrollPos true |> dispatch + | true, false -> + let pars' = { pars with CursorTime = curs'; ClkSvgWidth = pars.ClkSvgWidth; LastClkTime = pars.LastClkTime } + dispatch <| InitiateWaveSimulation(WSViewerOpen, pars') + UpdateScrollPos true |> dispatch + | false, _ -> () + +/// change cursor value by 1 up or down +let private cursorMove increase (wSMod: WaveSimModel) dispatch = + match increase, wSMod.SimParams.CursorTime with + | true, n -> n + 1u |> changeCursorPos wSMod dispatch + | false, n -> n - 1u |> changeCursorPos wSMod dispatch + +/// change the order of the waveforms in the simulator +let private moveWave (model:Model) (wSMod: WaveSimModel) up = + let moveBy = if up then -1.5 else 1.5 + let addLastPort arr p = + Array.mapi (fun i el -> if i <> Array.length arr - 1 then el + else fst el, Array.append (snd el) [| p |]) arr + let svgCache = wSMod.DispWaveSVGCache + let movedNames = + wSMod.SimParams.DispNames + |> Array.map (fun name -> isWaveSelected model wSMod.AllWaves[name], name) + |> Array.fold (fun (arr, prevSel) (sel,p) -> + match sel, prevSel with + | true, true -> addLastPort arr p, sel + | s, _ -> Array.append arr [| s, [|p|] |], s ) ([||], false) + |> fst + |> Array.mapi (fun i (sel, ports) -> if sel + then float i + moveBy, ports + else float i, ports) + |> Array.sortBy fst + |> Array.collect snd + setDispNames movedNames wSMod + |> SetWSMod + +let private viewerWaveSet (wavesToSet: WaveformSpec array) (on:bool) (wSMod: WaveSimModel) dispatch = + let waves = + wSMod.AllWaves + |> Map.map (fun wid wave -> + match wave.WType with + | ViewerWaveform _ when Array.contains wave wavesToSet -> + {wave with WType = ViewerWaveform on} + | _ -> wave) + dispatch <| SetWSMod {wSMod with AllWaves = waves} + + +/// select all waveforms in the WaveAdder View +let private waveAdderSelectAll model (wSMod: WaveSimModel) (on: bool) dispatch = + let waves = mapValues wSMod.AllWaves + let conns = + match on with + | true -> + waves + |> Array.collect (fun wave -> wave.Conns) + | false -> + [||] + selectExactConns model conns dispatch + viewerWaveSet waves on wSMod dispatch + +let showSimulationLoading (wsModel: WaveSimModel) (dispatch: Msg ->Unit) = + let nv = wsModel.WSTransition + let v = wsModel.WSViewState + let resetV waves = + waves + |> Map.map (fun wid wave -> + match wave.WType with + | ViewerWaveform _ -> + {wave with WType = ViewerWaveform false} + | _ -> wave) + match nv, v with + | None, _ -> false + | Some _, _ -> + dispatch <| WaveSimulateNow + dispatch <| Sheet Sheet.ResetSelection + dispatch <| UpdateWSModel (fun wsm -> {wsm with AllWaves = resetV wsm.AllWaves}) + true + + +////////////////////////////////////////////// +// ReactElements of the Waveformm Simulator // +////////////////////////////////////////////// + + +/// labels displayed in the right column of the simulator +let private makeCursVals wsModel = + let string2Lbl = Array.map (fun l -> label [ Class "cursVals" ] [ str l ]) + Array.map string2Lbl <| cursorValueStrings wsModel + +let private makeRamReactCol (wsModel: WaveSimModel) ramPath = + let makeReactEl l = + + [| label [ Class "ramVals"; Style [FontSize "12px"] ] [ str l ] |] + let ramName, ramLocs = getRamInfoToDisplay wsModel ramPath + [| label [ Class "ramVals"; ] [p [Style [FontWeight "Bold"; TextAlign TextAlignOptions.Center]] [str ramName]] |] :: List.map makeReactEl ramLocs + |> List.toArray + + + +/// tuple of React elements of middle column, left column, right column. +/// shows waveforms and labels and cursor col. +/// The vertical order is fixed and as in DispNames +let private waveSimViewerRows compIds model (wsMod: WaveSimModel) (dispatch: Msg -> unit) = + let allWaves = wsMod.AllWaves + let names = wsMod.SimParams.DispNames + let labelCols = + names + |> makeLabels + |> Array.zip names + |> Array.map (fun (name,lab) -> + if Map.tryFind name allWaves = None then + printfn "Help - cannot lookup %A in allwaves for label %A" name lab + failwithf "Terminating!" + tr [ Class "rowHeight" ] + [ td [ Class "checkboxCol" ] + [ input + [ Type "checkbox" + Class "check" + Checked <| isWaveSelected model allWaves[name] + Style [ Float FloatOptions.Left ] + OnChange(fun _ -> toggleWaveConnsSelect model wsMod name dispatch) ] ] + td + [ Class "waveNamesCol" + Style [ TextAlign TextAlignOptions.Right ] ] [ lab ] ]) + + let cursValCol = + makeCursVals wsMod + |> Array.map (fun c -> tr [ Class "rowHeight" ] [ td [ Class "cursValsCol" ] c ]) + + wsMod.DispWaveSVGCache, labelCols, cursValCol + +/// ReactElement of the tabs for changing displayed radix +let private radixTabs (wsModel: WaveSimModel) dispatch = + let radixString = + [ Dec, "uDec" + Bin, "Bin" + Hex, "Hex" + SDec, "sDec" ] |> Map.ofList + + let radTab rad = + Tabs.tab + [ Tabs.Tab.IsActive(wsModel.SimParams.WaveViewerRadix = rad) + Tabs.Tab.Props + [ Style + [ Width "35px" + Height "30px" ] ] ] + [ a + [ Style + [ Padding "0 0 0 0" + Height "30px" ] + OnClick(fun _ -> + InitiateWaveSimulation (WSViewerOpen,{wsModel.SimParams with WaveViewerRadix = rad}) + |> dispatch) ] [ str (radixString[rad]) ] ] + Tabs.tabs + [ Tabs.IsToggle + Tabs.Props + [ Style + [ Width "140px" + Height "30px" + FontSize "80%" + Float FloatOptions.Right + Margin "0 10px 0 10px" ] ] ] + [ radTab Bin + radTab Hex + radTab Dec + radTab SDec ] + +/// ReactElement of the buttons for changing the cursor value +let private cursorButtons (model: Model) wSMod dispatch = + div [ Class "cursor" ] + [ Button.button + [ Button.CustomClass "cursLeft" + Button.OnClick(fun _ -> cursorMove false wSMod dispatch) ] [ str "◀" ] + Input.number + [ Input.Props + [ Min 0 + Class "cursor form" + SpellCheck false + Step 1 ] + Input.Id "cursor" + match currWaveSimModel model with + | Some wSMod when wSMod.CursorBoxIsEmpty = false -> + string wSMod.SimParams.CursorTime + | Some _ -> "" + | None -> "0" + |> Input.Value + Input.OnChange(fun c -> + match System.Int32.TryParse c.Value with + | true, n when n >= 0 -> + { wSMod with CursorBoxIsEmpty = false } + |> SetWSMod |> dispatch + changeCursorPos wSMod dispatch <| uint n + | false, _ when c.Value = "" -> + { wSMod with CursorBoxIsEmpty = true } + |> SetWSMod |> dispatch + changeCursorPos wSMod dispatch 0u + | _ -> + { wSMod with CursorBoxIsEmpty = false } + |> SetWSMod |> dispatch ) ] + button [ Button.CustomClass "cursRight" ] (fun _ -> cursorMove true wSMod dispatch) "▶" ] + +/// ReactElement of the loading button +let private loadingButton wsMod dispatch = + if showSimulationLoading wsMod dispatch then + button [Button.Color Color.IsBlackBis; Button.IsLoading true] (fun _ -> ()) "" + else str "" + +/// React Element of the buttons Bar at the top of the waveform simulator +let private viewWaveSimButtonsBar model wSMod dispatch = + div [ Style [ Height "45px" ] ] + [ loadingButton wSMod dispatch + radixTabs wSMod dispatch + cursorButtons model wSMod dispatch ] + +/// ReactElement of the right column of the waveform simulator +let private cursorValuesCol rows = + let rightCol = Array.append [| tr [ Class "rowHeight" ] [ td [ Class "rowHeight" ] [] ] |] rows + div + [ Style + [ Float FloatOptions.Right + Height "100%" + BorderTop "2px solid rgb(219,219,219)" + BorderLeft "2px solid rgb(219,219,219)" ] ] [ table [] [ tbody [] rightCol ] ] + +/// ReactElement of the waveforms' name labels column +let private nameLabelsCol model (wsMod: WaveSimModel) labelRows (dispatch: Msg -> unit) = + let waveAddDelBut = + th [ Class "waveNamesCol" ] + [ Button.button + [ Button.CustomClass "newWaveButton" + Button.Color IsSuccess + Button.OnClick(fun _ -> + openEditorFromViewer model dispatch) ] [ str "Edit list..." ] ] + + let top = + [| tr [ Class "rowHeight" ] + [ th [ Class "checkboxCol" ] + [ div [ Class "updownDiv" ] + [ Button.button + [ Button.CustomClass "updownBut" + Button.OnClick(fun _ -> moveWave model wsMod true |> dispatch) ] [ str "▲" ] + Button.button + [ Button.CustomClass "updownBut" + Button.OnClick(fun _ -> moveWave model wsMod false |> dispatch) ] [ str "▼" ] ] ] + waveAddDelBut ] |] + + let bot = + [| tr [ Class "fullHeight" ] + [ td [ Class "checkboxCol" ] [] + td [] [] ] |] + + let leftCol = Array.concat [| top; labelRows; bot |] + + div + [ Style + [ Float FloatOptions.Left + Height "100%" ] ] [ table [ Class "leftTable" ] [ tbody [] leftCol ] ] + +/// ReactElement of the waveform SVGs' column +let private allWaveformsTableElement model (wSModel: WaveSimModel) waveformSvgRows dispatch = + let pars = wSModel.SimParams + let element = ref None + /// get reference to HTML elemnt that is scrolled + let allWaveformsHtmlRef (el: Browser.Types.Element) = + if not (isNull el) then // el can be Null, in which case we do nothing + element.Value <- Some el // set mutable reference to the HTML element for later use + let scrollPos = el.clientWidth + el.scrollLeft + if Some scrollPos <> pars.LastScrollPos then + SetLastScrollPos (Some scrollPos) |> ignore + match element.Value with + | Some e -> + match model.CheckWaveformScrollPosition with + | true when not (isCursorVisible wSModel e.clientWidth e.scrollLeft) -> + e.scrollLeft <- makeCursorVisiblePos wSModel e.clientWidth + UpdateScrollPos false |> dispatch + | _ -> () + | None -> + UpdateScrollPos false |> dispatch + + let scrollFun (ev:Browser.Types.UIEvent) = // function called whenever scroll position is changed + match element.Value with // element should now be the HTMl element that is scrolled + | None -> () // do nothing + | Some e -> + if e.scrollWidth - e.clientWidth - e.scrollLeft < 10.0 + then + let pars' = + { pars with + ClkSvgWidth = pars.ClkSvgWidth + CursorTime = pars.CursorTime + LastClkTime = + max ((float pars.LastClkTime + 1.0) * 0.1 |> uint) 10u + |> (+) pars.LastClkTime + |> min maxLastClk + } + dispatch <| InitiateWaveSimulation(WSViewerOpen, pars') + printfn "working" + else printfn "not working" + //e.scrollLeft <- 100. // this shows how to set scroll position COMMENT THIS OUT + // can use dispatch here to make something happen based on scroll position + // scroll position = min or max => at end + //printfn "scrolling with scrollPos=%f" e.scrollLeft + let waves = + wSModel.SimParams.DispNames + |> Array.map (fun name -> waveformSvgRows.Waves[name]) + div [ Ref allWaveformsHtmlRef + OnScroll scrollFun + Style [ MaxWidth(maxWavesColWidth wSModel) + MinHeight "100%" ] + Class "wavesTable" ] + [ div [ Class "cursorRectStyle"; cursRectStyle wSModel.SimParams ] [ str " " ] + table [ Style [ Height "100%" ] ] + [ tbody [ Style [ Height "100%" ] ] (Array.concat [|waveformSvgRows.Top; waves; waveformSvgRows.Bottom|]) ] ] + +let waveSimViewerRamDisplay wSMod ramPath = + makeRamReactCol wSMod ramPath + |> Array.map (fun c -> tr [] [ td [ Class "cursValsCol" ] c ]) + |> (fun r -> [|div [Style [Height "calc(100vh - 150px)"; OverflowY OverflowOptions.Auto]] r|]) + + +/// ReactElement of the bottom part of the waveform simulator when waveforms are being displayed +let private viewWaveformViewer compIds model wSMod (dispatch: Msg -> unit) = + let tableWaves, nameColMiddle, cursValsRows = waveSimViewerRows compIds model wSMod dispatch + div + [ Style + [ Height "calc(100% - 45px)" + Width "100%" + OverflowY OverflowOptions.Auto ] ] + ((List.map (fun ramPath -> cursorValuesCol (waveSimViewerRamDisplay wSMod ramPath)) wSMod.SimParams.MoreWaves) @ + [ + cursorValuesCol cursValsRows + div [ Style [ Height "100%" ] ] + [ nameLabelsCol model wSMod nameColMiddle dispatch + allWaveformsTableElement model wSMod tableWaves dispatch ] + ]) + +/// ReactElement of the zoom buttons +let private viewZoomDiv compIds model wSMod dispatch = + div [ Class "zoomDiv"] + [ button [Button.Option.IsOutlined; Button.CustomClass "zoomButLeft"] (fun _ -> changeViewerZoom compIds false model wSMod dispatch) "-" + button [ Button.CustomClass "zoomButRight" ] (fun _ -> changeViewerZoom compIds true model wSMod dispatch) "+" ] + +/// ReactElement of the top row of the WaveAdder (where Select All is) +let private waveEditorSelectAllRow model wSModel dispatch = + let allOn = Map.forall (fun k wave -> isWaveSelected model wave) wSModel.AllWaves + tr + [ Class "rowHeight" + Style [ VerticalAlign "middle" ] ] + [ td + [ Class "wACheckboxCol" + Class "rowHeight" + Style [ VerticalAlign "middle" ] ] + [ input + [ Type "checkbox" + Class "check" + Checked allOn + Style [ Float FloatOptions.Left ] + OnChange(fun _ -> waveAdderSelectAll model wSModel (not allOn) dispatch ) ] ] + td [ Style [ FontWeight "bold" ] ] [ str "Select All" ] ] + +/// ReactElement of Wave Editor waveform row +/// displays a tickbox and the NetGroup driver name +let private waveEditorTickBoxAndNameRow model wSModel name (dispatch: Msg -> unit) = + let allWaves = wSModel.AllWaves + + let getColorProp name = + if Array.contains name wSModel.SimParams.DispNames then + [FontWeight "Bold"] + else + [] + tr + [ Class "rowHeight" + Style [ VerticalAlign "middle" ] ] + [ td + [ Class "wAcheckboxCol" + Class "rowHeight" + Style [ VerticalAlign "middle" ] ] + [ input + [ Type "checkbox" + Class "check" + Checked <| isWaveSelected model allWaves[name] + Style [ Float FloatOptions.Left ] + OnChange(fun _ -> toggleWaveConnsSelect model wSModel name dispatch) ] ] + td [] [ label [Style (getColorProp name)] [ str <| allWaves[name].DisplayName ] ] ] + +let sortEditorNameOrder wsModel = + let otherNames = + wsModel.AllWaves + |> Map.filter (fun wId wSpec -> not <| Array.contains wId wsModel.SimParams.DispNames) + Array.append wsModel.SimParams.DispNames (mapKeys otherNames) + +/// ReactElement of all Wave Editor waveform rows +let private waveEditorTickBoxRows model wsModel (dispatch: Msg -> unit) = + let editorNameOrder = sortEditorNameOrder wsModel + sortEditorNameOrder wsModel + |> Array.map (fun name -> waveEditorTickBoxAndNameRow model wsModel name dispatch) + +/// ReactElement of the bottom section of the WaveAdder. +/// Contains tick-boxes for NetGroups +let private waveEditorTickBoxesAndNames (model: Model) wSModel (dispatch: Msg -> unit) = + div [ Style [ Position PositionOptions.Absolute + Top "300px" ] ] + [ table [] + [ tbody [] + (Array.append [| waveEditorSelectAllRow model wSModel dispatch |] + (waveEditorTickBoxRows model wSModel dispatch)) ] ] + +/// ReactElement of the buttons of the WaveAdder +let private waveEditorButtons (model: Model) (wSModel:WaveSimModel) dispatch = + + + + /// this is what actually gets displayed when editor exits + let closeWaveSimButtonAction _ev = + dispatch <| StartUICmd CloseWaveSim + dispatch <| SetWSMod {wSModel with InitWaveSimGraph=None; WSViewState=WSClosed; WSTransition = None} + dispatch <| ChangeRightTab Catalogue + dispatch <| SetWaveSimIsOutOfDate true + dispatch <| Sheet (Sheet.ResetSelection) + dispatch <| Sheet (Sheet.SetWaveSimMode false) + dispatch ClosePropertiesNotification + dispatch FinishUICmd + + /// Return the RAM etc view options window. data is the current (initial) set of RAMs to be viewed. + let getWavePopup dispatch (data: MoreWaveSetup option) = + match data with + | None -> div [] [] + | Some moreData -> + div [] [ + reactMoreWaves moreData (Option.get wSModel.InitWaveSimGraph).Graph dispatch; + div [Style [Display DisplayOptions.Flex; AlignItems AlignItemsOptions.Center; JustifyContent "Center"]] [ + Button.button [Button.OnClick (fun _ -> dispatch <| ClosePopup)] [str "Close"]] + ] + + let moreWaveEditorButtonAction _ = + dispatch <| SetPopupWaveSetup (getWaveSetup wSModel model) + PopupView.showWaveSetupPopup (Some "RAM Viewer Setup: tick to view RAM or ROM contents") (getWavePopup dispatch) None [] dispatch + + + + let waveEditorViewSimButtonAction = + let allWaves = wSModel.AllWaves + let viewableWaves = + allWaves + + |> standardOrderWaves wSModel.SimParams.DispNames (fun s -> + Map.containsKey s allWaves && isWaveSelected model allWaves[s]) + + + match viewableWaves.Length with + | 0 -> [ Button.IsLight; Button.Color IsSuccess ] + | _ -> + [ + Button.Color IsSuccess + Button.IsLoading (showSimulationLoading wSModel dispatch) + Button.OnClick(fun _ -> + let par' = {wSModel.SimParams with DispNames = viewableWaves } + let msgs = + [ + (StartUICmd ViewWaveSim) + ClosePropertiesNotification + (InitiateWaveSimulation( WSViewerOpen, par')) + ] + dispatch (Sheet (Sheet.SetSpinner true)) + dispatch <| SendSeqMsgAsynch msgs) + ] + |> (fun lst -> + Button.Props [ Style [ MarginLeft "10px" ] ] :: lst) + let cancelButton = + Button.button + [ Button.Color IsSuccess + Button.OnClick(closeWaveSimButtonAction) ] [ str "Close" ] + + let moreButton = + Button.button + [ Button.Color IsSuccess + Button.Props [ Style [ MarginRight "10px" ] ] + Button.OnClick(moreWaveEditorButtonAction) ] [ str "RAM" ] + + let actionButtons = + match dispWaves wSModel with + | [||] -> [ moreButton ; Button.button waveEditorViewSimButtonAction [ str "View selected" ] ] + | _ -> [ moreButton; cancelButton; Button.button waveEditorViewSimButtonAction [ str "View" ] ] + div [ Style [ Display DisplayOptions.Block ] ] actionButtons + +/// ReactElement list of the WaveAdder +let private waveEditorView model wSMod (dispatch: Msg -> unit) = + [ div + [ Style + [ Width "90%" + MarginLeft "5%" + MarginTop "15px" ] ] + [ Heading.h4 [] [ str "Waveform Simulation" ] + str "Ctrl-click on diagram connections or use tick boxes below to add or remove waveforms." + str "Test combinational logic by closing this simulator and using Simulate tab." + hr [] + div [] + [ waveEditorButtons model wSMod dispatch + waveEditorTickBoxesAndNames model wSMod dispatch ] ] ] + +/// ReactElement list of the waveforms view +let private waveformsView compIds model netList wSMod dispatch = + [ div + [ Style + [ Width "calc(100% - 10px)" + Height "100%" + MarginLeft "0%" + MarginTop "0px" + OverflowX OverflowOptions.Hidden ] ] + [ viewWaveSimButtonsBar model wSMod dispatch + viewWaveformViewer compIds model wSMod dispatch + viewZoomDiv compIds model wSMod dispatch ] ] + + + +//-------------------------------------------------------------------// +// TOP-LEVEL WAVE SIMULATION TRANSITIONS AND VIEWS // +//-------------------------------------------------------------------// + + + + + +/// TRANSITION: Switch between WaveformEditor (WSEditorOpen) and WaveformViewer (WSVieweropen) view +/// sets wsModel for the new view +let private openEditorFromViewer model (dispatch: Msg -> Unit) : Unit = + let wsModel = getWSModelOrFail model "What? no wsModel in openCloseWaveEditor" + // set the currently displayed waves as selected in wave editor + let waves = wsModel.SimParams.DispNames |> Array.map (fun name -> wsModel.AllWaves[name]) + Array.iter (fun wave -> selectWaveConns model true wave dispatch) waves + viewerWaveSet waves true wsModel dispatch + dispatch <| UpdateWSModel (setEditorView WSEditorOpen) + + +//----------------------------------------------------------------------------------------------------------------- + +/// TRANSITION +/// This starts a wave simulation of a new circuit +/// Set wsModel to show the list of waveforms that can be selected from a new simulation +/// Sets data persistent over editor open and close. +/// Sets WaveSim to have editor open +let startWaveSim compIds rState (simData: SimulatorTypes.SimulationData) model (dispatch: Msg -> unit) _ev = + let comps,conns = model.Sheet.GetCanvasState() + let compIds = comps |> List.map (fun c -> ComponentId c.Id) |> Set + let rState = Extractor.extractReducedState (comps,conns) + // subfunction to generate popup over waveeditor screen if there are undriven input connections + let inputWarningPopup (simData:SimulatorTypes.SimulationData) dispatch = + if simData.Inputs <> [] then + let inputs = + simData.Inputs + |> List.map (fun (_,ComponentLabel lab,_) -> lab) + |> String.concat "," + let popup = Notifications.warningPropsNotification (sprintf "Inputs (%s) will be set to 0." inputs) + dispatch <| SetPropertiesNotification popup + + let startingWsModel = + let modelWithWaveSimSheet = {model with WaveSimSheet = Option.get (getCurrFile model)} + let wsModel = getWSModelOrFail modelWithWaveSimSheet "What? Can't get wsModel at start of new simulation" + let okCompNum = (Set.intersect compIds (simData.Graph |> mapKeys |> Set)).Count + let simCompNum = simData.Graph.Count (* + printfn + "DEBUG: sheet=%s, modelSheet=%s, okNum = %d, wavesim num = %d drawNum=%d" + modelWithWaveSimSheet.WaveSimSheet + model.WaveSimSheet + okCompNum + simCompNum + compIds.Count + printfn + "DEBUG: simComps=%A\n\ndrawcomps=%A\n\n" + (simData.Graph |> mapValues |> Array.map (fun c -> c.Label) |> Array.sort) + (model.Sheet.GetCanvasState() |> fst |> List.map (fun c -> c.Label) |> List.sort) *) + + let wSpecs = + SimulatorTypes.getWaveformSpecifications (netGroup2Label compIds) simData rState + // printfn "Starting comps = %A" (fst rState |> List.map (fun comp -> comp.Label, comp.Type)) + // SimulatorTypes.printSimGraph simData.Graph + let allowedNames = + wsModel.SimParams.DispNames + |> Array.filter (fun name -> Map.containsKey name wSpecs) + Array.iter (fun wave -> selectWaveConns model false wave dispatch) (mapValues wSpecs) + let waves = allowedNames |> Array.map (fun name -> wSpecs[name]) + Array.iter (fun wave -> selectWaveConns model true wave dispatch) waves + let wSpecs = + wSpecs + |> Map.map (fun name spec -> + match spec.WType, Array.contains name allowedNames with + | ViewerWaveform _, isDisplayed -> {spec with WType = ViewerWaveform isDisplayed} + | _ -> spec) + { + wsModel with + AllWaves = wSpecs + SimParams = {wsModel.SimParams with DispNames = allowedNames} + InitWaveSimGraph = Some simData // start with 0 sample only + SimDataCache = [| simData |] + LastCanvasState = Some rState + WSViewState = WSEditorOpen; + WSTransition = None + } + dispatch EndSimulation // end a step simulation just in case + dispatch <| SetWSModAndSheet(startingWsModel, Option.get (getCurrFile model)) + dispatch <| SetViewerWidth minViewerWidth + dispatch <| SetLastSimulatedCanvasState (Some rState) + dispatch <| SetWaveSimIsOutOfDate false + inputWarningPopup simData dispatch + dispatch <| ChangeRightTab WaveSim + dispatch FinishUICmd + +//------------------------------------------------------------------------------------------------------------ + + +/// Waveforms >> Button React element with colour determined by current circuit error state +let WaveformButtonFunc compIds model dispatch = + // based on simulation results determine color of button and what happens if it is clicked + let simulationButton = + match currWaveSimModel model with + + | None -> + // If we have never yet run wavesim create initial wSModel + match model.CurrentProj with + | Some _ -> + initFileWS model dispatch + | None -> () + Button.button + [ Button.OnClick(fun _ -> + dispatch <| ChangeRightTab WaveSim) + ] + | Some wSModel -> + match wSModel.WSViewState, model.WaveSimulationIsOutOfDate, SimulationView.makeSimData model with + | WSClosed, _, Some (Ok simData, rState) + | _, true, Some (Ok simData, rState) -> + let isClocked = SynchronousUtils.hasSynchronousComponents simData.Graph + if isClocked then + // display the WaveEditor window if circuit is OK + Button.button + [ + Button.Color IsSuccess + Button.OnClick(fun ev -> + dispatch (StartUICmd StartWaveSim) + (startWaveSim compIds rState simData model dispatch ev)) + ] + else + Button.button + [ + Button.Color IsSuccess + Button.IsLight + Button.OnClick(fun _ -> + let popup = Notifications.errorPropsNotification "Combinational logic does not have waveforms" + dispatch <| SetPropertiesNotification popup + ) + ] + | WSClosed, _, Some( Error err,_) + | _, true, Some (Error err, _) -> + // display the current error if circuit has errors + Button.button + [ Button.Color IsWarning + Button.OnClick(fun _ -> + dispatch <| SetWSError (Some err) + dispatch <| ChangeRightTab WaveSim + SimulationView.SetSimErrorFeedback err model dispatch) + ] + | x,y,z -> + //printfn "other%A %A %A" x y (match z with | None -> "None" | Some ((Error c),_) -> "Some Error" | Some ((Ok _),_) -> "Some Ok") + Button.button + [ Button.Color IsSuccess + Button.IsLight + Button.OnClick(fun _ -> + dispatch <| ChangeRightTab WaveSim) + ] + simulationButton [ str "Waveforms >>" ] + +/// This is the top-level view function entry for the wave simulator after it has been set up. +/// ReactElement list of the whole waveform simulator +let viewWaveSim (model: Model) dispatch = + let compIds = getComponentIds model + match currWaveSimModel model, snd model.WaveSim with + + // normal case, display waveform adder editor or waveforms + | Some wSModel, None -> + // we derive all the waveSim circuit details from LastSimulatedCanvasState which does not change until a new simulation is run + let netList = Helpers.getNetList <| Option.defaultValue ([],[]) model.LastSimulatedCanvasState + match wSModel.WSViewState, wSModel.WSTransition with + | WSEditorOpen, _ -> // display waveAdder if simulation has not finished and adder is open + let start = TimeHelpers.getTimeMs() + waveEditorView model wSModel dispatch + |> TimeHelpers.instrumentInterval "Wave Editor open" start + | WSViewerOpen, _ -> // otherwise display waveforms + waveformsView compIds model netList wSModel dispatch + | _, prog -> + printfn "ViewWaveSim should not be called when WaveSimEditorOpen =%A, inProgress = %A" wSModel.WSViewState prog + [ div [] [] ] + + // Set the current simulation error message + | Some _, Some simError -> + + [ div [ Style [ Width "90%"; MarginLeft "5%"; MarginTop "15px" ] ] + [ SimulationView.viewSimulationError simError + button [ Button.Color IsDanger ] (fun _ -> + dispatch CloseSimulationNotification // Close error notifications. + dispatch <| Sheet(Sheet.ResetSelection) // Remove highlights. + dispatch <| (JSDiagramMsg << InferWidths) () // Repaint connections. + dispatch <| SetWSError None + match getCurrentWSMod model with + | Some ws -> + dispatch <| SetWSMod {ws with InitWaveSimGraph=None} + | _ -> () + dispatch <| ChangeRightTab Catalogue + ) + "Ok" ] ] + + // no WaveSim data, so start with initial data + // derived from model + | None, _ -> + initFileWS model dispatch + [] + diff --git a/src/Renderer/main.js b/src/Renderer/main.js new file mode 100644 index 0000000..871fed5 --- /dev/null +++ b/src/Renderer/main.js @@ -0,0 +1 @@ +// Simple workaround for https://github.com/electron-userland/electron-webpack/issues/225 \ No newline at end of file diff --git a/src/Renderer/paket.references b/src/Renderer/paket.references new file mode 100644 index 0000000..ae67e37 --- /dev/null +++ b/src/Renderer/paket.references @@ -0,0 +1,15 @@ +group Electron + Fable.Browser.Css + Fable.Core + Fable.Browser.Dom + Fable.Electron + Fable.Elmish + Fable.Elmish.React + Fable.Elmish.Debugger + Fable.Elmish.HMR + Fable.Node + Fable.Promise + Fable.React + Fulma + Fulma.Extensions.Wikiki.Tooltip + Fable.SimpleJson \ No newline at end of file diff --git a/src/Renderer/scss/main.css b/src/Renderer/scss/main.css new file mode 100644 index 0000000..1f5a92f --- /dev/null +++ b/src/Renderer/scss/main.css @@ -0,0 +1,11437 @@ +@charset "UTF-8"; +/*! + * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome + * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) + */ +/* FONT PATH + * -------------------------- */ +@font-face { + font-family: 'FontAwesome'; + src: url("./../../../node_modules/font-awesome/fonts//fontawesome-webfont.eot?v=4.7.0"); + src: url("./../../../node_modules/font-awesome/fonts//fontawesome-webfont.eot?#iefix&v=4.7.0") format("embedded-opentype"), url("./../../../node_modules/font-awesome/fonts//fontawesome-webfont.woff2?v=4.7.0") format("woff2"), url("./../../../node_modules/font-awesome/fonts//fontawesome-webfont.woff?v=4.7.0") format("woff"), url("./../../../node_modules/font-awesome/fonts//fontawesome-webfont.ttf?v=4.7.0") format("truetype"), url("./../../../node_modules/font-awesome/fonts//fontawesome-webfont.svg?v=4.7.0#fontawesomeregular") format("svg"); + font-weight: normal; + font-style: normal; } + +.fa { + display: inline-block; + font: normal normal normal 14px/1 FontAwesome; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } + +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.33333em; + line-height: 0.75em; + vertical-align: -15%; } + +.fa-2x { + font-size: 2em; } + +.fa-3x { + font-size: 3em; } + +.fa-4x { + font-size: 4em; } + +.fa-5x { + font-size: 5em; } + +.fa-fw { + width: 1.28571em; + text-align: center; } + +.fa-ul { + padding-left: 0; + margin-left: 2.14286em; + list-style-type: none; } + .fa-ul > li { + position: relative; } + +.fa-li { + position: absolute; + left: -2.14286em; + width: 2.14286em; + top: 0.14286em; + text-align: center; } + .fa-li.fa-lg { + left: -1.85714em; } + +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eee; + border-radius: .1em; } + +.fa-pull-left { + float: left; } + +.fa-pull-right { + float: right; } + +.fa.fa-pull-left { + margin-right: .3em; } + +.fa.fa-pull-right { + margin-left: .3em; } + +/* Deprecated as of 4.4.0 */ +.pull-right { + float: right; } + +.pull-left { + float: left; } + +.fa.pull-left { + margin-right: .3em; } + +.fa.pull-right { + margin-left: .3em; } + +.fa-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; } + +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); } + +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); } } + +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); } } + +.fa-rotate-90 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); } + +.fa-rotate-180 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; + -webkit-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); } + +.fa-rotate-270 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; + -webkit-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); } + +.fa-flip-horizontal { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; + -webkit-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + transform: scale(-1, 1); } + +.fa-flip-vertical { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; + -webkit-transform: scale(1, -1); + -ms-transform: scale(1, -1); + transform: scale(1, -1); } + +:root .fa-rotate-90, +:root .fa-rotate-180, +:root .fa-rotate-270, +:root .fa-flip-horizontal, +:root .fa-flip-vertical { + filter: none; } + +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; } + +.fa-stack-1x, .fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; } + +.fa-stack-1x { + line-height: inherit; } + +.fa-stack-2x { + font-size: 2em; } + +.fa-inverse { + color: #fff; } + +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.fa-glass:before { + content: ""; } + +.fa-music:before { + content: ""; } + +.fa-search:before { + content: ""; } + +.fa-envelope-o:before { + content: ""; } + +.fa-heart:before { + content: ""; } + +.fa-star:before { + content: ""; } + +.fa-star-o:before { + content: ""; } + +.fa-user:before { + content: ""; } + +.fa-film:before { + content: ""; } + +.fa-th-large:before { + content: ""; } + +.fa-th:before { + content: ""; } + +.fa-th-list:before { + content: ""; } + +.fa-check:before { + content: ""; } + +.fa-remove:before, +.fa-close:before, +.fa-times:before { + content: ""; } + +.fa-search-plus:before { + content: ""; } + +.fa-search-minus:before { + content: ""; } + +.fa-power-off:before { + content: ""; } + +.fa-signal:before { + content: ""; } + +.fa-gear:before, +.fa-cog:before { + content: ""; } + +.fa-trash-o:before { + content: ""; } + +.fa-home:before { + content: ""; } + +.fa-file-o:before { + content: ""; } + +.fa-clock-o:before { + content: ""; } + +.fa-road:before { + content: ""; } + +.fa-download:before { + content: ""; } + +.fa-arrow-circle-o-down:before { + content: ""; } + +.fa-arrow-circle-o-up:before { + content: ""; } + +.fa-inbox:before { + content: ""; } + +.fa-play-circle-o:before { + content: ""; } + +.fa-rotate-right:before, +.fa-repeat:before { + content: ""; } + +.fa-refresh:before { + content: ""; } + +.fa-list-alt:before { + content: ""; } + +.fa-lock:before { + content: ""; } + +.fa-flag:before { + content: ""; } + +.fa-headphones:before { + content: ""; } + +.fa-volume-off:before { + content: ""; } + +.fa-volume-down:before { + content: ""; } + +.fa-volume-up:before { + content: ""; } + +.fa-qrcode:before { + content: ""; } + +.fa-barcode:before { + content: ""; } + +.fa-tag:before { + content: ""; } + +.fa-tags:before { + content: ""; } + +.fa-book:before { + content: ""; } + +.fa-bookmark:before { + content: ""; } + +.fa-print:before { + content: ""; } + +.fa-camera:before { + content: ""; } + +.fa-font:before { + content: ""; } + +.fa-bold:before { + content: ""; } + +.fa-italic:before { + content: ""; } + +.fa-text-height:before { + content: ""; } + +.fa-text-width:before { + content: ""; } + +.fa-align-left:before { + content: ""; } + +.fa-align-center:before { + content: ""; } + +.fa-align-right:before { + content: ""; } + +.fa-align-justify:before { + content: ""; } + +.fa-list:before { + content: ""; } + +.fa-dedent:before, +.fa-outdent:before { + content: ""; } + +.fa-indent:before { + content: ""; } + +.fa-video-camera:before { + content: ""; } + +.fa-photo:before, +.fa-image:before, +.fa-picture-o:before { + content: ""; } + +.fa-pencil:before { + content: ""; } + +.fa-map-marker:before { + content: ""; } + +.fa-adjust:before { + content: ""; } + +.fa-tint:before { + content: ""; } + +.fa-edit:before, +.fa-pencil-square-o:before { + content: ""; } + +.fa-share-square-o:before { + content: ""; } + +.fa-check-square-o:before { + content: ""; } + +.fa-arrows:before { + content: ""; } + +.fa-step-backward:before { + content: ""; } + +.fa-fast-backward:before { + content: ""; } + +.fa-backward:before { + content: ""; } + +.fa-play:before { + content: ""; } + +.fa-pause:before { + content: ""; } + +.fa-stop:before { + content: ""; } + +.fa-forward:before { + content: ""; } + +.fa-fast-forward:before { + content: ""; } + +.fa-step-forward:before { + content: ""; } + +.fa-eject:before { + content: ""; } + +.fa-chevron-left:before { + content: ""; } + +.fa-chevron-right:before { + content: ""; } + +.fa-plus-circle:before { + content: ""; } + +.fa-minus-circle:before { + content: ""; } + +.fa-times-circle:before { + content: ""; } + +.fa-check-circle:before { + content: ""; } + +.fa-question-circle:before { + content: ""; } + +.fa-info-circle:before { + content: ""; } + +.fa-crosshairs:before { + content: ""; } + +.fa-times-circle-o:before { + content: ""; } + +.fa-check-circle-o:before { + content: ""; } + +.fa-ban:before { + content: ""; } + +.fa-arrow-left:before { + content: ""; } + +.fa-arrow-right:before { + content: ""; } + +.fa-arrow-up:before { + content: ""; } + +.fa-arrow-down:before { + content: ""; } + +.fa-mail-forward:before, +.fa-share:before { + content: ""; } + +.fa-expand:before { + content: ""; } + +.fa-compress:before { + content: ""; } + +.fa-plus:before { + content: ""; } + +.fa-minus:before { + content: ""; } + +.fa-asterisk:before { + content: ""; } + +.fa-exclamation-circle:before { + content: ""; } + +.fa-gift:before { + content: ""; } + +.fa-leaf:before { + content: ""; } + +.fa-fire:before { + content: ""; } + +.fa-eye:before { + content: ""; } + +.fa-eye-slash:before { + content: ""; } + +.fa-warning:before, +.fa-exclamation-triangle:before { + content: ""; } + +.fa-plane:before { + content: ""; } + +.fa-calendar:before { + content: ""; } + +.fa-random:before { + content: ""; } + +.fa-comment:before { + content: ""; } + +.fa-magnet:before { + content: ""; } + +.fa-chevron-up:before { + content: ""; } + +.fa-chevron-down:before { + content: ""; } + +.fa-retweet:before { + content: ""; } + +.fa-shopping-cart:before { + content: ""; } + +.fa-folder:before { + content: ""; } + +.fa-folder-open:before { + content: ""; } + +.fa-arrows-v:before { + content: ""; } + +.fa-arrows-h:before { + content: ""; } + +.fa-bar-chart-o:before, +.fa-bar-chart:before { + content: ""; } + +.fa-twitter-square:before { + content: ""; } + +.fa-facebook-square:before { + content: ""; } + +.fa-camera-retro:before { + content: ""; } + +.fa-key:before { + content: ""; } + +.fa-gears:before, +.fa-cogs:before { + content: ""; } + +.fa-comments:before { + content: ""; } + +.fa-thumbs-o-up:before { + content: ""; } + +.fa-thumbs-o-down:before { + content: ""; } + +.fa-star-half:before { + content: ""; } + +.fa-heart-o:before { + content: ""; } + +.fa-sign-out:before { + content: ""; } + +.fa-linkedin-square:before { + content: ""; } + +.fa-thumb-tack:before { + content: ""; } + +.fa-external-link:before { + content: ""; } + +.fa-sign-in:before { + content: ""; } + +.fa-trophy:before { + content: ""; } + +.fa-github-square:before { + content: ""; } + +.fa-upload:before { + content: ""; } + +.fa-lemon-o:before { + content: ""; } + +.fa-phone:before { + content: ""; } + +.fa-square-o:before { + content: ""; } + +.fa-bookmark-o:before { + content: ""; } + +.fa-phone-square:before { + content: ""; } + +.fa-twitter:before { + content: ""; } + +.fa-facebook-f:before, +.fa-facebook:before { + content: ""; } + +.fa-github:before { + content: ""; } + +.fa-unlock:before { + content: ""; } + +.fa-credit-card:before { + content: ""; } + +.fa-feed:before, +.fa-rss:before { + content: ""; } + +.fa-hdd-o:before { + content: ""; } + +.fa-bullhorn:before { + content: ""; } + +.fa-bell:before { + content: ""; } + +.fa-certificate:before { + content: ""; } + +.fa-hand-o-right:before { + content: ""; } + +.fa-hand-o-left:before { + content: ""; } + +.fa-hand-o-up:before { + content: ""; } + +.fa-hand-o-down:before { + content: ""; } + +.fa-arrow-circle-left:before { + content: ""; } + +.fa-arrow-circle-right:before { + content: ""; } + +.fa-arrow-circle-up:before { + content: ""; } + +.fa-arrow-circle-down:before { + content: ""; } + +.fa-globe:before { + content: ""; } + +.fa-wrench:before { + content: ""; } + +.fa-tasks:before { + content: ""; } + +.fa-filter:before { + content: ""; } + +.fa-briefcase:before { + content: ""; } + +.fa-arrows-alt:before { + content: ""; } + +.fa-group:before, +.fa-users:before { + content: ""; } + +.fa-chain:before, +.fa-link:before { + content: ""; } + +.fa-cloud:before { + content: ""; } + +.fa-flask:before { + content: ""; } + +.fa-cut:before, +.fa-scissors:before { + content: ""; } + +.fa-copy:before, +.fa-files-o:before { + content: ""; } + +.fa-paperclip:before { + content: ""; } + +.fa-save:before, +.fa-floppy-o:before { + content: ""; } + +.fa-square:before { + content: ""; } + +.fa-navicon:before, +.fa-reorder:before, +.fa-bars:before { + content: ""; } + +.fa-list-ul:before { + content: ""; } + +.fa-list-ol:before { + content: ""; } + +.fa-strikethrough:before { + content: ""; } + +.fa-underline:before { + content: ""; } + +.fa-table:before { + content: ""; } + +.fa-magic:before { + content: ""; } + +.fa-truck:before { + content: ""; } + +.fa-pinterest:before { + content: ""; } + +.fa-pinterest-square:before { + content: ""; } + +.fa-google-plus-square:before { + content: ""; } + +.fa-google-plus:before { + content: ""; } + +.fa-money:before { + content: ""; } + +.fa-caret-down:before { + content: ""; } + +.fa-caret-up:before { + content: ""; } + +.fa-caret-left:before { + content: ""; } + +.fa-caret-right:before { + content: ""; } + +.fa-columns:before { + content: ""; } + +.fa-unsorted:before, +.fa-sort:before { + content: ""; } + +.fa-sort-down:before, +.fa-sort-desc:before { + content: ""; } + +.fa-sort-up:before, +.fa-sort-asc:before { + content: ""; } + +.fa-envelope:before { + content: ""; } + +.fa-linkedin:before { + content: ""; } + +.fa-rotate-left:before, +.fa-undo:before { + content: ""; } + +.fa-legal:before, +.fa-gavel:before { + content: ""; } + +.fa-dashboard:before, +.fa-tachometer:before { + content: ""; } + +.fa-comment-o:before { + content: ""; } + +.fa-comments-o:before { + content: ""; } + +.fa-flash:before, +.fa-bolt:before { + content: ""; } + +.fa-sitemap:before { + content: ""; } + +.fa-umbrella:before { + content: ""; } + +.fa-paste:before, +.fa-clipboard:before { + content: ""; } + +.fa-lightbulb-o:before { + content: ""; } + +.fa-exchange:before { + content: ""; } + +.fa-cloud-download:before { + content: ""; } + +.fa-cloud-upload:before { + content: ""; } + +.fa-user-md:before { + content: ""; } + +.fa-stethoscope:before { + content: ""; } + +.fa-suitcase:before { + content: ""; } + +.fa-bell-o:before { + content: ""; } + +.fa-coffee:before { + content: ""; } + +.fa-cutlery:before { + content: ""; } + +.fa-file-text-o:before { + content: ""; } + +.fa-building-o:before { + content: ""; } + +.fa-hospital-o:before { + content: ""; } + +.fa-ambulance:before { + content: ""; } + +.fa-medkit:before { + content: ""; } + +.fa-fighter-jet:before { + content: ""; } + +.fa-beer:before { + content: ""; } + +.fa-h-square:before { + content: ""; } + +.fa-plus-square:before { + content: ""; } + +.fa-angle-double-left:before { + content: ""; } + +.fa-angle-double-right:before { + content: ""; } + +.fa-angle-double-up:before { + content: ""; } + +.fa-angle-double-down:before { + content: ""; } + +.fa-angle-left:before { + content: ""; } + +.fa-angle-right:before { + content: ""; } + +.fa-angle-up:before { + content: ""; } + +.fa-angle-down:before { + content: ""; } + +.fa-desktop:before { + content: ""; } + +.fa-laptop:before { + content: ""; } + +.fa-tablet:before { + content: ""; } + +.fa-mobile-phone:before, +.fa-mobile:before { + content: ""; } + +.fa-circle-o:before { + content: ""; } + +.fa-quote-left:before { + content: ""; } + +.fa-quote-right:before { + content: ""; } + +.fa-spinner:before { + content: ""; } + +.fa-circle:before { + content: ""; } + +.fa-mail-reply:before, +.fa-reply:before { + content: ""; } + +.fa-github-alt:before { + content: ""; } + +.fa-folder-o:before { + content: ""; } + +.fa-folder-open-o:before { + content: ""; } + +.fa-smile-o:before { + content: ""; } + +.fa-frown-o:before { + content: ""; } + +.fa-meh-o:before { + content: ""; } + +.fa-gamepad:before { + content: ""; } + +.fa-keyboard-o:before { + content: ""; } + +.fa-flag-o:before { + content: ""; } + +.fa-flag-checkered:before { + content: ""; } + +.fa-terminal:before { + content: ""; } + +.fa-code:before { + content: ""; } + +.fa-mail-reply-all:before, +.fa-reply-all:before { + content: ""; } + +.fa-star-half-empty:before, +.fa-star-half-full:before, +.fa-star-half-o:before { + content: ""; } + +.fa-location-arrow:before { + content: ""; } + +.fa-crop:before { + content: ""; } + +.fa-code-fork:before { + content: ""; } + +.fa-unlink:before, +.fa-chain-broken:before { + content: ""; } + +.fa-question:before { + content: ""; } + +.fa-info:before { + content: ""; } + +.fa-exclamation:before { + content: ""; } + +.fa-superscript:before { + content: ""; } + +.fa-subscript:before { + content: ""; } + +.fa-eraser:before { + content: ""; } + +.fa-puzzle-piece:before { + content: ""; } + +.fa-microphone:before { + content: ""; } + +.fa-microphone-slash:before { + content: ""; } + +.fa-shield:before { + content: ""; } + +.fa-calendar-o:before { + content: ""; } + +.fa-fire-extinguisher:before { + content: ""; } + +.fa-rocket:before { + content: ""; } + +.fa-maxcdn:before { + content: ""; } + +.fa-chevron-circle-left:before { + content: ""; } + +.fa-chevron-circle-right:before { + content: ""; } + +.fa-chevron-circle-up:before { + content: ""; } + +.fa-chevron-circle-down:before { + content: ""; } + +.fa-html5:before { + content: ""; } + +.fa-css3:before { + content: ""; } + +.fa-anchor:before { + content: ""; } + +.fa-unlock-alt:before { + content: ""; } + +.fa-bullseye:before { + content: ""; } + +.fa-ellipsis-h:before { + content: ""; } + +.fa-ellipsis-v:before { + content: ""; } + +.fa-rss-square:before { + content: ""; } + +.fa-play-circle:before { + content: ""; } + +.fa-ticket:before { + content: ""; } + +.fa-minus-square:before { + content: ""; } + +.fa-minus-square-o:before { + content: ""; } + +.fa-level-up:before { + content: ""; } + +.fa-level-down:before { + content: ""; } + +.fa-check-square:before { + content: ""; } + +.fa-pencil-square:before { + content: ""; } + +.fa-external-link-square:before { + content: ""; } + +.fa-share-square:before { + content: ""; } + +.fa-compass:before { + content: ""; } + +.fa-toggle-down:before, +.fa-caret-square-o-down:before { + content: ""; } + +.fa-toggle-up:before, +.fa-caret-square-o-up:before { + content: ""; } + +.fa-toggle-right:before, +.fa-caret-square-o-right:before { + content: ""; } + +.fa-euro:before, +.fa-eur:before { + content: ""; } + +.fa-gbp:before { + content: ""; } + +.fa-dollar:before, +.fa-usd:before { + content: ""; } + +.fa-rupee:before, +.fa-inr:before { + content: ""; } + +.fa-cny:before, +.fa-rmb:before, +.fa-yen:before, +.fa-jpy:before { + content: ""; } + +.fa-ruble:before, +.fa-rouble:before, +.fa-rub:before { + content: ""; } + +.fa-won:before, +.fa-krw:before { + content: ""; } + +.fa-bitcoin:before, +.fa-btc:before { + content: ""; } + +.fa-file:before { + content: ""; } + +.fa-file-text:before { + content: ""; } + +.fa-sort-alpha-asc:before { + content: ""; } + +.fa-sort-alpha-desc:before { + content: ""; } + +.fa-sort-amount-asc:before { + content: ""; } + +.fa-sort-amount-desc:before { + content: ""; } + +.fa-sort-numeric-asc:before { + content: ""; } + +.fa-sort-numeric-desc:before { + content: ""; } + +.fa-thumbs-up:before { + content: ""; } + +.fa-thumbs-down:before { + content: ""; } + +.fa-youtube-square:before { + content: ""; } + +.fa-youtube:before { + content: ""; } + +.fa-xing:before { + content: ""; } + +.fa-xing-square:before { + content: ""; } + +.fa-youtube-play:before { + content: ""; } + +.fa-dropbox:before { + content: ""; } + +.fa-stack-overflow:before { + content: ""; } + +.fa-instagram:before { + content: ""; } + +.fa-flickr:before { + content: ""; } + +.fa-adn:before { + content: ""; } + +.fa-bitbucket:before { + content: ""; } + +.fa-bitbucket-square:before { + content: ""; } + +.fa-tumblr:before { + content: ""; } + +.fa-tumblr-square:before { + content: ""; } + +.fa-long-arrow-down:before { + content: ""; } + +.fa-long-arrow-up:before { + content: ""; } + +.fa-long-arrow-left:before { + content: ""; } + +.fa-long-arrow-right:before { + content: ""; } + +.fa-apple:before { + content: ""; } + +.fa-windows:before { + content: ""; } + +.fa-android:before { + content: ""; } + +.fa-linux:before { + content: ""; } + +.fa-dribbble:before { + content: ""; } + +.fa-skype:before { + content: ""; } + +.fa-foursquare:before { + content: ""; } + +.fa-trello:before { + content: ""; } + +.fa-female:before { + content: ""; } + +.fa-male:before { + content: ""; } + +.fa-gittip:before, +.fa-gratipay:before { + content: ""; } + +.fa-sun-o:before { + content: ""; } + +.fa-moon-o:before { + content: ""; } + +.fa-archive:before { + content: ""; } + +.fa-bug:before { + content: ""; } + +.fa-vk:before { + content: ""; } + +.fa-weibo:before { + content: ""; } + +.fa-renren:before { + content: ""; } + +.fa-pagelines:before { + content: ""; } + +.fa-stack-exchange:before { + content: ""; } + +.fa-arrow-circle-o-right:before { + content: ""; } + +.fa-arrow-circle-o-left:before { + content: ""; } + +.fa-toggle-left:before, +.fa-caret-square-o-left:before { + content: ""; } + +.fa-dot-circle-o:before { + content: ""; } + +.fa-wheelchair:before { + content: ""; } + +.fa-vimeo-square:before { + content: ""; } + +.fa-turkish-lira:before, +.fa-try:before { + content: ""; } + +.fa-plus-square-o:before { + content: ""; } + +.fa-space-shuttle:before { + content: ""; } + +.fa-slack:before { + content: ""; } + +.fa-envelope-square:before { + content: ""; } + +.fa-wordpress:before { + content: ""; } + +.fa-openid:before { + content: ""; } + +.fa-institution:before, +.fa-bank:before, +.fa-university:before { + content: ""; } + +.fa-mortar-board:before, +.fa-graduation-cap:before { + content: ""; } + +.fa-yahoo:before { + content: ""; } + +.fa-google:before { + content: ""; } + +.fa-reddit:before { + content: ""; } + +.fa-reddit-square:before { + content: ""; } + +.fa-stumbleupon-circle:before { + content: ""; } + +.fa-stumbleupon:before { + content: ""; } + +.fa-delicious:before { + content: ""; } + +.fa-digg:before { + content: ""; } + +.fa-pied-piper-pp:before { + content: ""; } + +.fa-pied-piper-alt:before { + content: ""; } + +.fa-drupal:before { + content: ""; } + +.fa-joomla:before { + content: ""; } + +.fa-language:before { + content: ""; } + +.fa-fax:before { + content: ""; } + +.fa-building:before { + content: ""; } + +.fa-child:before { + content: ""; } + +.fa-paw:before { + content: ""; } + +.fa-spoon:before { + content: ""; } + +.fa-cube:before { + content: ""; } + +.fa-cubes:before { + content: ""; } + +.fa-behance:before { + content: ""; } + +.fa-behance-square:before { + content: ""; } + +.fa-steam:before { + content: ""; } + +.fa-steam-square:before { + content: ""; } + +.fa-recycle:before { + content: ""; } + +.fa-automobile:before, +.fa-car:before { + content: ""; } + +.fa-cab:before, +.fa-taxi:before { + content: ""; } + +.fa-tree:before { + content: ""; } + +.fa-spotify:before { + content: ""; } + +.fa-deviantart:before { + content: ""; } + +.fa-soundcloud:before { + content: ""; } + +.fa-database:before { + content: ""; } + +.fa-file-pdf-o:before { + content: ""; } + +.fa-file-word-o:before { + content: ""; } + +.fa-file-excel-o:before { + content: ""; } + +.fa-file-powerpoint-o:before { + content: ""; } + +.fa-file-photo-o:before, +.fa-file-picture-o:before, +.fa-file-image-o:before { + content: ""; } + +.fa-file-zip-o:before, +.fa-file-archive-o:before { + content: ""; } + +.fa-file-sound-o:before, +.fa-file-audio-o:before { + content: ""; } + +.fa-file-movie-o:before, +.fa-file-video-o:before { + content: ""; } + +.fa-file-code-o:before { + content: ""; } + +.fa-vine:before { + content: ""; } + +.fa-codepen:before { + content: ""; } + +.fa-jsfiddle:before { + content: ""; } + +.fa-life-bouy:before, +.fa-life-buoy:before, +.fa-life-saver:before, +.fa-support:before, +.fa-life-ring:before { + content: ""; } + +.fa-circle-o-notch:before { + content: ""; } + +.fa-ra:before, +.fa-resistance:before, +.fa-rebel:before { + content: ""; } + +.fa-ge:before, +.fa-empire:before { + content: ""; } + +.fa-git-square:before { + content: ""; } + +.fa-git:before { + content: ""; } + +.fa-y-combinator-square:before, +.fa-yc-square:before, +.fa-hacker-news:before { + content: ""; } + +.fa-tencent-weibo:before { + content: ""; } + +.fa-qq:before { + content: ""; } + +.fa-wechat:before, +.fa-weixin:before { + content: ""; } + +.fa-send:before, +.fa-paper-plane:before { + content: ""; } + +.fa-send-o:before, +.fa-paper-plane-o:before { + content: ""; } + +.fa-history:before { + content: ""; } + +.fa-circle-thin:before { + content: ""; } + +.fa-header:before { + content: ""; } + +.fa-paragraph:before { + content: ""; } + +.fa-sliders:before { + content: ""; } + +.fa-share-alt:before { + content: ""; } + +.fa-share-alt-square:before { + content: ""; } + +.fa-bomb:before { + content: ""; } + +.fa-soccer-ball-o:before, +.fa-futbol-o:before { + content: ""; } + +.fa-tty:before { + content: ""; } + +.fa-binoculars:before { + content: ""; } + +.fa-plug:before { + content: ""; } + +.fa-slideshare:before { + content: ""; } + +.fa-twitch:before { + content: ""; } + +.fa-yelp:before { + content: ""; } + +.fa-newspaper-o:before { + content: ""; } + +.fa-wifi:before { + content: ""; } + +.fa-calculator:before { + content: ""; } + +.fa-paypal:before { + content: ""; } + +.fa-google-wallet:before { + content: ""; } + +.fa-cc-visa:before { + content: ""; } + +.fa-cc-mastercard:before { + content: ""; } + +.fa-cc-discover:before { + content: ""; } + +.fa-cc-amex:before { + content: ""; } + +.fa-cc-paypal:before { + content: ""; } + +.fa-cc-stripe:before { + content: ""; } + +.fa-bell-slash:before { + content: ""; } + +.fa-bell-slash-o:before { + content: ""; } + +.fa-trash:before { + content: ""; } + +.fa-copyright:before { + content: ""; } + +.fa-at:before { + content: ""; } + +.fa-eyedropper:before { + content: ""; } + +.fa-paint-brush:before { + content: ""; } + +.fa-birthday-cake:before { + content: ""; } + +.fa-area-chart:before { + content: ""; } + +.fa-pie-chart:before { + content: ""; } + +.fa-line-chart:before { + content: ""; } + +.fa-lastfm:before { + content: ""; } + +.fa-lastfm-square:before { + content: ""; } + +.fa-toggle-off:before { + content: ""; } + +.fa-toggle-on:before { + content: ""; } + +.fa-bicycle:before { + content: ""; } + +.fa-bus:before { + content: ""; } + +.fa-ioxhost:before { + content: ""; } + +.fa-angellist:before { + content: ""; } + +.fa-cc:before { + content: ""; } + +.fa-shekel:before, +.fa-sheqel:before, +.fa-ils:before { + content: ""; } + +.fa-meanpath:before { + content: ""; } + +.fa-buysellads:before { + content: ""; } + +.fa-connectdevelop:before { + content: ""; } + +.fa-dashcube:before { + content: ""; } + +.fa-forumbee:before { + content: ""; } + +.fa-leanpub:before { + content: ""; } + +.fa-sellsy:before { + content: ""; } + +.fa-shirtsinbulk:before { + content: ""; } + +.fa-simplybuilt:before { + content: ""; } + +.fa-skyatlas:before { + content: ""; } + +.fa-cart-plus:before { + content: ""; } + +.fa-cart-arrow-down:before { + content: ""; } + +.fa-diamond:before { + content: ""; } + +.fa-ship:before { + content: ""; } + +.fa-user-secret:before { + content: ""; } + +.fa-motorcycle:before { + content: ""; } + +.fa-street-view:before { + content: ""; } + +.fa-heartbeat:before { + content: ""; } + +.fa-venus:before { + content: ""; } + +.fa-mars:before { + content: ""; } + +.fa-mercury:before { + content: ""; } + +.fa-intersex:before, +.fa-transgender:before { + content: ""; } + +.fa-transgender-alt:before { + content: ""; } + +.fa-venus-double:before { + content: ""; } + +.fa-mars-double:before { + content: ""; } + +.fa-venus-mars:before { + content: ""; } + +.fa-mars-stroke:before { + content: ""; } + +.fa-mars-stroke-v:before { + content: ""; } + +.fa-mars-stroke-h:before { + content: ""; } + +.fa-neuter:before { + content: ""; } + +.fa-genderless:before { + content: ""; } + +.fa-facebook-official:before { + content: ""; } + +.fa-pinterest-p:before { + content: ""; } + +.fa-whatsapp:before { + content: ""; } + +.fa-server:before { + content: ""; } + +.fa-user-plus:before { + content: ""; } + +.fa-user-times:before { + content: ""; } + +.fa-hotel:before, +.fa-bed:before { + content: ""; } + +.fa-viacoin:before { + content: ""; } + +.fa-train:before { + content: ""; } + +.fa-subway:before { + content: ""; } + +.fa-medium:before { + content: ""; } + +.fa-yc:before, +.fa-y-combinator:before { + content: ""; } + +.fa-optin-monster:before { + content: ""; } + +.fa-opencart:before { + content: ""; } + +.fa-expeditedssl:before { + content: ""; } + +.fa-battery-4:before, +.fa-battery:before, +.fa-battery-full:before { + content: ""; } + +.fa-battery-3:before, +.fa-battery-three-quarters:before { + content: ""; } + +.fa-battery-2:before, +.fa-battery-half:before { + content: ""; } + +.fa-battery-1:before, +.fa-battery-quarter:before { + content: ""; } + +.fa-battery-0:before, +.fa-battery-empty:before { + content: ""; } + +.fa-mouse-pointer:before { + content: ""; } + +.fa-i-cursor:before { + content: ""; } + +.fa-object-group:before { + content: ""; } + +.fa-object-ungroup:before { + content: ""; } + +.fa-sticky-note:before { + content: ""; } + +.fa-sticky-note-o:before { + content: ""; } + +.fa-cc-jcb:before { + content: ""; } + +.fa-cc-diners-club:before { + content: ""; } + +.fa-clone:before { + content: ""; } + +.fa-balance-scale:before { + content: ""; } + +.fa-hourglass-o:before { + content: ""; } + +.fa-hourglass-1:before, +.fa-hourglass-start:before { + content: ""; } + +.fa-hourglass-2:before, +.fa-hourglass-half:before { + content: ""; } + +.fa-hourglass-3:before, +.fa-hourglass-end:before { + content: ""; } + +.fa-hourglass:before { + content: ""; } + +.fa-hand-grab-o:before, +.fa-hand-rock-o:before { + content: ""; } + +.fa-hand-stop-o:before, +.fa-hand-paper-o:before { + content: ""; } + +.fa-hand-scissors-o:before { + content: ""; } + +.fa-hand-lizard-o:before { + content: ""; } + +.fa-hand-spock-o:before { + content: ""; } + +.fa-hand-pointer-o:before { + content: ""; } + +.fa-hand-peace-o:before { + content: ""; } + +.fa-trademark:before { + content: ""; } + +.fa-registered:before { + content: ""; } + +.fa-creative-commons:before { + content: ""; } + +.fa-gg:before { + content: ""; } + +.fa-gg-circle:before { + content: ""; } + +.fa-tripadvisor:before { + content: ""; } + +.fa-odnoklassniki:before { + content: ""; } + +.fa-odnoklassniki-square:before { + content: ""; } + +.fa-get-pocket:before { + content: ""; } + +.fa-wikipedia-w:before { + content: ""; } + +.fa-safari:before { + content: ""; } + +.fa-chrome:before { + content: ""; } + +.fa-firefox:before { + content: ""; } + +.fa-opera:before { + content: ""; } + +.fa-internet-explorer:before { + content: ""; } + +.fa-tv:before, +.fa-television:before { + content: ""; } + +.fa-contao:before { + content: ""; } + +.fa-500px:before { + content: ""; } + +.fa-amazon:before { + content: ""; } + +.fa-calendar-plus-o:before { + content: ""; } + +.fa-calendar-minus-o:before { + content: ""; } + +.fa-calendar-times-o:before { + content: ""; } + +.fa-calendar-check-o:before { + content: ""; } + +.fa-industry:before { + content: ""; } + +.fa-map-pin:before { + content: ""; } + +.fa-map-signs:before { + content: ""; } + +.fa-map-o:before { + content: ""; } + +.fa-map:before { + content: ""; } + +.fa-commenting:before { + content: ""; } + +.fa-commenting-o:before { + content: ""; } + +.fa-houzz:before { + content: ""; } + +.fa-vimeo:before { + content: ""; } + +.fa-black-tie:before { + content: ""; } + +.fa-fonticons:before { + content: ""; } + +.fa-reddit-alien:before { + content: ""; } + +.fa-edge:before { + content: ""; } + +.fa-credit-card-alt:before { + content: ""; } + +.fa-codiepie:before { + content: ""; } + +.fa-modx:before { + content: ""; } + +.fa-fort-awesome:before { + content: ""; } + +.fa-usb:before { + content: ""; } + +.fa-product-hunt:before { + content: ""; } + +.fa-mixcloud:before { + content: ""; } + +.fa-scribd:before { + content: ""; } + +.fa-pause-circle:before { + content: ""; } + +.fa-pause-circle-o:before { + content: ""; } + +.fa-stop-circle:before { + content: ""; } + +.fa-stop-circle-o:before { + content: ""; } + +.fa-shopping-bag:before { + content: ""; } + +.fa-shopping-basket:before { + content: ""; } + +.fa-hashtag:before { + content: ""; } + +.fa-bluetooth:before { + content: ""; } + +.fa-bluetooth-b:before { + content: ""; } + +.fa-percent:before { + content: ""; } + +.fa-gitlab:before { + content: ""; } + +.fa-wpbeginner:before { + content: ""; } + +.fa-wpforms:before { + content: ""; } + +.fa-envira:before { + content: ""; } + +.fa-universal-access:before { + content: ""; } + +.fa-wheelchair-alt:before { + content: ""; } + +.fa-question-circle-o:before { + content: ""; } + +.fa-blind:before { + content: ""; } + +.fa-audio-description:before { + content: ""; } + +.fa-volume-control-phone:before { + content: ""; } + +.fa-braille:before { + content: ""; } + +.fa-assistive-listening-systems:before { + content: ""; } + +.fa-asl-interpreting:before, +.fa-american-sign-language-interpreting:before { + content: ""; } + +.fa-deafness:before, +.fa-hard-of-hearing:before, +.fa-deaf:before { + content: ""; } + +.fa-glide:before { + content: ""; } + +.fa-glide-g:before { + content: ""; } + +.fa-signing:before, +.fa-sign-language:before { + content: ""; } + +.fa-low-vision:before { + content: ""; } + +.fa-viadeo:before { + content: ""; } + +.fa-viadeo-square:before { + content: ""; } + +.fa-snapchat:before { + content: ""; } + +.fa-snapchat-ghost:before { + content: ""; } + +.fa-snapchat-square:before { + content: ""; } + +.fa-pied-piper:before { + content: ""; } + +.fa-first-order:before { + content: ""; } + +.fa-yoast:before { + content: ""; } + +.fa-themeisle:before { + content: ""; } + +.fa-google-plus-circle:before, +.fa-google-plus-official:before { + content: ""; } + +.fa-fa:before, +.fa-font-awesome:before { + content: ""; } + +.fa-handshake-o:before { + content: ""; } + +.fa-envelope-open:before { + content: ""; } + +.fa-envelope-open-o:before { + content: ""; } + +.fa-linode:before { + content: ""; } + +.fa-address-book:before { + content: ""; } + +.fa-address-book-o:before { + content: ""; } + +.fa-vcard:before, +.fa-address-card:before { + content: ""; } + +.fa-vcard-o:before, +.fa-address-card-o:before { + content: ""; } + +.fa-user-circle:before { + content: ""; } + +.fa-user-circle-o:before { + content: ""; } + +.fa-user-o:before { + content: ""; } + +.fa-id-badge:before { + content: ""; } + +.fa-drivers-license:before, +.fa-id-card:before { + content: ""; } + +.fa-drivers-license-o:before, +.fa-id-card-o:before { + content: ""; } + +.fa-quora:before { + content: ""; } + +.fa-free-code-camp:before { + content: ""; } + +.fa-telegram:before { + content: ""; } + +.fa-thermometer-4:before, +.fa-thermometer:before, +.fa-thermometer-full:before { + content: ""; } + +.fa-thermometer-3:before, +.fa-thermometer-three-quarters:before { + content: ""; } + +.fa-thermometer-2:before, +.fa-thermometer-half:before { + content: ""; } + +.fa-thermometer-1:before, +.fa-thermometer-quarter:before { + content: ""; } + +.fa-thermometer-0:before, +.fa-thermometer-empty:before { + content: ""; } + +.fa-shower:before { + content: ""; } + +.fa-bathtub:before, +.fa-s15:before, +.fa-bath:before { + content: ""; } + +.fa-podcast:before { + content: ""; } + +.fa-window-maximize:before { + content: ""; } + +.fa-window-minimize:before { + content: ""; } + +.fa-window-restore:before { + content: ""; } + +.fa-times-rectangle:before, +.fa-window-close:before { + content: ""; } + +.fa-times-rectangle-o:before, +.fa-window-close-o:before { + content: ""; } + +.fa-bandcamp:before { + content: ""; } + +.fa-grav:before { + content: ""; } + +.fa-etsy:before { + content: ""; } + +.fa-imdb:before { + content: ""; } + +.fa-ravelry:before { + content: ""; } + +.fa-eercast:before { + content: ""; } + +.fa-microchip:before { + content: ""; } + +.fa-snowflake-o:before { + content: ""; } + +.fa-superpowers:before { + content: ""; } + +.fa-wpexplorer:before { + content: ""; } + +.fa-meetup:before { + content: ""; } + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; } + +.sr-only-focusable:active, .sr-only-focusable:focus { + position: static; + width: auto; + height: auto; + margin: 0; + overflow: visible; + clip: auto; } + +/*! bulma.io v0.9.2 | MIT License | github.com/jgthms/bulma */ +/* Bulma Utilities */ +.button, .input, .textarea, .select select, .file-cta, +.file-name, .pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis { + -moz-appearance: none; + -webkit-appearance: none; + align-items: center; + border: 1px solid transparent; + border-radius: 4px; + box-shadow: none; + display: inline-flex; + font-size: 1rem; + height: 2.5em; + justify-content: flex-start; + line-height: 1.5; + padding-bottom: calc(0.5em - 1px); + padding-left: calc(0.75em - 1px); + padding-right: calc(0.75em - 1px); + padding-top: calc(0.5em - 1px); + position: relative; + vertical-align: top; } + .button:focus, .input:focus, .textarea:focus, .select select:focus, .file-cta:focus, + .file-name:focus, .pagination-previous:focus, + .pagination-next:focus, + .pagination-link:focus, + .pagination-ellipsis:focus, .is-focused.button, .is-focused.input, .is-focused.textarea, .select select.is-focused, .is-focused.file-cta, + .is-focused.file-name, .is-focused.pagination-previous, + .is-focused.pagination-next, + .is-focused.pagination-link, + .is-focused.pagination-ellipsis, .button:active, .input:active, .textarea:active, .select select:active, .file-cta:active, + .file-name:active, .pagination-previous:active, + .pagination-next:active, + .pagination-link:active, + .pagination-ellipsis:active, .is-active.button, .is-active.input, .is-active.textarea, .select select.is-active, .is-active.file-cta, + .is-active.file-name, .is-active.pagination-previous, + .is-active.pagination-next, + .is-active.pagination-link, + .is-active.pagination-ellipsis { + outline: none; } + .button[disabled], .input[disabled], .textarea[disabled], .select select[disabled], .file-cta[disabled], + .file-name[disabled], .pagination-previous[disabled], + .pagination-next[disabled], + .pagination-link[disabled], + .pagination-ellipsis[disabled], + fieldset[disabled] .button, + fieldset[disabled] .input, + fieldset[disabled] .textarea, + fieldset[disabled] .select select, + .select fieldset[disabled] select, + fieldset[disabled] .file-cta, + fieldset[disabled] .file-name, + fieldset[disabled] .pagination-previous, + fieldset[disabled] .pagination-next, + fieldset[disabled] .pagination-link, + fieldset[disabled] .pagination-ellipsis { + cursor: not-allowed; } + +.button, .file, .breadcrumb, .pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis, .tabs, .is-unselectable { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; } + +.select:not(.is-multiple):not(.is-loading)::after, .navbar-link:not(.is-arrowless)::after { + border: 3px solid transparent; + border-radius: 2px; + border-right: 0; + border-top: 0; + content: " "; + display: block; + height: 0.625em; + margin-top: -0.4375em; + pointer-events: none; + position: absolute; + top: 50%; + transform: rotate(-45deg); + transform-origin: center; + width: 0.625em; } + +.box:not(:last-child), .content:not(:last-child), .notification:not(:last-child), .progress:not(:last-child), .table:not(:last-child), .table-container:not(:last-child), .title:not(:last-child), +.subtitle:not(:last-child), .block:not(:last-child), .highlight:not(:last-child), .breadcrumb:not(:last-child), .level:not(:last-child), .message:not(:last-child), .pagination:not(:last-child), .tabs:not(:last-child) { + margin-bottom: 1.5rem; } + +.delete, .modal-close { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -moz-appearance: none; + -webkit-appearance: none; + background-color: rgba(10, 10, 10, 0.2); + border: none; + border-radius: 290486px; + cursor: pointer; + pointer-events: auto; + display: inline-block; + flex-grow: 0; + flex-shrink: 0; + font-size: 0; + height: 20px; + max-height: 20px; + max-width: 20px; + min-height: 20px; + min-width: 20px; + outline: none; + position: relative; + vertical-align: top; + width: 20px; } + .delete::before, .modal-close::before, .delete::after, .modal-close::after { + background-color: white; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; } + .delete::before, .modal-close::before { + height: 2px; + width: 50%; } + .delete::after, .modal-close::after { + height: 50%; + width: 2px; } + .delete:hover, .modal-close:hover, .delete:focus, .modal-close:focus { + background-color: rgba(10, 10, 10, 0.3); } + .delete:active, .modal-close:active { + background-color: rgba(10, 10, 10, 0.4); } + .is-small.delete, .is-small.modal-close { + height: 16px; + max-height: 16px; + max-width: 16px; + min-height: 16px; + min-width: 16px; + width: 16px; } + .is-medium.delete, .is-medium.modal-close { + height: 24px; + max-height: 24px; + max-width: 24px; + min-height: 24px; + min-width: 24px; + width: 24px; } + .is-large.delete, .is-large.modal-close { + height: 32px; + max-height: 32px; + max-width: 32px; + min-height: 32px; + min-width: 32px; + width: 32px; } + +.button.is-loading::after, .loader, .select.is-loading::after, .control.is-loading::after { + animation: spinAround 500ms infinite linear; + border: 2px solid #dbdbdb; + border-radius: 290486px; + border-right-color: transparent; + border-top-color: transparent; + content: ""; + display: block; + height: 1em; + position: relative; + width: 1em; } + +.image.is-square img, +.image.is-square .has-ratio, .image.is-1by1 img, +.image.is-1by1 .has-ratio, .image.is-5by4 img, +.image.is-5by4 .has-ratio, .image.is-4by3 img, +.image.is-4by3 .has-ratio, .image.is-3by2 img, +.image.is-3by2 .has-ratio, .image.is-5by3 img, +.image.is-5by3 .has-ratio, .image.is-16by9 img, +.image.is-16by9 .has-ratio, .image.is-2by1 img, +.image.is-2by1 .has-ratio, .image.is-3by1 img, +.image.is-3by1 .has-ratio, .image.is-4by5 img, +.image.is-4by5 .has-ratio, .image.is-3by4 img, +.image.is-3by4 .has-ratio, .image.is-2by3 img, +.image.is-2by3 .has-ratio, .image.is-3by5 img, +.image.is-3by5 .has-ratio, .image.is-9by16 img, +.image.is-9by16 .has-ratio, .image.is-1by2 img, +.image.is-1by2 .has-ratio, .image.is-1by3 img, +.image.is-1by3 .has-ratio, .modal, .modal-background, .is-overlay, .hero-video { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; } + +/* Bulma Base */ +/*! minireset.css v0.0.6 | MIT License | github.com/jgthms/minireset.css */ +html, +body, +p, +ol, +ul, +li, +dl, +dt, +dd, +blockquote, +figure, +fieldset, +legend, +textarea, +pre, +iframe, +hr, +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + padding: 0; } + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: 100%; + font-weight: normal; } + +ul { + list-style: none; } + +button, +input, +select, +textarea { + margin: 0; } + +html { + box-sizing: border-box; } + +*, *::before, *::after { + box-sizing: inherit; } + +img, +video { + height: auto; + max-width: 100%; } + +iframe { + border: 0; } + +table { + border-collapse: collapse; + border-spacing: 0; } + +td, +th { + padding: 0; } + td:not([align]), + th:not([align]) { + text-align: inherit; } + +html { + background-color: white; + font-size: 16px; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + min-width: 300px; + overflow-x: hidden; + overflow-y: scroll; + text-rendering: optimizeLegibility; + text-size-adjust: 100%; } + +article, +aside, +figure, +footer, +header, +hgroup, +section { + display: block; } + +body, +button, +input, +optgroup, +select, +textarea { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif; } + +code, +pre { + -moz-osx-font-smoothing: auto; + -webkit-font-smoothing: auto; + font-family: monospace; } + +body { + color: #4a4a4a; + font-size: 1em; + font-weight: 400; + line-height: 1.5; } + +a { + color: #3273dc; + cursor: pointer; + text-decoration: none; } + a strong { + color: currentColor; } + a:hover { + color: #363636; } + +code { + background-color: whitesmoke; + color: #da1039; + font-size: 0.875em; + font-weight: normal; + padding: 0.25em 0.5em 0.25em; } + +hr { + background-color: whitesmoke; + border: none; + display: block; + height: 2px; + margin: 1.5rem 0; } + +img { + height: auto; + max-width: 100%; } + +input[type="checkbox"], +input[type="radio"] { + vertical-align: baseline; } + +small { + font-size: 0.875em; } + +span { + font-style: inherit; + font-weight: inherit; } + +strong { + color: #363636; + font-weight: 700; } + +fieldset { + border: none; } + +pre { + -webkit-overflow-scrolling: touch; + background-color: whitesmoke; + color: #4a4a4a; + font-size: 0.875em; + overflow-x: auto; + padding: 1.25rem 1.5rem; + white-space: pre; + word-wrap: normal; } + pre code { + background-color: transparent; + color: currentColor; + font-size: 1em; + padding: 0; } + +table td, +table th { + vertical-align: top; } + table td:not([align]), + table th:not([align]) { + text-align: inherit; } + +table th { + color: #363636; } + +@keyframes spinAround { + from { + transform: rotate(0deg); } + to { + transform: rotate(359deg); } } + +/* Bulma Elements */ +.box { + background-color: white; + border-radius: 6px; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + color: #4a4a4a; + display: block; + padding: 1.25rem; } + +a.box:hover, a.box:focus { + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0 0 1px #3273dc; } + +a.box:active { + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.2), 0 0 0 1px #3273dc; } + +.button { + background-color: white; + border-color: #dbdbdb; + border-width: 1px; + color: #363636; + cursor: pointer; + justify-content: center; + padding-bottom: calc(0.5em - 1px); + padding-left: 1em; + padding-right: 1em; + padding-top: calc(0.5em - 1px); + text-align: center; + white-space: nowrap; } + .button strong { + color: inherit; } + .button .icon, .button .icon.is-small, .button .icon.is-medium, .button .icon.is-large { + height: 1.5em; + width: 1.5em; } + .button .icon:first-child:not(:last-child) { + margin-left: calc(-0.5em - 1px); + margin-right: 0.25em; } + .button .icon:last-child:not(:first-child) { + margin-left: 0.25em; + margin-right: calc(-0.5em - 1px); } + .button .icon:first-child:last-child { + margin-left: calc(-0.5em - 1px); + margin-right: calc(-0.5em - 1px); } + .button:hover, .button.is-hovered { + border-color: #b5b5b5; + color: #363636; } + .button:focus, .button.is-focused { + border-color: #3273dc; + color: #363636; } + .button:focus:not(:active), .button.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .button:active, .button.is-active { + border-color: #4a4a4a; + color: #363636; } + .button.is-text { + background-color: transparent; + border-color: transparent; + color: #4a4a4a; + text-decoration: underline; } + .button.is-text:hover, .button.is-text.is-hovered, .button.is-text:focus, .button.is-text.is-focused { + background-color: whitesmoke; + color: #363636; } + .button.is-text:active, .button.is-text.is-active { + background-color: #e8e8e8; + color: #363636; } + .button.is-text[disabled], + fieldset[disabled] .button.is-text { + background-color: transparent; + border-color: transparent; + box-shadow: none; } + .button.is-ghost { + background: none; + border-color: transparent; + color: #3273dc; + text-decoration: none; } + .button.is-ghost:hover, .button.is-ghost.is-hovered { + color: #3273dc; + text-decoration: underline; } + .button.is-white { + background-color: white; + border-color: transparent; + color: #0a0a0a; } + .button.is-white:hover, .button.is-white.is-hovered { + background-color: #f9f9f9; + border-color: transparent; + color: #0a0a0a; } + .button.is-white:focus, .button.is-white.is-focused { + border-color: transparent; + color: #0a0a0a; } + .button.is-white:focus:not(:active), .button.is-white.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); } + .button.is-white:active, .button.is-white.is-active { + background-color: #f2f2f2; + border-color: transparent; + color: #0a0a0a; } + .button.is-white[disabled], + fieldset[disabled] .button.is-white { + background-color: white; + border-color: transparent; + box-shadow: none; } + .button.is-white.is-inverted { + background-color: #0a0a0a; + color: white; } + .button.is-white.is-inverted:hover, .button.is-white.is-inverted.is-hovered { + background-color: black; } + .button.is-white.is-inverted[disabled], + fieldset[disabled] .button.is-white.is-inverted { + background-color: #0a0a0a; + border-color: transparent; + box-shadow: none; + color: white; } + .button.is-white.is-loading::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; } + .button.is-white.is-outlined { + background-color: transparent; + border-color: white; + color: white; } + .button.is-white.is-outlined:hover, .button.is-white.is-outlined.is-hovered, .button.is-white.is-outlined:focus, .button.is-white.is-outlined.is-focused { + background-color: white; + border-color: white; + color: #0a0a0a; } + .button.is-white.is-outlined.is-loading::after { + border-color: transparent transparent white white !important; } + .button.is-white.is-outlined.is-loading:hover::after, .button.is-white.is-outlined.is-loading.is-hovered::after, .button.is-white.is-outlined.is-loading:focus::after, .button.is-white.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; } + .button.is-white.is-outlined[disabled], + fieldset[disabled] .button.is-white.is-outlined { + background-color: transparent; + border-color: white; + box-shadow: none; + color: white; } + .button.is-white.is-inverted.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + color: #0a0a0a; } + .button.is-white.is-inverted.is-outlined:hover, .button.is-white.is-inverted.is-outlined.is-hovered, .button.is-white.is-inverted.is-outlined:focus, .button.is-white.is-inverted.is-outlined.is-focused { + background-color: #0a0a0a; + color: white; } + .button.is-white.is-inverted.is-outlined.is-loading:hover::after, .button.is-white.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-white.is-inverted.is-outlined.is-loading:focus::after, .button.is-white.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent white white !important; } + .button.is-white.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-white.is-inverted.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + box-shadow: none; + color: #0a0a0a; } + .button.is-black { + background-color: #0a0a0a; + border-color: transparent; + color: white; } + .button.is-black:hover, .button.is-black.is-hovered { + background-color: #040404; + border-color: transparent; + color: white; } + .button.is-black:focus, .button.is-black.is-focused { + border-color: transparent; + color: white; } + .button.is-black:focus:not(:active), .button.is-black.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); } + .button.is-black:active, .button.is-black.is-active { + background-color: black; + border-color: transparent; + color: white; } + .button.is-black[disabled], + fieldset[disabled] .button.is-black { + background-color: #0a0a0a; + border-color: transparent; + box-shadow: none; } + .button.is-black.is-inverted { + background-color: white; + color: #0a0a0a; } + .button.is-black.is-inverted:hover, .button.is-black.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-black.is-inverted[disabled], + fieldset[disabled] .button.is-black.is-inverted { + background-color: white; + border-color: transparent; + box-shadow: none; + color: #0a0a0a; } + .button.is-black.is-loading::after { + border-color: transparent transparent white white !important; } + .button.is-black.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + color: #0a0a0a; } + .button.is-black.is-outlined:hover, .button.is-black.is-outlined.is-hovered, .button.is-black.is-outlined:focus, .button.is-black.is-outlined.is-focused { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; } + .button.is-black.is-outlined.is-loading::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; } + .button.is-black.is-outlined.is-loading:hover::after, .button.is-black.is-outlined.is-loading.is-hovered::after, .button.is-black.is-outlined.is-loading:focus::after, .button.is-black.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent white white !important; } + .button.is-black.is-outlined[disabled], + fieldset[disabled] .button.is-black.is-outlined { + background-color: transparent; + border-color: #0a0a0a; + box-shadow: none; + color: #0a0a0a; } + .button.is-black.is-inverted.is-outlined { + background-color: transparent; + border-color: white; + color: white; } + .button.is-black.is-inverted.is-outlined:hover, .button.is-black.is-inverted.is-outlined.is-hovered, .button.is-black.is-inverted.is-outlined:focus, .button.is-black.is-inverted.is-outlined.is-focused { + background-color: white; + color: #0a0a0a; } + .button.is-black.is-inverted.is-outlined.is-loading:hover::after, .button.is-black.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-black.is-inverted.is-outlined.is-loading:focus::after, .button.is-black.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #0a0a0a #0a0a0a !important; } + .button.is-black.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-black.is-inverted.is-outlined { + background-color: transparent; + border-color: white; + box-shadow: none; + color: white; } + .button.is-light { + background-color: whitesmoke; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-light:hover, .button.is-light.is-hovered { + background-color: #eeeeee; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-light:focus, .button.is-light.is-focused { + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-light:focus:not(:active), .button.is-light.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); } + .button.is-light:active, .button.is-light.is-active { + background-color: #e8e8e8; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-light[disabled], + fieldset[disabled] .button.is-light { + background-color: whitesmoke; + border-color: transparent; + box-shadow: none; } + .button.is-light.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + color: whitesmoke; } + .button.is-light.is-inverted:hover, .button.is-light.is-inverted.is-hovered { + background-color: rgba(0, 0, 0, 0.7); } + .button.is-light.is-inverted[disabled], + fieldset[disabled] .button.is-light.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + border-color: transparent; + box-shadow: none; + color: whitesmoke; } + .button.is-light.is-loading::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; } + .button.is-light.is-outlined { + background-color: transparent; + border-color: whitesmoke; + color: whitesmoke; } + .button.is-light.is-outlined:hover, .button.is-light.is-outlined.is-hovered, .button.is-light.is-outlined:focus, .button.is-light.is-outlined.is-focused { + background-color: whitesmoke; + border-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .button.is-light.is-outlined.is-loading::after { + border-color: transparent transparent whitesmoke whitesmoke !important; } + .button.is-light.is-outlined.is-loading:hover::after, .button.is-light.is-outlined.is-loading.is-hovered::after, .button.is-light.is-outlined.is-loading:focus::after, .button.is-light.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; } + .button.is-light.is-outlined[disabled], + fieldset[disabled] .button.is-light.is-outlined { + background-color: transparent; + border-color: whitesmoke; + box-shadow: none; + color: whitesmoke; } + .button.is-light.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + color: rgba(0, 0, 0, 0.7); } + .button.is-light.is-inverted.is-outlined:hover, .button.is-light.is-inverted.is-outlined.is-hovered, .button.is-light.is-inverted.is-outlined:focus, .button.is-light.is-inverted.is-outlined.is-focused { + background-color: rgba(0, 0, 0, 0.7); + color: whitesmoke; } + .button.is-light.is-inverted.is-outlined.is-loading:hover::after, .button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-light.is-inverted.is-outlined.is-loading:focus::after, .button.is-light.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent whitesmoke whitesmoke !important; } + .button.is-light.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-light.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + box-shadow: none; + color: rgba(0, 0, 0, 0.7); } + .button.is-dark { + background-color: #363636; + border-color: transparent; + color: #fff; } + .button.is-dark:hover, .button.is-dark.is-hovered { + background-color: #2f2f2f; + border-color: transparent; + color: #fff; } + .button.is-dark:focus, .button.is-dark.is-focused { + border-color: transparent; + color: #fff; } + .button.is-dark:focus:not(:active), .button.is-dark.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); } + .button.is-dark:active, .button.is-dark.is-active { + background-color: #292929; + border-color: transparent; + color: #fff; } + .button.is-dark[disabled], + fieldset[disabled] .button.is-dark { + background-color: #363636; + border-color: transparent; + box-shadow: none; } + .button.is-dark.is-inverted { + background-color: #fff; + color: #363636; } + .button.is-dark.is-inverted:hover, .button.is-dark.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-dark.is-inverted[disabled], + fieldset[disabled] .button.is-dark.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #363636; } + .button.is-dark.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-dark.is-outlined { + background-color: transparent; + border-color: #363636; + color: #363636; } + .button.is-dark.is-outlined:hover, .button.is-dark.is-outlined.is-hovered, .button.is-dark.is-outlined:focus, .button.is-dark.is-outlined.is-focused { + background-color: #363636; + border-color: #363636; + color: #fff; } + .button.is-dark.is-outlined.is-loading::after { + border-color: transparent transparent #363636 #363636 !important; } + .button.is-dark.is-outlined.is-loading:hover::after, .button.is-dark.is-outlined.is-loading.is-hovered::after, .button.is-dark.is-outlined.is-loading:focus::after, .button.is-dark.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-dark.is-outlined[disabled], + fieldset[disabled] .button.is-dark.is-outlined { + background-color: transparent; + border-color: #363636; + box-shadow: none; + color: #363636; } + .button.is-dark.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-dark.is-inverted.is-outlined:hover, .button.is-dark.is-inverted.is-outlined.is-hovered, .button.is-dark.is-inverted.is-outlined:focus, .button.is-dark.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #363636; } + .button.is-dark.is-inverted.is-outlined.is-loading:hover::after, .button.is-dark.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-dark.is-inverted.is-outlined.is-loading:focus::after, .button.is-dark.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #363636 #363636 !important; } + .button.is-dark.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-dark.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-primary { + background-color: #00d1b2; + border-color: transparent; + color: #fff; } + .button.is-primary:hover, .button.is-primary.is-hovered { + background-color: #00c4a7; + border-color: transparent; + color: #fff; } + .button.is-primary:focus, .button.is-primary.is-focused { + border-color: transparent; + color: #fff; } + .button.is-primary:focus:not(:active), .button.is-primary.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); } + .button.is-primary:active, .button.is-primary.is-active { + background-color: #00b89c; + border-color: transparent; + color: #fff; } + .button.is-primary[disabled], + fieldset[disabled] .button.is-primary { + background-color: #00d1b2; + border-color: transparent; + box-shadow: none; } + .button.is-primary.is-inverted { + background-color: #fff; + color: #00d1b2; } + .button.is-primary.is-inverted:hover, .button.is-primary.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-primary.is-inverted[disabled], + fieldset[disabled] .button.is-primary.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #00d1b2; } + .button.is-primary.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-primary.is-outlined { + background-color: transparent; + border-color: #00d1b2; + color: #00d1b2; } + .button.is-primary.is-outlined:hover, .button.is-primary.is-outlined.is-hovered, .button.is-primary.is-outlined:focus, .button.is-primary.is-outlined.is-focused { + background-color: #00d1b2; + border-color: #00d1b2; + color: #fff; } + .button.is-primary.is-outlined.is-loading::after { + border-color: transparent transparent #00d1b2 #00d1b2 !important; } + .button.is-primary.is-outlined.is-loading:hover::after, .button.is-primary.is-outlined.is-loading.is-hovered::after, .button.is-primary.is-outlined.is-loading:focus::after, .button.is-primary.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-primary.is-outlined[disabled], + fieldset[disabled] .button.is-primary.is-outlined { + background-color: transparent; + border-color: #00d1b2; + box-shadow: none; + color: #00d1b2; } + .button.is-primary.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-primary.is-inverted.is-outlined:hover, .button.is-primary.is-inverted.is-outlined.is-hovered, .button.is-primary.is-inverted.is-outlined:focus, .button.is-primary.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #00d1b2; } + .button.is-primary.is-inverted.is-outlined.is-loading:hover::after, .button.is-primary.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-primary.is-inverted.is-outlined.is-loading:focus::after, .button.is-primary.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #00d1b2 #00d1b2 !important; } + .button.is-primary.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-primary.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-primary.is-light { + background-color: #ebfffc; + color: #00947e; } + .button.is-primary.is-light:hover, .button.is-primary.is-light.is-hovered { + background-color: #defffa; + border-color: transparent; + color: #00947e; } + .button.is-primary.is-light:active, .button.is-primary.is-light.is-active { + background-color: #d1fff8; + border-color: transparent; + color: #00947e; } + .button.is-link { + background-color: #3273dc; + border-color: transparent; + color: #fff; } + .button.is-link:hover, .button.is-link.is-hovered { + background-color: #276cda; + border-color: transparent; + color: #fff; } + .button.is-link:focus, .button.is-link.is-focused { + border-color: transparent; + color: #fff; } + .button.is-link:focus:not(:active), .button.is-link.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .button.is-link:active, .button.is-link.is-active { + background-color: #2366d1; + border-color: transparent; + color: #fff; } + .button.is-link[disabled], + fieldset[disabled] .button.is-link { + background-color: #3273dc; + border-color: transparent; + box-shadow: none; } + .button.is-link.is-inverted { + background-color: #fff; + color: #3273dc; } + .button.is-link.is-inverted:hover, .button.is-link.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-link.is-inverted[disabled], + fieldset[disabled] .button.is-link.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #3273dc; } + .button.is-link.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-link.is-outlined { + background-color: transparent; + border-color: #3273dc; + color: #3273dc; } + .button.is-link.is-outlined:hover, .button.is-link.is-outlined.is-hovered, .button.is-link.is-outlined:focus, .button.is-link.is-outlined.is-focused { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; } + .button.is-link.is-outlined.is-loading::after { + border-color: transparent transparent #3273dc #3273dc !important; } + .button.is-link.is-outlined.is-loading:hover::after, .button.is-link.is-outlined.is-loading.is-hovered::after, .button.is-link.is-outlined.is-loading:focus::after, .button.is-link.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-link.is-outlined[disabled], + fieldset[disabled] .button.is-link.is-outlined { + background-color: transparent; + border-color: #3273dc; + box-shadow: none; + color: #3273dc; } + .button.is-link.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-link.is-inverted.is-outlined:hover, .button.is-link.is-inverted.is-outlined.is-hovered, .button.is-link.is-inverted.is-outlined:focus, .button.is-link.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #3273dc; } + .button.is-link.is-inverted.is-outlined.is-loading:hover::after, .button.is-link.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-link.is-inverted.is-outlined.is-loading:focus::after, .button.is-link.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #3273dc #3273dc !important; } + .button.is-link.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-link.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-link.is-light { + background-color: #eef3fc; + color: #2160c4; } + .button.is-link.is-light:hover, .button.is-link.is-light.is-hovered { + background-color: #e3ecfa; + border-color: transparent; + color: #2160c4; } + .button.is-link.is-light:active, .button.is-link.is-light.is-active { + background-color: #d8e4f8; + border-color: transparent; + color: #2160c4; } + .button.is-info { + background-color: #3298dc; + border-color: transparent; + color: #fff; } + .button.is-info:hover, .button.is-info.is-hovered { + background-color: #2793da; + border-color: transparent; + color: #fff; } + .button.is-info:focus, .button.is-info.is-focused { + border-color: transparent; + color: #fff; } + .button.is-info:focus:not(:active), .button.is-info.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(50, 152, 220, 0.25); } + .button.is-info:active, .button.is-info.is-active { + background-color: #238cd1; + border-color: transparent; + color: #fff; } + .button.is-info[disabled], + fieldset[disabled] .button.is-info { + background-color: #3298dc; + border-color: transparent; + box-shadow: none; } + .button.is-info.is-inverted { + background-color: #fff; + color: #3298dc; } + .button.is-info.is-inverted:hover, .button.is-info.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-info.is-inverted[disabled], + fieldset[disabled] .button.is-info.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #3298dc; } + .button.is-info.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-info.is-outlined { + background-color: transparent; + border-color: #3298dc; + color: #3298dc; } + .button.is-info.is-outlined:hover, .button.is-info.is-outlined.is-hovered, .button.is-info.is-outlined:focus, .button.is-info.is-outlined.is-focused { + background-color: #3298dc; + border-color: #3298dc; + color: #fff; } + .button.is-info.is-outlined.is-loading::after { + border-color: transparent transparent #3298dc #3298dc !important; } + .button.is-info.is-outlined.is-loading:hover::after, .button.is-info.is-outlined.is-loading.is-hovered::after, .button.is-info.is-outlined.is-loading:focus::after, .button.is-info.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-info.is-outlined[disabled], + fieldset[disabled] .button.is-info.is-outlined { + background-color: transparent; + border-color: #3298dc; + box-shadow: none; + color: #3298dc; } + .button.is-info.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-info.is-inverted.is-outlined:hover, .button.is-info.is-inverted.is-outlined.is-hovered, .button.is-info.is-inverted.is-outlined:focus, .button.is-info.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #3298dc; } + .button.is-info.is-inverted.is-outlined.is-loading:hover::after, .button.is-info.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-info.is-inverted.is-outlined.is-loading:focus::after, .button.is-info.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #3298dc #3298dc !important; } + .button.is-info.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-info.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-info.is-light { + background-color: #eef6fc; + color: #1d72aa; } + .button.is-info.is-light:hover, .button.is-info.is-light.is-hovered { + background-color: #e3f1fa; + border-color: transparent; + color: #1d72aa; } + .button.is-info.is-light:active, .button.is-info.is-light.is-active { + background-color: #d8ebf8; + border-color: transparent; + color: #1d72aa; } + .button.is-success { + background-color: #48c774; + border-color: transparent; + color: #fff; } + .button.is-success:hover, .button.is-success.is-hovered { + background-color: #3ec46d; + border-color: transparent; + color: #fff; } + .button.is-success:focus, .button.is-success.is-focused { + border-color: transparent; + color: #fff; } + .button.is-success:focus:not(:active), .button.is-success.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(72, 199, 116, 0.25); } + .button.is-success:active, .button.is-success.is-active { + background-color: #3abb67; + border-color: transparent; + color: #fff; } + .button.is-success[disabled], + fieldset[disabled] .button.is-success { + background-color: #48c774; + border-color: transparent; + box-shadow: none; } + .button.is-success.is-inverted { + background-color: #fff; + color: #48c774; } + .button.is-success.is-inverted:hover, .button.is-success.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-success.is-inverted[disabled], + fieldset[disabled] .button.is-success.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #48c774; } + .button.is-success.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-success.is-outlined { + background-color: transparent; + border-color: #48c774; + color: #48c774; } + .button.is-success.is-outlined:hover, .button.is-success.is-outlined.is-hovered, .button.is-success.is-outlined:focus, .button.is-success.is-outlined.is-focused { + background-color: #48c774; + border-color: #48c774; + color: #fff; } + .button.is-success.is-outlined.is-loading::after { + border-color: transparent transparent #48c774 #48c774 !important; } + .button.is-success.is-outlined.is-loading:hover::after, .button.is-success.is-outlined.is-loading.is-hovered::after, .button.is-success.is-outlined.is-loading:focus::after, .button.is-success.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-success.is-outlined[disabled], + fieldset[disabled] .button.is-success.is-outlined { + background-color: transparent; + border-color: #48c774; + box-shadow: none; + color: #48c774; } + .button.is-success.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-success.is-inverted.is-outlined:hover, .button.is-success.is-inverted.is-outlined.is-hovered, .button.is-success.is-inverted.is-outlined:focus, .button.is-success.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #48c774; } + .button.is-success.is-inverted.is-outlined.is-loading:hover::after, .button.is-success.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-success.is-inverted.is-outlined.is-loading:focus::after, .button.is-success.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #48c774 #48c774 !important; } + .button.is-success.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-success.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-success.is-light { + background-color: #effaf3; + color: #257942; } + .button.is-success.is-light:hover, .button.is-success.is-light.is-hovered { + background-color: #e6f7ec; + border-color: transparent; + color: #257942; } + .button.is-success.is-light:active, .button.is-success.is-light.is-active { + background-color: #dcf4e4; + border-color: transparent; + color: #257942; } + .button.is-warning { + background-color: #ffdd57; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning:hover, .button.is-warning.is-hovered { + background-color: #ffdb4a; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning:focus, .button.is-warning.is-focused { + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning:focus:not(:active), .button.is-warning.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(255, 221, 87, 0.25); } + .button.is-warning:active, .button.is-warning.is-active { + background-color: #ffd83d; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning[disabled], + fieldset[disabled] .button.is-warning { + background-color: #ffdd57; + border-color: transparent; + box-shadow: none; } + .button.is-warning.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + color: #ffdd57; } + .button.is-warning.is-inverted:hover, .button.is-warning.is-inverted.is-hovered { + background-color: rgba(0, 0, 0, 0.7); } + .button.is-warning.is-inverted[disabled], + fieldset[disabled] .button.is-warning.is-inverted { + background-color: rgba(0, 0, 0, 0.7); + border-color: transparent; + box-shadow: none; + color: #ffdd57; } + .button.is-warning.is-loading::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; } + .button.is-warning.is-outlined { + background-color: transparent; + border-color: #ffdd57; + color: #ffdd57; } + .button.is-warning.is-outlined:hover, .button.is-warning.is-outlined.is-hovered, .button.is-warning.is-outlined:focus, .button.is-warning.is-outlined.is-focused { + background-color: #ffdd57; + border-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning.is-outlined.is-loading::after { + border-color: transparent transparent #ffdd57 #ffdd57 !important; } + .button.is-warning.is-outlined.is-loading:hover::after, .button.is-warning.is-outlined.is-loading.is-hovered::after, .button.is-warning.is-outlined.is-loading:focus::after, .button.is-warning.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent rgba(0, 0, 0, 0.7) rgba(0, 0, 0, 0.7) !important; } + .button.is-warning.is-outlined[disabled], + fieldset[disabled] .button.is-warning.is-outlined { + background-color: transparent; + border-color: #ffdd57; + box-shadow: none; + color: #ffdd57; } + .button.is-warning.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + color: rgba(0, 0, 0, 0.7); } + .button.is-warning.is-inverted.is-outlined:hover, .button.is-warning.is-inverted.is-outlined.is-hovered, .button.is-warning.is-inverted.is-outlined:focus, .button.is-warning.is-inverted.is-outlined.is-focused { + background-color: rgba(0, 0, 0, 0.7); + color: #ffdd57; } + .button.is-warning.is-inverted.is-outlined.is-loading:hover::after, .button.is-warning.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-warning.is-inverted.is-outlined.is-loading:focus::after, .button.is-warning.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #ffdd57 #ffdd57 !important; } + .button.is-warning.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-warning.is-inverted.is-outlined { + background-color: transparent; + border-color: rgba(0, 0, 0, 0.7); + box-shadow: none; + color: rgba(0, 0, 0, 0.7); } + .button.is-warning.is-light { + background-color: #fffbeb; + color: #947600; } + .button.is-warning.is-light:hover, .button.is-warning.is-light.is-hovered { + background-color: #fff8de; + border-color: transparent; + color: #947600; } + .button.is-warning.is-light:active, .button.is-warning.is-light.is-active { + background-color: #fff6d1; + border-color: transparent; + color: #947600; } + .button.is-danger { + background-color: #f14668; + border-color: transparent; + color: #fff; } + .button.is-danger:hover, .button.is-danger.is-hovered { + background-color: #f03a5f; + border-color: transparent; + color: #fff; } + .button.is-danger:focus, .button.is-danger.is-focused { + border-color: transparent; + color: #fff; } + .button.is-danger:focus:not(:active), .button.is-danger.is-focused:not(:active) { + box-shadow: 0 0 0 0.125em rgba(241, 70, 104, 0.25); } + .button.is-danger:active, .button.is-danger.is-active { + background-color: #ef2e55; + border-color: transparent; + color: #fff; } + .button.is-danger[disabled], + fieldset[disabled] .button.is-danger { + background-color: #f14668; + border-color: transparent; + box-shadow: none; } + .button.is-danger.is-inverted { + background-color: #fff; + color: #f14668; } + .button.is-danger.is-inverted:hover, .button.is-danger.is-inverted.is-hovered { + background-color: #f2f2f2; } + .button.is-danger.is-inverted[disabled], + fieldset[disabled] .button.is-danger.is-inverted { + background-color: #fff; + border-color: transparent; + box-shadow: none; + color: #f14668; } + .button.is-danger.is-loading::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-danger.is-outlined { + background-color: transparent; + border-color: #f14668; + color: #f14668; } + .button.is-danger.is-outlined:hover, .button.is-danger.is-outlined.is-hovered, .button.is-danger.is-outlined:focus, .button.is-danger.is-outlined.is-focused { + background-color: #f14668; + border-color: #f14668; + color: #fff; } + .button.is-danger.is-outlined.is-loading::after { + border-color: transparent transparent #f14668 #f14668 !important; } + .button.is-danger.is-outlined.is-loading:hover::after, .button.is-danger.is-outlined.is-loading.is-hovered::after, .button.is-danger.is-outlined.is-loading:focus::after, .button.is-danger.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #fff #fff !important; } + .button.is-danger.is-outlined[disabled], + fieldset[disabled] .button.is-danger.is-outlined { + background-color: transparent; + border-color: #f14668; + box-shadow: none; + color: #f14668; } + .button.is-danger.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + color: #fff; } + .button.is-danger.is-inverted.is-outlined:hover, .button.is-danger.is-inverted.is-outlined.is-hovered, .button.is-danger.is-inverted.is-outlined:focus, .button.is-danger.is-inverted.is-outlined.is-focused { + background-color: #fff; + color: #f14668; } + .button.is-danger.is-inverted.is-outlined.is-loading:hover::after, .button.is-danger.is-inverted.is-outlined.is-loading.is-hovered::after, .button.is-danger.is-inverted.is-outlined.is-loading:focus::after, .button.is-danger.is-inverted.is-outlined.is-loading.is-focused::after { + border-color: transparent transparent #f14668 #f14668 !important; } + .button.is-danger.is-inverted.is-outlined[disabled], + fieldset[disabled] .button.is-danger.is-inverted.is-outlined { + background-color: transparent; + border-color: #fff; + box-shadow: none; + color: #fff; } + .button.is-danger.is-light { + background-color: #feecf0; + color: #cc0f35; } + .button.is-danger.is-light:hover, .button.is-danger.is-light.is-hovered { + background-color: #fde0e6; + border-color: transparent; + color: #cc0f35; } + .button.is-danger.is-light:active, .button.is-danger.is-light.is-active { + background-color: #fcd4dc; + border-color: transparent; + color: #cc0f35; } + .button.is-small { + font-size: 0.75rem; } + .button.is-small:not(.is-rounded) { + border-radius: 2px; } + .button.is-normal { + font-size: 1rem; } + .button.is-medium { + font-size: 1.25rem; } + .button.is-large { + font-size: 1.5rem; } + .button[disabled], + fieldset[disabled] .button { + background-color: white; + border-color: #dbdbdb; + box-shadow: none; + opacity: 0.5; } + .button.is-fullwidth { + display: flex; + width: 100%; } + .button.is-loading { + color: transparent !important; + pointer-events: none; } + .button.is-loading::after { + position: absolute; + left: calc(50% - (1em / 2)); + top: calc(50% - (1em / 2)); + position: absolute !important; } + .button.is-static { + background-color: whitesmoke; + border-color: #dbdbdb; + color: #7a7a7a; + box-shadow: none; + pointer-events: none; } + .button.is-rounded { + border-radius: 290486px; + padding-left: calc(1em + 0.25em); + padding-right: calc(1em + 0.25em); } + +.buttons { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; } + .buttons .button { + margin-bottom: 0.5rem; } + .buttons .button:not(:last-child):not(.is-fullwidth) { + margin-right: 0.5rem; } + .buttons:last-child { + margin-bottom: -0.5rem; } + .buttons:not(:last-child) { + margin-bottom: 1rem; } + .buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large) { + font-size: 0.75rem; } + .buttons.are-small .button:not(.is-normal):not(.is-medium):not(.is-large):not(.is-rounded) { + border-radius: 2px; } + .buttons.are-medium .button:not(.is-small):not(.is-normal):not(.is-large) { + font-size: 1.25rem; } + .buttons.are-large .button:not(.is-small):not(.is-normal):not(.is-medium) { + font-size: 1.5rem; } + .buttons.has-addons .button:not(:first-child) { + border-bottom-left-radius: 0; + border-top-left-radius: 0; } + .buttons.has-addons .button:not(:last-child) { + border-bottom-right-radius: 0; + border-top-right-radius: 0; + margin-right: -1px; } + .buttons.has-addons .button:last-child { + margin-right: 0; } + .buttons.has-addons .button:hover, .buttons.has-addons .button.is-hovered { + z-index: 2; } + .buttons.has-addons .button:focus, .buttons.has-addons .button.is-focused, .buttons.has-addons .button:active, .buttons.has-addons .button.is-active, .buttons.has-addons .button.is-selected { + z-index: 3; } + .buttons.has-addons .button:focus:hover, .buttons.has-addons .button.is-focused:hover, .buttons.has-addons .button:active:hover, .buttons.has-addons .button.is-active:hover, .buttons.has-addons .button.is-selected:hover { + z-index: 4; } + .buttons.has-addons .button.is-expanded { + flex-grow: 1; + flex-shrink: 1; } + .buttons.is-centered { + justify-content: center; } + .buttons.is-centered:not(.has-addons) .button:not(.is-fullwidth) { + margin-left: 0.25rem; + margin-right: 0.25rem; } + .buttons.is-right { + justify-content: flex-end; } + .buttons.is-right:not(.has-addons) .button:not(.is-fullwidth) { + margin-left: 0.25rem; + margin-right: 0.25rem; } + +.container { + flex-grow: 1; + margin: 0 auto; + position: relative; + width: auto; } + .container.is-fluid { + max-width: none !important; + padding-left: 32px; + padding-right: 32px; + width: 100%; } + @media screen and (min-width: 1024px) { + .container { + max-width: 960px; } } + @media screen and (max-width: 1215px) { + .container.is-widescreen:not(.is-max-desktop) { + max-width: 1152px; } } + @media screen and (max-width: 1407px) { + .container.is-fullhd:not(.is-max-desktop):not(.is-max-widescreen) { + max-width: 1344px; } } + @media screen and (min-width: 1216px) { + .container:not(.is-max-desktop) { + max-width: 1152px; } } + @media screen and (min-width: 1408px) { + .container:not(.is-max-desktop):not(.is-max-widescreen) { + max-width: 1344px; } } + +.content li + li { + margin-top: 0.25em; } + +.content p:not(:last-child), +.content dl:not(:last-child), +.content ol:not(:last-child), +.content ul:not(:last-child), +.content blockquote:not(:last-child), +.content pre:not(:last-child), +.content table:not(:last-child) { + margin-bottom: 1em; } + +.content h1, +.content h2, +.content h3, +.content h4, +.content h5, +.content h6 { + color: #363636; + font-weight: 600; + line-height: 1.125; } + +.content h1 { + font-size: 2em; + margin-bottom: 0.5em; } + .content h1:not(:first-child) { + margin-top: 1em; } + +.content h2 { + font-size: 1.75em; + margin-bottom: 0.5714em; } + .content h2:not(:first-child) { + margin-top: 1.1428em; } + +.content h3 { + font-size: 1.5em; + margin-bottom: 0.6666em; } + .content h3:not(:first-child) { + margin-top: 1.3333em; } + +.content h4 { + font-size: 1.25em; + margin-bottom: 0.8em; } + +.content h5 { + font-size: 1.125em; + margin-bottom: 0.8888em; } + +.content h6 { + font-size: 1em; + margin-bottom: 1em; } + +.content blockquote { + background-color: whitesmoke; + border-left: 5px solid #dbdbdb; + padding: 1.25em 1.5em; } + +.content ol { + list-style-position: outside; + margin-left: 2em; + margin-top: 1em; } + .content ol:not([type]) { + list-style-type: decimal; } + .content ol:not([type]).is-lower-alpha { + list-style-type: lower-alpha; } + .content ol:not([type]).is-lower-roman { + list-style-type: lower-roman; } + .content ol:not([type]).is-upper-alpha { + list-style-type: upper-alpha; } + .content ol:not([type]).is-upper-roman { + list-style-type: upper-roman; } + +.content ul { + list-style: disc outside; + margin-left: 2em; + margin-top: 1em; } + .content ul ul { + list-style-type: circle; + margin-top: 0.5em; } + .content ul ul ul { + list-style-type: square; } + +.content dd { + margin-left: 2em; } + +.content figure { + margin-left: 2em; + margin-right: 2em; + text-align: center; } + .content figure:not(:first-child) { + margin-top: 2em; } + .content figure:not(:last-child) { + margin-bottom: 2em; } + .content figure img { + display: inline-block; } + .content figure figcaption { + font-style: italic; } + +.content pre { + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding: 1.25em 1.5em; + white-space: pre; + word-wrap: normal; } + +.content sup, +.content sub { + font-size: 75%; } + +.content table { + width: 100%; } + .content table td, + .content table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; } + .content table th { + color: #363636; } + .content table th:not([align]) { + text-align: inherit; } + .content table thead td, + .content table thead th { + border-width: 0 0 2px; + color: #363636; } + .content table tfoot td, + .content table tfoot th { + border-width: 2px 0 0; + color: #363636; } + .content table tbody tr:last-child td, + .content table tbody tr:last-child th { + border-bottom-width: 0; } + +.content .tabs li + li { + margin-top: 0; } + +.content.is-small { + font-size: 0.75rem; } + +.content.is-medium { + font-size: 1.25rem; } + +.content.is-large { + font-size: 1.5rem; } + +.icon { + align-items: center; + display: inline-flex; + justify-content: center; + height: 1.5rem; + width: 1.5rem; } + .icon.is-small { + height: 1rem; + width: 1rem; } + .icon.is-medium { + height: 2rem; + width: 2rem; } + .icon.is-large { + height: 3rem; + width: 3rem; } + +.icon-text { + align-items: flex-start; + color: inherit; + display: inline-flex; + flex-wrap: wrap; + line-height: 1.5rem; + vertical-align: top; } + .icon-text .icon { + flex-grow: 0; + flex-shrink: 0; } + .icon-text .icon:not(:last-child) { + margin-right: 0.25em; } + .icon-text .icon:not(:first-child) { + margin-left: 0.25em; } + +div.icon-text { + display: flex; } + +.image { + display: block; + position: relative; } + .image img { + display: block; + height: auto; + width: 100%; } + .image img.is-rounded { + border-radius: 290486px; } + .image.is-fullwidth { + width: 100%; } + .image.is-square img, + .image.is-square .has-ratio, .image.is-1by1 img, + .image.is-1by1 .has-ratio, .image.is-5by4 img, + .image.is-5by4 .has-ratio, .image.is-4by3 img, + .image.is-4by3 .has-ratio, .image.is-3by2 img, + .image.is-3by2 .has-ratio, .image.is-5by3 img, + .image.is-5by3 .has-ratio, .image.is-16by9 img, + .image.is-16by9 .has-ratio, .image.is-2by1 img, + .image.is-2by1 .has-ratio, .image.is-3by1 img, + .image.is-3by1 .has-ratio, .image.is-4by5 img, + .image.is-4by5 .has-ratio, .image.is-3by4 img, + .image.is-3by4 .has-ratio, .image.is-2by3 img, + .image.is-2by3 .has-ratio, .image.is-3by5 img, + .image.is-3by5 .has-ratio, .image.is-9by16 img, + .image.is-9by16 .has-ratio, .image.is-1by2 img, + .image.is-1by2 .has-ratio, .image.is-1by3 img, + .image.is-1by3 .has-ratio { + height: 100%; + width: 100%; } + .image.is-square, .image.is-1by1 { + padding-top: 100%; } + .image.is-5by4 { + padding-top: 80%; } + .image.is-4by3 { + padding-top: 75%; } + .image.is-3by2 { + padding-top: 66.6666%; } + .image.is-5by3 { + padding-top: 60%; } + .image.is-16by9 { + padding-top: 56.25%; } + .image.is-2by1 { + padding-top: 50%; } + .image.is-3by1 { + padding-top: 33.3333%; } + .image.is-4by5 { + padding-top: 125%; } + .image.is-3by4 { + padding-top: 133.3333%; } + .image.is-2by3 { + padding-top: 150%; } + .image.is-3by5 { + padding-top: 166.6666%; } + .image.is-9by16 { + padding-top: 177.7777%; } + .image.is-1by2 { + padding-top: 200%; } + .image.is-1by3 { + padding-top: 300%; } + .image.is-16x16 { + height: 16px; + width: 16px; } + .image.is-24x24 { + height: 24px; + width: 24px; } + .image.is-32x32 { + height: 32px; + width: 32px; } + .image.is-48x48 { + height: 48px; + width: 48px; } + .image.is-64x64 { + height: 64px; + width: 64px; } + .image.is-96x96 { + height: 96px; + width: 96px; } + .image.is-128x128 { + height: 128px; + width: 128px; } + +.notification { + background-color: whitesmoke; + border-radius: 4px; + position: relative; + padding: 1.25rem 2.5rem 1.25rem 1.5rem; } + .notification a:not(.button):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; } + .notification strong { + color: currentColor; } + .notification code, + .notification pre { + background: white; } + .notification pre code { + background: transparent; } + .notification > .delete { + right: 0.5rem; + position: absolute; + top: 0.5rem; } + .notification .title, + .notification .subtitle, + .notification .content { + color: currentColor; } + .notification.is-white { + background-color: white; + color: #0a0a0a; } + .notification.is-black { + background-color: #0a0a0a; + color: white; } + .notification.is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .notification.is-dark { + background-color: #363636; + color: #fff; } + .notification.is-primary { + background-color: #00d1b2; + color: #fff; } + .notification.is-primary.is-light { + background-color: #ebfffc; + color: #00947e; } + .notification.is-link { + background-color: #3273dc; + color: #fff; } + .notification.is-link.is-light { + background-color: #eef3fc; + color: #2160c4; } + .notification.is-info { + background-color: #3298dc; + color: #fff; } + .notification.is-info.is-light { + background-color: #eef6fc; + color: #1d72aa; } + .notification.is-success { + background-color: #48c774; + color: #fff; } + .notification.is-success.is-light { + background-color: #effaf3; + color: #257942; } + .notification.is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .notification.is-warning.is-light { + background-color: #fffbeb; + color: #947600; } + .notification.is-danger { + background-color: #f14668; + color: #fff; } + .notification.is-danger.is-light { + background-color: #feecf0; + color: #cc0f35; } + +.progress { + -moz-appearance: none; + -webkit-appearance: none; + border: none; + border-radius: 290486px; + display: block; + height: 1rem; + overflow: hidden; + padding: 0; + width: 100%; } + .progress::-webkit-progress-bar { + background-color: #ededed; } + .progress::-webkit-progress-value { + background-color: #4a4a4a; } + .progress::-moz-progress-bar { + background-color: #4a4a4a; } + .progress::-ms-fill { + background-color: #4a4a4a; + border: none; } + .progress.is-white::-webkit-progress-value { + background-color: white; } + .progress.is-white::-moz-progress-bar { + background-color: white; } + .progress.is-white::-ms-fill { + background-color: white; } + .progress.is-white:indeterminate { + background-image: linear-gradient(to right, white 30%, #ededed 30%); } + .progress.is-black::-webkit-progress-value { + background-color: #0a0a0a; } + .progress.is-black::-moz-progress-bar { + background-color: #0a0a0a; } + .progress.is-black::-ms-fill { + background-color: #0a0a0a; } + .progress.is-black:indeterminate { + background-image: linear-gradient(to right, #0a0a0a 30%, #ededed 30%); } + .progress.is-light::-webkit-progress-value { + background-color: whitesmoke; } + .progress.is-light::-moz-progress-bar { + background-color: whitesmoke; } + .progress.is-light::-ms-fill { + background-color: whitesmoke; } + .progress.is-light:indeterminate { + background-image: linear-gradient(to right, whitesmoke 30%, #ededed 30%); } + .progress.is-dark::-webkit-progress-value { + background-color: #363636; } + .progress.is-dark::-moz-progress-bar { + background-color: #363636; } + .progress.is-dark::-ms-fill { + background-color: #363636; } + .progress.is-dark:indeterminate { + background-image: linear-gradient(to right, #363636 30%, #ededed 30%); } + .progress.is-primary::-webkit-progress-value { + background-color: #00d1b2; } + .progress.is-primary::-moz-progress-bar { + background-color: #00d1b2; } + .progress.is-primary::-ms-fill { + background-color: #00d1b2; } + .progress.is-primary:indeterminate { + background-image: linear-gradient(to right, #00d1b2 30%, #ededed 30%); } + .progress.is-link::-webkit-progress-value { + background-color: #3273dc; } + .progress.is-link::-moz-progress-bar { + background-color: #3273dc; } + .progress.is-link::-ms-fill { + background-color: #3273dc; } + .progress.is-link:indeterminate { + background-image: linear-gradient(to right, #3273dc 30%, #ededed 30%); } + .progress.is-info::-webkit-progress-value { + background-color: #3298dc; } + .progress.is-info::-moz-progress-bar { + background-color: #3298dc; } + .progress.is-info::-ms-fill { + background-color: #3298dc; } + .progress.is-info:indeterminate { + background-image: linear-gradient(to right, #3298dc 30%, #ededed 30%); } + .progress.is-success::-webkit-progress-value { + background-color: #48c774; } + .progress.is-success::-moz-progress-bar { + background-color: #48c774; } + .progress.is-success::-ms-fill { + background-color: #48c774; } + .progress.is-success:indeterminate { + background-image: linear-gradient(to right, #48c774 30%, #ededed 30%); } + .progress.is-warning::-webkit-progress-value { + background-color: #ffdd57; } + .progress.is-warning::-moz-progress-bar { + background-color: #ffdd57; } + .progress.is-warning::-ms-fill { + background-color: #ffdd57; } + .progress.is-warning:indeterminate { + background-image: linear-gradient(to right, #ffdd57 30%, #ededed 30%); } + .progress.is-danger::-webkit-progress-value { + background-color: #f14668; } + .progress.is-danger::-moz-progress-bar { + background-color: #f14668; } + .progress.is-danger::-ms-fill { + background-color: #f14668; } + .progress.is-danger:indeterminate { + background-image: linear-gradient(to right, #f14668 30%, #ededed 30%); } + .progress:indeterminate { + animation-duration: 1.5s; + animation-iteration-count: infinite; + animation-name: moveIndeterminate; + animation-timing-function: linear; + background-color: #ededed; + background-image: linear-gradient(to right, #4a4a4a 30%, #ededed 30%); + background-position: top left; + background-repeat: no-repeat; + background-size: 150% 150%; } + .progress:indeterminate::-webkit-progress-bar { + background-color: transparent; } + .progress:indeterminate::-moz-progress-bar { + background-color: transparent; } + .progress:indeterminate::-ms-fill { + animation-name: none; } + .progress.is-small { + height: 0.75rem; } + .progress.is-medium { + height: 1.25rem; } + .progress.is-large { + height: 1.5rem; } + +@keyframes moveIndeterminate { + from { + background-position: 200% 0; } + to { + background-position: -200% 0; } } + +.table { + background-color: white; + color: #363636; } + .table td, + .table th { + border: 1px solid #dbdbdb; + border-width: 0 0 1px; + padding: 0.5em 0.75em; + vertical-align: top; } + .table td.is-white, + .table th.is-white { + background-color: white; + border-color: white; + color: #0a0a0a; } + .table td.is-black, + .table th.is-black { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; } + .table td.is-light, + .table th.is-light { + background-color: whitesmoke; + border-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .table td.is-dark, + .table th.is-dark { + background-color: #363636; + border-color: #363636; + color: #fff; } + .table td.is-primary, + .table th.is-primary { + background-color: #00d1b2; + border-color: #00d1b2; + color: #fff; } + .table td.is-link, + .table th.is-link { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; } + .table td.is-info, + .table th.is-info { + background-color: #3298dc; + border-color: #3298dc; + color: #fff; } + .table td.is-success, + .table th.is-success { + background-color: #48c774; + border-color: #48c774; + color: #fff; } + .table td.is-warning, + .table th.is-warning { + background-color: #ffdd57; + border-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .table td.is-danger, + .table th.is-danger { + background-color: #f14668; + border-color: #f14668; + color: #fff; } + .table td.is-narrow, + .table th.is-narrow { + white-space: nowrap; + width: 1%; } + .table td.is-selected, + .table th.is-selected { + background-color: #00d1b2; + color: #fff; } + .table td.is-selected a, + .table td.is-selected strong, + .table th.is-selected a, + .table th.is-selected strong { + color: currentColor; } + .table td.is-vcentered, + .table th.is-vcentered { + vertical-align: middle; } + .table th { + color: #363636; } + .table th:not([align]) { + text-align: inherit; } + .table tr.is-selected { + background-color: #00d1b2; + color: #fff; } + .table tr.is-selected a, + .table tr.is-selected strong { + color: currentColor; } + .table tr.is-selected td, + .table tr.is-selected th { + border-color: #fff; + color: currentColor; } + .table thead { + background-color: transparent; } + .table thead td, + .table thead th { + border-width: 0 0 2px; + color: #363636; } + .table tfoot { + background-color: transparent; } + .table tfoot td, + .table tfoot th { + border-width: 2px 0 0; + color: #363636; } + .table tbody { + background-color: transparent; } + .table tbody tr:last-child td, + .table tbody tr:last-child th { + border-bottom-width: 0; } + .table.is-bordered td, + .table.is-bordered th { + border-width: 1px; } + .table.is-bordered tr:last-child td, + .table.is-bordered tr:last-child th { + border-bottom-width: 1px; } + .table.is-fullwidth { + width: 100%; } + .table.is-hoverable tbody tr:not(.is-selected):hover { + background-color: #fafafa; } + .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover { + background-color: #fafafa; } + .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even) { + background-color: whitesmoke; } + .table.is-narrow td, + .table.is-narrow th { + padding: 0.25em 0.5em; } + .table.is-striped tbody tr:not(.is-selected):nth-child(even) { + background-color: #fafafa; } + +.table-container { + -webkit-overflow-scrolling: touch; + overflow: auto; + overflow-y: hidden; + max-width: 100%; } + +.tags { + align-items: center; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; } + .tags .tag { + margin-bottom: 0.5rem; } + .tags .tag:not(:last-child) { + margin-right: 0.5rem; } + .tags:last-child { + margin-bottom: -0.5rem; } + .tags:not(:last-child) { + margin-bottom: 1rem; } + .tags.are-medium .tag:not(.is-normal):not(.is-large) { + font-size: 1rem; } + .tags.are-large .tag:not(.is-normal):not(.is-medium) { + font-size: 1.25rem; } + .tags.is-centered { + justify-content: center; } + .tags.is-centered .tag { + margin-right: 0.25rem; + margin-left: 0.25rem; } + .tags.is-right { + justify-content: flex-end; } + .tags.is-right .tag:not(:first-child) { + margin-left: 0.5rem; } + .tags.is-right .tag:not(:last-child) { + margin-right: 0; } + .tags.has-addons .tag { + margin-right: 0; } + .tags.has-addons .tag:not(:first-child) { + margin-left: 0; + border-top-left-radius: 0; + border-bottom-left-radius: 0; } + .tags.has-addons .tag:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; } + +.tag:not(body) { + align-items: center; + background-color: whitesmoke; + border-radius: 4px; + color: #4a4a4a; + display: inline-flex; + font-size: 0.75rem; + height: 2em; + justify-content: center; + line-height: 1.5; + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; } + .tag:not(body) .delete { + margin-left: 0.25rem; + margin-right: -0.375rem; } + .tag:not(body).is-white { + background-color: white; + color: #0a0a0a; } + .tag:not(body).is-black { + background-color: #0a0a0a; + color: white; } + .tag:not(body).is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .tag:not(body).is-dark { + background-color: #363636; + color: #fff; } + .tag:not(body).is-primary { + background-color: #00d1b2; + color: #fff; } + .tag:not(body).is-primary.is-light { + background-color: #ebfffc; + color: #00947e; } + .tag:not(body).is-link { + background-color: #3273dc; + color: #fff; } + .tag:not(body).is-link.is-light { + background-color: #eef3fc; + color: #2160c4; } + .tag:not(body).is-info { + background-color: #3298dc; + color: #fff; } + .tag:not(body).is-info.is-light { + background-color: #eef6fc; + color: #1d72aa; } + .tag:not(body).is-success { + background-color: #48c774; + color: #fff; } + .tag:not(body).is-success.is-light { + background-color: #effaf3; + color: #257942; } + .tag:not(body).is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .tag:not(body).is-warning.is-light { + background-color: #fffbeb; + color: #947600; } + .tag:not(body).is-danger { + background-color: #f14668; + color: #fff; } + .tag:not(body).is-danger.is-light { + background-color: #feecf0; + color: #cc0f35; } + .tag:not(body).is-normal { + font-size: 0.75rem; } + .tag:not(body).is-medium { + font-size: 1rem; } + .tag:not(body).is-large { + font-size: 1.25rem; } + .tag:not(body) .icon:first-child:not(:last-child) { + margin-left: -0.375em; + margin-right: 0.1875em; } + .tag:not(body) .icon:last-child:not(:first-child) { + margin-left: 0.1875em; + margin-right: -0.375em; } + .tag:not(body) .icon:first-child:last-child { + margin-left: -0.375em; + margin-right: -0.375em; } + .tag:not(body).is-delete { + margin-left: 1px; + padding: 0; + position: relative; + width: 2em; } + .tag:not(body).is-delete::before, .tag:not(body).is-delete::after { + background-color: currentColor; + content: ""; + display: block; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%) rotate(45deg); + transform-origin: center center; } + .tag:not(body).is-delete::before { + height: 1px; + width: 50%; } + .tag:not(body).is-delete::after { + height: 50%; + width: 1px; } + .tag:not(body).is-delete:hover, .tag:not(body).is-delete:focus { + background-color: #e8e8e8; } + .tag:not(body).is-delete:active { + background-color: #dbdbdb; } + .tag:not(body).is-rounded { + border-radius: 290486px; } + +a.tag:hover { + text-decoration: underline; } + +.title, +.subtitle { + word-break: break-word; } + .title em, + .title span, + .subtitle em, + .subtitle span { + font-weight: inherit; } + .title sub, + .subtitle sub { + font-size: 0.75em; } + .title sup, + .subtitle sup { + font-size: 0.75em; } + .title .tag, + .subtitle .tag { + vertical-align: middle; } + +.title { + color: #363636; + font-size: 2rem; + font-weight: 600; + line-height: 1.125; } + .title strong { + color: inherit; + font-weight: inherit; } + .title + .highlight { + margin-top: -0.75rem; } + .title:not(.is-spaced) + .subtitle { + margin-top: -1.25rem; } + .title.is-1 { + font-size: 3rem; } + .title.is-2 { + font-size: 2.5rem; } + .title.is-3 { + font-size: 2rem; } + .title.is-4 { + font-size: 1.5rem; } + .title.is-5 { + font-size: 1.25rem; } + .title.is-6 { + font-size: 1rem; } + .title.is-7 { + font-size: 0.75rem; } + +.subtitle { + color: #4a4a4a; + font-size: 1.25rem; + font-weight: 400; + line-height: 1.25; } + .subtitle strong { + color: #363636; + font-weight: 600; } + .subtitle:not(.is-spaced) + .title { + margin-top: -1.25rem; } + .subtitle.is-1 { + font-size: 3rem; } + .subtitle.is-2 { + font-size: 2.5rem; } + .subtitle.is-3 { + font-size: 2rem; } + .subtitle.is-4 { + font-size: 1.5rem; } + .subtitle.is-5 { + font-size: 1.25rem; } + .subtitle.is-6 { + font-size: 1rem; } + .subtitle.is-7 { + font-size: 0.75rem; } + +.heading { + display: block; + font-size: 11px; + letter-spacing: 1px; + margin-bottom: 5px; + text-transform: uppercase; } + +.highlight { + font-weight: 400; + max-width: 100%; + overflow: hidden; + padding: 0; } + .highlight pre { + overflow: auto; + max-width: 100%; } + +.number { + align-items: center; + background-color: whitesmoke; + border-radius: 290486px; + display: inline-flex; + font-size: 1.25rem; + height: 2em; + justify-content: center; + margin-right: 1.5rem; + min-width: 2.5em; + padding: 0.25rem 0.5rem; + text-align: center; + vertical-align: top; } + +/* Bulma Form */ +.input, .textarea, .select select { + background-color: white; + border-color: #dbdbdb; + border-radius: 4px; + color: #363636; } + .input::-moz-placeholder, .textarea::-moz-placeholder, .select select::-moz-placeholder { + color: rgba(54, 54, 54, 0.3); } + .input::-webkit-input-placeholder, .textarea::-webkit-input-placeholder, .select select::-webkit-input-placeholder { + color: rgba(54, 54, 54, 0.3); } + .input:-moz-placeholder, .textarea:-moz-placeholder, .select select:-moz-placeholder { + color: rgba(54, 54, 54, 0.3); } + .input:-ms-input-placeholder, .textarea:-ms-input-placeholder, .select select:-ms-input-placeholder { + color: rgba(54, 54, 54, 0.3); } + .input:hover, .textarea:hover, .select select:hover, .is-hovered.input, .is-hovered.textarea, .select select.is-hovered { + border-color: #b5b5b5; } + .input:focus, .textarea:focus, .select select:focus, .is-focused.input, .is-focused.textarea, .select select.is-focused, .input:active, .textarea:active, .select select:active, .is-active.input, .is-active.textarea, .select select.is-active { + border-color: #3273dc; + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .input[disabled], .textarea[disabled], .select select[disabled], + fieldset[disabled] .input, + fieldset[disabled] .textarea, + fieldset[disabled] .select select, + .select fieldset[disabled] select { + background-color: whitesmoke; + border-color: whitesmoke; + box-shadow: none; + color: #7a7a7a; } + .input[disabled]::-moz-placeholder, .textarea[disabled]::-moz-placeholder, .select select[disabled]::-moz-placeholder, + fieldset[disabled] .input::-moz-placeholder, + fieldset[disabled] .textarea::-moz-placeholder, + fieldset[disabled] .select select::-moz-placeholder, + .select fieldset[disabled] select::-moz-placeholder { + color: rgba(122, 122, 122, 0.3); } + .input[disabled]::-webkit-input-placeholder, .textarea[disabled]::-webkit-input-placeholder, .select select[disabled]::-webkit-input-placeholder, + fieldset[disabled] .input::-webkit-input-placeholder, + fieldset[disabled] .textarea::-webkit-input-placeholder, + fieldset[disabled] .select select::-webkit-input-placeholder, + .select fieldset[disabled] select::-webkit-input-placeholder { + color: rgba(122, 122, 122, 0.3); } + .input[disabled]:-moz-placeholder, .textarea[disabled]:-moz-placeholder, .select select[disabled]:-moz-placeholder, + fieldset[disabled] .input:-moz-placeholder, + fieldset[disabled] .textarea:-moz-placeholder, + fieldset[disabled] .select select:-moz-placeholder, + .select fieldset[disabled] select:-moz-placeholder { + color: rgba(122, 122, 122, 0.3); } + .input[disabled]:-ms-input-placeholder, .textarea[disabled]:-ms-input-placeholder, .select select[disabled]:-ms-input-placeholder, + fieldset[disabled] .input:-ms-input-placeholder, + fieldset[disabled] .textarea:-ms-input-placeholder, + fieldset[disabled] .select select:-ms-input-placeholder, + .select fieldset[disabled] select:-ms-input-placeholder { + color: rgba(122, 122, 122, 0.3); } + +.input, .textarea { + box-shadow: inset 0 0.0625em 0.125em rgba(10, 10, 10, 0.05); + max-width: 100%; + width: 100%; } + .input[readonly], .textarea[readonly] { + box-shadow: none; } + .is-white.input, .is-white.textarea { + border-color: white; } + .is-white.input:focus, .is-white.textarea:focus, .is-white.is-focused.input, .is-white.is-focused.textarea, .is-white.input:active, .is-white.textarea:active, .is-white.is-active.input, .is-white.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); } + .is-black.input, .is-black.textarea { + border-color: #0a0a0a; } + .is-black.input:focus, .is-black.textarea:focus, .is-black.is-focused.input, .is-black.is-focused.textarea, .is-black.input:active, .is-black.textarea:active, .is-black.is-active.input, .is-black.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); } + .is-light.input, .is-light.textarea { + border-color: whitesmoke; } + .is-light.input:focus, .is-light.textarea:focus, .is-light.is-focused.input, .is-light.is-focused.textarea, .is-light.input:active, .is-light.textarea:active, .is-light.is-active.input, .is-light.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); } + .is-dark.input, .is-dark.textarea { + border-color: #363636; } + .is-dark.input:focus, .is-dark.textarea:focus, .is-dark.is-focused.input, .is-dark.is-focused.textarea, .is-dark.input:active, .is-dark.textarea:active, .is-dark.is-active.input, .is-dark.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); } + .is-primary.input, .is-primary.textarea { + border-color: #00d1b2; } + .is-primary.input:focus, .is-primary.textarea:focus, .is-primary.is-focused.input, .is-primary.is-focused.textarea, .is-primary.input:active, .is-primary.textarea:active, .is-primary.is-active.input, .is-primary.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); } + .is-link.input, .is-link.textarea { + border-color: #3273dc; } + .is-link.input:focus, .is-link.textarea:focus, .is-link.is-focused.input, .is-link.is-focused.textarea, .is-link.input:active, .is-link.textarea:active, .is-link.is-active.input, .is-link.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .is-info.input, .is-info.textarea { + border-color: #3298dc; } + .is-info.input:focus, .is-info.textarea:focus, .is-info.is-focused.input, .is-info.is-focused.textarea, .is-info.input:active, .is-info.textarea:active, .is-info.is-active.input, .is-info.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(50, 152, 220, 0.25); } + .is-success.input, .is-success.textarea { + border-color: #48c774; } + .is-success.input:focus, .is-success.textarea:focus, .is-success.is-focused.input, .is-success.is-focused.textarea, .is-success.input:active, .is-success.textarea:active, .is-success.is-active.input, .is-success.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(72, 199, 116, 0.25); } + .is-warning.input, .is-warning.textarea { + border-color: #ffdd57; } + .is-warning.input:focus, .is-warning.textarea:focus, .is-warning.is-focused.input, .is-warning.is-focused.textarea, .is-warning.input:active, .is-warning.textarea:active, .is-warning.is-active.input, .is-warning.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(255, 221, 87, 0.25); } + .is-danger.input, .is-danger.textarea { + border-color: #f14668; } + .is-danger.input:focus, .is-danger.textarea:focus, .is-danger.is-focused.input, .is-danger.is-focused.textarea, .is-danger.input:active, .is-danger.textarea:active, .is-danger.is-active.input, .is-danger.is-active.textarea { + box-shadow: 0 0 0 0.125em rgba(241, 70, 104, 0.25); } + .is-small.input, .is-small.textarea { + border-radius: 2px; + font-size: 0.75rem; } + .is-medium.input, .is-medium.textarea { + font-size: 1.25rem; } + .is-large.input, .is-large.textarea { + font-size: 1.5rem; } + .is-fullwidth.input, .is-fullwidth.textarea { + display: block; + width: 100%; } + .is-inline.input, .is-inline.textarea { + display: inline; + width: auto; } + +.input.is-rounded { + border-radius: 290486px; + padding-left: calc(calc(0.75em - 1px) + 0.375em); + padding-right: calc(calc(0.75em - 1px) + 0.375em); } + +.input.is-static { + background-color: transparent; + border-color: transparent; + box-shadow: none; + padding-left: 0; + padding-right: 0; } + +.textarea { + display: block; + max-width: 100%; + min-width: 100%; + padding: calc(0.75em - 1px); + resize: vertical; } + .textarea:not([rows]) { + max-height: 40em; + min-height: 8em; } + .textarea[rows] { + height: initial; } + .textarea.has-fixed-size { + resize: none; } + +.checkbox, .radio { + cursor: pointer; + display: inline-block; + line-height: 1.25; + position: relative; } + .checkbox input, .radio input { + cursor: pointer; } + .checkbox:hover, .radio:hover { + color: #363636; } + .checkbox[disabled], .radio[disabled], + fieldset[disabled] .checkbox, + fieldset[disabled] .radio, + .checkbox input[disabled], + .radio input[disabled] { + color: #7a7a7a; + cursor: not-allowed; } + +.radio + .radio { + margin-left: 0.5em; } + +.select { + display: inline-block; + max-width: 100%; + position: relative; + vertical-align: top; } + .select:not(.is-multiple) { + height: 2.5em; } + .select:not(.is-multiple):not(.is-loading)::after { + border-color: #3273dc; + right: 1.125em; + z-index: 4; } + .select.is-rounded select { + border-radius: 290486px; + padding-left: 1em; } + .select select { + cursor: pointer; + display: block; + font-size: 1em; + max-width: 100%; + outline: none; } + .select select::-ms-expand { + display: none; } + .select select[disabled]:hover, + fieldset[disabled] .select select:hover { + border-color: whitesmoke; } + .select select:not([multiple]) { + padding-right: 2.5em; } + .select select[multiple] { + height: auto; + padding: 0; } + .select select[multiple] option { + padding: 0.5em 1em; } + .select:not(.is-multiple):not(.is-loading):hover::after { + border-color: #363636; } + .select.is-white:not(:hover)::after { + border-color: white; } + .select.is-white select { + border-color: white; } + .select.is-white select:hover, .select.is-white select.is-hovered { + border-color: #f2f2f2; } + .select.is-white select:focus, .select.is-white select.is-focused, .select.is-white select:active, .select.is-white select.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 255, 255, 0.25); } + .select.is-black:not(:hover)::after { + border-color: #0a0a0a; } + .select.is-black select { + border-color: #0a0a0a; } + .select.is-black select:hover, .select.is-black select.is-hovered { + border-color: black; } + .select.is-black select:focus, .select.is-black select.is-focused, .select.is-black select:active, .select.is-black select.is-active { + box-shadow: 0 0 0 0.125em rgba(10, 10, 10, 0.25); } + .select.is-light:not(:hover)::after { + border-color: whitesmoke; } + .select.is-light select { + border-color: whitesmoke; } + .select.is-light select:hover, .select.is-light select.is-hovered { + border-color: #e8e8e8; } + .select.is-light select:focus, .select.is-light select.is-focused, .select.is-light select:active, .select.is-light select.is-active { + box-shadow: 0 0 0 0.125em rgba(245, 245, 245, 0.25); } + .select.is-dark:not(:hover)::after { + border-color: #363636; } + .select.is-dark select { + border-color: #363636; } + .select.is-dark select:hover, .select.is-dark select.is-hovered { + border-color: #292929; } + .select.is-dark select:focus, .select.is-dark select.is-focused, .select.is-dark select:active, .select.is-dark select.is-active { + box-shadow: 0 0 0 0.125em rgba(54, 54, 54, 0.25); } + .select.is-primary:not(:hover)::after { + border-color: #00d1b2; } + .select.is-primary select { + border-color: #00d1b2; } + .select.is-primary select:hover, .select.is-primary select.is-hovered { + border-color: #00b89c; } + .select.is-primary select:focus, .select.is-primary select.is-focused, .select.is-primary select:active, .select.is-primary select.is-active { + box-shadow: 0 0 0 0.125em rgba(0, 209, 178, 0.25); } + .select.is-link:not(:hover)::after { + border-color: #3273dc; } + .select.is-link select { + border-color: #3273dc; } + .select.is-link select:hover, .select.is-link select.is-hovered { + border-color: #2366d1; } + .select.is-link select:focus, .select.is-link select.is-focused, .select.is-link select:active, .select.is-link select.is-active { + box-shadow: 0 0 0 0.125em rgba(50, 115, 220, 0.25); } + .select.is-info:not(:hover)::after { + border-color: #3298dc; } + .select.is-info select { + border-color: #3298dc; } + .select.is-info select:hover, .select.is-info select.is-hovered { + border-color: #238cd1; } + .select.is-info select:focus, .select.is-info select.is-focused, .select.is-info select:active, .select.is-info select.is-active { + box-shadow: 0 0 0 0.125em rgba(50, 152, 220, 0.25); } + .select.is-success:not(:hover)::after { + border-color: #48c774; } + .select.is-success select { + border-color: #48c774; } + .select.is-success select:hover, .select.is-success select.is-hovered { + border-color: #3abb67; } + .select.is-success select:focus, .select.is-success select.is-focused, .select.is-success select:active, .select.is-success select.is-active { + box-shadow: 0 0 0 0.125em rgba(72, 199, 116, 0.25); } + .select.is-warning:not(:hover)::after { + border-color: #ffdd57; } + .select.is-warning select { + border-color: #ffdd57; } + .select.is-warning select:hover, .select.is-warning select.is-hovered { + border-color: #ffd83d; } + .select.is-warning select:focus, .select.is-warning select.is-focused, .select.is-warning select:active, .select.is-warning select.is-active { + box-shadow: 0 0 0 0.125em rgba(255, 221, 87, 0.25); } + .select.is-danger:not(:hover)::after { + border-color: #f14668; } + .select.is-danger select { + border-color: #f14668; } + .select.is-danger select:hover, .select.is-danger select.is-hovered { + border-color: #ef2e55; } + .select.is-danger select:focus, .select.is-danger select.is-focused, .select.is-danger select:active, .select.is-danger select.is-active { + box-shadow: 0 0 0 0.125em rgba(241, 70, 104, 0.25); } + .select.is-small { + border-radius: 2px; + font-size: 0.75rem; } + .select.is-medium { + font-size: 1.25rem; } + .select.is-large { + font-size: 1.5rem; } + .select.is-disabled::after { + border-color: #7a7a7a; } + .select.is-fullwidth { + width: 100%; } + .select.is-fullwidth select { + width: 100%; } + .select.is-loading::after { + margin-top: 0; + position: absolute; + right: 0.625em; + top: 0.625em; + transform: none; } + .select.is-loading.is-small:after { + font-size: 0.75rem; } + .select.is-loading.is-medium:after { + font-size: 1.25rem; } + .select.is-loading.is-large:after { + font-size: 1.5rem; } + +.file { + align-items: stretch; + display: flex; + justify-content: flex-start; + position: relative; } + .file.is-white .file-cta { + background-color: white; + border-color: transparent; + color: #0a0a0a; } + .file.is-white:hover .file-cta, .file.is-white.is-hovered .file-cta { + background-color: #f9f9f9; + border-color: transparent; + color: #0a0a0a; } + .file.is-white:focus .file-cta, .file.is-white.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255, 255, 255, 0.25); + color: #0a0a0a; } + .file.is-white:active .file-cta, .file.is-white.is-active .file-cta { + background-color: #f2f2f2; + border-color: transparent; + color: #0a0a0a; } + .file.is-black .file-cta { + background-color: #0a0a0a; + border-color: transparent; + color: white; } + .file.is-black:hover .file-cta, .file.is-black.is-hovered .file-cta { + background-color: #040404; + border-color: transparent; + color: white; } + .file.is-black:focus .file-cta, .file.is-black.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(10, 10, 10, 0.25); + color: white; } + .file.is-black:active .file-cta, .file.is-black.is-active .file-cta { + background-color: black; + border-color: transparent; + color: white; } + .file.is-light .file-cta { + background-color: whitesmoke; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-light:hover .file-cta, .file.is-light.is-hovered .file-cta { + background-color: #eeeeee; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-light:focus .file-cta, .file.is-light.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(245, 245, 245, 0.25); + color: rgba(0, 0, 0, 0.7); } + .file.is-light:active .file-cta, .file.is-light.is-active .file-cta { + background-color: #e8e8e8; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-dark .file-cta { + background-color: #363636; + border-color: transparent; + color: #fff; } + .file.is-dark:hover .file-cta, .file.is-dark.is-hovered .file-cta { + background-color: #2f2f2f; + border-color: transparent; + color: #fff; } + .file.is-dark:focus .file-cta, .file.is-dark.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(54, 54, 54, 0.25); + color: #fff; } + .file.is-dark:active .file-cta, .file.is-dark.is-active .file-cta { + background-color: #292929; + border-color: transparent; + color: #fff; } + .file.is-primary .file-cta { + background-color: #00d1b2; + border-color: transparent; + color: #fff; } + .file.is-primary:hover .file-cta, .file.is-primary.is-hovered .file-cta { + background-color: #00c4a7; + border-color: transparent; + color: #fff; } + .file.is-primary:focus .file-cta, .file.is-primary.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(0, 209, 178, 0.25); + color: #fff; } + .file.is-primary:active .file-cta, .file.is-primary.is-active .file-cta { + background-color: #00b89c; + border-color: transparent; + color: #fff; } + .file.is-link .file-cta { + background-color: #3273dc; + border-color: transparent; + color: #fff; } + .file.is-link:hover .file-cta, .file.is-link.is-hovered .file-cta { + background-color: #276cda; + border-color: transparent; + color: #fff; } + .file.is-link:focus .file-cta, .file.is-link.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(50, 115, 220, 0.25); + color: #fff; } + .file.is-link:active .file-cta, .file.is-link.is-active .file-cta { + background-color: #2366d1; + border-color: transparent; + color: #fff; } + .file.is-info .file-cta { + background-color: #3298dc; + border-color: transparent; + color: #fff; } + .file.is-info:hover .file-cta, .file.is-info.is-hovered .file-cta { + background-color: #2793da; + border-color: transparent; + color: #fff; } + .file.is-info:focus .file-cta, .file.is-info.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(50, 152, 220, 0.25); + color: #fff; } + .file.is-info:active .file-cta, .file.is-info.is-active .file-cta { + background-color: #238cd1; + border-color: transparent; + color: #fff; } + .file.is-success .file-cta { + background-color: #48c774; + border-color: transparent; + color: #fff; } + .file.is-success:hover .file-cta, .file.is-success.is-hovered .file-cta { + background-color: #3ec46d; + border-color: transparent; + color: #fff; } + .file.is-success:focus .file-cta, .file.is-success.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(72, 199, 116, 0.25); + color: #fff; } + .file.is-success:active .file-cta, .file.is-success.is-active .file-cta { + background-color: #3abb67; + border-color: transparent; + color: #fff; } + .file.is-warning .file-cta { + background-color: #ffdd57; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-warning:hover .file-cta, .file.is-warning.is-hovered .file-cta { + background-color: #ffdb4a; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-warning:focus .file-cta, .file.is-warning.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(255, 221, 87, 0.25); + color: rgba(0, 0, 0, 0.7); } + .file.is-warning:active .file-cta, .file.is-warning.is-active .file-cta { + background-color: #ffd83d; + border-color: transparent; + color: rgba(0, 0, 0, 0.7); } + .file.is-danger .file-cta { + background-color: #f14668; + border-color: transparent; + color: #fff; } + .file.is-danger:hover .file-cta, .file.is-danger.is-hovered .file-cta { + background-color: #f03a5f; + border-color: transparent; + color: #fff; } + .file.is-danger:focus .file-cta, .file.is-danger.is-focused .file-cta { + border-color: transparent; + box-shadow: 0 0 0.5em rgba(241, 70, 104, 0.25); + color: #fff; } + .file.is-danger:active .file-cta, .file.is-danger.is-active .file-cta { + background-color: #ef2e55; + border-color: transparent; + color: #fff; } + .file.is-small { + font-size: 0.75rem; } + .file.is-medium { + font-size: 1.25rem; } + .file.is-medium .file-icon .fa { + font-size: 21px; } + .file.is-large { + font-size: 1.5rem; } + .file.is-large .file-icon .fa { + font-size: 28px; } + .file.has-name .file-cta { + border-bottom-right-radius: 0; + border-top-right-radius: 0; } + .file.has-name .file-name { + border-bottom-left-radius: 0; + border-top-left-radius: 0; } + .file.has-name.is-empty .file-cta { + border-radius: 4px; } + .file.has-name.is-empty .file-name { + display: none; } + .file.is-boxed .file-label { + flex-direction: column; } + .file.is-boxed .file-cta { + flex-direction: column; + height: auto; + padding: 1em 3em; } + .file.is-boxed .file-name { + border-width: 0 1px 1px; } + .file.is-boxed .file-icon { + height: 1.5em; + width: 1.5em; } + .file.is-boxed .file-icon .fa { + font-size: 21px; } + .file.is-boxed.is-small .file-icon .fa { + font-size: 14px; } + .file.is-boxed.is-medium .file-icon .fa { + font-size: 28px; } + .file.is-boxed.is-large .file-icon .fa { + font-size: 35px; } + .file.is-boxed.has-name .file-cta { + border-radius: 4px 4px 0 0; } + .file.is-boxed.has-name .file-name { + border-radius: 0 0 4px 4px; + border-width: 0 1px 1px; } + .file.is-centered { + justify-content: center; } + .file.is-fullwidth .file-label { + width: 100%; } + .file.is-fullwidth .file-name { + flex-grow: 1; + max-width: none; } + .file.is-right { + justify-content: flex-end; } + .file.is-right .file-cta { + border-radius: 0 4px 4px 0; } + .file.is-right .file-name { + border-radius: 4px 0 0 4px; + border-width: 1px 0 1px 1px; + order: -1; } + +.file-label { + align-items: stretch; + display: flex; + cursor: pointer; + justify-content: flex-start; + overflow: hidden; + position: relative; } + .file-label:hover .file-cta { + background-color: #eeeeee; + color: #363636; } + .file-label:hover .file-name { + border-color: #d5d5d5; } + .file-label:active .file-cta { + background-color: #e8e8e8; + color: #363636; } + .file-label:active .file-name { + border-color: #cfcfcf; } + +.file-input { + height: 100%; + left: 0; + opacity: 0; + outline: none; + position: absolute; + top: 0; + width: 100%; } + +.file-cta, +.file-name { + border-color: #dbdbdb; + border-radius: 4px; + font-size: 1em; + padding-left: 1em; + padding-right: 1em; + white-space: nowrap; } + +.file-cta { + background-color: whitesmoke; + color: #4a4a4a; } + +.file-name { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px 1px 1px 0; + display: block; + max-width: 16em; + overflow: hidden; + text-align: inherit; + text-overflow: ellipsis; } + +.file-icon { + align-items: center; + display: flex; + height: 1em; + justify-content: center; + margin-right: 0.5em; + width: 1em; } + .file-icon .fa { + font-size: 14px; } + +.label { + color: #363636; + display: block; + font-size: 1rem; + font-weight: 700; } + .label:not(:last-child) { + margin-bottom: 0.5em; } + .label.is-small { + font-size: 0.75rem; } + .label.is-medium { + font-size: 1.25rem; } + .label.is-large { + font-size: 1.5rem; } + +.help { + display: block; + font-size: 0.75rem; + margin-top: 0.25rem; } + .help.is-white { + color: white; } + .help.is-black { + color: #0a0a0a; } + .help.is-light { + color: whitesmoke; } + .help.is-dark { + color: #363636; } + .help.is-primary { + color: #00d1b2; } + .help.is-link { + color: #3273dc; } + .help.is-info { + color: #3298dc; } + .help.is-success { + color: #48c774; } + .help.is-warning { + color: #ffdd57; } + .help.is-danger { + color: #f14668; } + +.field:not(:last-child) { + margin-bottom: 0.75rem; } + +.field.has-addons { + display: flex; + justify-content: flex-start; } + .field.has-addons .control:not(:last-child) { + margin-right: -1px; } + .field.has-addons .control:not(:first-child):not(:last-child) .button, + .field.has-addons .control:not(:first-child):not(:last-child) .input, + .field.has-addons .control:not(:first-child):not(:last-child) .select select { + border-radius: 0; } + .field.has-addons .control:first-child:not(:only-child) .button, + .field.has-addons .control:first-child:not(:only-child) .input, + .field.has-addons .control:first-child:not(:only-child) .select select { + border-bottom-right-radius: 0; + border-top-right-radius: 0; } + .field.has-addons .control:last-child:not(:only-child) .button, + .field.has-addons .control:last-child:not(:only-child) .input, + .field.has-addons .control:last-child:not(:only-child) .select select { + border-bottom-left-radius: 0; + border-top-left-radius: 0; } + .field.has-addons .control .button:not([disabled]):hover, .field.has-addons .control .button:not([disabled]).is-hovered, + .field.has-addons .control .input:not([disabled]):hover, + .field.has-addons .control .input:not([disabled]).is-hovered, + .field.has-addons .control .select select:not([disabled]):hover, + .field.has-addons .control .select select:not([disabled]).is-hovered { + z-index: 2; } + .field.has-addons .control .button:not([disabled]):focus, .field.has-addons .control .button:not([disabled]).is-focused, .field.has-addons .control .button:not([disabled]):active, .field.has-addons .control .button:not([disabled]).is-active, + .field.has-addons .control .input:not([disabled]):focus, + .field.has-addons .control .input:not([disabled]).is-focused, + .field.has-addons .control .input:not([disabled]):active, + .field.has-addons .control .input:not([disabled]).is-active, + .field.has-addons .control .select select:not([disabled]):focus, + .field.has-addons .control .select select:not([disabled]).is-focused, + .field.has-addons .control .select select:not([disabled]):active, + .field.has-addons .control .select select:not([disabled]).is-active { + z-index: 3; } + .field.has-addons .control .button:not([disabled]):focus:hover, .field.has-addons .control .button:not([disabled]).is-focused:hover, .field.has-addons .control .button:not([disabled]):active:hover, .field.has-addons .control .button:not([disabled]).is-active:hover, + .field.has-addons .control .input:not([disabled]):focus:hover, + .field.has-addons .control .input:not([disabled]).is-focused:hover, + .field.has-addons .control .input:not([disabled]):active:hover, + .field.has-addons .control .input:not([disabled]).is-active:hover, + .field.has-addons .control .select select:not([disabled]):focus:hover, + .field.has-addons .control .select select:not([disabled]).is-focused:hover, + .field.has-addons .control .select select:not([disabled]):active:hover, + .field.has-addons .control .select select:not([disabled]).is-active:hover { + z-index: 4; } + .field.has-addons .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; } + .field.has-addons.has-addons-centered { + justify-content: center; } + .field.has-addons.has-addons-right { + justify-content: flex-end; } + .field.has-addons.has-addons-fullwidth .control { + flex-grow: 1; + flex-shrink: 0; } + +.field.is-grouped { + display: flex; + justify-content: flex-start; } + .field.is-grouped > .control { + flex-shrink: 0; } + .field.is-grouped > .control:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; } + .field.is-grouped > .control.is-expanded { + flex-grow: 1; + flex-shrink: 1; } + .field.is-grouped.is-grouped-centered { + justify-content: center; } + .field.is-grouped.is-grouped-right { + justify-content: flex-end; } + .field.is-grouped.is-grouped-multiline { + flex-wrap: wrap; } + .field.is-grouped.is-grouped-multiline > .control:last-child, .field.is-grouped.is-grouped-multiline > .control:not(:last-child) { + margin-bottom: 0.75rem; } + .field.is-grouped.is-grouped-multiline:last-child { + margin-bottom: -0.75rem; } + .field.is-grouped.is-grouped-multiline:not(:last-child) { + margin-bottom: 0; } + +@media screen and (min-width: 769px), print { + .field.is-horizontal { + display: flex; } } + +.field-label .label { + font-size: inherit; } + +@media screen and (max-width: 768px) { + .field-label { + margin-bottom: 0.5rem; } } + +@media screen and (min-width: 769px), print { + .field-label { + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + margin-right: 1.5rem; + text-align: right; } + .field-label.is-small { + font-size: 0.75rem; + padding-top: 0.375em; } + .field-label.is-normal { + padding-top: 0.375em; } + .field-label.is-medium { + font-size: 1.25rem; + padding-top: 0.375em; } + .field-label.is-large { + font-size: 1.5rem; + padding-top: 0.375em; } } + +.field-body .field .field { + margin-bottom: 0; } + +@media screen and (min-width: 769px), print { + .field-body { + display: flex; + flex-basis: 0; + flex-grow: 5; + flex-shrink: 1; } + .field-body .field { + margin-bottom: 0; } + .field-body > .field { + flex-shrink: 1; } + .field-body > .field:not(.is-narrow) { + flex-grow: 1; } + .field-body > .field:not(:last-child) { + margin-right: 0.75rem; } } + +.control { + box-sizing: border-box; + clear: both; + font-size: 1rem; + position: relative; + text-align: inherit; } + .control.has-icons-left .input:focus ~ .icon, + .control.has-icons-left .select:focus ~ .icon, .control.has-icons-right .input:focus ~ .icon, + .control.has-icons-right .select:focus ~ .icon { + color: #4a4a4a; } + .control.has-icons-left .input.is-small ~ .icon, + .control.has-icons-left .select.is-small ~ .icon, .control.has-icons-right .input.is-small ~ .icon, + .control.has-icons-right .select.is-small ~ .icon { + font-size: 0.75rem; } + .control.has-icons-left .input.is-medium ~ .icon, + .control.has-icons-left .select.is-medium ~ .icon, .control.has-icons-right .input.is-medium ~ .icon, + .control.has-icons-right .select.is-medium ~ .icon { + font-size: 1.25rem; } + .control.has-icons-left .input.is-large ~ .icon, + .control.has-icons-left .select.is-large ~ .icon, .control.has-icons-right .input.is-large ~ .icon, + .control.has-icons-right .select.is-large ~ .icon { + font-size: 1.5rem; } + .control.has-icons-left .icon, .control.has-icons-right .icon { + color: #dbdbdb; + height: 2.5em; + pointer-events: none; + position: absolute; + top: 0; + width: 2.5em; + z-index: 4; } + .control.has-icons-left .input, + .control.has-icons-left .select select { + padding-left: 2.5em; } + .control.has-icons-left .icon.is-left { + left: 0; } + .control.has-icons-right .input, + .control.has-icons-right .select select { + padding-right: 2.5em; } + .control.has-icons-right .icon.is-right { + right: 0; } + .control.is-loading::after { + position: absolute !important; + right: 0.625em; + top: 0.625em; + z-index: 4; } + .control.is-loading.is-small:after { + font-size: 0.75rem; } + .control.is-loading.is-medium:after { + font-size: 1.25rem; } + .control.is-loading.is-large:after { + font-size: 1.5rem; } + +/* Bulma Components */ +.breadcrumb { + font-size: 1rem; + white-space: nowrap; } + .breadcrumb a { + align-items: center; + color: #3273dc; + display: flex; + justify-content: center; + padding: 0 0.75em; } + .breadcrumb a:hover { + color: #363636; } + .breadcrumb li { + align-items: center; + display: flex; } + .breadcrumb li:first-child a { + padding-left: 0; } + .breadcrumb li.is-active a { + color: #363636; + cursor: default; + pointer-events: none; } + .breadcrumb li + li::before { + color: #b5b5b5; + content: "\0002f"; } + .breadcrumb ul, + .breadcrumb ol { + align-items: flex-start; + display: flex; + flex-wrap: wrap; + justify-content: flex-start; } + .breadcrumb .icon:first-child { + margin-right: 0.5em; } + .breadcrumb .icon:last-child { + margin-left: 0.5em; } + .breadcrumb.is-centered ol, + .breadcrumb.is-centered ul { + justify-content: center; } + .breadcrumb.is-right ol, + .breadcrumb.is-right ul { + justify-content: flex-end; } + .breadcrumb.is-small { + font-size: 0.75rem; } + .breadcrumb.is-medium { + font-size: 1.25rem; } + .breadcrumb.is-large { + font-size: 1.5rem; } + .breadcrumb.has-arrow-separator li + li::before { + content: "\02192"; } + .breadcrumb.has-bullet-separator li + li::before { + content: "\02022"; } + .breadcrumb.has-dot-separator li + li::before { + content: "\000b7"; } + .breadcrumb.has-succeeds-separator li + li::before { + content: "\0227B"; } + +.card { + background-color: white; + border-radius: 0.25rem; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + color: #4a4a4a; + max-width: 100%; + position: relative; } + +.card-header:first-child, .card-content:first-child, .card-footer:first-child { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; } + +.card-header:last-child, .card-content:last-child, .card-footer:last-child { + border-bottom-left-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; } + +.card-header { + background-color: transparent; + align-items: stretch; + box-shadow: 0 0.125em 0.25em rgba(10, 10, 10, 0.1); + display: flex; } + +.card-header-title { + align-items: center; + color: #363636; + display: flex; + flex-grow: 1; + font-weight: 700; + padding: 0.75rem 1rem; } + .card-header-title.is-centered { + justify-content: center; } + +.card-header-icon { + align-items: center; + cursor: pointer; + display: flex; + justify-content: center; + padding: 0.75rem 1rem; } + +.card-image { + display: block; + position: relative; } + .card-image:first-child img { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; } + .card-image:last-child img { + border-bottom-left-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; } + +.card-content { + background-color: transparent; + padding: 1.5rem; } + +.card-footer { + background-color: transparent; + border-top: 1px solid #ededed; + align-items: stretch; + display: flex; } + +.card-footer-item { + align-items: center; + display: flex; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 0; + justify-content: center; + padding: 0.75rem; } + .card-footer-item:not(:last-child) { + border-right: 1px solid #ededed; } + +.card .media:not(:last-child) { + margin-bottom: 1.5rem; } + +.dropdown { + display: inline-flex; + position: relative; + vertical-align: top; } + .dropdown.is-active .dropdown-menu, .dropdown.is-hoverable:hover .dropdown-menu { + display: block; } + .dropdown.is-right .dropdown-menu { + left: auto; + right: 0; } + .dropdown.is-up .dropdown-menu { + bottom: 100%; + padding-bottom: 4px; + padding-top: initial; + top: auto; } + +.dropdown-menu { + display: none; + left: 0; + min-width: 12rem; + padding-top: 4px; + position: absolute; + top: 100%; + z-index: 20; } + +.dropdown-content { + background-color: white; + border-radius: 4px; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + padding-bottom: 0.5rem; + padding-top: 0.5rem; } + +.dropdown-item { + color: #4a4a4a; + display: block; + font-size: 0.875rem; + line-height: 1.5; + padding: 0.375rem 1rem; + position: relative; } + +a.dropdown-item, +button.dropdown-item { + padding-right: 3rem; + text-align: inherit; + white-space: nowrap; + width: 100%; } + a.dropdown-item:hover, + button.dropdown-item:hover { + background-color: whitesmoke; + color: #0a0a0a; } + a.dropdown-item.is-active, + button.dropdown-item.is-active { + background-color: #3273dc; + color: #fff; } + +.dropdown-divider { + background-color: #ededed; + border: none; + display: block; + height: 1px; + margin: 0.5rem 0; } + +.level { + align-items: center; + justify-content: space-between; } + .level code { + border-radius: 4px; } + .level img { + display: inline-block; + vertical-align: top; } + .level.is-mobile { + display: flex; } + .level.is-mobile .level-left, + .level.is-mobile .level-right { + display: flex; } + .level.is-mobile .level-left + .level-right { + margin-top: 0; } + .level.is-mobile .level-item:not(:last-child) { + margin-bottom: 0; + margin-right: 0.75rem; } + .level.is-mobile .level-item:not(.is-narrow) { + flex-grow: 1; } + @media screen and (min-width: 769px), print { + .level { + display: flex; } + .level > .level-item:not(.is-narrow) { + flex-grow: 1; } } + +.level-item { + align-items: center; + display: flex; + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; + justify-content: center; } + .level-item .title, + .level-item .subtitle { + margin-bottom: 0; } + @media screen and (max-width: 768px) { + .level-item:not(:last-child) { + margin-bottom: 0.75rem; } } + +.level-left, +.level-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; } + .level-left .level-item.is-flexible, + .level-right .level-item.is-flexible { + flex-grow: 1; } + @media screen and (min-width: 769px), print { + .level-left .level-item:not(:last-child), + .level-right .level-item:not(:last-child) { + margin-right: 0.75rem; } } + +.level-left { + align-items: center; + justify-content: flex-start; } + @media screen and (max-width: 768px) { + .level-left + .level-right { + margin-top: 1.5rem; } } + @media screen and (min-width: 769px), print { + .level-left { + display: flex; } } + +.level-right { + align-items: center; + justify-content: flex-end; } + @media screen and (min-width: 769px), print { + .level-right { + display: flex; } } + +.media { + align-items: flex-start; + display: flex; + text-align: inherit; } + .media .content:not(:last-child) { + margin-bottom: 0.75rem; } + .media .media { + border-top: 1px solid rgba(219, 219, 219, 0.5); + display: flex; + padding-top: 0.75rem; } + .media .media .content:not(:last-child), + .media .media .control:not(:last-child) { + margin-bottom: 0.5rem; } + .media .media .media { + padding-top: 0.5rem; } + .media .media .media + .media { + margin-top: 0.5rem; } + .media + .media { + border-top: 1px solid rgba(219, 219, 219, 0.5); + margin-top: 1rem; + padding-top: 1rem; } + .media.is-large + .media { + margin-top: 1.5rem; + padding-top: 1.5rem; } + +.media-left, +.media-right { + flex-basis: auto; + flex-grow: 0; + flex-shrink: 0; } + +.media-left { + margin-right: 1rem; } + +.media-right { + margin-left: 1rem; } + +.media-content { + flex-basis: auto; + flex-grow: 1; + flex-shrink: 1; + text-align: inherit; } + +@media screen and (max-width: 768px) { + .media-content { + overflow-x: auto; } } + +.menu { + font-size: 1rem; } + .menu.is-small { + font-size: 0.75rem; } + .menu.is-medium { + font-size: 1.25rem; } + .menu.is-large { + font-size: 1.5rem; } + +.menu-list { + line-height: 1.25; } + .menu-list a { + border-radius: 2px; + color: #4a4a4a; + display: block; + padding: 0.5em 0.75em; } + .menu-list a:hover { + background-color: whitesmoke; + color: #363636; } + .menu-list a.is-active { + background-color: #3273dc; + color: #fff; } + .menu-list li ul { + border-left: 1px solid #dbdbdb; + margin: 0.75em; + padding-left: 0.75em; } + +.menu-label { + color: #7a7a7a; + font-size: 0.75em; + letter-spacing: 0.1em; + text-transform: uppercase; } + .menu-label:not(:first-child) { + margin-top: 1em; } + .menu-label:not(:last-child) { + margin-bottom: 1em; } + +.message { + background-color: whitesmoke; + border-radius: 4px; + font-size: 1rem; } + .message strong { + color: currentColor; } + .message a:not(.button):not(.tag):not(.dropdown-item) { + color: currentColor; + text-decoration: underline; } + .message.is-small { + font-size: 0.75rem; } + .message.is-medium { + font-size: 1.25rem; } + .message.is-large { + font-size: 1.5rem; } + .message.is-white { + background-color: white; } + .message.is-white .message-header { + background-color: white; + color: #0a0a0a; } + .message.is-white .message-body { + border-color: white; } + .message.is-black { + background-color: #fafafa; } + .message.is-black .message-header { + background-color: #0a0a0a; + color: white; } + .message.is-black .message-body { + border-color: #0a0a0a; } + .message.is-light { + background-color: #fafafa; } + .message.is-light .message-header { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .message.is-light .message-body { + border-color: whitesmoke; } + .message.is-dark { + background-color: #fafafa; } + .message.is-dark .message-header { + background-color: #363636; + color: #fff; } + .message.is-dark .message-body { + border-color: #363636; } + .message.is-primary { + background-color: #ebfffc; } + .message.is-primary .message-header { + background-color: #00d1b2; + color: #fff; } + .message.is-primary .message-body { + border-color: #00d1b2; + color: #00947e; } + .message.is-link { + background-color: #eef3fc; } + .message.is-link .message-header { + background-color: #3273dc; + color: #fff; } + .message.is-link .message-body { + border-color: #3273dc; + color: #2160c4; } + .message.is-info { + background-color: #eef6fc; } + .message.is-info .message-header { + background-color: #3298dc; + color: #fff; } + .message.is-info .message-body { + border-color: #3298dc; + color: #1d72aa; } + .message.is-success { + background-color: #effaf3; } + .message.is-success .message-header { + background-color: #48c774; + color: #fff; } + .message.is-success .message-body { + border-color: #48c774; + color: #257942; } + .message.is-warning { + background-color: #fffbeb; } + .message.is-warning .message-header { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .message.is-warning .message-body { + border-color: #ffdd57; + color: #947600; } + .message.is-danger { + background-color: #feecf0; } + .message.is-danger .message-header { + background-color: #f14668; + color: #fff; } + .message.is-danger .message-body { + border-color: #f14668; + color: #cc0f35; } + +.message-header { + align-items: center; + background-color: #4a4a4a; + border-radius: 4px 4px 0 0; + color: #fff; + display: flex; + font-weight: 700; + justify-content: space-between; + line-height: 1.25; + padding: 0.75em 1em; + position: relative; } + .message-header .delete { + flex-grow: 0; + flex-shrink: 0; + margin-left: 0.75em; } + .message-header + .message-body { + border-width: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; } + +.message-body { + border-color: #dbdbdb; + border-radius: 4px; + border-style: solid; + border-width: 0 0 0 4px; + color: #4a4a4a; + padding: 1.25em 1.5em; } + .message-body code, + .message-body pre { + background-color: white; } + .message-body pre code { + background-color: transparent; } + +.modal { + align-items: center; + display: none; + flex-direction: column; + justify-content: center; + overflow: hidden; + position: fixed; + z-index: 40; } + .modal.is-active { + display: flex; } + +.modal-background { + background-color: rgba(10, 10, 10, 0.86); } + +.modal-content, +.modal-card { + margin: 0 20px; + max-height: calc(100vh - 160px); + overflow: auto; + position: relative; + width: 100%; } + @media screen and (min-width: 769px) { + .modal-content, + .modal-card { + margin: 0 auto; + max-height: calc(100vh - 40px); + width: 640px; } } + +.modal-close { + background: none; + height: 40px; + position: fixed; + right: 20px; + top: 20px; + width: 40px; } + +.modal-card { + display: flex; + flex-direction: column; + max-height: calc(100vh - 40px); + overflow: hidden; + -ms-overflow-y: visible; } + +.modal-card-head, +.modal-card-foot { + align-items: center; + background-color: whitesmoke; + display: flex; + flex-shrink: 0; + justify-content: flex-start; + padding: 20px; + position: relative; } + +.modal-card-head { + border-bottom: 1px solid #dbdbdb; + border-top-left-radius: 6px; + border-top-right-radius: 6px; } + +.modal-card-title { + color: #363636; + flex-grow: 1; + flex-shrink: 0; + font-size: 1.5rem; + line-height: 1; } + +.modal-card-foot { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 1px solid #dbdbdb; } + .modal-card-foot .button:not(:last-child) { + margin-right: 0.5em; } + +.modal-card-body { + -webkit-overflow-scrolling: touch; + background-color: white; + flex-grow: 1; + flex-shrink: 1; + overflow: auto; + padding: 20px; } + +.navbar { + background-color: white; + min-height: 3.25rem; + position: relative; + z-index: 30; } + .navbar.is-white { + background-color: white; + color: #0a0a0a; } + .navbar.is-white .navbar-brand > .navbar-item, + .navbar.is-white .navbar-brand .navbar-link { + color: #0a0a0a; } + .navbar.is-white .navbar-brand > a.navbar-item:focus, .navbar.is-white .navbar-brand > a.navbar-item:hover, .navbar.is-white .navbar-brand > a.navbar-item.is-active, + .navbar.is-white .navbar-brand .navbar-link:focus, + .navbar.is-white .navbar-brand .navbar-link:hover, + .navbar.is-white .navbar-brand .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; } + .navbar.is-white .navbar-brand .navbar-link::after { + border-color: #0a0a0a; } + .navbar.is-white .navbar-burger { + color: #0a0a0a; } + @media screen and (min-width: 1024px) { + .navbar.is-white .navbar-start > .navbar-item, + .navbar.is-white .navbar-start .navbar-link, + .navbar.is-white .navbar-end > .navbar-item, + .navbar.is-white .navbar-end .navbar-link { + color: #0a0a0a; } + .navbar.is-white .navbar-start > a.navbar-item:focus, .navbar.is-white .navbar-start > a.navbar-item:hover, .navbar.is-white .navbar-start > a.navbar-item.is-active, + .navbar.is-white .navbar-start .navbar-link:focus, + .navbar.is-white .navbar-start .navbar-link:hover, + .navbar.is-white .navbar-start .navbar-link.is-active, + .navbar.is-white .navbar-end > a.navbar-item:focus, + .navbar.is-white .navbar-end > a.navbar-item:hover, + .navbar.is-white .navbar-end > a.navbar-item.is-active, + .navbar.is-white .navbar-end .navbar-link:focus, + .navbar.is-white .navbar-end .navbar-link:hover, + .navbar.is-white .navbar-end .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; } + .navbar.is-white .navbar-start .navbar-link::after, + .navbar.is-white .navbar-end .navbar-link::after { + border-color: #0a0a0a; } + .navbar.is-white .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-white .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #f2f2f2; + color: #0a0a0a; } + .navbar.is-white .navbar-dropdown a.navbar-item.is-active { + background-color: white; + color: #0a0a0a; } } + .navbar.is-black { + background-color: #0a0a0a; + color: white; } + .navbar.is-black .navbar-brand > .navbar-item, + .navbar.is-black .navbar-brand .navbar-link { + color: white; } + .navbar.is-black .navbar-brand > a.navbar-item:focus, .navbar.is-black .navbar-brand > a.navbar-item:hover, .navbar.is-black .navbar-brand > a.navbar-item.is-active, + .navbar.is-black .navbar-brand .navbar-link:focus, + .navbar.is-black .navbar-brand .navbar-link:hover, + .navbar.is-black .navbar-brand .navbar-link.is-active { + background-color: black; + color: white; } + .navbar.is-black .navbar-brand .navbar-link::after { + border-color: white; } + .navbar.is-black .navbar-burger { + color: white; } + @media screen and (min-width: 1024px) { + .navbar.is-black .navbar-start > .navbar-item, + .navbar.is-black .navbar-start .navbar-link, + .navbar.is-black .navbar-end > .navbar-item, + .navbar.is-black .navbar-end .navbar-link { + color: white; } + .navbar.is-black .navbar-start > a.navbar-item:focus, .navbar.is-black .navbar-start > a.navbar-item:hover, .navbar.is-black .navbar-start > a.navbar-item.is-active, + .navbar.is-black .navbar-start .navbar-link:focus, + .navbar.is-black .navbar-start .navbar-link:hover, + .navbar.is-black .navbar-start .navbar-link.is-active, + .navbar.is-black .navbar-end > a.navbar-item:focus, + .navbar.is-black .navbar-end > a.navbar-item:hover, + .navbar.is-black .navbar-end > a.navbar-item.is-active, + .navbar.is-black .navbar-end .navbar-link:focus, + .navbar.is-black .navbar-end .navbar-link:hover, + .navbar.is-black .navbar-end .navbar-link.is-active { + background-color: black; + color: white; } + .navbar.is-black .navbar-start .navbar-link::after, + .navbar.is-black .navbar-end .navbar-link::after { + border-color: white; } + .navbar.is-black .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-black .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link { + background-color: black; + color: white; } + .navbar.is-black .navbar-dropdown a.navbar-item.is-active { + background-color: #0a0a0a; + color: white; } } + .navbar.is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-brand > .navbar-item, + .navbar.is-light .navbar-brand .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-brand > a.navbar-item:focus, .navbar.is-light .navbar-brand > a.navbar-item:hover, .navbar.is-light .navbar-brand > a.navbar-item.is-active, + .navbar.is-light .navbar-brand .navbar-link:focus, + .navbar.is-light .navbar-brand .navbar-link:hover, + .navbar.is-light .navbar-brand .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-brand .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-burger { + color: rgba(0, 0, 0, 0.7); } + @media screen and (min-width: 1024px) { + .navbar.is-light .navbar-start > .navbar-item, + .navbar.is-light .navbar-start .navbar-link, + .navbar.is-light .navbar-end > .navbar-item, + .navbar.is-light .navbar-end .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-start > a.navbar-item:focus, .navbar.is-light .navbar-start > a.navbar-item:hover, .navbar.is-light .navbar-start > a.navbar-item.is-active, + .navbar.is-light .navbar-start .navbar-link:focus, + .navbar.is-light .navbar-start .navbar-link:hover, + .navbar.is-light .navbar-start .navbar-link.is-active, + .navbar.is-light .navbar-end > a.navbar-item:focus, + .navbar.is-light .navbar-end > a.navbar-item:hover, + .navbar.is-light .navbar-end > a.navbar-item.is-active, + .navbar.is-light .navbar-end .navbar-link:focus, + .navbar.is-light .navbar-end .navbar-link:hover, + .navbar.is-light .navbar-end .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-start .navbar-link::after, + .navbar.is-light .navbar-end .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-light .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-light .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } } + .navbar.is-dark { + background-color: #363636; + color: #fff; } + .navbar.is-dark .navbar-brand > .navbar-item, + .navbar.is-dark .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-dark .navbar-brand > a.navbar-item:focus, .navbar.is-dark .navbar-brand > a.navbar-item:hover, .navbar.is-dark .navbar-brand > a.navbar-item.is-active, + .navbar.is-dark .navbar-brand .navbar-link:focus, + .navbar.is-dark .navbar-brand .navbar-link:hover, + .navbar.is-dark .navbar-brand .navbar-link.is-active { + background-color: #292929; + color: #fff; } + .navbar.is-dark .navbar-brand .navbar-link::after { + border-color: #fff; } + .navbar.is-dark .navbar-burger { + color: #fff; } + @media screen and (min-width: 1024px) { + .navbar.is-dark .navbar-start > .navbar-item, + .navbar.is-dark .navbar-start .navbar-link, + .navbar.is-dark .navbar-end > .navbar-item, + .navbar.is-dark .navbar-end .navbar-link { + color: #fff; } + .navbar.is-dark .navbar-start > a.navbar-item:focus, .navbar.is-dark .navbar-start > a.navbar-item:hover, .navbar.is-dark .navbar-start > a.navbar-item.is-active, + .navbar.is-dark .navbar-start .navbar-link:focus, + .navbar.is-dark .navbar-start .navbar-link:hover, + .navbar.is-dark .navbar-start .navbar-link.is-active, + .navbar.is-dark .navbar-end > a.navbar-item:focus, + .navbar.is-dark .navbar-end > a.navbar-item:hover, + .navbar.is-dark .navbar-end > a.navbar-item.is-active, + .navbar.is-dark .navbar-end .navbar-link:focus, + .navbar.is-dark .navbar-end .navbar-link:hover, + .navbar.is-dark .navbar-end .navbar-link.is-active { + background-color: #292929; + color: #fff; } + .navbar.is-dark .navbar-start .navbar-link::after, + .navbar.is-dark .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-dark .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #292929; + color: #fff; } + .navbar.is-dark .navbar-dropdown a.navbar-item.is-active { + background-color: #363636; + color: #fff; } } + .navbar.is-primary { + background-color: #00d1b2; + color: #fff; } + .navbar.is-primary .navbar-brand > .navbar-item, + .navbar.is-primary .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-primary .navbar-brand > a.navbar-item:focus, .navbar.is-primary .navbar-brand > a.navbar-item:hover, .navbar.is-primary .navbar-brand > a.navbar-item.is-active, + .navbar.is-primary .navbar-brand .navbar-link:focus, + .navbar.is-primary .navbar-brand .navbar-link:hover, + .navbar.is-primary .navbar-brand .navbar-link.is-active { + background-color: #00b89c; + color: #fff; } + .navbar.is-primary .navbar-brand .navbar-link::after { + border-color: #fff; } + .navbar.is-primary .navbar-burger { + color: #fff; } + @media screen and (min-width: 1024px) { + .navbar.is-primary .navbar-start > .navbar-item, + .navbar.is-primary .navbar-start .navbar-link, + .navbar.is-primary .navbar-end > .navbar-item, + .navbar.is-primary .navbar-end .navbar-link { + color: #fff; } + .navbar.is-primary .navbar-start > a.navbar-item:focus, .navbar.is-primary .navbar-start > a.navbar-item:hover, .navbar.is-primary .navbar-start > a.navbar-item.is-active, + .navbar.is-primary .navbar-start .navbar-link:focus, + .navbar.is-primary .navbar-start .navbar-link:hover, + .navbar.is-primary .navbar-start .navbar-link.is-active, + .navbar.is-primary .navbar-end > a.navbar-item:focus, + .navbar.is-primary .navbar-end > a.navbar-item:hover, + .navbar.is-primary .navbar-end > a.navbar-item.is-active, + .navbar.is-primary .navbar-end .navbar-link:focus, + .navbar.is-primary .navbar-end .navbar-link:hover, + .navbar.is-primary .navbar-end .navbar-link.is-active { + background-color: #00b89c; + color: #fff; } + .navbar.is-primary .navbar-start .navbar-link::after, + .navbar.is-primary .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-primary .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #00b89c; + color: #fff; } + .navbar.is-primary .navbar-dropdown a.navbar-item.is-active { + background-color: #00d1b2; + color: #fff; } } + .navbar.is-link { + background-color: #3273dc; + color: #fff; } + .navbar.is-link .navbar-brand > .navbar-item, + .navbar.is-link .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-link .navbar-brand > a.navbar-item:focus, .navbar.is-link .navbar-brand > a.navbar-item:hover, .navbar.is-link .navbar-brand > a.navbar-item.is-active, + .navbar.is-link .navbar-brand .navbar-link:focus, + .navbar.is-link .navbar-brand .navbar-link:hover, + .navbar.is-link .navbar-brand .navbar-link.is-active { + background-color: #2366d1; + color: #fff; } + .navbar.is-link .navbar-brand .navbar-link::after { + border-color: #fff; } + .navbar.is-link .navbar-burger { + color: #fff; } + @media screen and (min-width: 1024px) { + .navbar.is-link .navbar-start > .navbar-item, + .navbar.is-link .navbar-start .navbar-link, + .navbar.is-link .navbar-end > .navbar-item, + .navbar.is-link .navbar-end .navbar-link { + color: #fff; } + .navbar.is-link .navbar-start > a.navbar-item:focus, .navbar.is-link .navbar-start > a.navbar-item:hover, .navbar.is-link .navbar-start > a.navbar-item.is-active, + .navbar.is-link .navbar-start .navbar-link:focus, + .navbar.is-link .navbar-start .navbar-link:hover, + .navbar.is-link .navbar-start .navbar-link.is-active, + .navbar.is-link .navbar-end > a.navbar-item:focus, + .navbar.is-link .navbar-end > a.navbar-item:hover, + .navbar.is-link .navbar-end > a.navbar-item.is-active, + .navbar.is-link .navbar-end .navbar-link:focus, + .navbar.is-link .navbar-end .navbar-link:hover, + .navbar.is-link .navbar-end .navbar-link.is-active { + background-color: #2366d1; + color: #fff; } + .navbar.is-link .navbar-start .navbar-link::after, + .navbar.is-link .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-link .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-link .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #2366d1; + color: #fff; } + .navbar.is-link .navbar-dropdown a.navbar-item.is-active { + background-color: #3273dc; + color: #fff; } } + .navbar.is-info { + background-color: #3298dc; + color: #fff; } + .navbar.is-info .navbar-brand > .navbar-item, + .navbar.is-info .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-info .navbar-brand > a.navbar-item:focus, .navbar.is-info .navbar-brand > a.navbar-item:hover, .navbar.is-info .navbar-brand > a.navbar-item.is-active, + .navbar.is-info .navbar-brand .navbar-link:focus, + .navbar.is-info .navbar-brand .navbar-link:hover, + .navbar.is-info .navbar-brand .navbar-link.is-active { + background-color: #238cd1; + color: #fff; } + .navbar.is-info .navbar-brand .navbar-link::after { + border-color: #fff; } + .navbar.is-info .navbar-burger { + color: #fff; } + @media screen and (min-width: 1024px) { + .navbar.is-info .navbar-start > .navbar-item, + .navbar.is-info .navbar-start .navbar-link, + .navbar.is-info .navbar-end > .navbar-item, + .navbar.is-info .navbar-end .navbar-link { + color: #fff; } + .navbar.is-info .navbar-start > a.navbar-item:focus, .navbar.is-info .navbar-start > a.navbar-item:hover, .navbar.is-info .navbar-start > a.navbar-item.is-active, + .navbar.is-info .navbar-start .navbar-link:focus, + .navbar.is-info .navbar-start .navbar-link:hover, + .navbar.is-info .navbar-start .navbar-link.is-active, + .navbar.is-info .navbar-end > a.navbar-item:focus, + .navbar.is-info .navbar-end > a.navbar-item:hover, + .navbar.is-info .navbar-end > a.navbar-item.is-active, + .navbar.is-info .navbar-end .navbar-link:focus, + .navbar.is-info .navbar-end .navbar-link:hover, + .navbar.is-info .navbar-end .navbar-link.is-active { + background-color: #238cd1; + color: #fff; } + .navbar.is-info .navbar-start .navbar-link::after, + .navbar.is-info .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-info .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-info .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #238cd1; + color: #fff; } + .navbar.is-info .navbar-dropdown a.navbar-item.is-active { + background-color: #3298dc; + color: #fff; } } + .navbar.is-success { + background-color: #48c774; + color: #fff; } + .navbar.is-success .navbar-brand > .navbar-item, + .navbar.is-success .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-success .navbar-brand > a.navbar-item:focus, .navbar.is-success .navbar-brand > a.navbar-item:hover, .navbar.is-success .navbar-brand > a.navbar-item.is-active, + .navbar.is-success .navbar-brand .navbar-link:focus, + .navbar.is-success .navbar-brand .navbar-link:hover, + .navbar.is-success .navbar-brand .navbar-link.is-active { + background-color: #3abb67; + color: #fff; } + .navbar.is-success .navbar-brand .navbar-link::after { + border-color: #fff; } + .navbar.is-success .navbar-burger { + color: #fff; } + @media screen and (min-width: 1024px) { + .navbar.is-success .navbar-start > .navbar-item, + .navbar.is-success .navbar-start .navbar-link, + .navbar.is-success .navbar-end > .navbar-item, + .navbar.is-success .navbar-end .navbar-link { + color: #fff; } + .navbar.is-success .navbar-start > a.navbar-item:focus, .navbar.is-success .navbar-start > a.navbar-item:hover, .navbar.is-success .navbar-start > a.navbar-item.is-active, + .navbar.is-success .navbar-start .navbar-link:focus, + .navbar.is-success .navbar-start .navbar-link:hover, + .navbar.is-success .navbar-start .navbar-link.is-active, + .navbar.is-success .navbar-end > a.navbar-item:focus, + .navbar.is-success .navbar-end > a.navbar-item:hover, + .navbar.is-success .navbar-end > a.navbar-item.is-active, + .navbar.is-success .navbar-end .navbar-link:focus, + .navbar.is-success .navbar-end .navbar-link:hover, + .navbar.is-success .navbar-end .navbar-link.is-active { + background-color: #3abb67; + color: #fff; } + .navbar.is-success .navbar-start .navbar-link::after, + .navbar.is-success .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-success .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-success .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #3abb67; + color: #fff; } + .navbar.is-success .navbar-dropdown a.navbar-item.is-active { + background-color: #48c774; + color: #fff; } } + .navbar.is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-brand > .navbar-item, + .navbar.is-warning .navbar-brand .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-brand > a.navbar-item:focus, .navbar.is-warning .navbar-brand > a.navbar-item:hover, .navbar.is-warning .navbar-brand > a.navbar-item.is-active, + .navbar.is-warning .navbar-brand .navbar-link:focus, + .navbar.is-warning .navbar-brand .navbar-link:hover, + .navbar.is-warning .navbar-brand .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-brand .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-burger { + color: rgba(0, 0, 0, 0.7); } + @media screen and (min-width: 1024px) { + .navbar.is-warning .navbar-start > .navbar-item, + .navbar.is-warning .navbar-start .navbar-link, + .navbar.is-warning .navbar-end > .navbar-item, + .navbar.is-warning .navbar-end .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-start > a.navbar-item:focus, .navbar.is-warning .navbar-start > a.navbar-item:hover, .navbar.is-warning .navbar-start > a.navbar-item.is-active, + .navbar.is-warning .navbar-start .navbar-link:focus, + .navbar.is-warning .navbar-start .navbar-link:hover, + .navbar.is-warning .navbar-start .navbar-link.is-active, + .navbar.is-warning .navbar-end > a.navbar-item:focus, + .navbar.is-warning .navbar-end > a.navbar-item:hover, + .navbar.is-warning .navbar-end > a.navbar-item.is-active, + .navbar.is-warning .navbar-end .navbar-link:focus, + .navbar.is-warning .navbar-end .navbar-link:hover, + .navbar.is-warning .navbar-end .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-start .navbar-link::after, + .navbar.is-warning .navbar-end .navbar-link::after { + border-color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-dropdown a.navbar-item.is-active { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } } + .navbar.is-danger { + background-color: #f14668; + color: #fff; } + .navbar.is-danger .navbar-brand > .navbar-item, + .navbar.is-danger .navbar-brand .navbar-link { + color: #fff; } + .navbar.is-danger .navbar-brand > a.navbar-item:focus, .navbar.is-danger .navbar-brand > a.navbar-item:hover, .navbar.is-danger .navbar-brand > a.navbar-item.is-active, + .navbar.is-danger .navbar-brand .navbar-link:focus, + .navbar.is-danger .navbar-brand .navbar-link:hover, + .navbar.is-danger .navbar-brand .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; } + .navbar.is-danger .navbar-brand .navbar-link::after { + border-color: #fff; } + .navbar.is-danger .navbar-burger { + color: #fff; } + @media screen and (min-width: 1024px) { + .navbar.is-danger .navbar-start > .navbar-item, + .navbar.is-danger .navbar-start .navbar-link, + .navbar.is-danger .navbar-end > .navbar-item, + .navbar.is-danger .navbar-end .navbar-link { + color: #fff; } + .navbar.is-danger .navbar-start > a.navbar-item:focus, .navbar.is-danger .navbar-start > a.navbar-item:hover, .navbar.is-danger .navbar-start > a.navbar-item.is-active, + .navbar.is-danger .navbar-start .navbar-link:focus, + .navbar.is-danger .navbar-start .navbar-link:hover, + .navbar.is-danger .navbar-start .navbar-link.is-active, + .navbar.is-danger .navbar-end > a.navbar-item:focus, + .navbar.is-danger .navbar-end > a.navbar-item:hover, + .navbar.is-danger .navbar-end > a.navbar-item.is-active, + .navbar.is-danger .navbar-end .navbar-link:focus, + .navbar.is-danger .navbar-end .navbar-link:hover, + .navbar.is-danger .navbar-end .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; } + .navbar.is-danger .navbar-start .navbar-link::after, + .navbar.is-danger .navbar-end .navbar-link::after { + border-color: #fff; } + .navbar.is-danger .navbar-item.has-dropdown:focus .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link, + .navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #ef2e55; + color: #fff; } + .navbar.is-danger .navbar-dropdown a.navbar-item.is-active { + background-color: #f14668; + color: #fff; } } + .navbar > .container { + align-items: stretch; + display: flex; + min-height: 3.25rem; + width: 100%; } + .navbar.has-shadow { + box-shadow: 0 2px 0 0 whitesmoke; } + .navbar.is-fixed-bottom, .navbar.is-fixed-top { + left: 0; + position: fixed; + right: 0; + z-index: 30; } + .navbar.is-fixed-bottom { + bottom: 0; } + .navbar.is-fixed-bottom.has-shadow { + box-shadow: 0 -2px 0 0 whitesmoke; } + .navbar.is-fixed-top { + top: 0; } + +html.has-navbar-fixed-top, +body.has-navbar-fixed-top { + padding-top: 3.25rem; } + +html.has-navbar-fixed-bottom, +body.has-navbar-fixed-bottom { + padding-bottom: 3.25rem; } + +.navbar-brand, +.navbar-tabs { + align-items: stretch; + display: flex; + flex-shrink: 0; + min-height: 3.25rem; } + +.navbar-brand a.navbar-item:focus, .navbar-brand a.navbar-item:hover { + background-color: transparent; } + +.navbar-tabs { + -webkit-overflow-scrolling: touch; + max-width: 100vw; + overflow-x: auto; + overflow-y: hidden; } + +.navbar-burger { + color: #4a4a4a; + cursor: pointer; + display: block; + height: 3.25rem; + position: relative; + width: 3.25rem; + margin-left: auto; } + .navbar-burger span { + background-color: currentColor; + display: block; + height: 1px; + left: calc(50% - 8px); + position: absolute; + transform-origin: center; + transition-duration: 86ms; + transition-property: background-color, opacity, transform; + transition-timing-function: ease-out; + width: 16px; } + .navbar-burger span:nth-child(1) { + top: calc(50% - 6px); } + .navbar-burger span:nth-child(2) { + top: calc(50% - 1px); } + .navbar-burger span:nth-child(3) { + top: calc(50% + 4px); } + .navbar-burger:hover { + background-color: rgba(0, 0, 0, 0.05); } + .navbar-burger.is-active span:nth-child(1) { + transform: translateY(5px) rotate(45deg); } + .navbar-burger.is-active span:nth-child(2) { + opacity: 0; } + .navbar-burger.is-active span:nth-child(3) { + transform: translateY(-5px) rotate(-45deg); } + +.navbar-menu { + display: none; } + +.navbar-item, +.navbar-link { + color: #4a4a4a; + display: block; + line-height: 1.5; + padding: 0.5rem 0.75rem; + position: relative; } + .navbar-item .icon:only-child, + .navbar-link .icon:only-child { + margin-left: -0.25rem; + margin-right: -0.25rem; } + +a.navbar-item, +.navbar-link { + cursor: pointer; } + a.navbar-item:focus, a.navbar-item:focus-within, a.navbar-item:hover, a.navbar-item.is-active, + .navbar-link:focus, + .navbar-link:focus-within, + .navbar-link:hover, + .navbar-link.is-active { + background-color: #fafafa; + color: #3273dc; } + +.navbar-item { + flex-grow: 0; + flex-shrink: 0; } + .navbar-item img { + max-height: 1.75rem; } + .navbar-item.has-dropdown { + padding: 0; } + .navbar-item.is-expanded { + flex-grow: 1; + flex-shrink: 1; } + .navbar-item.is-tab { + border-bottom: 1px solid transparent; + min-height: 3.25rem; + padding-bottom: calc(0.5rem - 1px); } + .navbar-item.is-tab:focus, .navbar-item.is-tab:hover { + background-color: transparent; + border-bottom-color: #3273dc; } + .navbar-item.is-tab.is-active { + background-color: transparent; + border-bottom-color: #3273dc; + border-bottom-style: solid; + border-bottom-width: 3px; + color: #3273dc; + padding-bottom: calc(0.5rem - 3px); } + +.navbar-content { + flex-grow: 1; + flex-shrink: 1; } + +.navbar-link:not(.is-arrowless) { + padding-right: 2.5em; } + .navbar-link:not(.is-arrowless)::after { + border-color: #3273dc; + margin-top: -0.375em; + right: 1.125em; } + +.navbar-dropdown { + font-size: 0.875rem; + padding-bottom: 0.5rem; + padding-top: 0.5rem; } + .navbar-dropdown .navbar-item { + padding-left: 1.5rem; + padding-right: 1.5rem; } + +.navbar-divider { + background-color: whitesmoke; + border: none; + display: none; + height: 2px; + margin: 0.5rem 0; } + +@media screen and (max-width: 1023px) { + .navbar > .container { + display: block; } + .navbar-brand .navbar-item, + .navbar-tabs .navbar-item { + align-items: center; + display: flex; } + .navbar-link::after { + display: none; } + .navbar-menu { + background-color: white; + box-shadow: 0 8px 16px rgba(10, 10, 10, 0.1); + padding: 0.5rem 0; } + .navbar-menu.is-active { + display: block; } + .navbar.is-fixed-bottom-touch, .navbar.is-fixed-top-touch { + left: 0; + position: fixed; + right: 0; + z-index: 30; } + .navbar.is-fixed-bottom-touch { + bottom: 0; } + .navbar.is-fixed-bottom-touch.has-shadow { + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); } + .navbar.is-fixed-top-touch { + top: 0; } + .navbar.is-fixed-top .navbar-menu, .navbar.is-fixed-top-touch .navbar-menu { + -webkit-overflow-scrolling: touch; + max-height: calc(100vh - 3.25rem); + overflow: auto; } + html.has-navbar-fixed-top-touch, + body.has-navbar-fixed-top-touch { + padding-top: 3.25rem; } + html.has-navbar-fixed-bottom-touch, + body.has-navbar-fixed-bottom-touch { + padding-bottom: 3.25rem; } } + +@media screen and (min-width: 1024px) { + .navbar, + .navbar-menu, + .navbar-start, + .navbar-end { + align-items: stretch; + display: flex; } + .navbar { + min-height: 3.25rem; } + .navbar.is-spaced { + padding: 1rem 2rem; } + .navbar.is-spaced .navbar-start, + .navbar.is-spaced .navbar-end { + align-items: center; } + .navbar.is-spaced a.navbar-item, + .navbar.is-spaced .navbar-link { + border-radius: 4px; } + .navbar.is-transparent a.navbar-item:focus, .navbar.is-transparent a.navbar-item:hover, .navbar.is-transparent a.navbar-item.is-active, + .navbar.is-transparent .navbar-link:focus, + .navbar.is-transparent .navbar-link:hover, + .navbar.is-transparent .navbar-link.is-active { + background-color: transparent !important; } + .navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:focus-within .navbar-link, .navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link { + background-color: transparent !important; } + .navbar.is-transparent .navbar-dropdown a.navbar-item:focus, .navbar.is-transparent .navbar-dropdown a.navbar-item:hover { + background-color: whitesmoke; + color: #0a0a0a; } + .navbar.is-transparent .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #3273dc; } + .navbar-burger { + display: none; } + .navbar-item, + .navbar-link { + align-items: center; + display: flex; } + .navbar-item.has-dropdown { + align-items: stretch; } + .navbar-item.has-dropdown-up .navbar-link::after { + transform: rotate(135deg) translate(0.25em, -0.25em); } + .navbar-item.has-dropdown-up .navbar-dropdown { + border-bottom: 2px solid #dbdbdb; + border-radius: 6px 6px 0 0; + border-top: none; + bottom: 100%; + box-shadow: 0 -8px 8px rgba(10, 10, 10, 0.1); + top: auto; } + .navbar-item.is-active .navbar-dropdown, .navbar-item.is-hoverable:focus .navbar-dropdown, .navbar-item.is-hoverable:focus-within .navbar-dropdown, .navbar-item.is-hoverable:hover .navbar-dropdown { + display: block; } + .navbar.is-spaced .navbar-item.is-active .navbar-dropdown, .navbar-item.is-active .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:focus .navbar-dropdown, .navbar-item.is-hoverable:focus .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:focus-within .navbar-dropdown, .navbar-item.is-hoverable:focus-within .navbar-dropdown.is-boxed, .navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown, .navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed { + opacity: 1; + pointer-events: auto; + transform: translateY(0); } + .navbar-menu { + flex-grow: 1; + flex-shrink: 0; } + .navbar-start { + justify-content: flex-start; + margin-right: auto; } + .navbar-end { + justify-content: flex-end; + margin-left: auto; } + .navbar-dropdown { + background-color: white; + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; + border-top: 2px solid #dbdbdb; + box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1); + display: none; + font-size: 0.875rem; + left: 0; + min-width: 100%; + position: absolute; + top: 100%; + z-index: 20; } + .navbar-dropdown .navbar-item { + padding: 0.375rem 1rem; + white-space: nowrap; } + .navbar-dropdown a.navbar-item { + padding-right: 3rem; } + .navbar-dropdown a.navbar-item:focus, .navbar-dropdown a.navbar-item:hover { + background-color: whitesmoke; + color: #0a0a0a; } + .navbar-dropdown a.navbar-item.is-active { + background-color: whitesmoke; + color: #3273dc; } + .navbar.is-spaced .navbar-dropdown, .navbar-dropdown.is-boxed { + border-radius: 6px; + border-top: none; + box-shadow: 0 8px 8px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); + display: block; + opacity: 0; + pointer-events: none; + top: calc(100% + (-4px)); + transform: translateY(-5px); + transition-duration: 86ms; + transition-property: opacity, transform; } + .navbar-dropdown.is-right { + left: auto; + right: 0; } + .navbar-divider { + display: block; } + .navbar > .container .navbar-brand, + .container > .navbar .navbar-brand { + margin-left: -0.75rem; } + .navbar > .container .navbar-menu, + .container > .navbar .navbar-menu { + margin-right: -0.75rem; } + .navbar.is-fixed-bottom-desktop, .navbar.is-fixed-top-desktop { + left: 0; + position: fixed; + right: 0; + z-index: 30; } + .navbar.is-fixed-bottom-desktop { + bottom: 0; } + .navbar.is-fixed-bottom-desktop.has-shadow { + box-shadow: 0 -2px 3px rgba(10, 10, 10, 0.1); } + .navbar.is-fixed-top-desktop { + top: 0; } + html.has-navbar-fixed-top-desktop, + body.has-navbar-fixed-top-desktop { + padding-top: 3.25rem; } + html.has-navbar-fixed-bottom-desktop, + body.has-navbar-fixed-bottom-desktop { + padding-bottom: 3.25rem; } + html.has-spaced-navbar-fixed-top, + body.has-spaced-navbar-fixed-top { + padding-top: 5.25rem; } + html.has-spaced-navbar-fixed-bottom, + body.has-spaced-navbar-fixed-bottom { + padding-bottom: 5.25rem; } + a.navbar-item.is-active, + .navbar-link.is-active { + color: #0a0a0a; } + a.navbar-item.is-active:not(:focus):not(:hover), + .navbar-link.is-active:not(:focus):not(:hover) { + background-color: transparent; } + .navbar-item.has-dropdown:focus .navbar-link, .navbar-item.has-dropdown:hover .navbar-link, .navbar-item.has-dropdown.is-active .navbar-link { + background-color: #fafafa; } } + +.hero.is-fullheight-with-navbar { + min-height: calc(100vh - 3.25rem); } + +.pagination { + font-size: 1rem; + margin: -0.25rem; } + .pagination.is-small { + font-size: 0.75rem; } + .pagination.is-medium { + font-size: 1.25rem; } + .pagination.is-large { + font-size: 1.5rem; } + .pagination.is-rounded .pagination-previous, + .pagination.is-rounded .pagination-next { + padding-left: 1em; + padding-right: 1em; + border-radius: 290486px; } + .pagination.is-rounded .pagination-link { + border-radius: 290486px; } + +.pagination, +.pagination-list { + align-items: center; + display: flex; + justify-content: center; + text-align: center; } + +.pagination-previous, +.pagination-next, +.pagination-link, +.pagination-ellipsis { + font-size: 1em; + justify-content: center; + margin: 0.25rem; + padding-left: 0.5em; + padding-right: 0.5em; + text-align: center; } + +.pagination-previous, +.pagination-next, +.pagination-link { + border-color: #dbdbdb; + color: #363636; + min-width: 2.5em; } + .pagination-previous:hover, + .pagination-next:hover, + .pagination-link:hover { + border-color: #b5b5b5; + color: #363636; } + .pagination-previous:focus, + .pagination-next:focus, + .pagination-link:focus { + border-color: #3273dc; } + .pagination-previous:active, + .pagination-next:active, + .pagination-link:active { + box-shadow: inset 0 1px 2px rgba(10, 10, 10, 0.2); } + .pagination-previous[disabled], + .pagination-next[disabled], + .pagination-link[disabled] { + background-color: #dbdbdb; + border-color: #dbdbdb; + box-shadow: none; + color: #7a7a7a; + opacity: 0.5; } + +.pagination-previous, +.pagination-next { + padding-left: 0.75em; + padding-right: 0.75em; + white-space: nowrap; } + +.pagination-link.is-current { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; } + +.pagination-ellipsis { + color: #b5b5b5; + pointer-events: none; } + +.pagination-list { + flex-wrap: wrap; } + .pagination-list li { + list-style: none; } + +@media screen and (max-width: 768px) { + .pagination { + flex-wrap: wrap; } + .pagination-previous, + .pagination-next { + flex-grow: 1; + flex-shrink: 1; } + .pagination-list li { + flex-grow: 1; + flex-shrink: 1; } } + +@media screen and (min-width: 769px), print { + .pagination-list { + flex-grow: 1; + flex-shrink: 1; + justify-content: flex-start; + order: 1; } + .pagination-previous { + order: 2; } + .pagination-next { + order: 3; } + .pagination { + justify-content: space-between; } + .pagination.is-centered .pagination-previous { + order: 1; } + .pagination.is-centered .pagination-list { + justify-content: center; + order: 2; } + .pagination.is-centered .pagination-next { + order: 3; } + .pagination.is-right .pagination-previous { + order: 1; } + .pagination.is-right .pagination-next { + order: 2; } + .pagination.is-right .pagination-list { + justify-content: flex-end; + order: 3; } } + +.panel { + border-radius: 6px; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0px 0 1px rgba(10, 10, 10, 0.02); + font-size: 1rem; } + .panel:not(:last-child) { + margin-bottom: 1.5rem; } + .panel.is-white .panel-heading { + background-color: white; + color: #0a0a0a; } + .panel.is-white .panel-tabs a.is-active { + border-bottom-color: white; } + .panel.is-white .panel-block.is-active .panel-icon { + color: white; } + .panel.is-black .panel-heading { + background-color: #0a0a0a; + color: white; } + .panel.is-black .panel-tabs a.is-active { + border-bottom-color: #0a0a0a; } + .panel.is-black .panel-block.is-active .panel-icon { + color: #0a0a0a; } + .panel.is-light .panel-heading { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .panel.is-light .panel-tabs a.is-active { + border-bottom-color: whitesmoke; } + .panel.is-light .panel-block.is-active .panel-icon { + color: whitesmoke; } + .panel.is-dark .panel-heading { + background-color: #363636; + color: #fff; } + .panel.is-dark .panel-tabs a.is-active { + border-bottom-color: #363636; } + .panel.is-dark .panel-block.is-active .panel-icon { + color: #363636; } + .panel.is-primary .panel-heading { + background-color: #00d1b2; + color: #fff; } + .panel.is-primary .panel-tabs a.is-active { + border-bottom-color: #00d1b2; } + .panel.is-primary .panel-block.is-active .panel-icon { + color: #00d1b2; } + .panel.is-link .panel-heading { + background-color: #3273dc; + color: #fff; } + .panel.is-link .panel-tabs a.is-active { + border-bottom-color: #3273dc; } + .panel.is-link .panel-block.is-active .panel-icon { + color: #3273dc; } + .panel.is-info .panel-heading { + background-color: #3298dc; + color: #fff; } + .panel.is-info .panel-tabs a.is-active { + border-bottom-color: #3298dc; } + .panel.is-info .panel-block.is-active .panel-icon { + color: #3298dc; } + .panel.is-success .panel-heading { + background-color: #48c774; + color: #fff; } + .panel.is-success .panel-tabs a.is-active { + border-bottom-color: #48c774; } + .panel.is-success .panel-block.is-active .panel-icon { + color: #48c774; } + .panel.is-warning .panel-heading { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .panel.is-warning .panel-tabs a.is-active { + border-bottom-color: #ffdd57; } + .panel.is-warning .panel-block.is-active .panel-icon { + color: #ffdd57; } + .panel.is-danger .panel-heading { + background-color: #f14668; + color: #fff; } + .panel.is-danger .panel-tabs a.is-active { + border-bottom-color: #f14668; } + .panel.is-danger .panel-block.is-active .panel-icon { + color: #f14668; } + +.panel-tabs:not(:last-child), +.panel-block:not(:last-child) { + border-bottom: 1px solid #ededed; } + +.panel-heading { + background-color: #ededed; + border-radius: 6px 6px 0 0; + color: #363636; + font-size: 1.25em; + font-weight: 700; + line-height: 1.25; + padding: 0.75em 1em; } + +.panel-tabs { + align-items: flex-end; + display: flex; + font-size: 0.875em; + justify-content: center; } + .panel-tabs a { + border-bottom: 1px solid #dbdbdb; + margin-bottom: -1px; + padding: 0.5em; } + .panel-tabs a.is-active { + border-bottom-color: #4a4a4a; + color: #363636; } + +.panel-list a { + color: #4a4a4a; } + .panel-list a:hover { + color: #3273dc; } + +.panel-block { + align-items: center; + color: #363636; + display: flex; + justify-content: flex-start; + padding: 0.5em 0.75em; } + .panel-block input[type="checkbox"] { + margin-right: 0.75em; } + .panel-block > .control { + flex-grow: 1; + flex-shrink: 1; + width: 100%; } + .panel-block.is-wrapped { + flex-wrap: wrap; } + .panel-block.is-active { + border-left-color: #3273dc; + color: #363636; } + .panel-block.is-active .panel-icon { + color: #3273dc; } + .panel-block:last-child { + border-bottom-left-radius: 6px; + border-bottom-right-radius: 6px; } + +a.panel-block, +label.panel-block { + cursor: pointer; } + a.panel-block:hover, + label.panel-block:hover { + background-color: whitesmoke; } + +.panel-icon { + display: inline-block; + font-size: 14px; + height: 1em; + line-height: 1em; + text-align: center; + vertical-align: top; + width: 1em; + color: #7a7a7a; + margin-right: 0.75em; } + .panel-icon .fa { + font-size: inherit; + line-height: inherit; } + +.tabs { + -webkit-overflow-scrolling: touch; + align-items: stretch; + display: flex; + font-size: 1rem; + justify-content: space-between; + overflow: hidden; + overflow-x: auto; + white-space: nowrap; } + .tabs a { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + color: #4a4a4a; + display: flex; + justify-content: center; + margin-bottom: -1px; + padding: 0.5em 1em; + vertical-align: top; } + .tabs a:hover { + border-bottom-color: #363636; + color: #363636; } + .tabs li { + display: block; } + .tabs li.is-active a { + border-bottom-color: #3273dc; + color: #3273dc; } + .tabs ul { + align-items: center; + border-bottom-color: #dbdbdb; + border-bottom-style: solid; + border-bottom-width: 1px; + display: flex; + flex-grow: 1; + flex-shrink: 0; + justify-content: flex-start; } + .tabs ul.is-left { + padding-right: 0.75em; } + .tabs ul.is-center { + flex: none; + justify-content: center; + padding-left: 0.75em; + padding-right: 0.75em; } + .tabs ul.is-right { + justify-content: flex-end; + padding-left: 0.75em; } + .tabs .icon:first-child { + margin-right: 0.5em; } + .tabs .icon:last-child { + margin-left: 0.5em; } + .tabs.is-centered ul { + justify-content: center; } + .tabs.is-right ul { + justify-content: flex-end; } + .tabs.is-boxed a { + border: 1px solid transparent; + border-radius: 4px 4px 0 0; } + .tabs.is-boxed a:hover { + background-color: whitesmoke; + border-bottom-color: #dbdbdb; } + .tabs.is-boxed li.is-active a { + background-color: white; + border-color: #dbdbdb; + border-bottom-color: transparent !important; } + .tabs.is-fullwidth li { + flex-grow: 1; + flex-shrink: 0; } + .tabs.is-toggle a { + border-color: #dbdbdb; + border-style: solid; + border-width: 1px; + margin-bottom: 0; + position: relative; } + .tabs.is-toggle a:hover { + background-color: whitesmoke; + border-color: #b5b5b5; + z-index: 2; } + .tabs.is-toggle li + li { + margin-left: -1px; } + .tabs.is-toggle li:first-child a { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; } + .tabs.is-toggle li:last-child a { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; } + .tabs.is-toggle li.is-active a { + background-color: #3273dc; + border-color: #3273dc; + color: #fff; + z-index: 1; } + .tabs.is-toggle ul { + border-bottom: none; } + .tabs.is-toggle.is-toggle-rounded li:first-child a { + border-bottom-left-radius: 290486px; + border-top-left-radius: 290486px; + padding-left: 1.25em; } + .tabs.is-toggle.is-toggle-rounded li:last-child a { + border-bottom-right-radius: 290486px; + border-top-right-radius: 290486px; + padding-right: 1.25em; } + .tabs.is-small { + font-size: 0.75rem; } + .tabs.is-medium { + font-size: 1.25rem; } + .tabs.is-large { + font-size: 1.5rem; } + +/* Bulma Grid */ +.column { + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + padding: 0.75rem; } + .columns.is-mobile > .column.is-narrow { + flex: none; + width: unset; } + .columns.is-mobile > .column.is-full { + flex: none; + width: 100%; } + .columns.is-mobile > .column.is-three-quarters { + flex: none; + width: 75%; } + .columns.is-mobile > .column.is-two-thirds { + flex: none; + width: 66.6666%; } + .columns.is-mobile > .column.is-half { + flex: none; + width: 50%; } + .columns.is-mobile > .column.is-one-third { + flex: none; + width: 33.3333%; } + .columns.is-mobile > .column.is-one-quarter { + flex: none; + width: 25%; } + .columns.is-mobile > .column.is-one-fifth { + flex: none; + width: 20%; } + .columns.is-mobile > .column.is-two-fifths { + flex: none; + width: 40%; } + .columns.is-mobile > .column.is-three-fifths { + flex: none; + width: 60%; } + .columns.is-mobile > .column.is-four-fifths { + flex: none; + width: 80%; } + .columns.is-mobile > .column.is-offset-three-quarters { + margin-left: 75%; } + .columns.is-mobile > .column.is-offset-two-thirds { + margin-left: 66.6666%; } + .columns.is-mobile > .column.is-offset-half { + margin-left: 50%; } + .columns.is-mobile > .column.is-offset-one-third { + margin-left: 33.3333%; } + .columns.is-mobile > .column.is-offset-one-quarter { + margin-left: 25%; } + .columns.is-mobile > .column.is-offset-one-fifth { + margin-left: 20%; } + .columns.is-mobile > .column.is-offset-two-fifths { + margin-left: 40%; } + .columns.is-mobile > .column.is-offset-three-fifths { + margin-left: 60%; } + .columns.is-mobile > .column.is-offset-four-fifths { + margin-left: 80%; } + .columns.is-mobile > .column.is-0 { + flex: none; + width: 0%; } + .columns.is-mobile > .column.is-offset-0 { + margin-left: 0%; } + .columns.is-mobile > .column.is-1 { + flex: none; + width: 8.33333%; } + .columns.is-mobile > .column.is-offset-1 { + margin-left: 8.33333%; } + .columns.is-mobile > .column.is-2 { + flex: none; + width: 16.66667%; } + .columns.is-mobile > .column.is-offset-2 { + margin-left: 16.66667%; } + .columns.is-mobile > .column.is-3 { + flex: none; + width: 25%; } + .columns.is-mobile > .column.is-offset-3 { + margin-left: 25%; } + .columns.is-mobile > .column.is-4 { + flex: none; + width: 33.33333%; } + .columns.is-mobile > .column.is-offset-4 { + margin-left: 33.33333%; } + .columns.is-mobile > .column.is-5 { + flex: none; + width: 41.66667%; } + .columns.is-mobile > .column.is-offset-5 { + margin-left: 41.66667%; } + .columns.is-mobile > .column.is-6 { + flex: none; + width: 50%; } + .columns.is-mobile > .column.is-offset-6 { + margin-left: 50%; } + .columns.is-mobile > .column.is-7 { + flex: none; + width: 58.33333%; } + .columns.is-mobile > .column.is-offset-7 { + margin-left: 58.33333%; } + .columns.is-mobile > .column.is-8 { + flex: none; + width: 66.66667%; } + .columns.is-mobile > .column.is-offset-8 { + margin-left: 66.66667%; } + .columns.is-mobile > .column.is-9 { + flex: none; + width: 75%; } + .columns.is-mobile > .column.is-offset-9 { + margin-left: 75%; } + .columns.is-mobile > .column.is-10 { + flex: none; + width: 83.33333%; } + .columns.is-mobile > .column.is-offset-10 { + margin-left: 83.33333%; } + .columns.is-mobile > .column.is-11 { + flex: none; + width: 91.66667%; } + .columns.is-mobile > .column.is-offset-11 { + margin-left: 91.66667%; } + .columns.is-mobile > .column.is-12 { + flex: none; + width: 100%; } + .columns.is-mobile > .column.is-offset-12 { + margin-left: 100%; } + @media screen and (max-width: 768px) { + .column.is-narrow-mobile { + flex: none; + width: unset; } + .column.is-full-mobile { + flex: none; + width: 100%; } + .column.is-three-quarters-mobile { + flex: none; + width: 75%; } + .column.is-two-thirds-mobile { + flex: none; + width: 66.6666%; } + .column.is-half-mobile { + flex: none; + width: 50%; } + .column.is-one-third-mobile { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-mobile { + flex: none; + width: 25%; } + .column.is-one-fifth-mobile { + flex: none; + width: 20%; } + .column.is-two-fifths-mobile { + flex: none; + width: 40%; } + .column.is-three-fifths-mobile { + flex: none; + width: 60%; } + .column.is-four-fifths-mobile { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-mobile { + margin-left: 75%; } + .column.is-offset-two-thirds-mobile { + margin-left: 66.6666%; } + .column.is-offset-half-mobile { + margin-left: 50%; } + .column.is-offset-one-third-mobile { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-mobile { + margin-left: 25%; } + .column.is-offset-one-fifth-mobile { + margin-left: 20%; } + .column.is-offset-two-fifths-mobile { + margin-left: 40%; } + .column.is-offset-three-fifths-mobile { + margin-left: 60%; } + .column.is-offset-four-fifths-mobile { + margin-left: 80%; } + .column.is-0-mobile { + flex: none; + width: 0%; } + .column.is-offset-0-mobile { + margin-left: 0%; } + .column.is-1-mobile { + flex: none; + width: 8.33333%; } + .column.is-offset-1-mobile { + margin-left: 8.33333%; } + .column.is-2-mobile { + flex: none; + width: 16.66667%; } + .column.is-offset-2-mobile { + margin-left: 16.66667%; } + .column.is-3-mobile { + flex: none; + width: 25%; } + .column.is-offset-3-mobile { + margin-left: 25%; } + .column.is-4-mobile { + flex: none; + width: 33.33333%; } + .column.is-offset-4-mobile { + margin-left: 33.33333%; } + .column.is-5-mobile { + flex: none; + width: 41.66667%; } + .column.is-offset-5-mobile { + margin-left: 41.66667%; } + .column.is-6-mobile { + flex: none; + width: 50%; } + .column.is-offset-6-mobile { + margin-left: 50%; } + .column.is-7-mobile { + flex: none; + width: 58.33333%; } + .column.is-offset-7-mobile { + margin-left: 58.33333%; } + .column.is-8-mobile { + flex: none; + width: 66.66667%; } + .column.is-offset-8-mobile { + margin-left: 66.66667%; } + .column.is-9-mobile { + flex: none; + width: 75%; } + .column.is-offset-9-mobile { + margin-left: 75%; } + .column.is-10-mobile { + flex: none; + width: 83.33333%; } + .column.is-offset-10-mobile { + margin-left: 83.33333%; } + .column.is-11-mobile { + flex: none; + width: 91.66667%; } + .column.is-offset-11-mobile { + margin-left: 91.66667%; } + .column.is-12-mobile { + flex: none; + width: 100%; } + .column.is-offset-12-mobile { + margin-left: 100%; } } + @media screen and (min-width: 769px), print { + .column.is-narrow, .column.is-narrow-tablet { + flex: none; + width: unset; } + .column.is-full, .column.is-full-tablet { + flex: none; + width: 100%; } + .column.is-three-quarters, .column.is-three-quarters-tablet { + flex: none; + width: 75%; } + .column.is-two-thirds, .column.is-two-thirds-tablet { + flex: none; + width: 66.6666%; } + .column.is-half, .column.is-half-tablet { + flex: none; + width: 50%; } + .column.is-one-third, .column.is-one-third-tablet { + flex: none; + width: 33.3333%; } + .column.is-one-quarter, .column.is-one-quarter-tablet { + flex: none; + width: 25%; } + .column.is-one-fifth, .column.is-one-fifth-tablet { + flex: none; + width: 20%; } + .column.is-two-fifths, .column.is-two-fifths-tablet { + flex: none; + width: 40%; } + .column.is-three-fifths, .column.is-three-fifths-tablet { + flex: none; + width: 60%; } + .column.is-four-fifths, .column.is-four-fifths-tablet { + flex: none; + width: 80%; } + .column.is-offset-three-quarters, .column.is-offset-three-quarters-tablet { + margin-left: 75%; } + .column.is-offset-two-thirds, .column.is-offset-two-thirds-tablet { + margin-left: 66.6666%; } + .column.is-offset-half, .column.is-offset-half-tablet { + margin-left: 50%; } + .column.is-offset-one-third, .column.is-offset-one-third-tablet { + margin-left: 33.3333%; } + .column.is-offset-one-quarter, .column.is-offset-one-quarter-tablet { + margin-left: 25%; } + .column.is-offset-one-fifth, .column.is-offset-one-fifth-tablet { + margin-left: 20%; } + .column.is-offset-two-fifths, .column.is-offset-two-fifths-tablet { + margin-left: 40%; } + .column.is-offset-three-fifths, .column.is-offset-three-fifths-tablet { + margin-left: 60%; } + .column.is-offset-four-fifths, .column.is-offset-four-fifths-tablet { + margin-left: 80%; } + .column.is-0, .column.is-0-tablet { + flex: none; + width: 0%; } + .column.is-offset-0, .column.is-offset-0-tablet { + margin-left: 0%; } + .column.is-1, .column.is-1-tablet { + flex: none; + width: 8.33333%; } + .column.is-offset-1, .column.is-offset-1-tablet { + margin-left: 8.33333%; } + .column.is-2, .column.is-2-tablet { + flex: none; + width: 16.66667%; } + .column.is-offset-2, .column.is-offset-2-tablet { + margin-left: 16.66667%; } + .column.is-3, .column.is-3-tablet { + flex: none; + width: 25%; } + .column.is-offset-3, .column.is-offset-3-tablet { + margin-left: 25%; } + .column.is-4, .column.is-4-tablet { + flex: none; + width: 33.33333%; } + .column.is-offset-4, .column.is-offset-4-tablet { + margin-left: 33.33333%; } + .column.is-5, .column.is-5-tablet { + flex: none; + width: 41.66667%; } + .column.is-offset-5, .column.is-offset-5-tablet { + margin-left: 41.66667%; } + .column.is-6, .column.is-6-tablet { + flex: none; + width: 50%; } + .column.is-offset-6, .column.is-offset-6-tablet { + margin-left: 50%; } + .column.is-7, .column.is-7-tablet { + flex: none; + width: 58.33333%; } + .column.is-offset-7, .column.is-offset-7-tablet { + margin-left: 58.33333%; } + .column.is-8, .column.is-8-tablet { + flex: none; + width: 66.66667%; } + .column.is-offset-8, .column.is-offset-8-tablet { + margin-left: 66.66667%; } + .column.is-9, .column.is-9-tablet { + flex: none; + width: 75%; } + .column.is-offset-9, .column.is-offset-9-tablet { + margin-left: 75%; } + .column.is-10, .column.is-10-tablet { + flex: none; + width: 83.33333%; } + .column.is-offset-10, .column.is-offset-10-tablet { + margin-left: 83.33333%; } + .column.is-11, .column.is-11-tablet { + flex: none; + width: 91.66667%; } + .column.is-offset-11, .column.is-offset-11-tablet { + margin-left: 91.66667%; } + .column.is-12, .column.is-12-tablet { + flex: none; + width: 100%; } + .column.is-offset-12, .column.is-offset-12-tablet { + margin-left: 100%; } } + @media screen and (max-width: 1023px) { + .column.is-narrow-touch { + flex: none; + width: unset; } + .column.is-full-touch { + flex: none; + width: 100%; } + .column.is-three-quarters-touch { + flex: none; + width: 75%; } + .column.is-two-thirds-touch { + flex: none; + width: 66.6666%; } + .column.is-half-touch { + flex: none; + width: 50%; } + .column.is-one-third-touch { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-touch { + flex: none; + width: 25%; } + .column.is-one-fifth-touch { + flex: none; + width: 20%; } + .column.is-two-fifths-touch { + flex: none; + width: 40%; } + .column.is-three-fifths-touch { + flex: none; + width: 60%; } + .column.is-four-fifths-touch { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-touch { + margin-left: 75%; } + .column.is-offset-two-thirds-touch { + margin-left: 66.6666%; } + .column.is-offset-half-touch { + margin-left: 50%; } + .column.is-offset-one-third-touch { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-touch { + margin-left: 25%; } + .column.is-offset-one-fifth-touch { + margin-left: 20%; } + .column.is-offset-two-fifths-touch { + margin-left: 40%; } + .column.is-offset-three-fifths-touch { + margin-left: 60%; } + .column.is-offset-four-fifths-touch { + margin-left: 80%; } + .column.is-0-touch { + flex: none; + width: 0%; } + .column.is-offset-0-touch { + margin-left: 0%; } + .column.is-1-touch { + flex: none; + width: 8.33333%; } + .column.is-offset-1-touch { + margin-left: 8.33333%; } + .column.is-2-touch { + flex: none; + width: 16.66667%; } + .column.is-offset-2-touch { + margin-left: 16.66667%; } + .column.is-3-touch { + flex: none; + width: 25%; } + .column.is-offset-3-touch { + margin-left: 25%; } + .column.is-4-touch { + flex: none; + width: 33.33333%; } + .column.is-offset-4-touch { + margin-left: 33.33333%; } + .column.is-5-touch { + flex: none; + width: 41.66667%; } + .column.is-offset-5-touch { + margin-left: 41.66667%; } + .column.is-6-touch { + flex: none; + width: 50%; } + .column.is-offset-6-touch { + margin-left: 50%; } + .column.is-7-touch { + flex: none; + width: 58.33333%; } + .column.is-offset-7-touch { + margin-left: 58.33333%; } + .column.is-8-touch { + flex: none; + width: 66.66667%; } + .column.is-offset-8-touch { + margin-left: 66.66667%; } + .column.is-9-touch { + flex: none; + width: 75%; } + .column.is-offset-9-touch { + margin-left: 75%; } + .column.is-10-touch { + flex: none; + width: 83.33333%; } + .column.is-offset-10-touch { + margin-left: 83.33333%; } + .column.is-11-touch { + flex: none; + width: 91.66667%; } + .column.is-offset-11-touch { + margin-left: 91.66667%; } + .column.is-12-touch { + flex: none; + width: 100%; } + .column.is-offset-12-touch { + margin-left: 100%; } } + @media screen and (min-width: 1024px) { + .column.is-narrow-desktop { + flex: none; + width: unset; } + .column.is-full-desktop { + flex: none; + width: 100%; } + .column.is-three-quarters-desktop { + flex: none; + width: 75%; } + .column.is-two-thirds-desktop { + flex: none; + width: 66.6666%; } + .column.is-half-desktop { + flex: none; + width: 50%; } + .column.is-one-third-desktop { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-desktop { + flex: none; + width: 25%; } + .column.is-one-fifth-desktop { + flex: none; + width: 20%; } + .column.is-two-fifths-desktop { + flex: none; + width: 40%; } + .column.is-three-fifths-desktop { + flex: none; + width: 60%; } + .column.is-four-fifths-desktop { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-desktop { + margin-left: 75%; } + .column.is-offset-two-thirds-desktop { + margin-left: 66.6666%; } + .column.is-offset-half-desktop { + margin-left: 50%; } + .column.is-offset-one-third-desktop { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-desktop { + margin-left: 25%; } + .column.is-offset-one-fifth-desktop { + margin-left: 20%; } + .column.is-offset-two-fifths-desktop { + margin-left: 40%; } + .column.is-offset-three-fifths-desktop { + margin-left: 60%; } + .column.is-offset-four-fifths-desktop { + margin-left: 80%; } + .column.is-0-desktop { + flex: none; + width: 0%; } + .column.is-offset-0-desktop { + margin-left: 0%; } + .column.is-1-desktop { + flex: none; + width: 8.33333%; } + .column.is-offset-1-desktop { + margin-left: 8.33333%; } + .column.is-2-desktop { + flex: none; + width: 16.66667%; } + .column.is-offset-2-desktop { + margin-left: 16.66667%; } + .column.is-3-desktop { + flex: none; + width: 25%; } + .column.is-offset-3-desktop { + margin-left: 25%; } + .column.is-4-desktop { + flex: none; + width: 33.33333%; } + .column.is-offset-4-desktop { + margin-left: 33.33333%; } + .column.is-5-desktop { + flex: none; + width: 41.66667%; } + .column.is-offset-5-desktop { + margin-left: 41.66667%; } + .column.is-6-desktop { + flex: none; + width: 50%; } + .column.is-offset-6-desktop { + margin-left: 50%; } + .column.is-7-desktop { + flex: none; + width: 58.33333%; } + .column.is-offset-7-desktop { + margin-left: 58.33333%; } + .column.is-8-desktop { + flex: none; + width: 66.66667%; } + .column.is-offset-8-desktop { + margin-left: 66.66667%; } + .column.is-9-desktop { + flex: none; + width: 75%; } + .column.is-offset-9-desktop { + margin-left: 75%; } + .column.is-10-desktop { + flex: none; + width: 83.33333%; } + .column.is-offset-10-desktop { + margin-left: 83.33333%; } + .column.is-11-desktop { + flex: none; + width: 91.66667%; } + .column.is-offset-11-desktop { + margin-left: 91.66667%; } + .column.is-12-desktop { + flex: none; + width: 100%; } + .column.is-offset-12-desktop { + margin-left: 100%; } } + @media screen and (min-width: 1216px) { + .column.is-narrow-widescreen { + flex: none; + width: unset; } + .column.is-full-widescreen { + flex: none; + width: 100%; } + .column.is-three-quarters-widescreen { + flex: none; + width: 75%; } + .column.is-two-thirds-widescreen { + flex: none; + width: 66.6666%; } + .column.is-half-widescreen { + flex: none; + width: 50%; } + .column.is-one-third-widescreen { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-widescreen { + flex: none; + width: 25%; } + .column.is-one-fifth-widescreen { + flex: none; + width: 20%; } + .column.is-two-fifths-widescreen { + flex: none; + width: 40%; } + .column.is-three-fifths-widescreen { + flex: none; + width: 60%; } + .column.is-four-fifths-widescreen { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-widescreen { + margin-left: 75%; } + .column.is-offset-two-thirds-widescreen { + margin-left: 66.6666%; } + .column.is-offset-half-widescreen { + margin-left: 50%; } + .column.is-offset-one-third-widescreen { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-widescreen { + margin-left: 25%; } + .column.is-offset-one-fifth-widescreen { + margin-left: 20%; } + .column.is-offset-two-fifths-widescreen { + margin-left: 40%; } + .column.is-offset-three-fifths-widescreen { + margin-left: 60%; } + .column.is-offset-four-fifths-widescreen { + margin-left: 80%; } + .column.is-0-widescreen { + flex: none; + width: 0%; } + .column.is-offset-0-widescreen { + margin-left: 0%; } + .column.is-1-widescreen { + flex: none; + width: 8.33333%; } + .column.is-offset-1-widescreen { + margin-left: 8.33333%; } + .column.is-2-widescreen { + flex: none; + width: 16.66667%; } + .column.is-offset-2-widescreen { + margin-left: 16.66667%; } + .column.is-3-widescreen { + flex: none; + width: 25%; } + .column.is-offset-3-widescreen { + margin-left: 25%; } + .column.is-4-widescreen { + flex: none; + width: 33.33333%; } + .column.is-offset-4-widescreen { + margin-left: 33.33333%; } + .column.is-5-widescreen { + flex: none; + width: 41.66667%; } + .column.is-offset-5-widescreen { + margin-left: 41.66667%; } + .column.is-6-widescreen { + flex: none; + width: 50%; } + .column.is-offset-6-widescreen { + margin-left: 50%; } + .column.is-7-widescreen { + flex: none; + width: 58.33333%; } + .column.is-offset-7-widescreen { + margin-left: 58.33333%; } + .column.is-8-widescreen { + flex: none; + width: 66.66667%; } + .column.is-offset-8-widescreen { + margin-left: 66.66667%; } + .column.is-9-widescreen { + flex: none; + width: 75%; } + .column.is-offset-9-widescreen { + margin-left: 75%; } + .column.is-10-widescreen { + flex: none; + width: 83.33333%; } + .column.is-offset-10-widescreen { + margin-left: 83.33333%; } + .column.is-11-widescreen { + flex: none; + width: 91.66667%; } + .column.is-offset-11-widescreen { + margin-left: 91.66667%; } + .column.is-12-widescreen { + flex: none; + width: 100%; } + .column.is-offset-12-widescreen { + margin-left: 100%; } } + @media screen and (min-width: 1408px) { + .column.is-narrow-fullhd { + flex: none; + width: unset; } + .column.is-full-fullhd { + flex: none; + width: 100%; } + .column.is-three-quarters-fullhd { + flex: none; + width: 75%; } + .column.is-two-thirds-fullhd { + flex: none; + width: 66.6666%; } + .column.is-half-fullhd { + flex: none; + width: 50%; } + .column.is-one-third-fullhd { + flex: none; + width: 33.3333%; } + .column.is-one-quarter-fullhd { + flex: none; + width: 25%; } + .column.is-one-fifth-fullhd { + flex: none; + width: 20%; } + .column.is-two-fifths-fullhd { + flex: none; + width: 40%; } + .column.is-three-fifths-fullhd { + flex: none; + width: 60%; } + .column.is-four-fifths-fullhd { + flex: none; + width: 80%; } + .column.is-offset-three-quarters-fullhd { + margin-left: 75%; } + .column.is-offset-two-thirds-fullhd { + margin-left: 66.6666%; } + .column.is-offset-half-fullhd { + margin-left: 50%; } + .column.is-offset-one-third-fullhd { + margin-left: 33.3333%; } + .column.is-offset-one-quarter-fullhd { + margin-left: 25%; } + .column.is-offset-one-fifth-fullhd { + margin-left: 20%; } + .column.is-offset-two-fifths-fullhd { + margin-left: 40%; } + .column.is-offset-three-fifths-fullhd { + margin-left: 60%; } + .column.is-offset-four-fifths-fullhd { + margin-left: 80%; } + .column.is-0-fullhd { + flex: none; + width: 0%; } + .column.is-offset-0-fullhd { + margin-left: 0%; } + .column.is-1-fullhd { + flex: none; + width: 8.33333%; } + .column.is-offset-1-fullhd { + margin-left: 8.33333%; } + .column.is-2-fullhd { + flex: none; + width: 16.66667%; } + .column.is-offset-2-fullhd { + margin-left: 16.66667%; } + .column.is-3-fullhd { + flex: none; + width: 25%; } + .column.is-offset-3-fullhd { + margin-left: 25%; } + .column.is-4-fullhd { + flex: none; + width: 33.33333%; } + .column.is-offset-4-fullhd { + margin-left: 33.33333%; } + .column.is-5-fullhd { + flex: none; + width: 41.66667%; } + .column.is-offset-5-fullhd { + margin-left: 41.66667%; } + .column.is-6-fullhd { + flex: none; + width: 50%; } + .column.is-offset-6-fullhd { + margin-left: 50%; } + .column.is-7-fullhd { + flex: none; + width: 58.33333%; } + .column.is-offset-7-fullhd { + margin-left: 58.33333%; } + .column.is-8-fullhd { + flex: none; + width: 66.66667%; } + .column.is-offset-8-fullhd { + margin-left: 66.66667%; } + .column.is-9-fullhd { + flex: none; + width: 75%; } + .column.is-offset-9-fullhd { + margin-left: 75%; } + .column.is-10-fullhd { + flex: none; + width: 83.33333%; } + .column.is-offset-10-fullhd { + margin-left: 83.33333%; } + .column.is-11-fullhd { + flex: none; + width: 91.66667%; } + .column.is-offset-11-fullhd { + margin-left: 91.66667%; } + .column.is-12-fullhd { + flex: none; + width: 100%; } + .column.is-offset-12-fullhd { + margin-left: 100%; } } + +.columns { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; } + .columns:last-child { + margin-bottom: -0.75rem; } + .columns:not(:last-child) { + margin-bottom: calc(1.5rem - 0.75rem); } + .columns.is-centered { + justify-content: center; } + .columns.is-gapless { + margin-left: 0; + margin-right: 0; + margin-top: 0; } + .columns.is-gapless > .column { + margin: 0; + padding: 0 !important; } + .columns.is-gapless:not(:last-child) { + margin-bottom: 1.5rem; } + .columns.is-gapless:last-child { + margin-bottom: 0; } + .columns.is-mobile { + display: flex; } + .columns.is-multiline { + flex-wrap: wrap; } + .columns.is-vcentered { + align-items: center; } + @media screen and (min-width: 769px), print { + .columns:not(.is-desktop) { + display: flex; } } + @media screen and (min-width: 1024px) { + .columns.is-desktop { + display: flex; } } + +.columns.is-variable { + --columnGap: 0.75rem; + margin-left: calc(-1 * var(--columnGap)); + margin-right: calc(-1 * var(--columnGap)); } + .columns.is-variable > .column { + padding-left: var(--columnGap); + padding-right: var(--columnGap); } + .columns.is-variable.is-0 { + --columnGap: 0rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-0-mobile { + --columnGap: 0rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-0-tablet { + --columnGap: 0rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-0-tablet-only { + --columnGap: 0rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-0-touch { + --columnGap: 0rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-0-desktop { + --columnGap: 0rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-0-desktop-only { + --columnGap: 0rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-0-widescreen { + --columnGap: 0rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-0-widescreen-only { + --columnGap: 0rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-0-fullhd { + --columnGap: 0rem; } } + .columns.is-variable.is-1 { + --columnGap: 0.25rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-1-mobile { + --columnGap: 0.25rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-1-tablet { + --columnGap: 0.25rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-1-tablet-only { + --columnGap: 0.25rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-1-touch { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-1-desktop { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-1-desktop-only { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-1-widescreen { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-1-widescreen-only { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-1-fullhd { + --columnGap: 0.25rem; } } + .columns.is-variable.is-2 { + --columnGap: 0.5rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-2-mobile { + --columnGap: 0.5rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-2-tablet { + --columnGap: 0.5rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-2-tablet-only { + --columnGap: 0.5rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-2-touch { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-2-desktop { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-2-desktop-only { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-2-widescreen { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-2-widescreen-only { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-2-fullhd { + --columnGap: 0.5rem; } } + .columns.is-variable.is-3 { + --columnGap: 0.75rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-3-mobile { + --columnGap: 0.75rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-3-tablet { + --columnGap: 0.75rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-3-tablet-only { + --columnGap: 0.75rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-3-touch { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-3-desktop { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-3-desktop-only { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-3-widescreen { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-3-widescreen-only { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-3-fullhd { + --columnGap: 0.75rem; } } + .columns.is-variable.is-4 { + --columnGap: 1rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-4-mobile { + --columnGap: 1rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-4-tablet { + --columnGap: 1rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-4-tablet-only { + --columnGap: 1rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-4-touch { + --columnGap: 1rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-4-desktop { + --columnGap: 1rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-4-desktop-only { + --columnGap: 1rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-4-widescreen { + --columnGap: 1rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-4-widescreen-only { + --columnGap: 1rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-4-fullhd { + --columnGap: 1rem; } } + .columns.is-variable.is-5 { + --columnGap: 1.25rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-5-mobile { + --columnGap: 1.25rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-5-tablet { + --columnGap: 1.25rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-5-tablet-only { + --columnGap: 1.25rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-5-touch { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-5-desktop { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-5-desktop-only { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-5-widescreen { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-5-widescreen-only { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-5-fullhd { + --columnGap: 1.25rem; } } + .columns.is-variable.is-6 { + --columnGap: 1.5rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-6-mobile { + --columnGap: 1.5rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-6-tablet { + --columnGap: 1.5rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-6-tablet-only { + --columnGap: 1.5rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-6-touch { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-6-desktop { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-6-desktop-only { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-6-widescreen { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-6-widescreen-only { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-6-fullhd { + --columnGap: 1.5rem; } } + .columns.is-variable.is-7 { + --columnGap: 1.75rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-7-mobile { + --columnGap: 1.75rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-7-tablet { + --columnGap: 1.75rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-7-tablet-only { + --columnGap: 1.75rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-7-touch { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-7-desktop { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-7-desktop-only { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-7-widescreen { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-7-widescreen-only { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-7-fullhd { + --columnGap: 1.75rem; } } + .columns.is-variable.is-8 { + --columnGap: 2rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-8-mobile { + --columnGap: 2rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-8-tablet { + --columnGap: 2rem; } } + @media screen and (min-width: 769px) and (max-width: 1023px) { + .columns.is-variable.is-8-tablet-only { + --columnGap: 2rem; } } + @media screen and (max-width: 1023px) { + .columns.is-variable.is-8-touch { + --columnGap: 2rem; } } + @media screen and (min-width: 1024px) { + .columns.is-variable.is-8-desktop { + --columnGap: 2rem; } } + @media screen and (min-width: 1024px) and (max-width: 1215px) { + .columns.is-variable.is-8-desktop-only { + --columnGap: 2rem; } } + @media screen and (min-width: 1216px) { + .columns.is-variable.is-8-widescreen { + --columnGap: 2rem; } } + @media screen and (min-width: 1216px) and (max-width: 1407px) { + .columns.is-variable.is-8-widescreen-only { + --columnGap: 2rem; } } + @media screen and (min-width: 1408px) { + .columns.is-variable.is-8-fullhd { + --columnGap: 2rem; } } + +.tile { + align-items: stretch; + display: block; + flex-basis: 0; + flex-grow: 1; + flex-shrink: 1; + min-height: min-content; } + .tile.is-ancestor { + margin-left: -0.75rem; + margin-right: -0.75rem; + margin-top: -0.75rem; } + .tile.is-ancestor:last-child { + margin-bottom: -0.75rem; } + .tile.is-ancestor:not(:last-child) { + margin-bottom: 0.75rem; } + .tile.is-child { + margin: 0 !important; } + .tile.is-parent { + padding: 0.75rem; } + .tile.is-vertical { + flex-direction: column; } + .tile.is-vertical > .tile.is-child:not(:last-child) { + margin-bottom: 1.5rem !important; } + @media screen and (min-width: 769px), print { + .tile:not(.is-child) { + display: flex; } + .tile.is-1 { + flex: none; + width: 8.33333%; } + .tile.is-2 { + flex: none; + width: 16.66667%; } + .tile.is-3 { + flex: none; + width: 25%; } + .tile.is-4 { + flex: none; + width: 33.33333%; } + .tile.is-5 { + flex: none; + width: 41.66667%; } + .tile.is-6 { + flex: none; + width: 50%; } + .tile.is-7 { + flex: none; + width: 58.33333%; } + .tile.is-8 { + flex: none; + width: 66.66667%; } + .tile.is-9 { + flex: none; + width: 75%; } + .tile.is-10 { + flex: none; + width: 83.33333%; } + .tile.is-11 { + flex: none; + width: 91.66667%; } + .tile.is-12 { + flex: none; + width: 100%; } } + +/* Bulma Helpers */ +.has-text-white { + color: white !important; } + +a.has-text-white:hover, a.has-text-white:focus { + color: #e6e6e6 !important; } + +.has-background-white { + background-color: white !important; } + +.has-text-black { + color: #0a0a0a !important; } + +a.has-text-black:hover, a.has-text-black:focus { + color: black !important; } + +.has-background-black { + background-color: #0a0a0a !important; } + +.has-text-light { + color: whitesmoke !important; } + +a.has-text-light:hover, a.has-text-light:focus { + color: #dbdbdb !important; } + +.has-background-light { + background-color: whitesmoke !important; } + +.has-text-dark { + color: #363636 !important; } + +a.has-text-dark:hover, a.has-text-dark:focus { + color: #1c1c1c !important; } + +.has-background-dark { + background-color: #363636 !important; } + +.has-text-primary { + color: #00d1b2 !important; } + +a.has-text-primary:hover, a.has-text-primary:focus { + color: #009e86 !important; } + +.has-background-primary { + background-color: #00d1b2 !important; } + +.has-text-primary-light { + color: #ebfffc !important; } + +a.has-text-primary-light:hover, a.has-text-primary-light:focus { + color: #b8fff4 !important; } + +.has-background-primary-light { + background-color: #ebfffc !important; } + +.has-text-primary-dark { + color: #00947e !important; } + +a.has-text-primary-dark:hover, a.has-text-primary-dark:focus { + color: #00c7a9 !important; } + +.has-background-primary-dark { + background-color: #00947e !important; } + +.has-text-link { + color: #3273dc !important; } + +a.has-text-link:hover, a.has-text-link:focus { + color: #205bbc !important; } + +.has-background-link { + background-color: #3273dc !important; } + +.has-text-link-light { + color: #eef3fc !important; } + +a.has-text-link-light:hover, a.has-text-link-light:focus { + color: #c2d5f5 !important; } + +.has-background-link-light { + background-color: #eef3fc !important; } + +.has-text-link-dark { + color: #2160c4 !important; } + +a.has-text-link-dark:hover, a.has-text-link-dark:focus { + color: #3b79de !important; } + +.has-background-link-dark { + background-color: #2160c4 !important; } + +.has-text-info { + color: #3298dc !important; } + +a.has-text-info:hover, a.has-text-info:focus { + color: #207dbc !important; } + +.has-background-info { + background-color: #3298dc !important; } + +.has-text-info-light { + color: #eef6fc !important; } + +a.has-text-info-light:hover, a.has-text-info-light:focus { + color: #c2e0f5 !important; } + +.has-background-info-light { + background-color: #eef6fc !important; } + +.has-text-info-dark { + color: #1d72aa !important; } + +a.has-text-info-dark:hover, a.has-text-info-dark:focus { + color: #248fd6 !important; } + +.has-background-info-dark { + background-color: #1d72aa !important; } + +.has-text-success { + color: #48c774 !important; } + +a.has-text-success:hover, a.has-text-success:focus { + color: #34a85c !important; } + +.has-background-success { + background-color: #48c774 !important; } + +.has-text-success-light { + color: #effaf3 !important; } + +a.has-text-success-light:hover, a.has-text-success-light:focus { + color: #c8eed6 !important; } + +.has-background-success-light { + background-color: #effaf3 !important; } + +.has-text-success-dark { + color: #257942 !important; } + +a.has-text-success-dark:hover, a.has-text-success-dark:focus { + color: #31a058 !important; } + +.has-background-success-dark { + background-color: #257942 !important; } + +.has-text-warning { + color: #ffdd57 !important; } + +a.has-text-warning:hover, a.has-text-warning:focus { + color: #ffd324 !important; } + +.has-background-warning { + background-color: #ffdd57 !important; } + +.has-text-warning-light { + color: #fffbeb !important; } + +a.has-text-warning-light:hover, a.has-text-warning-light:focus { + color: #fff1b8 !important; } + +.has-background-warning-light { + background-color: #fffbeb !important; } + +.has-text-warning-dark { + color: #947600 !important; } + +a.has-text-warning-dark:hover, a.has-text-warning-dark:focus { + color: #c79f00 !important; } + +.has-background-warning-dark { + background-color: #947600 !important; } + +.has-text-danger { + color: #f14668 !important; } + +a.has-text-danger:hover, a.has-text-danger:focus { + color: #ee1742 !important; } + +.has-background-danger { + background-color: #f14668 !important; } + +.has-text-danger-light { + color: #feecf0 !important; } + +a.has-text-danger-light:hover, a.has-text-danger-light:focus { + color: #fabdc9 !important; } + +.has-background-danger-light { + background-color: #feecf0 !important; } + +.has-text-danger-dark { + color: #cc0f35 !important; } + +a.has-text-danger-dark:hover, a.has-text-danger-dark:focus { + color: #ee2049 !important; } + +.has-background-danger-dark { + background-color: #cc0f35 !important; } + +.has-text-black-bis { + color: #121212 !important; } + +.has-background-black-bis { + background-color: #121212 !important; } + +.has-text-black-ter { + color: #242424 !important; } + +.has-background-black-ter { + background-color: #242424 !important; } + +.has-text-grey-darker { + color: #363636 !important; } + +.has-background-grey-darker { + background-color: #363636 !important; } + +.has-text-grey-dark { + color: #4a4a4a !important; } + +.has-background-grey-dark { + background-color: #4a4a4a !important; } + +.has-text-grey { + color: #7a7a7a !important; } + +.has-background-grey { + background-color: #7a7a7a !important; } + +.has-text-grey-light { + color: #b5b5b5 !important; } + +.has-background-grey-light { + background-color: #b5b5b5 !important; } + +.has-text-grey-lighter { + color: #dbdbdb !important; } + +.has-background-grey-lighter { + background-color: #dbdbdb !important; } + +.has-text-white-ter { + color: whitesmoke !important; } + +.has-background-white-ter { + background-color: whitesmoke !important; } + +.has-text-white-bis { + color: #fafafa !important; } + +.has-background-white-bis { + background-color: #fafafa !important; } + +.is-flex-direction-row { + flex-direction: row !important; } + +.is-flex-direction-row-reverse { + flex-direction: row-reverse !important; } + +.is-flex-direction-column { + flex-direction: column !important; } + +.is-flex-direction-column-reverse { + flex-direction: column-reverse !important; } + +.is-flex-wrap-nowrap { + flex-wrap: nowrap !important; } + +.is-flex-wrap-wrap { + flex-wrap: wrap !important; } + +.is-flex-wrap-wrap-reverse { + flex-wrap: wrap-reverse !important; } + +.is-justify-content-flex-start { + justify-content: flex-start !important; } + +.is-justify-content-flex-end { + justify-content: flex-end !important; } + +.is-justify-content-center { + justify-content: center !important; } + +.is-justify-content-space-between { + justify-content: space-between !important; } + +.is-justify-content-space-around { + justify-content: space-around !important; } + +.is-justify-content-space-evenly { + justify-content: space-evenly !important; } + +.is-justify-content-start { + justify-content: start !important; } + +.is-justify-content-end { + justify-content: end !important; } + +.is-justify-content-left { + justify-content: left !important; } + +.is-justify-content-right { + justify-content: right !important; } + +.is-align-content-flex-start { + align-content: flex-start !important; } + +.is-align-content-flex-end { + align-content: flex-end !important; } + +.is-align-content-center { + align-content: center !important; } + +.is-align-content-space-between { + align-content: space-between !important; } + +.is-align-content-space-around { + align-content: space-around !important; } + +.is-align-content-space-evenly { + align-content: space-evenly !important; } + +.is-align-content-stretch { + align-content: stretch !important; } + +.is-align-content-start { + align-content: start !important; } + +.is-align-content-end { + align-content: end !important; } + +.is-align-content-baseline { + align-content: baseline !important; } + +.is-align-items-stretch { + align-items: stretch !important; } + +.is-align-items-flex-start { + align-items: flex-start !important; } + +.is-align-items-flex-end { + align-items: flex-end !important; } + +.is-align-items-center { + align-items: center !important; } + +.is-align-items-baseline { + align-items: baseline !important; } + +.is-align-items-start { + align-items: start !important; } + +.is-align-items-end { + align-items: end !important; } + +.is-align-items-self-start { + align-items: self-start !important; } + +.is-align-items-self-end { + align-items: self-end !important; } + +.is-align-self-auto { + align-self: auto !important; } + +.is-align-self-flex-start { + align-self: flex-start !important; } + +.is-align-self-flex-end { + align-self: flex-end !important; } + +.is-align-self-center { + align-self: center !important; } + +.is-align-self-baseline { + align-self: baseline !important; } + +.is-align-self-stretch { + align-self: stretch !important; } + +.is-flex-grow-0 { + flex-grow: 0 !important; } + +.is-flex-grow-1 { + flex-grow: 1 !important; } + +.is-flex-grow-2 { + flex-grow: 2 !important; } + +.is-flex-grow-3 { + flex-grow: 3 !important; } + +.is-flex-grow-4 { + flex-grow: 4 !important; } + +.is-flex-grow-5 { + flex-grow: 5 !important; } + +.is-flex-shrink-0 { + flex-shrink: 0 !important; } + +.is-flex-shrink-1 { + flex-shrink: 1 !important; } + +.is-flex-shrink-2 { + flex-shrink: 2 !important; } + +.is-flex-shrink-3 { + flex-shrink: 3 !important; } + +.is-flex-shrink-4 { + flex-shrink: 4 !important; } + +.is-flex-shrink-5 { + flex-shrink: 5 !important; } + +.is-clearfix::after { + clear: both; + content: " "; + display: table; } + +.is-pulled-left { + float: left !important; } + +.is-pulled-right { + float: right !important; } + +.is-radiusless { + border-radius: 0 !important; } + +.is-shadowless { + box-shadow: none !important; } + +.is-clickable { + cursor: pointer !important; + pointer-events: all !important; } + +.is-clipped { + overflow: hidden !important; } + +.is-relative { + position: relative !important; } + +.is-marginless { + margin: 0 !important; } + +.is-paddingless { + padding: 0 !important; } + +.m-0 { + margin: 0 !important; } + +.mt-0 { + margin-top: 0 !important; } + +.mr-0 { + margin-right: 0 !important; } + +.mb-0 { + margin-bottom: 0 !important; } + +.ml-0 { + margin-left: 0 !important; } + +.mx-0 { + margin-left: 0 !important; + margin-right: 0 !important; } + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; } + +.m-1 { + margin: 0.25rem !important; } + +.mt-1 { + margin-top: 0.25rem !important; } + +.mr-1 { + margin-right: 0.25rem !important; } + +.mb-1 { + margin-bottom: 0.25rem !important; } + +.ml-1 { + margin-left: 0.25rem !important; } + +.mx-1 { + margin-left: 0.25rem !important; + margin-right: 0.25rem !important; } + +.my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; } + +.m-2 { + margin: 0.5rem !important; } + +.mt-2 { + margin-top: 0.5rem !important; } + +.mr-2 { + margin-right: 0.5rem !important; } + +.mb-2 { + margin-bottom: 0.5rem !important; } + +.ml-2 { + margin-left: 0.5rem !important; } + +.mx-2 { + margin-left: 0.5rem !important; + margin-right: 0.5rem !important; } + +.my-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; } + +.m-3 { + margin: 0.75rem !important; } + +.mt-3 { + margin-top: 0.75rem !important; } + +.mr-3 { + margin-right: 0.75rem !important; } + +.mb-3 { + margin-bottom: 0.75rem !important; } + +.ml-3 { + margin-left: 0.75rem !important; } + +.mx-3 { + margin-left: 0.75rem !important; + margin-right: 0.75rem !important; } + +.my-3 { + margin-top: 0.75rem !important; + margin-bottom: 0.75rem !important; } + +.m-4 { + margin: 1rem !important; } + +.mt-4 { + margin-top: 1rem !important; } + +.mr-4 { + margin-right: 1rem !important; } + +.mb-4 { + margin-bottom: 1rem !important; } + +.ml-4 { + margin-left: 1rem !important; } + +.mx-4 { + margin-left: 1rem !important; + margin-right: 1rem !important; } + +.my-4 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; } + +.m-5 { + margin: 1.5rem !important; } + +.mt-5 { + margin-top: 1.5rem !important; } + +.mr-5 { + margin-right: 1.5rem !important; } + +.mb-5 { + margin-bottom: 1.5rem !important; } + +.ml-5 { + margin-left: 1.5rem !important; } + +.mx-5 { + margin-left: 1.5rem !important; + margin-right: 1.5rem !important; } + +.my-5 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; } + +.m-6 { + margin: 3rem !important; } + +.mt-6 { + margin-top: 3rem !important; } + +.mr-6 { + margin-right: 3rem !important; } + +.mb-6 { + margin-bottom: 3rem !important; } + +.ml-6 { + margin-left: 3rem !important; } + +.mx-6 { + margin-left: 3rem !important; + margin-right: 3rem !important; } + +.my-6 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; } + +.p-0 { + padding: 0 !important; } + +.pt-0 { + padding-top: 0 !important; } + +.pr-0 { + padding-right: 0 !important; } + +.pb-0 { + padding-bottom: 0 !important; } + +.pl-0 { + padding-left: 0 !important; } + +.px-0 { + padding-left: 0 !important; + padding-right: 0 !important; } + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; } + +.p-1 { + padding: 0.25rem !important; } + +.pt-1 { + padding-top: 0.25rem !important; } + +.pr-1 { + padding-right: 0.25rem !important; } + +.pb-1 { + padding-bottom: 0.25rem !important; } + +.pl-1 { + padding-left: 0.25rem !important; } + +.px-1 { + padding-left: 0.25rem !important; + padding-right: 0.25rem !important; } + +.py-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; } + +.p-2 { + padding: 0.5rem !important; } + +.pt-2 { + padding-top: 0.5rem !important; } + +.pr-2 { + padding-right: 0.5rem !important; } + +.pb-2 { + padding-bottom: 0.5rem !important; } + +.pl-2 { + padding-left: 0.5rem !important; } + +.px-2 { + padding-left: 0.5rem !important; + padding-right: 0.5rem !important; } + +.py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; } + +.p-3 { + padding: 0.75rem !important; } + +.pt-3 { + padding-top: 0.75rem !important; } + +.pr-3 { + padding-right: 0.75rem !important; } + +.pb-3 { + padding-bottom: 0.75rem !important; } + +.pl-3 { + padding-left: 0.75rem !important; } + +.px-3 { + padding-left: 0.75rem !important; + padding-right: 0.75rem !important; } + +.py-3 { + padding-top: 0.75rem !important; + padding-bottom: 0.75rem !important; } + +.p-4 { + padding: 1rem !important; } + +.pt-4 { + padding-top: 1rem !important; } + +.pr-4 { + padding-right: 1rem !important; } + +.pb-4 { + padding-bottom: 1rem !important; } + +.pl-4 { + padding-left: 1rem !important; } + +.px-4 { + padding-left: 1rem !important; + padding-right: 1rem !important; } + +.py-4 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; } + +.p-5 { + padding: 1.5rem !important; } + +.pt-5 { + padding-top: 1.5rem !important; } + +.pr-5 { + padding-right: 1.5rem !important; } + +.pb-5 { + padding-bottom: 1.5rem !important; } + +.pl-5 { + padding-left: 1.5rem !important; } + +.px-5 { + padding-left: 1.5rem !important; + padding-right: 1.5rem !important; } + +.py-5 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; } + +.p-6 { + padding: 3rem !important; } + +.pt-6 { + padding-top: 3rem !important; } + +.pr-6 { + padding-right: 3rem !important; } + +.pb-6 { + padding-bottom: 3rem !important; } + +.pl-6 { + padding-left: 3rem !important; } + +.px-6 { + padding-left: 3rem !important; + padding-right: 3rem !important; } + +.py-6 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; } + +.is-size-1 { + font-size: 3rem !important; } + +.is-size-2 { + font-size: 2.5rem !important; } + +.is-size-3 { + font-size: 2rem !important; } + +.is-size-4 { + font-size: 1.5rem !important; } + +.is-size-5 { + font-size: 1.25rem !important; } + +.is-size-6 { + font-size: 1rem !important; } + +.is-size-7 { + font-size: 0.75rem !important; } + +@media screen and (max-width: 768px) { + .is-size-1-mobile { + font-size: 3rem !important; } + .is-size-2-mobile { + font-size: 2.5rem !important; } + .is-size-3-mobile { + font-size: 2rem !important; } + .is-size-4-mobile { + font-size: 1.5rem !important; } + .is-size-5-mobile { + font-size: 1.25rem !important; } + .is-size-6-mobile { + font-size: 1rem !important; } + .is-size-7-mobile { + font-size: 0.75rem !important; } } + +@media screen and (min-width: 769px), print { + .is-size-1-tablet { + font-size: 3rem !important; } + .is-size-2-tablet { + font-size: 2.5rem !important; } + .is-size-3-tablet { + font-size: 2rem !important; } + .is-size-4-tablet { + font-size: 1.5rem !important; } + .is-size-5-tablet { + font-size: 1.25rem !important; } + .is-size-6-tablet { + font-size: 1rem !important; } + .is-size-7-tablet { + font-size: 0.75rem !important; } } + +@media screen and (max-width: 1023px) { + .is-size-1-touch { + font-size: 3rem !important; } + .is-size-2-touch { + font-size: 2.5rem !important; } + .is-size-3-touch { + font-size: 2rem !important; } + .is-size-4-touch { + font-size: 1.5rem !important; } + .is-size-5-touch { + font-size: 1.25rem !important; } + .is-size-6-touch { + font-size: 1rem !important; } + .is-size-7-touch { + font-size: 0.75rem !important; } } + +@media screen and (min-width: 1024px) { + .is-size-1-desktop { + font-size: 3rem !important; } + .is-size-2-desktop { + font-size: 2.5rem !important; } + .is-size-3-desktop { + font-size: 2rem !important; } + .is-size-4-desktop { + font-size: 1.5rem !important; } + .is-size-5-desktop { + font-size: 1.25rem !important; } + .is-size-6-desktop { + font-size: 1rem !important; } + .is-size-7-desktop { + font-size: 0.75rem !important; } } + +@media screen and (min-width: 1216px) { + .is-size-1-widescreen { + font-size: 3rem !important; } + .is-size-2-widescreen { + font-size: 2.5rem !important; } + .is-size-3-widescreen { + font-size: 2rem !important; } + .is-size-4-widescreen { + font-size: 1.5rem !important; } + .is-size-5-widescreen { + font-size: 1.25rem !important; } + .is-size-6-widescreen { + font-size: 1rem !important; } + .is-size-7-widescreen { + font-size: 0.75rem !important; } } + +@media screen and (min-width: 1408px) { + .is-size-1-fullhd { + font-size: 3rem !important; } + .is-size-2-fullhd { + font-size: 2.5rem !important; } + .is-size-3-fullhd { + font-size: 2rem !important; } + .is-size-4-fullhd { + font-size: 1.5rem !important; } + .is-size-5-fullhd { + font-size: 1.25rem !important; } + .is-size-6-fullhd { + font-size: 1rem !important; } + .is-size-7-fullhd { + font-size: 0.75rem !important; } } + +.has-text-centered { + text-align: center !important; } + +.has-text-justified { + text-align: justify !important; } + +.has-text-left { + text-align: left !important; } + +.has-text-right { + text-align: right !important; } + +@media screen and (max-width: 768px) { + .has-text-centered-mobile { + text-align: center !important; } } + +@media screen and (min-width: 769px), print { + .has-text-centered-tablet { + text-align: center !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-centered-tablet-only { + text-align: center !important; } } + +@media screen and (max-width: 1023px) { + .has-text-centered-touch { + text-align: center !important; } } + +@media screen and (min-width: 1024px) { + .has-text-centered-desktop { + text-align: center !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-centered-desktop-only { + text-align: center !important; } } + +@media screen and (min-width: 1216px) { + .has-text-centered-widescreen { + text-align: center !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-centered-widescreen-only { + text-align: center !important; } } + +@media screen and (min-width: 1408px) { + .has-text-centered-fullhd { + text-align: center !important; } } + +@media screen and (max-width: 768px) { + .has-text-justified-mobile { + text-align: justify !important; } } + +@media screen and (min-width: 769px), print { + .has-text-justified-tablet { + text-align: justify !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-justified-tablet-only { + text-align: justify !important; } } + +@media screen and (max-width: 1023px) { + .has-text-justified-touch { + text-align: justify !important; } } + +@media screen and (min-width: 1024px) { + .has-text-justified-desktop { + text-align: justify !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-justified-desktop-only { + text-align: justify !important; } } + +@media screen and (min-width: 1216px) { + .has-text-justified-widescreen { + text-align: justify !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-justified-widescreen-only { + text-align: justify !important; } } + +@media screen and (min-width: 1408px) { + .has-text-justified-fullhd { + text-align: justify !important; } } + +@media screen and (max-width: 768px) { + .has-text-left-mobile { + text-align: left !important; } } + +@media screen and (min-width: 769px), print { + .has-text-left-tablet { + text-align: left !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-left-tablet-only { + text-align: left !important; } } + +@media screen and (max-width: 1023px) { + .has-text-left-touch { + text-align: left !important; } } + +@media screen and (min-width: 1024px) { + .has-text-left-desktop { + text-align: left !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-left-desktop-only { + text-align: left !important; } } + +@media screen and (min-width: 1216px) { + .has-text-left-widescreen { + text-align: left !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-left-widescreen-only { + text-align: left !important; } } + +@media screen and (min-width: 1408px) { + .has-text-left-fullhd { + text-align: left !important; } } + +@media screen and (max-width: 768px) { + .has-text-right-mobile { + text-align: right !important; } } + +@media screen and (min-width: 769px), print { + .has-text-right-tablet { + text-align: right !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-text-right-tablet-only { + text-align: right !important; } } + +@media screen and (max-width: 1023px) { + .has-text-right-touch { + text-align: right !important; } } + +@media screen and (min-width: 1024px) { + .has-text-right-desktop { + text-align: right !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-text-right-desktop-only { + text-align: right !important; } } + +@media screen and (min-width: 1216px) { + .has-text-right-widescreen { + text-align: right !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-text-right-widescreen-only { + text-align: right !important; } } + +@media screen and (min-width: 1408px) { + .has-text-right-fullhd { + text-align: right !important; } } + +.is-capitalized { + text-transform: capitalize !important; } + +.is-lowercase { + text-transform: lowercase !important; } + +.is-uppercase { + text-transform: uppercase !important; } + +.is-italic { + font-style: italic !important; } + +.has-text-weight-light { + font-weight: 300 !important; } + +.has-text-weight-normal { + font-weight: 400 !important; } + +.has-text-weight-medium { + font-weight: 500 !important; } + +.has-text-weight-semibold { + font-weight: 600 !important; } + +.has-text-weight-bold { + font-weight: 700 !important; } + +.is-family-primary { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; } + +.is-family-secondary { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; } + +.is-family-sans-serif { + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif !important; } + +.is-family-monospace { + font-family: monospace !important; } + +.is-family-code { + font-family: monospace !important; } + +.is-block { + display: block !important; } + +@media screen and (max-width: 768px) { + .is-block-mobile { + display: block !important; } } + +@media screen and (min-width: 769px), print { + .is-block-tablet { + display: block !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-block-tablet-only { + display: block !important; } } + +@media screen and (max-width: 1023px) { + .is-block-touch { + display: block !important; } } + +@media screen and (min-width: 1024px) { + .is-block-desktop { + display: block !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-block-desktop-only { + display: block !important; } } + +@media screen and (min-width: 1216px) { + .is-block-widescreen { + display: block !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-block-widescreen-only { + display: block !important; } } + +@media screen and (min-width: 1408px) { + .is-block-fullhd { + display: block !important; } } + +.is-flex { + display: flex !important; } + +@media screen and (max-width: 768px) { + .is-flex-mobile { + display: flex !important; } } + +@media screen and (min-width: 769px), print { + .is-flex-tablet { + display: flex !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-flex-tablet-only { + display: flex !important; } } + +@media screen and (max-width: 1023px) { + .is-flex-touch { + display: flex !important; } } + +@media screen and (min-width: 1024px) { + .is-flex-desktop { + display: flex !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-flex-desktop-only { + display: flex !important; } } + +@media screen and (min-width: 1216px) { + .is-flex-widescreen { + display: flex !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-flex-widescreen-only { + display: flex !important; } } + +@media screen and (min-width: 1408px) { + .is-flex-fullhd { + display: flex !important; } } + +.is-inline { + display: inline !important; } + +@media screen and (max-width: 768px) { + .is-inline-mobile { + display: inline !important; } } + +@media screen and (min-width: 769px), print { + .is-inline-tablet { + display: inline !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-inline-tablet-only { + display: inline !important; } } + +@media screen and (max-width: 1023px) { + .is-inline-touch { + display: inline !important; } } + +@media screen and (min-width: 1024px) { + .is-inline-desktop { + display: inline !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-inline-desktop-only { + display: inline !important; } } + +@media screen and (min-width: 1216px) { + .is-inline-widescreen { + display: inline !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-inline-widescreen-only { + display: inline !important; } } + +@media screen and (min-width: 1408px) { + .is-inline-fullhd { + display: inline !important; } } + +.is-inline-block { + display: inline-block !important; } + +@media screen and (max-width: 768px) { + .is-inline-block-mobile { + display: inline-block !important; } } + +@media screen and (min-width: 769px), print { + .is-inline-block-tablet { + display: inline-block !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-inline-block-tablet-only { + display: inline-block !important; } } + +@media screen and (max-width: 1023px) { + .is-inline-block-touch { + display: inline-block !important; } } + +@media screen and (min-width: 1024px) { + .is-inline-block-desktop { + display: inline-block !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-inline-block-desktop-only { + display: inline-block !important; } } + +@media screen and (min-width: 1216px) { + .is-inline-block-widescreen { + display: inline-block !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-inline-block-widescreen-only { + display: inline-block !important; } } + +@media screen and (min-width: 1408px) { + .is-inline-block-fullhd { + display: inline-block !important; } } + +.is-inline-flex { + display: inline-flex !important; } + +@media screen and (max-width: 768px) { + .is-inline-flex-mobile { + display: inline-flex !important; } } + +@media screen and (min-width: 769px), print { + .is-inline-flex-tablet { + display: inline-flex !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-inline-flex-tablet-only { + display: inline-flex !important; } } + +@media screen and (max-width: 1023px) { + .is-inline-flex-touch { + display: inline-flex !important; } } + +@media screen and (min-width: 1024px) { + .is-inline-flex-desktop { + display: inline-flex !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-inline-flex-desktop-only { + display: inline-flex !important; } } + +@media screen and (min-width: 1216px) { + .is-inline-flex-widescreen { + display: inline-flex !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-inline-flex-widescreen-only { + display: inline-flex !important; } } + +@media screen and (min-width: 1408px) { + .is-inline-flex-fullhd { + display: inline-flex !important; } } + +.is-hidden { + display: none !important; } + +.is-sr-only { + border: none !important; + clip: rect(0, 0, 0, 0) !important; + height: 0.01em !important; + overflow: hidden !important; + padding: 0 !important; + position: absolute !important; + white-space: nowrap !important; + width: 0.01em !important; } + +@media screen and (max-width: 768px) { + .is-hidden-mobile { + display: none !important; } } + +@media screen and (min-width: 769px), print { + .is-hidden-tablet { + display: none !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-hidden-tablet-only { + display: none !important; } } + +@media screen and (max-width: 1023px) { + .is-hidden-touch { + display: none !important; } } + +@media screen and (min-width: 1024px) { + .is-hidden-desktop { + display: none !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-hidden-desktop-only { + display: none !important; } } + +@media screen and (min-width: 1216px) { + .is-hidden-widescreen { + display: none !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-hidden-widescreen-only { + display: none !important; } } + +@media screen and (min-width: 1408px) { + .is-hidden-fullhd { + display: none !important; } } + +.is-invisible { + visibility: hidden !important; } + +@media screen and (max-width: 768px) { + .is-invisible-mobile { + visibility: hidden !important; } } + +@media screen and (min-width: 769px), print { + .is-invisible-tablet { + visibility: hidden !important; } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .is-invisible-tablet-only { + visibility: hidden !important; } } + +@media screen and (max-width: 1023px) { + .is-invisible-touch { + visibility: hidden !important; } } + +@media screen and (min-width: 1024px) { + .is-invisible-desktop { + visibility: hidden !important; } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .is-invisible-desktop-only { + visibility: hidden !important; } } + +@media screen and (min-width: 1216px) { + .is-invisible-widescreen { + visibility: hidden !important; } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .is-invisible-widescreen-only { + visibility: hidden !important; } } + +@media screen and (min-width: 1408px) { + .is-invisible-fullhd { + visibility: hidden !important; } } + +/* Bulma Layout */ +.hero { + align-items: stretch; + display: flex; + flex-direction: column; + justify-content: space-between; } + .hero .navbar { + background: none; } + .hero .tabs ul { + border-bottom: none; } + .hero.is-white { + background-color: white; + color: #0a0a0a; } + .hero.is-white a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-white strong { + color: inherit; } + .hero.is-white .title { + color: #0a0a0a; } + .hero.is-white .subtitle { + color: rgba(10, 10, 10, 0.9); } + .hero.is-white .subtitle a:not(.button), + .hero.is-white .subtitle strong { + color: #0a0a0a; } + @media screen and (max-width: 1023px) { + .hero.is-white .navbar-menu { + background-color: white; } } + .hero.is-white .navbar-item, + .hero.is-white .navbar-link { + color: rgba(10, 10, 10, 0.7); } + .hero.is-white a.navbar-item:hover, .hero.is-white a.navbar-item.is-active, + .hero.is-white .navbar-link:hover, + .hero.is-white .navbar-link.is-active { + background-color: #f2f2f2; + color: #0a0a0a; } + .hero.is-white .tabs a { + color: #0a0a0a; + opacity: 0.9; } + .hero.is-white .tabs a:hover { + opacity: 1; } + .hero.is-white .tabs li.is-active a { + opacity: 1; } + .hero.is-white .tabs.is-boxed a, .hero.is-white .tabs.is-toggle a { + color: #0a0a0a; } + .hero.is-white .tabs.is-boxed a:hover, .hero.is-white .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-white .tabs.is-boxed li.is-active a, .hero.is-white .tabs.is-boxed li.is-active a:hover, .hero.is-white .tabs.is-toggle li.is-active a, .hero.is-white .tabs.is-toggle li.is-active a:hover { + background-color: #0a0a0a; + border-color: #0a0a0a; + color: white; } + .hero.is-white.is-bold { + background-image: linear-gradient(141deg, #e6e6e6 0%, white 71%, white 100%); } + @media screen and (max-width: 768px) { + .hero.is-white.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #e6e6e6 0%, white 71%, white 100%); } } + .hero.is-black { + background-color: #0a0a0a; + color: white; } + .hero.is-black a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-black strong { + color: inherit; } + .hero.is-black .title { + color: white; } + .hero.is-black .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-black .subtitle a:not(.button), + .hero.is-black .subtitle strong { + color: white; } + @media screen and (max-width: 1023px) { + .hero.is-black .navbar-menu { + background-color: #0a0a0a; } } + .hero.is-black .navbar-item, + .hero.is-black .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-black a.navbar-item:hover, .hero.is-black a.navbar-item.is-active, + .hero.is-black .navbar-link:hover, + .hero.is-black .navbar-link.is-active { + background-color: black; + color: white; } + .hero.is-black .tabs a { + color: white; + opacity: 0.9; } + .hero.is-black .tabs a:hover { + opacity: 1; } + .hero.is-black .tabs li.is-active a { + opacity: 1; } + .hero.is-black .tabs.is-boxed a, .hero.is-black .tabs.is-toggle a { + color: white; } + .hero.is-black .tabs.is-boxed a:hover, .hero.is-black .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-black .tabs.is-boxed li.is-active a, .hero.is-black .tabs.is-boxed li.is-active a:hover, .hero.is-black .tabs.is-toggle li.is-active a, .hero.is-black .tabs.is-toggle li.is-active a:hover { + background-color: white; + border-color: white; + color: #0a0a0a; } + .hero.is-black.is-bold { + background-image: linear-gradient(141deg, black 0%, #0a0a0a 71%, #181616 100%); } + @media screen and (max-width: 768px) { + .hero.is-black.is-bold .navbar-menu { + background-image: linear-gradient(141deg, black 0%, #0a0a0a 71%, #181616 100%); } } + .hero.is-light { + background-color: whitesmoke; + color: rgba(0, 0, 0, 0.7); } + .hero.is-light a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-light strong { + color: inherit; } + .hero.is-light .title { + color: rgba(0, 0, 0, 0.7); } + .hero.is-light .subtitle { + color: rgba(0, 0, 0, 0.9); } + .hero.is-light .subtitle a:not(.button), + .hero.is-light .subtitle strong { + color: rgba(0, 0, 0, 0.7); } + @media screen and (max-width: 1023px) { + .hero.is-light .navbar-menu { + background-color: whitesmoke; } } + .hero.is-light .navbar-item, + .hero.is-light .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .hero.is-light a.navbar-item:hover, .hero.is-light a.navbar-item.is-active, + .hero.is-light .navbar-link:hover, + .hero.is-light .navbar-link.is-active { + background-color: #e8e8e8; + color: rgba(0, 0, 0, 0.7); } + .hero.is-light .tabs a { + color: rgba(0, 0, 0, 0.7); + opacity: 0.9; } + .hero.is-light .tabs a:hover { + opacity: 1; } + .hero.is-light .tabs li.is-active a { + opacity: 1; } + .hero.is-light .tabs.is-boxed a, .hero.is-light .tabs.is-toggle a { + color: rgba(0, 0, 0, 0.7); } + .hero.is-light .tabs.is-boxed a:hover, .hero.is-light .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-light .tabs.is-boxed li.is-active a, .hero.is-light .tabs.is-boxed li.is-active a:hover, .hero.is-light .tabs.is-toggle li.is-active a, .hero.is-light .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0, 0, 0, 0.7); + border-color: rgba(0, 0, 0, 0.7); + color: whitesmoke; } + .hero.is-light.is-bold { + background-image: linear-gradient(141deg, #dfd8d9 0%, whitesmoke 71%, white 100%); } + @media screen and (max-width: 768px) { + .hero.is-light.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #dfd8d9 0%, whitesmoke 71%, white 100%); } } + .hero.is-dark { + background-color: #363636; + color: #fff; } + .hero.is-dark a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-dark strong { + color: inherit; } + .hero.is-dark .title { + color: #fff; } + .hero.is-dark .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-dark .subtitle a:not(.button), + .hero.is-dark .subtitle strong { + color: #fff; } + @media screen and (max-width: 1023px) { + .hero.is-dark .navbar-menu { + background-color: #363636; } } + .hero.is-dark .navbar-item, + .hero.is-dark .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-dark a.navbar-item:hover, .hero.is-dark a.navbar-item.is-active, + .hero.is-dark .navbar-link:hover, + .hero.is-dark .navbar-link.is-active { + background-color: #292929; + color: #fff; } + .hero.is-dark .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-dark .tabs a:hover { + opacity: 1; } + .hero.is-dark .tabs li.is-active a { + opacity: 1; } + .hero.is-dark .tabs.is-boxed a, .hero.is-dark .tabs.is-toggle a { + color: #fff; } + .hero.is-dark .tabs.is-boxed a:hover, .hero.is-dark .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-dark .tabs.is-boxed li.is-active a, .hero.is-dark .tabs.is-boxed li.is-active a:hover, .hero.is-dark .tabs.is-toggle li.is-active a, .hero.is-dark .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #363636; } + .hero.is-dark.is-bold { + background-image: linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%); } + @media screen and (max-width: 768px) { + .hero.is-dark.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%); } } + .hero.is-primary { + background-color: #00d1b2; + color: #fff; } + .hero.is-primary a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-primary strong { + color: inherit; } + .hero.is-primary .title { + color: #fff; } + .hero.is-primary .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-primary .subtitle a:not(.button), + .hero.is-primary .subtitle strong { + color: #fff; } + @media screen and (max-width: 1023px) { + .hero.is-primary .navbar-menu { + background-color: #00d1b2; } } + .hero.is-primary .navbar-item, + .hero.is-primary .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-primary a.navbar-item:hover, .hero.is-primary a.navbar-item.is-active, + .hero.is-primary .navbar-link:hover, + .hero.is-primary .navbar-link.is-active { + background-color: #00b89c; + color: #fff; } + .hero.is-primary .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-primary .tabs a:hover { + opacity: 1; } + .hero.is-primary .tabs li.is-active a { + opacity: 1; } + .hero.is-primary .tabs.is-boxed a, .hero.is-primary .tabs.is-toggle a { + color: #fff; } + .hero.is-primary .tabs.is-boxed a:hover, .hero.is-primary .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-primary .tabs.is-boxed li.is-active a, .hero.is-primary .tabs.is-boxed li.is-active a:hover, .hero.is-primary .tabs.is-toggle li.is-active a, .hero.is-primary .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #00d1b2; } + .hero.is-primary.is-bold { + background-image: linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%); } + @media screen and (max-width: 768px) { + .hero.is-primary.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%); } } + .hero.is-link { + background-color: #3273dc; + color: #fff; } + .hero.is-link a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-link strong { + color: inherit; } + .hero.is-link .title { + color: #fff; } + .hero.is-link .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-link .subtitle a:not(.button), + .hero.is-link .subtitle strong { + color: #fff; } + @media screen and (max-width: 1023px) { + .hero.is-link .navbar-menu { + background-color: #3273dc; } } + .hero.is-link .navbar-item, + .hero.is-link .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-link a.navbar-item:hover, .hero.is-link a.navbar-item.is-active, + .hero.is-link .navbar-link:hover, + .hero.is-link .navbar-link.is-active { + background-color: #2366d1; + color: #fff; } + .hero.is-link .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-link .tabs a:hover { + opacity: 1; } + .hero.is-link .tabs li.is-active a { + opacity: 1; } + .hero.is-link .tabs.is-boxed a, .hero.is-link .tabs.is-toggle a { + color: #fff; } + .hero.is-link .tabs.is-boxed a:hover, .hero.is-link .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-link .tabs.is-boxed li.is-active a, .hero.is-link .tabs.is-boxed li.is-active a:hover, .hero.is-link .tabs.is-toggle li.is-active a, .hero.is-link .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #3273dc; } + .hero.is-link.is-bold { + background-image: linear-gradient(141deg, #1577c6 0%, #3273dc 71%, #4366e5 100%); } + @media screen and (max-width: 768px) { + .hero.is-link.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #1577c6 0%, #3273dc 71%, #4366e5 100%); } } + .hero.is-info { + background-color: #3298dc; + color: #fff; } + .hero.is-info a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-info strong { + color: inherit; } + .hero.is-info .title { + color: #fff; } + .hero.is-info .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-info .subtitle a:not(.button), + .hero.is-info .subtitle strong { + color: #fff; } + @media screen and (max-width: 1023px) { + .hero.is-info .navbar-menu { + background-color: #3298dc; } } + .hero.is-info .navbar-item, + .hero.is-info .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-info a.navbar-item:hover, .hero.is-info a.navbar-item.is-active, + .hero.is-info .navbar-link:hover, + .hero.is-info .navbar-link.is-active { + background-color: #238cd1; + color: #fff; } + .hero.is-info .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-info .tabs a:hover { + opacity: 1; } + .hero.is-info .tabs li.is-active a { + opacity: 1; } + .hero.is-info .tabs.is-boxed a, .hero.is-info .tabs.is-toggle a { + color: #fff; } + .hero.is-info .tabs.is-boxed a:hover, .hero.is-info .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-info .tabs.is-boxed li.is-active a, .hero.is-info .tabs.is-boxed li.is-active a:hover, .hero.is-info .tabs.is-toggle li.is-active a, .hero.is-info .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #3298dc; } + .hero.is-info.is-bold { + background-image: linear-gradient(141deg, #159dc6 0%, #3298dc 71%, #4389e5 100%); } + @media screen and (max-width: 768px) { + .hero.is-info.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #159dc6 0%, #3298dc 71%, #4389e5 100%); } } + .hero.is-success { + background-color: #48c774; + color: #fff; } + .hero.is-success a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-success strong { + color: inherit; } + .hero.is-success .title { + color: #fff; } + .hero.is-success .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-success .subtitle a:not(.button), + .hero.is-success .subtitle strong { + color: #fff; } + @media screen and (max-width: 1023px) { + .hero.is-success .navbar-menu { + background-color: #48c774; } } + .hero.is-success .navbar-item, + .hero.is-success .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-success a.navbar-item:hover, .hero.is-success a.navbar-item.is-active, + .hero.is-success .navbar-link:hover, + .hero.is-success .navbar-link.is-active { + background-color: #3abb67; + color: #fff; } + .hero.is-success .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-success .tabs a:hover { + opacity: 1; } + .hero.is-success .tabs li.is-active a { + opacity: 1; } + .hero.is-success .tabs.is-boxed a, .hero.is-success .tabs.is-toggle a { + color: #fff; } + .hero.is-success .tabs.is-boxed a:hover, .hero.is-success .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-success .tabs.is-boxed li.is-active a, .hero.is-success .tabs.is-boxed li.is-active a:hover, .hero.is-success .tabs.is-toggle li.is-active a, .hero.is-success .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #48c774; } + .hero.is-success.is-bold { + background-image: linear-gradient(141deg, #29b342 0%, #48c774 71%, #56d296 100%); } + @media screen and (max-width: 768px) { + .hero.is-success.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #29b342 0%, #48c774 71%, #56d296 100%); } } + .hero.is-warning { + background-color: #ffdd57; + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-warning strong { + color: inherit; } + .hero.is-warning .title { + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning .subtitle { + color: rgba(0, 0, 0, 0.9); } + .hero.is-warning .subtitle a:not(.button), + .hero.is-warning .subtitle strong { + color: rgba(0, 0, 0, 0.7); } + @media screen and (max-width: 1023px) { + .hero.is-warning .navbar-menu { + background-color: #ffdd57; } } + .hero.is-warning .navbar-item, + .hero.is-warning .navbar-link { + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning a.navbar-item:hover, .hero.is-warning a.navbar-item.is-active, + .hero.is-warning .navbar-link:hover, + .hero.is-warning .navbar-link.is-active { + background-color: #ffd83d; + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning .tabs a { + color: rgba(0, 0, 0, 0.7); + opacity: 0.9; } + .hero.is-warning .tabs a:hover { + opacity: 1; } + .hero.is-warning .tabs li.is-active a { + opacity: 1; } + .hero.is-warning .tabs.is-boxed a, .hero.is-warning .tabs.is-toggle a { + color: rgba(0, 0, 0, 0.7); } + .hero.is-warning .tabs.is-boxed a:hover, .hero.is-warning .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-warning .tabs.is-boxed li.is-active a, .hero.is-warning .tabs.is-boxed li.is-active a:hover, .hero.is-warning .tabs.is-toggle li.is-active a, .hero.is-warning .tabs.is-toggle li.is-active a:hover { + background-color: rgba(0, 0, 0, 0.7); + border-color: rgba(0, 0, 0, 0.7); + color: #ffdd57; } + .hero.is-warning.is-bold { + background-image: linear-gradient(141deg, #ffaf24 0%, #ffdd57 71%, #fffa70 100%); } + @media screen and (max-width: 768px) { + .hero.is-warning.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #ffaf24 0%, #ffdd57 71%, #fffa70 100%); } } + .hero.is-danger { + background-color: #f14668; + color: #fff; } + .hero.is-danger a:not(.button):not(.dropdown-item):not(.tag):not(.pagination-link.is-current), + .hero.is-danger strong { + color: inherit; } + .hero.is-danger .title { + color: #fff; } + .hero.is-danger .subtitle { + color: rgba(255, 255, 255, 0.9); } + .hero.is-danger .subtitle a:not(.button), + .hero.is-danger .subtitle strong { + color: #fff; } + @media screen and (max-width: 1023px) { + .hero.is-danger .navbar-menu { + background-color: #f14668; } } + .hero.is-danger .navbar-item, + .hero.is-danger .navbar-link { + color: rgba(255, 255, 255, 0.7); } + .hero.is-danger a.navbar-item:hover, .hero.is-danger a.navbar-item.is-active, + .hero.is-danger .navbar-link:hover, + .hero.is-danger .navbar-link.is-active { + background-color: #ef2e55; + color: #fff; } + .hero.is-danger .tabs a { + color: #fff; + opacity: 0.9; } + .hero.is-danger .tabs a:hover { + opacity: 1; } + .hero.is-danger .tabs li.is-active a { + opacity: 1; } + .hero.is-danger .tabs.is-boxed a, .hero.is-danger .tabs.is-toggle a { + color: #fff; } + .hero.is-danger .tabs.is-boxed a:hover, .hero.is-danger .tabs.is-toggle a:hover { + background-color: rgba(10, 10, 10, 0.1); } + .hero.is-danger .tabs.is-boxed li.is-active a, .hero.is-danger .tabs.is-boxed li.is-active a:hover, .hero.is-danger .tabs.is-toggle li.is-active a, .hero.is-danger .tabs.is-toggle li.is-active a:hover { + background-color: #fff; + border-color: #fff; + color: #f14668; } + .hero.is-danger.is-bold { + background-image: linear-gradient(141deg, #fa0a62 0%, #f14668 71%, #f7595f 100%); } + @media screen and (max-width: 768px) { + .hero.is-danger.is-bold .navbar-menu { + background-image: linear-gradient(141deg, #fa0a62 0%, #f14668 71%, #f7595f 100%); } } + .hero.is-small .hero-body { + padding: 1.5rem; } + @media screen and (min-width: 769px), print { + .hero.is-medium .hero-body { + padding: 9rem 1.5rem; } } + @media screen and (min-width: 769px), print { + .hero.is-large .hero-body { + padding: 18rem 1.5rem; } } + .hero.is-halfheight .hero-body, .hero.is-fullheight .hero-body, .hero.is-fullheight-with-navbar .hero-body { + align-items: center; + display: flex; } + .hero.is-halfheight .hero-body > .container, .hero.is-fullheight .hero-body > .container, .hero.is-fullheight-with-navbar .hero-body > .container { + flex-grow: 1; + flex-shrink: 1; } + .hero.is-halfheight { + min-height: 50vh; } + .hero.is-fullheight { + min-height: 100vh; } + +.hero-video { + overflow: hidden; } + .hero-video video { + left: 50%; + min-height: 100%; + min-width: 100%; + position: absolute; + top: 50%; + transform: translate3d(-50%, -50%, 0); } + .hero-video.is-transparent { + opacity: 0.3; } + @media screen and (max-width: 768px) { + .hero-video { + display: none; } } + +.hero-buttons { + margin-top: 1.5rem; } + @media screen and (max-width: 768px) { + .hero-buttons .button { + display: flex; } + .hero-buttons .button:not(:last-child) { + margin-bottom: 0.75rem; } } + @media screen and (min-width: 769px), print { + .hero-buttons { + display: flex; + justify-content: center; } + .hero-buttons .button:not(:last-child) { + margin-right: 1.5rem; } } + +.hero-head, +.hero-foot { + flex-grow: 0; + flex-shrink: 0; } + +.hero-body { + flex-grow: 1; + flex-shrink: 0; + padding: 3rem 1.5rem; } + +.section { + padding: 3rem 1.5rem; } + @media screen and (min-width: 1024px) { + .section.is-medium { + padding: 9rem 1.5rem; } + .section.is-large { + padding: 18rem 1.5rem; } } + +.footer { + background-color: #fafafa; + padding: 3rem 1.5rem 6rem; } + +[data-tooltip]:not(.is-loading), [data-tooltip]:not(.is-disabled), [data-tooltip]:not([disabled]) { + cursor: pointer; + overflow: visible; + position: relative; } + [data-tooltip]:not(.is-loading)::before, [data-tooltip]:not(.is-loading)::after, [data-tooltip]:not(.is-disabled)::before, [data-tooltip]:not(.is-disabled)::after, [data-tooltip]:not([disabled])::before, [data-tooltip]:not([disabled])::after { + box-sizing: border-box; + color: white; + display: inline-block; + font-family: BlinkMacSystemFont, -apple-system, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", "Helvetica", "Arial", sans-serif; + font-size: 0.75rem; + hyphens: auto; + opacity: 0; + overflow: hidden; + pointer-events: none; + position: absolute; + visibility: hidden; + z-index: 1020; } + [data-tooltip]:not(.is-loading)::after, [data-tooltip]:not(.is-disabled)::after, [data-tooltip]:not([disabled])::after { + content: ''; + border-style: solid; + border-width: 6px; + border-color: rgba(74, 74, 74, 0.9) transparent transparent transparent; + margin-bottom: -5px; } + [data-tooltip]:not(.is-loading)::after, [data-tooltip]:not(.is-disabled)::after, [data-tooltip]:not([disabled])::after { + top: 0; + right: auto; + bottom: auto; + left: 50%; + margin-top: -5px; + margin-right: auto; + margin-bottom: auto; + margin-left: -5px; + border-color: rgba(74, 74, 74, 0.9) transparent transparent transparent; } + [data-tooltip]:not(.is-loading)::before, [data-tooltip]:not(.is-disabled)::before, [data-tooltip]:not([disabled])::before { + background: rgba(74, 74, 74, 0.9); + border-radius: 2px; + content: attr(data-tooltip); + padding: 0.5rem 1rem; + text-overflow: ellipsis; + white-space: pre; } + [data-tooltip]:not(.is-loading)::before, [data-tooltip]:not(.is-disabled)::before, [data-tooltip]:not([disabled])::before { + top: 0; + right: auto; + bottom: auto; + left: 50%; + top: 0; + margin-top: -5px; + margin-bottom: auto; + transform: translate(-50%, -100%); } + [data-tooltip]:not(.is-loading).has-tooltip-bottom::after, [data-tooltip]:not(.is-disabled).has-tooltip-bottom::after, [data-tooltip]:not([disabled]).has-tooltip-bottom::after { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-right: auto; + margin-bottom: -5px; + margin-left: -5px; + border-color: transparent transparent rgba(74, 74, 74, 0.9) transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-bottom::before, [data-tooltip]:not(.is-disabled).has-tooltip-bottom::before, [data-tooltip]:not([disabled]).has-tooltip-bottom::before { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-bottom: -5px; + transform: translate(-50%, 100%); } + [data-tooltip]:not(.is-loading).has-tooltip-left::after, [data-tooltip]:not(.is-disabled).has-tooltip-left::after, [data-tooltip]:not([disabled]).has-tooltip-left::after { + top: auto; + right: auto; + bottom: 50%; + left: 0; + margin-top: auto; + margin-right: auto; + margin-bottom: -6px; + margin-left: -11px; + border-color: transparent transparent transparent rgba(74, 74, 74, 0.9); } + [data-tooltip]:not(.is-loading).has-tooltip-left::before, [data-tooltip]:not(.is-disabled).has-tooltip-left::before, [data-tooltip]:not([disabled]).has-tooltip-left::before { + top: auto; + right: auto; + bottom: 50%; + left: -11px; + transform: translate(-100%, 50%); } + [data-tooltip]:not(.is-loading).has-tooltip-right::after, [data-tooltip]:not(.is-disabled).has-tooltip-right::after, [data-tooltip]:not([disabled]).has-tooltip-right::after { + top: auto; + right: 0; + bottom: 50%; + left: auto; + margin-top: auto; + margin-right: -11px; + margin-bottom: -6px; + margin-left: auto; + border-color: transparent rgba(74, 74, 74, 0.9) transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-right::before, [data-tooltip]:not(.is-disabled).has-tooltip-right::before, [data-tooltip]:not([disabled]).has-tooltip-right::before { + top: auto; + right: -11px; + bottom: 50%; + left: auto; + margin-top: auto; + transform: translate(100%, 50%); } + [data-tooltip]:not(.is-loading).has-tooltip-multiline::before, [data-tooltip]:not(.is-disabled).has-tooltip-multiline::before, [data-tooltip]:not([disabled]).has-tooltip-multiline::before { + height: auto; + width: 15rem; + max-width: 15rem; + text-overflow: clip; + white-space: normal; + word-break: keep-all; } + [data-tooltip]:not(.is-loading).has-tooltip-white.has-tooltip-bottom::after, [data-tooltip]:not(.is-disabled).has-tooltip-white.has-tooltip-bottom::after, [data-tooltip]:not([disabled]).has-tooltip-white.has-tooltip-bottom::after { + border-color: transparent transparent rgba(255, 255, 255, 0.9) transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-white.has-tooltip-left::after, [data-tooltip]:not(.is-disabled).has-tooltip-white.has-tooltip-left::after, [data-tooltip]:not([disabled]).has-tooltip-white.has-tooltip-left::after { + border-color: transparent transparent transparent rgba(255, 255, 255, 0.9); } + [data-tooltip]:not(.is-loading).has-tooltip-white.has-tooltip-right::after, [data-tooltip]:not(.is-disabled).has-tooltip-white.has-tooltip-right::after, [data-tooltip]:not([disabled]).has-tooltip-white.has-tooltip-right::after { + border-color: transparent rgba(255, 255, 255, 0.9) transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-white:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-loading).has-tooltip-white:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-loading).has-tooltip-white:not(.has-tooltip-right)::after, [data-tooltip]:not(.is-disabled).has-tooltip-white:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-disabled).has-tooltip-white:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-disabled).has-tooltip-white:not(.has-tooltip-right)::after, [data-tooltip]:not([disabled]).has-tooltip-white:not(.has-tooltip-bottom)::after, [data-tooltip]:not([disabled]).has-tooltip-white:not(.has-tooltip-left)::after, [data-tooltip]:not([disabled]).has-tooltip-white:not(.has-tooltip-right)::after { + border-color: rgba(255, 255, 255, 0.9) transparent transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-white:before, [data-tooltip]:not(.is-disabled).has-tooltip-white:before, [data-tooltip]:not([disabled]).has-tooltip-white:before { + background-color: rgba(255, 255, 255, 0.9); + color: #0a0a0a; } + [data-tooltip]:not(.is-loading).has-tooltip-black.has-tooltip-bottom::after, [data-tooltip]:not(.is-disabled).has-tooltip-black.has-tooltip-bottom::after, [data-tooltip]:not([disabled]).has-tooltip-black.has-tooltip-bottom::after { + border-color: transparent transparent rgba(10, 10, 10, 0.9) transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-black.has-tooltip-left::after, [data-tooltip]:not(.is-disabled).has-tooltip-black.has-tooltip-left::after, [data-tooltip]:not([disabled]).has-tooltip-black.has-tooltip-left::after { + border-color: transparent transparent transparent rgba(10, 10, 10, 0.9); } + [data-tooltip]:not(.is-loading).has-tooltip-black.has-tooltip-right::after, [data-tooltip]:not(.is-disabled).has-tooltip-black.has-tooltip-right::after, [data-tooltip]:not([disabled]).has-tooltip-black.has-tooltip-right::after { + border-color: transparent rgba(10, 10, 10, 0.9) transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-black:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-loading).has-tooltip-black:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-loading).has-tooltip-black:not(.has-tooltip-right)::after, [data-tooltip]:not(.is-disabled).has-tooltip-black:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-disabled).has-tooltip-black:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-disabled).has-tooltip-black:not(.has-tooltip-right)::after, [data-tooltip]:not([disabled]).has-tooltip-black:not(.has-tooltip-bottom)::after, [data-tooltip]:not([disabled]).has-tooltip-black:not(.has-tooltip-left)::after, [data-tooltip]:not([disabled]).has-tooltip-black:not(.has-tooltip-right)::after { + border-color: rgba(10, 10, 10, 0.9) transparent transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-black:before, [data-tooltip]:not(.is-disabled).has-tooltip-black:before, [data-tooltip]:not([disabled]).has-tooltip-black:before { + background-color: rgba(10, 10, 10, 0.9); + color: white; } + [data-tooltip]:not(.is-loading).has-tooltip-light.has-tooltip-bottom::after, [data-tooltip]:not(.is-disabled).has-tooltip-light.has-tooltip-bottom::after, [data-tooltip]:not([disabled]).has-tooltip-light.has-tooltip-bottom::after { + border-color: transparent transparent rgba(245, 245, 245, 0.9) transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-light.has-tooltip-left::after, [data-tooltip]:not(.is-disabled).has-tooltip-light.has-tooltip-left::after, [data-tooltip]:not([disabled]).has-tooltip-light.has-tooltip-left::after { + border-color: transparent transparent transparent rgba(245, 245, 245, 0.9); } + [data-tooltip]:not(.is-loading).has-tooltip-light.has-tooltip-right::after, [data-tooltip]:not(.is-disabled).has-tooltip-light.has-tooltip-right::after, [data-tooltip]:not([disabled]).has-tooltip-light.has-tooltip-right::after { + border-color: transparent rgba(245, 245, 245, 0.9) transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-light:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-loading).has-tooltip-light:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-loading).has-tooltip-light:not(.has-tooltip-right)::after, [data-tooltip]:not(.is-disabled).has-tooltip-light:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-disabled).has-tooltip-light:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-disabled).has-tooltip-light:not(.has-tooltip-right)::after, [data-tooltip]:not([disabled]).has-tooltip-light:not(.has-tooltip-bottom)::after, [data-tooltip]:not([disabled]).has-tooltip-light:not(.has-tooltip-left)::after, [data-tooltip]:not([disabled]).has-tooltip-light:not(.has-tooltip-right)::after { + border-color: rgba(245, 245, 245, 0.9) transparent transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-light:before, [data-tooltip]:not(.is-disabled).has-tooltip-light:before, [data-tooltip]:not([disabled]).has-tooltip-light:before { + background-color: rgba(245, 245, 245, 0.9); + color: rgba(0, 0, 0, 0.7); } + [data-tooltip]:not(.is-loading).has-tooltip-dark.has-tooltip-bottom::after, [data-tooltip]:not(.is-disabled).has-tooltip-dark.has-tooltip-bottom::after, [data-tooltip]:not([disabled]).has-tooltip-dark.has-tooltip-bottom::after { + border-color: transparent transparent rgba(54, 54, 54, 0.9) transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-dark.has-tooltip-left::after, [data-tooltip]:not(.is-disabled).has-tooltip-dark.has-tooltip-left::after, [data-tooltip]:not([disabled]).has-tooltip-dark.has-tooltip-left::after { + border-color: transparent transparent transparent rgba(54, 54, 54, 0.9); } + [data-tooltip]:not(.is-loading).has-tooltip-dark.has-tooltip-right::after, [data-tooltip]:not(.is-disabled).has-tooltip-dark.has-tooltip-right::after, [data-tooltip]:not([disabled]).has-tooltip-dark.has-tooltip-right::after { + border-color: transparent rgba(54, 54, 54, 0.9) transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-dark:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-loading).has-tooltip-dark:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-loading).has-tooltip-dark:not(.has-tooltip-right)::after, [data-tooltip]:not(.is-disabled).has-tooltip-dark:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-disabled).has-tooltip-dark:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-disabled).has-tooltip-dark:not(.has-tooltip-right)::after, [data-tooltip]:not([disabled]).has-tooltip-dark:not(.has-tooltip-bottom)::after, [data-tooltip]:not([disabled]).has-tooltip-dark:not(.has-tooltip-left)::after, [data-tooltip]:not([disabled]).has-tooltip-dark:not(.has-tooltip-right)::after { + border-color: rgba(54, 54, 54, 0.9) transparent transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-dark:before, [data-tooltip]:not(.is-disabled).has-tooltip-dark:before, [data-tooltip]:not([disabled]).has-tooltip-dark:before { + background-color: rgba(54, 54, 54, 0.9); + color: #fff; } + [data-tooltip]:not(.is-loading).has-tooltip-primary.has-tooltip-bottom::after, [data-tooltip]:not(.is-disabled).has-tooltip-primary.has-tooltip-bottom::after, [data-tooltip]:not([disabled]).has-tooltip-primary.has-tooltip-bottom::after { + border-color: transparent transparent rgba(0, 209, 178, 0.9) transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-primary.has-tooltip-left::after, [data-tooltip]:not(.is-disabled).has-tooltip-primary.has-tooltip-left::after, [data-tooltip]:not([disabled]).has-tooltip-primary.has-tooltip-left::after { + border-color: transparent transparent transparent rgba(0, 209, 178, 0.9); } + [data-tooltip]:not(.is-loading).has-tooltip-primary.has-tooltip-right::after, [data-tooltip]:not(.is-disabled).has-tooltip-primary.has-tooltip-right::after, [data-tooltip]:not([disabled]).has-tooltip-primary.has-tooltip-right::after { + border-color: transparent rgba(0, 209, 178, 0.9) transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-primary:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-loading).has-tooltip-primary:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-loading).has-tooltip-primary:not(.has-tooltip-right)::after, [data-tooltip]:not(.is-disabled).has-tooltip-primary:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-disabled).has-tooltip-primary:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-disabled).has-tooltip-primary:not(.has-tooltip-right)::after, [data-tooltip]:not([disabled]).has-tooltip-primary:not(.has-tooltip-bottom)::after, [data-tooltip]:not([disabled]).has-tooltip-primary:not(.has-tooltip-left)::after, [data-tooltip]:not([disabled]).has-tooltip-primary:not(.has-tooltip-right)::after { + border-color: rgba(0, 209, 178, 0.9) transparent transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-primary:before, [data-tooltip]:not(.is-disabled).has-tooltip-primary:before, [data-tooltip]:not([disabled]).has-tooltip-primary:before { + background-color: rgba(0, 209, 178, 0.9); + color: #fff; } + [data-tooltip]:not(.is-loading).has-tooltip-link.has-tooltip-bottom::after, [data-tooltip]:not(.is-disabled).has-tooltip-link.has-tooltip-bottom::after, [data-tooltip]:not([disabled]).has-tooltip-link.has-tooltip-bottom::after { + border-color: transparent transparent rgba(50, 115, 220, 0.9) transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-link.has-tooltip-left::after, [data-tooltip]:not(.is-disabled).has-tooltip-link.has-tooltip-left::after, [data-tooltip]:not([disabled]).has-tooltip-link.has-tooltip-left::after { + border-color: transparent transparent transparent rgba(50, 115, 220, 0.9); } + [data-tooltip]:not(.is-loading).has-tooltip-link.has-tooltip-right::after, [data-tooltip]:not(.is-disabled).has-tooltip-link.has-tooltip-right::after, [data-tooltip]:not([disabled]).has-tooltip-link.has-tooltip-right::after { + border-color: transparent rgba(50, 115, 220, 0.9) transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-link:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-loading).has-tooltip-link:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-loading).has-tooltip-link:not(.has-tooltip-right)::after, [data-tooltip]:not(.is-disabled).has-tooltip-link:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-disabled).has-tooltip-link:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-disabled).has-tooltip-link:not(.has-tooltip-right)::after, [data-tooltip]:not([disabled]).has-tooltip-link:not(.has-tooltip-bottom)::after, [data-tooltip]:not([disabled]).has-tooltip-link:not(.has-tooltip-left)::after, [data-tooltip]:not([disabled]).has-tooltip-link:not(.has-tooltip-right)::after { + border-color: rgba(50, 115, 220, 0.9) transparent transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-link:before, [data-tooltip]:not(.is-disabled).has-tooltip-link:before, [data-tooltip]:not([disabled]).has-tooltip-link:before { + background-color: rgba(50, 115, 220, 0.9); + color: #fff; } + [data-tooltip]:not(.is-loading).has-tooltip-info.has-tooltip-bottom::after, [data-tooltip]:not(.is-disabled).has-tooltip-info.has-tooltip-bottom::after, [data-tooltip]:not([disabled]).has-tooltip-info.has-tooltip-bottom::after { + border-color: transparent transparent rgba(50, 152, 220, 0.9) transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-info.has-tooltip-left::after, [data-tooltip]:not(.is-disabled).has-tooltip-info.has-tooltip-left::after, [data-tooltip]:not([disabled]).has-tooltip-info.has-tooltip-left::after { + border-color: transparent transparent transparent rgba(50, 152, 220, 0.9); } + [data-tooltip]:not(.is-loading).has-tooltip-info.has-tooltip-right::after, [data-tooltip]:not(.is-disabled).has-tooltip-info.has-tooltip-right::after, [data-tooltip]:not([disabled]).has-tooltip-info.has-tooltip-right::after { + border-color: transparent rgba(50, 152, 220, 0.9) transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-info:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-loading).has-tooltip-info:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-loading).has-tooltip-info:not(.has-tooltip-right)::after, [data-tooltip]:not(.is-disabled).has-tooltip-info:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-disabled).has-tooltip-info:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-disabled).has-tooltip-info:not(.has-tooltip-right)::after, [data-tooltip]:not([disabled]).has-tooltip-info:not(.has-tooltip-bottom)::after, [data-tooltip]:not([disabled]).has-tooltip-info:not(.has-tooltip-left)::after, [data-tooltip]:not([disabled]).has-tooltip-info:not(.has-tooltip-right)::after { + border-color: rgba(50, 152, 220, 0.9) transparent transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-info:before, [data-tooltip]:not(.is-disabled).has-tooltip-info:before, [data-tooltip]:not([disabled]).has-tooltip-info:before { + background-color: rgba(50, 152, 220, 0.9); + color: #fff; } + [data-tooltip]:not(.is-loading).has-tooltip-success.has-tooltip-bottom::after, [data-tooltip]:not(.is-disabled).has-tooltip-success.has-tooltip-bottom::after, [data-tooltip]:not([disabled]).has-tooltip-success.has-tooltip-bottom::after { + border-color: transparent transparent rgba(72, 199, 116, 0.9) transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-success.has-tooltip-left::after, [data-tooltip]:not(.is-disabled).has-tooltip-success.has-tooltip-left::after, [data-tooltip]:not([disabled]).has-tooltip-success.has-tooltip-left::after { + border-color: transparent transparent transparent rgba(72, 199, 116, 0.9); } + [data-tooltip]:not(.is-loading).has-tooltip-success.has-tooltip-right::after, [data-tooltip]:not(.is-disabled).has-tooltip-success.has-tooltip-right::after, [data-tooltip]:not([disabled]).has-tooltip-success.has-tooltip-right::after { + border-color: transparent rgba(72, 199, 116, 0.9) transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-success:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-loading).has-tooltip-success:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-loading).has-tooltip-success:not(.has-tooltip-right)::after, [data-tooltip]:not(.is-disabled).has-tooltip-success:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-disabled).has-tooltip-success:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-disabled).has-tooltip-success:not(.has-tooltip-right)::after, [data-tooltip]:not([disabled]).has-tooltip-success:not(.has-tooltip-bottom)::after, [data-tooltip]:not([disabled]).has-tooltip-success:not(.has-tooltip-left)::after, [data-tooltip]:not([disabled]).has-tooltip-success:not(.has-tooltip-right)::after { + border-color: rgba(72, 199, 116, 0.9) transparent transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-success:before, [data-tooltip]:not(.is-disabled).has-tooltip-success:before, [data-tooltip]:not([disabled]).has-tooltip-success:before { + background-color: rgba(72, 199, 116, 0.9); + color: #fff; } + [data-tooltip]:not(.is-loading).has-tooltip-warning.has-tooltip-bottom::after, [data-tooltip]:not(.is-disabled).has-tooltip-warning.has-tooltip-bottom::after, [data-tooltip]:not([disabled]).has-tooltip-warning.has-tooltip-bottom::after { + border-color: transparent transparent rgba(255, 221, 87, 0.9) transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-warning.has-tooltip-left::after, [data-tooltip]:not(.is-disabled).has-tooltip-warning.has-tooltip-left::after, [data-tooltip]:not([disabled]).has-tooltip-warning.has-tooltip-left::after { + border-color: transparent transparent transparent rgba(255, 221, 87, 0.9); } + [data-tooltip]:not(.is-loading).has-tooltip-warning.has-tooltip-right::after, [data-tooltip]:not(.is-disabled).has-tooltip-warning.has-tooltip-right::after, [data-tooltip]:not([disabled]).has-tooltip-warning.has-tooltip-right::after { + border-color: transparent rgba(255, 221, 87, 0.9) transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-warning:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-loading).has-tooltip-warning:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-loading).has-tooltip-warning:not(.has-tooltip-right)::after, [data-tooltip]:not(.is-disabled).has-tooltip-warning:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-disabled).has-tooltip-warning:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-disabled).has-tooltip-warning:not(.has-tooltip-right)::after, [data-tooltip]:not([disabled]).has-tooltip-warning:not(.has-tooltip-bottom)::after, [data-tooltip]:not([disabled]).has-tooltip-warning:not(.has-tooltip-left)::after, [data-tooltip]:not([disabled]).has-tooltip-warning:not(.has-tooltip-right)::after { + border-color: rgba(255, 221, 87, 0.9) transparent transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-warning:before, [data-tooltip]:not(.is-disabled).has-tooltip-warning:before, [data-tooltip]:not([disabled]).has-tooltip-warning:before { + background-color: rgba(255, 221, 87, 0.9); + color: rgba(0, 0, 0, 0.7); } + [data-tooltip]:not(.is-loading).has-tooltip-danger.has-tooltip-bottom::after, [data-tooltip]:not(.is-disabled).has-tooltip-danger.has-tooltip-bottom::after, [data-tooltip]:not([disabled]).has-tooltip-danger.has-tooltip-bottom::after { + border-color: transparent transparent rgba(241, 70, 104, 0.9) transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-danger.has-tooltip-left::after, [data-tooltip]:not(.is-disabled).has-tooltip-danger.has-tooltip-left::after, [data-tooltip]:not([disabled]).has-tooltip-danger.has-tooltip-left::after { + border-color: transparent transparent transparent rgba(241, 70, 104, 0.9); } + [data-tooltip]:not(.is-loading).has-tooltip-danger.has-tooltip-right::after, [data-tooltip]:not(.is-disabled).has-tooltip-danger.has-tooltip-right::after, [data-tooltip]:not([disabled]).has-tooltip-danger.has-tooltip-right::after { + border-color: transparent rgba(241, 70, 104, 0.9) transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-danger:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-loading).has-tooltip-danger:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-loading).has-tooltip-danger:not(.has-tooltip-right)::after, [data-tooltip]:not(.is-disabled).has-tooltip-danger:not(.has-tooltip-bottom)::after, [data-tooltip]:not(.is-disabled).has-tooltip-danger:not(.has-tooltip-left)::after, [data-tooltip]:not(.is-disabled).has-tooltip-danger:not(.has-tooltip-right)::after, [data-tooltip]:not([disabled]).has-tooltip-danger:not(.has-tooltip-bottom)::after, [data-tooltip]:not([disabled]).has-tooltip-danger:not(.has-tooltip-left)::after, [data-tooltip]:not([disabled]).has-tooltip-danger:not(.has-tooltip-right)::after { + border-color: rgba(241, 70, 104, 0.9) transparent transparent transparent; } + [data-tooltip]:not(.is-loading).has-tooltip-danger:before, [data-tooltip]:not(.is-disabled).has-tooltip-danger:before, [data-tooltip]:not([disabled]).has-tooltip-danger:before { + background-color: rgba(241, 70, 104, 0.9); + color: #fff; } + [data-tooltip]:not(.is-loading):focus::before, [data-tooltip]:not(.is-loading):focus::after, [data-tooltip]:not(.is-loading):hover::before, [data-tooltip]:not(.is-loading):hover::after, [data-tooltip]:not(.is-loading).has-tooltip-active::before, [data-tooltip]:not(.is-loading).has-tooltip-active::after, [data-tooltip]:not(.is-disabled):focus::before, [data-tooltip]:not(.is-disabled):focus::after, [data-tooltip]:not(.is-disabled):hover::before, [data-tooltip]:not(.is-disabled):hover::after, [data-tooltip]:not(.is-disabled).has-tooltip-active::before, [data-tooltip]:not(.is-disabled).has-tooltip-active::after, [data-tooltip]:not([disabled]):focus::before, [data-tooltip]:not([disabled]):focus::after, [data-tooltip]:not([disabled]):hover::before, [data-tooltip]:not([disabled]):hover::after, [data-tooltip]:not([disabled]).has-tooltip-active::before, [data-tooltip]:not([disabled]).has-tooltip-active::after { + opacity: 1; + visibility: visible; } + [data-tooltip]:not(.is-loading).has-tooltip-fade::before, [data-tooltip]:not(.is-loading).has-tooltip-fade::after, [data-tooltip]:not(.is-disabled).has-tooltip-fade::before, [data-tooltip]:not(.is-disabled).has-tooltip-fade::after, [data-tooltip]:not([disabled]).has-tooltip-fade::before, [data-tooltip]:not([disabled]).has-tooltip-fade::after { + transition: opacity .3s linear, visibility .3s linear; } + +@media screen and (max-width: 768px) { + .has-tooltip-top-mobile::after { + top: 0; + right: auto; + bottom: auto; + left: 50%; + margin-top: -5px; + margin-right: auto; + margin-bottom: auto; + margin-left: -5px; + border-color: rgba(74, 74, 74, 0.9) transparent transparent transparent; } + .has-tooltip-top-mobile::before { + top: 0; + right: auto; + bottom: auto; + left: 50%; + top: 0; + margin-top: -5px; + margin-bottom: auto; + transform: translate(-50%, -100%); } } + +@media screen and (min-width: 769px), print { + .has-tooltip-top-tablet::after { + top: 0; + right: auto; + bottom: auto; + left: 50%; + margin-top: -5px; + margin-right: auto; + margin-bottom: auto; + margin-left: -5px; + border-color: rgba(74, 74, 74, 0.9) transparent transparent transparent; } + .has-tooltip-top-tablet::before { + top: 0; + right: auto; + bottom: auto; + left: 50%; + top: 0; + margin-top: -5px; + margin-bottom: auto; + transform: translate(-50%, -100%); } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-tooltip-top-tablet-only::after { + top: 0; + right: auto; + bottom: auto; + left: 50%; + margin-top: -5px; + margin-right: auto; + margin-bottom: auto; + margin-left: -5px; + border-color: rgba(74, 74, 74, 0.9) transparent transparent transparent; } + .has-tooltip-top-tablet-only::before { + top: 0; + right: auto; + bottom: auto; + left: 50%; + top: 0; + margin-top: -5px; + margin-bottom: auto; + transform: translate(-50%, -100%); } } + +@media screen and (max-width: 1023px) { + .has-tooltip-top-touch::after { + top: 0; + right: auto; + bottom: auto; + left: 50%; + margin-top: -5px; + margin-right: auto; + margin-bottom: auto; + margin-left: -5px; + border-color: rgba(74, 74, 74, 0.9) transparent transparent transparent; } + .has-tooltip-top-touch::before { + top: 0; + right: auto; + bottom: auto; + left: 50%; + top: 0; + margin-top: -5px; + margin-bottom: auto; + transform: translate(-50%, -100%); } } + +@media screen and (min-width: 1024px) { + .has-tooltip-top-desktop::after { + top: 0; + right: auto; + bottom: auto; + left: 50%; + margin-top: -5px; + margin-right: auto; + margin-bottom: auto; + margin-left: -5px; + border-color: rgba(74, 74, 74, 0.9) transparent transparent transparent; } + .has-tooltip-top-desktop::before { + top: 0; + right: auto; + bottom: auto; + left: 50%; + top: 0; + margin-top: -5px; + margin-bottom: auto; + transform: translate(-50%, -100%); } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-tooltip-top-desktop-only::after { + top: 0; + right: auto; + bottom: auto; + left: 50%; + margin-top: -5px; + margin-right: auto; + margin-bottom: auto; + margin-left: -5px; + border-color: rgba(74, 74, 74, 0.9) transparent transparent transparent; } + .has-tooltip-top-desktop-only::before { + top: 0; + right: auto; + bottom: auto; + left: 50%; + top: 0; + margin-top: -5px; + margin-bottom: auto; + transform: translate(-50%, -100%); } } + +@media screen and (max-width: 1215px) { + .has-tooltip-top-until-widescreen::after { + top: 0; + right: auto; + bottom: auto; + left: 50%; + margin-top: -5px; + margin-right: auto; + margin-bottom: auto; + margin-left: -5px; + border-color: rgba(74, 74, 74, 0.9) transparent transparent transparent; } + .has-tooltip-top-until-widescreen::before { + top: 0; + right: auto; + bottom: auto; + left: 50%; + top: 0; + margin-top: -5px; + margin-bottom: auto; + transform: translate(-50%, -100%); } } + +@media screen and (min-width: 1216px) { + .has-tooltip-top-widescreen::after { + top: 0; + right: auto; + bottom: auto; + left: 50%; + margin-top: -5px; + margin-right: auto; + margin-bottom: auto; + margin-left: -5px; + border-color: rgba(74, 74, 74, 0.9) transparent transparent transparent; } + .has-tooltip-top-widescreen::before { + top: 0; + right: auto; + bottom: auto; + left: 50%; + top: 0; + margin-top: -5px; + margin-bottom: auto; + transform: translate(-50%, -100%); } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-tooltip-top-widescreen-only::after { + top: 0; + right: auto; + bottom: auto; + left: 50%; + margin-top: -5px; + margin-right: auto; + margin-bottom: auto; + margin-left: -5px; + border-color: rgba(74, 74, 74, 0.9) transparent transparent transparent; } + .has-tooltip-top-widescreen-only::before { + top: 0; + right: auto; + bottom: auto; + left: 50%; + top: 0; + margin-top: -5px; + margin-bottom: auto; + transform: translate(-50%, -100%); } } + +@media screen and (max-width: 1407px) { + .has-tooltip-top-until-fullhd::after { + top: 0; + right: auto; + bottom: auto; + left: 50%; + margin-top: -5px; + margin-right: auto; + margin-bottom: auto; + margin-left: -5px; + border-color: rgba(74, 74, 74, 0.9) transparent transparent transparent; } + .has-tooltip-top-until-fullhd::before { + top: 0; + right: auto; + bottom: auto; + left: 50%; + top: 0; + margin-top: -5px; + margin-bottom: auto; + transform: translate(-50%, -100%); } } + +@media screen and (min-width: 1408px) { + .has-tooltip-top-fullhd::after { + top: 0; + right: auto; + bottom: auto; + left: 50%; + margin-top: -5px; + margin-right: auto; + margin-bottom: auto; + margin-left: -5px; + border-color: rgba(74, 74, 74, 0.9) transparent transparent transparent; } + .has-tooltip-top-fullhd::before { + top: 0; + right: auto; + bottom: auto; + left: 50%; + top: 0; + margin-top: -5px; + margin-bottom: auto; + transform: translate(-50%, -100%); } } + +@media screen and (max-width: 768px) { + .has-tooltip-right-mobile::after { + top: auto; + right: 0; + bottom: 50%; + left: auto; + margin-top: auto; + margin-right: -11px; + margin-bottom: -6px; + margin-left: auto; + border-color: transparent rgba(74, 74, 74, 0.9) transparent transparent; } + .has-tooltip-right-mobile::before { + top: auto; + right: -11px; + bottom: 50%; + left: auto; + margin-top: auto; + transform: translate(100%, 50%); } } + +@media screen and (min-width: 769px), print { + .has-tooltip-right-tablet::after { + top: auto; + right: 0; + bottom: 50%; + left: auto; + margin-top: auto; + margin-right: -11px; + margin-bottom: -6px; + margin-left: auto; + border-color: transparent rgba(74, 74, 74, 0.9) transparent transparent; } + .has-tooltip-right-tablet::before { + top: auto; + right: -11px; + bottom: 50%; + left: auto; + margin-top: auto; + transform: translate(100%, 50%); } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-tooltip-right-tablet-only::after { + top: auto; + right: 0; + bottom: 50%; + left: auto; + margin-top: auto; + margin-right: -11px; + margin-bottom: -6px; + margin-left: auto; + border-color: transparent rgba(74, 74, 74, 0.9) transparent transparent; } + .has-tooltip-right-tablet-only::before { + top: auto; + right: -11px; + bottom: 50%; + left: auto; + margin-top: auto; + transform: translate(100%, 50%); } } + +@media screen and (max-width: 1023px) { + .has-tooltip-right-touch::after { + top: auto; + right: 0; + bottom: 50%; + left: auto; + margin-top: auto; + margin-right: -11px; + margin-bottom: -6px; + margin-left: auto; + border-color: transparent rgba(74, 74, 74, 0.9) transparent transparent; } + .has-tooltip-right-touch::before { + top: auto; + right: -11px; + bottom: 50%; + left: auto; + margin-top: auto; + transform: translate(100%, 50%); } } + +@media screen and (min-width: 1024px) { + .has-tooltip-right-desktop::after { + top: auto; + right: 0; + bottom: 50%; + left: auto; + margin-top: auto; + margin-right: -11px; + margin-bottom: -6px; + margin-left: auto; + border-color: transparent rgba(74, 74, 74, 0.9) transparent transparent; } + .has-tooltip-right-desktop::before { + top: auto; + right: -11px; + bottom: 50%; + left: auto; + margin-top: auto; + transform: translate(100%, 50%); } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-tooltip-right-desktop-only::after { + top: auto; + right: 0; + bottom: 50%; + left: auto; + margin-top: auto; + margin-right: -11px; + margin-bottom: -6px; + margin-left: auto; + border-color: transparent rgba(74, 74, 74, 0.9) transparent transparent; } + .has-tooltip-right-desktop-only::before { + top: auto; + right: -11px; + bottom: 50%; + left: auto; + margin-top: auto; + transform: translate(100%, 50%); } } + +@media screen and (max-width: 1215px) { + .has-tooltip-right-until-widescreen::after { + top: auto; + right: 0; + bottom: 50%; + left: auto; + margin-top: auto; + margin-right: -11px; + margin-bottom: -6px; + margin-left: auto; + border-color: transparent rgba(74, 74, 74, 0.9) transparent transparent; } + .has-tooltip-right-until-widescreen::before { + top: auto; + right: -11px; + bottom: 50%; + left: auto; + margin-top: auto; + transform: translate(100%, 50%); } } + +@media screen and (min-width: 1216px) { + .has-tooltip-right-widescreen::after { + top: auto; + right: 0; + bottom: 50%; + left: auto; + margin-top: auto; + margin-right: -11px; + margin-bottom: -6px; + margin-left: auto; + border-color: transparent rgba(74, 74, 74, 0.9) transparent transparent; } + .has-tooltip-right-widescreen::before { + top: auto; + right: -11px; + bottom: 50%; + left: auto; + margin-top: auto; + transform: translate(100%, 50%); } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-tooltip-right-widescreen-only::after { + top: auto; + right: 0; + bottom: 50%; + left: auto; + margin-top: auto; + margin-right: -11px; + margin-bottom: -6px; + margin-left: auto; + border-color: transparent rgba(74, 74, 74, 0.9) transparent transparent; } + .has-tooltip-right-widescreen-only::before { + top: auto; + right: -11px; + bottom: 50%; + left: auto; + margin-top: auto; + transform: translate(100%, 50%); } } + +@media screen and (max-width: 1407px) { + .has-tooltip-right-until-fullhd::after { + top: auto; + right: 0; + bottom: 50%; + left: auto; + margin-top: auto; + margin-right: -11px; + margin-bottom: -6px; + margin-left: auto; + border-color: transparent rgba(74, 74, 74, 0.9) transparent transparent; } + .has-tooltip-right-until-fullhd::before { + top: auto; + right: -11px; + bottom: 50%; + left: auto; + margin-top: auto; + transform: translate(100%, 50%); } } + +@media screen and (min-width: 1408px) { + .has-tooltip-right-fullhd::after { + top: auto; + right: 0; + bottom: 50%; + left: auto; + margin-top: auto; + margin-right: -11px; + margin-bottom: -6px; + margin-left: auto; + border-color: transparent rgba(74, 74, 74, 0.9) transparent transparent; } + .has-tooltip-right-fullhd::before { + top: auto; + right: -11px; + bottom: 50%; + left: auto; + margin-top: auto; + transform: translate(100%, 50%); } } + +@media screen and (max-width: 768px) { + .has-tooltip-bottom-mobile::after { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-right: auto; + margin-bottom: -5px; + margin-left: -5px; + border-color: transparent transparent rgba(74, 74, 74, 0.9) transparent; } + .has-tooltip-bottom-mobile::before { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-bottom: -5px; + transform: translate(-50%, 100%); } } + +@media screen and (min-width: 769px), print { + .has-tooltip-bottom-tablet::after { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-right: auto; + margin-bottom: -5px; + margin-left: -5px; + border-color: transparent transparent rgba(74, 74, 74, 0.9) transparent; } + .has-tooltip-bottom-tablet::before { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-bottom: -5px; + transform: translate(-50%, 100%); } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-tooltip-bottom-tablet-only::after { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-right: auto; + margin-bottom: -5px; + margin-left: -5px; + border-color: transparent transparent rgba(74, 74, 74, 0.9) transparent; } + .has-tooltip-bottom-tablet-only::before { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-bottom: -5px; + transform: translate(-50%, 100%); } } + +@media screen and (max-width: 1023px) { + .has-tooltip-bottom-touch::after { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-right: auto; + margin-bottom: -5px; + margin-left: -5px; + border-color: transparent transparent rgba(74, 74, 74, 0.9) transparent; } + .has-tooltip-bottom-touch::before { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-bottom: -5px; + transform: translate(-50%, 100%); } } + +@media screen and (min-width: 1024px) { + .has-tooltip-bottom-desktop::after { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-right: auto; + margin-bottom: -5px; + margin-left: -5px; + border-color: transparent transparent rgba(74, 74, 74, 0.9) transparent; } + .has-tooltip-bottom-desktop::before { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-bottom: -5px; + transform: translate(-50%, 100%); } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-tooltip-bottom-desktop-only::after { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-right: auto; + margin-bottom: -5px; + margin-left: -5px; + border-color: transparent transparent rgba(74, 74, 74, 0.9) transparent; } + .has-tooltip-bottom-desktop-only::before { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-bottom: -5px; + transform: translate(-50%, 100%); } } + +@media screen and (max-width: 1215px) { + .has-tooltip-bottom-until-widescreen::after { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-right: auto; + margin-bottom: -5px; + margin-left: -5px; + border-color: transparent transparent rgba(74, 74, 74, 0.9) transparent; } + .has-tooltip-bottom-until-widescreen::before { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-bottom: -5px; + transform: translate(-50%, 100%); } } + +@media screen and (min-width: 1216px) { + .has-tooltip-bottom-widescreen::after { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-right: auto; + margin-bottom: -5px; + margin-left: -5px; + border-color: transparent transparent rgba(74, 74, 74, 0.9) transparent; } + .has-tooltip-bottom-widescreen::before { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-bottom: -5px; + transform: translate(-50%, 100%); } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-tooltip-bottom-widescreen-only::after { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-right: auto; + margin-bottom: -5px; + margin-left: -5px; + border-color: transparent transparent rgba(74, 74, 74, 0.9) transparent; } + .has-tooltip-bottom-widescreen-only::before { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-bottom: -5px; + transform: translate(-50%, 100%); } } + +@media screen and (max-width: 1407px) { + .has-tooltip-bottom-until-fullhd::after { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-right: auto; + margin-bottom: -5px; + margin-left: -5px; + border-color: transparent transparent rgba(74, 74, 74, 0.9) transparent; } + .has-tooltip-bottom-until-fullhd::before { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-bottom: -5px; + transform: translate(-50%, 100%); } } + +@media screen and (min-width: 1408px) { + .has-tooltip-bottom-fullhd::after { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-right: auto; + margin-bottom: -5px; + margin-left: -5px; + border-color: transparent transparent rgba(74, 74, 74, 0.9) transparent; } + .has-tooltip-bottom-fullhd::before { + top: auto; + right: auto; + bottom: 0; + left: 50%; + margin-top: auto; + margin-bottom: -5px; + transform: translate(-50%, 100%); } } + +@media screen and (max-width: 768px) { + .has-tooltip-left-mobile::after { + top: auto; + right: auto; + bottom: 50%; + left: 0; + margin-top: auto; + margin-right: auto; + margin-bottom: -6px; + margin-left: -11px; + border-color: transparent transparent transparent rgba(74, 74, 74, 0.9); } + .has-tooltip-left-mobile::before { + top: auto; + right: auto; + bottom: 50%; + left: -11px; + transform: translate(-100%, 50%); } } + +@media screen and (min-width: 769px), print { + .has-tooltip-left-tablet::after { + top: auto; + right: auto; + bottom: 50%; + left: 0; + margin-top: auto; + margin-right: auto; + margin-bottom: -6px; + margin-left: -11px; + border-color: transparent transparent transparent rgba(74, 74, 74, 0.9); } + .has-tooltip-left-tablet::before { + top: auto; + right: auto; + bottom: 50%; + left: -11px; + transform: translate(-100%, 50%); } } + +@media screen and (min-width: 769px) and (max-width: 1023px) { + .has-tooltip-left-tablet-only::after { + top: auto; + right: auto; + bottom: 50%; + left: 0; + margin-top: auto; + margin-right: auto; + margin-bottom: -6px; + margin-left: -11px; + border-color: transparent transparent transparent rgba(74, 74, 74, 0.9); } + .has-tooltip-left-tablet-only::before { + top: auto; + right: auto; + bottom: 50%; + left: -11px; + transform: translate(-100%, 50%); } } + +@media screen and (max-width: 1023px) { + .has-tooltip-left-touch::after { + top: auto; + right: auto; + bottom: 50%; + left: 0; + margin-top: auto; + margin-right: auto; + margin-bottom: -6px; + margin-left: -11px; + border-color: transparent transparent transparent rgba(74, 74, 74, 0.9); } + .has-tooltip-left-touch::before { + top: auto; + right: auto; + bottom: 50%; + left: -11px; + transform: translate(-100%, 50%); } } + +@media screen and (min-width: 1024px) { + .has-tooltip-left-desktop::after { + top: auto; + right: auto; + bottom: 50%; + left: 0; + margin-top: auto; + margin-right: auto; + margin-bottom: -6px; + margin-left: -11px; + border-color: transparent transparent transparent rgba(74, 74, 74, 0.9); } + .has-tooltip-left-desktop::before { + top: auto; + right: auto; + bottom: 50%; + left: -11px; + transform: translate(-100%, 50%); } } + +@media screen and (min-width: 1024px) and (max-width: 1215px) { + .has-tooltip-left-desktop-only::after { + top: auto; + right: auto; + bottom: 50%; + left: 0; + margin-top: auto; + margin-right: auto; + margin-bottom: -6px; + margin-left: -11px; + border-color: transparent transparent transparent rgba(74, 74, 74, 0.9); } + .has-tooltip-left-desktop-only::before { + top: auto; + right: auto; + bottom: 50%; + left: -11px; + transform: translate(-100%, 50%); } } + +@media screen and (max-width: 1215px) { + .has-tooltip-left-until-widescreen::after { + top: auto; + right: auto; + bottom: 50%; + left: 0; + margin-top: auto; + margin-right: auto; + margin-bottom: -6px; + margin-left: -11px; + border-color: transparent transparent transparent rgba(74, 74, 74, 0.9); } + .has-tooltip-left-until-widescreen::before { + top: auto; + right: auto; + bottom: 50%; + left: -11px; + transform: translate(-100%, 50%); } } + +@media screen and (min-width: 1216px) { + .has-tooltip-left-widescreen::after { + top: auto; + right: auto; + bottom: 50%; + left: 0; + margin-top: auto; + margin-right: auto; + margin-bottom: -6px; + margin-left: -11px; + border-color: transparent transparent transparent rgba(74, 74, 74, 0.9); } + .has-tooltip-left-widescreen::before { + top: auto; + right: auto; + bottom: 50%; + left: -11px; + transform: translate(-100%, 50%); } } + +@media screen and (min-width: 1216px) and (max-width: 1407px) { + .has-tooltip-left-widescreen-only::after { + top: auto; + right: auto; + bottom: 50%; + left: 0; + margin-top: auto; + margin-right: auto; + margin-bottom: -6px; + margin-left: -11px; + border-color: transparent transparent transparent rgba(74, 74, 74, 0.9); } + .has-tooltip-left-widescreen-only::before { + top: auto; + right: auto; + bottom: 50%; + left: -11px; + transform: translate(-100%, 50%); } } + +@media screen and (max-width: 1407px) { + .has-tooltip-left-until-fullhd::after { + top: auto; + right: auto; + bottom: 50%; + left: 0; + margin-top: auto; + margin-right: auto; + margin-bottom: -6px; + margin-left: -11px; + border-color: transparent transparent transparent rgba(74, 74, 74, 0.9); } + .has-tooltip-left-until-fullhd::before { + top: auto; + right: auto; + bottom: 50%; + left: -11px; + transform: translate(-100%, 50%); } } + +@media screen and (min-width: 1408px) { + .has-tooltip-left-fullhd::after { + top: auto; + right: auto; + bottom: 50%; + left: 0; + margin-top: auto; + margin-right: auto; + margin-bottom: -6px; + margin-left: -11px; + border-color: transparent transparent transparent rgba(74, 74, 74, 0.9); } + .has-tooltip-left-fullhd::before { + top: auto; + right: auto; + bottom: 50%; + left: -11px; + transform: translate(-100%, 50%); } } + +#Draw2dCanvas { + z-index: -10; } + +.fullHeight { + height: 100%; } + +.rowHeight { + height: 30px; } + +.floatLeft { + float: left; } + +.sigLineStyle { + stroke-width: 0.025; } + +.clkLineStyle { + stroke: #c8c8c8; + stroke-width: 0.0125; } + +.cursorRectStyle { + background-color: #e6e6e6; + stroke-width: 0; + opacity: 0.4; + z-index: 6; + height: 100%; + position: absolute; } + +.clkNumStyle { + font-size: 1.5%; + text-anchor: middle; + top: 0.5; } + +.clkRulerSvg { + display: block; + height: 100%; } + +.lastWaveCellSvg { + height: 100%; + display: block; + position: absolute; } + +.waveCellSvg { + display: block; + height: 100%; } + +.busValueStyle { + fill: black; + text-anchor: middle; } + +.waveLbl { + fill: black; + left: 0; + text-anchor: start; + margin: 5px; } + +.ramVals { + fill: black; + left: 0; + text-anchor: start; + margin: 3px; } + +.cursVals { + fill: black; + left: 0; + text-anchor: start; + margin: 5px; } + +.blackLabel { + fill: black; } + .blackLabel .cursValLblStyle { + left: 0; + text-anchor: start; } + +.waveLblSvgStyle { + width: 100%; } + +.waveLblDivStyle { + float: left; + clear: both; + width: 20%; } + +.cursorDivStyle { + float: right; + width: 150px; + position: relative; } + +.zoomDiv { + float: right; + position: absolute; + bottom: 4%; + right: 2%; + width: 120px; } + +.waveNamesCol { + text-align: right; + border-right: 2px solid #dbdbdb; + white-space: nowrap; + vertical-align: bottom; + font-size: 12px; + min-width: 100px; } + +.cursValsCol { + vertical-align: bottom; + font-size: 12px; + min-width: 25px; } + +.leftTable { + border: 2px solid #dbdbdb; + width: 100%; + height: 100%; + border-spacing: 0; } + +.wavesTable { + min-height: 100%; + position: relative; + border: 2px solid #dbdbdb; + overflow-x: scroll; + overflow-y: hidden; } + +.checkboxCol { + border-right: 2px solid #dbdbdb; + vertical-align: bottom; + width: 5px; } + +.wACheckboxCol { + vertical-align: bottom; + width: 5px; } + +.check { + margin: 0 5px 0 5px; + cursor: pointer; } + +.rightSectionTabs { + font-size: 80%; + overflow-x: hidden; + height: 33px; } + +.disabledButton { + pointer-events: none; + cursor: not-allowed; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; } + +.reloadButtonStyle { + margin: 0 20px 0 20px; + width: 100px; + height: 30px; + position: relative; + float: left; + border-color: gray; + border-width: 1px; } + +.newWaveButton, .delWaveButton { + margin: 0; + height: 30px; + float: left; + position: relative; + border-color: gray; + border-width: 1px; + border-radius: 0; } + +.newWaveButton { + width: 100%; } + +.delWaveButton { + margin: 0 0 0 0; + width: 50%; } + +.newWaveLabel { + font-size: 70%; + position: relative; + float: left; + vertical-align: bottom; + background: #48c774; + border: thin; } + +.updownDiv { + width: 100%; + position: relative; + height: 30px; + float: left; } + +.updownBut { + margin: 0; + display: block; + width: 100%; + height: 50%; + padding: 0 0 0 0; + top: 0; + font-size: 40%; + position: relative; + border-color: gray; + border-width: 1px; + border-radius: 0; } + +.cursor { + float: right; + position: relative; + height: 30px; + text-align: center; + width: 100px; + display: inline-block; + font-size: 13px; + margin: 0 20px 0 20px; + resize: vertical; } + .cursor .form { + margin: 0 0 0 0; + float: left; + text-align: center; + width: 40px; + display: inline-block; + font-size: 13px; + resize: vertical; + -webkit-appearance: none; + border-color: gray; + border-width: 1px 1px 1px 1px; } + +.cursLeft, .cursRight { + margin: 0; + height: 30px; + padding: 0; + width: 30px; + position: relative; + float: left; + border-color: gray; + border-width: 1px; } + +.cursLeft { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; } + +.cursRight { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; } + +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; } + +.hZoomLabel { + float: left; + position: relative; } + +.zoomButLeft, .zoomButRight { + padding: 0 0; + width: 30px; + height: 30px; + position: relative; + float: left; + border-color: gray; + border-width: 1px; + z-index: 7; } + +.zoomButLeft { + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; } + +.zoomButRight { + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; } diff --git a/src/Renderer/scss/main.scss b/src/Renderer/scss/main.scss new file mode 100644 index 0000000..8fe0501 --- /dev/null +++ b/src/Renderer/scss/main.scss @@ -0,0 +1,361 @@ +$fa-font-path: './../../../node_modules/font-awesome/fonts/'; + +@import './../../../node_modules/font-awesome/scss/font-awesome.scss'; +@import './../../../node_modules/bulma/bulma.sass'; +@import './../../../node_modules/bulma-tooltip/src/sass/index.sass'; + + +#Draw2dCanvas { + z-index: -10 +} + +//Waveform simulator styles +$transLen: 0.1; +$vPos: 0.0; +$zoomFactor: 1.2; +$waveVBextraHeight: 0.5; +$maxBusValGap: 3; +$busLabelTextSize: 0.6; // multiplied by signal height +$clkLineWidth: 0.0125; +$boxStrokeThck: 0.05; +$persvgwidth: 100; +$sigLineThick: 0.025; + +.fullHeight { + height: 100%; +} + +.rowHeight { + height: 30px; +} + +.floatLeft { + float: left; +} + +//waveform svg elements + +.sigLineStyle { + stroke-width: $sigLineThick; +} + +.clkLineStyle { + stroke: rgb(200,200,200); + stroke-width: $clkLineWidth; +} + +.cursorRectStyle { + background-color: rgb(230,230,230); + stroke-width: 0; + //fill-opacity: 0.4; + opacity: 0.4; + z-index: 6; + height: 100%; + position: absolute; +} + +.clkNumStyle { + font-size: 1.5%; + text-anchor: middle; + top: 0.5; +} + +.clkRulerSvg { + display: block; + height: 100%; +} + +.lastWaveCellSvg { + height: 100%; + display: block; + position: absolute; +} + +.waveCellSvg { + display: block; + height: 100%; +} + +//labels +.busValueStyle { + fill: black; + text-anchor: middle; +} + +.waveLbl { + fill: black; + left: 0; + text-anchor: start; + margin: 5px; +} + +.ramVals { + fill: black; + left: 0; + text-anchor: start; + margin: 3px; +} + +.cursVals { + fill: black; + left: 0; + text-anchor: start; + margin: 5px; +} + +.blackLabel { + fill: black; + + .cursValLblStyle { + left: 0; + text-anchor: start; + } +} + +.waveLblSvgStyle { + width: 100%; +} + +//divs + +.waveLblDivStyle { + float: left; + clear: both; + width: 20%; +} + +.cursorDivStyle { + float: right; + width: 150px; + position: relative; +} + +.zoomDiv { + float: right; + position: absolute; + bottom: 4%; + right: 2%; + width: 120px; +} + +.waveNamesCol { + text-align: right; + border-right: 2px solid rgb(219,219,219); + white-space: nowrap; + vertical-align: bottom; + font-size: 12px; + min-width: 100px; +} + +.cursValsCol { + vertical-align: bottom; + font-size: 12px; + min-width: 25px; +} + + +.leftTable { + border: 2px solid rgb(219,219,219); + width: 100%; + height: 100%; + border-spacing: 0; +} + +.wavesTable { + min-height: 100%; + // height: fit-content; + position: relative; + border: 2px solid rgb(219,219,219); + overflow-x: scroll; + overflow-y: hidden; +} + +.checkboxCol { + border-right: 2px solid rgb(219,219,219); + vertical-align: bottom; + width: 5px; +} + +.wACheckboxCol { + vertical-align: bottom; + width: 5px; +} + +.check { + margin: 0 5px 0 5px; + cursor: pointer; +} + +.rightSectionTabs { + font-size: 80%; + overflow-x: hidden; + height: 33px; +} + +//buttons + +.disabledButton { + pointer-events: none; + cursor: not-allowed; + opacity: 0.65; + filter: alpha(opacity=65); + -webkit-box-shadow: none; + box-shadow: none; +} + +.reloadButtonStyle { + margin: 0 20px 0 20px; + width: 100px; + height: 30px; + position: relative; + float: left; + border-color: gray; + border-width: 1px +} + +%waveNameHeaderBut { + margin: 0; + height: 30px; + float: left; + position: relative; + border-color: gray; + border-width: 1px; + border-radius: 0; +} + +.newWaveButton { + @extend %waveNameHeaderBut; + width: 100%; +} + +.delWaveButton { + @extend %waveNameHeaderBut; + margin: 0 0 0 0; + width: 50%; +} + +.newWaveLabel { + font-size: 70%; + position: relative; + float: left; + vertical-align: bottom; + background: #48c774; + border: thin; +} + +.updownDiv { + width: 100%; + position: relative; + height: 30px; + float: left; +} + +.updownBut { + margin: 0; + display: block; + width: 100%; + height: 50%; + padding: 0 0 0 0; + top: 0; + font-size: 40%; + position: relative; + //color: white; + //background: #3273dc; + border-color: gray; + border-width: 1px; + border-radius: 0; +} + +//cursor group + +.cursor { + float: right; + position: relative; + height: 30px; + text-align: center; + width: 100px; + display: inline-block; + font-size: 13px; + margin: 0 20px 0 20px; + resize: vertical; + + .form { + margin: 0 0 0 0; + float: left; + text-align: center; + width: 40px; + display: inline-block; + font-size: 13px; + resize: vertical; + -webkit-appearance: none; + border-color: gray; + border-width: 1px 1px 1px 1px; + } +} + +%cursBut { + margin: 0; + height: 30px; + padding: 0; + width: 30px; + position: relative; + //color: white; + //border: rgb(128, 128, 128); + float: left; + border-color: gray; + border-width: 1px; +} + +.cursLeft { + @extend %cursBut; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + //background: #3273dc; +} + +.cursRight { + @extend %cursBut; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; + //background: #3273dc; +} + +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +//zoom group +.hZoomLabel { + float: left; + position: relative; +} + +%zoomBut { + padding: 0 0; + width: 30px; + height: 30px; + //background: #3273dc; + //color: white; + position: relative; + float: left; + border-color: gray; + border-width: 1px; + z-index: 7; +} + +.zoomButLeft { + @extend %zoomBut; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; +} + +.zoomButRight { + @extend %zoomBut; + border-top-right-radius: 4px; + border-bottom-right-radius: 4px; +} diff --git a/static/icon-1.png b/static/icon-1.png new file mode 100644 index 0000000..076ee0e Binary files /dev/null and b/static/icon-1.png differ diff --git a/static/icon2.png b/static/icon2.png new file mode 100644 index 0000000..54ed204 Binary files /dev/null and b/static/icon2.png differ diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..37bce9b --- /dev/null +++ b/static/index.html @@ -0,0 +1,9 @@ + + + + + + +
+ + diff --git a/webpack.additions.main.js b/webpack.additions.main.js new file mode 100644 index 0000000..cfa859d --- /dev/null +++ b/webpack.additions.main.js @@ -0,0 +1,14 @@ +var path = require("path"); + +function resolve(filePath) { + return path.join(__dirname, filePath) +} + +module.exports = { + entry: resolve("src/Main/Main.fs.js"), + module: { + rules: [ + + ] + } +} diff --git a/webpack.additions.renderer.js b/webpack.additions.renderer.js new file mode 100644 index 0000000..ec9e3ce --- /dev/null +++ b/webpack.additions.renderer.js @@ -0,0 +1,36 @@ +var path = require("path"); +var HtmlWebpackPlugin = require('html-webpack-plugin'); + +function resolve(filePath) { + return path.join(__dirname, filePath) +} + + + +module.exports = { + entry: [resolve("src/Renderer/scss/main.css"),resolve("src/Renderer/Renderer.fs.js")], + resolve: { + modules: ['node_modules'] + }, + output: { + filename: "renderer.js" + }, + optimization: { + splitChunks: { + chunks: 'all', + }, + }, + plugins: [ + + ], + module: { + rules: [ + { + test: /\.js$/, + enforce: "pre", + use: ["source-map-loader"], + } + + ] + } +}