commit 869f1920318e12188018f084a1ba4af557adda4f Author: philc Date: Sun Jan 22 10:53:09 2023 +0100 first new commit diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100755 index 0000000..73ba1d2 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,15 @@ +module.exports = { + "extends": "eslint:recommended", + "rules": { + "@typescript-eslint/no-unused-vars": "off", + "arrow-body-style": "off" + }, + "env": { + "browser": true, + "es6": true, + "node": true + }, + "parserOptions": { + "ecmaVersion": "latest" + } +}; diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..214f7a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/node_modules +/tmp +/tribes +/nationchains/blocks +/yarn* \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d41c0bd --- /dev/null +++ b/LICENSE @@ -0,0 +1,232 @@ +GNU GENERAL PUBLIC LICENSE +Version 3, 29 June 2007 + +Copyright © 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 . diff --git a/README.md b/README.md new file mode 100644 index 0000000..90f8dff --- /dev/null +++ b/README.md @@ -0,0 +1,67 @@ +# apiXtribe a Decentralized Autonomous Organisation (DAO) + +You are here on the tech side, to understand under the wood how it's work and how you can contribute to this tech journey. +See [apiXtribe web site](https://apixtribe.crabdance.com) how to create a new social world with apiXtribe. + +## apiXtribe Architecture a quick view & keywords definition + +- **a nation** is a topology network of nodes town that share the same fundamental rules (engrave into a common blockchain). +- **a town** is a physical installation node of a machine (linux server) plug into a LAN network (a telecom box NAT conf) accessible into internet a WAN network (domain name redirect to a town public IP). +- **a tribe** has a unique name and is a space to host data to apply specific algo rule register at the creation of a tribe by a druid that respect the town rules +- **a pagan** 'village farmer' is a unique identification create by anyone based on PGP (public/Private key) that allow a member to proof that he owns data. Can be anonymous but all his actions are store into a blockchain of reputation. +- **a druid** 'rules master' is a pagan that owned and defined rules of a tribe, he owns a domain name (DNS) to make it tribe's data accessible over the net. As pagan he can be anonymous, he is responsible of the tribe activities and can ban a pagan of his tribe. Any pagan become a druid when he decides to create a tribe by requesting a town mayor +- **a mayor** is a owner of a physical machine, he is in charge to make a town node working (IP availibily) and accept to be part of a nation (rules of the blockchain nation). +- **a contract** is an algorythme that is written into the blockchain and will be run if an action trig. Immutable contract are the one link to the blockchain. Any pagan/druid/major can defined a contract that apply to other pagans. +- **the Xtrib coin** is the token that drive the blockchain, it materialises an exchange value and is a conterpoint +- **a git apiXtribe** is a package ready to install a town by a mayor that will be able to join a nation (then it accepts nation rules). You can also create a nation and stay alone or not. Then mayor will be able to receive druid request to create a tribe. Then druid will invite pagan to join a tribe... + +All actors will have the same target to respect contracts and are free to leave or to stay into a nation, a town or a tribe. If a contract is not fair, then a nation, tribe, will not create value. + +## Network topology + +As it is a decentralize organisation, a public address directory is replicated on each instance of a town into /nationchains .
+Each town (instance) is accessible with an anonymlous DNS https://apixtribe.crabdance.com where the IP adresse is update when elected town's IP to register a new block into the blockchain (each 10minutes). + +``` +/nationchains + /blocks #the blockchain each file is a block + /socialword + /contracts/ #sign contracts each js file is a rules register in the blockchain + /metaobject/ #sign meta data under blockchain control to validate object integrity (pagans, druid, contract,town, nation, ...) + /objects/name/ # uuid.json object description content + /searchindex/ # index files to apply CRUD in an easy way + /static/ any usefull static file + apixtribe.html # Describe the project as a end-user + namennation.html # ex: antsnation.html describe the rules for this nation and explain benefit for a futur mayor to join it + +``` + + + +## apiXtribe Documentation + +**Documentation for apiXtribe usage to start**, tuto HOW TO for user, dev ... is [here](https://apixtribe.org/doc) +- [Set up](http://gitlab.ndda.fr/philc/apixtribe/-/wikis/SETUP) +- [Manage users](http://gitlab.ndda.fr/philc/apixtribe/-/wikis/HOWTOuser) +- [Manage multilangue referentials](http://gitlab.ndda.fr/philc/apixtribe/-/wikis/HOWTOreferential) +- [How to manage trigger action](http://gitlab.ndda.fr/philc/apixtribe/-/wikis/HOWTOtriggeraction) + +To quickly test we recommand you to "Set up for dev", you just need an linux desktop and it rocks... +Read more on the wiki's project [apixtribe wiki](http://gitlab.ndda.fr/philc/apixtribe/-/wikis/home) + + +**Documentation for apiXtribe dev** is done into the gitea wiki project. +You will find anything to understand how it works under the wood. Feel free to ask question, comment to improve the code. If you need to debug or you want to add a main feature setup your machine as local (no exchange with the blockchain) + +- [Nations -> Towns -> Tribes -> Pagans Architecture](https://gitea.ndda.fr/apixtribe/apixtribe/wiki/Architecture) the social world +- [nationchains]() the blockchain and social contracts between mpayor, druids and pagans. +- [package.json and tribes/townconf.js]() setup and convention rules: eslint, unit test, multi-lang, header +- [middleware/route/Models]() restfullapi logical from routes to middleware to models to datamapper and result res.status(http code).json({data,info,moreinfo}) +- [accessrights]() Access right definition on object (Object,...) +- [Odmdb.js]() convention for object descriptor manager to index, search, create, update, delete item of an Object collections (to simplify CRUD actions for Models) +- [Pagans.js]() decentralized and anonymous publicKey for a pagan based on PGP with accessright onto other objects. Authentification process and localStorage management of 24 hours JWT. Login/psw/email. +- [Tribes.js]() A Druid space to host a web space. +- [Tags.js]() Event trackers to log any usefull event that can be used into sodial contracts +- [Messages.js]() Notification (delete after read) and message between any interactions concerning pagans (1 to many or 1 to 1), trig by social contract or by a pagan + [Setup.js]() Technical infrastructure an +- [Blockchains and Contracts]() Contracts.js diff --git a/apxtrib.js b/apxtrib.js new file mode 100755 index 0000000..c871050 --- /dev/null +++ b/apxtrib.js @@ -0,0 +1,119 @@ +const fs = require( 'fs-extra' ); +const bodyParser = require( 'body-parser' ); +const cors = require( 'cors' ); +const express = require( 'express' ); + +/******************************************* + +SEE http://gitlab.ndda.fr/philc/apixtribe/-/wikis/HOWTOoverview +To have a quick understanding before doing deeply in source code + +*********************************************/ +// check setup +if( !fs.existsSync( '/etc/nginx/nginx.conf' ) ) { + console.log( '\x1b[31m Check documentation, nginx have to be installed on this server first, no /etc/nginx/nginx.conf available, install then rerun yarn command.' ); + process.exit(); +} +if( !fs.existsSync( './tribes/townconf.js' ) ) { + console.log( `\x1b[42m####################################\nWellcome into apixtribe, you need to init your town by "yarn setup" the first time . \nCheck README's project to learn more. more.\n #####################################\x1b[0m` ); + process.exit(); +} +// config.js exist in any case from Setup.checkinit(); +const config = require( './tribes/townconf.js' ); +// Tribes allow to get local apixtribe instance context +// dataclient .tribeids [] .DOMs [] .routes (plugins {url:name route:path}) .appname {tribeid:[website]} +const dataclient = require( './models/Tribes' ) + .init(); +console.log( 'allowed DOMs to access to this apixtribe server: ', dataclient.DOMs ) +const app = express(); +app.set( 'trust proxy', true ); +// To set depending of data form or get size to send +app.use( bodyParser.urlencoded( config.bodyparse.urlencoded ) ); +// To set depending of post put json data size to send +app.use( express.json() ) +app.use( bodyParser.json( config.bodyparse.json ) ); +app.locals.tribeids = dataclient.tribeids; +console.log( 'app.locals.tribeids', app.locals.tribeids ); +// User token authentification and user init user search +const datauser = require( './models/Pagans' ) + .init( dataclient.tribeids ); +app.locals.tokens = datauser.tokens; +console.log( 'app.locals.tokens key ', Object.keys( app.locals.tokens ) ) +// Cors management +const corsOptions = { + origin: ( origin, callback ) => { + if( origin === undefined ) { + callback( null, true ); + } else if( origin.indexOf( 'chrome-extension' ) > -1 ) { + callback( null, true ); + } else { + //console.log( 'origin', origin ) + //marchais avant modif eslint const rematch = ( /^https?\:\/\/(.*)\:.*/g ).exec( origin ) + const rematch = ( /^https?:\/\/(.*):.*/g ) + .exec( origin ) + //console.log( rematch ) + let tmp = origin.replace( /http.?:\/\//g, '' ) + .split( '.' ) + + if( rematch && rematch.length > 1 ) tmp = rematch[ 1 ].split( '.' ); + //console.log( 'tmp', tmp ) + let dom = tmp[ tmp.length - 1 ]; + if( tmp.length > 1 ) { + dom = `${tmp[tmp.length-2]}.${tmp[tmp.length-1]}` + } + console.log( `origin: ${origin}, dom:${dom}, CORS allowed? : ${dataclient.DOMs.includes( dom )}` ); + if( dataclient.DOMs.includes( dom ) ) { + callback( null, true ) + } else { + console.log( `Origin is not allowed by CORS` ); + callback( new Error( 'Not allowed by CORS' ) ); + } + } + }, + exposedHeaders: Object.keys( config.exposedHeaders ) +}; +// CORS +app.use( cors( corsOptions ) ); +// Static Routes +app.use( express.static( `${__dirname}/tribes/${config.mayorId}/www/cdn/public`, { + dotfiles: 'allow' +} ) ); + +//Allow to public access a space dev delivered by apixtribe +// this is just a static open route for dev purpose, +// for production, we'll use a nginx static set to /www/app/appname +/*console.log( `${config.dnsapixtribe}/space/tribeid/website`, dataclient.appname ); +Object.keys( dataclient.appname ) + .forEach( cid => { + dataclient.appname[ cid ].forEach( website => { + app.use( `/space/${cid}/${website}`, express.static( `${config.tribes}/${cid}/spacedev/${website}` ) ); + } ) + } ); +*/ +// Routers add any routes from /routes and /plugins +console.log( 'Routes available on this apixtribe instance' ); +console.log( dataclient.routes ); +// prefix only use for dev purpose in production a proxy nginx redirect /app/ to node apixtribe + +dataclient.routes.forEach( r => { + try { + app.use( r.url, require( r.route ) ); + } catch ( err ) { + console.log( `\x1b[31m!!! WARNING issue with route ${r.route} from ${r.url} check err if route is key then solve err, if not just be aware that this route won't work on your server. If you are not the maintainer and no turn around please contact the email maintainer.\x1b[0m` ) + console.log( 'raise err-:', err ); + } +} ) +// Listen web server from config profil (dev prod, other) +app.listen( config.porthttp, () => { + console.log( `check in your browser that api works http://${config.dnsapixtribe}:${config.porthttp}` ); +} ); +/*httpServer.setTimeout( config.settimeout ); +if( config.withssl == "YES" ) { + const httpsServer = https.createServer( config.SSLCredentials, app ); + httpsServer.listen( config.port.https, () => { + console.log( `check in your browser that api works https://${config.dnsapixtribe}:${config.port.https}` ); + } ); + httpsServer.setTimeout( config.settimeout ); +};*/ + +console.log( "\x1b[42m\x1b[37m", "Made with love for people's freedom, enjoy !!!", "\x1b[0m" ); diff --git a/middlewares/ASUPhaveAccessrighttoanobject.js b/middlewares/ASUPhaveAccessrighttoanobject.js new file mode 100755 index 0000000..09c8566 --- /dev/null +++ b/middlewares/ASUPhaveAccessrighttoanobject.js @@ -0,0 +1,95 @@ +const jwt = require( 'jwt-simple' ); +const jsonfile = require( 'jsonfile' ); +const fs = require( 'fs-extra' ); +const moment = require( 'moment' ); +const glob = require( 'glob' ); +const path = require( 'path' ); + +// A REMPLACER PAR hasAccessrighton.js +/* +qui permet de passer en parametre des tests d'actions autoriser sur une objet + +*/ + + +// Check if package is installed or not to pickup the right config file +const src = ( __dirname.indexOf( '/node_modules/' ) > -1 ) ? '../../..' : '..'; +const config = require( path.normalize( `${__dirname}/${src}/config.js` ) ); + +const haveAccessrighttoanobject = ( req, res, next ) => { + /* + from isAuthenticated req.session.header.accessrights={app:{'tribeid:projet':profile}, + data:{ "sitewebsrc": "RWCDO", + "contacts": "RWCDO"}} + from the last successfull authentification. + profile is a keyword menu available into clientconf.json of tribeid + data, list of object accessright Read Write Create Delete Owner + a xuuid can read any objet if R + if O wner means that it can only read write its object create by himself + + This middleware check that we apply RESTFull CRUD concept depending of access right of a xuuid trying to act onto a xworkon tribeid + Action get = Read put = Update post = Create delete = Delete + object = req.Urlpath.split(/)[0] + */ + console.log( 'haveAccessrighttoanobject()?' ); + // req.originalUrl contain /object/action/id object id to run action + // req.route.methods ={ put:true, delete:true post:true, get:true } + const objet = req.baseUrl.slice( 1 ); //contain /object + const model = objet.charAt( 0 ) + .toUpperCase() + objet.slice( 1 ); // model u object with first letter in uppercase + let droit = ""; + let ownby = []; + /* + Check if object exist and get the OWNBY array, not relevant for referentials object that is only manage by CRUD no Owner logic + */ + if( objet != "referentials" ) { + if( !fs.existsSync( `${config.tribes}/${req.session.header.xworkon}/${objet}/${req.params.id}.json` ) ) { + res.status( 404 ) + .send( { + payload: { + info: [ 'idNotfound' ], + model, + moreinfo: `${config.tribes}/${req.session.header.xworkon}/${objet}/${req.params.id}.json does not exist ` + } + } ); + } else { + ownby = jsonfile.readFileSync( `${config.tribes}/${req.session.header.xworkon}/${objet}/${req.params.id}.json` ) + .OWNBY; + } + } + //console.log( req.session.header ) + if( req.session.header.xpaganid == config.devnoauthxuuid ) { + console.log( 'haveAccessrighttoanobject yes cause dev test user' ); + } else { + // accessrights was load from isAuthenticated.js middleware to make it available in req.session.header to be used into route for specific access if needed mainly to filter data in the get request depending of profil and data accessright. + if( Object.keys( req.session.header.accessrights.data ) + .includes( "Alltribeid" ) && req.session.header.accessrights.data[ "Alltribeid" ][ objet ] ) { + droit = req.session.header.accessrights.data[ "Alltribeid" ][ objet ]; + } + // erase rights if tribeid is specified in addition of Alltribeid + if( ( req.session.header.accessrights.data[ req.session.header.xworkon ] ) && + req.session.header.accessrights.data[ req.session.header.xworkon ][ objet ] ) { + droit = req.session.header.accessrights.data[ req.session.header.xworkon ][ objet ]; + if( ( req.route.methods.get && droit.includes( 'R' ) ) || + ( req.route.methods.put && droit.includes( 'U' ) ) || + ( req.route.methods.delete && droit.includes( 'D' ) ) || + ownby.includes( req.params.id ) ) { + console.log( 'haveAccessrighttoanobject yes' ) + } else if( req.route.methods.post && droit.includes( 'C' ) ) { + console.log( 'haveAccessrighttoanobject yes create' ); + } else { + console.log( 'haveAccessrighttoanobject no' ) + res.status( 403 ) + .send( { + payload: { + info: [ 'NoAccessrights' ], + model, + moreinfo: `User ${req.session.header.xpaganid} accessrights are not set to do this action` + } + } ); + } + } + } + next(); +}; +module.exports = haveAccessrighttoanobject; diff --git a/middlewares/checkHeaders.js b/middlewares/checkHeaders.js new file mode 100755 index 0000000..ecf34ef --- /dev/null +++ b/middlewares/checkHeaders.js @@ -0,0 +1,88 @@ +const path = require( 'path' ); + +// Check if package is installed or not to pickup the right config file +//const src = ( __dirname.indexOf( '/node_modules/' ) > -1 ) ? '../../..' : '..'; +//const config = require( path.normalize( `${__dirname}/${src}/config.js` ) ); +const config = require( '../config.js' ); +/* +Check que le header contient des éléments necessaire pour les +routes utilisant tribeid / language / token / uuid +*/ +const checkHeaders = ( req, res, next ) => { + //console.log( 'checkHeaders()' ); + // These headers must be passed in the request + // X-Auth and X-Uuid could have any true value + // header is stored in req.app.locals.header to be pass to route + /* const header = { + xtribeid: req.header('x-client-id'), + xlang: req.header('x-language'), + xauth: req.header('x-auth'), + xuuid: req.header('x-uuid'), + xworkon: req.header('x-xorkon', + xapp:req.header('x-app')) + }; + On recupere accessrights via is Authenticated + */ + req.session = {}; + const header = {}; + let missingheader = ""; + //console.log( 'avant validation headers', req.headers ); + //attention changement 7/11/2021 phil des exposedheader cf config.js + //If in httprequest url header are send then they are used inpriority + //Use case : send an email with a unique link that works without password and request to change password + for( const h of config.exposedHeaders ) { + //console.log( h, req.header( h ) ) + if( req.params[ h ] ) { + header[ h ] = req.params[ h ] + } else if( req.header( h ) ) { + header[ h ] = req.header( h ) + } else { + // Missing header + missingheader += " " + h + } + }; + //console.log( 'header', header ) + if( req.params.xauth && req.params.xuuid ) { + // If this exist => it is a timeout limited token + req.app.locals.tokens[ req.params.xpaganid ] = req.params.xauth; + } + req.session.header = header; + // Each header have to be declared + if( missingheader != "" ) { + return res.status( 403 ) + .send( { + info: [ 'forbiddenAccess' ], + model: 'Pagans', + moreinfo: 'checkHeader headerIsMissing:' + missingheader + } ); + }; + //console.log( req.app.locals.tribeids ) + if( !req.app.locals.tribeids.includes( header.xtribe ) ) { + return res.status( 404 ) + .send( { + info: [ 'tribeiddoesnotexist' ], + model: 'Pagans', + moreinfo: `xtribe unknown: ${header.xtribe}` + } ); + } + if( !req.app.locals.tribeids.includes( header.xworkon ) ) { + return res.status( 404 ) + .send( { + info: [ 'tribeiddoesnotexist' ], + model: 'Pagans', + moreinfo: `xworkon unknown: ${header.xworkon}` + } ); + } + if( !config.languagesAvailable.includes( header.xlang ) ) { + return res.status( 404 ) + .send( { + info: [ 'langNotused' ], + model: 'Pagans', + moreinfo: `xlang unknown: ${header.xlang}` + } ); + } + //console.log( 'After middleare checkHeaders.js req.session.header', req.session.header ) + //console.log( 'checkheaders next' ) + next(); +}; +module.exports = checkHeaders; diff --git a/middlewares/hasAccessrighton.js b/middlewares/hasAccessrighton.js new file mode 100755 index 0000000..8b300e0 --- /dev/null +++ b/middlewares/hasAccessrighton.js @@ -0,0 +1,42 @@ +const fs = require( 'fs-extra' ); +const glob = require( 'glob' ); +const path = require( 'path' ); + +const config = require( '../config.js' ); + +const hasAccessrighton = ( object, action, ownby ) => { + /* + @action (mandatory) : CRUDO + @object (mandatory)= name of a folder object in /tribeid space can be a tree for example objects/items + @ownby (option) = list des uuid propriétaire + return next() if all action exist in req.app.local.tokens[UUID].ACCESSRIGHTS.data[object] + OR if last action ="O" and uuid exist in ownBy + Careffull if you have many action CRO let O at the end this will force req.right at true if the owner try an action on this object + */ + return ( req, res, next ) => { + //console.log( 'err.stack hasAccessrights', err.statck ) + //console.log( `test accessright on object:${object} for ${req.session.header.xworkon}:`, req.app.locals.tokens[ req.session.header.xpaganid ].ACCESSRIGHTS.data[ req.session.header.xworkon ] ) + req.right = false; + if( req.app.locals.tokens[ req.session.header.xpaganid ].ACCESSRIGHTS.data[ req.session.header.xworkon ] && req.app.locals.tokens[ req.session.header.xpaganid ].ACCESSRIGHTS.data[ req.session.header.xworkon ][ object ] ) { + req.right = true; + [ ...action ].forEach( a => { + if( a == "O" && ownby && ownby.includes( req.session.header.xpaganid ) ) { + req.right = true; + } else { + req.right = req.right && req.app.locals.tokens[ req.session.header.xpaganid ].ACCESSRIGHTS.data[ req.session.header.xworkon ][ object ].includes( a ) + } + } ) + } + //console.log( 'Access data autorise? ', req.right ) + if( !req.right ) { + return res.status( 403 ) + .send( { + info: [ 'forbiddenAccess' ], + model: 'middleware', + moreinfo: 'no auth to act on this object' + } ) + } + next(); + } +} +module.exports = hasAccessrighton; diff --git a/middlewares/isAuthenticated.js b/middlewares/isAuthenticated.js new file mode 100755 index 0000000..2ecbed0 --- /dev/null +++ b/middlewares/isAuthenticated.js @@ -0,0 +1,113 @@ +const jwt = require( 'jwt-simple' ); +const jsonfile = require( 'jsonfile' ); +const fs = require( 'fs-extra' ); +const moment = require( 'moment' ); +const glob = require( 'glob' ); +//const path = require( 'path' ); +// Check if package is installed or not to pickup the right config file +//const src = '..'; // ( __dirname.indexOf( '/node_modules/' ) > -1 ) ? '../../..' : '..'; +//const config = require( path.normalize( `${__dirname}/${src}/config.js` ) ); +const config = require( '../config.js' ); +const isAuthenticated = ( req, res, next ) => { + /* + check if authenticated with valid token + if not => set req.session.header.xauth=1 + if yes => set for xWorkon + req.session.header.accessrights={ + app:{'tribeid:website':[liste of menu]}, + data:{ "sitewebsrc": "RWCDO", + "contacts": "RWCDO"}} + Liste of menu is linked with the app tht have to be consistent with accessrights.data + data, list of object accessright Read Write Create Delete Owner + a xuuid can read any objet if R + if O wner means that it can only read write its object create by himself + */ + console.log( 'isAuthenticated()?' ); + //console.log( 'req.app.locals.tokens', req.app.locals.tokens ) + //console.log( 'req.session.header', req.session.header ); + // Check if token exist or not + req.session.header.accessrights = { app: "", data: {} } + if( req.session.header.xpaganid == config.devnoauthxuuid && req.session.header.xauth == config.devnoauthxauth ) { + console.log( 'isAuthenticated yes: carrefull using a bypass password give you accessrights={}' ); + } else if( req.session.header.xpaganid == "1" || !req.app.locals.tokens[ req.session.header.xpaganid ] ) { + console.log( `isAuthenticated no : uuid=1 (value=${req.session.header.xpaganid}) or locals.tokens[uuid] empty ` ); + console.log( 'req.app.locals.tokens de xpaganid', req.app.locals.tokens[ req.session.header.xpaganid ] ); + console.log( 'list key uuid de req.app.locals.tokens', Object.keys( req.app.locals.tokens ) ) + req.session.header.xauth = "1" + } else if( req.app.locals.tokens[ req.session.header.xpaganid ].TOKEN !== req.session.header.xauth ) { + // console.log(req.session.header.xuuid); + // console.log(req.session.header.xauth); + // update tokens from file in case recently logged + try { + console.log( 'token not in list of token (req.app.locals.tokens) try to refresh from file' ); + req.app.locals.tokens = jsonfile.readFileSync( `${config.tmp}/tokens.json` ); + } catch ( err ) { + console.log( `check isAuthenticated issue in reading ${config.tmp}/tokens.json` ); + } + if( req.app.locals.tokens[ req.session.header.xpaganid ].TOKEN !== req.session.header.xauth ) { + // if still does not exist then out + console.log( 'isAuthenticated no, token outdated' ); + req.session.header.xauth = "1" + req.session.header.xpaganid = "1" + } + } + if( req.session.header.xauth == "1" ) { + //return res.status( 403 ) + return res.status( 403 ) + .send( { + info: [ 'forbiddenAccess' ], + model: 'Pagans', + moreinfo: 'isAuthenticated faill' + } ) + } else { + console.log( 'isAuthenticated yes' ); + if( req.app.locals.tokens[ req.session.header.xpaganid ] ) { + //console.log( `accessright pour ${req.session.header.xpaganid}`, req.app.locals.tokens[ req.session.header.xpaganid ].ACCESSRIGHTS ); + //set header.accessrights from tokens.json + req.session.header.accessrights = req.app.locals.tokens[ req.session.header.xpaganid ].ACCESSRIGHTS + } else { + // case of bypass no accessright available + req.session.header.accessrights = {} + } + // Once per day, clean old token + const currentday = moment() + .date(); + console.log( 'test si menagedone' + currentday, !fs.existsSync( `${config.tmp}/menagedone${currentday}` ) ) + if( !fs.existsSync( `${config.tmp}/menagedone${currentday}` ) ) { + glob.sync( `${config.tmp}/menagedone*` ) + .forEach( f => { + fs.remove( f, ( err ) => { + if( err ) { + console.log( 'err remove menagedone', err ) + } + } ) + } ); + glob.sync( `${config.tmp}/mdcreator*.log` ) + .forEach( f => { + fs.remove( f, ( err ) => { + if( err ) { + console.log( 'err remove mdcreator log', err ) + } + } ) + } ); + const newtokens = {}; + for( const k of Object.keys( req.app.locals.tokens ) ) { + try { + const decodedToken = jwt.decode( req.app.locals.tokens[ k ].TOKEN, config.jwtSecret ); + //console.log( moment( decodedToken.expiration ), moment() ) + //console.log( moment( decodedToken.expiration ) >= moment() ) + if( moment( decodedToken.expiration ) >= moment() ) { + newtokens[ k ] = req.app.locals.tokens[ k ]; + } + } catch ( err ) { + console.log( "Check isAuthenticated cleaning token ", err ); + } + }; + req.app.locals.tokens = newtokens; + jsonfile.writeFileSync( `${config.tmp}/tokens.json`, newtokens ); + fs.writeFileSync( `${config.tmp}/menagedone${currentday}`, 'fichier semaphore to clean data each day can be deleted with no consequence', 'utf-8' ); + } + next(); + } +}; +module.exports = isAuthenticated; diff --git a/models/Contracts.js b/models/Contracts.js new file mode 100755 index 0000000..5c4d52d --- /dev/null +++ b/models/Contracts.js @@ -0,0 +1,121 @@ +const fs = require( 'fs-extra' ); +const jsonfile = require( 'jsonfile' ); +const glob = require( 'glob' ); +const path = require( 'path' ); +const moment = require( 'moment' ); +const axios = require( 'axios' ); +const scrapeit = require( 'scrape-it' ); +const cheerio = require( 'cheerio' ); +const Mustache = require( 'mustache' ); +const qrcode = require( 'qrcode' ); + +// Check if package is installed or not to pickup the right config file + +const config = require( '../tribes/townconf.js' ); + +/* +Model that will process actions plan for each client like sending email campain, or anything that +are plan in /tribes/tribeid/actions/todo +*/ +const Cards = {}; //require('../../models/Cards'); +const Contracts = {}; +/* +Send if envoicampain a liste of email in param.msg.destperso with param.headers +if not envoicampain, it just return a test about what to send +@param = {headers, msg:{destperso}} +*/ +Contracts.sendcampain = async ( param, envoicampain ) => { + if( envoicampain ) { + // Carefull w the action post outputs/msg just wait the feedback of the 1st message + const retcampain = await axios.post( 'https://mail.maildigit.fr/outputs/msg', param.msg, { + headers: param.headers + } ); + if( retcampain.status !== 200 ) { + console.log( "err", retcampain.payload.moreinfo ); + fs.appendFileSync( `${config.tribes}/log_erreurglobal.txt`, moment( new Date() ) + .format( 'YYYYMMDD HH:mm:ss' ) + ' - IMPOSSIBLE TO SEND CAMPAIN TODO for :' + param.tribeid + ' -- ' + retcampain.payload.moreinfo + '\n', 'utf-8' ); + }; + return retcampain; + } else { + // permet de tester ce qu'il y a à envoyer + let premieremail = ""; + for( let i = 0; i < param.msg.destperso.length; i++ ) { + premieremail += param.msg.destperso[ 0 ].email + ","; + } + return { + status: 201, + payload: { + info: [ 'simplecomptage' ], + model: 'Contracts', + moreinfo: "#email: " + param.msg.destperso.length + " - 5 1st emails: " + premieremail + } + }; + } +} +Contracts.initActiontodo = async ( envoie ) => { + const datedeb = moment( new Date() ) + .format( 'YYYYMMDD HH:mm:ss' ); + let todo, actiondone; + let log = { + nbaction: 0, + nbactionexec: 0, + nbactionerr: 0, + actionlist: "" + }; + const listclient = jsonfile.readFileSync( `${config.tribes}/tribeids.json` ); + for( let clid in listclient ) { + console.log( listclient[ clid ] ); + let listaction = glob.sync( `${config.tribes}/${listclient[clid]}/actions/todo/*.json` ); + for( let action in listaction ) { + console.log( listaction[ action ] ) + log.nbaction++; + todo = jsonfile.readFileSync( listaction[ action ] ); + let passdate = true; + // currentdate doit etre après la startDate si existe et avant valideuntilDate si existe + // console.log('test now est avant date start ', moment() < moment(todo.startDate, 'YYYYMMDD HH:mm:ss').toDate()); + if( todo.startDate && ( moment() < moment( todo.startDate, 'YYYYMMDD HH:mm:ss' ) + .toDate() ) ) { + passdate = false; + }; + // currentdate ne doit pas depasser la date de validité de la tache + // console.log('test now est après la date de validite ', moment() > moment(todo.validuntilDate, 'YYYYMMDD HH:mm:ss').toDate()); + if( todo.valideuntilDate && ( moment() > moment( todo.validuntilDate, 'YYYYMMDD HH:mm:ss' ) + .toDate() ) ) { + passdate = false; + }; + // currentdate + if( passdate && todo.action && todo.error == "" ) { + log.nbactionexec++; + const actiondone = await Contracts[ todo.action ]( todo, envoie ); + todo.datesRun.push( moment( new Date() ) + .format( 'YYYYMMDD HH:mm:ss' ) ); + //console.log("actiondone", actio jsonfile.writeFileSyncndone); + log.actionlist += "STATUS:" + actiondone.status + " -- " + listaction[ action ] + "\n"; + if( actiondone.status == 200 ) { + todo.error = ""; + } else { + log.nbactionerr++; + todo.error += "status : " + actiondone.status + ' ' + actiondone.payload.moreinfo; + }; + if( parseInt( todo.maxnumberoftime ) && todo.maxnumberoftime != "999" && ( todo.datesRun.length >= parseInt( todo.maxnumberoftime ) ) ) { + //archive en done this triggeraction + jsonfile.writeFileSync( listaction[ action ].replace( '/todo/', '/done/' ), todo, { + spaces: 2 + } ); + fs.unlinkSync( listaction[ action ] ); + } else { + jsonfile.writeFileSync( listaction[ action ], todo, { + spaces: 2 + } ); + } + } else { + log.actionlist += "STATUS : not executed " + listaction[ action ] + "\n"; + }; + }; + }; + const trace = "###################### LOGS ####################\nSTART:" + datedeb + " END:" + moment( new Date() ) + .format( 'YYYYMMDD HH:mm:ss' ) + "\n nombre d'actions analysées : " + log.nbaction + " dont executées : " + log.nbactionexec + " dont en erreur: " + log.nbactionerr + "\n" + log.actionlist; + fs.appendFileSync( `${config.tribes}/log.txt`, trace, 'utf-8' ); + return "done"; +} +module.exports = Contracts; diff --git a/models/Messages.js b/models/Messages.js new file mode 100755 index 0000000..7143952 --- /dev/null +++ b/models/Messages.js @@ -0,0 +1,400 @@ +const bcrypt = require( 'bcrypt' ); +const fs = require( 'fs-extra' ); +const path = require( 'path' ); +const jsonfile = require( 'jsonfile' ); +const glob = require( 'glob' ); +const Mustache = require( 'mustache' ); +const jwt = require( 'jwt-simple' ); +const { DateTime } = require( 'luxon' ); +const UUID = require( 'uuid' ); +const Outputs = require( '../models/Outputs.js' ); +const config = require( '../tribes/townconf.js' ); +const checkdata = require( `${config.tribes}/${config.mayorId}/www/cdn/public/js/checkdata` ); +/* +Message manager +* Manage apixtribe message at different level +* this means that an object (most often a user or a contact) want to send a question to an other user. + + +To know more http://gitlab.ndda.fr/philc/apixtribe/-/wikis/HOWTONotification + +*/ +const Messages = {}; +Messages.init = () => { + console.group( 'init Message' ); + Messages.aggregate(); +} + +Messages.byEmailwithmailjet = ( tribeid, msg ) => { + /* @tribeid requester + @msg =[{ + To:[{Email,Name}], + Cc:[{Email,Name}], + Bcc:[{Email,Name}]}], + Subject:"Subject", + TextPart:"texte content", + HTMLPart:"html content" + }] + If tribeid has a mailjet account it use it if not then it use the apixtribe @mailjetconf = {apikeypub:, apikeypriv:, From:{Email:,Name:}} + This send a bunch of messages check the mailjet account used + FYI: Basic account is 200 email /days 6000 /month + Log is stored into + tribeidsender/messages/logs/sent/timestamp.json + @todo GUI to manage statistics and notification alert limit sender email + */ + console.log( 'Envoie mailjet' ) + const confclient = fs.readJsonSync( `${config.tribes}/${tribeid}/clientconf.json` ); + let tribeidsender = tribeid; + if( confclient.smtp && confclient.smtp.mailjet ) { + mailjetconf = confclient.smtp.mailjet; + } else { + const confapixtribe = fs.readJsonSync( `${config.tribes}/${config.mayorId}/clientconf.json` ); + if( !( confapixtribe.smtp && confapixtribe.smtp.mailjet ) ) { + return { status: 403, data: { models: "Messages", info: [ "nosmtpmailjet" ], moreinfo: "missing smtpmailjet parameter in apixtribe contact your admin to activate an mailjet account on this server." } } + } + tribeidsender = "apixtribe"; + mailjetconf = confapixtribe.smtp.mailjet; + } + //add from from setings account + const MSG = msg.map( m => { m.From = mailjetconf.From; return m; } ); + const mailjet = require( 'node-mailjet' ) + .connect( mailjetconf.apikeypub, mailjetconf.apikeypriv ); + const request = mailjet.post( 'send', { version: 'v3.1' } ) + .request( { "Messages": MSG } ); + request + .then( result => { + //store into tribeidsender/messages/logs/sent/timestamp.json + const t = Date.now(); + MSG.result = result.body; + fs.outputJson( `${config.tribes}/${tribeidsender}/messages/logs/sent/${t}.json`, MSG ) + console.log( result.body ) + } ) + .catch( err => { + const t = Date.now(); + MSG.result = err; + fs.outputJson( `${config.tribes}/${tribeidsender}/messages/logs/error/${t}.json`, MSG ) + console.log( err.statusCode, err ) + } ) + +}; +Messages.buildemail = ( tribeid, tplmessage, data ) => { + /* @tribeid => client concerned by sending email get info from clientconf.json (customization, useradmin:{ EMAIL,LOGIN} , ...) + @tplmessage => folder where template is available (ex: apixtribe/referentials/dataManagement/template/order) + @data { destemail = email to + if destuuid => then it get user EMAIL if exiat + subject = mail subject + // any relevant information for template message + msgcontenthtml = html msg content + msgcontenttxt = text msg content + ....} + @return msg + mail part ready to send by mailjet or other smtp + */ + if( !fs.existsSync( `${config.tribes}/${tribeid}/clientconf.json` ) ) { + return { status: 404, data: { model: "Messages", info: [ "tribeiddoesnotexist" ], moreinfo: `${tribeid} does not exist` } } + } + if( !fs.existsSync( `${config.tribes}/${tplmessage}` ) ) { + return { status: 404, data: { model: "Messages", info: [ "tplmessagedoesnotexist" ], moreinfo: `tpl does not exist ${tplmessage}` } } + } + const clientconf = fs.readJsonSync( `${config.tribes}/${tribeid}/clientconf.json` ) + //add clientconf.customization into data for template + data.customization = clientconf.customization; + //manage receiver + const msg = { To: [ { Email: clientconf.useradmin.EMAIL, Name: clientconf.useradmin.LOGIN } ] }; + if( data.destemail ) { + msg.To.push( { Email: data.destemail } ) + } + if( data.destuuid && fs.exist( `${config.tribes}/${tribeid}/users/${data.destuuid}.json` ) ) { + const uuidconf = fs.readJsonSync( `${config.tribes}/${tribeid}/users/${data.destuuid}.json` ); + if( uuidconf.EMAIL && uuidconf.EMAIL.length > 4 ) { + msg.To.push( { Email: uuidconf.EMAIL, Name: uuidconf.LOGIN } ) + } + } + //console.log( data ) + // email content + msg.Subject = `Message from ${tribeid}`; + if( data.subject ) msg.Subject = data.subject; + msg.TextPart = Mustache.render( fs.readFileSync( `${config.tribes}/${data.tplmessage}/contenttxt.mustache`, 'utf-8' ), data ); + msg.HTMLPart = Mustache.render( fs.readFileSync( `${config.tribes}/${data.tplmessage}/contenthtml.mustache`, 'utf-8' ), data ); + return { + status: 200, + data: { model: "Messages", info: [ "msgcustomsuccessfull" ], msg: msg } + } +}; +Messages.postinfo = ( data ) => { + /* + Data must have: + at least one of desttribeid:,destuuid:,destemail: + if an email have to be sent tplmessage:"tribeid/referentials/dataManagement/template/tplname", + at least one of contactemail:,contactphone,contactlogin,contactuuid + any other usefull keys + + Data is stored into contacts object .json + */ + let contact = ""; + [ 'contactemail', 'contactphone', 'contactuuid', 'contactlogin' ].forEach( c => { + if( data[ c ] ) contact += c + "##" + data[ c ] + "###"; + } ) + console.log( contact ) + if( contact == "" ) { + return { status: 404, data: { model: "Messages", info: [ "contactundefine" ], moreinfo: "no contact field found in this form" } } + } + if( !data.desttribeid ) { + return { status: 404, data: { model: "Messages", info: [ "tribeidundefine" ], moreinfo: "no desttribeid field found in this form" } } + } + // save new message in contacts + let messages = {}; + if( fs.existsSync( `${config.tribes}/${data.desttribeid}/contacts/${contact}.json` ) ) { + messages = fs.readJsonSync( `${config.tribes}/${data.desttribeid}/contacts/${contact}.json`, 'utf-8' ); + } + messages[ Date.now() ] = data; + fs.outputJsonSync( `${config.tribes}/${data.desttribeid}/contacts/${contact}.json`, messages ); + + // if templatemessage exist then we send alert email + // data content have to be consistent with tplmessage to generate a clean email + if( data.tplmessage && data.tplmessage != "" && + fs.existsSync( `${config.tribes}/${data.tplmessage}` ) ) { + if( !( data.msgtplhtml && data.msgtpltxt ) ) { + data.msgcontenthtml = `

${data.contactname} - ${contact.replace(/###/g,' ').replace(/##/g,":")}

Message: ${data.contactmessage}

` + data.msgcontenttxt = `${data.contactname} - ${contact}/nMessage:${data.contactmessage}\n`; + } else { + data.msgcontenthtml = Mustache.render( data.msgtplhtml, data ) + data.msgcontenttxt = Mustache.render( data.msgtpltxt, data ) + } + const msg = Messages.buildemail( data.desttribeid, data.tplmessage, data ) + if( msg.status == 200 ) { + Messages.byEmailwithmailjet( data.desttribeid, [ msg.data.msg ] ); + } + // we get error message eventualy but email feedback sent is not in real time + return msg; + } else { + return { status: 404, data: { info: "missingtpl", model: "Messages", moreinfo: `missing template ${data.tplmessage}` } } + } +} +Messages.aggregate = () => { + // collect each json file and add them to a global.json notifat require level + const dest = {}; + try { + glob.sync( `${ config.tribes }/**/notif_*.json` ) + .forEach( f => { + //console.log( 'find ', f ) + const repglob = `${path.dirname(f)}/global.json`; + if( !dest[ repglob ] ) { dest[ repglob ] = [] } + dest[ repglob ].push( fs.readJsonSync( f, 'utf-8' ) ); + fs.removeSync( f ); + } ) + //console.log( dest ) + Object.keys( dest ) + .forEach( g => { + let notif = []; + if( fs.existsSync( g ) ) { notif = fs.readJsonSync( g ) }; + fs.writeJsonSync( g, notif.concat( dest[ g ] ), 'utf-8' ); + } ) + } catch ( err ) { + Console.log( "ATTENTION, des Messages risquent de disparaitre et ne sont pas traitées." ); + } +} +Messages.object = ( data, header ) => { + /* + Create or replace an object no check at all here this is only + a way to add / replace object + if deeper thing have to be checheck or done then a callback:{tribeidplugin,pluginname,functionname} + data.descttribeid tribeid to send at least to admin + data.tplmessage = folder of emailtemplate + */ + console.log( 'data', data ) + console.log( `${config.tribes}/${header.xworkon}/${data.object}` ) + if( !fs.existsSync( `${config.tribes}/${header.xworkon}/${data.object}` ) ) { + return { + status: 404, + data: { + model: "Messages", + info: [ 'UnknownObjectfortribeid' ], + moreinfo: `This object ${data.object} does not exist for this tribeid ${header.xworkon}` + } + }; + } + if( data.uuid == 0 ) { + data.uuid = UUID.v4(); + } + if( data.callback ) { + // check from plugin data and add relevant data + const Plug = require( `${config.tribes}/${data.callback.tribeid}/plugins/${data.callback.plugins}/Model.js` ); + const check = Plug[ data.callback.function ]( header.xworkon, data ); + if( check.status == 200 ) { + data = check.data.data; + } else { + return check; + } + }; + fs.outputJsonSync( `${config.tribes}/${header.xworkon}/${data.object}/${data.uuid}.json`, data ); + // if templatemessage exist then we try to send alert email + if( data.tplmessage && data.tplmessage != "" && + fs.existsSync( `${config.tribes}/${data.tplmessage}` ) ) { + const msg = Messages.buildemail( data.desttribeid, data.tplmessage, data ) + if( msg.status == 200 ) { + console.log( 'WARN EMAIL DESACTIVATED CHANGE TO ACTIVATE in Messages.js' ) + //Messages.byEmailwithmailjet( data.desttribeid, [ msg.data.msg ] ); + } + // we get error message eventualy but email feedback sent is not in real time see notification alert in case of email not sent. + }; + //Sendback data with new information + return { + status: 200, + data: { + model: "Messages", + info: [ 'Successregisterobject' ], + msg: data + } + }; +} +Messages.notification = ( data, header ) => { + //check if valid notification + if( !req.body.elapseddays ) { req.body.elapseddays = 3 } + let missingkey = ""; + [ 'uuid', 'title', 'desc', 'icon', 'elapseddays', 'classicon' ].forEach( k => { + if( !data[ k ] ) missingkey += ` ${k},` + if( k == "classicon" && !( [ 'text-danger', 'text-primary', 'text-success', 'text-warning', 'text-info' ].includes( data[ k ] ) ) ) { + missingkey += ` classicon is not well set ${data[k]}`; + } + } ) + if( missingkey != '' ) { + return { + status: 422, + data: { + model: "Messages", + info: [ 'InvalidNote' ], + moreinfo: `invalid notification sent cause missing key ${missingkey}` + } + }; + } + if( !fs.existsSync( `${config.tribes}/${header.xworkon}/${data.object}` ) ) { + return { + status: 404, + data: { + model: "Messages", + info: [ 'UnknownObjectfortribeid' ], + moreinfo: `This object ${data.object} does not exist for this tribeid ${data.tribeid}` + } + }; + } + //by default store in tmp/notification this is only for sysadmin + // user adminapixtribe + let notdest = `${config.tmp}`; + + if( data.app ) { + const destapp = `${config.tribes}/${data.app.split(':')[0]}/spacedev/${data.app.split(':')[1]}`; + if( fs.existsSync( destapp ) ) { + notdest = destapp; + } + } + if( data.plugins ) { + const destplugin = `${config.tribes}/${data.plugins.split(':')[0]}/plugins/${data.plugins.split(':')[1]}`; + if( fs.existsSync( destplugin ) ) { + notdest = destplugin; + } + } + if( data.object ) { + const destobject = `${config.tribes}/${data.tribeid}/${data.object}/`; + if( fs.existsSync( destobject ) ) { + notdest = destobject; + } + } + if( !data.time ) { + data.time = Date.now(); + } + fs.outputJsonSync( `${notdest}/Messages/notif_${data.time}.json`, data ); + + return { + status: 200, + data: { + model: "Messages", + info: [ 'Successregisternotification' ], + notif: data + } + }; +} + +Messages.request = ( tribeid, uuid, ACCESSRIGHTS, apprequest ) => { + // list notif for each app + // list notif for each tribeid / objects if Owned + // list notif for + // check uuid notification + // Collect all notification and agregate them at relevant level; + Messages.aggregate(); + + //for test purpose + //const notif = jsonfile.readFileSync( `${config.tribes}/ndda/spacedev/mesa/src/static/components/notification/data_notiflist_fr.json` ); + let notif; + if( !fs.existsSync( `${config.tribes}/${apprequest.tribeid}/spacedev/${apprequest.website}/src/static/components/notification/data_notiflist_${apprequest.lang}.json` ) ) { + // by default we send back this but this highlght an issue + notif = { + "iconnotif": "bell", + "number": 1, + "notifheader": "Your last Messages", + "notiffooter": "Check all Messages", + "actionnotifmanager": "", + "href": "?action=notification.view", + "notifs": [ { + "urldetail": "#", + "classicon": "text-danger", + "icon": "alert", + "title": `File does not exist`, + "desc": ` ${config.tribes}/${apprequest.tribeid}/spacedev/${apprequest.website}/src/static/components/notification/data_notiflist_${apprequest.lang}.json`, + "elapse": "il y a 13mn" + } ] + }; + } else { + notif = jsonfile.readFileSync( `${config.tribes}/${apprequest.tribeid}/spacedev/${apprequest.website}/src/static/components/notification/data_notiflist_${apprequest.lang}.json` ); + //clean up example notif + notif.notifs = []; + } + //check notification for plugins of tribeid of the login + glob.sync( `${config.tribes}/${tribeid}/plugins/*/Messages/global.json` ) + Object.keys( ACCESSRIGHTS.app ) + .forEach( a => { + // check for each app if notification about app + const appnot = `${config.tribes}/${a.split(':')[0]}/spacedev/${a.split(':')[1]}/Messages/global.json`; + if( fs.existsSync( appnot ) ) { + notif.notifs = notif.notifs.concat( fs.readJsonSync( appnot ) ); + } + } ); + Object.keys( ACCESSRIGHTS.plugin ) + .forEach( p => { + // each plugin + if( ACCESSRIGHTS.plugin[ p ].profil == "owner" ) { + const pluginnot = `${config.tribes}/${p.split(':')[0]}/plugins/${p.split(':')[1]}/Messages/global.json`; + if( fs.existsSync( pluginnot ) ) { + notif.notifs = notif.notifs.concat( fs.readJsonSync( pluginnot ) ); + } + } + } ); + Object.keys( ACCESSRIGHTS.data ) + .forEach( c => { + // each tribeid + Object.keys( ACCESSRIGHTS.data[ c ] ) + .forEach( o => { + const cliobjnot = `${config.tribes}/${c}/${o}/Messages/global.json` + //check for each tribeid / Object per accessright user + if( fs.existsSync( cliobjnot ) ) { + console.log( `droit sur client ${c} objet ${o} : ${ACCESSRIGHTS.data[ c ][ o ]}` ); + //check if intersection between user accessrigth for this object and the notification accessright is not empty @Todo replace true by intersec + console.log( 'WARN no actif filter all notif are shared with any authenticated user' ) + const newnotif = fs.readJsonSync( cliobjnot ) + .filter( n => { return true } ); + notif.notifs = notif.notifs.concat( newnotif ); + } + } ) + } ) + return { + status: 200, + data: { + model: "Messages", + info: [ 'successgetnotification' ], + notif: notif + } + }; +} + + +module.exports = Messages; diff --git a/models/Nationchains.js b/models/Nationchains.js new file mode 100755 index 0000000..ce1dc8b --- /dev/null +++ b/models/Nationchains.js @@ -0,0 +1,105 @@ +const bcrypt = require( 'bcrypt' ); +const fs = require( 'fs-extra' ); +const path = require( 'path' ); +const jsonfile = require( 'jsonfile' ); +const glob = require( 'glob' ); +const jwt = require( 'jwt-simple' ); +const moment = require( 'moment' ); +const axios = require( 'axios' ); +const UUID = require( 'uuid' ); +const Outputs = require( './Outputs.js' ); +const config = require( '../tribes/townconf.js' ); +const checkdata = require( `${config.tribes}/${config.mayorId}/www/cdn/public/js/checkdata` ); +/* +Blockchain manager +* Manage network directory +* read Blockchain and search, +* submit a transaction (now) or contract (futur) to store from userA.pubkey to userB.pubkey a number of AXESS +* mine to be able to register a block and create AXESS +* manage APIXP rules 20 M APIXP 1AXESS = 1 block validation +* manage contract = action if something appened validate by a proof of work +*/ +const Nationchains = {}; +Nationchains.init = () => { + console.group( 'init Nationchains' ); +} +Nationchains.synchronize = () => { + /* + Run process to communicate with a list of apixtribe instance to update transaction and earn AXP + To creation of a new tribeid or a new login + */ + //update himself then send to other information + if( process.env.NODE_ENV != "prod" ) { + // Not concerned + return {} + } + const initcurrentinstance = { + "fixedIP": "", + "lastblocknumber": 0, + "firsttimeupdate": 0, + "lastimeupdate": 0, + "positifupdate": 0, + "negatifupdate": 0, + "pubkeyadmin": "", + "tribeids": [], + "logins": [], + "knowninstance": [] + }; + let currentinstance = initcurrentinstance; + try { + currentinstance = fs.readFileSync( `${config.tribes}/${config.mayorId}/nationchains/nodes/${config.rootURL}`, 'utf-8' ) + } catch ( err ) { + console.log( 'first init' ) + } + const loginsglob = fs.readJsonSync( `${config.tmp}/loginsglob.json`, 'utf-8' ); + currentinstance.logins = Object.keys( loginsglob ); + currentinstance.tribeids = [ ...new Set( Object.values( loginsglob ) ) ]; + currentinstance.instanceknown = glob.Sync( `${config.tribes}/${config.mayorId}/nationchains/nodes/*` ); + //Save it + fs.outputJsonSync( `${config.tribes}/${config.mayorId}/nationchains/nodes/${config.rootURL}`, currentinstance ); + // proof of work + // try to find a key based on last block with difficulty + // if find then send to all for update and try to get token + // in any case rerun Nationchains.synchronize() + currentinstance.instanceknown.forEach( u => { + if( u != config.rootURL ) { + //send currentinstance info and get back state of + axios.post( `https://${u}/nationchains/push`, currentinstance ) + .then( rep => { + newdata = rep.payload.moreinfo + //Available update info + fs.readJson( `${config.tribes}/${config.mayorId}/nationchains/nodes/${u}`, ( err, data ) => { + if( err ) { + data.negatifupdate += 1; + data.lasttimeupdate = Date.now(); + } else { + data.positifupdate += 1; + data.lastimeupdate = Date.now(); + data.tribeids = newdata.tribeids; + data.logins = newdata.logins; + data.lastblocknumber = newdata.lastblocknumber; + newdata.knowninstance.forEach( k => { + if( !data.knowninstance.includes( k ) ) { + data.knowninstance.push( k ); + //init the domain for next update + initcurrentinstance.firsttimeupdate = Date.now(); + fs.outputJson( `${config.tribes}/${config.mayorId}/nationchains/nodes/${k}`, initcurrentinstance, 'utf-8' ) + } + } ) + } + //save with info + fs.outputJson( `${config.tribes}/${config.mayorId}/nationchains/nodes/${u}`, data ); + } ) + } ) + .catch( err => { + //Not available + data.negatifupdate += 1; + data.lasttimeupdate = Date.now(); + fs.outputJson( `${config.tribes}/${config.mayorId}/nationchains/nodes/${u}`, data ); + } ); + } + } ); +}; + + +module.exports = Nationchains; diff --git a/models/Odmdb.js b/models/Odmdb.js new file mode 100644 index 0000000..2452ef2 --- /dev/null +++ b/models/Odmdb.js @@ -0,0 +1,17 @@ +const glob = require( 'glob' ); +const path = require( 'path' ); +const fs = require( 'fs-extra' ); +const config = require( '../tribes/townconf.js' ); + +const Odmdb = {}; + +/* +Input: metaobject => data mapper of Key: Value + + objname + an object {} + action check => get a valid or not answer + objname + an object {} + action search => apply matching algo to find probalistic object id + objname + action index => update /searcindex of objects concern + +*/ + +module.exports = Odmdb; \ No newline at end of file diff --git a/models/Outputs.js b/models/Outputs.js new file mode 100755 index 0000000..8067193 --- /dev/null +++ b/models/Outputs.js @@ -0,0 +1,557 @@ +const fs = require( 'fs-extra' ); +const path = require( 'path' ); +const formidable = require( 'formidable' ); +const jsonfile = require( 'jsonfile' ); +const mustache = require( 'mustache' ); +const moment = require( 'moment' ); +const UUID = require( 'uuid' ); +const pdf = require( "pdf-creator-node" ); +const nodemailer = require( 'nodemailer' ); +const smtpTransport = require( 'nodemailer-smtp-transport' ); +const axios = require( 'axios' ); +const { GoogleSpreadsheet } = require( 'google-spreadsheet' ); +const config = require( '../tribes/townconf.js' ); +const checkdata = require( `${config.tribes}/${config.mayorId}/www/cdn/public/js/checkdata` ); + +const Outputs = {}; + +Outputs.ggsheet2json = async ( req, header ) => { + /* + req.ggsource = key name of the ggsheet into clientconf + req.sheets = [list of sheet names to import] + into /ggsheets/ ggsource.json = {resultfolder,productIdSpreadsheet, + googleDriveCredentials} + */ + if( !fs.existsSync( `${config.tribes}/${header.xworkon}/${req.ggsource}` ) ) { + // Misconfiguration + return { + status: 404, + payload: { + data: {}, + info: [ 'Misconfiguration' ], + moreinfo: `${header.xworkon}/${req.ggsource} missing file check gitlabdocumentation`, + model: 'Outputs' + } + }; + } + const confgg = fs.readJsonSync( `${config.tribes}/${header.xworkon}/${req.ggsource}`, 'utf-8' ) + //const ggconnect = clientconf.ggsheet[ req.ggsource ] + //googleDriveCredentials; + //console.log( ggconnect ) + doc = new GoogleSpreadsheet( confgg.productIdSpreadsheet ); + await doc.useServiceAccountAuth( confgg.googleDriveCredentials ); + await doc.loadInfo(); + let result = []; + let invalidfor = ""; + //console.log( "sheets", req.sheets ); + for( const sheetName of req.sheets ) { + console.log( 'loading: ', sheetName ); + if( !doc.sheetsByTitle[ sheetName ] ) { + invalidfor += " " + sheetName; + } else { + sheet = doc.sheetsByTitle[ sheetName ] + await sheet.loadHeaderRow(); + const records = await sheet.getRows( { offset: 1 } ) + records.forEach( record => { + let offer = {} + for( let index = 0; index < record._sheet.headerValues.length; index++ ) { + offer[ record._sheet.headerValues[ index ] ] = record[ record._sheet.headerValues[ index ] ]; + } + result.push( offer ); + } ); + } + } + const idfile = UUID.v4(); + fs.outputJsonSync( `${config.tribes}/${header.xworkon}/${confgg.resultfolder}/${idfile}.json`, result, 'utf8' ); + if( invalidfor == "" ) { + return { + status: 200, + payload: { + data: `${confgg.resultfolder}/${idfile}.json`, + info: [ 'Successfull' ], + model: 'Outputs' + } + } + } else { + return { + status: 207, + payload: { + data: `${confgg.resultfolder}/${idfile}.json`, + info: [ 'PartialySuccessfull' ], + moreinfo: `Following sheetNames does not exist :${invalidfor}`, + model: 'Outputs' + } + } + }; +}; + + + + +// REVOIR TOUT CE QU'IL Y A EN DESSOUS et ré-écrire avec la logique de ggsheet2json phil 25/10/2021 +/////////////////////////////////////////////////// +const sleep = ( milliseconds = 500 ) => new Promise( resolve => setTimeout( resolve, milliseconds ) ); +/* +Process any data to a specific output: +emailer => generate a finale text file to send +csv => export json file to csv data +pdf => generate a customized document +*/ +Outputs.envoiemail = async ( msg, nowait, nbfois ) => { + // console.log('{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}'); + // console.log('msg to send', msg); + console.log( 'nbfois', nbfois ); + let transporter = nodemailer.createTransport( msg.smtp ); + if( !nowait ) { + console.log( 'attente 1er msg avant d envoyer les autres' ); + const transport = await transporter.verify(); + console.log( 'transport', transport ); + if( transport.error ) { + console.log( 'Probleme de smtp', error ); + return { + status: 500, + payload: { + info: '' + } + }; + } else { + let rep = await transporter.sendMail( msg ); + console.log( 'rep sendMail', rep ); + if( rep.accepted && rep.accepted.length > 0 && rep.rejected.length == 0 ) { + fs.appendFileSync( `${config.tribes}/${msg.headers['x-client-nd-id']}/logs/${msg.headers['x-campaign-id']}_success.txt`, moment( new Date() ) + .format( 'YYYYMMDD HH:mm:ss' ) + ' - Success after waiting 1st email to send ' + msg.to + '\n', 'utf-8' ); + return { + status: '200', + payload: { + info: [ 'send1stemailok' ], + model: 'Outputs' + } + }; + } + // status à tester si necessaire de detecter une erreur + // if (rep.rejectedErrors) { + fs.appendFileSync( `${config.tribes}/${msg.headers['x-client-nd-id']}/logs/${msg.headers['x-campaign-id']}_error.txt`, moment( new Date() ) + .format( 'YYYYMMDD HH:mm:ss' ) + ' - err after waiting result\n ' + msg.to, 'utf-8' ); + return { + status: '500', + payload: { + info: [ 'rejectedError' ], + model: 'Outputs' + } + }; + } + } else { + transporter.sendMail( msg, async ( err, info ) => { + if( err ) { + if( nbfois < 4 ) { + console.log( 'nouvelle tentative ', nbfois ); + await sleep( 600000 ); // attends 60sec pour faire une niéme tentative + Outputs.envoiemail( msg, true, nbfois + 1 ); + } else { + // logerror in file + console.log( 'err', err ) + fs.appendFileSync( `${config.tribes}/${msg.headers['x-client-nd-id']}/logs/${msg.headers['x-campaign-id']}_error.txt`, moment( new Date() ) + .format( 'YYYYMMDD HH:mm:ss' ) + ' - err after 4 tries to ' + info.rejected.join( ',' ) + '\n', 'utf-8' ); + // console.log('msg.to not well sent', msg.to); + } + } else { + console.log( 'info', info ) + // console.log('msg.to well sent', msg.to); + fs.appendFileSync( `${config.tribes}/${msg.headers['x-client-nd-id']}/logs/${msg.headers['x-campaign-id']}_success.txt`, moment( new Date() ) + .format( 'YYYYMMDD HH:mm:ss' ) + ' - Success after ' + nbfois + ' tries to ' + info.accepted.join( ',' ) + '\n', 'utf-8' ); + } + } ); + } + // return something to not wait the rest of email + return { + status: '200', + payload: { + info: [ 'send1stemailok' ], + model: 'Outputs' + } + }; +}; +Outputs.generemsg = async ( msg, header ) => { + /* + wait msg sent and return result sent + */ + // Recupere les parametre smtp du domainName à utiliser + console.log( 'pass Outputs.generemsg' ) + try { + const confclientexpediteur = jsonfile.readFileSync( `${config.tribes}/${msg.tribeidperso.tribeidexpediteur}/clientconf.json` ); + //console.log('expediteur', confclientexpediteur); + msg.smtp = confclientexpediteur.smtp; + /* const confclient = jsonfile.readFileSync( + `${config.tribes}/${msg.tribeidperso.tribeid}/clientconf.json` + );*/ + } catch ( err ) { + console.log( 'la conf smtp du client n\'est pas definie' ); + return { + status: 404, + payload: { + info: [ 'smtpnotdefined' ], + model: 'Outputs' + } + }; + } + console.log( msg ); + if( !msg.template.sendascontent && msg.template.htmlfile ) { + try { + msg.template.html = fs.readFileSync( config.sharedData + '/' + msg.template.htmlfile + '/contentinline.mustache', 'utf-8' ); + msg.template.text = fs.readFileSync( config.sharedData + '/' + msg.template.htmlfile + '/contenttxt.mustache', 'utf-8' ); + } catch ( err ) { + console.log( 'WARNING, html file template missing ' + config.sharedData + '/' + msg.template.htmlfile ); + console.log( err ); + return { + status: 404, + payload: { + info: [ 'fileUnknown' ], + model: 'UploadFiles', + moreinfo: 'Template unavailable, check ' + config.sharedData + '/' + msg.template.htmlfile + '/contentinline.mustache and contenttxt.mustache' + } + }; + } + } + if( msg.template.html.length == 0 ) { + console.log( 'template.html est vide' ) + return { + status: 404, + payload: { + info: [ 'ERRnotemplate' ], + model: 'Outputs', + moreinfo: 'No template email check ' + } + }; + } + // mustache any data into + // console.log(msg); + const msg2send = {}; + msg2send.smtp = msg.smtp; + msg2send.from = msg.tribeidperso.from; + if( msg.tribeidperso.cc ) msg2send.cc = msg.tribeidperso.cc; + if( msg.tribeidperso.bcc ) msg2send.bcc = msg.tribeidperso.bcc; + if( msg.tribeidperso.replyTo ) msg2send.replyTo = msg.tribeidperso.replyTo; + msg2send.headers = { + 'x-campaign-id': msg.tribeidperso.messageId, + 'x-client-nd-id': msg.tribeidperso.tribeid, + 'x-template-nd-id': msg.tribeidperso.templateId + }; + // we get in datacust= {tribeidperso: with clientconf,destperso: personnalise data to send for email} + // console.log(msg); + console.log( 'nb de message to send:', msg.destperso.length ); + //console.log(msg.destperso); + //msg.destperso.forEach(async (perso, pos) => { + let pos; + let pass1ermsg = false; + for( pos = 0; pos < msg.destperso.length; pos++ ) { + const datacust = { + tribeidperso: msg.tribeidperso, + destperso: msg.destperso[ pos ] + }; + // Evaluation of each field if mustache exist + const datacusteval = {}; + Object.keys( datacust.tribeidperso ) + .forEach( k => { + if( typeof datacust.tribeidperso[ k ] === 'string' || datacust.tribeidperso[ k ] instanceof String ) { + datacusteval[ k ] = mustache.render( datacust.tribeidperso[ k ], datacust ) + } else { + datacusteval[ k ] = datacust.tribeidperso[ k ]; + } + } ) + Object.keys( datacust.destperso ) + .forEach( k => { + if( typeof datacust.destperso[ k ] === 'string' || datacust.destperso[ k ] instanceof String ) { + datacusteval[ k ] = mustache.render( datacust.destperso[ k ], datacust ) + } else { + datacusteval[ k ] = datacust.destperso[ k ]; + } + } ) + msg2send.to = msg.destperso[ pos ].email; + console.log( 'msg2send.to ' + msg2send.to + ' pos:' + pos ); + // console.log('avec datacusteval ', datacusteval) + msg2send.subject = mustache.render( msg.template.subject, datacusteval ); + msg2send.text = mustache.render( msg.template.text, datacusteval ); + msg2send.html = mustache.render( msg.template.html, datacusteval ); + let nowait = true; + if( config.emailerurl == 'http://devapia.maildigit.fr:3015' ) { + fs.writeFileSync( 'devdata/tmp/test.html', msg2send.html, 'utf-8' ); + console.log( 'lancement email sur dev, pour controler le mail générer voir ds ./config.js il faut changer config.emailerurl avec https://mail.maildigit.fr pour envoyer le mail ' ) + return { + status: 200, + payload: { + info: [ 'msgsentok' ], + model: 'Outputs', + moreinfo: "parametrer sur emailer de dev et pas de production" + } + } + } + if( pos == 0 ) { + nowait = false; + /* we are waiting the first email was sent ok then we send all other + check NEEDDATA/OVH/workspace/emailerovh to send emailer with nodemailer and nodemailer-smtp-transport + */ + // console.log('envoie msg', msg); + //console.log(msg2send); + const ret = await Outputs.envoiemail( msg2send, nowait, 0 ); + console.log( 'ret 1er msg', ret ); + if( ret.status == 200 ) { + pass1ermsg = true; + }; + } else if( pass1ermsg ) { + console.log( '###############################################' ) + console.log( "envoie msg numero: " + pos + " email: " + msg2send.to ) + //console.log(msg2send) + Outputs.envoiemail( msg2send, nowait, 0 ); + /*Outputs.envoiemail(msg2send, nowait, 0).then(rep => { + console.log("envoie email" + pos) + }).catch(err => { + console.log(err); + });*/ + }; + }; + if( pass1ermsg ) { + return { + status: 200, + payload: { + info: [ 'msgsentok' ], + model: 'Outputs' + } + }; + } else { + return { + status: 500, + payload: { + info: [ 'msgsentko' ], + model: 'Ouputs', + moreinfo: "1er msg non envoyé car erreur" + } + } + } +}; +Outputs.sendMailcampain = async ( msg, headersmsg ) => { + /* + Permet de lancer une campagne de mail personnalisé en mode web service + avec axios config.emailerurl https://mail qui peut être sur un autre serveur que celui en cours + Attention headermsg doit être retraduit avec les champs envoyé par un navigateur + Si le serveur en cours appelle cette fonction les champs du header doivent changer + voir config.js node_env .exposedHeaders + + Pour un exemple de msg voir u exemple type de message envoyé dans un tribeid/domain/clientconf.json + avec l'envoi d'email + */ + //console.log(msg) + // On ajoute le contenu du template directement dans la demande + if( msg.template.sendascontent && msg.template.htmlfile ) { + try { + console.log( 'test', msg.template.sendascontent ) + msg.template.html = fs.readFileSync( config.sharedData + '/' + msg.template.htmlfile + '/contentinline.mustache', 'utf-8' ); + msg.template.text = fs.readFileSync( config.sharedData + '/' + msg.template.htmlfile + '/contenttxt.mustache', 'utf-8' ); + } catch ( err ) { + console.log( 'WARNING, html file template missing ' + config.sharedData + '/' + msg.template.htmlfile ); + //console.log(err); + return { + status: 404, + payload: { + info: [ 'fileUnknown' ], + model: 'UploadFiles', + moreinfo: 'Template unavailable, check ' + config.sharedData + '/' + msg.template.htmlfile + '/contentinline.mustache and contenttxt.mustache' + } + }; + } + delete msg.template.htmlfile; + if( msg.template.html.length == 0 ) { + return { + status: 404, + payload: { + info: [ 'ERRnotemplate' ], + model: 'Outputs', + moreinfo: 'No template email check ' + } + }; + } + } + console.log( 'envoie sur', `${config.emailerurl}/outputs/msg` ) + //console.log(msg) + // on check si les key de headermsg sont des key traduite via exposedHeaders + // (cas ou c'est l'application qui envoie un email) + if( headersmsg.xtribeid ) { + Object.keys( config.exposedHeaders ) + .forEach( h => { + headersmsg[ h ] = headersmsg[ config.exposedHeaders[ h ] ]; + delete headersmsg[ config.exposedHeaders[ h ] ]; + } ); + } + // on ajoute le code pour la signature + headersmsg.hashbody = msg.code; + console.log( 'header after traduction: ', headersmsg ) + try { + const resCamp = await axios.post( `${config.emailerurl}/outputs/msg`, msg, { + headers: headersmsg + } ); + //console.log('Etat:', resCamp); + console.log( 'Tried to send 1st email of the campain ' + msg.destperso[ 0 ].email ); + // it just check the 1st email in destperso to return an answer if 1st is ok then all other are send in queue + if( resCamp ) { + return resCamp; + } else { + return { status: 200, payload: { info: [ 'CampainSent' ], model: 'Outputs' } }; + } + } catch ( err ) { + // aios error handler + return { status: 401, payload: { info: [ 'erreuraxios' ], model: 'Outputs', moreinfo: err.message } } + } +}; +Outputs.get = function ( filename, header ) { + // check file exist + const file = `${config.tribes}/${header.xworkon}/${filename}`; + // console.log('fichier demande ', file); + if( !fs.existsSync( file ) ) { + // console.log('le fichier demande n existe pas ', file); + return { + status: 404, + payload: { + info: [ 'fileUnknown' ], + model: 'UploadFiles' + } + }; + } else { + console.log( 'envoie le fichier ', file ); + return { + status: 200, + payload: { + info: [ 'fileknown' ], + model: 'UploadFiles', + file: file + } + }; + } +}; +Outputs.addjson = function ( data, header ) { + /* + Le header = {X-WorkOn:"",destinationfile:"", filename:""} + Le body = {jsonp:{},callback:function to launch after download,'code':'mot cle pour verifier que le fichier est à garder'} + */ + // console.log(req.body.jsonp); + try { + jsonfile.writeFileSync( header.destinationfile + '/' + header.filename, data.jsonp ); + if( data.callback ) { + const execCB = require( `${config.mainDir}/models/tribeid/${header.xworkon + }` ); + execCB[ data.callback ](); + } + return { + status: 200, + payload: { + info: [ 'wellUpload' ], + model: 'UploadFiles', + render: { + destination: header.destinationfile, + filename: header.filename + } + } + }; + } catch ( err ) { + console.log( 'Impossible de sauvegarder le fichier, A COMPRENDRE', err ); + return { + status: 503, + payload: { + info: [ 'savingError' ], + model: 'UploadFiles' + } + }; + } +}; +Outputs.add = function ( req, header ) { + const form = new formidable.IncomingForm(); + console.log( 'req.headers', req.headers ); + console.log( 'req.params', req.params ); + console.log( 'req.query', req.query ); + console.log( 'req.body', req.body ); + let destinationfile = `${config.tribes}/${header.xworkon}/${header.destinationfile + }`; + form.parse( req, function ( err, fields, files ) { + console.log( 'files', files.file.path ); + console.log( 'fields', fields ); + const oldpath = files.file.path; + destinationfile += '/' + files.file.name; + console.log( 'oldpath', oldpath ); + console.log( 'destinationfile', destinationfile ); + fs.copyFile( oldpath, destinationfile, function ( err ) { + if( err ) { + console.log( err ); + return { + status: 500, + payload: { + info: [ 'savingError' ], + model: 'UploadFiles' + } + }; + } else { + console.log( 'passe' ); + fs.unlink( oldpath ); + return { + status: 200, + payload: { + info: [ 'wellUpload' ], + model: 'UploadFiles', + render: { + destination: destinationfile + } + } + }; + } + } ); + } ); +}; +Outputs.generepdf = ( req, header ) => { + return new Promise( ( resolve, reject ) => { + let options = { + format: "A4", + orientation: "portrait", + border: "10mm", + footer: { + height: "20mm", + contents: { + default: '{{page}}/{{pages}}', // html pagination if edit needed + } + } + }; + let document = { + html: req.html, + data: { + data: req.data, + }, + path: `${config.tribes}/${header.xtribe}/outputs/${UUID.v4()}.pdf`, + type: "", + }; + pdf // generate pdf + .create( document, options ) + .then( ( res ) => { + resolve( { + status: 200, + payload: { + info: [ 'wellPdfGenerated' ], + model: 'Outputs', + data: { + path: document.path, + filename: req.data.filename + }, + render: { + filename: req.data.filename + } + } + } ); + } ) + .catch( ( err ) => { + reject( { + status: 500, + payload: { + info: [ 'pdfGenerationError' ], + model: 'Outputs', + error: err + } + } ); + } ); + } ); +}; +module.exports = Outputs; diff --git a/models/OutputsDev.js b/models/OutputsDev.js new file mode 100755 index 0000000..444da52 --- /dev/null +++ b/models/OutputsDev.js @@ -0,0 +1,492 @@ +const fs = require( 'fs-extra' ); +const path = require( 'path' ); +const formidable = require( 'formidable' ); +const jsonfile = require( 'jsonfile' ); +const mustache = require( 'mustache' ); +const moment = require( 'moment' ); +const UUID = require( 'uuid' ); +const pdf = require( "pdf-creator-node" ); +const nodemailer = require( 'nodemailer' ); +const smtpTransport = require( 'nodemailer-smtp-transport' ); +const axios = require( 'axios' ); +const { GoogleSpreadsheet } = require( 'google-spreadsheet' ); +const async = require( 'async' ); +const config = require( '../tribes/townconf.js' ); +const checkdata = require( `${config.tribes}/${config.mayorId}/www/cdn/public/js/checkdata` ); + +const Outputs = {}; +const sleep = ( milliseconds = 500 ) => new Promise( resolve => setTimeout( resolve, milliseconds ) ); +/* +Process any data to a specific output: +emailer => generate a finale text file to send +csv => export json file to csv data +pdf => generate a customized document +*/ +Outputs.envoiemail = ( msg, next ) => { + let transporter = nodemailer.createTransport( msg.smtp ); + transporter.sendMail( msg, async ( err, info ) => { + if( err ) { + next( err ); + } else { + console.log( 'info', info ) + fs.appendFileSync( `${config.tribes}/${msg.headers['x-client-nd-id']}/logs/${msg.headers['x-campaign-id']}_success.txt`, moment( new Date() ) + .format( 'YYYYMMDD HH:mm:ss' ) + ' - Success after ' + '0' + ' tries to ' + info.accepted.join( ',' ) + '\n', 'utf-8' ); + next( null ); + } + } ); +}; +Outputs.setupmail = ( msg, msg2send, index ) => { + const datacust = { + tribeidperso: msg.tribeidperso, + destperso: index + }; + // Evaluation of each field if mustache exist + const datacusteval = {}; + Object.keys( datacust.tribeidperso ) + .forEach( k => { + if( typeof datacust.tribeidperso[ k ] === 'string' || datacust.tribeidperso[ k ] instanceof String ) { + datacusteval[ k ] = mustache.render( datacust.tribeidperso[ k ], datacust ) + } else { + datacusteval[ k ] = datacust.tribeidperso[ k ]; + } + } ) + Object.keys( datacust.destperso ) + .forEach( k => { + if( typeof datacust.destperso[ k ] === 'string' || datacust.destperso[ k ] instanceof String ) { + datacusteval[ k ] = mustache.render( datacust.destperso[ k ], datacust ) + } else { + datacusteval[ k ] = datacust.destperso[ k ]; + } + } ) + msg2send.to = index.email; + console.log( 'msg2send.to ' + msg2send.to ); + msg2send.subject = mustache.render( msg.template.subject, datacusteval ); + msg2send.text = mustache.render( msg.template.text, datacusteval ); + msg2send.html = mustache.render( msg.template.html, datacusteval ); + // TODO need to move that in generemsg + // if (config.emailerurl == 'http://devapia.maildigit.fr:3015') { + // fs.writeFileSync('devdata/tmp/test.html', msg2send.html, 'utf-8'); + // console.log('lancement email sur dev, pour controler le mail générer voir ds ./config.js il faut changer config.emailerurl avec https://mail.maildigit.fr pour envoyer le mail ') + // return { + // status: 200, + // payload: { + // info: ['msgsentok'], + // model: 'Outputs', + // moreinfo: "parametrer sur emailer de dev et pas de production" + // } + // } + // } + return msg2send; +} +Outputs.envoiefirstmail = async ( msg ) => { + console.log( '###############################################' ) + console.log( "envoie first msg email: " + msg.to ) + let transporter = nodemailer.createTransport( msg.smtp ); + console.log( 'attente 1er msg avant d envoyer les autres' ); + const transport = await transporter.verify(); + console.log( 'transport', transport ); + if( transport.error ) { + console.log( 'Probleme de smtp', error ); + return { + status: 500, + payload: { + info: '' + } + }; + } else { + let rep = await transporter.sendMail( msg ); + console.log( 'rep sendMail', rep ); + if( rep.accepted && rep.accepted.length > 0 && rep.rejected.length == 0 ) { + fs.appendFileSync( `${config.tribes}/${msg.headers['x-client-nd-id']}/logs/${msg.headers['x-campaign-id']}_success.txt`, moment( new Date() ) + .format( 'YYYYMMDD HH:mm:ss' ) + ' - Success after waiting 1st email to send ' + msg.to + '\n', 'utf-8' ); + return { + status: '200', + payload: { + info: [ 'send1stemailok' ], + model: 'Outputs' + } + }; + } + // status à tester si necessaire de detecter une erreur + // if (rep.rejectedErrors) { + fs.appendFileSync( `${config.tribes}/${msg.headers['x-client-nd-id']}/logs/${msg.headers['x-campaign-id']}_error.txt`, moment( new Date() ) + .format( 'YYYYMMDD HH:mm:ss' ) + ' - err after waiting result\n ' + msg.to, 'utf-8' ); + return { + status: '500', + payload: { + info: [ 'rejectedError' ], + model: 'Outputs' + } + }; + } +} +Outputs.envoiemails = ( msg, msg2send, targets, iteration, resolve, reject ) => { + let newtargets = []; + async.each( targets, ( index, callback ) => { // iterate asynchronously in msg.destperso (targets) + let finalmsg = Outputs.setupmail( msg, msg2send, index ); + console.log( '###############################################' ) + console.log( "envoie msg email: " + finalmsg.to ) + Outputs.envoiemail( finalmsg, ( err ) => { + if( err ) { // intentionally don't pass this error in callback, we dont want to break loop + newtargets.push( index ); // stock all errored mails for next try + } + } ); + callback(); + }, function ( err ) { // part executed only once all iterations are done + if( newtargets.length > 0 && iteration < 4 ) { + setTimeout( () => { + Outputs.envoiemails( msg, msg2send, newtargets, iteration + 1, resolve, reject ); + }, 600000 ); + } else resolve( newtargets ); // return not resolved errors after 4 trys for log + } ); +} +Outputs.generemsg = async ( msg, header ) => { + /* + wait msg sent and return result sent + */ + // Recupere les parametre smtp du domainName à utiliser + console.log( 'pass Outputs.generemsg' ) + try { + const confclientexpediteur = jsonfile.readFileSync( `${config.tribes}/${msg.tribeidperso.tribeidexpediteur}/clientconf.json` ); + msg.smtp = confclientexpediteur.smtp; + } catch ( err ) { + console.log( 'la conf smtp du client n\'est pas definie' ); + return { + status: 404, + payload: { + info: [ 'smtpnotdefined' ], + model: 'Outputs' + } + }; + } + console.log( msg ); + if( !msg.template.sendascontent && msg.template.htmlfile ) { + try { + msg.template.html = fs.readFileSync( config.sharedData + '/' + msg.template.htmlfile + '/contentinline.mustache', 'utf-8' ); + msg.template.text = fs.readFileSync( config.sharedData + '/' + msg.template.htmlfile + '/contenttxt.mustache', 'utf-8' ); + } catch ( err ) { + console.log( 'WARNING, html file template missing ' + config.sharedData + '/' + msg.template.htmlfile ); + console.log( err ); + return { + status: 404, + payload: { + info: [ 'fileUnknown' ], + model: 'UploadFiles', + moreinfo: 'Template unavailable, check ' + config.sharedData + '/' + msg.template.htmlfile + '/contentinline.mustache and contenttxt.mustache' + } + }; + } + } + if( msg.template.html.length == 0 ) { + console.log( 'template.html est vide' ) + return { + status: 404, + payload: { + info: [ 'ERRnotemplate' ], + model: 'Outputs', + moreinfo: 'No template email check ' + } + }; + } + // mustache any data into + const msg2send = {}; + msg2send.smtp = msg.smtp; + msg2send.from = msg.tribeidperso.from; + if( msg.tribeidperso.cc ) msg2send.cc = msg.tribeidperso.cc; + if( msg.tribeidperso.bcc ) msg2send.bcc = msg.tribeidperso.bcc; + if( msg.tribeidperso.replyTo ) msg2send.replyTo = msg.tribeidperso.replyTo; + msg2send.headers = { + 'x-campaign-id': msg.tribeidperso.messageId, + 'x-client-nd-id': msg.tribeidperso.tribeid, + 'x-template-nd-id': msg.tribeidperso.templateId + }; + console.log( 'nb de message to send:', msg.destperso.length ); + // send first mail + const ret = await Outputs.envoiefirstmail( Outputs.setupmail( msg, msg2send, msg.destperso[ 0 ] ) ); + console.log( 'ret 1er msg', ret ); + if( ret.status == 200 ) { + pass1ermsg = true; + msg.destperso.shift(); + }; + console.log( 'attente 1er msg avant d envoyer les autres' ); + // send other mails + new Promise( ( resolve, reject ) => { // useless promise used for recursive calls in Outputs.envoiemails + Outputs.envoiemails( msg, msg2send, msg.destperso, 0, resolve, reject ); + } ) + .then( ( result ) => { + async.eachSeries( result, ( index, callback ) => { // variante of each but runs only a single operation at a time because of fs.appendFile + fs.appendFile( `${config.tribes}/${msg.headers['x-client-nd-id']}/logs/${msg.headers['x-campaign-id']}_error.txt`, moment( new Date() ) + .format( 'YYYYMMDD HH:mm:ss' ) + ' - err after 4 tries to ' + info.rejected.join( ',' ) + '\n', 'utf-8', ( err ) => { + callback( err ); + }, ( err ) => { + if( err ) console.log( err ); + } ); + console.log( 'msg.to not well sent', msg.to ); + } ); + } ) + if( pass1ermsg ) { + return { + status: 200, + payload: { + info: [ 'msgsentok' ], + model: 'Outputs' + } + }; + } else { + return { + status: 500, + payload: { + info: [ 'msgsentko' ], + model: 'Ouputs', + moreinfo: "1er msg non envoyé car erreur" + } + } + } +}; +Outputs.sendMailcampain = async ( msg, headersmsg ) => { + /* + Permet de lancer une campagne de mail personnalisé en mode web service + avec axios config.emailerurl https://mail qui peut être sur un autre serveur que celui en cours + Attention headermsg doit être retraduit avec les champs envoyé par un navigateur + Si le serveur en cours appelle cette fonction les champs du header doivent changer + voir config.js node_env .exposedHeaders + + Pour un exemple de msg voir u exemple type de message envoyé dans un tribeid/domain/clientconf.json + avec l'envoi d'email + */ + //console.log(msg) + // On ajoute le contenu du template directement dans la demande + if( msg.template.sendascontent && msg.template.htmlfile ) { + try { + console.log( 'test', msg.template.sendascontent ) + msg.template.html = fs.readFileSync( config.sharedData + '/' + msg.template.htmlfile + '/contentinline.mustache', 'utf-8' ); + msg.template.text = fs.readFileSync( config.sharedData + '/' + msg.template.htmlfile + '/contenttxt.mustache', 'utf-8' ); + } catch ( err ) { + console.log( 'WARNING, html file template missing ' + config.sharedData + '/' + msg.template.htmlfile ); + //console.log(err); + return { + status: 404, + payload: { + info: [ 'fileUnknown' ], + model: 'UploadFiles', + moreinfo: 'Template unavailable, check ' + config.sharedData + '/' + msg.template.htmlfile + '/contentinline.mustache and contenttxt.mustache' + } + }; + } + delete msg.template.htmlfile; + if( msg.template.html.length == 0 ) { + return { + status: 404, + payload: { + info: [ 'ERRnotemplate' ], + model: 'Outputs', + moreinfo: 'No template email check ' + } + }; + } + } + console.log( 'envoie sur', `${config.emailerurl}/outputs/msg` ) + //console.log(msg) + // on check si les key de headermsg sont des key traduite via exposedHeaders + // (cas ou c'est l'application qui envoie un email) + if( headersmsg.xtribeid ) { + Object.keys( config.exposedHeaders ) + .forEach( h => { + headersmsg[ h ] = headersmsg[ config.exposedHeaders[ h ] ]; + delete headersmsg[ config.exposedHeaders[ h ] ]; + } ); + } + // on ajoute le code pour la signature + headersmsg.hashbody = msg.code; + console.log( 'header after traduction: ', headersmsg ) + try { + const resCamp = await axios.post( `${config.emailerurl}/outputs/msg`, msg, { + headers: headersmsg + } ); + //console.log('Etat:', resCamp); + console.log( 'Tried to send 1st email of the campain ' + msg.destperso[ 0 ].email ); + // it just check the 1st email in destperso to return an answer if 1st is ok then all other are send in queue + if( resCamp ) { + return resCamp; + } else { + return { status: 200, payload: { info: [ 'CampainSent' ], model: 'Outputs' } }; + } + } catch ( err ) { + // aios error handler + return { status: 401, payload: { info: [ 'erreuraxios' ], model: 'Outputs', moreinfo: err.message } } + } +}; +Outputs.get = function ( filename, header ) { + // check file exist + const file = `${config.tribes}/${header.xworkon}/${filename}`; + // console.log('fichier demande ', file); + if( !fs.existsSync( file ) ) { + // console.log('le fichier demande n existe pas ', file); + return { + status: 404, + payload: { + info: [ 'fileUnknown' ], + model: 'UploadFiles' + } + }; + } else { + console.log( 'envoie le fichier ', file ); + return { + status: 200, + payload: { + info: [ 'fileknown' ], + model: 'UploadFiles', + file: file + } + }; + } +}; +Outputs.addjson = function ( data, header ) { + /* + Le header = {X-WorkOn:"",destinationfile:"", filename:""} + Le body = {jsonp:{},callback:function to launch after download,'code':'mot cle pour verifier que le fichier est à garder'} + */ + // console.log(req.body.jsonp); + try { + jsonfile.writeFileSync( header.destinationfile + '/' + header.filename, data.jsonp ); + if( data.callback ) { + const execCB = require( `${config.mainDir}/models/tribeid/${header.xworkon + }` ); + execCB[ data.callback ](); + } + return { + status: 200, + payload: { + info: [ 'wellUpload' ], + model: 'UploadFiles', + render: { + destination: header.destinationfile, + filename: header.filename + } + } + }; + } catch ( err ) { + console.log( 'Impossible de sauvegarder le fichier, A COMPRENDRE', err ); + return { + status: 503, + payload: { + info: [ 'savingError' ], + model: 'UploadFiles' + } + }; + } +}; +Outputs.add = function ( req, header ) { + const form = new formidable.IncomingForm(); + console.log( 'req.headers', req.headers ); + console.log( 'req.params', req.params ); + console.log( 'req.query', req.query ); + console.log( 'req.body', req.body ); + let destinationfile = `${config.tribes}/${header.xworkon}/${header.destinationfile + }`; + form.parse( req, function ( err, fields, files ) { + console.log( 'files', files.file.path ); + console.log( 'fields', fields ); + const oldpath = files.file.path; + destinationfile += '/' + files.file.name; + console.log( 'oldpath', oldpath ); + console.log( 'destinationfile', destinationfile ); + fs.copyFile( oldpath, destinationfile, function ( err ) { + if( err ) { + console.log( err ); + return { + status: 500, + payload: { + info: [ 'savingError' ], + model: 'UploadFiles' + } + }; + } else { + console.log( 'passe' ); + fs.unlink( oldpath ); + return { + status: 200, + payload: { + info: [ 'wellUpload' ], + model: 'UploadFiles', + render: { + destination: destinationfile + } + } + }; + } + } ); + } ); +}; +Outputs.sheettojson = async ( req, header ) => { + doc = new GoogleSpreadsheet( req.productIdSpreadsheet ); + await doc.useServiceAccountAuth( req.googleDriveCredentials ); + await doc.loadInfo(); + let result = []; + for( const sheetName of req.sheets ) { + console.log( 'loading: ', sheetName ); + sheet = doc.sheetsByTitle[ sheetName ] + await sheet.loadHeaderRow(); + const records = await sheet.getRows( { offset: 1 } ) + records.forEach( record => { + let offer = {} + for( let index = 0; index < record._sheet.headerValues.length; index++ ) { + offer[ record._sheet.headerValues[ index ] ] = record[ record._sheet.headerValues[ index ] ]; + } + result.push( offer ); + } ); + } + return result; +}; +Outputs.generepdf = ( req, header ) => { + return new Promise( ( resolve, reject ) => { + let options = { + format: "A4", + orientation: "portrait", + border: "10mm", + footer: { + height: "20mm", + contents: { + default: '{{page}}/{{pages}}', // html pagination if edit needed + } + } + }; + let document = { + html: req.html, + data: { + data: req.data, + }, + path: `${config.tribes}/${header.xtribeid}/outputs/${UUID.v4()}.pdf`, + type: "", + }; + pdf // generate pdf + .create( document, options ) + .then( ( res ) => { + resolve( { + status: 200, + payload: { + info: [ 'wellPdfGenerated' ], + model: 'Outputs', + data: { + path: document.path, + filename: req.data.filename + }, + render: { + filename: req.data.filename + } + } + } ); + } ) + .catch( ( err ) => { + reject( { + status: 500, + payload: { + info: [ 'pdfGenerationError' ], + model: 'Outputs', + error: err + } + } ); + } ); + } ); +}; +module.exports = Outputs; diff --git a/models/Pagans.js b/models/Pagans.js new file mode 100755 index 0000000..98d28fc --- /dev/null +++ b/models/Pagans.js @@ -0,0 +1,773 @@ +const bcrypt = require( 'bcrypt' ); +const fs = require( 'fs-extra' ); +const jsonfile = require( 'jsonfile' ); +const glob = require( 'glob' ); +const moment = require( 'moment' ); +const jwt = require( 'jwt-simple' ); +const UUID = require( 'uuid' ); +const Outputs = require( './Outputs.js' ); +const config = require( '../tribes/townconf.js' ); +const checkdata = require( `${config.tribes}/${config.mayorId}/www/cdn/public/js/checkdata` ); +/* +Gestion des utilisateurs connecte + +/tribes/tribeid/users/ + UUID.json + /searchindex/indexTOKEN = {TOKEN:UUID} + to check authentification + indexLOGIN = {LOGIN:UUID} + to check if LOGIN exist + +Used for referntial: +To update +Global: datashared/referentials/dataManagement/object/users.json +Local: data/tribe/*${header.workOn}/referentials/dataManagement/object/users.json +To use after a server rerun +data/tribe/*${header.workOn}/referentials/${header.langue}/object/users.json + +Faire comme contact charger les index au lancement +et changer la logique de user/id/profil o + + + On initialise les objets au lancement du serveur +this.uids[u.UUID] = [u.LOGIN, u.EMAIL, u.password, u.profil, u.TOKEN]; +this.logins[u.LOGIN] = u.UUID; +this.tokens[u.UUID] = u.TOKEN; +on stocke /domain/tribeid/users/logins.json et /uids.json +on stocke /domain/tribeids.json et tokkens.json + +On retourne l'objet {tribeids:[list tribeid], tokens:{UUID:TOKEN}} +*/ +const Pagans = {}; +Pagans.init = tribeids => { + console.group( 'init Pagans logins, tokens ...' ); + // store globaly tokens + const tokens = {}; + const emailsglob = {}; + const loginsglob = {}; + // For each tribeid create series of indexes + //console.log(tribeids); + tribeids.forEach( tribeid => { + // Reset for each domain + const uids = {}; + const logins = {}; + const emails = {}; + //check folder exist + /*if( !fs.existsSync( `${config.tribes}/${tribeid}/users` ) ) { + fs.mkdirSync( `${config.tribes}/${tribeid}/users` ) + } + if( !fs.existsSync( `${config.tribes}/${tribeid}/users/searchindex` ) ) { + fs.mkdirSync( `${config.tribes}/${tribeid}/users/searchindex` ) + }*/ + glob.sync( `${config.tribes}/${tribeid}/users/*.json` ) + .forEach( file => { + //console.log( file ); + const u = fs.readJsonSync( file, 'utf-8' ); + if( !u.TOKEN ) { + u.TOKEN = ''; + } + //console.log( u ) + uids[ u.UUID ] = [ u.LOGIN, u.EMAIL, u.PASSWORD, u.ACCESSRIGHTS, u.TOKEN ]; + logins[ u.LOGIN ] = u.UUID; + loginsglob[ u.LOGIN ] = tribeid; + // On ne charge que les TOKEN valide + let decodedTOKEN = {}; + if( u.TOKEN != '' ) { + try { + decodedTOKEN = jwt.decode( u.TOKEN, config.jwtSecret ); + //console.log( 'decodeTOKEN', decodedTOKEN ) + if( moment( decodedTOKEN.expiration ) > moment() ) { + tokens[ u.UUID ] = { TOKEN: u.TOKEN, ACCESSRIGHTS: u.ACCESSRIGHTS }; + //console.log( `add token valid for ${u.UUID}:`, tokens[ u.UUID ] ) + } + } catch ( err ) { + console.log( 'pb de TOKEN impossible a decoder' + u.TOKEN, err ); + } + } + if( u.EMAIL ) { + emails[ u.EMAIL ] = u.UUID; + emailsglob[ u.EMAIL ] = tribeid; + } + } ); + // UIDS INDEX BY DOMAIN ={UUID:[LOGIN,EMAIL,psw,accessRight,TOKEN]} + fs.outputJson( `${config.tribes}/${tribeid}/users/searchindex/uids.json`, uids, { + spaces: 2 + }, err => { + if( err ) throw err; + } ); + // LOGINS INDEX BY DOMAIN ={LOGIN:UUID} + fs.outputJson( `${config.tribes}/${tribeid}/users/searchindex/logins.json`, logins, { + spaces: 2 + }, err => { + if( err ) throw err; + } ); + // EMAILS INDEX BY DOMAIN ={EMAIL:UUID} + fs.outputJson( `${config.tribes}/${tribeid}/users/searchindex/emails.json`, emails, { + spaces: 2 + }, err => { + if( err ) throw err; + } ); + } ); + // EMAILS et appartenance domain + fs.outputJson( `${config.tmp}/emailsglob.json`, emailsglob, { + spaces: 2 + }, err => { + if( err ) throw err; + } ); + // logins et appartenance domain (permet de retrouver tribeid pour un LOGIN) + fs.outputJson( `${config.tmp}/loginsglob.json`, loginsglob, { + spaces: 2 + }, err => { + if( err ) throw err; + } ); + // TOKENS GLOBAL INDEX Centralise tous les TOKEN pour plus de rapidité + // {UUID:TOKEN} + fs.outputJson( `${config.tmp}/tokens.json`, tokens, { + spaces: 2 + }, err => { + if( err ) throw err; + } ); + console.groupEnd(); + return { tokens }; +}; +/** + * Update indexes: logins, uids and tokens + * @param {object} user User object + * @param {string} tribeid - The client identifier + * @rm {boolean} false => update, true => remove + */ +Pagans.updateDatabase = ( user, tribeid, rm = false ) => { + console.group( `Pagans.updateDatabase for ${tribeid} with user ${user.LOGIN}` ) + console.assert( config.loglevel == "quiet", 'user', user ); + const loginsIndex = `${config.tribes}/${tribeid}/users/searchindex/logins.json`; + jsonfile.readFile( loginsIndex, function ( err, logins ) { + console.assert( config.loglevel == "quiet", 'logins', logins ); + try { + if( rm ) { + delete logins[ user.LOGIN ]; + } else { + logins[ user.LOGIN ] = user.UUID; + } + jsonfile.writeFile( loginsIndex, logins, { + spaces: 2 + }, err => { + if( err ) console.log( err ); + } ); + } catch ( err ) { + console.log( 'Gros pb de mise à jour Pagans.updateDatabase conflit des logins' ); + } + } ); + const uidsIndex = `${config.tribes}/${tribeid}/users/searchindex/uids.json`; + jsonfile.readFile( uidsIndex, function ( err, uids ) { + try { + if( rm ) { + delete uids[ user.UUID ]; + } else { + uids[ user.UUID ] = [ + user.LOGIN, + user.EMAIL, + user.PASSWORD, + user.ACCESSRIGHTS, + user.TOKEN + ]; + } + jsonfile.writeFile( uidsIndex, uids, { + spaces: 2 + }, err => { + if( err ) console.log( err ); + } ); + } catch ( err ) { + console.log( 'Gros pb de mise à jour Pagans.updateDatabase conflit des uids si ce reproduit passer en mode sync bloquant' ); + } + } ); + const emailsIndex = `${config.tribes}/${tribeid}/users/searchindex/emails.json`; + jsonfile.readFile( emailsIndex, function ( err, emails ) { + console.assert( config.loglevel == "quiet", 'emailss', emails ); + try { + if( rm ) { + delete emails[ user.EMAIL ]; + } else { + emails[ user.EMAIL ] = user.UUID; + } + jsonfile.writeFile( emailsIndex, emails, { + spaces: 2 + }, err => { + if( err ) console.log( err ); + } ); + } catch ( err ) { + console.log( 'Gros pb de mise à jour Pagans.updateDatabase conflit des emails' ); + } + } ); + const tokensIndex = `${config.tmp}/tokens.json`; + let tokens = {}; + try { + tokens = jsonfile.readFileSync( tokensIndex ); + } catch ( err ) { + console.log( 'tokens.json not available' ) + } + // tokens[user.UUID] = user.TOKEN; + tokens[ user.UUID ] = { TOKEN: user.TOKEN, ACCESSRIGHTS: user.ACCESSRIGHTS }; + jsonfile.writeFileSync( tokensIndex, tokens, { + spaces: 2 + } ); + /* + jsonfile.readFile(tokensIndex, function(err, tokens) { + tokens[user.UUID] = user.TOKEN; + jsonfile.writeFile(tokensIndex, tokens, { spaces: 2 }, err => { + if (err) console.log(err); + }); + });*/ + console.groupEnd(); +}; +/** + * Read the profil.json of an user + * @param {[type]} UUID ID of the user + * @param {[type]} tribeid tribeid + * @return {Promise} - Return a promise resolved with user data or rejected with an error + */ +// A S U P P R I M E R utiliser getinfousers pour recuperer des indexs de users +// en créer d'autres si necessaire +Pagans.getUserlist = ( header, filter, field ) => { + console.group( `getUserlist filter with filter ${filter} to get ${field}` ); + /* const getuser = Pagans.getUser(header.xuuid, header.xtribeid); + if (getuser.status != 200) + return { status: getuser.status, data: getuser.payload }; + const user = getuser.payload.data; + // console.log(user); + // check if update accessright allowed + // choose the level depending of ownby xuuid + let accessright = user.objectRights[header.xtribeid].users[0]; + if (user.ownby.includes(header.xtribeid)) { + accessright = user.objectRights[header.xtribeid].users[1]; + } + // Check update is possible at least user itself ownby itself + console.log(accessright); + console.log(accessright & 4); + if ((accessright & 4) != 4) { + return { + status: 403, + data: { info: ['forbiddenAccess'], model: 'Pagans' } + }; + } + */ + const Userlist = []; + glob.sync( `${config.tribes}/${header.xworkon}/users/*/profil.json` ) + .forEach( f => { + const infouser = jsonfile.readFileSync( f ); + // Ajouter filter et liste de field + if( filter != 'all' ) { + // decode filter et test + } + const info = {}; + field.split( '______' ) + .forEach( k => { + if( ![ 'password' ].includes( k ) ) info[ k ] = infouser[ k ]; + } ); + Userlist.push( info ); + } ); + // console.log('userlist', Userlist); + console.groupEnd(); + return { + status: 200, + data: { + data: Userlist + } + }; +}; +Pagans.getinfoPagans = ( tribeid, accessrights, listindex ) => { + const info = {} + const object = 'users'; + const indexs = listindex.split( '_' ) + let access = true; + indexs.forEach( index => { + access = !( [ 'emails', 'logins', 'uids' ].includes( index ) && !( accessrights.data[ object ] && accessrights.data[ object ].includes( 'R' ) ) ); + if( access && fs.existsSync( `${config.tribes}/${tribeid}/${object}/searchindex/${index}.json` ) ) { + info[ index ] = jsonfile.readFileSync( `${config.tribes}/${tribeid}/${object}/searchindex/${index}.json` ) + } + } ) + console.log( info ) + return { status: 200, data: { info: info } } +} +Pagans.getUser = ( UUID, tribeid, accessrights ) => { + console.assert( config.loglevel == "quiet", `getUser on ${UUID} for ${tribeid} with ${JSON.stringify(accessrights)}` ); + if( !fs.existsSync( `${config.tribes}/${tribeid}/users/${UUID}.json` ) ) { + return { + status: 404, + data: { + info: [ 'useridNotfound' ], + model: 'Pagans', + render: { + UUID, + tribeid + } + } + } + } + const user = jsonfile.readFileSync( `${config.tribes}/${tribeid}/users/${UUID}.json` ); + let access = true; + //console.log("test accessrights.data['users'].includes('R')", accessrights.data['users'].includes('R')) + console.assert( config.loglevel == "quiet", 'accessrights', accessrights ) + access = accessrights.users && ( accessrights.users.includes( 'R' ) || ( accessrights.users.includes( 'O' ) && user.OWNEDBY.includes( UUID ) ) ); + if( access ) { + return { + status: 200, + data: { + user: user, + model: "User", + info: [ "Authorizedtogetuserinfo" ] + } + }; + } + return { + status: 403, + data: { + info: [ 'Forbidden' ], + model: 'Pagans', + render: { + UUID, + tribeid + } + } + }; +}; +Pagans.getUserIdFromEMAIL = ( tribeid, EMAIL ) => { + if( !checkdata.test.EMAIL( EMAIL ) ) { + return { + status: 400, + data: { + info: [ 'ERREMAIL' ], + model: 'Pagans' + } + }; + } + const emailsIndex = jsonfile.readFileSync( `${config.tribes}/${tribeid}/users/searchindex/emails.json` ); + if( !emailsIndex.hasOwnProperty( EMAIL ) ) { + return { + status: 404, + data: { + info: [ 'userEMAILNotfound' ], + model: 'Pagans' + } + }; + } + return emailsIndex[ EMAIL ]; +}; +Pagans.updateUserpassword = ( UUID, header, data ) => { + const getUser = Pagans.getUser( UUID, header.xtribeid, { users: 'W' } ); + if( getUser.status == 200 ) { + const user = getUser.data.user; + // console.log('user exist', user); + const match = bcrypt.compareSync( data.password, user.PASSWORD ); + if( !match ) { + return { + status: 401, + data: { + info: [ 'checkCredentials' ], + model: 'Pagans' + } + }; + } + // console.log('Credentials are matching!'); + if( checkdata.test.password( {}, data.pswnew ) ) { + user.PASSWORD = bcrypt.hashSync( data.pswnew, config.saltRounds ); + jsonfile.writeFileSync( `${config.tribes}/${header.xworkon}/users/${UUID}.json`, user, { + spaces: 2 + } ); + Pagans.updateDatabase( user, header.xworkon, false ); + return { + status: 200, + data: { + info: [ 'successfulUpdate' ], + model: 'Pagans' + } + }; + } else { + return { + status: 401, + data: { + info: [ 'pswTooSimple' ], + model: 'Pagans' + } + }; + } + } +}; +Pagans.createUser = ( header, data ) => { + /* + @input data={PUBKEY,EMAIL,LOGIN,UUID} check and create for header xworkon a user with generic password + */ + console.log( 'createUser on header.xworkon:' + header.xworkon + ' by user:' + header.xpaganid ); + console.assert( config.loglevel == "quiet", 'with data:', data ); + const ref = jsonfile.readFileSync( `${config.tribes}/${header.xworkon}/referentials/${header.xlang}/object/users.json` ); + const logins = jsonfile.readFileSync( `${config.tribes}/${header.xworkon}/users/searchindex/logins.json` ); + const LOGIN = Object.keys( logins ); + console.assert( config.loglevel == "quiet", 'LOGIN list', LOGIN ); + const emails = jsonfile.readFileSync( `${config.tribes}/${header.xworkon}/users/searchindex/emails.json` ); + console.assert( config.loglevel == "quiet", 'emails', emails ); + const EMAIL = Object.keys( emails ); + console.assert( config.loglevel == "quiet", 'EMAIL list', EMAIL ); + // list.UUID est forcement unique car on est en update et pas en create + if( !data.UUID ) data.UUID = UUID.v4(); + // pour la logique de checkdata il faut passer le parametre + const check = checkdata.evaluate( { + list: { + LOGIN, + EMAIL, + UUID: [] + } + }, ref, data ); + console.assert( config.loglevel == "quiet", 'check & clean data before update ', check ); + if( check.invalidefor.length > 0 ) { + return { + status: 403, + data: { + model: 'Pagans', + info: check.invalidefor + } + }; + } + const clientConfig = jsonfile.readFileSync( `${config.tribes}/${header.xworkon}/clientconf.json` ); + const user = check.data; + user.DATE_CREATE = new Date() + .toISOString(); + user.PASSWORD = bcrypt.hashSync( clientConfig.genericpsw, config.saltRounds ); + user.OWNBY = [ data.UUID ]; + user.OBJECT = 'users'; + // set le minimum de droit sur l'objet users dont il est le Owner + if( data.ACCESSRIGHTS ) { + user.ACCESSRIGHTS = data.ACCESSRIGHTS + } else { + user.ACCESSRIGHTS = { app: {}, data: {} }; + } + user.ACCESSRIGHTS.data[ header.xworkon ] = { users: "O" }; + jsonfile.writeFileSync( `${config.tribes}/${header.xworkon}/users/${user.UUID}.json`, user, { + spaces: 2 + } ); + Pagans.updateDatabase( user, header.xworkon, false ); + return { + status: 200, + data: { + uuid: user.UUID, + info: [ 'successfulCreate' ], + model: 'Pagans' + } + }; +}; +Pagans.updateUser = ( UUID, header, data ) => { + console.log( 'updateUser UUID:' + UUID + ' on header.xworkon:' + header.xworkon + ' by user' + header.xpaganid ); + // console.log('header', header); + console.assert( config.loglevel == "quiet", 'with data', data ); + const getuser = Pagans.getUser( UUID, header.xworkon, { users: 'R' } ); + if( getuser.status != 200 ) return { + status: getuser.status, + data: getuser.data.user + }; + const user = getuser.data.user; + /* + let userconnected = user; + if (UUID != header.xuuid) { + // mean connected user want to change other user + const getuserconnected = Pagans.getUser(header.xuuid, header.xtribeid); + userconnected = getuserconnected.payload.data; + } + console.log('user to update', user); + console.log('user connected that request update', userconnected); + + // check if update accessright allowed + // choose the level depending of ownby xuuid + let accessright = userconnected.objectRights[header.xworkon].users[0]; + if (user.ownby.includes(header.xuuid)) { + accessright = userconnected.objectRights[header.xworkon].users[1]; + } + // Check update is possible at least user itself ownby itself + console.log(accessright); + console.log(accessright & 2); + if ((accessright & 2) != 2) { + return { + status: 403, + data: { info: ['forbiddenAccess'], model: 'Pagans' } + }; + } + */ + const ref = jsonfile.readFileSync( `${config.tribes}/${header.xworkon}/referentials/object/users_${ + header.xlang + }.json` ); + const logins = jsonfile.readFileSync( `${config.tribes}/${header.xworkon}/users/searchindex/logins.json` ); + const LOGIN = Object.keys( logins ) + .filter( l => logins[ l ] != user.UUID ); + // console.log( 'LOGIN list', LOGIN ); + const emails = jsonfile.readFileSync( `${config.tribes}/${header.xworkon}/users/searchindex/emails.json` ); + // console.log( 'emails', emails ); + const EMAIL = Object.keys( emails ) + .filter( e => emails[ e ] != user.UUID ); + // console.log( 'EMAIL list', EMAIL ); + // list.UUID est forcement unique car on est en update et pas en create + // pour la logique de checkdata il faut passer le parametre + const check = checkdata.evaluate( { + profil: user[ 'apps' + header.xworkon + 'profil' ], + list: { + LOGIN, + EMAIL, + UUID: [] + } + }, ref, data ); + if( check.invalidefor.length > 0 ) { + return { + status: 403, + data: { + model: 'Pagans', + info: check.invalidefor, + } + }; + } + data = check.data; + let saveuser = false; + let updateDatabase = false; + Object.keys( data ) + .forEach( k => { + //console.log( user[ k ] ) + //console.log( data[ k ] ) + //console.log( '---' ) + if( user[ k ] != data[ k ] ) { + user[ k ] = data[ k ]; + saveuser = true; + if( [ 'TOKEN', 'LOGIN', 'EMAIL' ].includes( k ) ) updateDatabase = true; + // attention si LOGIN ou EMAIL change il faut checker qu il n existe pas dejà risque de conflit + } + } ); + if( saveuser ) { + //console.log( 'mise à jour user profile.json' ); + if( data.TOKEN ) { + user.date_lastLOGIN = new Date() + .toISOString(); + } else { + user.date_update = new Date() + .toISOString(); + } + try { + jsonfile.writeFileSync( `${config.tribes}/${header.xworkon}/users/${UUID}.json`, user, { + spaces: 2 + } ); + //console.log( 'declenche updatabase', updateDatabase ) + if( updateDatabase ) { + // mean index have to be updated + Pagans.updateDatabase( user, header.xworkon, false ); + console.assert( config.loglevel == "quiet", 'MISE A JOUR DU TOKEN ou de l\'EMAIL ou du LOGIN' ); + } + } catch ( err ) { + console.log( 'ERRRRR need to understand update impossible of user: ' + UUID + ' in domain:' + header.xworkon + ' from user ' + header.xpaganid + ' of domain:' + header.xtribe ); + console.log( 'with data :', data ); + return { + status: 400, + data: { + info: [ 'failtoWritefs' ], + model: 'Pagans' + } + }; + } + } + return { + status: 200, + data: { + info: [ 'successfulUpdate' ], + model: 'Pagans' + } + }; +}; +Pagans.deleteUser = ( UUID, header ) => { + // Delete remove from users object UUID and update index + // Activity is not deleted => means some activity can concern an UUID that does not exist anymore. + // update index + const infouser = jsonfile.readFileSync( `${config.tribes}/${header.xworkon}/users/${UUID}.json` ); + Pagans.updateDatabase( infouser, header.xworkon, true ); + fs.removeSync( `${config.tribes}/${header.xworkon}/users/${UUID}.json` ); + return { + status: 200, + data: { + info: [ 'successfulDelete' ], + modedl: 'Pagans' + } + }; +}; +/* +@header { xtribeid: client domain name data + A VERIFIER inutile ,xworkon: client domain name where user is store and where data are stored + ,xuuid: 1 if unknown else if user id auhtneticated + ,xlanguage: langue used fr en return referential in this lang + ,xauth: TOKEN valid for 24h'} + workon=xtribeid in an app client usage + in case of xtribeid=mymaidigit, + if workon==mymaildigit => admin role on any xworkon + else adlin role only in xworkon specified +@body {LOGIN: password:} +return {status:200, data:{data:{TOKEN,UUID}}} +return {status:401,data:{info:[code list], model: referential}} +*/ +Pagans.loginUser = ( header, body, checkpsw ) => { + // On recupere tribeid du LOGIN + // ATTENTION xworkon peut être different du user xtribeid + //(cas d'un user qui a des droits sur un autre domain et qui travail sur cet autre domain) + // les function Pagans utilise le domain de travail xWorkon + // il faut donc modifier le header au moment du LOGIN + // pour que l'update du user au moment du LOGIN concerne bien le bon domain + header.xworkon = header.xtribe + const LOGINdom = jsonfile.readFileSync( `${config.tmp}/loginsglob.json` ); + console.assert( config.loglevel == "quiet", LOGINdom ) + console.assert( config.loglevel == "quiet", body ) + if( !LOGINdom[ body.LOGIN ] ) { + return { + status: 401, + data: { info: [ 'LoginDoesNotExist' ], model: 'Pagans' } + }; + } + const logins = jsonfile.readFileSync( `${config.tribes}/${LOGINdom[body.LOGIN]}/users/searchindex/logins.json` ); + if( !Object.keys( logins ) + .includes( body.LOGIN ) ) { + return { + status: 401, + data: { + info: [ 'LOGINDoesNotExist' ], + model: 'Pagans', + moreinfo: `Le login ${body.LOGIN} does not exist for tribeid ${LOGINdom[body.LOGIN]}` + } + }; + } + // Load user + const uid = logins[ body.LOGIN ]; + const getUser = Pagans.getUser( uid, LOGINdom[ body.LOGIN ], { users: 'R' } ); + console.log( 'getPagans', getUser ) + if( getUser.status != 200 ) { + return { status: 200, data: { model: 'Pagans', user: getUser.data.user } }; + } + const user = getUser.data.user; + console.log( 'user', user ) + if( checkpsw ) { + const match = bcrypt.compareSync( body.PASSWORD, user.PASSWORD ); + if( !match ) { + return { + status: 401, + data: { + info: [ 'checkCredentials' ], + model: 'Pagans' + } + }; + } + } + // Mise à jour user pour app LOGIN + user.tribeid = LOGINdom[ body.LOGIN ] + user.TOKEN = jwt.encode( { + expiration: moment() + .add( 1, 'day' ), + UUID: user.UUID + }, config.jwtSecret ); + // on met à jour le header qui authentifie le user connecte + header.xtribe = LOGINdom[ body.LOGIN ] + header.xpaganid = user.UUID; + header.xauth = user.TOKEN; + // On modifie xworkon car au LOGIN on est forcemenet identifiable sur tribeid + // xworkon est utiliser pour travailler sur un environnement client different de celui + // de l'appartenace du user + header.xworkon = LOGINdom[ body.LOGIN ]; + const majuser = Pagans.updateUser( user.UUID, header, { + UUID: user.UUID, + TOKEN: user.TOKEN + } ); + // Enleve info confidentiel + delete user.PASSWORD; + if( user.ACCESSRIGHTS.data[ "Alltribeid" ] ) { + //cas admin on transforme les droits sur tous les tribeid existant + const newaccessrightsdata = {} + jsonfile.readFileSync( `${config.tribes}/tribeids.json` ) + .forEach( cid => { + newaccessrightsdata[ cid ] = user.ACCESSRIGHTS.data[ "Alltribeid" ] + } ) + user.ACCESSRIGHTS.data = newaccessrightsdata; + } + // on recupere le menu de l app qui demande le LOGIN si existe dans user.ACCESSRIGHTS.app[] + // header['X-app'] = tribeid:Projet pour récuperer le menu correspondant + console.assert( config.loglevel == "quiet", "header.xapp", header.xapp ) + console.assert( config.loglevel == "quiet", "user.ACCESSRIGHTS.app[header.xapp]", user.ACCESSRIGHTS.app[ header.xapp ] ); + + return { + status: 200, + data: { + model: "Pagans", + info: [ 'loginSuccess' ], + user: user + } + }; +}; +Pagans.getlinkwithoutpsw = async ( EMAIL, header ) => { + // check le domain d'appartenance de l'eamail dans /tribes/emailsglob.json={email:cleintId} + // on remplace le header.xtribeid + const domforemail = jsonfile.readFileSync( `${config.tribes}/emailsglob.json`, 'utf-8' ); + if( domforemail[ EMAIL ] ) { + header.xtribe = domforemail[ EMAIL ] + } else { + return { status: 404, info: { model: 'Pagans', info: [ 'emailnotfound' ], moreinfo: "email does not exist in /emailsglob.json" } }; + } + // recupere le uuid du user dans /tribes/tribeid/users/searchindex/emails.json + // puis l'ensemble des info des user du domain /uuids.json + // infoforuuid[uuidforemail[EMAIL]] permet de récupérer toutes info du user, droit, etc... + const uuidforemail = jsonfile.readFileSync( `${config.tribes}/${header.xtribe}/users/searchindex/emails.json`, 'utf8' ); + const infoforuuid = jsonfile.readFileSync( `${config.tribes}/${header.xtribe}/users/searchindex/uids.json`, 'utf8' ); + // On recupere le modele d'email appemailinfo qui doit être présent dans clientconf.json + let confdom = jsonfile.readFileSync( `${config.tribes}/${header.xtribe}/clientconf.json`, 'utf8' ); + let checkinfomail = ""; + if( !confdom.appemailinfo ) { + checkinfomail += ' Erreur de clientconfig il manque un objet appemailinfo pour poursuivre'; + } + if( checkinfomail != "" ) { + console.log( `Pb de config pour ${header.xtribe} ${checkinfomail} ` ) + return { + status: 500, + info: { + model: 'Pagans', + info: [ 'objectmissingclientconf' ], + moreinfo: checkinfomail + } + }; + } + let simulelogin; + try { + simulelogin = await Pagans.loginUser( header, { + LOGIN: infoforuuid[ uuidforemail[ EMAIL ] ][ 0 ], + PASSWORD: "" + }, false ); + console.log( 'info simulelogin', simulelogin ) + } catch ( err ) { + return { + status: 501, + info: { + model: 'Pagans', + info: [ 'loginImpossible' ], + moreinfo: "Impossible de se loger avec " + infoforuuid[ uuidforemail[ EMAIL ] ][ 0 ] + } + }; + } + const url = `${config.rootURL}?xauth=${simulelogin.data.TOKEN}&xuuid=${simulelogin.data.UUID}&xtribeid=${simulelogin.data.tribeid}&xworkOn=${header.xworkon}&xlang=${header.xlang}` + //console.log('envoi email avec' + url) + confdom.appemailinfo.msg.destperso = [ {} ]; + confdom.appemailinfo.msg.destperso[ 0 ].email = EMAIL; + confdom.appemailinfo.msg.destperso[ 0 ].subject = "Lien de réinitialisation valable 1h" + confdom.appemailinfo.msg.destperso[ 0 ].titre = "Vous avez oublier votre mot de passe" + confdom.appemailinfo.msg.destperso[ 0 ].texte = ` +

+ Bonjour,
Vous nous avez signalé que vous avez oublié votre mot de passe pour cette email. + Avec le lien suivant vous allez pouvoir utiliser votre interface 1h maximum. + Clicker ICI.
+ Nous vous conseillons de changer votre mot de passe.

+ ` + //console.log('envoi header :', header); + Outputs.sendMailcampain( confdom.appemailinfo.msg, header ); + console.log( confdom.appemailinfo ); + return { + status: 200, + info: { + model: 'Pagans', + info: [ 'emailsentforReinit' ], + moreinfo: 'EMAIL sent with unique link ' + url + } + }; +} +module.exports = Pagans; diff --git a/models/Referentials.js b/models/Referentials.js new file mode 100755 index 0000000..e2a8dbb --- /dev/null +++ b/models/Referentials.js @@ -0,0 +1,416 @@ +const glob = require( 'glob' ); +const path = require( 'path' ); +const fs = require( 'fs-extra' ); +const config = require( '../tribes/townconf.js' ); + +const Referentials = {}; +/* +Manage Referential object data + +each object is compose of a list of fields +each fields have it owns structur and check +those common rules allow to be used to manage: +- forms (creation to collect data) +- data check +- data access rights +common referential data stored in /data/shared/referential/ + +*/ +Referentials.clientconf = ( xworkOn, listkey ) => { + /* + Retourne les info d'un clientconf.json sur une liste de [cle] + */ + let conf = {}; + let dataconf = {}; + //console.log( `${config.tribes}/${xworkOn}/clientconf.json` ) + try { + conf = fs.readJsonSync( `${config.tribes}/${xworkOn}/clientconf.json` ); + // remove information notrelevant for + [ 'emailFrom', 'emailClient', 'emailCc', 'commentkey', 'clezoomprivate', 'stripekeyprivate', 'genericpsw' ].forEach( c => { + delete conf[ c ]; + } ); + listkey.forEach( k => dataconf[ k ] = conf[ k ] ) + //console.log( 'dataconf', dataconf ) + } catch ( err ) { + console.log( 'Attention demande sur clienId inconnu ' + xworkOn ); + } + return { + status: 200, + payload: { + data: dataconf + } + }; +}; +Referentials.clientconfglob = () => ( { + status: 200, + payload: { + data: fs.readJsonSync( `${config.tmp}/clientconfglob.json` ) + } +} ); +Referentials.getref = ( origin, source, ref, xworkOn, xlang ) => { + // If request origin then send back referential with all language in it + // if not origin or json source return by language + let referent = {}; + let src; + if( origin && [ 'object', 'data' ].includes( source ) ) { + src = `${config.tribes}/${xworkOn}/referentials/${source}/${ref}.json` + } else { + src = `${config.tribes}/${xworkOn}/referentials/${source}/${ref}_${xlang}.json`; + } + //console.log( src ) + try { + referent = fs.readJsonSync( src ); + } catch ( err ) { + console.log( `Request ${src} does not exist ` ); + } + return { + status: 200, + payload: { + data: referent + } + }; +}; +Referentials.putref = ( source, name, xworkOn, data ) => { + /* + We get a referential, we have 3 kinds of sources: + * data = [{uuid,DESC:{fr:,en,},DESCLONG:{fr:,en:}, other field}] + only DESC and DESCLONG have a translation + * json = are full complex object in language name_lg.json + * object = [{uuid,DESC:{fr,en},DESCLONG:{fr,en}},tpl,}] + Difference between data and object is that object defines rule to manage an object, and how to create a forms to get data each data is saved in one folder object/uuid.json and have to respect the corresponding object referentials definition. + + For data and object it is possible only to put a file with all language available. + When store this script erase with the new file per _lg + + name for source=json must end by _lg + */ + //console.log( data ) + const pat = /.*_..\.json$/; + const file = `${config.tribes}/${xworkOn}/referentials/${source}/${name}.json` + if( [ 'object', 'data' ].includes( source ) ) { + if( pat.test( name ) ) { + return { status: 404, payload: { model: 'Referentials', info: [ 'nameunconsistent' ], moreinfo: "can not be update with one lang need a full file with language for object or data" } } + } else { + fs.outputJsonSync( file, data ); + return Refernetials.update( xworkOn, source, name ) + } + } else { + if( !pat.test( name ) ) { + return { status: 404, payload: { model: 'Referentials', info: [ 'nameunconsistent' ], moreinfo: "can not be update without a lang _lg.json a referential json" } } + } else { + fs.outputJsonSync( file, data ); + return { status: 200, payload: { model: 'Referentials', info: [ 'successfull' ], moreinfo: "ref json updated " } } + } + }; +}; +Referentials.updatefull = ( tribeid ) => { + let err = ""; + let nbrefupdate = 0; + const pat = /.*_..\.json$/; + [ 'object', 'data' ].forEach( o => { + glob.sync( `${config.tribes}/${tribeid}/referentials/${o}/*.json` ) + .forEach( f => { + if( !pat.test( f ) ) { + const res = Referentials.update( tribeid, o, path.basename( f, '.json' ) ); + if( res.status != 200 ) { + err += `Error on ${o}/${path.basename(f)}` + } else { + nbrefupdate += 1; + } + } + } ) + } ); + if( err != "" ) { + return { status: 500, payload: { info: [ 'Errupdateref' ], model: "Referentials", moreinfo: err } } + } + return { status: 200, payload: { info: [ 'Success' ], model: "Referentials", moreinfo: `Number of object and data ref updated: ${nbrefupdate}` } } +}; + +Referentials.inittribeid = () => { + console.log( "Clientconf list for this server", `${config.tribes}/**/clientconf.json` ); + const TribesGlobalConfig = glob.sync( `${config.tribes}/**/clientconf.json` ) + .map( f => fs.readJsonSync( f ) ); + // store global conf for sharing to other api + fs.outputJsonSync( `${config.tmp}/clientconfglob.json`, TribesGlobalConfig, { + spaces: 2 + } ); + return { status: 200, payload: { moreinfo: TribesGlobalConfig } } +} +Referentials.generetribeids = () => { + const tribeids = []; + fs.readJsonSync( `${config.tmp}/clientconfglob.json` ) + .forEach( c => { + if( !tribeids.includes( c.tribeid ) ) tribeids.push( c.tribeid ); + } ); + fs.outputJsonSync( `${config.tmp}/tribeids.json`, tribeids ); + console.log( `update ${config.tribes}/tribeids` ); + return tribeids; +} +Referentials.genereallowedDOM = () => { + const confglob = fs.readJsonSync( `${config.tmp}/clientconfglob.json` ); + let allDom = []; + confglob.forEach( c => { + c.allowedDOMs.forEach( d => { + if( !allDom.includes( d ) ) allDom = allDom.concat( d ); + } ) + } ); + return allDom; +}; +/* A voir si encore necessaire pour générer un environnement identique + sur un autre server + + // Génére les domaines s'ils n'existe pas dans le repertoire + function genereEnvClient() { + const confglob = fs.readJsonSync( + `${config.sharedData}/clientconfglob.json` + ); + confglob.forEach(function(c) { + config.tribeidsConf[c.tribeid] = c; + if (c.allowedURLs) { + c.allowedURLs.forEach(u => { + if (!config.allowedURLs.includes(u)) { + config.allowedURLs.push(u); + } + }); + } else { + console.log('erreur de fichier config d\'un site pour ', c); + } + // GLOBAL Tribes IDS INDEX + maketribeidsIndex(); + if (!fs.existsSync(`${config.tribes}/${c.tribeid}`)) { + const execSync = require('child_process').execSync; + execSync(`cp -r ${config.tribes}/modele ${config.tribes}/${c.tribeid}`); + } + }); + } + + + + */ +Referentials.update = ( tribeid, source, name ) => { + /* + Replace for each language the referential name for a tribeid + After each update the version number is incremented by 1 in clientconf.json + */ + if( !fs.existsSync( `${config.tribes}/${tribeid}/referentials/${source}/${name}.json` ) ) { + return { status: 500, payload: { info: [ "unknownRef" ], model: "Referentials", moreinfo: `file does not exist ${config.tribes}/${tribeid}/referentials/${source}/${name}.json` } } + }; + + const clientconf = fs.readJsonSync( `${config.tribes}/${tribeid}/clientconf.json` ); + if( !clientconf.langueReferential ) { + return { status: 500, payload: { info: [ "missingConf" ], model: "Referentials", moreinfo: ` ${config.tribes}/${tribeid}/clientconf.json does not contain langueReferential array` } } + } + const ref = fs.readJsonSync( `${config.tribes}/${tribeid}/referentials/${source}/${name}.json` ); + + clientconf.langueReferential.forEach( lg => { + //manage translation + let refnew = []; + + refnew = []; + ref.forEach( d => { + if( d.DESC ) d.DESC = d.DESC[ lg ]; + if( d.DESCLONG ) d.DESCLONG = d.DESCLONG[ lg ]; + if( d.INFO ) d.INFO = d.INFO[ lg ]; + if( d.desc ) d.desc = d.desc[ lg ]; + if( d.desclong ) d.desclong = d.desclong[ lg ]; + if( d.info ) d.info = d.info[ lg ]; + if( d.placeholder ) d.placeholder = d.placeholder[ lg ]; + refnew.push( d ) + } ) + //save new ref in language + //console.log( "New ref", refnew ) + console.log( `Update referentials per lg ${config.tribes}/${tribeid}/referentials/${source}/${name}_${lg}.json` ) + fs.outputJsonSync( `${config.tribes}/${tribeid}/referentials/${source}/${name}_${lg}.json`, refnew, { + spaces: 2 + } ); + } ); + //upgrade version number + if( !clientconf.referentials ) clientconf.referentials = {}; + if( !clientconf.referentials[ source ] ) clientconf.referentials[ source ] = {}; + if( !clientconf.referentials[ source ][ name ] ) clientconf.referentials[ source ][ name ] = { version: 0 }; + clientconf.referentials[ source ][ name ].version += 1; + fs.outputJsonSync( `${config.tribes}/${tribeid}/clientconf.json`, clientconf, 'utf8' ); + return { + status: 200, + payload: { + info: [ 'successUpdate' ], + model: "Referentials", + moreinfo: `${name} updated` + } + } +}; +//console.log( Referentials.update( 'apixtribe', "object", "user" ) ) + +Referentials.genereobjet = ( tribeid, destination, tplmustache, objet, filtre ) => { + /* @TODO + Genere des objets d'agregat + @tribeid = data/tribee/ identifiant client + @destinations = [] of destination + @tplmustache = fichier mustache de mise en page + @objet = nom d'objet contact, companies, items, users + @filtre = fonction a executer + */ +} + +//////// EN DESSOUS DE CETTE LIGNE A SUPPRIMER + +/* +Le principe consistait à partager des referentiels dans shareddataLa gestion est trop compliqué => le principe chaque client duplique un referentiel pour que les app qui s'appuie sur des composants communs puissent fonctionner + +*/ + +/*Referentials.genereClientObjectASUPP = () => { + const confglob = fs.readJsonSync( `${config.tmp}/clientconfglob.json` ); + // Check and update folder and data per lang + // c as tribeid + confglob.forEach( ( c, postribeid ) => { + //check folder are well create + const lstfolder = [ 'actions', 'actions/done', 'actions/todo', 'cards', 'logs', 'orders', 'orders/reservation', 'orders/purchase', 'orders/contact', 'public', 'public/reservation', 'tags', 'tags/stats', 'tags/archives', 'tags/hits', 'tags/imgtg', 'users' ]; + lstfolder.forEach( fol => { + if( !fs.existsSync( `${config.tribes}/${c.tribeid}/${fol}` ) ) { + fs.mkdirSync( `${config.tribes}/${c.tribeid}/${fol}` ); + } + } ) + if( c.referentials && !c.langue ) { console.log( `ERREUR referentials mais pas de langue:[] pour ${c.tribeid}/clientconf.json` ) } + if( c.referentials && c.langue ) { + let majclientconf = false; + // Create and check Object structure + Object.keys( c.referentials.object ) + .forEach( o => { + // if object exist in shared then it merge sharedObject and domain referential object + let objfull = []; + const objshared = `${config.sharedData}/referentials/dataManagement/object/${o}.json`; + if( fs.existsSync( objshared ) ) { + objfull = objfull.concat( fs.readJsonSync( objshared ) ); + } + const objdomain = `${config.tribes}/${c.tribeid}/referentials/dataManagement/object/${o}.json`; + if( fs.existsSync( objdomain ) ) { + objfull = objfull.concat( fs.readJsonSync( objdomain ) ); + } + c.langue.forEach( lg => { + const objfulllg = objfull.map( field => { + if( field.DESC ) field.DESC = field.DESC[ lg ]; + if( field.DESCLONG ) field.DESCLONG = field.DESCLONG[ lg ]; + return field; + } ); + const objectdomlg = `${config.tribes}/${c.tribeid}/referentials/${lg}/object/${o}.json`; + let savedObject = {}; + if( fs.existsSync( objectdomlg ) ) { + savedObject = fs.readJsonSync( objectdomlg ); + } + // TODO Always true change later to update only if needded + if( !fs.existsSync( objectdomlg ) || objfulllg.length !== savedObject.length || 1 == 1 ) { + fs.outputJsonSync( objectdomlg, objfulllg, { + spaces: 2 + } ); + confglob[ postribeid ].referentials.object[ o ].version += 1; + majclientconf = true; + } + } ); + } ); + // datafile + Object.keys( c.referentials.data ) + .forEach( d => { + // if object exist in shared then it merge sharedObject and domain referential object + // console.log(c.tribeid + '--' + d); + let datafull = []; + const datashared = `${ + config.sharedData + }/referentials/dataManagement/data/${d}.json`; + if( fs.existsSync( datashared ) ) { + datafull = datafull.concat( fs.readJsonSync( datashared ) ); + } + const datadomain = `${config.tribes}/${ + c.tribeid + }/referentials/dataManagement/data/${d}.json`; + if( fs.existsSync( datadomain ) ) { + datafull = datafull.concat( fs.readJsonSync( datadomain ) ); + } + /* const defdata = `${config.tribes}/${ + c.tribeid + }/referentials/dataManagement/data/${d}.json`; + */ +// for each Langues => generate fr.obj and compare it with existing file +// if diff then => upgrade version number in clientconf +// console.log(datafull); +// this could be improved by usind d.meta wich is the object that DESCribe this data +/* c.langue.forEach( lg => { + let meta; + if( c.referentials.data[ d ].meta ) { + meta = fs.readJsonSync( `${config.tribes}/${c.tribeid}/referentials/${lg}/object/${ + c.referentials.data[d].meta + }.json` ); + } + let datalg; + const datafulllg = datafull.map( tup => { + datalg = {}; + meta.forEach( ch => { + if( tup[ ch.idfield ] ) { + if( ch.multilangue ) { + datalg[ ch.idfield ] = tup[ ch.idfield ][ lg ]; + } else { + datalg[ ch.idfield ] = tup[ ch.idfield ]; + } + } + } ); + return datalg; + } ); + // lit le fichier correspondant et le compare si différent le sauvegarde + // stocke l'information d'upgrade d ela version + const datadomlg = `${config.tribes}/${ + c.tribeid + }/referentials/${lg}/data/${d}.json`; + let saveddata = {}; + if( fs.existsSync( datadomlg ) ) { + saveddata = fs.readJsonSync( datadomlg ); + } + // Condition to improve + // TODO always change file to improvelater by detecting real change. + if( !fs.existsSync( datadomlg ) || datafulllg.length != saveddata.length || 1 == 1 ) { + fs.outputJsonSync( datadomlg, datafulllg, { + spaces: 2 + } ); + confglob[ postribeid ].referentials.data[ d ].version += 1; + majclientconf = true; + } + } ); + } ); + // json file that have to start with lg {lg:'':{json }} + Object.keys( c.referentials.json ) + .forEach( j => { + // if object exist in shared then it merge sharedObject and domain referential object + // console.log(c.tribeid + '--' + d); + let jsonfull = []; + const jsondomain = `${config.tribes}/${c.tribeid}/referentials/dataManagement/json/${j}.json`; + if( fs.existsSync( jsondomain ) ) { + jsonfull = fs.readJsonSync( jsondomain ); + } + c.langue.forEach( lg => { + const jsondomlg = `${config.tribes}/${ + c.tribeid + }/referentials/${lg}/json/${j}.json`; + // console.log('jsondomlg', jsondomlg); + let datalg = jsonfull; + if( jsonfull[ lg ] ) { + datalg = jsonfull[ lg ]; + } + fs.outputJsonSync( jsondomlg, datalg, { + spaces: 2 + } ); + } ); + } ); + // update clientconf domain with updated version + if( majclientconf ) { + fs.outputJsonSync( `${config.tribes}/${c.tribeid}/clientconf.json`, c, { + spaces: 2 + } ); + } + } + } ); + // update global conf + fs.outputJsonSync( `${config.tmp}/clientconfglob.json`, confglob, { + spaces: 2 + } ); +};*/ + +module.exports = Referentials; diff --git a/models/Referentialssave.js b/models/Referentialssave.js new file mode 100755 index 0000000..fd60fe1 --- /dev/null +++ b/models/Referentialssave.js @@ -0,0 +1,220 @@ +const glob = require( 'glob' ); +const path = require( 'path' ); +const fs = require( 'fs-extra' ); +// Check if package is installed or not to pickup the right config file +const config = require( '../tribes/townconf.js' ); + +const Referentials = {}; +/* +Manage Referential object data + +each object is compose of a list of fields +each fields have it owns structur and check +those common rules allow to be used to manage: +- forms (creation to collect data) +- data check +- data access rights +common referential data stored in /data/shared/referential/ + +*/ +Referentials.clientconf = ( xworkOn, listkey ) => { + /* + Retourne les info d'un clientconf.json sur une liste de [cle] + */ + let conf = {}; + let dataconf = {}; + console.log( `${config.tribes}/${xworkOn}/clientconf.json` ) + try { + conf = fs.readJsonSync( `${config.tribes}/${xworkOn}/clientconf.json` ); + // remove information notrelevant for + [ 'emailFrom', 'emailClient', 'emailCc', 'commentkey', 'clezoomprivate', 'stripekeyprivate', 'genericpsw' ].forEach( c => { + delete conf[ c ]; + } ); + listkey.forEach( k => dataconf[ k ] = conf[ k ] ) + console.log( 'dataconf', dataconf ) + } catch ( err ) { + console.log( 'Attention demande sur clienId inconnu ' + xworkOn ); + } + return { + status: 200, + payload: { + data: dataconf + } + }; +}; +Referentials.clientconfglob = () => ( { + status: 200, + payload: { + data: fs.readJsonSync( `${config.tmp}/clientconfglob.json` ) + } +} ); + +Referentials.inittribeid = () => { + console.log( "Clientconf list for this server", `${config.tribes}/**/clientconf.json` ); + const TribesGlobalConfig = glob.sync( `${config.tribes}/**/clientconf.json` ) + .map( f => fs.readJsonSync( f ) ); + // store global conf for sharing to other api + fs.outputJsonSync( `${config.tmp}/clientconfglob.json`, TribesGlobalConfig, { + spaces: 2 + } ); + return { status: 200, payload: { moreinfo: TribesGlobalConfig } } +} + + +Referentials.generetribeids = () => { + const tribeids = []; + fs.readJsonSync( `${config.tmp}/clientconfglob.json` ) + .forEach( c => { + if( !tribeids.includes( c.tribeid ) ) tribeids.push( c.tribeid ); + } ); + fs.outputJsonSync( `${config.tmp}/tribeids.json`, tribeids ); + console.log( `update ${config.tribes}/tribeids` ); + return tribeids; +} +Referentials.genereallowedDOM = () => { + const confglob = fs.readJsonSync( `${config.tmp}/clientconfglob.json` ); + let allDom = []; + confglob.forEach( c => { + c.allowedDOMs.forEach( d => { + if( !allDom.includes( d ) ) allDom = allDom.concat( d ); + } ) + } ); + return allDom; +}; + + +Referentials.getref = ( source, ref, xworkOn, xlang, singlelang = true ) => { + let referent = {}; + let src = `${config.tribes}/${xworkOn}/referentials/${xlang}/${source}/${ref}.json`; + if( !singlelang ) { + //request full referential to manage + src = `${config.tribes}/${xworkOn}/referentials/dataManagement/${source}/${ref}.json` + } + console.log( src ) + try { + referent = fs.readJsonSync( src ); + } catch ( err ) { + console.log( `Attention demande de referentiel inexistant pour ${src} ` ); + } + return { + status: 200, + payload: { + data: referent + } + }; +}; +Referentials.putref = ( source, name, xworkOn, data ) => { + /* + We get a referential, we have 3 kinds of sources: + * data = [{uuid,desc:{fr:,en,},desclong:{fr:,en:}, other field}] + only desc and desclong have a translation + * json = {"fr":{},"en":{}, ...} are full complex object in language + * object = [{uuid,desc:{fr,en},desclong:{fr,en}},tpl,}] + Difference between data and object is that object defines rule to manage an object, and how to create a forms to get data each data is saved in one folder object/uuid.json and have to respect the corresponding object referentials definition. + + */ + console.log( data ) + // Create a backup of the day hour if exist + const file = `${config.tribes}/${xworkOn}/referentials/dataManagement/${source}/${name}.json` + + if( fs.existsSync( file ) ) { + //backup change done per hour + const origin = fs.readJsonSync( file, 'utf-8' ) + fs.outputJsonSync( `${config.tribes}/${xworkOn}/referentials/dataManagementBackup/${source}/${name}${moment().format('YYYYMMDDHHmm')}.json`, origin, { spaces: 2 } ) + } else { + console.log( `Referential ${name}.json does not exist this created it` ) + } + console.log( 'ref backup before update', name ); + fs.outputJsonSync( file, data, { spaces: 2 } ); + // update/create new referential and new version + return Referentials.update( xworkOn, source, name ); +}; +Referentials.updatefull = ( tribeid ) => { + // source json are only per lg so no full update for json + let err = ""; + [ 'object', 'data' ].forEach( o => { + glob.sync( `${config.tribes}/${tribeid}/referentials/dataManagement/${o}/*.json` ) + .forEach( f => { + if( finipaspar_lg ) { + const res = Referentials.update( tribeid, o, path.basename( f, '.json' ) ); + if( res.status != 200 ) { + err += `Error on ${o}/${path.basename(f)}` + } + } + } ) + } ); + if( err != "" ) { + return { status: 500, payload: { info: [ 'Errupdateref' ], model: "Referentials", moreinfo: err } } + } + return { status: 200, payload: { info: [ 'Success' ], model: "Referentials" } } +}; + +Referentials.update = ( tribeid, source, name ) => { + /* + Replace for each language the referential name for a tribeid + After each update the version number is incremented by 1 in clientconf.json + */ + if( !fs.existsSync( `${config.tribes}/${tribeid}/referentials/${source}/${name}.json` ) ) { + return { status: 500, payload: { info: [ "unknownRef" ], model: "Referentials", moreinfo: `file does not exist ${config.tribes}/${tribeid}/referentials/${source}/${name}.json` } } + }; + + const clientconf = fs.readJsonSync( `${config.tribes}/${tribeid}/clientconf.json` ); + if( !clientconf.langueReferential ) { + return { status: 500, payload: { info: [ "missingConf" ], model: "Referentials", moreinfo: ` ${config.tribes}/${tribeid}/clientconf.json does not contain langueReferential array` } } + } + const ref = fs.readJsonSync( `${config.tribes}/${tribeid}/referentials/${source}/${name}.json` ); + + clientconf.langueReferential.forEach( lg => { + /*if( !fs.existsSync( `${config.tribes}/${tribeid}/referentials/${lg}` ) ) { + [ '', '/data', '/json', '/object' ].forEach( p => { + fs.mkdirSync( `${config.tribes}/${tribeid}/referentials/${lg}${p}` ); + } ) + } + */ + //manage translation + let refnew = []; + if( source == 'json' ) { + refnew = ref[ lg ] + } else { + refnew = []; + ref.forEach( d => { + if( d.desc ) d.desc = d.desc[ lg ]; + if( d.desclong ) d.desclong = d.desclong[ lg ]; + if( d.info ) d.info = d.info[ lg ]; + if( d.placeholder ) d.placeholder = d.placeholder[ lg ]; + refnew.push( d ) + } ) + } + //save new ref in language + console.log( "testtttt", refnew ) + console.log( `${config.tribes}/${tribeid}/referentials/${source}/${name}_${lg}.json` ) + fs.outputJsonSync( `${config.tribes}/${tribeid}/referentials/${source}/${name}_${lg}.json`, refnew, { + spaces: 2 + } ); + } ); + //upgrade version number + if( !clientconf.referentials[ source ][ name ] ) clientconf.referentials[ source ][ name ] = { version: 0 }; + clientconf.referentials[ source ][ name ].version += 1; + return { + status: 200, + payload: { + info: [ 'successUpdate' ], + model: "Referentials", + moreinfo: `${name} updated` + } + } +}; +//console.log( Referentials.update( 'apixtribe', "object", "user" ) ) + +Referentials.genereobjet = ( tribeid, destination, tplmustache, objet, filtre ) => { + /* @TODO + Genere des objets d'agregat + @tribeid = data/tribee/ identifiant client + @destinations = [] of destination + @tplmustache = fichier mustache de mise en page + @objet = nom d'objet contact, companies, items, users + @filtre = fonction a executer + */ +} + +module.exports = Referentials; diff --git a/models/Setup.js b/models/Setup.js new file mode 100755 index 0000000..137d6a7 --- /dev/null +++ b/models/Setup.js @@ -0,0 +1,149 @@ +const fs = require( 'fs-extra' ); +const path = require( 'path' ); +const dnsSync = require( 'dns-sync' ); +const Mustache = require( 'mustache' ); + +const Setup = {}; + +if( !fs.existsSync( '/etc/nginx/nginx.conf' ) ) { + console.log( '\x1b[31m Check documentation, nginx have to be installed on this server first, no /etc/nginx/nginx.conf available' ); + process.exit(); +} +if( !fs.existsSync( '../config.js' ) ) { + console.log( `\x1b[42m####################################\nWellcome into apixtribe, this is a first install.\nWe need to make this server accessible from internet subdomain.domain to current IP. This setup will create your unique tribeid, with an admin login user to let you connect to the parameter interface.\nCheck README's project to learn more. more.\n#####################################\x1b[0m` ); + const confdata = fs.readJsonSync( path.normalize( `${__dirname}/../setup/configsetup.json` ) ); + console.log( 'Current setup conf from :\n' + path.normalize( `${__dirname}/../setup/configsetup.json` + '\nChange with relevant setup data and rerun yarn setup' ) ); + console.log( confdata ) + const readline = require( 'readline' ); + const rl = readline.createInterface( { + input: process.stdin, + output: process.stdout + } ); + + rl.question( 'This is the data from setup/configsetup.json used, is it correct to use as first install (Yes/no)?', function ( rep1 ) { + let quest = `This is a production install, please check that ${confdata.subdomain}.${confdata.domain} IP is well redirect to tour server`; + if( rep1 !== "Yes" ) process.exit( 0 ); + if( confdata.domain == 'local.fr' ) { + quest = `This is a development installation, please add in your /etc/hosts "127.0.0.1 ${confdata.subdomain}.${confdata.domain} " `; + } + rl.question( quest + '\nAre you sure to set this? (Yes/no)', function ( rep2 ) { + if( rep2 == "Yes" ) { + const check = Setup.checkdata( confdata ); + if( check == "" ) { + Setup.config( confdata ); + } else { + console.log( check ); + } + } else { + console.log( 'Nothing done please, check setup/configsetup.json and answer twice Yes' ) + } + rl.close(); + } ); + } ); + rl.on( 'close', function () { + console.log( '\n Setup process ended' ); + process.exit( 0 ); + } ); +} else { + console.log( 'Carefull you have already a config.js that is running. If you want to change remove config.js file and run again yarn setup' ); +} + +Setup.checkdata = conf => { + let rep = ""; + if( ![ 'dev', 'prod' ].includes( conf.mode ) ) { + rep += "mode have to be 'dev' or 'prod' currently it's " + conf.mode + "\n"; + } + conf.language.forEach( l => { + if( ![ "fr", "en", "it", "de", "sp" ].includes( l ) ) { + rep += l + " Only fr,en,it,de,sp are available \n"; + } + } ); + if( !fs.existsSync( `/home/${conf.linuxuser}` ) ) { + rep += `/home/${conf.linuxuser} does not exist, user has to be create with a /home on this server\n`; + } + // avant eslint if( !( /^[a-z\s\-]+$/.test( conf.druidid ) ) ) { + if( !( /^[a-z\s-]+$/.test( conf.druidid ) ) ) { + rep += `${conf.druidid} have to contain only a-z characters `; + } + // add a check later have to be unique if not in dev + if( !( /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&.])[A-Za-z\d$@$!%*?&.{}:|\s]{8,}/.test( conf.genericpsw ) ) ) { + rep += "Give a generic pasword for all your tribeid's user,they will change it min 8 char special char upper lower case and number" + } + if( conf.jwtsecret.length < 32 ) { + rep += "Your jwtsecretkey must have at least 32 characters" + } + if( conf.mode != 'dev' && !dnsSync.resolve( `${conf.subdomain}.${conf.domain}` ) ) { + rep += `\nresolving ${conf.subdomain}.${conf.domain} will not responding valid IP, please setup domain redirection IP before runing this script` + } + return rep +}; +Setup.config = ( confdata ) => { + // Init this instance with a .config.js + Setup.configjs( confdata ); + // Create tribeid space + a user admin + webspace withe apixtribe webapp install + Setup.druidid( confdata ); +}; +Setup.configjs = ( confdata ) => { + // Set /config.js + let confapixtribe = fs.readFileSync( './setup/config.mustache', 'utf-8' ); + fs.writeFileSync( './config.js', Mustache.render( confapixtribe, confdata ), 'utf-8' ); + if( fs.existsSync( './config.js' ) ) { + console.log( 'config.js successfully created.' ); + } else { + console.log( "config.js not created, check what's wrong in tpl:", confapixtribe ); + console.log( "for data :", confdata ); + process.exit(); + } +}; +Setup.druidid = ( confdata ) => { + // create a tribeid with a user that will admin this instance into /tribes/tribeid /users + const config = require( '../config.js' ); + // Need to do it on setup this is also done again in models/Tribes.js + console.log( `${config.tribes}/${confdata.druidid}` ) + fs.ensureDirSync( `${config.tribes}/${confdata.druidid}` ); + [ 'users', 'www', 'referentials', 'nationchains' ].forEach( r => { + fs.copySync( `${config.mainDir}/setup/tribes/apixtribe/${r}`, `${config.tribes}/${confdata.druidid}/${r}` ); + } ) + /* const confcli = JSON.parse( Mustache.render( fs.readFileSync( `${config.mainDir}/setup/tribes/apixtribe/clientconf.mustache`, 'utf8' ), confdata ) ); + fs.outputJsonSync( `${config.tribes}/${confdata.druidid}/clientconf.json`, confcli ); + // Create a new tribeid + admin user for this tribeid + // with access to {druidid}:webapp as admin + */ + const Tribes = require( '../models/Tribes.js' ); + const access = { app: {}, data: {} } + access.app[ `${confdata.druidid}:webapp` ] = "admin"; + access.data[ confdata.druidid ] = { "users": "CRUDO", "referentials": "CRUDO", "www": "CRUDO" }; + const createclient = Tribes.create( { + tribeid: confdata.druidid, + genericpsw: confdata.genericpsw, + lanquageReferential: confdata.language, + useradmin: { + LOGIN: confdata.login, + xlang: confdata.language[ 0 ], + ACCESSRIGHTS: access + } + } ); + if( createclient.status == 200 ) { + console.log( `Your tribeid domain was created with login : ${confdata.login} and password: ${confdata.genericpsw}, change it after the 1st login on https://${confdata.subdomain}.${confdata.domain}` ); + // Create nginx conf for a first install + const confnginx = fs.readFileSync( './setup/nginx/nginx.conf.mustache', 'utf8' ); + fs.outputFileSync( '/etc/nginx/nginx.conf', Mustache.render( confnginx, confdata ), 'utf-8' ); + // Create a spacedev for webapp of apixtribe + // that will be accesible in prod from https://subdomain.domain/ and in dev http://webapp.local.fr + const addspaceweb = Tribes.addspaceweb( { + setup: true, + dnsname: [ `${confdata.subdomain}.${confdata.domain}` ], + mode: confdata.mode, + tribeid: confdata.druidid, + website: 'webapp', + pageindex: "app_index_fr.html" + } ); + if( addspaceweb.status == 200 ) { + console.log( `WELL DONE run yarn dev to test then yarn startpm2 ` ) + } + } else { + console.log( 'Issue ', createclient ) + } +} + +module.exports = Setup; diff --git a/models/Tags.js b/models/Tags.js new file mode 100755 index 0000000..ab64b3d --- /dev/null +++ b/models/Tags.js @@ -0,0 +1,229 @@ +const fs = require( 'fs' ); +const formidable = require( 'formidable' ); +const jsonfile = require( 'jsonfile' ); +const path = require( 'path' ); +const glob = require( 'glob' ); +const mustache = require( 'mustache' ); +const moment = require( 'moment' ); +// Check if package is installed or not to pickup the right config file +const config = require( '../tribes/townconf.js' ); + + +const Tags = {}; +/* +Keyword definition: + +id: b64 encoded field that can be : email , uuid +tribeid: apiamaildigit client Id, (a folder /tribes/tribeid have to exist) +email: identifiant of a person +uuid: identifiant o + contact database +operationId: code name of an operation +messageId: code name of an templatesource have to exist in /datashared/templatesource/generic/messageId + +*/ +/* +Manage tag data collection +Popup survey manager +*/ +Tags.info = ( data, req ) => { + //console.log('headers:', req.headers) + /*console.log('hostname', req.hostname) + console.log('req.ip', req.ip) + console.log('req.ips', req.ips) + console.log('req key', Object.keys(req)) + */ + //console.log('req.rawHeaders', req.body) + data.useragent = `${req.headers['user-agent']}__${req.headers['accept-language']}__${req.headers['accept-encoding']}__${req.headers['connection']}`; + data.ips = req.ips; + data.ip = req.ip; + data.proxyip = req.connection.remoteAddress; + data.cookie = "" + Object.keys( req.headers ) + .forEach( k => { + if( ![ 'user-agent', 'accept-language', 'accept-encoding', 'connection' ].includes( k ) ) { + data.cookie += `${k}__${req.headers['cookie']}|` + } + } ) + //data.cookie = `${req.headers['cookie']}__${req.headers['upgrade-insecure-requests']}__${req.headers['if-modified-since']}__${req.headers['if-no-match']}__${req.headers['cache-control']}`; + return data +} +Tags.getfile = ( filename, req ) => { + const infotg = filename.split( '__' ); + if( infotg.length < 3 && !fs.existsSync( `${config.tribes}/${infotg[1]}` ) ) { + return { + status: 400, + payload: { info: [ 'fileUnknown' ], model: 'UploadFiles' } + } + } + if( infotg[ 0 ] == "imgtg" ) { + jsonfile.writeFile( `${config.tribes}/${infotg[1]}/tags/imgtg/${Date.now()}.json`, Tags.info( { filename: filename, messageId: infotg[ 2 ], operationId: infotg[ 3 ], identifiant: infotg[ 4 ] }, req ), function ( err ) { + if( err ) { + console.log( `Erreur de sauvegarde de tag:${filename}` ) + } + } ); + return { + status: 200, + payload: { moreinfo: "Declenche tag", filename: `${config.mainDir}/public/imgtg.png` } + } + } + return { status: 404, payload: {} } +} +Tags.savehits = ( req ) => { + if( !fs.existsSync( `${config.tribes}/${req.params.tribeid}` ) ) { + console.log( `Erreur d'envoi de tag sur ${req.params.tribeid} pour ${req.params.r}` ); + return false; + } else { + const info = JSON.parse( JSON.stringify( req.body ) ); + jsonfile.writeFile( `${config.tribes}/${req.params.tribeid}/tags/hits/${Date.now()}.json`, Tags.info( info, req ), function ( err ) { + if( err ) { + console.log( `Erreur de sauvegarde de tag pour ${req.params.tribeid} check si /tags/hits et /tags/imgtg exist bien ` ) + } + } ); + } + return true; +} +Tags.dataloadstat = ( tribeid ) => { + /* + @TODO à appeler via une route pour agregation de tag + @TODO ajouter la suppression des fichiers hits traités qd le prog aura fait ses preuves en prod + @TODO corriger la prod pour que l'ip passe + + Si on recharge plusieurs fois un hits (on ne le comptabilise pas si même r et même timestamps) + + Manage tag info to agregate by user and by statistique + stats/data.json = {r:{ + info:{useragent:"",ip:[]}, + data:[ [timestamps, tit, cookie] ] + } + } + stats/graph.json = {"graphYears": {AAAA:#visites,"years":[AAAA,AAAA]}, + "graphMonths": {AAAA:{"Jan":#visites,..},"monthsLabels":["Jan",..],"years":[AAAA,]}, + "graphDaysOfWeek":{"labels":["Sun","Mon",...],"Sun":#visites}, + "graphHoursOfDay":{"labels":["OOh","01h",...],"00h":#visites} + } + Pour tester des evolutions ou un client en dev (recuperer son repertoire de prod /tags ) + ajouter Tags.dataloadstat('yes'); + NODE_ENV=dev node ./models/Tags.js + */ + const agrege = { + data: {}, + graph: { + visites: { + graphYears: { years: [] }, + graphMonths: { + years: [], + monthsLabels: [] + }, + graphMonths: { + years: [], + monthsLabels: [] + }, + graphDayOfWeek: { labels: [] }, + graphHourOfDay: { labels: [] } + }, + visitors: { + graphMonths: { + years: [], + monthsLabels: [] + } + } + } + }; + try { + agrege.data = jsonfile.readfileSync( `${config.tribes}/${tribeid}/tags/stats/data.json`, "utf-8" ); + agrege.graph = jsonfile.readfileSync( `${config.tribes}/${tribeid}/tags/stats/graph.json`, "utf-8" ); + } catch ( err ) { + console.log( "ATTENTION tag reinitialisé en data.json et graph.json, s'il s'agit de 1ere connexion pas de pb. Le risque est de perdre les tag historiques" ) + //return { status: 503, payload: { info: ['Errconfig'], model: 'Tags', moreinfo: `Il manque un ${config.tribes}/${tribeid}/tags/stats/data.json ou stats/graph.json` } } + } + glob.sync( `${config.tribes}/${tribeid}/tags/hits/*` ) + .forEach( f => { + const hit = jsonfile.readFileSync( f ); + const ts = parseInt( path.basename( f ) + .split( ".json" )[ 0 ] ); + //console.log(moment(ts).format('DD-MM-YYYY h:mm:ss')); + const tsm = moment( ts ) + const year = tsm.format( 'YYYY' ); + const month = tsm.format( 'MMM' ); + const dayow = tsm.format( 'ddd' ); + const hourod = tsm.format( 'HH' ) + "h"; + let newvisitor = false; + let alreadydone = false; + //console.log(hit.r, ts) + // Agrege data pour # visiteur vs # de visiteur + if( agrege.data[ hit.r ] ) { + if( !agrege.data[ hit.r ].data.some( el => el[ 0 ] == ts ) ) { + //evite de charger plusieurs fois le même + agrege.data[ hit.r ].data.push( [ ts, hit.tit, hit.cookie ] ) + } else { + alreadydone = true; + } + } else { + newvisitor = true; + agrege.data[ hit.r ] = { + info: { useragent: hit.useragent, ip: [ hit.ip ] }, + data: [ + [ ts, hit.tit, hit.cookie ] + ] + } + } + if( !alreadydone ) { + if( newvisitor ) { + //traite Month + if( !agrege.graph.visitors.graphMonths[ year ] ) { + agrege.graph.visitors.graphMonths[ year ] = {} + agrege.graph.visitors.graphMonths.years.push( year ) + } + if( agrege.graph.visitors.graphMonths[ year ][ month ] ) { + agrege.graph.visitors.graphMonths[ year ][ month ] += 1 + } else { + agrege.graph.visitors.graphMonths[ year ][ month ] = 1 + agrege.graph.visitors.graphMonths.monthsLabels.push( month ) + } + } + //traite graphe Year #visite + if( agrege.graph.visites.graphYears[ year ] ) { + agrege.graph.visites.graphYears[ year ] += 1 + } else { + agrege.graph.visites.graphYears[ year ] = 1 + agrege.graph.visites.graphYears.years.push( year ) + agrege.graph.visites.graphMonths[ year ] = {} + agrege.graph.visites.graphMonths.years.push( year ) + } + //traite graphe Month + if( agrege.graph.visites.graphMonths[ year ][ month ] ) { + agrege.graph.visites.graphMonths[ year ][ month ] += 1 + } else { + agrege.graph.visites.graphMonths[ year ][ month ] = 1 + agrege.graph.visites.graphMonths.monthsLabels.push( month ) + } + //traite graphe Days of week + if( agrege.graph.visites.graphDayOfWeek[ dayow ] ) { + agrege.graph.visites.graphDayOfWeek[ dayow ] += 1 + } else { + agrege.graph.visites.graphDayOfWeek[ dayow ] = 1 + agrege.graph.visites.graphDayOfWeek.labels.push( dayow ) + } + //traite graphe Hour of day + if( agrege.graph.visites.graphHourOfDay[ hourod ] ) { + agrege.graph.visites.graphHourOfDay[ hourod ] += 1 + } else { + agrege.graph.visites.graphHourOfDay[ hourod ] = 1 + agrege.graph.visites.graphHourOfDay.labels.push( hourod ) + } + } + } ) + jsonfile.writeFileSync( `${config.tribes}/${tribeid}/tags/stats/data.json`, agrege.data, 'utf-8' ); + jsonfile.writeFileSync( `${config.tribes}/${tribeid}/tags/stats/graph.json`, agrege.graph, 'utf-8' ); + return { status: 200, payload: { info: [ 'Statsupdated' ], model: 'Tags' } } +} +//console.log(Tags.dataloadstat('yes')); +/*const ar = [ + [1, 1], + [1, 2] +] +console.log(ar.some(el => el[0] == 1 && el[1] == 1)) +console.log(ar.some(el => el == [1, 3])) +*/ +module.exports = Tags; diff --git a/models/Tribes.js b/models/Tribes.js new file mode 100755 index 0000000..fc517e8 --- /dev/null +++ b/models/Tribes.js @@ -0,0 +1,353 @@ +const bcrypt = require( 'bcrypt' ); +const fs = require( 'fs-extra' ); +const path = require( 'path' ); +const glob = require( 'glob' ); +const Mustache = require( 'mustache' ); +const execSync = require( 'child_process' ) + .execSync; +const dnsSync = require( 'dns-sync' ); +const jwt = require( 'jwt-simple' ); +const moment = require( 'moment' ); +const UUID = require( 'uuid' ); +const Outputs = require( './Outputs.js' ); +const Pagans = require( './Pagans.js' ); +const config = require( '../tribes/townconf.js' ); + +const checkdata = require( `${config.tribes}/${config.mayorId}/www/cdn/public/js/checkdata` ); + +/* +tribeid manager + +/tribes/tribeid +Manage a tribeid space +* create +* update by managing option and contract +* delete a tribeid +* check accountability and + +*/ +const Tribes = {}; +Tribes.init = () => { + console.group( 'init Tribes' ); + let tribeids = []; + let routes = glob.sync( './routes/*.js' ) + .map( f => { + return { url: `/${path.basename(f,'.js')}`, route: f } + } ); + let DOMs = []; + let appname = {}; + TribesGlobalConfig = glob.sync( `${config.tribes}/**/clientconf.json` ) + .map( f => { + const conf = fs.readJSONSync( f ); + // check if plugins exist and add it in .plugins of each tribeid conf + conf.plugins = glob.sync( `${config.tribes}/${conf.tribeid}/plugins/**/package.json` ) + .map( p => { + const pack = fs.readJsonSync( p, 'utf8' ); + routes.push( { url: `/${pack.name}`, route: `${config.tribes}/${conf.tribeid}/plugins/${pack.name}/route.js` } ); + return pack; + } ); + //Add here any other info to get a global view and init + //... + tribeids.push( conf.tribeid ); + DOMs = [ ...new Set( [ ...DOMs, ...conf.allowedDOMs ] ) ]; + if( conf.website ) appname[ conf.tribeid ] = Object.keys( conf.website ) + return conf; + } ); + // store global conf fofs.existsSync( `${config.tmp}/clientconfglob.json` )r sharing to other api + fs.outputJsonSync( `${config.tmp}/clientconfglob.json`, TribesGlobalConfig, { + spaces: 2 + } ); + return { tribeids, routes, DOMs, appname } +} +Tribes.create = ( data ) => { + /* data = clientconf.json + { + "tribeid": "apixtribe", + "genericpsw": "Trze3aze!", + "website": { + "presentation":"https://www.apixtribe.org", + "webapp": "https://webapp.apixtribe.org" + }, + "allowedDOMs": ["local.fr", "localhost:9002", "ndda.fr", "apixtribe.org"], + "clientname": "apixtribe", + "clientlogo": "", + "geoloc": [], + "useradmin": {PUBKEY:"",EMAIL:"",LOGIN:"adminapixtribe",UUID:"adminapixtribe"}, + "smtp": { + "emailFrom": "support@apixtribe.org", + "emailcc": [], + "service": "gmail", + "auth": { + "user": "antonin.ha@gmail.com", + "pass": "Ha06110" + } + }, + "accepted-language": "fr,en", + "langueReferential": ["fr"] + } + What about: + "tribeid": same than the folder where all the client's file are stored + "genericpsw": a generic password for new user need upper lowercase number ans special char + "dnsname": a domain name belonging to the client + "subdns": "www", a sub domain subdns.dnsname give a public web access to + "website": { keywebsite:url}, give access to config.tribes/tribeid/www/keywebsite/index.html, + "allowedDOMs": ["local.fr", "localhost:9002", "nnda.fr"], //for CORS, @TODO generate from prévious URL this allow this apixtribe instance to be accessible + "clientname": Name of the organisation if any, + "clientlogo": logo of the organisation if any, + "geoloc": [], if any + "useradmin": { this is the 1st user create automaticaly to make gui available for the 1st user + "PUBKEY":public key to be authentify without an email, + "EMAIL":user email, we need at least one of authentification set up after the user can use both or only one + "LOGIN": login to use for access admintribeid, + "UUID": unique id normaly UUID but a uuid admintribeid is the same person in any apixtribe instance so we use it by convention. + "xlang": lang used by this user + }, + "smtp": { smtp used to send email by nodemailer lib basic example with a google account + "emailFrom": "support@xx.fr", + "emailcc": [], + "service": "gmail", + "auth": { + "user": "antonin.ha@gmail.com", + "pass": "Ha06110" + } + }, + "accepted-language": "fr,en", list of accepted-language in terme of http request. + "langueReferential": ["fr"], list of the text that have to be translate in referentials + } + */ + //update tmp/confglog.json + const dataclient = Tribes.init(); + //return in prod all instance apxinfo={tribeids:[],logins:[]} + // in dev return only local + //check tribeid name is unique + console.log( 'liste des tribeid', dataclient.tribeids ) + if( dataclient.tribeids.includes( data.tribeid ) ) { + return { status: 403, payload: { model: "client", info: [ 'tribeidalreadyexist' ] } } + } + //loginsglob = {login:tribeid} + let loginsglob = {}; + if( fs.existsSync( `${config.tmp}/loginsglob.json`, 'utf-8' ) ) { + loginsglob = fs.readJsonSync( `${config.tmp}/loginsglob.json`, 'utf-8' ); + } + const logins = Object.keys( loginsglob ); + if( logins.includes( data.useradmin.login ) ) { + return { status: 403, payload: { model: "client", info: [ 'loginalreadyexist' ] } } + } + fs.ensureDirSync( `${config.tribes}/${data.tribeid}` ); + [ 'users', 'www', 'referentials', 'nationchains' ].forEach( r => { + fs.copySync( `${config.mainDir}/setup/tribes/apixtribe/${r}`, `${config.tribes}/${data.tribeid}/${r}` ); + } ) + fs.outputJsonSync( `${config.tribes}/${data.tribeid}/clientconf.json`, data ); + const confcli = JSON.parse( Mustache.render( fs.readFileSync( `${config.mainDir}/setup/tribes/apixtribe/clientconf.mustache`, 'utf8' ), data ) ); + fs.outputJsonSync( `${config.tribes}/${data.tribeid}/clientconf.json`, confcli ); + + return Pagans.createUser( { + xpaganid: "setup", + xworkon: data.tribeid, + xlang: data.useradmin.xlang + }, data.useradmin ); +}; +Tribes.archive = ( tribeid ) => { + //A faire zip un repertoire tribeid dans + // remove tribeid de data ou devdata + try { + fs.moveSync( `${config.tribes}/${tribeid}`, `${config.archivefolder}/${tribeid}` ); + //update apixtribeenv + Tribes.init(); + return { status: 200, payload: { info: [ 'deletetribeidsuccessfull' ], models: 'Tribes', moreinfo: "TODO see in Tribes.archive" } } + } catch ( err ) { + console.log( "Erreur d'archivage", err ) + return { status: 403, payload: { info: [ 'archiveerror' ], models: 'Tribes', moreinfo: err } } + } +} +////////////// Manage file for Tribes +Tribes.checkaccessfolder = ( folder, typeaccessrequested, useraccessrights, useruuid ) => { + // check folder right + + + +} + +Tribes.checkaccessfiles = ( listfile, typeaccessrequested, useraccessrights, useruuid ) => { + // @listfile to check accessright on file or folder + // @typeaccessrequested on files R read or download, U for pdate, D for delete , O for owned a Owner has all rights RUD on its files + // @useraccessright from its account /userd/uuid.json + // @useruuid public uuid user + // return {'ok':[file auhtorized],'ko':[files not authorized]} + + const checkauthlistfile = { 'ok': [], 'ko': [] } + let structf = [] + let inforep = { file: {}, dir: {} } + let done; + for( const f of listfile ) { + done = false; + if( !fs.existsSync( `${config.tribes}/${f}` ) ) { + done = true; + checkauthlistfile.ko.push( f ) + console.log( `${f} file does not exist` ) + } else { + structf = f.split( '/' ); + } + //on ckeck tribeid existe / tribeid/object/ + if( !done && + useraccessrights.data[ structf[ 0 ] ] && + useraccessrights.data[ structf[ 0 ] ][ structf[ 1 ] ] && + useraccessrights.data[ structf[ 0 ] ][ structf[ 1 ] ].includes( typeaccessrequested ) ) { + done = true; + checkauthlistfile.ok.push( f ); + } else { + // check if in folder we have a.info.json .file[f].shared{useruuid:'CRUDO'} + console.log( 'structf', structf ) + if( fs.existsSync( `${config.tribes}/${structf.slice(0,-1).join('/')}/.info.json` ) ) { + inforep = fs.readJsonSync( `${config.tribes}/${structf.slice(0,-1).join('/')}/.info.json`, 'utf8' ) + } + console.log( `no accessrights for ${f} for ${useruuid} ` ) + } + if( !done && inforep.file[ f ] && inforep.file[ f ] && inforep.file[ f ].shared && inforep.file[ f ].shared[ useruuid ] && inforep.file[ f ].shared[ useruuid ].includes( typeaccessrequested ) ) { + done = true; + checkauthlistfile.ok.push( f ) + } + // If no authorization then ko + if( !done ) { + checkauthlistfile.ko.push( f ) + } + } // end loop for + //console.log( 'checkauthlistfile', checkauthlistfile ) + return checkauthlistfile; +} + +Tribes.dirls = ( tribeid, dir ) => { + /* + Return list of file into tribeid/dir + */ + let comment = { src: `${tribeid}/${dir}`, file: {}, dir: {} }; + if( fs.existsSync( `${config.tribes}/${tribeid}/${dir}/.info.json` ) ) { + comment = fs.readJsonSync( `${config.tribes}/${tribeid}/${dir}/.info.json`, 'utf-8' ); + } + const listfile = [] + const listdir = [] + glob.sync( `${config.tribes}/${tribeid}/${dir}/*` ) + .forEach( f => { + //console.log( f ) + const stats = fs.statSync( f ); + // console.log( stats ) + if( stats.isFile() ) { + listfile.push( path.basename( f ) ) + if( !comment.file[ path.basename( f ) ] ) { + comment.file[ path.basename( f ) ] = { tags: [], info: "", thumbb64: "" }; + } + comment.file[ path.basename( f ) ].mtime = stats.mtime; + comment.file[ path.basename( f ) ].ctime = stats.ctime; + comment.file[ path.basename( f ) ].size = stats.size; + } + if( stats.isDirectory() ) { + listdir.push( path.basename( f ) ) + if( !comment.dir[ path.basename( f ) ] ) { + comment.dir[ path.basename( f ) ] = { tags: [], info: "", thumbb64: "" } + } + comment.dir[ path.basename( f ) ].nbfile = glob.sync( `${f}/*.*` ) + .length; + comment.dir[ path.basename( f ) ].mtime = stats.mtime; + comment.dir[ path.basename( f ) ].ctime = stats.mtime; + console.log( 'comment.dir', comment.dir ) + } + } ); + // on remove les file or dir that was deleted + Object.keys( comment.file ) + .forEach( f => { + if( !listfile.includes( f ) ) delete comment.file[ f ] + } ) + Object.keys( comment.dir ) + .forEach( d => { + if( !listdir.includes( d ) ) delete comment.dir[ d ] + } ) + //console.log( comment ) + fs.outputJson( `${config.tribes}/${tribeid}/${dir}/.info.json`, comment, 'utf-8' ); + return { status: 200, payload: { info: [ 'succestogetls' ], models: 'Tribes', moreinfo: comment } } +}; +Tribes.addspaceweb = ( data ) => { + /* + To create a public spaceweb accessible from https://dnsname/pageindex + + input: + {dnsname:["archilinea.fr","www.archilinea.fr"], 1st is tha main dns other are just servername redirection + tribeid:"archilinea", from req.session.header.xworkon + website:"presentation", + pageindex:"app_index_fr.html" + mode:dev(local no ssl) | prod(IP + ssl) +} + output: + nginx conf and ssl to serve each https://dnsname to /{tribeid}/www/app/{website} + + + Carefull this action is executed with root and restart nginx + apixtribe to work + */ + data.configdomain = config.tribes; + data.porthttp = config.porthttp; + console.assert( config.loglevel == "quiet", 'data to create spaceweb:', data ); + // create spaceweb app for tribeid/www/app/website/pageindexname.html + if( !fs.existsSync( `${config.tribes}/${data.tribeid}/www/app/${data.website}` ) ) { + fs.outputFileSync( `${config.tribes}/${data.tribeid}/www/app/${data.website}/${data.pageindex}`, `

Hello ${data.tribeid} ${data.website} onto ${data.dnsname.join(',')}`, 'utf-8' ) + } + //create logs folder + fs.ensureDirSync( `${config.tribes}/${data.tribeid}/logs/nginx` ); + // add nginx http config + const confnginx = fs.readFileSync( 'setup/nginx/modelwebsite.conf.mustache', 'utf-8' ); + fs.outputFileSync( `/etc/nginx/conf.d/${data.dnsname[0]}.conf`, Mustache.render( confnginx, data ), 'utf-8' ); + if( data.mode == "dev" ) { + //add in /etc/hosts + let hosts = fs.readFileSync( '/etc/hosts', 'utf8' ); + let chg = false; + data.dnsname.forEach( d => { + if( !hosts.includes( `127.0.0.1 ${d}` ) ) { + hosts += `\n127.0.0.1 ${d}`; + chg = true; + } + if( chg ) { + fs.outputFileSync( '/etc/hosts', hosts, 'utf8' ) + } + } ); + }; + //Ckeck dns respond + data.dnsname.forEach( d => { + if( !dnsSync.resolve( `${d}` ) ) { + rep += `\nresolving ${d} will not responding valid IP, please setup domain redirection IP before runing this script` + } + } ) + //update clienconf.json + const clientconf = fs.readJsonSync( `${config.tribes}/${data.tribeid}/clientconf.json` ); + clientconf.website[ data.website ] = data.dnsname[ 0 ]; + //merge allowedDOMs in unique concat + clientconf.allowedDOMs = [ ...new Set( ...clientconf.allowedDOMs, ...data.dnsname ) ]; + fs.outputJsonSync( `${config.tribes}/${data.tribeid}/clientconf.json`, clientconf, 'utf-8' ); + if( !data.setup ) { + // in setup apixtribe is not running and it will be start manually at the 1st run + // in other case need to plan a restart for CORS + setTimeout( Tribes.restartapixtribe, 300000, data.clienId ); + } + const nginxrestart = execSync( `sudo systemctl restart nginx` ) + .toString(); + console.log( 'Restart nginx', nginxrestart ) + if( data.mode == "prod" ) { + // get ssl certificate ATTENTION il faut ajouter -d devant chaque domain qui redirige vers l'espace web. + const certbot = execSync( `sudo certbot --nginx -d ${data.dnsname.join(' -d ')}` ) + .toString(); + console.log( 'certbot is running A CHECKER POUR UNE VRAIE PROD ????', certbot ) + } + //sh execution to update change requested + return { + status: 200, + payload: { + model: "Tribes", + info: [ 'webspacecreated' ], + moreinfo: "Space web well created" + } + }; +} +Tribes.restartapixtribe = ( tribeid ) => { + console.log( 'A restarting was requested 5mn ago from a new spacedev for ' + tribeid ) + execSync( 'yarn restartpm2' ); +} + + +module.exports = Tribes; diff --git a/models/UploadFiles.js b/models/UploadFiles.js new file mode 100755 index 0000000..c814527 --- /dev/null +++ b/models/UploadFiles.js @@ -0,0 +1,152 @@ +const fs = require( 'fs-extra' ); +const path = require( 'path' ); +const formidable = require( 'formidable' ); +const jsonfile = require( 'jsonfile' ); +const mustache = require( 'mustache' ); +const config = require( '../tribes/townconf.js' ); + +/* +model A SUPPRIMER !!!!!!!!!!!!!!!!!!!!!! +les functions d'upload de file et de droits d'accès doivent être gérer dans Tribes + +*/ +const UploadFiles = {}; +UploadFiles.get = function ( filename, header ) { + // check file exist + const file = `${config.tribes}/${header.xworkon}/${filename}`; + // console.log('fichier demande ', file); + if( !fs.existsSync( file ) ) { + // console.log('le fichier demande n existe pas ', file); + return { + status: 404, + payload: { info: [ 'fileUnknown' ], model: 'UploadFiles' } + }; + } else { + console.log( 'envoie le fichier ', file ); + return { + status: 200, + payload: { info: [ 'fileknown' ], model: 'UploadFiles', file: file } + }; + } +}; +UploadFiles.addjson = function ( data, header ) { + /* + Le header = {X-WorkOn:"",destinationfile:"", filename:""} + Le body = {jsonp:{},callback:function to launch after download,'code':'mot cle pour verifier que le fichier est à garder'} + */ + // console.log(req.body.jsonp); + try { + jsonfile.writeFileSync( header.destinationfile + '/' + header.filename, data.jsonp ); + if( data.callback ) { + const execCB = require( `${config.mainDir}/models/tribeid/${ + header.xworkon + }` ); + execCB[ data.callback ](); + } + return { + status: 200, + payload: { + info: [ 'wellUpload' ], + model: 'UploadFiles', + render: { + destination: header.destinationfile, + filename: header.filename + } + } + }; + } catch ( err ) { + console.log( 'Impossible de sauvegarder le fichier, A COMPRENDRE', err ); + return { + status: 503, + payload: { info: [ 'savingError' ], model: 'UploadFiles' } + }; + } +}; +UploadFiles.add = function ( req, header ) { + const form = new formidable.IncomingForm(); + console.log( 'req.headers', req.headers ); + console.log( 'req.params', req.params ); + console.log( 'req.query', req.query ); + console.log( 'req.body', req.body ); + let destinationfile = `${config.tribes}/${header.xworkon}/${ + header.destinationfile + }`; + form.parse( req, function ( err, fields, files ) { + console.log( 'files', files.file.path ); + console.log( 'fields', fields ); + const oldpath = files.file.path; + destinationfile += '/' + files.file.name; + console.log( 'oldpath', oldpath ); + console.log( 'destinationfile', destinationfile ); + fs.copyFile( oldpath, destinationfile, function ( err ) { + if( err ) { + console.log( err ); + return { + status: 500, + payload: { info: [ 'savingError' ], model: 'UploadFiles' } + }; + } else { + console.log( 'passe' ); + fs.unlink( oldpath ); + return { + status: 200, + payload: { + info: [ 'wellUpload' ], + model: 'UploadFiles', + render: { + destination: destinationfile + } + } + }; + } + } ); + } ); +}; +UploadFiles.updateEvent = function ( domainId, eventId, event ) { + // checkAndCreateNeededDirectories(domainId); + const eventsFile = `${config.tribes}/${domainId}/actions/events/events.json`; + if( !fs.existsSync( eventsFile ) ) { + jsonfile.writeFileSync( eventsFile, {} ); + return { status: 404, payload: 'You have not any events.' }; + } + const events = jsonfile.readFileSync( eventsFile ); + if( !events.hasOwnProperty( eventId ) ) { + return { + status: 404, + payload: 'The event you are trying to update does not exist.' + }; + } + events[ eventId ] = { + eventName: event.eventName, + eventDate: event.eventDate, + eventDescription: event.eventDescription + }; + jsonfile.writeFileSync( eventsFile, events, { spaces: 2 } ); + return { + status: 200, + payload: events + }; +}; +UploadFiles.deleteEvent = function ( domainId, eventId ) { + // checkAndCreateNeededDirectories(domainId); + const eventsFile = `${config.tribes}/${domainId}/actions/events/events.json`; + if( !fs.existsSync( eventsFile ) ) { + jsonfile.writeFileSync( eventsFile, {} ); + return { status: 404, payload: 'You have not any events.' }; + } + const events = jsonfile.readFileSync( eventsFile ); + if( events.hasOwnProperty( eventId ) ) { + delete events[ eventId ]; + jsonfile.writeFileSync( eventsFile, events, { spaces: 2 } ); + return { + status: 200, + payload: events + }; + } else { + return { + status: 404, + payload: 'The event you are trying to delete does not exist.' + }; + } +}; +module.exports = UploadFiles; diff --git a/nationchains/antsnation.html b/nationchains/antsnation.html new file mode 100644 index 0000000..bd77bae --- /dev/null +++ b/nationchains/antsnation.html @@ -0,0 +1,13 @@ + + + + + ANTS Nation + + + + +

Info sur la nation des ANTS leur ville pour les rejoindre

+

+ + \ No newline at end of file diff --git a/nationchains/apixtribe.html b/nationchains/apixtribe.html new file mode 100644 index 0000000..cfcdf06 --- /dev/null +++ b/nationchains/apixtribe.html @@ -0,0 +1,72 @@ + + + + + apiXtribe pourquoi comment + + + + +

Info sur les nations (avec leur contrat accessible) et sur la town ainsi que les statistiques des tribes et de la town

+

+ **An answer to our crazy world:** +Few peoples want to control value create by mass people, by using technology (gafam, gov, ...). +This DAO aim to serve any tribe that wants to free themself by creating their own organisation/rules into blockchain (cipher to keep data privacy, crypto to dev trust behind anonymity, web and open source to decentralize and build an anti-fragile system until electricity is their). + +Our occidental society (globalization) wants us more and more money to control us (they say to protect us from ourself). Fine for, cozy chicken that accept to be eat when their master decides it. But not, **for free human that wants to apply consensual rules between them without any man in the middle**. + +To make us under control, our masters print money and force us to breath it. We have no choice; they control institutions, they can stole our properties or our freedom, they drive the single thought. Forget strke and demonstration, to rebalance and create counter-powers, an alternative is to earn the minimum of their money to stay under their radar and keep our ressources (time, energy) to learn, create and share value for our tribes of friends, family, or people that share common view... +A DAO, by design (the blockchain) cannot be control by a central power, because it is a common good, each actor has a benefit and is free to apply fair rules.
+apiXtribes aims to allow any group of people to define rules to apply for their exchange of values. + +With our master's money to create value you have to respect their rules (a register company, list of standards, list of taxes, ...) in exchange you benefit of institutions like protections (police with the legitimate violence), justice (law), school, medical, ... If you are a good boy then master give you back cash grant. + +If you agree with the master's world, and happy to let institution decide for you, this is fine (apiXtribe is not for you). But if you consider that diversity is more resilient than standard and **you want to have choices then this project is for you.** Who knows the futur ;-) apiXtribe could be use to run the democratie (demos kratos: by the people for the people). + +## Why money is the sinews of war + +Our masters killed social ties by implementing the KPI (Key Performance Indicator) to quantify the value of each of us base on their rules. Their money is magic, they use as KPI of an individual value as well as the tools to drive our life. In occident, who can survive today without money in his pocket or in master's bank? + +By **disconnecting value of money with gold or other "physical limit"** the money just value what they decide.
+apiXtribe use a crypto (that looks like a money but is not a money) to value each rule application to create a proof of work and at least a proof of stake that any human involve has an interest to protect it. + +Then rules (**contracts**) can be set by anyone based on **an algo like if/then** between 2 humans. When the condition is trig then something is register in the blockchain. + +``` +# Example of rule between A & B to exchange an object description O that B own : +# B create a rule: send Object O against X with process (A is free to act or not depending of B reputation into the community where the rule is set): + if ("A pay/send X to B") then + "B send O to A" + if "A do not receive O after n days" or "O does not fit the object description" then + "A send a bad feedback on B that is written in blockchain" + if "B get a bad feedback" then + "B have to pay back 50% of X to the commuinity master" + if ("A do not receive O after n days" and "B does not give back X to A" and "B does not pay after n days the 50% of X") or "B have an average of bad feedback with at least 5 transactions" then + "B is baned of the community" +``` + +**apiXtribe blockchain will register this standard "contracts" and "reputation" of those who respects or not contracts. This cannot be change by any one and any one can read it.**
+A and B are just unique identificator (anonymous or not), to prove a human own A or B, apiXtribe use cryptograpĥic PGP based on public/private key. apiXtribe needs a network topology to be strong enough to avoid central control. This is why apiXtribe recommand rewarding rules to actor that provide electricity, machine, network access. Virtual world exist because physical one exist. + +Until you stay **in crypto world, you just exchange data so no tax** (no master's rules). You can sale a service against money until you respect master/country's rule of this money (company that collect value tax, register turnover, ...). Then you can deliver crypto to your customer to consume your's or other's services when they want. If you exchange token against gov money then you have to respect your gov's laws (some country's law ask you to pay tax onto added value). So be aware of what you are doing some gov can kill you or put you in jail to exchange their money or data. This Xtrib coin is not for speculation is for social link without man in the middle that stole you. +

+

+ **As a non tech,** you can invest and request to get your own nation or town (become a mayor) or tribe (become a druid). As non tech you'll need the help of a dev that will help you to modelise and setup Contracts. Any way you can also simply join any tribe as pagan and sales data/product and exchange it again Xtrib coin of a nation. +For non tech, if you have a project please request it to [support@apixtribe.org](mailto:support@apixtribe.org) + +**As tech**: + +**- As sysadmin** you can install a town, for yourself or for a "non tech" and earn Xtrib in exchange
+**- As back-end and front-end dev** you can dev web service (node.js express static web based on pwa) that you can sale to a druid or a mayor, or become yourself a druid and host a town to sale usage against Xtribe.
+**- As a former** you can create tuto or training to explain how to install an apiXtribe node, how to dev quickly an app with a setup. This is agnostic about the front-end pwa framework, react, vue, angular, .. . For the back-end is suitable for node.js dev but you can use any linux command to produce something to deliver accross apiXtribe.
+**- As a newbie** you can join this open source project to learn how to dev as a part of the team and to increase your portfolio of node.js/linux project. + +We strongly believe in the cypher punk philosophy french :[cypher punk manifesto](https://dev.ndda.fr/cypherpunkmanifestofrench.html) english: [cypher punk manifesto](https://dev.ndda.fr/cypherpunkmanifestoenglish.html). + +As tech, if this sound to you please join us by register in [sign-in gitea](https://gitea.ndda.fr/user/sign_up) and we'll come back to you. + + +To exchange with the community on discord: [https://discord.gg/SQ8YAqJgZV](https://discord.gg/SQ8YAqJgZV) +

+ + \ No newline at end of file diff --git a/nationchains/socialworld/contracts/checkdata.js b/nationchains/socialworld/contracts/checkdata.js new file mode 100755 index 0000000..e9822d4 --- /dev/null +++ b/nationchains/socialworld/contracts/checkdata.js @@ -0,0 +1,185 @@ +/* +This module have to be independant of any external package +it is shared between back and front and is usefull +to apply common check in front before sending it in back +can be include in project with + +or with const checkdata = require('../public/js/checkdata.js') + +*/ + +// --## + +const checkdata = {}; +// each checkdata.test. return true or false +checkdata.test = {}; + +checkdata.test.emailadress = ( ctx, email ) => { + const regExp = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return regExp.test( email ); +}; +/* + * @emaillist = "email1,email2, email3" + * it check if each eamil separate by , are correct + */ +checkdata.test.emailadresslist = ( ctx, emaillist ) => { + //console.log(emaillist.split(',')) + if( emaillist.length > 0 ) { + const emails = emaillist.split( ',' ); + for( var i in emails ) { + //console.log(emails[i]) + if( !checkdata.test.emailadress( "", emails[ i ].trim() ) ) { + return false + } + } + }; + return true; +}; + +checkdata.test.password = ( ctx, pwd ) => { + const regExp = new RegExp( + /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&.])[A-Za-z\d$@$!%*?&.{}:|\s]{8,}/ + ); + return regExp.test( pwd ); +}; +checkdata.test.required = ( ctx, val ) => + ( val != null && val != 'undefined' && val.length > 0 ) || ( !!val && val.constructor === Array && val.length > 0 ) || ( !!val && val.constructor === Object && Object.keys( val ) + .length > 0 ); + +checkdata.test.isNumber = ( ctx, n ) => typeof n === 'number'; +checkdata.test.isInt = ( ctx, n ) => n != '' && !isNaN( n ) && Math.round( n ) == n; +checkdata.test.isFloat = ( ctx, n ) => n != '' && !isNaN( n ) && Math.round( n ) != n; +checkdata.test.unique = ( ctx, val ) => { + if( ctx.list[ ctx.currentfield ] ) { + return !ctx.list[ ctx.currentfield ].includes( val ); + } else { + console.log( 'ERR no list for field:' + ctx.currentfield ); + return false; + } +}; +checkdata.test.isDateDay = ( ctx, dateDay ) => true; +/* checkdata.test.filterInvalidInArray = (array, validate) => + array ? array.filter(el => !validate(el)) : true; +// return true when every elements is valid +*/ + +checkdata.test.postalCode = ( ctx, postalCode ) => { + if( postalCode.length == 0 ) return true; + const regExp = new RegExp( /(^\d{5}$)|(^\d{5}-\d{4}$)/ ); + return regExp.test( postalCode ); +}; +/** + * PHONE + */ +checkdata.test.phoneNumber = ( ctx, phoneNumber ) => { + if( phoneNumber.length == 0 ) return true; + phoneNumber = phoneNumber.trim() + .replace( /[- .]/g, '' ) + //french number + const regExpfr = new RegExp( /^0[1-9][0-9]{9}$/ ); + const regExpInternational = new RegExp( /^\+*(\d{3})*[0-9,\-]{8,}/ ); + return regExpfr.test( phoneNumber ) || regExpInternational.test( phoneNumber ); +}; +/* + * @phonelist = "phone1,phone2,phone3" + * it check if each phone separate by , are correct + */ +checkdata.test.phoneNumberlist = ( ctx, phonelist ) => { + //console.log(emaillist.split(',')) + if( phonelist.length > 0 ) { + const phones = phonelist.split( ',' ); + for( var i in phones ) { + //console.log(emails[i]) + if( !checkdata.test.phoneNumber( "", phones[ i ].trim() ) ) { + return false + } + } + }; + return true; +}; + +// checkdata.normalize take a correct data then reformat it to harmonise it +checkdata.normalize = {}; +checkdata.normalize.phoneNumber = ( ctx, phone ) => { + phone = phone.trim() + .replace( /[- .]/g, '' ); + if( checkdata.test.phoneNumber( '', phone ) && phone.length == 10 && phone[ 0 ] == "0" ) { + phone = '+33 ' + phone.substring( 1 ); + } + return phone; +} +checkdata.normalize.upperCase = ( ctx, txt ) => txt.toUpperCase(); +checkdata.normalize.lowerCase = ( ctx, txt ) => txt.toLowerCase(); +// fixe 10 position et complete par des 0 devant +checkdata.normalize.zfill10 = ( ctx, num ) => { + let s = num + ''; + while( s.length < 10 ) s = '0' + s; + return s; +}; +/*let tt = "+33 1 02.03 04 05"; +console.log(checkdata.test.phoneNumber('', tt)) +console.log(checkdata.normalize.phoneNumber('', tt)) +*/ +checkdata.evaluate = ( contexte, referential, data ) => { + /* + * contexte object {} with full info for evaluation + * file referential path to get object to apply + * data related to object + - return {validefor =[keyword of error] if empty no error, + clean data eventually reformated + updateDatabase} + */ + console.log( 'contexte', contexte ); + console.log( 'referentiel', referential ); + console.log( 'data', data ); + const invalidefor = []; + const objectdef = {}; + const listfield = referential.map( ch => { + objectdef[ ch.idfield ] = ch; + return ch.idfield; + } ); + + Object.keys( data ) + .forEach( field => { + if( !listfield.includes( field ) ) { + // some data can be inside an object with no control at all + // they are used for process only + // i leave it in case it will become a non sens + // invalidefor.push('ERRFIELD unknown of referentials ' + field); + } else { + if( objectdef[ field ].check ) { + // check data with rule list in check + objectdef[ field ].check.forEach( ctrl => { + console.log( 'ctrl', ctrl ); + contexte.currentfield = field; + if( !checkdata.test[ ctrl ] ) { + invalidefor.push( 'ERR check function does not exist :' + ctrl + '___' + field ) + } else { + if( !checkdata.test[ ctrl ]( contexte, data[ field ] ) ) + invalidefor.push( 'ERR' + ctrl + '___' + field ); + } + } ); + } + + if( objectdef[ field ].nouserupdate ) { + // check if user can modify this information + console.log( + 'evaluation :' + field + ' -- ' + objectdef[ field ].nouserupdate, + eval( objectdef[ field ].nouserupdate ) + ); + const evalright = eval( objectdef[ field ].nouserupdate ); + objectdef[ field ].nouserupdate = evalright; + } + } + } ); + console.log( { + invalidefor, + data + } ); + return { + invalidefor, + data + }; +}; + +if( typeof module !== 'undefined' ) module.exports = checkdata; diff --git a/nationchains/socialworld/contracts/toolsbox.js b/nationchains/socialworld/contracts/toolsbox.js new file mode 100755 index 0000000..97f9597 --- /dev/null +++ b/nationchains/socialworld/contracts/toolsbox.js @@ -0,0 +1,604 @@ +/* eslint-disable no-useless-escape */ +const fs = require( 'fs' ); +const path = require( 'path' ); +const bcrypt = require( 'bcrypt' ); +const moment = require( 'moment' ); +const config = require( '../config' ); +const utils = {}; + +console.log( "Check in /utils/index.js to find usefull function for your dev.\n Feel free to send suggestion, code to maintainer of apixtribe project (see /package.json to get email).\n We'll add to the roadmap to add it." ); + +/** + * EMAIL + */ +/* const validateEmail = email => { + const regExp = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; + return regExp.test(email); +}; + +const validatePassword = pwd => { + const regExp = new RegExp( + /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&.])[A-Za-z\d$@$!%*?&.{}:|\s]{8,}/ + ); + return regExp.test(pwd); +}; + +const filterInvalidInArray = (array, validate) => + array ? array.filter(el => !validate(el)) : undefined; // return undefined when every elements is valid + +/** + * POSTAL CODE + */ +/* +const validatePostalCode = postalCode => + /(^\d{5}$)|(^\d{5}-\d{4}$)/.test(postalCode); + +/** + * PHONE + */ +/* const validatePhoneNumber = phoneNumber => + /((^0[1-9]|\+[0-9]{3})([-. ]?[0-9]{2}){4}$)/.test(phoneNumber); + +const correctPhoneNumber = phone => + phone[0] === '0' ? '+33' + phone.substr(1) : phone; + +const checkData = (appProfil, referential, data) => { + // @TODO get a referentiel per object then check data validity and allowed access + // need to add referentiel manager + const invalidefor = []; + let updateDatabase = false; + Object.keys(data).forEach(field => { + switch (field) { + case 'token': + updateDatabase = true; + break; + case 'email': + if (!validateEmail(data.email)) { + invalidefor.push('ERREMAIL:' + field); + } else { + updateDatabase = true; + } + break; + case 'password': + if (!validatePassword(data.password)) { + invalidefor.push('ERRPWD:' + field); + } else { + data.password = bcrypt.hash(data.password, config.saltRounds); + updateDatabase = true; + } + break; + } + }); + return { invalidefor, data, updateDatabase }; +}; +*/ +//Permet d'attendre en milliseconde +// s'utilise avec async ()=>{ +// await sleep(2000) +//} +utils.sleep = ( ms ) => { + return new Promise( resolve => setTimeout( resolve, ms ) ); +} +utils.generemdp = ( nbpos ) => { + const chaine = "ABCDEFGHIJKLMNPQRSTUVWZY123456789"; + let mdp = ""; + for( var i = 0; i < nbpos; i++ ) { + var pos = Math.floor( Math.random() * chaine.length ); + mdp += chaine.substring( pos, pos + 1 ); + } + return mdp; +} +utils.generecompteur = ( filecpt, typeincrement ) => { + let file = `${filecpt}/${typeincrement}.json`; + let prefix = ""; + if( typeincrement = "ANNEESEMAINE" ) { + file = `${filecpt}/${typeincrement}${moment().format('YYYY')}${moment().format('WW')}.json` + prefix = `${moment().format('YYYY')}${moment().format('WW')}` + } + let num = 1; + try { + num = parseInt( fs.readFileSync( file, 'utf8' ) ) + 1; + } catch ( err ) { + console.log( "Nouveau compteur incrementale ", file ) + } + fs.writeFileSync( file, num, 'utf8' ); + return prefix + num +} +/** + * CSV + */ +utils.json2csv = ( jsondata, options, callback ) => { + // uniquement json = [{niv1:val,niv1:[liste of val]}] + // console.log('_________________________'); + // console.log(jsondata) + // console.log('_________________________'); + if( jsondata.length == 0 ) { + return callback( "Empty json", null ); + } + if( !options.retln ) options.retln = '\n'; + if( !options.sep ) options.sep = ';'; + if( !options.arraysplitsep ) options.arraysplitsep = ","; + if( !options.replacespecialcarJson2Csv ) { + options.replacespecialcarJson2Csv = [] + } else { + if( typeof options.replacespecialcarJson2Csv == "string" ) { + //permet de passer des regex en string + options.replacespecialcarJson2Csv = eval( options.replacespecialcarJson2Csv ); + } + }; + let etat = ""; + let csv = ''; + let entete = ''; + let prem = true; + for( const j in jsondata ) { + // console.log(jsondata[j]) + for( const c in options.champs ) { + if( prem ) { + entete += options.champs[ c ] + options.sep; + } + if( jsondata[ j ][ options.champs[ c ] ] ) { + if( options.array.indexOf( options.champs[ c ] ) > -1 ) { + csv += jsondata[ j ][ options.champs[ c ] ].join( options.arraysplitsep ) + options.sep; + } else { + let currentValue = ""; + if( jsondata[ j ][ options.champs[ c ] ] ) currentValue += jsondata[ j ][ options.champs[ c ] ]; + options.replacespecialcarJson2Csv.forEach( re => { + //console.log(currentValue) + currentValue = currentValue.replace( re[ 1 ], re[ 0 ] ) + } ) + csv += currentValue + options.sep; + } + } else { + csv += options.sep; + } + } + csv = csv.substring( 0, csv.length - 1 ) + options.retln; + if( prem ) { + prem = false; + entete = entete.substring( 0, entete.length - 1 ) + options.retln; + // console.log(entete) + } + } + // return entete + csv; + if( etat == "" ) { + return callback( null, entete + csv ); + } else { + return callback( etat, null ); + } +}; +/** + * Get headers from first line of CSV + * @param {array} lines array of string which contains each csv lines + * @return {array} string array of headers + */ +utils.getHeaders = ( lines, sep ) => lines[ 0 ].split( sep ) + .map( i => i.replace( /"/g, '' ) ); +/** + * [csv2json description] + * @param {object} csv object of csv file that has been read + * @param {object} options object containing csv options, headers, ... + {retln:'code de retour de ligne \n ou \n\r', + sep:'code to split cells', + champs:[ch1,ch2,...] catch only those field, + array:[ch1, ] can have more than one field champs with same name then data are push into an array } + * @param {Function} callback callback function + * @return {callback} - return an error if error, else return json + it convert a csv file into a json = [{field:value}] + +Usage example: +fiche.csv2article = (err, fiche) => { + if (!err) { + console.log(fiche) + } +} +utils.csv2json(fs.readFileSync('./devdata/tribee/aubergenville/infoexterne/localbusiness.csv', 'utf-8'), { + retln: "\n", + sep: ";", + champs: ["NOM", "OBJET", "ADRESSE_PRO", "CP_PRO", "VILLE_PRO", "ZONE", "PHONE_PRO", "HORAIRESDESC", "HORAIREDATA", "URL", "FACEBOOK", "INSTA", "EMAIL_PRO", "IMG", "TAG"], + array: ["TAG", "PHONE_PRO", "EMAIL_PRO"] +}, fiche.csv2article) + + */ +utils.replacecarbtweendblquote = ( csv, car, carremplacant ) => { + /* + return csv text with any car betwenn 2 " by CARSEPARATOR + */ + let newcsv = ""; + let txtencours = ""; + let flagouvert = false + const sepreg = new RegExp( `${car}`, 'gmi' ) + for( let j = 0; j < csv.length; j++ ) { + //if((csv[j] == "\"" && csv[j + 1] && csv[j + 1] != "\"") || (csv[j] == "\"" && csv[j - 1] && csv[j - 1] != "\"") || (csv[j] == "\"" && csv[j - 1] && csv[j - 2] && csv[j - 1] != "\"" && csv[j - 2] != "\"")) { + if( csv[ j ] == "\"" ) { + if( flagouvert ) { + // on cherche à ferme une chaine de texte + if( csv[ j + 1 ] == "\"" ) { + //on a "" consecutif qu'on remplace par "" et on fait j+1 + txtencours += "\"\"" + j++ + } else { + // on a bien une fermeture + flagouvert = false + newcsv += txtencours.replace( sepreg, carremplacant ) + txtencours = "\"" + } + } else { + // on ouvre une chaine + flagouvert = true + //on met le contenu précédent ds newcsv + newcsv += txtencours + txtencours = "\"" + } + //} else if((csv[j] !== "\n") && (csv[j + 1] && csv[j] + csv[j + 1] !== "\n\r")) { + } else if( csv[ j ] !== "\n" ) { + txtencours += csv[ j ] + // } else if((csv[j] == "\n") || (csv[j + 1] && csv[j] + csv[j + 1] == "\n\r")) { + } else if( csv[ j ] == "\n" ) { + if( !flagouvert ) txtencours += "\n" + } + } + return newcsv + txtencours +} +utils.analysestring = ( string ) => { + let buftxt = "" + let bufcode = "" + let i = 0 + let avecRL = false + for( let p = 0; p < string.length; p++ ) { + if( string[ p ].charCodeAt() == 10 ) { + buftxt += "[RL]" + avecRL = true + } else { + buftxt += string[ p ] + } + bufcode += "-" + string[ p ].charCodeAt(); + if( i == 20 ) { + if( avecRL ) { + console.log( `${buftxt} - ${bufcode}` ) + } else { + console.log( `${buftxt} ---- ${bufcode}` ) + } + i = 0; + buftxt = "" + bufcode = "" + avecRL = false + } + i++; + } +} + +const txtstring = `32932,BK_F2F_B_COM_10x1H-09,"My Communication Workshop ""Session N°9 - 1H""","

 

+ + + + + + +
+

Learner who needs to develop their ability to communicate effectively at work, both in writing and speaking

+
",,english,2,0,,2,0,classroom,"0000-00-00 00:00:00","0000-00-00 00:00:00",0000-00-00,0000-00-00,https://www.yesnyoulearning.com/lms/index.php?r=player&course_id=32932,1101,,"BUSINESS KEYS",0, +32933,BK_F2F_B_COM_10x1H-10,"My Communication Workshop Session N°10 - 1H","

 

+ + + + + + +
+

Learner who needs to develop their ability to communicate effectively at work, both in writing and speaking

+
",,english,2,0,,2,0,classroom,"0000-00-00 00:00:00","0000-00-00 00:00:00",0000-00-00,0000-00-00,https://www.yesnyoulearning.com/lms/index.php?r=player&course_id=32933,1101,,"BUSINESS KEYS",0, +32934,BK_F2F_B_JOB_10x1H-01,"My Job Search Workshop Session N°1 - 1H","

PACK JOB SEARCH

",,english,2,0,,2,0,classroom,,,0000-00-00,0000-00-00,https://www.yesnyoulearning.com/lms/index.php?r=player&course_id=32934,1108,,,0, +32935,BK_F2F_B_JOB_10x1H-02,"My Job Search Workshop Session N°2 - 1H","

PACK JOB SEARCH

",,english,2,0,,2,0,classroom,,,0000-00-00,0000-00-00,https://www.yesnyoulearning.com/lms/index.php?r=player&course_id=32935,1108,,,0,` +//utils.analysestring(txtstring) +//console.log(utils.replacecarbtweendblquote(txtstring, ",", 'CARSEPARATOR') +// .split("\n")[0].split(",")) +utils.csv2json = ( csv, options, callback ) => { + // EN CAS DE PB AVEC UN FICHIER EXCEL RECALCITRANT + // l'ouvrir dans calc linux et sauvegarder csv utf8, ; , " enregistrer le contenu de la cellule comme affiché + console.log( '\n--------------- CSV2JSON ---------------\n' ); + // Default CSV options + if( !options.retln ) options.retln = '\n'; + if( csv.indexOf( '\n\r' ) > -1 ) options.retln = '\n\r'; + if( !options.sep ) options.sep = ';'; + //gestion d un separateur dans une chaine de texte + //const regseptext = new RegExp(`${options.sep}(?!(?:[^"]*"[^"]*")*[^"]*$)`, 'gm'); + //csv = csv.replace(regseptext, "CARACSEPAR"); + // csv = utils.replacecarbtweendblquote(csv, options.retln, "RETLIGNE") + csv = utils.replacecarbtweendblquote( csv, options.sep, "CARSEPARATOR" ) + if( !options.replacespecialcarCsv2Json ) { + options.replacespecialcarCsv2Json = [] + } else { + if( typeof options.replacespecialcarCsv2Json == "string" ) { + //permet de passer des regex en string + options.replacespecialcarCsv2Json = eval( options.replacespecialcarCsv2Json ); + } + }; + const result = []; + const lines = csv.split( options.retln ); + const headers = utils.getHeaders( lines, options.sep ); + let unknownHeaders = ''; + //console.log('headers', headers) + //console.log('options.champs', options.champs) + headers.forEach( header => { + // Si un header n'est pas présent dans la liste des champs prédéfinis + // on l'ajoute aux champs inconnus + if( options.champs.indexOf( header ) === -1 ) { + unknownHeaders += `${header}, `; + } + } ); + if( unknownHeaders !== '' ) { + const errorMsg = `CSV2JSON() - Champs inconnus : ${unknownHeaders}`; + return callback( errorMsg, null ); + } + lines.forEach( ( line, index ) => { + // Skip headers line or empty lines + if( index === 0 || line.replace( /\s/g, '' ) + .length === 0 ) { + return; + } + // pour debuguer on met origincsv pour voir la ligne d'origine + const currentLineData = { 'origincsv': line, 'linenumber': index }; + const currentLine = line.split( options.sep ); // Current string in the line + for( let j = 0; j < headers.length; j++ ) { + // Si la ligne n'est pas vide + if( currentLine[ j ] ) { + // On clean le champs + // ajout eventuel de modification de caracter reservé ; dans les libelléetc... + let currentValue = currentLine[ j ].trim() + //on transforme le caractere separateur modifié entre double quote + currentValue = currentValue.replace( 'CARSEPARATOR', options.sep ); + options.replacespecialcarCsv2Json.forEach( re => { + currentValue = currentValue.replace( re[ 0 ], re[ 1 ] ) + } ) + // Si le header est un email + if( headers[ j ].includes( 'EMAIL' ) ) { + // Supprimer tous les espaces + currentValue = currentLine[ j ].replace( /\s/g, '' ); + } + // on check si le chamos doit être numerique + if( options.numericfield.includes( headers[ j ] ) ) { + currentValue = currentLine[ j ].replace( /\,/g, '.' ); + try { + const test = parseFloat( currentValue ); + } catch ( er ) { + return callback( `${headers[j]} contiens la valeur -${currentValue}- et devrait être numerique`, null ); + } + } + if( currentValue ) { + // Si le header actuel est de type array + // Cela signifie que le header apparaît plusieurs fois dans le CSV + // et que les valeurs correspondantes à ce header + // doivent être mis dans un array + if( options.array && options.array.indexOf( headers[ j ] ) > -1 ) { + // Si le tableau pour ce header n'existe pas on le crée + if( !currentLineData[ headers[ j ] ] ) { + currentLineData[ headers[ j ] ] = []; + } + if( options.arraysplitsep ) { + currentValue.split( options.arraysplitsep ) + .forEach( v => { + currentLineData[ headers[ j ] ].push( v ); + } ) + } else { + currentLineData[ headers[ j ] ].push( currentValue ); + } + } else { + // Si un header est déjà présent pour la ligne + // alors que il n'est pas spécifié comme étant un array + // on retourne une erreur + if( currentLineData[ headers[ j ] ] ) { + const errorMsg = `Le champ ${ + headers[j] + } est présent plusieurs fois alors qu'il n'est pas spécifié comme étant un array !`; + return callback( errorMsg, null ); + } + currentLineData[ headers[ j ] ] = currentValue; + } + } + } + } + result.push( currentLineData ); + } ); + return callback( null, result ); +}; +/** + * [csvparam2json description] + * @param {object} csv object of csv file that has been read + * @param {object} options object containing csv options, headers, ... + {retln:'code de retour de ligne \n ou \n\r', + sep:'code to split cells', + champs:[ch1,ch2,...] catch only those field, + array:[ch1, ] can have more than one field champs with same name then data are push into an array } + * @param {Function} callback callback function + * @return {callback} - return an error if error, else return json + it converts a csv with 3 column col1;col2;col3 in a json in a tree + if in col1 we have __ => then it splits a leaf + col1 = xxxx__yyyy ; col2 = value ; col3 = comment that is ignored + return data = {xxxx:{yyyy:value}} + col1 = xxxx; col2 = value; col3 = comment ignored +return data = {xxxx:value} + +Usage example: +fiche.csvparam2article = (err, fiche) => { + if (!err) { + console.log(fiche) + } +} +utils.csvparam2json(fs.readFileSync('./devdata/tribee/aubergenville/infoexterne/localbusiness.csv', 'utf-8'), { + retln: "\n", + sep: ";", + champs: ["NOM", "OBJET", "ADRESSE_PRO", "CP_PRO", "VILLE_PRO", "ZONE", "PHONE_PRO", "HORAIRESDESC", "HORAIREDATA", "URL", "FACEBOOK", "INSTA", "EMAIL_PRO", "IMG", "TAG"], + array: ["TAG", "PHONE_PRO", "EMAIL_PRO"] +}, fiche.csv2article) + + */ +utils.csvparam2json = ( csv, options, callback ) => { + console.log( '\n--------------- CSVPARAM2JSON ---------------\n' ); + let etat = ""; + const param = {}; + if( !options.retln ) { + options.retln = '\n'; + } + if( csv.indexOf( '\n\r' ) > -1 ) { + options.retln = '\n\r'; + } + if( !options.sep ) { + options.sep = ';'; + } + if( !options.seplevel ) { + options.seplevel = "__"; + } + if( !options.replacespecialcarCsv2Json ) { + options.replacespecialcarCsv2Json = [] + } else { + if( typeof options.replacespecialcarCsv2Json == "string" ) { + //permet de passer des regex en string + options.replacespecialcarCsv2Json = eval( options.replacespecialcarCsv2Json ); + } + }; + const lines = csv.split( options.retln ); + for( let i = 0; i < lines.length; i++ ) { + const infol = lines[ i ].split( options.sep ) + //console.log(infol) + if( infol[ 0 ].length > 4 && infol.length < 2 ) { + // si le 1er element à plus de 4 caractere et s'il y a moins de 3 colonnes c'est qu'il y a un pb + etat += `Erreur sur ${lines[i]} moins de 3 column separé par ${options.sep}`; + continue; + } + // On ajoute ici la gestion de tous les caracteres spéciaux + // reservées pour le csv ; ' etc..' + if( infol[ 1 ] && infol[ 1 ] + "" == infol[ 1 ] ) { + options.replacespecialcarCsv2Json.forEach( re => { + //console.log("gggggggggggggggggggg", infol[1]) + infol[ 1 ] = infol[ 1 ].replace( re[ 0 ], re[ 1 ] ); + } ) + // console.log(infol[1]) + infol[ 1 ] = infol[ 1 ].replace( /'|’/g, "\"" ); + //console.log(infol[1]) + if( infol[ 1 ].toLowerCase() === 'true' ) { + infol[ 1 ] = true; + } else if( infol[ 1 ].toLowerCase() === 'false' ) { + infol[ 1 ] = false; + } + } + console.log( infol[ 1 ] ) + //supprime des lignes vides + if( infol[ 0 ] == '' ) continue; + if( infol[ 0 ].indexOf( options.seplevel ) == -1 ) { + param[ infol[ 0 ] ] = infol[ 1 ] + continue; + } else { + const arbre = infol[ 0 ].split( options.seplevel ) + switch ( arbre.length ) { + case 1: + param[ arbre[ 0 ] ] = infol[ 1 ]; + break; + case 2: + if( arbre[ 1 ] != "ARRAY" ) { + if( !param[ arbre[ 0 ] ] ) param[ arbre[ 0 ] ] = {}; + param[ arbre[ 0 ] ][ arbre[ 1 ] ] = infol[ 1 ]; + } else { + if( !param[ arbre[ 0 ] ] ) param[ arbre[ 0 ] ] = []; + //console.log('aff', infol[1].substring(1, infol[1].length - 1).replace(/""/g, '"')) + eval( "result=" + infol[ 1 ] ) + //.substring(1, infol[1].length - 1).replace(/""/g, '"')) + param[ arbre[ 0 ] ].push( result ) + } + break; + case 3: + if( arbre[ 2 ] != "ARRAY" ) { + if( !param[ arbre[ 0 ] ] ) param[ arbre[ 0 ] ] = {}; + if( !param[ arbre[ 0 ] ][ arbre[ 1 ] ] ) param[ arbre[ 0 ] ][ arbre[ 1 ] ] = {}; + param[ arbre[ 0 ] ][ arbre[ 1 ] ][ arbre[ 2 ] ] = infol[ 1 ]; + } else { + if( !param[ arbre[ 0 ] ] ) param[ arbre[ 0 ] ] = {}; + if( !param[ arbre[ 0 ] ][ arbre[ 1 ] ] ) param[ arbre[ 0 ] ][ arbre[ 1 ] ] = []; + //eval("result = \"test\""); + //console.log(result); + eval( "result=" + infol[ 1 ] ); + //.substring(1, infol[1].length - 1).replace(/""/g, '"')) + param[ arbre[ 0 ] ][ arbre[ 1 ] ].push( result ) + } + break; + case 4: + if( arbre[ 3 ] != "ARRAY" ) { + if( !param[ arbre[ 0 ] ] ) param[ arbre[ 0 ] ] = {}; + if( !param[ arbre[ 0 ] ][ arbre[ 1 ] ] ) param[ arbre[ 0 ] ][ arbre[ 1 ] ] = {}; + if( !param[ arbre[ 0 ] ][ arbre[ 1 ] ][ arbre[ 2 ] ] ) param[ arbre[ 0 ] ][ arbre[ 1 ] ][ arbre[ 2 ] ] = {}; + param[ arbre[ 0 ] ][ arbre[ 1 ] ][ arbre[ 2 ] ][ arbre[ 3 ] ] = infol[ 1 ]; + } else { + if( !param[ arbre[ 0 ] ] ) param[ arbre[ 0 ] ] = {}; + if( !param[ arbre[ 0 ] ][ arbre[ 1 ] ] ) param[ arbre[ 0 ] ][ arbre[ 1 ] ] = {}; + if( !param[ arbre[ 0 ] ][ arbre[ 1 ] ][ arbre[ 2 ] ] ) param[ arbre[ 0 ] ][ arbre[ 1 ] ][ arbre[ 2 ] ] = []; + eval( "result=" + infol[ 1 ] ) + //.substring(1, infol[1].length - 1).replace(/""/g, '"')) + param[ arbre[ 0 ] ][ arbre[ 1 ] ][ arbre[ 2 ] ].push( result ) + break; + } + default: + break; + } + } + } + // JSON.parse(JSON.stringify(param)) + console.log( 'kkkkkkkkkkkkkkkkkk', param[ 'catalogue' ][ 'filtrecatalog' ][ 'searchengine' ] ) + if( etat == "" ) { + return callback( null, JSON.parse( JSON.stringify( param ) ) ); + } else { + return callback( etat, null ); + } +} +utils.levenshtein = ( a, b ) => { + if( a.length === 0 ) return b.length; + if( b.length === 0 ) return a.length; + let tmp, i, j, prev, val, row; + // swap to save some memory O(min(a,b)) instead of O(a) + if( a.length > b.length ) { + tmp = a; + a = b; + b = tmp; + } + row = Array( a.length + 1 ); + // init the row + for( i = 0; i <= a.length; i++ ) { + row[ i ] = i; + } + // fill in the rest + for( i = 1; i <= b.length; i++ ) { + prev = i; + for( j = 1; j <= a.length; j++ ) { + if( b[ i - 1 ] === a[ j - 1 ] ) { + val = row[ j - 1 ]; // match + } else { + val = Math.min( row[ j - 1 ] + 1, // substitution + Math.min( prev + 1, // insertion + row[ j ] + 1 ) ); // deletion + } + row[ j - 1 ] = prev; + prev = val; + } + row[ a.length ] = prev; + } + return row[ a.length ]; +}; +utils.testinarray = ( array, arrayreferent ) => { + // au moins un element de array existe dans arryreferent + let exist = false; + if( arrayreferent ) { + //console.log('arrrrrrrrrrrrrrr', arrayreferent) + array.forEach( e => { + //console.log(e) + if( arrayreferent.includes( e ) ) exist = true + } ) + } + return exist +}; +/* +DIRECTORY +*/ +const isDirectory = source => fs.lstatSync( source ) + .isDirectory(); +const getDirectories = source => fs.readdirSync( source ) + .map( name => path.join( source, name ) ) + .filter( isDirectory ); +module.exports = utils; diff --git a/nationchains/socialworld/metaobject/nation.json b/nationchains/socialworld/metaobject/nation.json new file mode 100644 index 0000000..94c8b2d --- /dev/null +++ b/nationchains/socialworld/metaobject/nation.json @@ -0,0 +1,36 @@ +[ + { + "idfield": "name", + "nouserupdate": true, + "nouservisible": true, + "desc": { + "fr": "Nom unique d'une nation dans un monde social", + "en": "A unique nation name in a social world" + }, + "desclong": { + "fr": "Nom unique identifiant une nation dans le monde social créer par un maire d'une nouvelle ville avec un contrat sociale specifique", + "en": "Unique nation name in the social world created by a mayor of a town." + }, + "info": { + "fr": "

Une nation posséde un nom unique, un contrat sociale (contracts/name.js) signé et validé par tous les maires des villes associées à cette nation

", + "en": "

A nation is defined by this unique name and a contratcs/nationname.js signed by each town's major define the common nation rules

" + }, + "check": ["required", "unique"], + "type": "text", + "questioncollecte":"questioninput", + "searchindex":["all"] + }, + { + "idfield": "nationtype", + "searchindex": ["name"], + "check": ["required"], + "desc": { + "fr": "Type de nation" + }, + "default": "ACTIVE", + "type": "data", + "questioncollect": "questionselect", + "data": "state.json" + }, + +] \ No newline at end of file diff --git a/nationchains/socialworld/metaobject/pagans.json b/nationchains/socialworld/metaobject/pagans.json new file mode 100755 index 0000000..58fae87 --- /dev/null +++ b/nationchains/socialworld/metaobject/pagans.json @@ -0,0 +1,265 @@ +[{ + "idfield": "UUID", + "nouserupdate": true, + "nouservisible": true, + "desc": { + "fr": "identifiant utilisateur", + "en": "user id" + }, + "desclong": { + "fr": "Identifiant unique généré via UUID v4", + "en": "unique Id from a UUID v4" + }, + "info": { + "fr": "

L'usage d'UUID v4 permet de générer un code unique sans centralisation, car il est basé sur un timestamp et une clé crypto ce qui donne un code du type 7d8291c0-e137-11e8-9f7b-1dc8e57bed33

", + "en": "

UUID v4 allow a client to generate a unique code without centralisation, base on a timestamp and a salt it looks like 7d8291c0-e137-11e8-9f7b-1dc8e57bed33

" + }, + "check": ["required", "unique"], + "type": "text", + "tpl": "input" + }, + { + "idfield": "LOGIN", + "nouserupdate": true, + "check": ["required", "unique"], + "desc": { + "fr": "login", + "en": "login" + }, + "type": "text", + "tpl": "input", + "info": { + "fr": "

Le login doit être unique sur une instance d'apixtribe.

Pour échanger en dehors d'une instance apixtribe on utilise la clé public du user ou pour un humain login@apixtribe.domain.xx avec le nom du domaine qui heberge l'instance

Ou encore login@domain.xx tout domain.xx utilisé pour heberger un espace web client /tribeid/www/

", + "en": "

Login have to be unique into an apixtribe instance

To exchange outside of an apixtribe instance, we use PublicKey or login@apixtribe.domain.xx or login@domainclient.xx where domain.xx is a apixtribe name server on internet and domain.xx is a tribeid name where a /tribeid/www is available on the net.

" + } + }, + { + "idfield": "BIOGRAPHY", + "desc": { + "fr": "Vous en quelques mots", + "en": "Few words" + }, + "placeholder": { + "fr": "", + "en": "" + }, + "rows": 2, + "tpl": "textarea" + }, + { + "nouserupdate": true, + "idfield": "PUBLICKEY", + "desc": { + "fr": "Votre clé public pour ce compte", + "en": "Your public key for this uuid" + }, + "info": { + "fr": "

Cette clé est générée par votre navigateur, garder précisuesement votre clé privée que seule vous connaissez. En cas de perte de cette clé tous vos actifs seront perdus.

Cette méthode nous permet de vous garantir un contrôle total décentralisé.

", + "en": "

This key was generated by your browser, keep the private key related to this public key.

We garanty your total control by this way

." + }, + "tpl": "textarea" + }, + { + "idfield": "IMGAVATAR", + "tpl": "inputimg", + "altimg": "image avatar", + "classimg": "rounded-circle img-responsive mt-2", + "width": 128, + "height:" + 128, + "classdivupload": "mt-2", + "classbtn": "btn-primary", + "desc": { + "fr": "changer votre avatar", + "en": "upload an avatar" + }, + "info": { + "fr": "Pour un meilleur rendu, une mage carré de 128pc en foat jpg", + "en": "For best results, use an image at least 128px by 128px in .jpg format" + }, + + }, + { + "idfield": "EMAIL", + "desc": { + "fr": "email", + "en": "email" + }, + "tpl": "input", + "type": "email", + "check": ["emailadress", "unique"], + "placeholder": { + "fr": "#@", + "en": "@" + } + }, + { + "idfield": "PHONE", + "desc": { + "fr": "Tel", + "en": "Phone" + }, + "check": ["phone"] + "tpl": "input", + "type": "text" + }, + { + "idfield": "NAME", + "desc": { + "fr": "Nom", + "en": "Name" + }, + "tpl": "input", + "type": "text" + }, + { + "idfield": "FIRSTNAME", + "desc": { + "fr": "Prénom", + "en": "First Name" + }, + "tpl": "input", + "type": "text" + }, + { + "idfield": "NICKNAME", + "desc": { + "fr": "Pseudo", + "en": "Nickname" + }, + "tpl": "input", + "type": "text" + }, + "info": { + "fr": "

Nom avec lequel vous souhaitez qu'on vous reconnaisse sur l'instance de l'apixtribe

Attention ce nom n'est unique que sur une instance d'apixtribe. Un même speudo peut-être utilisé sur un autre serveur pour garantir l'identité vérifié pseudo@ domaine de rattachement.

", + "en": "

Carrefull a pseudo is unique into an instance of apixtribe to be sure to contact the right person check pseudo@ domain

.

Pseudo can be changed that is not the case of login.

" + }, + "tpl": "input", + "type": "text" +}, { + "idfield": "COMPANYNAME", + "desc": { + "fr": "Nom de Société", + "en": "Compagnie name" + }, + "tpl": "input", + "type": "text" +}, { + "idfield": "BILLINGADD", + "desc": { + "fr": "Adresse complete de facturation par defaut", + "en": "Full billing adress default" + }, + "tpl": "input", + "type": "text", + "placeholder": { + "fr": "1 chemin du paradis - 91430 IGNY France", + "en": "123 Main St- 123MZ -Oxford UK" + } +}, { + "idfield": "DELIVERYADD", + "desc": { + "fr": "Adresse complete de livraison par defaut", + "en": "Full delivery adress default" + }, + "tpl": "input", + "type": "text", + "placeholder": { + "fr": "1 chemin du paradis - 91430 IGNY France", + "en": "123 Main St- 123MZ -Oxford UK" + } +}, { + "idfield": "ADDRESS1", + "desc": { + "fr": "Adresse", + "en": "Address" + }, + "tpl": "input", + "type": "text", + "placeholder": { + "fr": "1 chemin du paradis", + "en": "123 Main St" + } +}, { + "idfield": "ADDRESS2", + "desc": { + "fr": "Adresse 2", + "en": "Address 2" + }, + "tpl": "input", + "type": "text", + "placeholder": { + "fr": "Appartement B", + "en": "Apt B" + } +}, { + "idfield": "CITY", + "desc": { + "fr": "Ville ", + "en": "CITY" + }, + "tpl": "input", + "type": "text" +}, { + "idfield": "ZIP", + "desc": { + "fr": "Code Postal", + "en": "ZIP" + }, + "tpl": "input", + "type": "text" +}, { + "idfield": "COUNTRY", + "desc": { + "fr": "Pays", + "en": "Country" + }, + "tpl": "input", + "type": "text" +}, { + "nouserupdate": true, + "idfield": "DATE_CREATE", + "desc": { + "fr": "Date de création", + "en": "Create Date" + }, + "tpl": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')" +}, { + "nouserupdate": true,o + "idfield": "DATE_UPDATE", + "desc": { + "fr": "Date mise à jour", + "en": "Update date" + }, + "tpl": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')" +}, { + "nouserupdate": true, + "idfield": "DATE_LASTLOGIN", + "desc": { + "fr": "Date de derniére connexion", + "en": "Last date login" + }, + "tpl": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')" +}, { + "idfield": "ACCESSRIGHTS", + "nouserupdate": true, + "desc": { + "fr": "Vos droits d'accès", + "en": "Your access rights" + }, + "default": { + "app": {}, + "data": { + "tribeidname": { + "users": "O" + } + } + }, + "tpl": "jsoneditor" +}] diff --git a/nationchains/socialworld/metaobject/towns.json b/nationchains/socialworld/metaobject/towns.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/nationchains/socialworld/metaobject/towns.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/nationchains/socialworld/objects/nations/ants.json b/nationchains/socialworld/objects/nations/ants.json new file mode 100644 index 0000000..154bb6e --- /dev/null +++ b/nationchains/socialworld/objects/nations/ants.json @@ -0,0 +1,7 @@ +{"UUID":"ants", +"publickey":"123", +"status":"open", +"domain":["antsnation.mooo.com"], +"svg":"", +"towns":["hill"] +} \ No newline at end of file diff --git a/nationchains/socialworld/objects/nations/escape.json b/nationchains/socialworld/objects/nations/escape.json new file mode 100644 index 0000000..f9c28d3 --- /dev/null +++ b/nationchains/socialworld/objects/nations/escape.json @@ -0,0 +1,5 @@ +{"UUID":"escape", +"publickey":"123", +"status":"open", +"towns":["game"] +} \ No newline at end of file diff --git a/nationchains/socialworld/objects/nations/searchindex/nationslist.json b/nationchains/socialworld/objects/nations/searchindex/nationslist.json new file mode 100644 index 0000000..6843706 --- /dev/null +++ b/nationchains/socialworld/objects/nations/searchindex/nationslist.json @@ -0,0 +1 @@ +["escapenation"] \ No newline at end of file diff --git a/nationchains/socialworld/objects/nations/searchindex/townslist.json b/nationchains/socialworld/objects/nations/searchindex/townslist.json new file mode 100644 index 0000000..e69de29 diff --git a/nationchains/socialworld/objects/nations/searchindex/tribeslist.json b/nationchains/socialworld/objects/nations/searchindex/tribeslist.json new file mode 100644 index 0000000..0ef9f40 --- /dev/null +++ b/nationchains/socialworld/objects/nations/searchindex/tribeslist.json @@ -0,0 +1 @@ +{"archilinea":["escapenation","game"]} \ No newline at end of file diff --git a/nationchains/socialworld/objects/towns/game.json b/nationchains/socialworld/objects/towns/game.json new file mode 100644 index 0000000..a6ece87 --- /dev/null +++ b/nationchains/socialworld/objects/towns/game.json @@ -0,0 +1,7 @@ +{ + "url":"https://escape.game.apixtribe.org", + "IP":"213.32.65.213", + "mayorid":"123", + "status":"" + "tribes":[] + } \ No newline at end of file diff --git a/nationchains/socialworld/objects/tribes/searchindex/tribeslist.json b/nationchains/socialworld/objects/tribes/searchindex/tribeslist.json new file mode 100644 index 0000000..e69de29 diff --git a/nationchains/static/error/404.html b/nationchains/static/error/404.html new file mode 100644 index 0000000..3a2b7dd --- /dev/null +++ b/nationchains/static/error/404.html @@ -0,0 +1 @@ +

404 - Not found on town {{config.town}} for the {{config.nation}} nation mettre un js qui /app qui retourne le serveur concerne

\ No newline at end of file diff --git a/nationchains/static/error/50x.html.html b/nationchains/static/error/50x.html.html new file mode 100644 index 0000000..28260c1 --- /dev/null +++ b/nationchains/static/error/50x.html.html @@ -0,0 +1 @@ +

50x - Not found on town {{config.town}} for the {{config.nation}} nation mettre un js qui /app qui retourne le serveur concerne

\ No newline at end of file diff --git a/nationchains/static/fonts/Cantarell-Bold.ttf b/nationchains/static/fonts/Cantarell-Bold.ttf new file mode 100755 index 0000000..af5f05a Binary files /dev/null and b/nationchains/static/fonts/Cantarell-Bold.ttf differ diff --git a/nationchains/static/fonts/Cantarell-BoldItalic.ttf b/nationchains/static/fonts/Cantarell-BoldItalic.ttf new file mode 100755 index 0000000..22b83d4 Binary files /dev/null and b/nationchains/static/fonts/Cantarell-BoldItalic.ttf differ diff --git a/nationchains/static/fonts/Cantarell-Italic.ttf b/nationchains/static/fonts/Cantarell-Italic.ttf new file mode 100755 index 0000000..77a699d Binary files /dev/null and b/nationchains/static/fonts/Cantarell-Italic.ttf differ diff --git a/nationchains/static/fonts/Cantarell-Regular.ttf b/nationchains/static/fonts/Cantarell-Regular.ttf new file mode 100755 index 0000000..f5d16d7 Binary files /dev/null and b/nationchains/static/fonts/Cantarell-Regular.ttf differ diff --git a/nationchains/static/fonts/OFL.txt b/nationchains/static/fonts/OFL.txt new file mode 100755 index 0000000..4e49501 --- /dev/null +++ b/nationchains/static/fonts/OFL.txt @@ -0,0 +1,93 @@ +Copyright (c) 2009-2010, Understanding Limited (dave@understandinglimited.com) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/nationchains/static/fonts/cantarell-bold-demo.html b/nationchains/static/fonts/cantarell-bold-demo.html new file mode 100755 index 0000000..b5eb8f4 --- /dev/null +++ b/nationchains/static/fonts/cantarell-bold-demo.html @@ -0,0 +1,622 @@ + + + + + + + + + + + + + Cantarell Bold Specimen + + + + + + +
+ + + +
+ + +
+ +
+
+
AaBb
+
+
+ +
+
A​B​C​D​E​F​G​H​I​J​K​L​M​N​O​P​Q​R​S​T​U​V​W​X​Y​Z​a​b​c​d​e​f​g​h​i​j​k​l​m​n​o​p​q​r​s​t​u​v​w​x​y​z​1​2​3​4​5​6​7​8​9​0​&​.​,​?​!​@​(​)​#​$​%​*​+​-​=​:​;
+
+
+
+ + + + + + + + + + + + + + + + +
10abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
11abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
12abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
13abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
14abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
16abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
18abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
20abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
24abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
30abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
36abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
48abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
60abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
72abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
90abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ +
+ +
+ + + +
+ + +
+
◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼body
body
body
body
+
+ bodyCantarell Bold +
+
+ bodyArial +
+
+ bodyVerdana +
+
+ bodyGeorgia +
+ + + +
+ + +
+ +
+

10.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

11.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

12.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

13.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+
+
+

14.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

16.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

18.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+ +
+ +
+ +
+
+

20.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+

24.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+ +
+ +
+ +
+
+

30.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+ +
+ + + +
+
+

10.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

11.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

12.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

13.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+ +
+
+

14.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

16.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

18.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+ +
+
+

20.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+

24.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+ +
+ +
+ +
+
+

30.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+ +
+ + + + +
+ +
+ +
+ +
+

Lorem Ipsum Dolor

+

Etiam porta sem malesuada magna mollis euismod

+ + +
+
+
+
+

Donec sed odio dui. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

+ + +

Pellentesque ornare sem

+ +

Maecenas sed diam eget risus varius blandit sit amet non magna. Maecenas faucibus mollis interdum. Donec ullamcorper nulla non metus auctor fringilla. Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam id dolor id nibh ultricies vehicula ut id elit.

+ +

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

+ +

Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Aenean lacinia bibendum nulla sed consectetur.

+ +

Nullam quis risus eget urna mollis ornare vel eu leo. Nullam quis risus eget urna mollis ornare vel eu leo. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec ullamcorper nulla non metus auctor fringilla.

+ +

Cras mattis consectetur

+ +

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Aenean lacinia bibendum nulla sed consectetur. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Cras mattis consectetur purus sit amet fermentum.

+ +

Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam quis risus eget urna mollis ornare vel eu leo. Cras mattis consectetur purus sit amet fermentum.

+
+ + +
+ +
+ + + + + + +
+
+
+ +

Language Support

+

The subset of Cantarell Bold in this kit supports the following languages:
+ + Albanian, Basque, Breton, Chamorro, Danish, Dutch, English, Faroese, Finnish, French, Frisian, Galician, German, Icelandic, Italian, Malagasy, Norwegian, Portuguese, Spanish, Alsatian, Aragonese, Arapaho, Arrernte, Asturian, Aymara, Bislama, Cebuano, Corsican, Fijian, French_creole, Genoese, Gilbertese, Greenlandic, Haitian_creole, Hiligaynon, Hmong, Hopi, Ibanag, Iloko_ilokano, Indonesian, Interglossa_glosa, Interlingua, Irish_gaelic, Jerriais, Lojban, Lombard, Luxembourgeois, Manx, Mohawk, Norfolk_pitcairnese, Occitan, Oromo, Pangasinan, Papiamento, Piedmontese, Potawatomi, Rhaeto-romance, Romansh, Rotokas, Sami_lule, Samoan, Sardinian, Scots_gaelic, Seychelles_creole, Shona, Sicilian, Somali, Southern_ndebele, Swahili, Swati_swazi, Tagalog_filipino_pilipino, Tetum, Tok_pisin, Uyghur_latinized, Volapuk, Walloon, Warlpiri, Xhosa, Yapese, Zulu, Latinbasic, Ubasic, Demo

+

Glyph Chart

+

The subset of Cantarell Bold in this kit includes all the glyphs listed below. Unicode entities are included above each glyph to help you insert individual characters into your layout.

+
+ +

&#13;

+

&#32;

+

&#33;

!
+

&#34;

"
+

&#35;

#
+

&#36;

$
+

&#37;

%
+

&#38;

&
+

&#39;

'
+

&#40;

(
+

&#41;

)
+

&#42;

*
+

&#43;

+
+

&#44;

,
+

&#45;

-
+

&#46;

.
+

&#47;

/
+

&#48;

0
+

&#49;

1
+

&#50;

2
+

&#51;

3
+

&#52;

4
+

&#53;

5
+

&#54;

6
+

&#55;

7
+

&#56;

8
+

&#57;

9
+

&#58;

:
+

&#59;

;
+

&#60;

<
+

&#61;

=
+

&#62;

>
+

&#63;

?
+

&#64;

@
+

&#65;

A
+

&#66;

B
+

&#67;

C
+

&#68;

D
+

&#69;

E
+

&#70;

F
+

&#71;

G
+

&#72;

H
+

&#73;

I
+

&#74;

J
+

&#75;

K
+

&#76;

L
+

&#77;

M
+

&#78;

N
+

&#79;

O
+

&#80;

P
+

&#81;

Q
+

&#82;

R
+

&#83;

S
+

&#84;

T
+

&#85;

U
+

&#86;

V
+

&#87;

W
+

&#88;

X
+

&#89;

Y
+

&#90;

Z
+

&#91;

[
+

&#92;

\
+

&#93;

]
+

&#94;

^
+

&#95;

_
+

&#96;

`
+

&#97;

a
+

&#98;

b
+

&#99;

c
+

&#100;

d
+

&#101;

e
+

&#102;

f
+

&#103;

g
+

&#104;

h
+

&#105;

i
+

&#106;

j
+

&#107;

k
+

&#108;

l
+

&#109;

m
+

&#110;

n
+

&#111;

o
+

&#112;

p
+

&#113;

q
+

&#114;

r
+

&#115;

s
+

&#116;

t
+

&#117;

u
+

&#118;

v
+

&#119;

w
+

&#120;

x
+

&#121;

y
+

&#122;

z
+

&#123;

{
+

&#124;

|
+

&#125;

}
+

&#126;

~
+

&#160;

 
+

&#161;

¡
+

&#162;

¢
+

&#163;

£
+

&#164;

¤
+

&#165;

¥
+

&#166;

¦
+

&#167;

§
+

&#168;

¨
+

&#169;

©
+

&#170;

ª
+

&#171;

«
+

&#172;

¬
+

&#173;

­
+

&#174;

®
+

&#175;

¯
+

&#176;

°
+

&#177;

±
+

&#178;

²
+

&#179;

³
+

&#180;

´
+

&#181;

µ
+

&#182;

+

&#183;

·
+

&#184;

¸
+

&#185;

¹
+

&#186;

º
+

&#187;

»
+

&#188;

¼
+

&#189;

½
+

&#190;

¾
+

&#191;

¿
+

&#192;

À
+

&#193;

Á
+

&#194;

Â
+

&#195;

Ã
+

&#196;

Ä
+

&#197;

Å
+

&#198;

Æ
+

&#199;

Ç
+

&#200;

È
+

&#201;

É
+

&#202;

Ê
+

&#203;

Ë
+

&#204;

Ì
+

&#205;

Í
+

&#206;

Î
+

&#207;

Ï
+

&#208;

Ð
+

&#209;

Ñ
+

&#210;

Ò
+

&#211;

Ó
+

&#212;

Ô
+

&#213;

Õ
+

&#214;

Ö
+

&#215;

×
+

&#216;

Ø
+

&#217;

Ù
+

&#218;

Ú
+

&#219;

Û
+

&#220;

Ü
+

&#221;

Ý
+

&#222;

Þ
+

&#223;

ß
+

&#224;

à
+

&#225;

á
+

&#226;

â
+

&#227;

ã
+

&#228;

ä
+

&#229;

å
+

&#230;

æ
+

&#231;

ç
+

&#232;

è
+

&#233;

é
+

&#234;

ê
+

&#235;

ë
+

&#236;

ì
+

&#237;

í
+

&#238;

î
+

&#239;

ï
+

&#240;

ð
+

&#241;

ñ
+

&#242;

ò
+

&#243;

ó
+

&#244;

ô
+

&#245;

õ
+

&#246;

ö
+

&#247;

÷
+

&#248;

ø
+

&#249;

ù
+

&#250;

ú
+

&#251;

û
+

&#252;

ü
+

&#253;

ý
+

&#254;

þ
+

&#255;

ÿ
+

&#338;

Œ
+

&#339;

œ
+

&#376;

Ÿ
+

&#710;

ˆ
+

&#732;

˜
+

&#8192;

 
+

&#8193;

+

&#8194;

+

&#8195;

+

&#8196;

+

&#8197;

+

&#8198;

+

&#8199;

+

&#8200;

+

&#8201;

+

&#8202;

+

&#8208;

+

&#8209;

+

&#8210;

+

&#8211;

+

&#8212;

+

&#8216;

+

&#8217;

+

&#8218;

+

&#8220;

+

&#8221;

+

&#8222;

+

&#8226;

+

&#8230;

+

&#8239;

+

&#8249;

+

&#8250;

+

&#8287;

+

&#8364;

+

&#8482;

+

&#9724;

+

&#64257;

+

&#64258;

+

&#64259;

+

&#64260;

+
+
+ + +
+
+ + +
+ +
+ +
+
+
+

Installing Webfonts

+ +

Webfonts are supported by all major browser platforms but not all in the same way. There are currently four different font formats that must be included in order to target all browsers. This includes TTF, WOFF, EOT and SVG.

+ +

1. Upload your webfonts

+

You must upload your webfont kit to your website. They should be in or near the same directory as your CSS files.

+ +

2. Include the webfont stylesheet

+

A special CSS @font-face declaration helps the various browsers select the appropriate font it needs without causing you a bunch of headaches. Learn more about this syntax by reading the Fontspring blog post about it. The code for it is as follows:

+ + + +@font-face{ + font-family: 'MyWebFont'; + src: url('WebFont.eot'); + src: url('WebFont.eot?#iefix') format('embedded-opentype'), + url('WebFont.woff') format('woff'), + url('WebFont.ttf') format('truetype'), + url('WebFont.svg#webfont') format('svg'); +} + + +

We've already gone ahead and generated the code for you. All you have to do is link to the stylesheet in your HTML, like this:

+ <link rel="stylesheet" href="stylesheet.css" type="text/css" charset="utf-8" /> + +

3. Modify your own stylesheet

+

To take advantage of your new fonts, you must tell your stylesheet to use them. Look at the original @font-face declaration above and find the property called "font-family." The name linked there will be what you use to reference the font. Prepend that webfont name to the font stack in the "font-family" property, inside the selector you want to change. For example:

+p { font-family: 'WebFont', Arial, sans-serif; } + +

4. Test

+

Getting webfonts to work cross-browser can be tricky. Use the information in the sidebar to help you if you find that fonts aren't loading in a particular browser.

+
+ + +
+ +
+ +
+ +
+ + \ No newline at end of file diff --git a/nationchains/static/fonts/cantarell-bold-webfont.woff b/nationchains/static/fonts/cantarell-bold-webfont.woff new file mode 100755 index 0000000..58552f9 Binary files /dev/null and b/nationchains/static/fonts/cantarell-bold-webfont.woff differ diff --git a/nationchains/static/fonts/cantarell-bold-webfont.woff2 b/nationchains/static/fonts/cantarell-bold-webfont.woff2 new file mode 100755 index 0000000..271c046 Binary files /dev/null and b/nationchains/static/fonts/cantarell-bold-webfont.woff2 differ diff --git a/nationchains/static/fonts/cantarell-bolditalic-demo.html b/nationchains/static/fonts/cantarell-bolditalic-demo.html new file mode 100755 index 0000000..16a11e7 --- /dev/null +++ b/nationchains/static/fonts/cantarell-bolditalic-demo.html @@ -0,0 +1,622 @@ + + + + + + + + + + + + + Cantarell BoldOblique Specimen + + + + + + +
+ + + +
+ + +
+ +
+
+
AaBb
+
+
+ +
+
A​B​C​D​E​F​G​H​I​J​K​L​M​N​O​P​Q​R​S​T​U​V​W​X​Y​Z​a​b​c​d​e​f​g​h​i​j​k​l​m​n​o​p​q​r​s​t​u​v​w​x​y​z​1​2​3​4​5​6​7​8​9​0​&​.​,​?​!​@​(​)​#​$​%​*​+​-​=​:​;
+
+
+
+ + + + + + + + + + + + + + + + +
10abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
11abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
12abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
13abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
14abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
16abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
18abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
20abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
24abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
30abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
36abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
48abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
60abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
72abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
90abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ +
+ +
+ + + +
+ + +
+
◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼body
body
body
body
+
+ bodyCantarell BoldOblique +
+
+ bodyArial +
+
+ bodyVerdana +
+
+ bodyGeorgia +
+ + + +
+ + +
+ +
+

10.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

11.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

12.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

13.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+
+
+

14.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

16.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

18.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+ +
+ +
+ +
+
+

20.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+

24.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+ +
+ +
+ +
+
+

30.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+ +
+ + + +
+
+

10.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

11.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

12.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

13.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+ +
+
+

14.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

16.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

18.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+ +
+
+

20.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+

24.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+ +
+ +
+ +
+
+

30.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+ +
+ + + + +
+ +
+ +
+ +
+

Lorem Ipsum Dolor

+

Etiam porta sem malesuada magna mollis euismod

+ + +
+
+
+
+

Donec sed odio dui. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

+ + +

Pellentesque ornare sem

+ +

Maecenas sed diam eget risus varius blandit sit amet non magna. Maecenas faucibus mollis interdum. Donec ullamcorper nulla non metus auctor fringilla. Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam id dolor id nibh ultricies vehicula ut id elit.

+ +

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

+ +

Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Aenean lacinia bibendum nulla sed consectetur.

+ +

Nullam quis risus eget urna mollis ornare vel eu leo. Nullam quis risus eget urna mollis ornare vel eu leo. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec ullamcorper nulla non metus auctor fringilla.

+ +

Cras mattis consectetur

+ +

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Aenean lacinia bibendum nulla sed consectetur. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Cras mattis consectetur purus sit amet fermentum.

+ +

Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam quis risus eget urna mollis ornare vel eu leo. Cras mattis consectetur purus sit amet fermentum.

+
+ + +
+ +
+ + + + + + +
+
+
+ +

Language Support

+

The subset of Cantarell BoldOblique in this kit supports the following languages:
+ + Albanian, Basque, Breton, Chamorro, Danish, Dutch, English, Faroese, Finnish, French, Frisian, Galician, German, Icelandic, Italian, Malagasy, Norwegian, Portuguese, Spanish, Alsatian, Aragonese, Arapaho, Arrernte, Asturian, Aymara, Bislama, Cebuano, Corsican, Fijian, French_creole, Genoese, Gilbertese, Greenlandic, Haitian_creole, Hiligaynon, Hmong, Hopi, Ibanag, Iloko_ilokano, Indonesian, Interglossa_glosa, Interlingua, Irish_gaelic, Jerriais, Lojban, Lombard, Luxembourgeois, Manx, Mohawk, Norfolk_pitcairnese, Occitan, Oromo, Pangasinan, Papiamento, Piedmontese, Potawatomi, Rhaeto-romance, Romansh, Rotokas, Sami_lule, Samoan, Sardinian, Scots_gaelic, Seychelles_creole, Shona, Sicilian, Somali, Southern_ndebele, Swahili, Swati_swazi, Tagalog_filipino_pilipino, Tetum, Tok_pisin, Uyghur_latinized, Volapuk, Walloon, Warlpiri, Xhosa, Yapese, Zulu, Latinbasic, Ubasic, Demo

+

Glyph Chart

+

The subset of Cantarell BoldOblique in this kit includes all the glyphs listed below. Unicode entities are included above each glyph to help you insert individual characters into your layout.

+
+ +

&#13;

+

&#32;

+

&#33;

!
+

&#34;

"
+

&#35;

#
+

&#36;

$
+

&#37;

%
+

&#38;

&
+

&#39;

'
+

&#40;

(
+

&#41;

)
+

&#42;

*
+

&#43;

+
+

&#44;

,
+

&#45;

-
+

&#46;

.
+

&#47;

/
+

&#48;

0
+

&#49;

1
+

&#50;

2
+

&#51;

3
+

&#52;

4
+

&#53;

5
+

&#54;

6
+

&#55;

7
+

&#56;

8
+

&#57;

9
+

&#58;

:
+

&#59;

;
+

&#60;

<
+

&#61;

=
+

&#62;

>
+

&#63;

?
+

&#64;

@
+

&#65;

A
+

&#66;

B
+

&#67;

C
+

&#68;

D
+

&#69;

E
+

&#70;

F
+

&#71;

G
+

&#72;

H
+

&#73;

I
+

&#74;

J
+

&#75;

K
+

&#76;

L
+

&#77;

M
+

&#78;

N
+

&#79;

O
+

&#80;

P
+

&#81;

Q
+

&#82;

R
+

&#83;

S
+

&#84;

T
+

&#85;

U
+

&#86;

V
+

&#87;

W
+

&#88;

X
+

&#89;

Y
+

&#90;

Z
+

&#91;

[
+

&#92;

\
+

&#93;

]
+

&#94;

^
+

&#95;

_
+

&#96;

`
+

&#97;

a
+

&#98;

b
+

&#99;

c
+

&#100;

d
+

&#101;

e
+

&#102;

f
+

&#103;

g
+

&#104;

h
+

&#105;

i
+

&#106;

j
+

&#107;

k
+

&#108;

l
+

&#109;

m
+

&#110;

n
+

&#111;

o
+

&#112;

p
+

&#113;

q
+

&#114;

r
+

&#115;

s
+

&#116;

t
+

&#117;

u
+

&#118;

v
+

&#119;

w
+

&#120;

x
+

&#121;

y
+

&#122;

z
+

&#123;

{
+

&#124;

|
+

&#125;

}
+

&#126;

~
+

&#160;

 
+

&#161;

¡
+

&#162;

¢
+

&#163;

£
+

&#164;

¤
+

&#165;

¥
+

&#166;

¦
+

&#167;

§
+

&#168;

¨
+

&#169;

©
+

&#170;

ª
+

&#171;

«
+

&#172;

¬
+

&#173;

­
+

&#174;

®
+

&#175;

¯
+

&#176;

°
+

&#177;

±
+

&#178;

²
+

&#179;

³
+

&#180;

´
+

&#181;

µ
+

&#182;

+

&#183;

·
+

&#184;

¸
+

&#185;

¹
+

&#186;

º
+

&#187;

»
+

&#188;

¼
+

&#189;

½
+

&#190;

¾
+

&#191;

¿
+

&#192;

À
+

&#193;

Á
+

&#194;

Â
+

&#195;

Ã
+

&#196;

Ä
+

&#197;

Å
+

&#198;

Æ
+

&#199;

Ç
+

&#200;

È
+

&#201;

É
+

&#202;

Ê
+

&#203;

Ë
+

&#204;

Ì
+

&#205;

Í
+

&#206;

Î
+

&#207;

Ï
+

&#208;

Ð
+

&#209;

Ñ
+

&#210;

Ò
+

&#211;

Ó
+

&#212;

Ô
+

&#213;

Õ
+

&#214;

Ö
+

&#215;

×
+

&#216;

Ø
+

&#217;

Ù
+

&#218;

Ú
+

&#219;

Û
+

&#220;

Ü
+

&#221;

Ý
+

&#222;

Þ
+

&#223;

ß
+

&#224;

à
+

&#225;

á
+

&#226;

â
+

&#227;

ã
+

&#228;

ä
+

&#229;

å
+

&#230;

æ
+

&#231;

ç
+

&#232;

è
+

&#233;

é
+

&#234;

ê
+

&#235;

ë
+

&#236;

ì
+

&#237;

í
+

&#238;

î
+

&#239;

ï
+

&#240;

ð
+

&#241;

ñ
+

&#242;

ò
+

&#243;

ó
+

&#244;

ô
+

&#245;

õ
+

&#246;

ö
+

&#247;

÷
+

&#248;

ø
+

&#249;

ù
+

&#250;

ú
+

&#251;

û
+

&#252;

ü
+

&#253;

ý
+

&#254;

þ
+

&#255;

ÿ
+

&#338;

Œ
+

&#339;

œ
+

&#376;

Ÿ
+

&#710;

ˆ
+

&#732;

˜
+

&#8192;

 
+

&#8193;

+

&#8194;

+

&#8195;

+

&#8196;

+

&#8197;

+

&#8198;

+

&#8199;

+

&#8200;

+

&#8201;

+

&#8202;

+

&#8208;

+

&#8209;

+

&#8210;

+

&#8211;

+

&#8212;

+

&#8216;

+

&#8217;

+

&#8218;

+

&#8220;

+

&#8221;

+

&#8222;

+

&#8226;

+

&#8230;

+

&#8239;

+

&#8249;

+

&#8250;

+

&#8287;

+

&#8364;

+

&#8482;

+

&#9724;

+

&#64257;

+

&#64258;

+

&#64259;

+

&#64260;

+
+
+ + +
+
+ + +
+ +
+ +
+
+
+

Installing Webfonts

+ +

Webfonts are supported by all major browser platforms but not all in the same way. There are currently four different font formats that must be included in order to target all browsers. This includes TTF, WOFF, EOT and SVG.

+ +

1. Upload your webfonts

+

You must upload your webfont kit to your website. They should be in or near the same directory as your CSS files.

+ +

2. Include the webfont stylesheet

+

A special CSS @font-face declaration helps the various browsers select the appropriate font it needs without causing you a bunch of headaches. Learn more about this syntax by reading the Fontspring blog post about it. The code for it is as follows:

+ + + +@font-face{ + font-family: 'MyWebFont'; + src: url('WebFont.eot'); + src: url('WebFont.eot?#iefix') format('embedded-opentype'), + url('WebFont.woff') format('woff'), + url('WebFont.ttf') format('truetype'), + url('WebFont.svg#webfont') format('svg'); +} + + +

We've already gone ahead and generated the code for you. All you have to do is link to the stylesheet in your HTML, like this:

+ <link rel="stylesheet" href="stylesheet.css" type="text/css" charset="utf-8" /> + +

3. Modify your own stylesheet

+

To take advantage of your new fonts, you must tell your stylesheet to use them. Look at the original @font-face declaration above and find the property called "font-family." The name linked there will be what you use to reference the font. Prepend that webfont name to the font stack in the "font-family" property, inside the selector you want to change. For example:

+p { font-family: 'WebFont', Arial, sans-serif; } + +

4. Test

+

Getting webfonts to work cross-browser can be tricky. Use the information in the sidebar to help you if you find that fonts aren't loading in a particular browser.

+
+ + +
+ +
+ +
+ +
+ + \ No newline at end of file diff --git a/nationchains/static/fonts/cantarell-bolditalic-webfont.woff b/nationchains/static/fonts/cantarell-bolditalic-webfont.woff new file mode 100755 index 0000000..deed3a0 Binary files /dev/null and b/nationchains/static/fonts/cantarell-bolditalic-webfont.woff differ diff --git a/nationchains/static/fonts/cantarell-bolditalic-webfont.woff2 b/nationchains/static/fonts/cantarell-bolditalic-webfont.woff2 new file mode 100755 index 0000000..0507e51 Binary files /dev/null and b/nationchains/static/fonts/cantarell-bolditalic-webfont.woff2 differ diff --git a/nationchains/static/fonts/cantarell-italic-demo.html b/nationchains/static/fonts/cantarell-italic-demo.html new file mode 100755 index 0000000..755225d --- /dev/null +++ b/nationchains/static/fonts/cantarell-italic-demo.html @@ -0,0 +1,622 @@ + + + + + + + + + + + + + Cantarell Oblique Specimen + + + + + + +
+ + + +
+ + +
+ +
+
+
AaBb
+
+
+ +
+
A​B​C​D​E​F​G​H​I​J​K​L​M​N​O​P​Q​R​S​T​U​V​W​X​Y​Z​a​b​c​d​e​f​g​h​i​j​k​l​m​n​o​p​q​r​s​t​u​v​w​x​y​z​1​2​3​4​5​6​7​8​9​0​&​.​,​?​!​@​(​)​#​$​%​*​+​-​=​:​;
+
+
+
+ + + + + + + + + + + + + + + + +
10abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
11abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
12abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
13abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
14abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
16abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
18abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
20abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
24abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
30abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
36abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
48abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
60abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
72abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
90abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ +
+ +
+ + + +
+ + +
+
◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼body
body
body
body
+
+ bodyCantarell Oblique +
+
+ bodyArial +
+
+ bodyVerdana +
+
+ bodyGeorgia +
+ + + +
+ + +
+ +
+

10.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

11.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

12.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

13.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+
+
+

14.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

16.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

18.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+ +
+ +
+ +
+
+

20.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+

24.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+ +
+ +
+ +
+
+

30.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+ +
+ + + +
+
+

10.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

11.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

12.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

13.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+ +
+
+

14.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

16.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

18.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+ +
+
+

20.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+

24.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+ +
+ +
+ +
+
+

30.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+ +
+ + + + +
+ +
+ +
+ +
+

Lorem Ipsum Dolor

+

Etiam porta sem malesuada magna mollis euismod

+ + +
+
+
+
+

Donec sed odio dui. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

+ + +

Pellentesque ornare sem

+ +

Maecenas sed diam eget risus varius blandit sit amet non magna. Maecenas faucibus mollis interdum. Donec ullamcorper nulla non metus auctor fringilla. Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam id dolor id nibh ultricies vehicula ut id elit.

+ +

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

+ +

Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Aenean lacinia bibendum nulla sed consectetur.

+ +

Nullam quis risus eget urna mollis ornare vel eu leo. Nullam quis risus eget urna mollis ornare vel eu leo. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec ullamcorper nulla non metus auctor fringilla.

+ +

Cras mattis consectetur

+ +

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Aenean lacinia bibendum nulla sed consectetur. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Cras mattis consectetur purus sit amet fermentum.

+ +

Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam quis risus eget urna mollis ornare vel eu leo. Cras mattis consectetur purus sit amet fermentum.

+
+ + +
+ +
+ + + + + + +
+
+
+ +

Language Support

+

The subset of Cantarell Oblique in this kit supports the following languages:
+ + Albanian, Basque, Breton, Chamorro, Danish, Dutch, English, Faroese, Finnish, French, Frisian, Galician, German, Icelandic, Italian, Malagasy, Norwegian, Portuguese, Spanish, Alsatian, Aragonese, Arapaho, Arrernte, Asturian, Aymara, Bislama, Cebuano, Corsican, Fijian, French_creole, Genoese, Gilbertese, Greenlandic, Haitian_creole, Hiligaynon, Hmong, Hopi, Ibanag, Iloko_ilokano, Indonesian, Interglossa_glosa, Interlingua, Irish_gaelic, Jerriais, Lojban, Lombard, Luxembourgeois, Manx, Mohawk, Norfolk_pitcairnese, Occitan, Oromo, Pangasinan, Papiamento, Piedmontese, Potawatomi, Rhaeto-romance, Romansh, Rotokas, Sami_lule, Samoan, Sardinian, Scots_gaelic, Seychelles_creole, Shona, Sicilian, Somali, Southern_ndebele, Swahili, Swati_swazi, Tagalog_filipino_pilipino, Tetum, Tok_pisin, Uyghur_latinized, Volapuk, Walloon, Warlpiri, Xhosa, Yapese, Zulu, Latinbasic, Ubasic, Demo

+

Glyph Chart

+

The subset of Cantarell Oblique in this kit includes all the glyphs listed below. Unicode entities are included above each glyph to help you insert individual characters into your layout.

+
+ +

&#13;

+

&#32;

+

&#33;

!
+

&#34;

"
+

&#35;

#
+

&#36;

$
+

&#37;

%
+

&#38;

&
+

&#39;

'
+

&#40;

(
+

&#41;

)
+

&#42;

*
+

&#43;

+
+

&#44;

,
+

&#45;

-
+

&#46;

.
+

&#47;

/
+

&#48;

0
+

&#49;

1
+

&#50;

2
+

&#51;

3
+

&#52;

4
+

&#53;

5
+

&#54;

6
+

&#55;

7
+

&#56;

8
+

&#57;

9
+

&#58;

:
+

&#59;

;
+

&#60;

<
+

&#61;

=
+

&#62;

>
+

&#63;

?
+

&#64;

@
+

&#65;

A
+

&#66;

B
+

&#67;

C
+

&#68;

D
+

&#69;

E
+

&#70;

F
+

&#71;

G
+

&#72;

H
+

&#73;

I
+

&#74;

J
+

&#75;

K
+

&#76;

L
+

&#77;

M
+

&#78;

N
+

&#79;

O
+

&#80;

P
+

&#81;

Q
+

&#82;

R
+

&#83;

S
+

&#84;

T
+

&#85;

U
+

&#86;

V
+

&#87;

W
+

&#88;

X
+

&#89;

Y
+

&#90;

Z
+

&#91;

[
+

&#92;

\
+

&#93;

]
+

&#94;

^
+

&#95;

_
+

&#96;

`
+

&#97;

a
+

&#98;

b
+

&#99;

c
+

&#100;

d
+

&#101;

e
+

&#102;

f
+

&#103;

g
+

&#104;

h
+

&#105;

i
+

&#106;

j
+

&#107;

k
+

&#108;

l
+

&#109;

m
+

&#110;

n
+

&#111;

o
+

&#112;

p
+

&#113;

q
+

&#114;

r
+

&#115;

s
+

&#116;

t
+

&#117;

u
+

&#118;

v
+

&#119;

w
+

&#120;

x
+

&#121;

y
+

&#122;

z
+

&#123;

{
+

&#124;

|
+

&#125;

}
+

&#126;

~
+

&#160;

 
+

&#161;

¡
+

&#162;

¢
+

&#163;

£
+

&#164;

¤
+

&#165;

¥
+

&#166;

¦
+

&#167;

§
+

&#168;

¨
+

&#169;

©
+

&#170;

ª
+

&#171;

«
+

&#172;

¬
+

&#173;

­
+

&#174;

®
+

&#175;

¯
+

&#176;

°
+

&#177;

±
+

&#178;

²
+

&#179;

³
+

&#180;

´
+

&#181;

µ
+

&#182;

+

&#183;

·
+

&#184;

¸
+

&#185;

¹
+

&#186;

º
+

&#187;

»
+

&#188;

¼
+

&#189;

½
+

&#190;

¾
+

&#191;

¿
+

&#192;

À
+

&#193;

Á
+

&#194;

Â
+

&#195;

Ã
+

&#196;

Ä
+

&#197;

Å
+

&#198;

Æ
+

&#199;

Ç
+

&#200;

È
+

&#201;

É
+

&#202;

Ê
+

&#203;

Ë
+

&#204;

Ì
+

&#205;

Í
+

&#206;

Î
+

&#207;

Ï
+

&#208;

Ð
+

&#209;

Ñ
+

&#210;

Ò
+

&#211;

Ó
+

&#212;

Ô
+

&#213;

Õ
+

&#214;

Ö
+

&#215;

×
+

&#216;

Ø
+

&#217;

Ù
+

&#218;

Ú
+

&#219;

Û
+

&#220;

Ü
+

&#221;

Ý
+

&#222;

Þ
+

&#223;

ß
+

&#224;

à
+

&#225;

á
+

&#226;

â
+

&#227;

ã
+

&#228;

ä
+

&#229;

å
+

&#230;

æ
+

&#231;

ç
+

&#232;

è
+

&#233;

é
+

&#234;

ê
+

&#235;

ë
+

&#236;

ì
+

&#237;

í
+

&#238;

î
+

&#239;

ï
+

&#240;

ð
+

&#241;

ñ
+

&#242;

ò
+

&#243;

ó
+

&#244;

ô
+

&#245;

õ
+

&#246;

ö
+

&#247;

÷
+

&#248;

ø
+

&#249;

ù
+

&#250;

ú
+

&#251;

û
+

&#252;

ü
+

&#253;

ý
+

&#254;

þ
+

&#255;

ÿ
+

&#338;

Œ
+

&#339;

œ
+

&#376;

Ÿ
+

&#710;

ˆ
+

&#732;

˜
+

&#8192;

 
+

&#8193;

+

&#8194;

+

&#8195;

+

&#8196;

+

&#8197;

+

&#8198;

+

&#8199;

+

&#8200;

+

&#8201;

+

&#8202;

+

&#8208;

+

&#8209;

+

&#8210;

+

&#8211;

+

&#8212;

+

&#8216;

+

&#8217;

+

&#8218;

+

&#8220;

+

&#8221;

+

&#8222;

+

&#8226;

+

&#8230;

+

&#8239;

+

&#8249;

+

&#8250;

+

&#8287;

+

&#8364;

+

&#8482;

+

&#9724;

+

&#64257;

+

&#64258;

+

&#64259;

+

&#64260;

+
+
+ + +
+
+ + +
+ +
+ +
+
+
+

Installing Webfonts

+ +

Webfonts are supported by all major browser platforms but not all in the same way. There are currently four different font formats that must be included in order to target all browsers. This includes TTF, WOFF, EOT and SVG.

+ +

1. Upload your webfonts

+

You must upload your webfont kit to your website. They should be in or near the same directory as your CSS files.

+ +

2. Include the webfont stylesheet

+

A special CSS @font-face declaration helps the various browsers select the appropriate font it needs without causing you a bunch of headaches. Learn more about this syntax by reading the Fontspring blog post about it. The code for it is as follows:

+ + + +@font-face{ + font-family: 'MyWebFont'; + src: url('WebFont.eot'); + src: url('WebFont.eot?#iefix') format('embedded-opentype'), + url('WebFont.woff') format('woff'), + url('WebFont.ttf') format('truetype'), + url('WebFont.svg#webfont') format('svg'); +} + + +

We've already gone ahead and generated the code for you. All you have to do is link to the stylesheet in your HTML, like this:

+ <link rel="stylesheet" href="stylesheet.css" type="text/css" charset="utf-8" /> + +

3. Modify your own stylesheet

+

To take advantage of your new fonts, you must tell your stylesheet to use them. Look at the original @font-face declaration above and find the property called "font-family." The name linked there will be what you use to reference the font. Prepend that webfont name to the font stack in the "font-family" property, inside the selector you want to change. For example:

+p { font-family: 'WebFont', Arial, sans-serif; } + +

4. Test

+

Getting webfonts to work cross-browser can be tricky. Use the information in the sidebar to help you if you find that fonts aren't loading in a particular browser.

+
+ + +
+ +
+ +
+ +
+ + \ No newline at end of file diff --git a/nationchains/static/fonts/cantarell-italic-webfont.woff b/nationchains/static/fonts/cantarell-italic-webfont.woff new file mode 100755 index 0000000..0ebdd89 Binary files /dev/null and b/nationchains/static/fonts/cantarell-italic-webfont.woff differ diff --git a/nationchains/static/fonts/cantarell-italic-webfont.woff2 b/nationchains/static/fonts/cantarell-italic-webfont.woff2 new file mode 100755 index 0000000..2d36bfd Binary files /dev/null and b/nationchains/static/fonts/cantarell-italic-webfont.woff2 differ diff --git a/nationchains/static/fonts/cantarell-regular-demo.html b/nationchains/static/fonts/cantarell-regular-demo.html new file mode 100755 index 0000000..fe19bce --- /dev/null +++ b/nationchains/static/fonts/cantarell-regular-demo.html @@ -0,0 +1,622 @@ + + + + + + + + + + + + + Cantarell Regular Specimen + + + + + + +
+ + + +
+ + +
+ +
+
+
AaBb
+
+
+ +
+
A​B​C​D​E​F​G​H​I​J​K​L​M​N​O​P​Q​R​S​T​U​V​W​X​Y​Z​a​b​c​d​e​f​g​h​i​j​k​l​m​n​o​p​q​r​s​t​u​v​w​x​y​z​1​2​3​4​5​6​7​8​9​0​&​.​,​?​!​@​(​)​#​$​%​*​+​-​=​:​;
+
+
+
+ + + + + + + + + + + + + + + + +
10abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
11abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
12abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
13abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
14abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
16abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
18abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
20abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
24abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
30abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
36abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
48abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
60abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
72abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
90abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+ +
+ +
+ + + +
+ + +
+
◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼body
body
body
body
+
+ bodyCantarell Regular +
+
+ bodyArial +
+
+ bodyVerdana +
+
+ bodyGeorgia +
+ + + +
+ + +
+ +
+

10.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

11.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

12.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

13.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+
+
+

14.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

16.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

18.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+ +
+ +
+ +
+
+

20.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+

24.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+ +
+ +
+ +
+
+

30.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+ +
+ + + +
+
+

10.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

11.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

12.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

13.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+ +
+
+

14.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

16.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+

18.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+ +
+
+ +
+ +
+
+

20.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+

24.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+ +
+ +
+ +
+
+

30.Aenean lacinia bibendum nulla sed consectetur. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Nullam id dolor id nibh ultricies vehicula ut id elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nulla vitae elit libero, a pharetra augue.

+
+
+ +
+ + + + +
+ +
+ +
+ +
+

Lorem Ipsum Dolor

+

Etiam porta sem malesuada magna mollis euismod

+ + +
+
+
+
+

Donec sed odio dui. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.

+ + +

Pellentesque ornare sem

+ +

Maecenas sed diam eget risus varius blandit sit amet non magna. Maecenas faucibus mollis interdum. Donec ullamcorper nulla non metus auctor fringilla. Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam id dolor id nibh ultricies vehicula ut id elit.

+ +

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus.

+ +

Nulla vitae elit libero, a pharetra augue. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Aenean lacinia bibendum nulla sed consectetur.

+ +

Nullam quis risus eget urna mollis ornare vel eu leo. Nullam quis risus eget urna mollis ornare vel eu leo. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec ullamcorper nulla non metus auctor fringilla.

+ +

Cras mattis consectetur

+ +

Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Aenean lacinia bibendum nulla sed consectetur. Integer posuere erat a ante venenatis dapibus posuere velit aliquet. Cras mattis consectetur purus sit amet fermentum.

+ +

Nullam id dolor id nibh ultricies vehicula ut id elit. Nullam quis risus eget urna mollis ornare vel eu leo. Cras mattis consectetur purus sit amet fermentum.

+
+ + +
+ +
+ + + + + + +
+
+
+ +

Language Support

+

The subset of Cantarell Regular in this kit supports the following languages:
+ + Albanian, Basque, Breton, Chamorro, Danish, Dutch, English, Faroese, Finnish, French, Frisian, Galician, German, Icelandic, Italian, Malagasy, Norwegian, Portuguese, Spanish, Alsatian, Aragonese, Arapaho, Arrernte, Asturian, Aymara, Bislama, Cebuano, Corsican, Fijian, French_creole, Genoese, Gilbertese, Greenlandic, Haitian_creole, Hiligaynon, Hmong, Hopi, Ibanag, Iloko_ilokano, Indonesian, Interglossa_glosa, Interlingua, Irish_gaelic, Jerriais, Lojban, Lombard, Luxembourgeois, Manx, Mohawk, Norfolk_pitcairnese, Occitan, Oromo, Pangasinan, Papiamento, Piedmontese, Potawatomi, Rhaeto-romance, Romansh, Rotokas, Sami_lule, Samoan, Sardinian, Scots_gaelic, Seychelles_creole, Shona, Sicilian, Somali, Southern_ndebele, Swahili, Swati_swazi, Tagalog_filipino_pilipino, Tetum, Tok_pisin, Uyghur_latinized, Volapuk, Walloon, Warlpiri, Xhosa, Yapese, Zulu, Latinbasic, Ubasic, Demo

+

Glyph Chart

+

The subset of Cantarell Regular in this kit includes all the glyphs listed below. Unicode entities are included above each glyph to help you insert individual characters into your layout.

+
+ +

&#13;

+

&#32;

+

&#33;

!
+

&#34;

"
+

&#35;

#
+

&#36;

$
+

&#37;

%
+

&#38;

&
+

&#39;

'
+

&#40;

(
+

&#41;

)
+

&#42;

*
+

&#43;

+
+

&#44;

,
+

&#45;

-
+

&#46;

.
+

&#47;

/
+

&#48;

0
+

&#49;

1
+

&#50;

2
+

&#51;

3
+

&#52;

4
+

&#53;

5
+

&#54;

6
+

&#55;

7
+

&#56;

8
+

&#57;

9
+

&#58;

:
+

&#59;

;
+

&#60;

<
+

&#61;

=
+

&#62;

>
+

&#63;

?
+

&#64;

@
+

&#65;

A
+

&#66;

B
+

&#67;

C
+

&#68;

D
+

&#69;

E
+

&#70;

F
+

&#71;

G
+

&#72;

H
+

&#73;

I
+

&#74;

J
+

&#75;

K
+

&#76;

L
+

&#77;

M
+

&#78;

N
+

&#79;

O
+

&#80;

P
+

&#81;

Q
+

&#82;

R
+

&#83;

S
+

&#84;

T
+

&#85;

U
+

&#86;

V
+

&#87;

W
+

&#88;

X
+

&#89;

Y
+

&#90;

Z
+

&#91;

[
+

&#92;

\
+

&#93;

]
+

&#94;

^
+

&#95;

_
+

&#96;

`
+

&#97;

a
+

&#98;

b
+

&#99;

c
+

&#100;

d
+

&#101;

e
+

&#102;

f
+

&#103;

g
+

&#104;

h
+

&#105;

i
+

&#106;

j
+

&#107;

k
+

&#108;

l
+

&#109;

m
+

&#110;

n
+

&#111;

o
+

&#112;

p
+

&#113;

q
+

&#114;

r
+

&#115;

s
+

&#116;

t
+

&#117;

u
+

&#118;

v
+

&#119;

w
+

&#120;

x
+

&#121;

y
+

&#122;

z
+

&#123;

{
+

&#124;

|
+

&#125;

}
+

&#126;

~
+

&#160;

 
+

&#161;

¡
+

&#162;

¢
+

&#163;

£
+

&#164;

¤
+

&#165;

¥
+

&#166;

¦
+

&#167;

§
+

&#168;

¨
+

&#169;

©
+

&#170;

ª
+

&#171;

«
+

&#172;

¬
+

&#173;

­
+

&#174;

®
+

&#175;

¯
+

&#176;

°
+

&#177;

±
+

&#178;

²
+

&#179;

³
+

&#180;

´
+

&#181;

µ
+

&#182;

+

&#183;

·
+

&#184;

¸
+

&#185;

¹
+

&#186;

º
+

&#187;

»
+

&#188;

¼
+

&#189;

½
+

&#190;

¾
+

&#191;

¿
+

&#192;

À
+

&#193;

Á
+

&#194;

Â
+

&#195;

Ã
+

&#196;

Ä
+

&#197;

Å
+

&#198;

Æ
+

&#199;

Ç
+

&#200;

È
+

&#201;

É
+

&#202;

Ê
+

&#203;

Ë
+

&#204;

Ì
+

&#205;

Í
+

&#206;

Î
+

&#207;

Ï
+

&#208;

Ð
+

&#209;

Ñ
+

&#210;

Ò
+

&#211;

Ó
+

&#212;

Ô
+

&#213;

Õ
+

&#214;

Ö
+

&#215;

×
+

&#216;

Ø
+

&#217;

Ù
+

&#218;

Ú
+

&#219;

Û
+

&#220;

Ü
+

&#221;

Ý
+

&#222;

Þ
+

&#223;

ß
+

&#224;

à
+

&#225;

á
+

&#226;

â
+

&#227;

ã
+

&#228;

ä
+

&#229;

å
+

&#230;

æ
+

&#231;

ç
+

&#232;

è
+

&#233;

é
+

&#234;

ê
+

&#235;

ë
+

&#236;

ì
+

&#237;

í
+

&#238;

î
+

&#239;

ï
+

&#240;

ð
+

&#241;

ñ
+

&#242;

ò
+

&#243;

ó
+

&#244;

ô
+

&#245;

õ
+

&#246;

ö
+

&#247;

÷
+

&#248;

ø
+

&#249;

ù
+

&#250;

ú
+

&#251;

û
+

&#252;

ü
+

&#253;

ý
+

&#254;

þ
+

&#255;

ÿ
+

&#338;

Œ
+

&#339;

œ
+

&#376;

Ÿ
+

&#710;

ˆ
+

&#732;

˜
+

&#8192;

 
+

&#8193;

+

&#8194;

+

&#8195;

+

&#8196;

+

&#8197;

+

&#8198;

+

&#8199;

+

&#8200;

+

&#8201;

+

&#8202;

+

&#8208;

+

&#8209;

+

&#8210;

+

&#8211;

+

&#8212;

+

&#8216;

+

&#8217;

+

&#8218;

+

&#8220;

+

&#8221;

+

&#8222;

+

&#8226;

+

&#8230;

+

&#8239;

+

&#8249;

+

&#8250;

+

&#8287;

+

&#8364;

+

&#8482;

+

&#9724;

+

&#64257;

+

&#64258;

+

&#64259;

+

&#64260;

+
+
+ + +
+
+ + +
+ +
+ +
+
+
+

Installing Webfonts

+ +

Webfonts are supported by all major browser platforms but not all in the same way. There are currently four different font formats that must be included in order to target all browsers. This includes TTF, WOFF, EOT and SVG.

+ +

1. Upload your webfonts

+

You must upload your webfont kit to your website. They should be in or near the same directory as your CSS files.

+ +

2. Include the webfont stylesheet

+

A special CSS @font-face declaration helps the various browsers select the appropriate font it needs without causing you a bunch of headaches. Learn more about this syntax by reading the Fontspring blog post about it. The code for it is as follows:

+ + + +@font-face{ + font-family: 'MyWebFont'; + src: url('WebFont.eot'); + src: url('WebFont.eot?#iefix') format('embedded-opentype'), + url('WebFont.woff') format('woff'), + url('WebFont.ttf') format('truetype'), + url('WebFont.svg#webfont') format('svg'); +} + + +

We've already gone ahead and generated the code for you. All you have to do is link to the stylesheet in your HTML, like this:

+ <link rel="stylesheet" href="stylesheet.css" type="text/css" charset="utf-8" /> + +

3. Modify your own stylesheet

+

To take advantage of your new fonts, you must tell your stylesheet to use them. Look at the original @font-face declaration above and find the property called "font-family." The name linked there will be what you use to reference the font. Prepend that webfont name to the font stack in the "font-family" property, inside the selector you want to change. For example:

+p { font-family: 'WebFont', Arial, sans-serif; } + +

4. Test

+

Getting webfonts to work cross-browser can be tricky. Use the information in the sidebar to help you if you find that fonts aren't loading in a particular browser.

+
+ + +
+ +
+ +
+ +
+ + \ No newline at end of file diff --git a/nationchains/static/fonts/cantarell-regular-webfont.woff b/nationchains/static/fonts/cantarell-regular-webfont.woff new file mode 100755 index 0000000..dd8fb46 Binary files /dev/null and b/nationchains/static/fonts/cantarell-regular-webfont.woff differ diff --git a/nationchains/static/fonts/cantarell-regular-webfont.woff2 b/nationchains/static/fonts/cantarell-regular-webfont.woff2 new file mode 100755 index 0000000..1f55bcd Binary files /dev/null and b/nationchains/static/fonts/cantarell-regular-webfont.woff2 differ diff --git a/nationchains/static/fonts/generator_config.txt b/nationchains/static/fonts/generator_config.txt new file mode 100755 index 0000000..81e64f6 --- /dev/null +++ b/nationchains/static/fonts/generator_config.txt @@ -0,0 +1,5 @@ +# Font Squirrel Font-face Generator Configuration File +# Upload this file to the generator to recreate the settings +# you used to create these fonts. + +{"mode":"optimal","formats":["woff","woff2"],"tt_instructor":"default","fix_gasp":"xy","fix_vertical_metrics":"Y","metrics_ascent":"","metrics_descent":"","metrics_linegap":"","add_spaces":"Y","add_hyphens":"Y","fallback":"none","fallback_custom":"100","options_subset":"basic","subset_custom":"","subset_custom_range":"","subset_ot_features_list":"","css_stylesheet":"stylesheet.css","filename_suffix":"-webfont","emsquare":"2048","spacing_adjustment":"0"} \ No newline at end of file diff --git a/nationchains/static/fonts/specimen_files/grid_12-825-55-15.css b/nationchains/static/fonts/specimen_files/grid_12-825-55-15.css new file mode 100755 index 0000000..3d6aef7 --- /dev/null +++ b/nationchains/static/fonts/specimen_files/grid_12-825-55-15.css @@ -0,0 +1,129 @@ +/*Notes about grid: +Columns: 12 +Grid Width: 825px +Column Width: 55px +Gutter Width: 15px +-------------------------------*/ + + + +.section {margin-bottom: 18px; +} +.section:after {content: ".";display: block;height: 0;clear: both;visibility: hidden;} +.section {*zoom: 1;} + +.section .firstcolumn, +.section .firstcol {margin-left: 0;} + + +/* Border on left hand side of a column. */ +.border { + padding-left: 7px; + margin-left: 7px; + border-left: 1px solid #eee; +} + +/* Border with more whitespace, spans one column. */ +.colborder { + padding-left: 42px; + margin-left: 42px; + border-left: 1px solid #eee; +} + + + +/* The Grid Classes */ +.grid1, .grid1_2cols, .grid1_3cols, .grid1_4cols, .grid2, .grid2_3cols, .grid2_4cols, .grid3, .grid3_2cols, .grid3_4cols, .grid4, .grid4_3cols, .grid5, .grid5_2cols, .grid5_3cols, .grid5_4cols, .grid6, .grid6_4cols, .grid7, .grid7_2cols, .grid7_3cols, .grid7_4cols, .grid8, .grid8_3cols, .grid9, .grid9_2cols, .grid9_4cols, .grid10, .grid10_3cols, .grid10_4cols, .grid11, .grid11_2cols, .grid11_3cols, .grid11_4cols, .grid12 +{margin-left: 15px;float: left;display: inline; overflow: hidden;} + + +.width1, .grid1, .span-1 {width: 55px;} +.width1_2cols,.grid1_2cols {width: 20px;} +.width1_3cols,.grid1_3cols {width: 8px;} +.width1_4cols,.grid1_4cols {width: 2px;} +.input_width1 {width: 49px;} + +.width2, .grid2, .span-2 {width: 125px;} +.width2_3cols,.grid2_3cols {width: 31px;} +.width2_4cols,.grid2_4cols {width: 20px;} +.input_width2 {width: 119px;} + +.width3, .grid3, .span-3 {width: 195px;} +.width3_2cols,.grid3_2cols {width: 90px;} +.width3_4cols,.grid3_4cols {width: 37px;} +.input_width3 {width: 189px;} + +.width4, .grid4, .span-4 {width: 265px;} +.width4_3cols,.grid4_3cols {width: 78px;} +.input_width4 {width: 259px;} + +.width5, .grid5, .span-5 {width: 335px;} +.width5_2cols,.grid5_2cols {width: 160px;} +.width5_3cols,.grid5_3cols {width: 101px;} +.width5_4cols,.grid5_4cols {width: 72px;} +.input_width5 {width: 329px;} + +.width6, .grid6, .span-6 {width: 405px;} +.width6_4cols,.grid6_4cols {width: 90px;} +.input_width6 {width: 399px;} + +.width7, .grid7, .span-7 {width: 475px;} +.width7_2cols,.grid7_2cols {width: 230px;} +.width7_3cols,.grid7_3cols {width: 148px;} +.width7_4cols,.grid7_4cols {width: 107px;} +.input_width7 {width: 469px;} + +.width8, .grid8, .span-8 {width: 545px;} +.width8_3cols,.grid8_3cols {width: 171px;} +.input_width8 {width: 539px;} + +.width9, .grid9, .span-9 {width: 615px;} +.width9_2cols,.grid9_2cols {width: 300px;} +.width9_4cols,.grid9_4cols {width: 142px;} +.input_width9 {width: 609px;} + +.width10, .grid10, .span-10 {width: 685px;} +.width10_3cols,.grid10_3cols {width: 218px;} +.width10_4cols,.grid10_4cols {width: 160px;} +.input_width10 {width: 679px;} + +.width11, .grid11, .span-11 {width: 755px;} +.width11_2cols,.grid11_2cols {width: 370px;} +.width11_3cols,.grid11_3cols {width: 241px;} +.width11_4cols,.grid11_4cols {width: 177px;} +.input_width11 {width: 749px;} + +.width12, .grid12, .span-12 {width: 825px;} +.input_width12 {width: 819px;} + +/* Subdivided grid spaces */ +.emptycols_left1, .prepend-1 {padding-left: 70px;} +.emptycols_right1, .append-1 {padding-right: 70px;} +.emptycols_left2, .prepend-2 {padding-left: 140px;} +.emptycols_right2, .append-2 {padding-right: 140px;} +.emptycols_left3, .prepend-3 {padding-left: 210px;} +.emptycols_right3, .append-3 {padding-right: 210px;} +.emptycols_left4, .prepend-4 {padding-left: 280px;} +.emptycols_right4, .append-4 {padding-right: 280px;} +.emptycols_left5, .prepend-5 {padding-left: 350px;} +.emptycols_right5, .append-5 {padding-right: 350px;} +.emptycols_left6, .prepend-6 {padding-left: 420px;} +.emptycols_right6, .append-6 {padding-right: 420px;} +.emptycols_left7, .prepend-7 {padding-left: 490px;} +.emptycols_right7, .append-7 {padding-right: 490px;} +.emptycols_left8, .prepend-8 {padding-left: 560px;} +.emptycols_right8, .append-8 {padding-right: 560px;} +.emptycols_left9, .prepend-9 {padding-left: 630px;} +.emptycols_right9, .append-9 {padding-right: 630px;} +.emptycols_left10, .prepend-10 {padding-left: 700px;} +.emptycols_right10, .append-10 {padding-right: 700px;} +.emptycols_left11, .prepend-11 {padding-left: 770px;} +.emptycols_right11, .append-11 {padding-right: 770px;} +.pull-1 {margin-left: -70px;} +.push-1 {margin-right: -70px;margin-left: 18px;float: right;} +.pull-2 {margin-left: -140px;} +.push-2 {margin-right: -140px;margin-left: 18px;float: right;} +.pull-3 {margin-left: -210px;} +.push-3 {margin-right: -210px;margin-left: 18px;float: right;} +.pull-4 {margin-left: -280px;} +.push-4 {margin-right: -280px;margin-left: 18px;float: right;} \ No newline at end of file diff --git a/nationchains/static/fonts/specimen_files/specimen_stylesheet.css b/nationchains/static/fonts/specimen_files/specimen_stylesheet.css new file mode 100755 index 0000000..aecc43c --- /dev/null +++ b/nationchains/static/fonts/specimen_files/specimen_stylesheet.css @@ -0,0 +1,396 @@ +@import url('grid_12-825-55-15.css'); + +/* + CSS Reset by Eric Meyer - Released under Public Domain + http://meyerweb.com/eric/tools/css/reset/ +*/ +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, font, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, table, +caption, tbody, tfoot, thead, tr, th, td + {margin: 0;padding: 0;border: 0;outline: 0; + font-size: 100%;vertical-align: baseline; + background: transparent;} +body {line-height: 1;} +ol, ul {list-style: none;} +blockquote, q {quotes: none;} +blockquote:before, blockquote:after, +q:before, q:after {content: ''; content: none;} +:focus {outline: 0;} +ins {text-decoration: none;} +del {text-decoration: line-through;} +table {border-collapse: collapse;border-spacing: 0;} + + + + +body { + color: #000; + background-color: #dcdcdc; +} + +a { + text-decoration: none; + color: #1883ba; +} + +h1{ + font-size: 32px; + font-weight: normal; + font-style: normal; + margin-bottom: 18px; +} + +h2{ + font-size: 18px; +} + +#container { + width: 865px; + margin: 0px auto; +} + + +#header { + padding: 20px; + font-size: 36px; + background-color: #000; + color: #fff; +} + +#header span { + color: #666; +} +#main_content { + background-color: #fff; + padding: 60px 20px 20px; +} + + +#footer p { + margin: 0; + padding-top: 10px; + padding-bottom: 50px; + color: #333; + font: 10px Arial, sans-serif; +} + +.tabs { + width: 100%; + height: 31px; + background-color: #444; +} +.tabs li { + float: left; + margin: 0; + overflow: hidden; + background-color: #444; +} +.tabs li a { + display: block; + color: #fff; + text-decoration: none; + font: bold 11px/11px 'Arial'; + text-transform: uppercase; + padding: 10px 15px; + border-right: 1px solid #fff; +} + +.tabs li a:hover { + background-color: #00b3ff; + +} + +.tabs li.active a { + color: #000; + background-color: #fff; +} + + + +div.huge { + + font-size: 300px; + line-height: 1em; + padding: 0; + letter-spacing: -.02em; + overflow: hidden; +} +div.glyph_range { + font-size: 72px; + line-height: 1.1em; +} + +.size10{ font-size: 10px; } +.size11{ font-size: 11px; } +.size12{ font-size: 12px; } +.size13{ font-size: 13px; } +.size14{ font-size: 14px; } +.size16{ font-size: 16px; } +.size18{ font-size: 18px; } +.size20{ font-size: 20px; } +.size24{ font-size: 24px; } +.size30{ font-size: 30px; } +.size36{ font-size: 36px; } +.size48{ font-size: 48px; } +.size60{ font-size: 60px; } +.size72{ font-size: 72px; } +.size90{ font-size: 90px; } + + +.psample_row1 { height: 120px;} +.psample_row1 { height: 120px;} +.psample_row2 { height: 160px;} +.psample_row3 { height: 160px;} +.psample_row4 { height: 160px;} + +.psample { + overflow: hidden; + position: relative; +} +.psample p { + line-height: 1.3em; + display: block; + overflow: hidden; + margin: 0; +} + +.psample span { + margin-right: .5em; +} + +.white_blend { + width: 100%; + height: 61px; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVkAAAA9CAYAAAAH4BojAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAO1JREFUeNrs3TsKgFAMRUE/eer+NxztxMYuEWQG3ECKwwUF58ycAKixOAGAyAKILAAiCyCyACILgMgCiCyAyAIgsgAiCyCyAIgsgMgCiCwAIgsgsgAiC4DIAogsACIL0CWuZ3UGgLrIhjMA1EV2OAOAJQtgyQLwjOzmDAAiCyCyAIgsQFtkd2cAEFkAkQVAZAHaIns4A4AlC2DJAiCyACILILIAiCzAV5H1dQGAJQsgsgCILIDIAvwisl58AViyAJYsACILILIAIgvAe2T9EhxAZAFEFgCRBeiL7HAGgLrIhjMAWLIAliwAt1OAAQDwygTBulLIlQAAAABJRU5ErkJggg==); + position: absolute; + bottom: 0; +} +.black_blend { + width: 100%; + height: 61px; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVkAAAA9CAYAAAAH4BojAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPJJREFUeNrs3TEKhTAQRVGjibr/9QoxhY2N3Ywo50A28IrLwP9g6b1PAMSYTQAgsgAiC4DIAogsgMgCILIAIgsgsgCILIDIAogsACILILIAIguAyAKILIDIAiCyACILgMgCZCnjLWYAiFGvB0BQZJsZAFyyAC5ZAO6RXc0AILIAIguAyAKkRXYzA4DIAogsACILkBbZ3QwALlkAlywAIgsgsgAiC4DIArwVWf8uAHDJAogsACILILIAv4isH74AXLIALlkARBZAZAFEFoDnyPokOIDIAogsACILkBfZZgaAuMhWMwC4ZAE+p4x3mAEgxinAAJ+XBbPWGkwAAAAAAElFTkSuQmCC); + position: absolute; + bottom: 0; +} +.fullreverse { + background: #000 !important; + color: #fff !important; + margin-left: -20px; + padding-left: 20px; + margin-right: -20px; + padding-right: 20px; + padding: 20px; + margin-bottom:0; +} + + +.sample_table td { + padding-top: 3px; + padding-bottom:5px; + padding-left: 5px; + vertical-align: middle; + line-height: 1.2em; +} + +.sample_table td:first-child { + background-color: #eee; + text-align: right; + padding-right: 5px; + padding-left: 0; + padding: 5px; + font: 11px/12px "Courier New", Courier, mono; +} + +code { + white-space: pre; + background-color: #eee; + display: block; + padding: 10px; + margin-bottom: 18px; + overflow: auto; +} + + +.bottom,.last {margin-bottom:0 !important; padding-bottom:0 !important;} + +.box { + padding: 18px; + margin-bottom: 18px; + background: #eee; +} + +.reverse,.reversed { background: #000 !important;color: #fff !important; border: none !important;} + +#bodycomparison { + position: relative; + overflow: hidden; + font-size: 72px; + height: 90px; + white-space: nowrap; +} + +#bodycomparison div{ + font-size: 72px; + line-height: 90px; + display: inline; + margin: 0 15px 0 0; + padding: 0; +} + +#bodycomparison div span{ + font: 10px Arial; + position: absolute; + left: 0; +} +#xheight { + float: none; + position: absolute; + color: #d9f3ff; + font-size: 72px; + line-height: 90px; +} + +.fontbody { + position: relative; +} +.arialbody{ + font-family: Arial; + position: relative; +} +.verdanabody{ + font-family: Verdana; + position: relative; +} +.georgiabody{ + font-family: Georgia; + position: relative; +} + +/* @group Layout page + */ + +#layout h1 { + font-size: 36px; + line-height: 42px; + font-weight: normal; + font-style: normal; +} + +#layout h2 { + font-size: 24px; + line-height: 23px; + font-weight: normal; + font-style: normal; +} + +#layout h3 { + font-size: 22px; + line-height: 1.4em; + margin-top: 1em; + font-weight: normal; + font-style: normal; +} + + +#layout p.byline { + font-size: 12px; + margin-top: 18px; + line-height: 12px; + margin-bottom: 0; +} +#layout p { + font-size: 14px; + line-height: 21px; + margin-bottom: .5em; +} + +#layout p.large{ + font-size: 18px; + line-height: 26px; +} + +#layout .sidebar p{ + font-size: 12px; + line-height: 1.4em; +} + +#layout p.caption { + font-size: 10px; + margin-top: -16px; + margin-bottom: 18px; +} + +/* @end */ + +/* @group Glyphs */ + +#glyph_chart div{ + background-color: #d9f3ff; + color: black; + float: left; + font-size: 36px; + height: 1.2em; + line-height: 1.2em; + margin-bottom: 1px; + margin-right: 1px; + text-align: center; + width: 1.2em; + position: relative; + padding: .6em .2em .2em; +} + +#glyph_chart div p { + position: absolute; + left: 0; + top: 0; + display: block; + text-align: center; + font: bold 9px Arial, sans-serif; + background-color: #3a768f; + width: 100%; + color: #fff; + padding: 2px 0; +} + + +#glyphs h1 { + font-family: Arial, sans-serif; +} +/* @end */ + +/* @group Installing */ + +#installing { + font: 13px Arial, sans-serif; +} + +#installing p, +#glyphs p{ + line-height: 1.2em; + margin-bottom: 18px; + font: 13px Arial, sans-serif; +} + + + +#installing h3{ + font-size: 15px; + margin-top: 18px; +} + +/* @end */ + +#rendering h1 { + font-family: Arial, sans-serif; +} +.render_table td { + font: 11px "Courier New", Courier, mono; + vertical-align: middle; +} + + diff --git a/nationchains/static/fonts/stylesheet.css b/nationchains/static/fonts/stylesheet.css new file mode 100755 index 0000000..325365e --- /dev/null +++ b/nationchains/static/fonts/stylesheet.css @@ -0,0 +1,12 @@ +/*! Generated by Font Squirrel (https://www.fontsquirrel.com) on March 24, 2022 */ + + + +@font-face { + font-family: 'cantarelloblique'; + src: url('cantarell-italic-webfont.woff2') format('woff2'), + url('cantarell-italic-webfont.woff') format('woff'); + font-weight: normal; + font-style: normal; + +} \ No newline at end of file diff --git a/nationchains/static/img/avataranonymous.png b/nationchains/static/img/avataranonymous.png new file mode 100755 index 0000000..4063253 Binary files /dev/null and b/nationchains/static/img/avataranonymous.png differ diff --git a/nationchains/static/img/avataranonymous1.png b/nationchains/static/img/avataranonymous1.png new file mode 100755 index 0000000..fadb45a Binary files /dev/null and b/nationchains/static/img/avataranonymous1.png differ diff --git a/nationchains/static/img/avataranonymous2.png b/nationchains/static/img/avataranonymous2.png new file mode 100755 index 0000000..687c446 Binary files /dev/null and b/nationchains/static/img/avataranonymous2.png differ diff --git a/nationchains/static/img/chartegraphique/codecouleur.png b/nationchains/static/img/chartegraphique/codecouleur.png new file mode 100755 index 0000000..eae586f Binary files /dev/null and b/nationchains/static/img/chartegraphique/codecouleur.png differ diff --git a/nationchains/static/img/chartegraphique/favicon.png b/nationchains/static/img/chartegraphique/favicon.png new file mode 100755 index 0000000..efd5d56 Binary files /dev/null and b/nationchains/static/img/chartegraphique/favicon.png differ diff --git a/nationchains/static/img/chartegraphique/logo_bgplein.png b/nationchains/static/img/chartegraphique/logo_bgplein.png new file mode 100755 index 0000000..444e055 Binary files /dev/null and b/nationchains/static/img/chartegraphique/logo_bgplein.png differ diff --git a/nationchains/static/img/chartegraphique/logo_bgtransparent.png b/nationchains/static/img/chartegraphique/logo_bgtransparent.png new file mode 100644 index 0000000..5c28dc1 Binary files /dev/null and b/nationchains/static/img/chartegraphique/logo_bgtransparent.png differ diff --git a/nationchains/static/img/chartegraphique/logocarre_bgplein.png b/nationchains/static/img/chartegraphique/logocarre_bgplein.png new file mode 100755 index 0000000..c2fea91 Binary files /dev/null and b/nationchains/static/img/chartegraphique/logocarre_bgplein.png differ diff --git a/nationchains/static/img/chartegraphique/planchelogo.svg b/nationchains/static/img/chartegraphique/planchelogo.svg new file mode 100755 index 0000000..6bd3855 --- /dev/null +++ b/nationchains/static/img/chartegraphique/planchelogo.svg @@ -0,0 +1,317 @@ + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + ap + X + trib + + ap + X + trib + + X + + X + + ap + X + trib + ap + X + trib + + diff --git a/nationchains/static/img/imgtg.png b/nationchains/static/img/imgtg.png new file mode 100755 index 0000000..5514ad4 Binary files /dev/null and b/nationchains/static/img/imgtg.png differ diff --git a/nationchains/static/img/nations/ants/antsNation.svg b/nationchains/static/img/nations/ants/antsNation.svg new file mode 100644 index 0000000..5ff0def --- /dev/null +++ b/nationchains/static/img/nations/ants/antsNation.svg @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + Openclipart + + + 2006-08-29T16:35:08 + Balanced ant design with specularity + http://openclipart.org/detail/66/ant-by-andy + + + Andy + + + + + animal + ant + black + black & white + bug + clip art + clipart + creature + creepy + glossy + icon + insect + logo + shiny + spooky + + + + + + + + + + + diff --git a/nationchains/testnetwork.html b/nationchains/testnetwork.html new file mode 100755 index 0000000..9766475 --- /dev/null +++ b/nationchains/testnetwork.html @@ -0,0 +1 @@ +ok diff --git a/package.json b/package.json new file mode 100755 index 0000000..2c3aaaf --- /dev/null +++ b/package.json @@ -0,0 +1,130 @@ +{ + "name": "apxtrib", + "version": "0.0.1", + "logo": { + "file": "./nationchains/static/img/chartegraphique/logocarre_bgplein.png" + }, + "description": "A standard conf api based on express.js with basic and usefull component to manage api project", + "main": "apxtrib.js", + "repository": { + "url": "https://gitea.ndda.fr/apxtrib/apxtrib", + "type": "git" + }, + "scripts": { + "apidoc": "apidoc -i routes/ -o apidoc/", + "stoppm2": "pm2 stop apxtrib.js", + "startpm2": "pm2 start apxtrib.js --log-date-format 'DD-MM HH:mm:ss.SSS'", + "restartpm2": "pm2 restart apxtrib.js --log-date-format 'DD-MM HH:mm:ss.SSS'", + "startblockchain": "pm2 start ./models/Blockchains.js --log-date-format 'DD-MM HH:mm:ss:SSS'", + "logpm2": "pm2 logs apxtrib.js --lines 200", + "setup": "node models/Setup.js", + "dev": "node apxtrib.js", + "dev-watch": "nodemon apxtrib.js" + }, + "apidoc": { + "url": "https://apxtrib.crabdance.com/apidoc" + }, + "maintainers": [ + { + "name": "Philippe Colzy", + "email": "support@need-data.com", + "url": "https://need-data.com" + } + ], + "contributors": [ + { + "name": "Antonin Hattabe", + "email": "", + "url": "" + }, + { + "name": "Maxime Serrato", + "email": "", + "url": "" + }, + { + "name": "Charles Filuzeau", + "email": "", + "url": "" + } + ], + "author": { + "name": "patma", + "email": "patma@mail.be", + "url": "" + }, + "license": "MIT", + "dependencies": { + "@editorjs/editorjs": "^2.22.2", + "@fortawesome/fontawesome-free": "^5.15.4", + "@popperjs/core": "^2.11.2", + "@web-component/code-flask": "^0.0.1", + "add-to-calendar-button": "^1.6.1", + "aos": "^3.0.0-beta.6", + "async": "^3.2.0", + "axios": "^0.18.0", + "baunsu": "^0.2.3", + "bcrypt": "^5.0.0", + "bootstrap": "^5.1.3", + "cheerio": "^1.0.0-rc.3", + "cors": "^2.8.4", + "crypto-js": "^4.1.1", + "dns-sync": "^0.2.1", + "express": "^4.16.3", + "feather-icons": "^4.28.0", + "filepond": "^4.30.3", + "filepond-plugin-file-metadata": "^1.0.8", + "filepond-plugin-image-crop": "^2.0.6", + "filepond-plugin-image-edit": "^1.6.3", + "filepond-plugin-image-exif-orientation": "^1.0.11", + "filepond-plugin-image-filter": "^1.0.1", + "filepond-plugin-image-preview": "^4.6.11", + "filepond-plugin-image-validate-size": "^1.2.7", + "flatpickr": "^4.6.9", + "formidable": "^1.2.1", + "fs-extra": "^6.0.1", + "glob": "^7.1.2", + "google-spreadsheet": "^3.1.15", + "html-to-text": "^5.1.1", + "iconv": "^3.0.1", + "jquery": "^3.6.0", + "js-beautify": "^1.14.0", + "jsdom": "^11.11.0", + "jsonfile": "^5.0.0", + "jszip": "^3.7.1", + "juice": "^5.2.0", + "jwt-simple": "^0.5.1", + "libxmljs": "^0.19.10", + "lodash": "^4.17.10", + "luxon": "^2.1.1", + "mailparser": "^2.3.2", + "minifyjs": "^0.2.0", + "moment": "^2.22.1", + "multer": "^1.3.0", + "mustache": "^2.3.0", + "natural": "^0.6.3", + "node-mailjet": "^3.3.4", + "node-mbox": "^1.0.0", + "node-sass": "^6.0.1", + "nodemailer": "^6.1.1", + "nodemailer-smtp-transport": "^2.7.4", + "parse-filepath": "^1.0.2", + "pdf-creator-node": "^2.2.2", + "pm2": "^5.1.2", + "prompt": "^1.2.0", + "qrcode": "^1.3.3", + "request-promise": "^4.2.4", + "rimraf": "^2.6.2", + "sass": "^1.54.5", + "scrape-it": "^5.1.4", + "serialize-javascript": "^5.0.1", + "simplebar": "^5.3.6", + "stripe": "^7.4.0", + "swiper": "^8.0.6", + "uuid": "^3.2.1" + }, + "devDependencies": { + "nodemon": "^1.17.3", + "request": "^2.85.0" + } +} diff --git a/routes/messages.js b/routes/messages.js new file mode 100755 index 0000000..217cc8a --- /dev/null +++ b/routes/messages.js @@ -0,0 +1,63 @@ +const express = require( 'express' ); +const path = require( 'path' ); +// Classes +const Messages = require( '../models/Messages.js' ); +// Middlewares ( prefix, object ) => { +const checkHeaders = require( '../middlewares/checkHeaders' ); +const isAuthenticated = require( '../middlewares/isAuthenticated' ); +const hasAccessrighton = require( '../middlewares/hasAccessrighton' ); +const router = express.Router(); + +router.post( '/', checkHeaders, ( req, res ) => { + /* + add message to (no authentification and accessright needs) : + a tribeid or uuid => create a contact based on email.json or phone.json or email_phone.json + if req.body.orderuuid exist then it store the req.body in /orders/orderuuid.json an order with state = order + */ + // check if a receiver is well identify if not then it send message to all user tribeid to inform ** + if( !req.body.desttribeid ) req.body.desttribeid = req.session.header.xworkon; + if( !req.body.lang ) req.body.lang = req.session.header.xlang; + console.log( '/messages t send for ', req.session.header.xworkon ); + //console.log(' Content: ',req.body); + const result = Messages.postinfo( req.body ); + res.status( result.status ) + .send( result.data ) +} ); + +router.put( '/:objectname/:uuid', checkHeaders, isAuthenticated, ( req, res ) => { + // message that will create an object and sendback an email. + // if objectnane/uuid_lg.json exist ans accessright is ste to U for the user then it replace object data with req.body.key value + // if does not exist and accessright C then it create it with uuid + // then if req.body.tplmessage => render email with data + // No data management are done here, if need you can add plugin to create a workflow based object + // if need specific data check => req.body.callback={tribeidpugin,pluginname,function} will run pluginname.function(data) add data run specific stuf before saved the message object in /objectname/data.uuid_lg/json + let result; + console.log( "object", req.params.objectname ) + if( req.params.objectname == 'notifications' ) { + //uuid is a timestamp + req.body.time = req.params.uuid; + result = Messages.notification( req.body, req.session.header ); + } else { + req.body.uuid = req.params.uuid; + req.body.object = req.params.objectname; + result = Messages.object( req.body, req.session.header ); + } + //console.log( 'result', result ); + res.status( result.status ) + .json( result.data ) +} ); + +router.get( '/user', checkHeaders, isAuthenticated, ( req, res ) => { + // run agregate for tribeid concerned + // + console.log( "request notifiation for user", req.session.header.xpaganid ); + const app = { + tribeid: req.session.header.xapp.split( ':' )[ 0 ], + website: req.session.header.xapp.split( ':' )[ 1 ], + lang: req.session.header.xlang + }; + res.send( Messages.request( req.session.header.xtribe, req.session.header.xpaganid, + req.app.locals.tokens[ req.session.header.xpaganid ].ACCESSRIGHTS, app ) ); +} ); + +module.exports = router; diff --git a/routes/nationchains.js b/routes/nationchains.js new file mode 100755 index 0000000..f651265 --- /dev/null +++ b/routes/nationchains.js @@ -0,0 +1,37 @@ +const express = require( 'express' ); +const config = require( '../config.js' ); + +// Classes +const Nationchains = require( '../models/Nationchains.js' ); +// Middlewares +const checkHeaders = require( '../middlewares/checkHeaders' ); +const isAuthenticated = require( '../middlewares/isAuthenticated' ); +const hasAccessrighton = require( '../middlewares/hasAccessrighton' ); +const router = express.Router(); + +/* +Manage the social world + +@Todo + +Manage a new nation +A major create a nation with at least a town => nation:{name, towns:[]} contracts/nationname.js + contracts/townsname.js +Manage a new towns in a nation => update nation:[nationname:towns:[]} contracts/townname.js + + + + + + + +*/ +router.post( '/push', checkHeaders, ( req, res ) => { + // Get information from other apixtribe instance in req.body + // check req.body.hashnext => means this is a candidate to validate next block + // + // return it's own information back with the last call to Nationchains.synchronize() + res.send( { status: 200, payload: { moreinfo: fs.readFileSync( `${config.tribes}/${config.mayorId}/nationchains/nodes/${config.rootURL}`, 'utf-8' ) } } ) +} ) + + +module.exports = router; diff --git a/routes/odmdb.js b/routes/odmdb.js new file mode 100644 index 0000000..1d039f4 --- /dev/null +++ b/routes/odmdb.js @@ -0,0 +1,19 @@ +const express = require( 'express' ); +const glob = require( 'glob' ); +const path = require( 'path' ); +// Classes +const Odmdb = require( '../models/Odmdb.js' ); +// Middlewares +const checkHeaders = require( '../middlewares/checkHeaders' ); +const isAuthenticated = require( '../middlewares/isAuthenticated' ); +const hasAccessrighton = require( '../middlewares/hasAccessrighton' ); +const router = express.Router(); + +router.get('/searchauth/:objectname/:question',checkHeaders,isAuthenticated,( req, res ) => { + console.log( 'route referentials get all language' + req.params.objectname + '-' + req.params.question ); + const getref = Referentials.getref( true, req.params.source, req.params.idref, req.session.header.xworkon, req.session.header.xlang ); + // Return any status the data if any erreur return empty object + res.jsonp( getref.payload.data ); +} ); + +module.exports = router; diff --git a/routes/outputs.js b/routes/outputs.js new file mode 100755 index 0000000..f3bea37 --- /dev/null +++ b/routes/outputs.js @@ -0,0 +1,65 @@ +// Upload de file +const express = require( 'express' ); +const fs = require( 'fs-extra' ); +// Classes +const UploadFile = require( '../models/UploadFiles' ); +const Outputs = require( '../models/Outputs' ); +//const Outputstest = require('../models/Outputstest'); +// Middlewares +const checkHeaders = require( '../middlewares/checkHeaders' ); +const isAuthenticated = require( '../middlewares/isAuthenticated' ); +const router = express.Router(); + + +router.post( '/ggsheet2json', checkHeaders, async ( req, res ) => { + console.log( 'route outputs sheet to json' ); + let result = await Outputs.ggsheet2json( req.body, req.session.header ); + res.send( result ); +} ); + + + + +// checkHeaders, isuploadFileValid +router.post( '/msg', checkHeaders, async ( req, res ) => { + console.log( 'route outputs msg post ' ); + const envoi = await Outputs.generemsg( req.body, req.session.header ); + res.status( envoi.status ) + .send( { + payload: envoi.payload + } ); +} ); +/*test functionnalité +router.post('/msgtest', checkHeaders, isemailValid, async (req, res) => { + console.log('route outputs msg post en test'); + const envoi = await Outputstest.generemsg(req.body, req.session.header); + res.status(envoi.status).send({ + payload: envoi.payload + }); +}); +*/ +router.post( '/template', checkHeaders, ( req, res ) => { + console.log( 'route outputs post de fichier template ' ); + // a callback can be pass to req.body to run a specific process after upload + const saveFile = UploadFile.addjson( req.body, req.session.header ); + console.log( saveFile ); + res.send( saveFile ); + // res.send({ status: 200, payload: { info: 'fine' } }); +} ); + +router.post( '/pdf', checkHeaders, ( req, res ) => { + console.log( 'route outputs pdf post' ); + Outputs.generepdf( req.body, req.session.header ) + .then( ( doc ) => { + res.status( doc.status ) + .download( doc.payload.data.path, doc.payload.data.name ); + } ) + .catch( ( err ) => { + console.log( err ); + res.status( err.status ) + .send( { payload: err.payload } ); + } ); +} ); + + +module.exports = router; diff --git a/routes/pagans.js b/routes/pagans.js new file mode 100755 index 0000000..4dc96ab --- /dev/null +++ b/routes/pagans.js @@ -0,0 +1,211 @@ +const express = require( 'express' ); +const path = require( 'path' ); + +// Classes +const Pagans = require( '../models/Pagans.js' ); +// Middlewares +const checkHeaders = require( '../middlewares/checkHeaders' ); +const isAuthenticated = require( '../middlewares/isAuthenticated' ); +const hasAccessrighton = require( '../middlewares/hasAccessrighton' ); +const router = express.Router(); +/* +models/Pagans.js +Managed: +/data/tribee/client-Id/users/uuid.json +/searchindex/emails.json {email:uuid} + /login.json {login:uuid} + /uids.json {uuid;[[ + login, + email, + encrypted psw, + accessrights]} + +ACCESSRIGHTS = { +app:{"tribeid:appname":"profil"}, +data:{"tribeid":{object:"CRUDO"}} +} +ACCESSRIGHTS is store into the token and is load into req.session.header.accessrights by hasAccessrighton() middleware + +appname is a website space object /sitewebsrc/appname +website live is strored into /dist source in /src + +This can be managed by maildigitcreator or not. +apixtribe/sitewebs/webapp is the webinterface of apixtribe + +profil: admin / manager / user are key word to give specific access to data into model. Any kind of other profil can exist. It is usefull to manage specific menu in an app. +It is also possible to authorize update a field's object depending of rule into dataManagement/object/ +{ field:X + nouserupdate: "!(['admin','manager'].includes(contexte.profil))", +} + +data allow a user to access tribeid with Create Read Update Delete Own (CRUDO) on each object of a tribeid independantly of any app. + +Create allow to create a new object respecting rules defined into /referentials/dataManagement/object/name.json +Update idem +Delete idem +Owner means it can be Write/Delete if field OWNER contain the UUID that try to act on this object. Usefull to allow someone to fully manage its objects. + +*/ +router.get( '/isauth', checkHeaders, isAuthenticated, ( req, res ) => { + if( req.session.header.xpaganid == "1" ) { + return res.status( 401 ) + .send( { info: "not authenticate" } ); + } else return res.status( 200 ) + .send( { info: "well authenticated" } ) +} ) +router.post( '/login', checkHeaders, async ( req, res ) => { + // console.log('POST /users/login with: ', req.app.locals.header); + /* + Check un mot de passe pour un login pour obtenir un token d'authentification + valable 1 hour, 1 day + @header + @body.LOGIN + @body.PASSWORD + @checkpsw = true check si les 2 mot de passe cryptés correspondent + false bypass le contrôle et permet de générer un token + utile le temps de reinitialisé son mot de passe. + @return + */ + console.log( 'login for ', req.body, "in", req.session.header ) + const log = await Pagans.loginUser( req.session.header, req.body, true ); + console.log( "log user login", log ); + if( log.status == 200 ) { + // update req.app.locals.tokens for this uuid just after login success then next isAuth will be valid + req.app.locals.tokens[ log.data.user.UUID ] = { TOKEN: log.data.user.TOKEN, ACCESSRIGHTS: log.data.user.ACCESSRIGHTS } + console.log( req.app.locals ) + } + return res.status( log.status ) + .send( log.data ); +} ); + + +router.get( '/getlinkwithoutpsw/:email', checkHeaders, async ( req, res ) => { + /* + Permet pour un email existant de renvoyer un email avec un lien valable 1h + @email est le compte pour lequel on demande un accès + Réponse: + Si email n'existe pas on n'envoie pas d'email + Si email existe on envoie un email avec un lien dont le token est valable 1h + + @return + {status:200 ou erreur , + payload:{ + info:[list de key to appear in correct requester langue], + model:'Pagans', + moreinfo: 'texte pour log ' + } + } + */ + console.log( `GET /users/getlinkwithoutpsw for email: ${req.params.email} tribeid :${req.header('X-Client-Id')}` ); + if( !req.params.email ) { + return res.status( 404 ) + .send( { + info: [ 'emailmissing' ], + model: 'Pagans' + } ); + } else { + try { + const getlink = await Pagans.getlinkwithoutpsw( req.params.email, req.session.header ); + console.log( 'getlink', getlink ) + //met à jour le token créer pour le uuid + req.app.locals.tokens[ getlink.data.info.xuuid ] = getlink.data.info.token; + // attention si on relance le serveur le token temporaire est perdu + return res.status( getlink.status ) + .send( getlink.data ); + } catch ( err ) { + console.log( err ) + return res.status( 500 ) + .send( { info: [ 'errServer' ], model: 'Pagans' } ); + } + } +} ); +router.post( '/register', checkHeaders, async ( req, res ) => { + console.log( `POST /users for ${req.session.header.xtribe}` ); + if( req.session.header.xauth == '123123' ) { + // Creation d'un utilisateur avec information de base aucun droit + // On modifie le contenu du form pour n egarder que login/email et psw + // pour le client_id permet de traiter un user en attente de validation + console.log( 'req du post', req ); + } +} ); +router.get( '/info/:listindex', checkHeaders, isAuthenticated, hasAccessrighton( 'users', 'R' ), async ( req, res ) => { + console.log( `get users info on tribeid ${req.session.header.xworkon} for ${req.params.listindex} with accessright`, req.session.header.accessrights.data ); + const result = await Pagans.getinfoPagans( req.session.header.xpresworkon, req.session.header.accessrights, req.params.listindex ); + res.status( result.status ) + .send( result.data ); +} ); +router.get( '/list/:filter/:field', checkHeaders, isAuthenticated, hasAccessrighton( 'users', 'R' ), async ( req, res ) => { + console.log( 'GET /users/list/filtre/champs list for ' + req.session.header.xworkon ); + if( + [ 'admin', 'manager' ].includes( req.session.header.decodetoken[ 'apps' + req.session.header.xworkon + 'profil' ] ) ) { + try { + const userslist = await Pagans.getUserlist( req.session.header, req.params.filter, req.params.field ); + console.log( 'userslist', userslist ); + if( userslist.status == 200 ) { + return res.status( userslist.status ) + .send( userslist.data ); + } + } catch ( err ) { + console.log( err ); + return res.status( 400 ) + .send( { info: 'erreur' } ); + } + } else { + res.status( 403 ) + .send( { + info: [ 'forbiddenAccess' ], + model: 'Pagans' + } ); + } +} ); +router.get( '/uuid/:id', checkHeaders, isAuthenticated, hasAccessrighton( 'users', 'R' ), async ( req, res ) => { + console.log( `GET /users/uuid/${req.params.id}` ); + //console.log('req.app.locals: ', req.app.locals); + //console.log('req.session', req.session); + const result = await Pagans.getUser( req.params.id, req.session.header.xworkon, req.session.header.accessrights ); + res.status( result.status ) + .send( result.data ); +} ); +router.put( '/chgpsw/:id', checkHeaders, isAuthenticated, async ( req, res ) => { + console.log( `PUT update /users/chgpsw/${req.params.id}` ); + try { + const majpsw = await Pagans.updateUserpassword( req.params.id, req.session.header, req.body ); + res.status( majpsw.status ) + .send( majpsw.data ); + } catch ( { + status, + data + } ) { + res.status( status ) + .send( data ); + } +} ); +router.post( '/uuid', checkHeaders, isAuthenticated, hasAccessrighton( 'users', 'C' ), async ( req, res ) => { + console.log( 'POST /users create for ' + req.session.header.xworkon, req.body ); + const usercreate = await Pagans.createUser( req.session.header, req.body ); + return res.status( usercreate.status ) + .send( usercreate.data ); +} ); +router.put( '/uuid/:id', checkHeaders, isAuthenticated, hasAccessrighton( 'users', 'U' ), async ( req, res ) => { + console.log( `PUT update /users/${req.params.id}` ); + // console.log('req.app.locals: ', req.app.locals); + // console.log('req.session', req.session); + try { + const majUser = await Pagans.updateUser( req.params.id, req.session.header, req.body ); + res.status( majUser.status ) + .send( majUser.data ); + } catch ( { + status, + data + } ) { + res.status( status ) + .send( data ); + } +} ); +router.delete( '/uuid/:id', checkHeaders, isAuthenticated, hasAccessrighton( 'users', 'D' ), ( req, res ) => { + console.log( `DELETE /users/uuid/${req.params.id}` ); + const result = Pagans.deleteUser( req.params.id, req.session.header ); + res.status( result.status ) + .send( result.data ); +} ); +module.exports = router; diff --git a/routes/referentials.js b/routes/referentials.js new file mode 100755 index 0000000..73558fb --- /dev/null +++ b/routes/referentials.js @@ -0,0 +1,94 @@ +// Upload de file +const express = require( 'express' ); +const glob = require( 'glob' ); +const path = require( 'path' ); +// Classes +const Referentials = require( '../models/Referentials' ); +// Middlewares +const checkHeaders = require( '../middlewares/checkHeaders' ); +const isAuthenticated = require( '../middlewares/isAuthenticated' ); +const hasAccessrighton = require( '../middlewares/hasAccessrighton' ); +const router = express.Router(); +/* + * keylist = list of key at 1st level in clientconf.json separated by _ + * we use header.xworkon + * To manage AccesRight obkect referentials does not follow the same logic than other object this is why + */ +router.get( '/clientconf/:keylist', checkHeaders, isAuthenticated, ( req, res ) => { + // retourne liste info (non sensible) du tribeid inside headers.xworkon sur keylist ="key1_key2" + /* + if (req.session.header.accessrights.data[ "Alltribeid" ] && req.session.header.accessrights.data[ "Alltribeid" ].referentials.includes('R') ; + */ + console.log( `get clientconf for ${req.session.header.xworkon} on ${req.params.keylist}` ) + let dataref = {} + if( req.params.keylist.split( '_' ) + .length > 0 ) { + const ref = Referentials.clientconf( req.session.header.xworkon, req.params.keylist.split( '_' ) ) + if( ref.status == 200 ) { + dataref = ref.payload.data; + } else { + console.log( "erreur ", ref ) + } + } + console.log( 'envoie en jsonp: dataref' ) + res.jsonp( dataref ) +} ); +router.get( '/clientconfglob', checkHeaders, isAuthenticated, ( req, res ) => { + res.jsonp( Referentials.clientconfglob() + .payload.data ); +} ); +router.get( '/contentlist/:source', checkHeaders, isAuthenticated, + ( req, res ) => { + const payload = []; + console.log( req.params.source, `${config.tribes}/${req.session.header.xworkon}/referentials/dataManagement/${req.params.source}/*.json` ) + glob.sync( `${config.tribes}/${req.session.header.xworkon}/referentials/dataManagement/${req.params.source}/*.json` ) + .forEach( f => { + payload.push( path.basename( f, '.json' ) ); + } ) + res.json( payload ); + } ); +router.get( '/contentfull/:source/:idref', checkHeaders, isAuthenticated, + ( req, res ) => { + //only for data and object + console.log( 'route referentials get all language' + req.params.source + '-' + req.params.idref ); + const getref = Referentials.getref( true, req.params.source, req.params.idref, req.session.header.xworkon, req.session.header.xlang ); + // Return any status the data if any erreur return empty object + res.jsonp( getref.payload.data ); + } ); +router.get( '/content/:source/:idref', checkHeaders, isAuthenticated, + ( req, res ) => { + console.log( 'route referentials get ' + req.params.source + '-' + req.params.idref ); + const getref = Referentials.getref( false, req.params.source, req.params.idref, req.session.header.xworkon, req.session.header.xlang ); + res.jsonp( getref.payload.data ); + } ); +// get with no authentification +router.get( '/contentnoauth/:source/:idref', checkHeaders, + ( req, res ) => { + console.log( 'route referentials get ' + req.params.source + '-' + req.params.idref ); + // @TODO check access right in clientconf before sending back json file + const getref = Referentials.getref( false, req.params.source, req.params.idref, req.session.header.xworkon, req.session.header.xlang ); + res.jsonp( getref.payload.data ); + } ); +router.get( '/lg', ( req, res ) => { + console.log( req.headers[ "accept-language" ] ) + let lg = '??'; + if( req.headers[ "accept-language" ] && req.headers[ "accept-language" ].split( ',' ) + .length > 0 ) { + lg = req.headers[ "accept-language" ].split( ',' )[ 0 ]; + } + res.json( { lg } ) +} ); +router.put( '/content/:source/:idref', checkHeaders, isAuthenticated, ( req, res ) => { + console.log( `route put content for ${req.params.idref} that is a ${req.params.source}` ); + const putref = Referentials.putref( req.params.source, req.params.idref, req.session.header.xworkon, req.body ) + return res.status( putref.status ) + .send( { payload: putref.payload } ) +} ); +//hasAccessrighton( 'referentials', 'U' ) +router.get( '/updatefull', checkHeaders, isAuthenticated, hasAccessrighton( 'referentials', 'U' ), ( req, res ) => { + console.log( `route get to force update content updatefull is accessrighton` ); + const updtref = Referentials.updatefull( req.session.header.xworkon ) + return res.status( updtref.status ) + .send( { payload: updtref.payload } ) +} ); +module.exports = router; diff --git a/routes/tags.js b/routes/tags.js new file mode 100755 index 0000000..ed6a139 --- /dev/null +++ b/routes/tags.js @@ -0,0 +1,29 @@ +//Installation d'un tag +/* + + + +*/ +// Upload de file +const express = require('express'); +// Classes +const Tags = require('../models/Tags'); +// Middlewares +const router = express.Router(); +router.get('/:filename', (req, res) => { + //console.log('route tags get ', req.params.filename); + const savetag = Tags.getfile(req.params.filename, req); + if(savetag.status == 200) { + res.sendFile(savetag.payload.filename); + } else { + res.status(savetag.status) + .send({ payload: savetag.payload }) + } +}) +router.post('/:tribeid', (req, res) => { + //console.log('route tags post ', req.params.tribeid); + const savetag = Tags.savehits(req); + res.status(200) + .send(''); +}) +module.exports = router; diff --git a/routes/tribes.js b/routes/tribes.js new file mode 100755 index 0000000..94db2ef --- /dev/null +++ b/routes/tribes.js @@ -0,0 +1,374 @@ +const express = require( 'express' ); +const fs = require( 'fs-extra' ); +const path = require( 'path' ); +const config = require( '../tribes/townconf.js' ); + +// Classes +const Tribes = require( '../models/Tribes.js' ); +// Middlewares +const checkHeaders = require( '../middlewares/checkHeaders' ); +const isAuthenticated = require( '../middlewares/isAuthenticated' ); +const hasAccessrighton = require( '../middlewares/hasAccessrighton' ); +const router = express.Router(); + + +router.get( '/clientconf/:tribeid', checkHeaders, isAuthenticated, ( req, res ) => { + /* + get a clientconf.json for a tribeid depending of user accessright + if tribeid == all and user is admin of apixtribe => get /tmp/clientconfglob.json + req.session.header.accessrights, req.session.header.apixpaganid + */ + console.log( `Tribes/clientconf for tribeid:${req.params.tribeid}` ) + if( req.params.tribeid == "all" && req.session.header.accessrights.data.apixtribe && req.session.header.accessrights.data.apixtribe.tribeid && req.session.header.accessrights.data.apixtribe.tribeid.includes( 'R' ) ) { + res.status( 200 ) + .send( { moreinfo: fs.readJsonSync( `${config.tmp}/clientconfglob.json`, 'utf-8' ) } ); + return; + } + if( req.session.header.accessrights.data[ req.params.tribeid ] && + req.session.header.accessrights.data[ req.params.tribeid ].tribeid && + req.session.header.accessrights.data[ req.params.tribeid ].tribeid.includes( 'R' ) && + fs.existsSync( `${config.tribes}/${req.params.tribeid}/clientconf.json` ) ) { + // const conftribeid = { moreinfo: {} } + // conftribeid.moreinfo[ req.params.tribeid ] = fs.readJsonSync( `${config.tribes}/${req.params.tribeid}/clientconf.json`, 'utf-8' ); + res.status( 200 ) + .send( { moreinfo: [ fs.readJsonSync( `${config.tribes}/${req.params.tribeid}/clientconf.json`, 'utf-8' ) ] } ); + return; + } + // if not authorized or dos not exist return empty + // no specific message is send for security reason (check only log) + res.status( 403 ) + .send( { info: [ 'forbidenAccess' ], models: 'Tribes' } ) + .end(); +} ) +router.put( '/', checkHeaders, isAuthenticated, ( req, res ) => { + console.log( 'Create a new tribeid, with a useradmin' ) + console.log( ' send data = clientconf.json with all parameter.' ) + // !!!!! check for security any ; \n or so because data can be used into shell + const add = Tribes.create( req.body ); + res.status( add.status ) + .send( add.payload ) +} ) +router.delete( '/archivetribeid/:tribeid', checkHeaders, isAuthenticated, ( req, res ) => { + console.log( "request archive tribeid" ) + const archive = Tribes.archive( req.params.tribeid ); + res.status( archive.status ) + .send( archive.payload ) +} ); +router.post( '/spaceweb', checkHeaders, isAuthenticated, ( req, res ) => { + // !!!!! check for security any ; \n or so because data can be used into shell + console.log( 'Create a new webapp for xworkon ' ) + req.body.tribeid = req.session.header.xworkon; + const add = Tribes.addspaceweb( req.body ) + res.status( add.status ) + .send( add.payload ) +} ) +router.get( '/spaceweb/components/:tribeid/:website/:key', checkHeaders, ( req, res ) => { + // check if key is valid before continue + // exemple: get Tribes/spaceweb/components/ndda/mesa/123?rep=appmesatable/appsimpletable.mustache + const file = `${config.tribes}/${req.params.tribeid}/spacedev/${req.params.website}/src/ctatic/components/${req.query.path}` + console.log( `Request components file from ${file}` ) + if( fs.existsSync( file ) ) { + res.sendFile( file ); + } else { + res.send( `console.error("Missing components file in ${req.params.tribeid}/spacedev/${req.params.website}/src/ctatic/components/${req.query.path}");` ); + } +} ) +router.get( '/plugins/:tribeid/:pluginname/:key/:filename', ( req, res ) => { + // No accessright possible cause it is load on the fly + // @todo Check key to authorize access to the plugin (key comme from user ACCESSRIGHTS[tribeid plugin owner:pluginname]).key + // return a file into /:tribeid owner of plugin/plugins/:pluginname/components/:filename + // if not exist or invalid key then return console.error + const file = `${config.tribes}/${req.params.tribeid}/plugins/${req.params.pluginname}/components/${req.params.filename}` + console.log( 'Tribes/plugins/ ', file ) + if( fs.existsSync( file ) ) { + res.sendFile( file ); + } else { + res.send( `console.error("Missing plugin file in ${req.params.tribeid}/plugins/${req.params.pluginname}/components/${req.params.filename}");` ); + } +} ); + +router.get( '/dirls', checkHeaders, isAuthenticated, ( req, res ) => { + // url /Tribes/dirls?rep=referentials/dataManagement + // request information about a req.query.rep from header xworkon/ + // return + // {file:[{}],dir:[{}]} + // @todo check if isAuthorized and exist + + console.log( 'request dirls', `${config.tribes}/${req.session.header.xworkon}/${req.query.rep}` ); + if( !fs.existsSync( `${config.tribes}/${req.session.header.xworkon}/${req.query.rep}` ) ) { + res.status( 404 ) + .send( { 'info': [ 'dirnotexist' ], model: 'Tribes' } ); + } + const info = Tribes.dirls( req.session.header.xworkon, req.query.rep ); + console.log( info ) + res.status( info.status ) + .send( info.payload ); +} ) +router.delete( '/ls', checkHeaders, isAuthenticated, ( req, res ) => { + // check Accessright with D or O on each + // url /Tribes/ls + // req.body.files=[listfiles file to delete ] + const authfiles = Tribes.checkaccessfiles( req.body, 'D', req.session.header.accessrights, req.session.header.apixpaganid ); + authfiles.ok.forEach( f => { fs.remove( `${config.tribes}/${f}` ); } ) + res.status( 200 ) + .send( { 'info': [ 'fileauthdeleted' ], models: 'Tribes', moreinfo: authfiles } ) +} ); +router.put( '/sendjson', checkHeaders, isAuthenticated, ( req, res ) => { + //req.body = {object:spacedev, path:website/src/data/tpldataname_lg.json, data:{...}} + //console.log( req.body ) + const dest = `${config.tribes}/${req.session.header.xworkon}/${req.body.object}/${req.body.path}`; + console.log( `Send json to saved to ${dest}` ); + if( !( req.body.object && fs.existsSync( `${config.tribes}/${req.session.header.xworkon}/${req.body.object}` ) ) ) { + res.status( '404' ) + .send( { info: [ 'objectmissiong' ], models: 'Tribes', moreinfo: `object: ${req.body.object} does not exist req.body must {object, data, path} into data ${req.session.header.xworkon}/${req.body.object}` } ) + } else { + if( fs.existsSync( `${config.tribes}/${req.session.header.xworkon}/${req.body.object}/${req.body.path}` ) ) { + // exist so can be update check accessright update on this + hasAccessrighton( req.body.object, "U" ); + } else { + hasAccessrighton( req.body.object, "C" ); + } + fs.outputJsonSync( dest, req.body.data ); + res.status( 200 ) + .send( { info: [ 'filesaved' ], models: 'Tribes' } ) + } +} ); +router.post( '/downloadls', checkHeaders, isAuthenticated, ( req, res ) => { + // midlleware hasAccessrighton.js is not apply here only to access/update/create information inside an object + // to get file a user need accessrights to data: object: R or to Own it + // or if exist a .info.json into folder get shared as R in uuid + + //req.body contain list of path file or folder if only 1 file then download it, otherwise zip list and send zip file + + const authfiles = Tribes.checkaccessfiles( req.body.files, 'R', req.session.header.accessrights, req.session.header.xpaganid ); + if( authfiles.ok.length == 1 ) { + // bidouille en attendnat de faire un .zip binaire propre + if( !authfiles.ok[ 0 ].includes( '.xml' ) ) { + res.status( 200 ) + .download( `${config.tribes}/${authfiles.ok[0]}`, authfiles.ok[ 0 ] ); + } else { + fs.copySync( `${config.tribes}/${authfiles.ok[0]}`, `${config.tribes}/${config.mayorId}/www/app/webapp/static/tmp/${authfiles.ok[ 0 ]}` ) + } + } else if( authfiles.ok.length > 1 ) { + // on zip et on envoie + //res.status( 200 ) + // .download( `${config.tribes}/${authfiles.ok[0]}`, authfiles.ok[ 0 ]) + res.status( 200 ) + .attachment( `${config.tribes}/${authfiles.ok[0]}` ); + + } else { + req.body.filepon + res.status( 403 ) + .send( 'Forbidden access' ) + } +} ); +router.post( '/upfilepond', checkHeaders, isAuthenticated, ( req, res ) => { + console.log( 'post /Tribes/uploadfilepond' ); + // Store file and return a unique id to save button + // that provide folder where to store it + const formidable = require( 'formidable' ); + const form = formidable( { multiples: false } ); + form.parse( req, ( err, fields, files ) => { + if( err ) { next( err ); return; } + //console.log( 'fields',fields); + // fileMetadaObject send + let context = JSON.parse( fields.filepond ); + let idfile = files.filepond.path; + let name = files.filepond.name; + let subfolder = context.subfolder; + name = name.replace( /[ ,'"’]/g, "_" ); + //console.log( 'files.filepond:', files.filepond ); + console.log( idfile, `${config.tribes}/${req.session.header.xworkon}/www/${subfolder}/${name}` ) + // On le supprime s'il existe deja + fs.removeSync( `${config.tribes}/${req.session.header.xworkon}/www/${subfolder}/${name}` ); + // mv tmp + fs.moveSync( idfile, `${config.tribes}/${req.session.header.xworkon}/www/${subfolder}/${name}` ); + //res.status(200).send({models:"Tribes",info:["Savedsuccess"],moreinfo:{id:file.filepond.path}}) + //return for filepond + res.writeHead( 200, { 'Content-Type': 'text/plain' } ); + res.end( idfile ); + } ) +} ); +router.delete( '/file', checkHeaders, isAuthenticated, ( req, res ) => { + //src = objectfolder with accessright/... + //hasAccessrighton( "www", "D" ), + if( !req.query.src ) { + res.status( 404 ) + .send( { info: [ 'deleteerror' ], models: "Tribes", moreinfo: "your del req need a src" } ) + return; + }; + hasAccessrighton( req.query.src.split( '/' )[ 0 ], "D" ); + console.log( 'Remove file', `${config.tribes}/${req.session.header.xworkon}/${req.query.src}` ) + console.log( req.body ) + fs.removeSync( `${config.tribes}/${req.session.header.xworkon}/${req.query.src}` ); + res.status( 200 ) + .send( { info: [ 'Successfullremove' ], models: "Tribes" } ) +} ); +router.post( '/uploadfile', checkHeaders, isAuthenticated, ( req, res ) => { + console.log( 'upload a file ' ) + /* Authentification is needed to get a TOKEN + curl -X POST -H "xtribe: apixtribe" -H "xworkon: pvmsaveurs" -H "xlang: fr" -H "xpaganid: 1" -H "xauth: 1" -H "xapp: pvmsaveurs:pvmsaveurs" -H "Content-Type: application/json" -d '{"LOGIN":"adminapixtribe","PASSWORD":"Trze3aze!"}' http://pvmsaveurs.pvmsaveurs.fr/app/users/login + if exist replace xpaganidTOKEN with payload.TOKEN value + + curl -H "xtribe: pvmsaveurs" -H "xworkon: pvmsaveurs" -H "xlang: fr" -H "xpaganid: adminapixtribe" -H "xauth: xpressuuisToken" -H "xapp: pvmsaveurs:pvmsaveurs" -F 'data=@filename.xx' http://pvmsaveurs.pvmsaveurs.fr/app/Tribes/uploadfile + */ + const formidable = require( 'formidable' ); + const form = formidable( { multiples: false } ); + form.parse( req, function ( err, fields, files ) { + //console.log( files.data ) + var oldPath = files.data.path; + var newPath = `${config.tribes}/${req.session.header.xworkon}/${clientconf.uploadzip[files.data.name].dest}`; + console.log( 'oldPath', oldPath ) + console.log( 'newPath', newPath ) + var rawData = fs.readFileSync( oldPath ) + fs.outputFile( newPath, rawData, function ( err ) { + if( err ) { + console.log( err ); + return res.status( 405 ) + .send( { info: [ 'savederror' ], models: "Tribes", moreinfo: "your file was not able to be saved into the server" } ) + } else { + return res.status( 200 ) + .send( { + info: [ "successfullsent" ], + models: "Tribes" + } ); + } + } ) + } ); +} ); +router.post( '/uploadzip', checkHeaders, ( req, res ) => { + console.log( 'uploadzip a file ' ) + + /* no authentification to upload a zip filename into /tribes/${xworkon}/${clientconf.uploadzip[filename].dest} + unzip it using the password ${clientconf.uploadzip[filename].psw + if no error then run the callback ${clientconf.uploadzip[filename].callback + but a password to unzip + in clientconf.json need to be set + "uploadzip": { + "articlesTribespvm.zip": { + "comment": "unzip with overwrite if same name", + "psw": "azPI1209qtrse", + "dest": "importexport/tmp", + "unzipoption": "-aoa", + "callback": "importexport/integrationitem.js" + } + }, + Example: + cd where zip file is stored + curl -H "xtribe: pvmsaveurs" -H "xworkon: pvmsaveurs" -H "xlang: fr" -H "xpaganid: adminapixtribe" -H "xauth: 1" -H "xapp: pvmsaveurs:pvmsaveurs" -F 'data=@articlesTribespvm.zip' http://pvmsaveurs.pvmsaveurs.fr/app/Tribes/uploadzip + + */ + const clientconf = fs.readJSONSync( `${config.tribes}/${req.session.header.xworkon}/clientconf.json` ) + if( !clientconf.uploadzip ) { + return res.status( '404' ) + .send( { info: [ "missconf" ], models: "Tribes", moreinfo: `no uploadzip in clientconf for ${req.session.header.xworkon} please contact apixtribe admin ` } ); + }; + const uploadzip = clientconf.uploadzip; + const formidable = require( 'formidable' ); + const form = formidable( { multiples: false } ); + form.parse( req, function ( err, fields, files ) { + //console.log( files.data ) + var oldPath = files.data.path; + if( !Object.keys( clientconf.uploadzip ) + .includes( files.data.name ) ) { + return res.status( 403 ) + .send( { info: [ "notAllowed" ], models: "Tribes", moreinfo: `file ${files.data.name} not allowed to be upload` } ) + } else { + console.log( "context:", clientconf.uploadzip[ files.data.name ] ) + var newPath = `${config.tribes}/${req.session.header.xworkon}/${clientconf.uploadzip[files.data.name].dest}`; + //console.log( 'oldPath', oldPath ) + //console.log( 'newPath', `${newPath}/${files.data.name}` ) + fs.moveSync( oldPath, `${newPath}/${files.data.name}`, { overwrite: true } ); + const cp = require( 'child_process' ); + //console.log( `7z e -p${clientconf.uploadzip[ files.data.name ].psw} ${newPath}/${files.data.name}` ); + console.log( '7z', [ 'e', `-p${clientconf.uploadzip[ files.data.name ].psw}`, `${newPath}/${files.data.name}`, `-o${config.tribes}/${req.session.header.xworkon}/${clientconf.uploadzip[ files.data.name ].dest}`, clientconf.uploadzip[ files.data.name ].unzipoption ] ); + var newFiles = cp.spawnSync( '7z', [ 'e', `-p${clientconf.uploadzip[ files.data.name ].psw}`, `${newPath}/${files.data.name}`, `-o${config.tribes}/${req.session.header.xworkon}/${clientconf.uploadzip[ files.data.name ].dest}`, clientconf.uploadzip[ files.data.name ].unzipoption ] ); + console.log( newFiles.output.toString() ) + if( newFiles.output.toString() + .includes( 'Everything is Ok' ) ) { + if( clientconf.uploadzip[ files.data.name ].callback ) { + const integ = require( `${config.tribes}/${req.session.header.xworkon}/${clientconf.uploadzip[files.data.name].callback}` ) + .run(); + console.log( 'integration', integ ) + return res.status( integ.status ) + .send( integ.payload ); + } else { + return res.status( 200 ) + .send( { + info: [ "successfullsent" ], + models: "Tribes" + } ); + } + } else { + return res.status( 400 ) + .send( { + info: [ "zipfileerror" ], + models: "Tribes", + moreinfo: newFiles.output.toString() + } ) + } + } + } ) +} ); + +router.post( '/upload', checkHeaders, isAuthenticated, ( req, res ) => { + 1 // ACHANGER VIA usage sendjson + // url /Tribes/upload?save=tmp&rep=referentials/dataManagement + // if save=tmp then store in a tmp file + // if save=ok then mv the tmp file to the folder + // midlleware hasAccessrighton.js is not apply here only to access/update/create information inside an object + // to upload a file a user need accessrights to data: object: C or to Own it + // or if dir.file exist a .info.json into folder get shared as C in uuid accessright + /* + to add in front +
+ + +
+ */ + console.log( 'Envoie image' ) + console.log( 'body', req.body ); + console.log( 'params', req.params ); + //const authfolder = Tribes.checkaccessfiles( req.params.rep, 'C', req.session.header.accessrights, req.session.header.xpaganid ); + // cheack autorisation to create or replace a file for this accessrights user + const authfolder = { ok: "tt" } + if( authfolder.ok ) { + if( req.params.save == 'file' ) { + if( fs.existsSync( req.body.filepond ) ) { + fs.mv( req.body.filepond, req.params.rep ); + } + }; + // voir si c'est toujours pertinent car upload est géré par filepond pour les image + if( req.params.save == 'upload' ) { + const form = formidable( { multiples: false } ); + form.parse( req, ( err, fields, files ) => { + if( err ) { next( err ); return; } + let thefile = files.filebond.path; + fs.outputFileSync() + console.log( 'thefile:' + thefile ); + res.writeHead( 200, { 'Content-Type': 'text/plain' } ); + res.end( theFile ); + } ) + } + } else { + res.status( 403 ) + .send( 'forbiden access' ); + } +} ); +/* +Manage tribeid into /data/tribee/tribeid +client space dedicated + +@Todo +clientconfglob copy cut from Referentials.clientconfglob +clientconf.json copy cut from Referentials.clientconf +list of tribeid copy cut from Referentials. +Add a tribeid +update clientconf + + +*/ + + + +module.exports = router; diff --git a/routes/uploadFiles.js b/routes/uploadFiles.js new file mode 100755 index 0000000..3652da1 --- /dev/null +++ b/routes/uploadFiles.js @@ -0,0 +1,49 @@ +// Upload de file +const express = require( 'express' ); +const path = require( 'path' ); +const jsonfile = require( 'jsonfile' ); +const fs = require( 'fs' ); + +// Classes +const UploadFile = require( '../models/UploadFiles' ); +// Middlewares +const checkHeaders = require( '../middlewares/checkHeaders' ); +const isAuthenticated = require( '../middlewares/isAuthenticated' ); +const router = express.Router(); + +router.post( '/', checkHeaders, ( req, res ) => { + console.log( 'route uploadFile post ' ); + const saveFile = UploadFile.add( req, req.session.header ); + res.send( saveFile ); + // res.send({ status: 200, payload: { info: 'fine' } }); +} ); + +router.post( '/json', checkHeaders, ( req, res ) => { + console.log( 'route uploadFile post de fichier json ' ); + // a callback can be pass to req.body to run a specific process after upload + const saveFile = UploadFile.addjson( req.body, req.session.header ); + console.log( saveFile ); + res.send( saveFile ); + // res.send({ status: 200, payload: { info: 'fine' } }); +} ); + +router.get( '/:filename', checkHeaders, isAuthenticated, ( req, res ) => { + console.log( 'route uploadFile get ', req.params.filename ); + const pushFile = UploadFile.get( + req.params.filename.replace( /______/g, '/' ), + req.session.header + ); + if( pushFile.status == 200 ) { + if( path.extname( pushFile.payload.file ) === '.json' ) { + jsonfile.readFile( pushFile.payload.file, ( err, p ) => { + if( err ) console.error( err ); + res.jsonp( p ); + } ); + } else { + res.download( pushFile.payload.file, path.basename( pushFile.payload.file ) ); + } + } else { + res.send( pushFile ); + } +} ); +module.exports = router; diff --git a/setup/ASUPconfig.jsold b/setup/ASUPconfig.jsold new file mode 100755 index 0000000..6337ae0 --- /dev/null +++ b/setup/ASUPconfig.jsold @@ -0,0 +1,111 @@ +'use strict'; +const path = require( 'path' ); +const fs = require( 'fs' ); +const config = {}; +if( !process.env.NODE_ENV ) process.env.NODE_ENV = "dev" +console.log( 'apixtribe process.env.NODE_ENV: ', process.env.NODE_ENV ); +// VOIR l'ancien fichier de cnfig au cas ou il manque des chemins dans config +// voir la doc http://gitlab.ndda.fr/philc/apiamaildigitfr/wikis/InstallConf +config.prod = { + mainDir: __dirname, + tmp: path.join( __dirname, '/tmp' ), + public: path.join( __dirname, '/public' ), + archivefolder: path.join( __dirname, '/archive' ), + rootURL: '{{setupdns}}', + domain: path.join( __dirname, '/data/tribee' ), + withssl: "{{withssl}}", + SSLCredentials: { + key: path.join( __dirname, '/data/certs/{{setupdns}}.key' ), + cert: path.join( __dirname, '/data/certs/{{setupdns}}.crt' ), + ca: path.join( __dirname, '/data/certs/{{setupdns}}.csr' ) + }, + port: { + http: "{{httpport}}", + https: "{{httpsport}}" + }, + jwtSecret: '{{jwtsecretkey}}', + saltRounds: 10, + languagesAvailable: [ 'fr', 'en', 'it', 'de', 'ru' ], + lg: {}, + exposedHeaders: { + 'x-auth': 'xauth', + 'x-uuid': 'xuuid', + 'x-language': 'xlang', + 'x-client-id': 'xtribeid', + 'x-workOn': 'xworkOn', + 'x-app': 'xapp' + }, + bodyparse: { + urlencoded: { + limit: '50mb', + extended: true + }, + json: { limit: '500mb' } + } +}; +// Development and test config +// apixtribe.local.fr + +config.dev = { + mainDir: __dirname, + tmp: path.join( __dirname, '/tmp' ), + public: path.join( __dirname, '/public' ), + //public allow to serve on /public file into folder /public with or without login + archivefolder: path.join( __dirname, '/archive' ), + rootURL: 'apixtribe.local.fr', + domain: path.join( __dirname, '/data/tribee' ), + withssl: "YES", + SSLCredentials: { + key: path.join( __dirname, '/setup/data/certs/apixtribe.local.fr.key' ), + cert: path.join( __dirname, '/setup/data/certs/apixtribe.local.fr.crt' ), + ca: path.join( __dirname, '/setup/data/certs/apixtribe.local.fr.csr' ) + }, + port: { + http: "{{httpport}}", + https: "{{httpsport}}" + }, + jwtSecret: 'dnsqd515+npsc^dsqdsqd^d$qdd$$$dŝqdze154615ae.Dsd:sqd!', + // Avoid authentification for uuid2 and this auth token + // Always remove this from production + devnoauthxuuid: "2", + devnoauthxauth: "autoriserparlapatrouille", + saltRounds: 10, + languagesAvailable: [ 'fr', 'en', 'it', 'de', 'ru' ], + lg: {}, + exposedHeaders: { + 'x-auth': 'xauth', + 'x-uuid': 'xuuid', + 'x-language': 'xlang', + 'x-client-id': 'xtribeid', + 'x-workOn': 'xworkOn', + 'x-app': 'xapp' + }, + bodyparse: { + urlencoded: { + limit: '50mb', + extended: true + }, + json: { limit: '500mb' } + } +}; +if( !config[ process.env.NODE_ENV ] ) { + console.log( 'config.js -> Exit setup due to node_ENV have to be set as prod or dev instead of ', process.env.NODE_ENV ) + process.exit(); +} +const confuse = config[ process.env.NODE_ENV ]; +if( confuse.withssl == "YES" ) { + if( !fs.existsSync( confuse.SSLCredentials.key ) ) { + const prompt = require( 'prompt-sync' )( { sigint: true } ); + //const repdata = ( process.NODE_ENV == "dev" ) ? 'devdata' : 'data'; + const reinit = prompt( `Missing file to ssl ${confuse.SSLCredentials.key}, please run the process letsencrypt to get a ssl certificat or reinit project (type reinit will erase ) and answer no to question: Do you want to manage ssl : ` ); + if( reinit == 'reinit' ) { + fs.removeSync( `${__dirname}/config.js` ); + fs.removeSync( `${__dirname}/data` ) + } + process.exit(); + } + confuse.SSLCredentials.key = fs.readFileSync( confuse.SSLCredentials.key, 'utf8' ); + confuse.SSLCredentials.cert = fs.readFileSync( confuse.SSLCredentials.cert, 'utf8' ); + confuse.SSLCredentials.ca = fs.readFileSync( confuse.SSLCredentials.ca, 'utf8' ); +} +module.exports = confuse; diff --git a/setup/apixtribe.crabdance.com.mustache b/setup/apixtribe.crabdance.com.mustache new file mode 100755 index 0000000..473cb3c --- /dev/null +++ b/setup/apixtribe.crabdance.com.mustache @@ -0,0 +1,37 @@ +server { + server_name {{config.apixtribeDNS}}; + add_header X-Request-ID $request_id; # Return to client + add_header Access-Control-Allow-Origin *; + add_header Access-Control-Max-Age 3600; + add_header Access-Control-Expose-Headers Content-Length; + add_header Access-Control-Allow-Headers Range; + + access_log /media/phil/usbfarm/apixtribe/tmp/nginx/apixtribe.crabdance.access.log main; + + #location = /app { + # return 302 /app/; + #} + location /app/ { + rewrite /app/(.*$) /$1 break; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + client_max_body_size 10m; + client_body_buffer_size 128k; + proxy_connect_timeout 90; + proxy_send_timeout 90; + proxy_read_timeout 90; + proxy_buffers 32 4k; + proxy_set_header X-NginX-Proxy true; + proxy_pass http://localhost:3017; + proxy_redirect off; + } + + location / { + root /media/phil/usbfarm/apixtribe/nationchains/; + index apixtribe.html; + } + error_page 404 /media/phil/usbfarm/apixtribe/nationchains/error/404.html; + error_page 500 502 503 504 /media/phil/usbfarm/apixtribe/nationchains/error/50x.html; +} + diff --git a/setup/config.mustache b/setup/config.mustache new file mode 100755 index 0000000..336f2ea --- /dev/null +++ b/setup/config.mustache @@ -0,0 +1,26 @@ +const path = require( 'path' ); +const config = { + loglevel:"{{consoleloglevel}}", + linuxuser:"{{linuxuser}}", + druidid:"{{druidid}}", + dnsapixtribe:"{{subdomain}}.{{domain}}", + mainDir: __dirname, + tmp: path.join( __dirname, '/tmp' ), + public: path.join( __dirname, 'data/tribe/{{druidid}}/www/cdn' ), + //(@TODO ASUP mettre /cdn de apixtribe) public allow to serve on /public file into folder /public with or without login + archivefolder: path.join( __dirname, '/archive' ), + domain: path.join( __dirname, '/data/tribe' ), + porthttp:{{porthttp}} , + jwtSecret: '{{jwtsecret}}', + saltRounds: 10, + languagesAvailable: [ {{#language}}'{{.}}',{{/language}} ], + exposedHeaders:[ 'xauth', 'xpaganid', 'xlang', 'xtribe', 'xworkon', 'xapp' ], + bodyparse: { + urlencoded: { + limit: '50mb', + extended: true + }, + json: { limit: '500mb' } + } +}; +module.exports = config; diff --git a/setup/configsetup.json b/setup/configsetup.json new file mode 100755 index 0000000..f427af0 --- /dev/null +++ b/setup/configsetup.json @@ -0,0 +1,13 @@ +{ + "linuxuser": "phil", + "mode": "dev", + "domain": "local.fr", + "subdomain": "dev", + "consoleloglevel": "quiet", + "porthttp": 3018, + "language": ["fr", "en"], + "jwtsecret": "longsentenceusedtoencryptionChangethisforproduction", + "druidid": "test", + "login": "testadmin", + "genericpsw": "@12ABab@" +} \ No newline at end of file diff --git a/setup/data/domain/apixpress/blockchains/blocks/0.json b/setup/data/domain/apixpress/blockchains/blocks/0.json new file mode 100755 index 0000000..5a67612 --- /dev/null +++ b/setup/data/domain/apixpress/blockchains/blocks/0.json @@ -0,0 +1,9 @@ +{ + "hash": "", + "previousblockhash": "", + "nextblockhash": "", + "info": "txt:freedomandthefuturofinternet##", + "time": 1643763742, + "size": "", + "difficulty": "" +} \ No newline at end of file diff --git a/setup/data/domain/apixpress/blockchains/nodes/apixpress.ndda.fr b/setup/data/domain/apixpress/blockchains/nodes/apixpress.ndda.fr new file mode 100755 index 0000000..2519b01 --- /dev/null +++ b/setup/data/domain/apixpress/blockchains/nodes/apixpress.ndda.fr @@ -0,0 +1,10 @@ +{ +"fixedIP":"", +"firsttimeping":0, +"lastimeping":0, +"positifping":0, +"negatifping":0, +"pubkeyadmin":"", +"tribeids":[], +"logins":[] +} diff --git a/setup/data/domain/apixpress/clientconf.mustache b/setup/data/domain/apixpress/clientconf.mustache new file mode 100755 index 0000000..8cb5d32 --- /dev/null +++ b/setup/data/domain/apixpress/clientconf.mustache @@ -0,0 +1,28 @@ +{ + "tribeid": "{{tribeid}}", + "genericpsw": "{{genericpsw}}", + "saltRounds": "tomakeitharderbetterstronger", + "website": { + "webapp": "{{subdomain}}.{{domain}}" + }, + "allowedDOMs": ["{{domain}}"], + "customization": { + "claim": "Be a Producer, not a product.", + "name": "apixtribe", + "logo": "https://{{subdomain}}.{{domain}}/cdn/{{druidid}}/img/logo/apixtribe.png", + "favicon": "https://{{subdomain}}.{{domain}}/cdn/{{druidid}}/img/iconX74x74.png", + "colors": { + "primary": "#01717B", + "secondary": "#CA5F00", + "success": "", + "info": "", + "warning": "", + "danger": "", + "light": "#fff", + "dark": "#222" + } + }, + "smtp": {}, + "accepted-language": "fr,en", + "langueReferential": ["fr"] +} diff --git a/setup/data/domain/apixpress/referentials/dataManagement/data/OrdersAction.json b/setup/data/domain/apixpress/referentials/dataManagement/data/OrdersAction.json new file mode 100755 index 0000000..fbe591b --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/data/OrdersAction.json @@ -0,0 +1,106 @@ +[{ + "uuid": "ERRcritical", + "desc": { + "fr": "Erreur critique", + "en": "Critical Error" + } + }, + { + "uuid": "failtoWritefs", + "desc": { + "fr": "Impossible d'enregistrer cette information", + "en": "Fail to write on system" + } + }, + { + "uuid": "successfulCreate", + "desc": { + "fr": "Création réussie", + "en": "Creation is successful" + } + }, + { + "uuid": "successfulUpdate", + "desc": { + "fr": "Mise à jour réussie", + "en": "Succesfull update" + } + }, + { + "uuid": "successfulDelete", + "desc": { + "fr": "Suppression effectuée", + "en": "The user has been deleted" + } + }, + { + "uuid": "forbiddenAccess", + "desc": { + "fr": "Accès non autorisé", + "en": "Forbidden access" + } + }, + { + "uuid": "userNotAllowtoCreate", + "desc": { + "fr": "L'utilisateur n'est pas authorisé à créer un nouvel utilisateur", + "en": "Pagans is not allowed to create a new user account" + } + }, + { + "uuid": "userNotAllowtoUpdate", + "desc": { + "fr": "L'utilisateur n'est pas authorisé à mettre à jour cet utilisateur", + "en": "Pagans is not allowed to update this user account" + } + }, + { + "uuid": "userNotAllowtoDelete", + "desc": { + "fr": "L'utilisateur n'est pas authrisé à supprimer utilisateur", + "en": "Pagans is not allowed to delete a user account" + } + }, + { + "uuid": "invalidData", + "desc": { + "fr": "Vérifiez vos données", + "en": "Check your data" + } + }, + { + "uuid": "ERRemail", + "desc": { + "fr": "Vérifiez votre email", + "en": "Check your email" + } + }, + { + "uuid": "Reservationplandoesnotexist", + "desc": { + "fr": "Il n'y a pas de Planning de réservation", + "en": "No reservation plan at this adress" + } + }, + { + "uuid": "Reservationitemwelldone", + "desc": { + "fr": "Votre reservation a bien été enregistrée", + "en": "Registration well done." + } + }, + { + "uuid": "Nomoreavailability", + "desc": { + "fr": "Désolé, la place n'est plus disponible", + "en": "Unavailable." + } + }, + { + "uuid": "CatalogdoesnotExist", + "desc": { + "fr": "Désolé, ce catagoue n'existe pas", + "en": "This catalog does not exist." + } + } +] \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagement/data/OutputsAction.json b/setup/data/domain/apixpress/referentials/dataManagement/data/OutputsAction.json new file mode 100755 index 0000000..f2536b5 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/data/OutputsAction.json @@ -0,0 +1,170 @@ +[ + { + "uuid": "ERRcritical", + "desc": { + "fr": "Erreur critique", + "en": "Critical Error" + } + }, + { + "uuid": "msgsentok", + "desc": { + "fr": "L'email a bien été envoyé", + "en": "email sent" + } + }, + { + "uuid": "emailAlreadyExist", + "desc": { + "fr": "Cet email a déjà un compte", + "en": "Email already exists" + } + }, + { + "uuid": "failtoWritefs", + "desc": { + "fr": "Impossible d'enregistrer cette information", + "en": "Fail to write on system" + } + }, + { + "uuid": "successfulCreate", + "desc": { + "fr": "Création réussie", + "en": "Creation is successful" + } + }, + { + "uuid": "successfulUpdate", + "desc": { + "fr": "Mise à jour réussie", + "en": "Succesfull update" + } + }, + { + "uuid": "successfulDelete", + "desc": { + "fr": "Suppression effectuée", + "en": "The user has been deleted" + } + }, + { + "uuid": "serverNeedAuthentification", + "desc": { + "fr": "Ce serveur nécessite une authentification", + "en": "This server needs authentification" + } + }, + { + "uuid": "forbiddenAccess", + "desc": { + "fr": "Accès non autorisé", + "en": "Forbidden access" + } + }, + { + "uuid": "userNotAllowtoCreate", + "desc": { + "fr": "L'utilisateur n'est pas authorisé à créer un nouvel utilisateur", + "en": "Pagans is not allowed to create a new user account" + } + }, + { + "uuid": "userNotAllowtoUpdate", + "desc": { + "fr": "L'utilisateur n'est pas authorisé à mettre à jour cet utilisateur", + "en": "Pagans is not allowed to update this user account" + } + }, + { + "uuid": "userNotAllowtoDelete", + "desc": { + "fr": "L'utilisateur n'est pas authrisé à supprimer utilisateur", + "en": "Pagans is not allowed to delete a user account" + } + }, + { + "uuid": "useridNotfound", + "desc": { + "fr": "L'utilisateur {{uuid}} n'existe pas sur {{tribeid}}", + "en": "Pagans {{uuid}} not found for {{tribeid}}" + } + }, + { + "uuid": "useremailNotfound", + "desc": { + "fr": "L'email n'existe pas", + "en": "Email not found" + } + }, + { + "uuid": "loginDoesNotExist", + "desc": { + "fr": "Ce login n'existe pas", + "en": "This login doesn't exist" + } + }, + { + "uuid": "checkCredentials", + "desc": { + "fr": "Vérifiez vos identifiants", + "en": "Check your credentials" + } + }, + { + "uuid": "wrongPassword", + "desc": { + "fr": "Vérifiez votre mot de passe", + "en": "Check your password" + } + }, + { + "uuid": "invalidData", + "desc": { + "fr": "Vérifiez vos données", + "en": "Check your data" + } + }, + { + "uuid": "pswTooSimple", + "desc": { + "fr": "Le mot de passe doit faire au moins 8 caractéres comporter au moins un chiffre, une lettre minuscule, une lettre majuscule et un caractere spécial type @ !...", + "en": "Password too simple, need to contain at least 8 caracters lower and uppercase, number and @! ..." + } + }, + { + "uuid": "ERRemail", + "desc": { + "fr": "Vérifiez votre email", + "en": "Check your email" + } + }, + { + "uuid": "ERRnewnewbisdiff", + "desc": { + "fr": "Le mot de passe de confirmation ne correspond pas", + "en": "Check your confirmation password" + } + }, + { + "uuid": "ERRnotemplate", + "desc": { + "fr": "il n'y a pas de template d'email dans la demande template.html est vide et pas de htmlfile présent.", + "en": "Check your email template conf tribeid no msg.template.htmlfile and msg.html==''" + } + }, + { + "uuid": "wellPdfGenerated", + "desc": { + "fr": "Le pdf: {{filename}} a ete genere correctement.", + "en": "Pdf well generated" + } + }, + { + "uuid": "pdfGenerationError", + "desc": { + "fr": "Erreur dans la generation de pdf, verifiez le json", + "en": "Error in pdf generation, check the json" + } + } +] \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagement/data/UploadFilesAction.json b/setup/data/domain/apixpress/referentials/dataManagement/data/UploadFilesAction.json new file mode 100755 index 0000000..7fc2f3f --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/data/UploadFilesAction.json @@ -0,0 +1,23 @@ +[ + { + "uuid": "fileUnknown", + "desc": { + "fr": "Fichier inconnu", + "en": "File unknown" + } + }, + { + "uuid": "wellUpload", + "desc": { + "fr": "Fichier bien récupéré dans {{destination}}/{{filename}}", + "en": "File well uploaded in {{destination}}/{{filename}}" + } + }, + { + "uuid": "savingError", + "desc": { + "fr": "Impossible de sauvegarder", + "en": "Saving file is impossible" + } + } +] diff --git a/setup/data/domain/apixpress/referentials/dataManagement/data/UsersAction.json b/setup/data/domain/apixpress/referentials/dataManagement/data/UsersAction.json new file mode 100755 index 0000000..343cd86 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/data/UsersAction.json @@ -0,0 +1,149 @@ +[ + { + "uuid": "ERRcritical", + "desc": { + "fr": "Erreur critique", + "en": "Critical Error" + } + }, + { + "uuid": "loginAlreadyExist", + "desc": { + "fr": "Ce login est déjà attribué", + "en": "Login already exists" + } + }, + { + "uuid": "emailAlreadyExist", + "desc": { + "fr": "Cet email a déjà un compte", + "en": "Email already exists" + } + }, + { + "uuid": "failtoWritefs", + "desc": { + "fr": "Impossible d'enregistrer cette information", + "en": "Fail to write on system" + } + }, + { + "uuid": "successfulCreate", + "desc": { + "fr": "Création réussie", + "en": "Creation is successful" + } + }, + { + "uuid": "successfulUpdate", + "desc": { + "fr": "Mise à jour réussie", + "en": "Succesfull update" + } + }, + { + "uuid": "successfulDelete", + "desc": { + "fr": "Suppression effectuée", + "en": "The user has been deleted" + } + }, + { + "uuid": "serverNeedAuthentification", + "desc": { + "fr": "Ce serveur nécessite une authentification", + "en": "This server needs authentification" + } + }, + { + "uuid": "forbiddenAccess", + "desc": { + "fr": "Accès non autorisé", + "en": "Forbidden access" + } + }, + { + "uuid": "userNotAllowtoCreate", + "desc": { + "fr": "L'utilisateur n'est pas authorisé à créer un nouvel utilisateur", + "en": "Pagans is not allowed to create a new user account" + } + }, + { + "uuid": "userNotAllowtoUpdate", + "desc": { + "fr": "L'utilisateur n'est pas authorisé à mettre à jour cet utilisateur", + "en": "Pagans is not allowed to update this user account" + } + }, + { + "uuid": "userNotAllowtoDelete", + "desc": { + "fr": "L'utilisateur n'est pas authrisé à supprimer utilisateur", + "en": "Pagans is not allowed to delete a user account" + } + }, + { + "uuid": "useridNotfound", + "desc": { + "fr": "L'utilisateur {{uuid}} n'existe pas sur {{tribeid}}", + "en": "Pagans {{uuid}} not found for {{tribeid}}" + } + }, + { + "uuid": "useremailNotfound", + "desc": { + "fr": "L'email n'existe pas", + "en": "Email not found" + } + }, + { + "uuid": "loginDoesNotExist", + "desc": { + "fr": "Ce login n'existe pas", + "en": "This login doesn't exist" + } + }, + { + "uuid": "checkCredentials", + "desc": { + "fr": "Vérifiez vos identifiants", + "en": "Check your credentials" + } + }, + { + "uuid": "wrongPassword", + "desc": { + "fr": "Vérifiez votre mot de passe", + "en": "Check your password" + } + }, + { + "uuid": "invalidData", + "desc": { + "fr": "Vérifiez vos données", + "en": "Check your data" + } + }, + { + "uuid": "pswTooSimple", + "desc": { + "fr": "Le mot de passe doit faire au moins 8 caractéres comporter au moins un chiffre, une lettre minuscule, une lettre majuscule et un caractere spécial type @ !...", + "en": "Password too simple, need to contain at least 8 caracters lower and uppercase, number and @! ..." + } + }, + { + "uuid": "ERRemail", + "desc": { + "fr": "Vérifiez votre email", + "en": "Check your email" + } + }, + { + "uuid": "ERRnewnewbisdiff", + "desc": { + "fr": "Le mot de passe de confirmation ne correspond pas", + "en": "Check your confirmation password" + } + } +] diff --git a/setup/data/domain/apixpress/referentials/dataManagement/data/gender.json b/setup/data/domain/apixpress/referentials/dataManagement/data/gender.json new file mode 100755 index 0000000..bcba50b --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/data/gender.json @@ -0,0 +1,12 @@ +[ + { + "uuid": 0, + "desclong": { "fr": "Monsieur", "en": "Mister" }, + "desc": { "fr": "M.", "en": "M." } + }, + { + "uuid": 1, + "desclong": { "fr": "Madame", "en": "Miss" }, + "desc": { "fr": "Mme", "en": "Miss" } + } +] diff --git a/setup/data/domain/apixpress/referentials/dataManagement/data/missionpos.json b/setup/data/domain/apixpress/referentials/dataManagement/data/missionpos.json new file mode 100755 index 0000000..f9a3f98 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/data/missionpos.json @@ -0,0 +1,314 @@ +[ + { + "uuid": "AMDTA", + "desc": { "fr": "Amiante (DTA)" }, + "desclong": { + "fr": "correspond au champ diag_01 dans le modèle de rapport Ordre de mission" + }, + "color": "#449245" + }, + { + "uuid": "AMVENT", + "desc": { "fr": "Amiante (Vente)" }, + "desclong": { + "fr": "correspond au champ diag_02 dans le modèle de rapport Ordre de mission" + }, + "color": "#136202" + }, + { + "uuid": "AMTRAV", + "desc": { "fr": "Amiante (Travaux)" }, + "desclong": { + "fr": "correspond au champ diag_03 dans le modèle de rapport Ordre de mission" + }, + "color": "#865694" + }, + { + "uuid": "AMDEMOL", + "desc": { "fr": "Amiante (Démol)" }, + "desclong": { + "fr": "correspond au champ diag_04 dans le modèle de rapport Ordre de mission" + }, + "color": "#086446" + }, + { + "uuid": "DIAGTERM", + "desc": { "fr": "Diag.Termites" }, + "desclong": { + "fr": "correspond au champ diag_05 dans le modèle de rapport Ordre de mission" + }, + "color": "#036034" + }, + { + "uuid": "DIAGPARA", + "desc": { "fr": "Diag.Parasites" }, + "desclong": { + "fr": "correspond au champ diag_06 dans le modèle de rapport Ordre de mission" + }, + "color": "#116801" + }, + { + "uuid": "CARREZ", + "desc": { "fr": "Mesurage (Carrez)" }, + "desclong": { + "fr": "correspond au champ diag_07 dans le modèle de rapport Ordre de mission" + }, + "color": "#341770" + }, + { + "uuid": "CREP", + "desc": { "fr": "Constat des risques d'exposition au plomb (CREP)" }, + "desclong": { + "fr": "correspond au champ diag_08 dans le modèle de rapport Ordre de mission" + }, + "color": "#303924" + }, + { + "uuid": "ASSAINISS", + "desc": { "fr": "Assainissement" }, + "desclong": { + "fr": "correspond au champ diag_09 dans le modèle de rapport Ordre de mission" + }, + "color": "#279573" + }, + { + "uuid": "PISCINE", + "desc": { "fr": "Piscine" }, + "desclong": { + "fr": "correspond au champ diag_10 dans le modèle de rapport Ordre de mission" + }, + "color": "#450176" + }, + { + "uuid": "GAZ", + "desc": { "fr": "Gaz" }, + "desclong": { + "fr": "correspond au champ diag_11 dans le modèle de rapport Ordre de mission" + }, + "color": "#763822" + }, + { + "uuid": "ELEC", + "desc": { "fr": "Electricité" }, + "desclong": { + "fr": "correspond au champ diag_12 dans le modèle de rapport Ordre de mission" + }, + "color": "#873048" + }, + { + "uuid": "SRU", + "desc": { "fr": "D.Technique SRU" }, + "desclong": { + "fr": "correspond au champ diag_13 dans le modèle de rapport Ordre de mission" + }, + "color": "#279870" + }, + { + "uuid": "DPE", + "desc": { "fr": "DPE" }, + "desclong": { + "fr": "correspond au champ diag_14 dans le modèle de rapport Ordre de mission" + }, + "color": "#862302" + }, + { + "uuid": "TX0", + "desc": { "fr": "Prêt à taux zéro" }, + "desclong": { + "fr": "correspond au champ diag_15 dans le modèle de rapport Ordre de mission" + }, + "color": "#279050" + }, + { + "uuid": "ERNT", + "desc": { "fr": "ERNT" }, + "desclong": { + "fr": "correspond au champ diag_16 dans le modèle de rapport Ordre de mission" + }, + "color": "#870447" + }, + { + "uuid": "ROBIEN", + "desc": { "fr": "Robien" }, + "desclong": { + "fr": "correspond au champ diag_17 dans le modèle de rapport Ordre de mission" + }, + "color": "#238577" + }, + { + "uuid": "ETATLIEU", + "desc": { "fr": "Etat des lieux" }, + "desclong": { + "fr": "correspond au champ diag_18 dans le modèle de rapport Ordre de mission" + }, + "color": "#159488" + }, + { + "uuid": "DIAGPBEAU", + "desc": { "fr": "Diag. plomb dans l'eau" }, + "desclong": { + "fr": "correspond au champ diag_19 dans le modèle de rapport Ordre de mission" + }, + "color": "#210836" + }, + { + "uuid": "ASCENSE", + "desc": { "fr": "Ascenseur" }, + "desclong": { + "fr": "correspond au champ diag_20 dans le modèle de rapport Ordre de mission" + }, + "color": "#702852" + }, + { + "uuid": "RADON", + "desc": { "fr": "Radon" }, + "desclong": { + "fr": "correspond au champ diag_21 dans le modèle de rapport Ordre de mission" + }, + "color": "#851497" + }, + { + "uuid": "INCENDIE", + "desc": { "fr": "Incendie" }, + "desclong": { + "fr": "correspond au champ diag_22 dans le modèle de rapport Ordre de mission" + }, + "color": "#329688" + }, + { + "uuid": "HANDICAP", + "desc": { "fr": "Handicapé" }, + "desclong": { + "fr": "correspond au champ diag_23 dans le modèle de rapport Ordre de mission" + }, + "color": "#752339" + }, + { + "uuid": "BOUTIN", + "desc": { "fr": "Mesurage (Boutin)" }, + "desclong": { + "fr": "correspond au champ diag_24 dans le modèle de rapport Ordre de mission" + }, + "color": "#645556" + }, + { + "uuid": "AMDAPP", + "desc": { "fr": "Amiante DAPP" }, + "desclong": { + "fr": "correspond au champ diag_25 dans le modèle de rapport Ordre de mission" + }, + "color": "#594067" + }, + { + "uuid": "DRIPP", + "desc": { "fr": "DRIPP" }, + "desclong": { + "fr": "correspond au champ diag_26 dans le modèle de rapport Ordre de mission" + }, + "color": "#135691" + }, + { + "uuid": "DPN", + "desc": { "fr": "DPN Performance numérique" }, + "desclong": { + "fr": "correspond au champ diag_27 dans le modèle de rapport Ordre de mission" + }, + "color": "#659536" + }, + { + "uuid": "INFILTRO", + "desc": { "fr": "Infiltrométrie" }, + "desclong": { + "fr": "correspond au champ diag_28 dans le modèle de rapport Ordre de mission" + }, + "color": "#931708" + }, + { + "uuid": "AMAPTVX", + "desc": { "fr": "Amiante Examun Visuel APTVX" }, + "desclong": { + "fr": "correspond au champ diag_29 dans le modèle de rapport Ordre de mission" + }, + "color": "#165812" + }, + { + "uuid": "DECHET", + "desc": { "fr": "Dechet" }, + "desclong": { + "fr": "correspond au champ diag_30 dans le modèle de rapport Ordre de mission" + }, + "color": "#682853" + }, + { + "uuid": "PBAPTVX", + "desc": { "fr": "Plomb APTVX" }, + "desclong": { + "fr": "correspond au champ diag_31 dans le modèle de rapport Ordre de mission" + }, + "color": "#051199" + }, + { + "uuid": "AMCTRLPERIO", + "desc": { "fr": "Amiante Contrôl périodique" }, + "desclong": { + "fr": "correspond au champ diag_32 dans le modèle de rapport Ordre de mission" + }, + "color": "#726364" + }, + { + "uuid": "AMEMPOUSS", + "desc": { "fr": "Amiante Empoussièrement" }, + "desclong": { + "fr": "correspond au champ diag_33 dans le modèle de rapport Ordre de mission" + }, + "color": "#053460" + }, + { + "uuid": "DEVINTERNE", + "desc": { "fr": "Module developpement Interne" }, + "desclong": { + "fr": "correspond au champ diag_34 dans le modèle de rapport Ordre de mission" + }, + "color": "#687134" + }, + { + "uuid": "HOMEINSPECT", + "desc": { "fr": "Home Inspection" }, + "desclong": { + "fr": "correspond au champ diag_35 dans le modèle de rapport Ordre de mission" + }, + "color": "#574776" + }, + { + "uuid": "4PTINSPECTION", + "desc": { "fr": "4PT Inspection" }, + "desclong": { + "fr": "correspond au champ diag_36 dans le modèle de rapport Ordre de mission" + }, + "color": "#729909" + }, + { + "uuid": "WINDMITIG", + "desc": { "fr": "Wind Mitigation Inspection" }, + "desclong": { + "fr": "correspond au champ diag_37 dans le modèle de rapport Ordre de mission" + }, + "color": "#646189" + }, + { + "uuid": "PBAVTVX", + "desc": { "fr": "Plomb Av Tvx" }, + "desclong": { + "fr": "correspond au champ diag_37 DIAG_38 dans le modèle de rapport Ordre de mission" + }, + "color": "#971402" + }, + { + "uuid": "HAP", + "desc": { "fr": "HAP" }, + "desclong": { + "fr": "correspond au champ DIAG_39 dans le modèle de rapport Ordre de mission" + }, + "color": "#577844" + } +] diff --git a/setup/data/domain/apixpress/referentials/dataManagement/data/profile.json b/setup/data/domain/apixpress/referentials/dataManagement/data/profile.json new file mode 100755 index 0000000..ad25c16 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/data/profile.json @@ -0,0 +1,46 @@ +[ + { + "uuid": "USER", + "desc": { + "fr": "USER - Utilisateur interne", + "en": "USER - User profil" + }, + "desclong": { + "fr": "Utilisateur interne à l'organisation", + "en": "User profil" + } + }, + { + "uuid": "CLIENT", + "desc": { + "fr": "CLIENT - Utilisateur externe", + "en": "CLIENT - User profil" + }, + "desclong": { + "fr": "Utilisateur externe type client", + "en": "User profil" + } + }, + { + "uuid": "MANAGER", + "desc": { + "fr": "MANAGER - Gestionnaire de données", + "en": "MANAGER - Data Manager" + }, + "desclong": { + "fr": "Gestionnaire de données avec des accès sensible", + "en": "Data Manager with sensible data access" + } + }, + { + "uuid": "ADMIN", + "desc": { + "fr": "ADMIN - Admininstrateur", + "en": "ADMIN - Admin profil" + }, + "desclong": { + "fr": "Admininstrateur avec accès complet aux comptes", + "en": "Admin profil with full access" + } + } +] diff --git a/setup/data/domain/apixpress/referentials/dataManagement/data/role.json b/setup/data/domain/apixpress/referentials/dataManagement/data/role.json new file mode 100755 index 0000000..0dcf1c5 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/data/role.json @@ -0,0 +1,17 @@ +[ + { + "uuid": "OTHER", + "desclong": { "fr": "Autre", "en": "Other" }, + "desc": { "fr": "Aut.", "en": "Oth." } + }, + { + "uuid": "DIAG", + "desclong": { "fr": "Diagnostiqueur", "en": "Diag" }, + "desc": { "fr": "Diag", "en": "DIAG" } + }, + { + "uuid": "GEST", + "desclong": { "fr": "Gestion", "en": "Management" }, + "desc": { "fr": "Gest", "en": "Manag" } + } +] diff --git a/setup/data/domain/apixpress/referentials/dataManagement/json/catalogueCompanies.json b/setup/data/domain/apixpress/referentials/dataManagement/json/catalogueCompanies.json new file mode 100755 index 0000000..89ca765 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/json/catalogueCompanies.json @@ -0,0 +1,129 @@ +{ + "commentaire": "Parametrage permettant de mettre à jour le cataloguecatBoutiquefixe.json", + "nomcatalogue": "", + "objet": "companies", + "optioncatalogcsv": { + "retln": "\n", + "sep": ";", + "seplevel": "__", + "replacespecialcarCsv2Json": "[[/Semicolon/g,';']]", + "replacespecialcarJson2Csv": "[[/;/g, 'Semicolon']]" + }, + "removeforPublic": "", + "templates": { + "templateidintro": "", + "menu": "", + "header": "", + "section": "", + "filtre": "bdcfiltercateg", + "card": "bdccard" + }, + "vendeur": { + "nom": "Commune d’Igny", + "siret": "333 951 978 00050", + "responsable": "Marie Faujas (Directrice de la Communication, Culture et Evènementiel)", + "adressesociale": "23, avenue de la division Leclerc", + "CP": "91430", + "ville": "IGNY", + "logo": "logo.png", + "email": "mairie@igny.fr", + "tel": "01 69 33 11 19", + "telinter": "33169331119", + "cartegmap": "", + "reseauxociaux": [], + "horaire": "", + "horairedata": "", + "IBAN": "", + "tribunalRCS": "", + "ScanKbis": "", + "RIBSociete": "", + "ScanIdcardResp1": "", + "JustifDomicileResp1": "", + "ScanIdcardResp2": "", + "JustifDomicileResp2": "" + }, + "hebergeur": { + "nom": "SAS Need-Data", + "adresse": "6 Avenue des Andes", + "CP": "91940", + "Ville": "Les Ulis", + "site": "https://need-data.com" + }, + "page": { + "objettype": "page", + "nom": "", + "urlsite": "https://shop.igny.fr", + "couleurprimaire": "", + "couleursecondaire": "", + "description": "", + "metaauthor": "", + "keywords": "", + "ogtitle": "", + "ogvignette": "", + "title": "", + "ordre": [] + }, + "header": { + "objettype": "html", + "photopleinepage": "", + "TITREpage": "", + "SSTITREpage": "", + "inscriptionemailbouton": "S'inscrire", + "TEXTpage": "" + }, + "edito": { + "objettype": "html", + "tmpl": "sectionmaildigit", + "contenthtml": "static/data/staticContentwebsite/edito.html" + }, + "referencer": { + "objettype": "html", + "tmpl": "sectionmaildigit", + "contenthtml": "static/data/staticContentwebsite/referencer.html" + }, + "footer": { + "objettype": "html", + "tmpl": "sectionmaildigit", + "classsection": "footer text-center bg-primary text-white", + "contenthtml": "static/data/staticContentwebsite/footer.html" + }, + "catalogue": { + "objettype": "catalogueCards", + "tmpl": "sectionmaildigit", + "tpl": "", + "titre": "", + "sstitre": "", + "text": "", + "youtube": "", + "youtubesmallscreen": "", + "youtubebtn": "", + "filtrecatalog": { + "tpl": "bdcfiltercateg", + "btnlist": true, + "seleclist": false, + "classbtn": "btn-outline-primary", + "modalbutton": "video pour passer commande", + "modalcontent": "", + "modalcontentsmallscreen": "", + "classcolfiltre": "text-left", + "titrefiltre": "", + "message": "

La livraison est offerte à partir de 6 cartons 2 cartons (pendant la période de confinement)

", + "categorie": "Nos Gammes", + "btncategorie": "btn-outline-primary", + "item": [] + }, + "cards": { + "tpl": "bdccard", + "devise": "€", + "buttonajoutpanier": true, + "showAvailibility": false, + "masqueitemifnomoreavailable": true, + "buttonBookwithemail": false, + "buttonBookaddForm": true, + "cardClass": "col-12", + "btndesc": "Ajouter cette réservation", + "cardbtn": "btn-primary", + "objet": {} + } + } +} \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagement/json/importcsvCompanies.json b/setup/data/domain/apixpress/referentials/dataManagement/json/importcsvCompanies.json new file mode 100755 index 0000000..041d9b3 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/json/importcsvCompanies.json @@ -0,0 +1,18 @@ +{ + "commentaire": "Spécification permettant d'importer et d'exporter en csv des companies, pour documentation voir gitlab", + "object": "companies", + "cardscsv": "compagniesIGNY.csv", + "ASUPPcatalogPerso": "catalogueCommerceIGNY.csv", + "optioncardscsv": { + "retln": "\n", + "sep": ";", + "champs": ["UUID", "TYPE", "STATUT", "CATEGORIE", "TITRE", "SSTITRE", "KEYWORD", "MOTHTMLDUMAGASIN", "MOTTXTDUMAGASIN", "ADRESSE_PRO", "CP_PRO", "VILLE_PRO", "PHONE_PRO", "HORAIRESDESC", "HORAIREDATA", "URL", "FACEBOOK", "INSTA", "YOUTUBE", "LINKEDIN", "EMAIL_PRO", "IMG_VIGNETTE", "DATEOUVERTURE", "DATEFERMETURE", "HTML", "COMMENTPOSTTRT", "DATE_CREATE", "DATE_UPDATE"], + "array": ["CATEGORIE", "PHONE_PRO", "EMAIL_PRO"], + "arraysplitsep": ",", + "numericfield": [], + "search": "(fiche.UUID && fiche.UUID == data.UUID) || (fiche.EMAIL_PRO && utils.testinarray(fiche.EMAIL_PRO,data.EMAIL_PRO)) || (fiche.PHONE_PRO && utils.testinarray(fiche.PHONE_PRO,data.PHONE_PRO))", + "merge": [], + "replacespecialcarCsv2Json": "[[/Semicolon/g,';']]", + "replacespecialcarJson2Csv": "[[/;/g, 'Semicolon']]" + } +} \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagement/json/menuAdmin.json b/setup/data/domain/apixpress/referentials/dataManagement/json/menuAdmin.json new file mode 100755 index 0000000..d4adaa6 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/json/menuAdmin.json @@ -0,0 +1,134 @@ +{ + "fr": { + "menuleft": { + "sbbrandlink": "app.html", + "sbtitle": "YES", + "sbgroupmenu": [{ + "groupheader": "Suivi", + "sbssgroupmenu": [{ + "name": "Reporting", + "icon": "sliders", + "actionclick": "pwa.reporting.init()" + }, { + "name": "Test sous niveau", + "icon": "sliders", + "actionclick": "pwa.reporting.init()", + "iditemmenus": "suivitest", + "itemmenus": [{ + "name": "sousmenu", + "actionclick": "pwa.reporting.init()" + }] + }] + }, { + "groupheader": "Admin", + "sbssgroupmenu": [{ + "name": "Pagans", + "icon": "sliders", + "actionclick": "pwa.users.init()" + }, { + "name": "Referentiels", + "icon": "sliders", + "iditemmenus": "adminreferentiel", + "itemmenus": [{ + "name": "Offre", + "actionclick": "pwa.referential.setting('offre')" + }, { + "name": "return action", + "actionclick": "pwa.referential.setting('returnaction')" + }, { + "name": "data", + "actionclick": "pwa.referential.setting('data')" + }, { + "name": "json", + "actionclick": "pwa.referential.setting('json')" + }, { + "name": "Objects", + "actionclick": "pwa.referential.setting('object')" + }] + }] + }, { + "groupheader": "Teacher", + "sbssgroupmenu": [{ + "name": "Evaluation", + "icon": "sliders", + "actionclick": "pwa.evaluation.init()" + }, { + "name": "ScheduleOnce", + "icon": "sliders", + "actionclick": "pwa.scheduleonce.init()" + }] + }, { + "groupheader": "Operation", + "sbssgroupmenu": [{ + "name": "Action Learner", + "icon": "sliders", + "actionclick": "pwa.actionlearner.init()" + }, { + "name": "Action teacher", + "icon": "sliders", + "actionclick": "pwa.actionteacher.init()" + }] + }, { + "groupheader": "Marketing", + "sbssgroupmenu": [{ + "name": "Gestion l'offre", + "icon": "sliders", + "actionclick": "pwa.offers.init()" + }, { + "name": "Action teacher", + "icon": "sliders", + "actionclick": "pwa.actionteacher.init()" + }] + }, { + "groupheader": "Learner", + "sbssgroupmenu": [{ + "name": "Mes evaluations", + "icon": "sliders", + "actionclick": "pwa.learner.init()" + }, + { + "name": "Actions learner", + "icon": "sliders", + "actionclick": "pwa.learner.action()" + } + ] + }] + }, + "menutop": { + "withsearch": true, + "searchtxt": "Recherche...", + "withnotification": true, + "notificationheader": "Vos notifications", + "notificationfooter": "Voir toutes les notifications", + "href": "?action=notification.view", + "withmessage": false, + "messageheader": "Vos messages non lus", + "messagefooter": "Voir tous les messages", + "avatarimg": "", + "name": "", + "menuprofil": [{ + "icon": "user", + "desc": "Profile", + "href": "?action=user.settings", + "menubreaker": false + }, + { + "icon": "pie-chart", + "desc": "Activity", + "href": "?action=user.activity", + "menubreaker": true + }, + { + "icon": "settings", + "desc": "Log out", + "href": "?action=userauth.logout", + "menubreaker": false + } + ] + } + }, + "en": { + "menuleft": {}, + "menutop": {} + } +} \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagement/json/menuUser.json b/setup/data/domain/apixpress/referentials/dataManagement/json/menuUser.json new file mode 100755 index 0000000..d4adaa6 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/json/menuUser.json @@ -0,0 +1,134 @@ +{ + "fr": { + "menuleft": { + "sbbrandlink": "app.html", + "sbtitle": "YES", + "sbgroupmenu": [{ + "groupheader": "Suivi", + "sbssgroupmenu": [{ + "name": "Reporting", + "icon": "sliders", + "actionclick": "pwa.reporting.init()" + }, { + "name": "Test sous niveau", + "icon": "sliders", + "actionclick": "pwa.reporting.init()", + "iditemmenus": "suivitest", + "itemmenus": [{ + "name": "sousmenu", + "actionclick": "pwa.reporting.init()" + }] + }] + }, { + "groupheader": "Admin", + "sbssgroupmenu": [{ + "name": "Pagans", + "icon": "sliders", + "actionclick": "pwa.users.init()" + }, { + "name": "Referentiels", + "icon": "sliders", + "iditemmenus": "adminreferentiel", + "itemmenus": [{ + "name": "Offre", + "actionclick": "pwa.referential.setting('offre')" + }, { + "name": "return action", + "actionclick": "pwa.referential.setting('returnaction')" + }, { + "name": "data", + "actionclick": "pwa.referential.setting('data')" + }, { + "name": "json", + "actionclick": "pwa.referential.setting('json')" + }, { + "name": "Objects", + "actionclick": "pwa.referential.setting('object')" + }] + }] + }, { + "groupheader": "Teacher", + "sbssgroupmenu": [{ + "name": "Evaluation", + "icon": "sliders", + "actionclick": "pwa.evaluation.init()" + }, { + "name": "ScheduleOnce", + "icon": "sliders", + "actionclick": "pwa.scheduleonce.init()" + }] + }, { + "groupheader": "Operation", + "sbssgroupmenu": [{ + "name": "Action Learner", + "icon": "sliders", + "actionclick": "pwa.actionlearner.init()" + }, { + "name": "Action teacher", + "icon": "sliders", + "actionclick": "pwa.actionteacher.init()" + }] + }, { + "groupheader": "Marketing", + "sbssgroupmenu": [{ + "name": "Gestion l'offre", + "icon": "sliders", + "actionclick": "pwa.offers.init()" + }, { + "name": "Action teacher", + "icon": "sliders", + "actionclick": "pwa.actionteacher.init()" + }] + }, { + "groupheader": "Learner", + "sbssgroupmenu": [{ + "name": "Mes evaluations", + "icon": "sliders", + "actionclick": "pwa.learner.init()" + }, + { + "name": "Actions learner", + "icon": "sliders", + "actionclick": "pwa.learner.action()" + } + ] + }] + }, + "menutop": { + "withsearch": true, + "searchtxt": "Recherche...", + "withnotification": true, + "notificationheader": "Vos notifications", + "notificationfooter": "Voir toutes les notifications", + "href": "?action=notification.view", + "withmessage": false, + "messageheader": "Vos messages non lus", + "messagefooter": "Voir tous les messages", + "avatarimg": "", + "name": "", + "menuprofil": [{ + "icon": "user", + "desc": "Profile", + "href": "?action=user.settings", + "menubreaker": false + }, + { + "icon": "pie-chart", + "desc": "Activity", + "href": "?action=user.activity", + "menubreaker": true + }, + { + "icon": "settings", + "desc": "Log out", + "href": "?action=userauth.logout", + "menubreaker": false + } + ] + } + }, + "en": { + "menuleft": {}, + "menutop": {} + } +} \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagement/json/referentialsetting.json b/setup/data/domain/apixpress/referentials/dataManagement/json/referentialsetting.json new file mode 100755 index 0000000..0161474 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/json/referentialsetting.json @@ -0,0 +1,70 @@ +{ + "fr": { + "titre": "Gestion des référentiels Administrateur", + "submenutitre": "Liste", + "btnsave": "Sauvegarder", + "btndelete": "Supprimer", + "btncopy": "Dupliquer", + "copyplaceholder": "avec le nom de referentiel", + "submenuitems": [{ + "active": "active", + "groupinfo": "menuAdmin", + "id": "referentialmenuadmin", + "optionjsoneditor": { + "theme": "tailwind" + }, + "onclick": "pwa.referential.save(event,'referentialmenuadmin')" + }, { + "active": "", + "id": "referentialmenuteacher", + "optionjsoneditor": {}, + "groupinfo": "menuTeacher", + "onclick": "pwa.referential.save(event,'referentialmenuteacher')" + }, + { + "active": "", + "id": "referentialusersetting", + "groupinfo": "usersetting", + "optionjsoneditor": {}, + "btnsave": "Sauvegarder", + "onclick": "pwa.referential.save(event,'referentialmenuteacher')" + }, + { + "active": "", + "id": "referentialreferentialsettting", + "optionjsoneditor": {}, + "groupinfo": "referentialsetting", + "btnsave": "Sauvegarder", + "onclick": "pwa.referential.save(event,'referentialmenuteacher')" + } + ] + }, + "en": { + "titre": "Gestion des référentiels", + "submenutitre": "Liste", + "submenuitems": [{ + "active": "active", + "groupinfo": "menuAdmin.json", + "id": "referentialmenuadmin", + "btnsave": "Sauvegarder", + "onclick": "pwa.form.submit(event,'referentialmenuadmin',pwa.referentials.save)" + }, { + "active": "", + "id": "referentialmenuTeacher", + "groupinfo": "menuTeacher.json", + "btnsave": "Sauvegarder", + "onclick": "pwa.form.submit(event,'referentialmenuteacher',pwa.referentials.save)" + }, + { + "active": "", + "id": "referentialusersetting", + "groupinfo": "usersetting.json" + }, + { + "active": "", + "id": "referentialreferentialsettting", + "groupinfo": "referentialsetting.json" + } + ] + } +} \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagement/json/testref.json b/setup/data/domain/apixpress/referentials/dataManagement/json/testref.json new file mode 100755 index 0000000..7466b29 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/json/testref.json @@ -0,0 +1 @@ +{"fr":{"niv1":1,"niv2":12222222},"en":{"niv1":1,"niv2":2}} diff --git a/setup/data/domain/apixpress/referentials/dataManagement/json/usersetting.json b/setup/data/domain/apixpress/referentials/dataManagement/json/usersetting.json new file mode 100755 index 0000000..19fc213 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/json/usersetting.json @@ -0,0 +1,60 @@ +{ + "fr": { + "titre": "Information", + "submenutitre": "Vos paramétres", + "submenuitems": [{ + "active": "active", + "id": "usersettingaccount", + "groupinfo": "Compte", + "publicinfo": "Informations publiques", + "pseudoplaceholder": "Votre pseudo", + "pseudodesc": "Votre pseudo", + "biographyplaceholder": "Quelque chose qui vous décrit", + "biographydesc": "Biographie", + "imguserupload": "Charger votre avatar", + "infoimgavatar": "Pour un bon résultat, utiliser une image carrée de 128px au format .jpg", + "btnsave": "Sauvegarder", + "onclick": "pwa.form.submit(event,'userpublicinfo',pwa.user.save)" + }, { + "active": "", + "id": "usersettingpassword", + "groupinfo": "Mot de passe" + }, + { + "active": "", + "id": "usersettingprivacy", + "groupinfo": "Protection des données" + }, + { + "active": "", + "id": "usersettingdelete", + "groupinfo": "Supprimer son compte" + } + ] + }, + "en": { + "titre": "Information", + "submenutitre": "Vos paramétres", + "submenuitems": [{ + "active": "active", + "id": "usersettingaccount", + "groupinfo": "Compte" + + }, { + "active": "", + "id": "usersettingpassword", + "groupinfo": "Mot de passe" + }, + { + "active": "", + "id": "usersettingprivacy", + "groupinfo": "Protection des données" + }, + { + "active": "", + "id": "usersettingdelete", + "groupinfo": "Supprimer son compte" + } + ] + } +} \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagement/object/action.json b/setup/data/domain/apixpress/referentials/dataManagement/object/action.json new file mode 100755 index 0000000..3ea5e16 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/object/action.json @@ -0,0 +1,21 @@ +[ + { + "idfield": "uuid", + "desc": { "fr": "identifiant de l'action", "en": "action id" }, + "multilangue": false, + "required": true, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "desc", + "required": true, + "multilangue": true, + "desc": { + "fr": "Description courte de cette modalité d'action", + "en": "Short Modality Description" + }, + "type": "text", + "tpl": "questionInputVertical" + } +] diff --git a/setup/data/domain/apixpress/referentials/dataManagement/object/basic.json b/setup/data/domain/apixpress/referentials/dataManagement/object/basic.json new file mode 100755 index 0000000..8401c43 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/object/basic.json @@ -0,0 +1,40 @@ +[ + { + "idfield": "uuid", + "desc": { "fr": "identifiant de l'objet", "en": "object id" }, + "multilangue": false, + "required": true, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "desc", + "required": true, + "multilangue": true, + "desc": { + "fr": "Description courte de cette modalité d'objet", + "en": "Short Modality Description" + }, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "desclong", + "multilangue": true, + "desc": { + "fr": "Description de cette modalité d'objet", + "en": "Modality Description" + }, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "deschtml", + "desc": { + "fr": "Description en bloc html de cette modalité d'objet", + "en": "Html description of this object" + }, + "type": "text", + "tpl": "questionTextarea" + } +] diff --git a/setup/data/domain/apixpress/referentials/dataManagement/object/basicnolang.json b/setup/data/domain/apixpress/referentials/dataManagement/object/basicnolang.json new file mode 100755 index 0000000..0485e5d --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/object/basicnolang.json @@ -0,0 +1,41 @@ +[ + { + "idfield": "uuid", + "desc": { "fr": "identifiant de l'objet", "en": "object id" }, + "multilangue": false, + "required": true, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "desc", + "required": true, + "multilangue": false, + "desc": { + "fr": "Description courte de cette modalité d'objet", + "en": "Short Modality Description" + }, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "desclong", + "multilangue": true, + "desc": { + "fr": "Description de cette modalité d'objet", + "en": "Modality Description" + }, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "deschtml", + "multilangue": true, + "desc": { + "fr": "Description en bloc html de cette modalité d'objet", + "en": "Html description of this object" + }, + "type": "text", + "tpl": "questionTextarea" + } +] diff --git a/setup/data/domain/apixpress/referentials/dataManagement/object/cards.json b/setup/data/domain/apixpress/referentials/dataManagement/object/cards.json new file mode 100755 index 0000000..bd30352 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/object/cards.json @@ -0,0 +1,96 @@ +[{ + "idfield": "UUID", + "desc": { + "fr": "identifiant utilisateur", + "en": "user id" + }, + "nouservisible": true, + "check": ["required", "unique"], + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "LOGIN", + "check": ["required", "unique"], + "desc": { + "fr": "login", + "en": "login" + }, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "EMAIL", + "desc": { + "fr": "email", + "en": "email" + }, + "type": "email", + "check": ["email", "unique"], + "placeholder": "@", + "tpl": "questionInputVertical" + }, + { + "idfield": "NAME", + "desc": { + "fr": "Nom", + "en": "Name" + }, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "NICKNAME", + "desc": { + "fr": "Prénom", + "en": "Nickname" + }, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "PSEUDO", + "desc": { + "fr": "pseudo", + "en": "pseudo" + }, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "nouserupdate": true, + "idfield": "DATE_CREATE", + "desc": { + "fr": "Date de création", + "en": "Create Date" + }, + "type": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')", + "tpl": "questionInputVertical" + }, + { + "nouserupdate": true, + "idfield": "DATE_UPDATE", + "desc": { + "fr": "Date mise à jour", + "en": "Update date" + }, + "type": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')", + "tpl": "questionInputVertical" + }, + { + "nouserupdate": true, + "idfield": "DATE_LASTLOGIN", + "desc": { + "fr": "Date de derniére connexion", + "en": "Last date login" + }, + "type": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')", + "tpl": "questionInputVertical" + } +] \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagement/object/chgpsw.json b/setup/data/domain/apixpress/referentials/dataManagement/object/chgpsw.json new file mode 100755 index 0000000..a0ae028 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/object/chgpsw.json @@ -0,0 +1,54 @@ +[{ + "idfield": "UUID", + "desc": { + "fr": "identifiant utilisateur", + "en": "user id" + }, + "nouservisible": true, + "check": ["required"], + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "LOGIN", + "desc": { + "fr": "Login", + "en": "Login" + }, + "multilangue": false, + "required": true, + "nouserupdate": true, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "PASSWORD", + "required": true, + "desc": { + "fr": "Mot de passe actuel", + "en": "Current password" + }, + "type": "password", + "tpl": "questionInputVertical" + }, + { + "idfield": "PSNEW", + "required": true, + "check": ["password"], + "desc": { + "fr": "Nouveau mot de passe", + "en": "New password" + }, + "type": "password", + "tpl": "questionInputVertical" + }, + { + "idfield": "PSWNEWBIS", + "desc": { + "fr": "Confirmation de mot de passe", + "en": "Password confirmation" + }, + "type": "password", + "tpl": "questionInputVertical" + } +] \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagement/object/companies.json b/setup/data/domain/apixpress/referentials/dataManagement/object/companies.json new file mode 100755 index 0000000..bd30352 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/object/companies.json @@ -0,0 +1,96 @@ +[{ + "idfield": "UUID", + "desc": { + "fr": "identifiant utilisateur", + "en": "user id" + }, + "nouservisible": true, + "check": ["required", "unique"], + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "LOGIN", + "check": ["required", "unique"], + "desc": { + "fr": "login", + "en": "login" + }, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "EMAIL", + "desc": { + "fr": "email", + "en": "email" + }, + "type": "email", + "check": ["email", "unique"], + "placeholder": "@", + "tpl": "questionInputVertical" + }, + { + "idfield": "NAME", + "desc": { + "fr": "Nom", + "en": "Name" + }, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "NICKNAME", + "desc": { + "fr": "Prénom", + "en": "Nickname" + }, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "PSEUDO", + "desc": { + "fr": "pseudo", + "en": "pseudo" + }, + "type": "text", + "tpl": "questionInputVertical" + }, + { + "nouserupdate": true, + "idfield": "DATE_CREATE", + "desc": { + "fr": "Date de création", + "en": "Create Date" + }, + "type": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')", + "tpl": "questionInputVertical" + }, + { + "nouserupdate": true, + "idfield": "DATE_UPDATE", + "desc": { + "fr": "Date mise à jour", + "en": "Update date" + }, + "type": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')", + "tpl": "questionInputVertical" + }, + { + "nouserupdate": true, + "idfield": "DATE_LASTLOGIN", + "desc": { + "fr": "Date de derniére connexion", + "en": "Last date login" + }, + "type": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')", + "tpl": "questionInputVertical" + } +] \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagement/object/item.json b/setup/data/domain/apixpress/referentials/dataManagement/object/item.json new file mode 100755 index 0000000..a7d1b80 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/object/item.json @@ -0,0 +1,108 @@ +[{ + "idfield": "UUID", + "desc": { + "fr": "identifiant de l'items", + "en": "item id" + }, + "check": ["required", "unique"], + "type": "text", + "questioncollecte": "questioninput" + }, + { + "idfield": "ETAT", + "check": ["required"], + "desc": { + "fr": "Etat", + "en": "Stat" + }, + "type": "text", + "questioncollect": "questionselect", + "options": [{ + "uuid": "available", + "desc": { + "fr": "Disponible", + "en": "Available" + } + }, + { + "uuid": "unavailable", + "desc": { + "fr": "Indisponible", + "en": "Unavailable" + } + } + ] + }, + { + "idfield": "DESC", + "desc": { + "fr": "Description courte", + "en": "Short description" + }, + "questioncollecte": "questioninput" + }, + { + "idfield": "DESCLONG", + "desc": { + "fr": "Descrition longue", + "en": "Long description" + }, + "questioncollecte": "questioninput" + }, + { + "idfield": "URL", + "desc": { + "fr": "URL", + "en": "URL" + }, + "desclong": { + "fr": "Lien vers une page de détail de l'items", + "en": "Link to a web page that describe item" + }, + "questioncollecte": "questioninput" + }, + { + "idfield": "PRICETTC", + "desc": { + "fr": "Prix TTC en cents", + "en": "VAT Price in cents" + }, + "check": ["isInt"], + "desclong": { + "fr": "Prix TTC exprimé en cents Prix x 100", + "en": "Price including Tax x 100" + } + }, + { + "idfield": "CARACTERES", + "desc": { + "fr": "Objet contennat des caractéres pour mettre une mise en forme", + "en": " Contain list of characteristics to style " + }, + "desclong": { + "fr": "Stockage d'information pour décricre des formulaires", + "en": "" + } + }, + { + "idfield": "DATE_CREATE", + "desc": { + "fr": "Date de création", + "en": "Create Date" + }, + "type": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')", + "questioncollecte": "questioninput" + }, { + "idfield": "DATE_UPDATE", + "desc": { + "fr": "Date mise à jour", + "en": "Update date" + }, + "type": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')", + "questioncollecte": "questioninput" + } +] \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagement/object/userOperator.json b/setup/data/domain/apixpress/referentials/dataManagement/object/userOperator.json new file mode 100755 index 0000000..31be03e --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/object/userOperator.json @@ -0,0 +1,48 @@ +[{ + "idfield": "UUID", + "desc": { + "fr": "identifiant utilisateur", + "en": "user id" + }, + "nouservisible": true, + "check": ["required", "unique"], + "type": "text", + "tpl": "questionInputVertical" + }, + { + "nouserupdate": "!(['ADMIN','MANAGER'].includes(contexte.profil))", + "check": ["required"], + "idfield": "appsdiagimmoprofil", + "desc": { + "fr": "Droits" + }, + "desclong": { + "fr": "USER ne peut voir que ses informations, MANAGER voit tout le monde et peut modifier les informations, ADMIN accede à tout et peut modifier " + }, + "default": "USER", + "values": "profile", + "type": "text", + "tpl": "questionSelect" + }, + { + "idfield": "role", + "desc": { + "fr": "Rôle", + "en": "Role" + }, + "default": "Autre", + "values": "role", + "tpl": "questionSelect" + }, + { + "idfield": "manypseudo", + "desc": { + "fr": "Liste des noms touvés dans liciel séparé par , " + }, + "desclong": { + "fr": "Permet de regrouper plusieurs noms sous ce login" + }, + "type": "text", + "tpl": "questionInputVertical" + } +] \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagement/object/users.json b/setup/data/domain/apixpress/referentials/dataManagement/object/users.json new file mode 100755 index 0000000..0a14d3f --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagement/object/users.json @@ -0,0 +1,231 @@ +[{ + "idfield": "UUID", + "nouserupdate": true, + "nouservisible": true, + "desc": { + "fr": "identifiant utilisateur", + "en": "user id" + }, + "desclong": { + "fr": "Identifiant unique généré via UUID v4", + "en": "unique Id from a UUID v4" + }, + "info": { + "fr": "

L'usage d'UUID v4 permet de générer un code unique sans centralisation, car il est basé sur un timestamp et une clé crypto ce qui donne un code du type 7d8291c0-e137-11e8-9f7b-1dc8e57bed33

", + "en": "

UUID v4 allow a client to generate a unique code without centralisation, base on a timestamp and a salt it looks like 7d8291c0-e137-11e8-9f7b-1dc8e57bed33

" + }, + "check": ["required", "unique"], + "type": "text", + "tpl": "input" + }, + { + "idfield": "LOGIN", + "nouserupdate": true, + "check": ["required", "unique"], + "desc": { + "fr": "login", + "en": "login" + }, + "type": "text", + "tpl": "input", + "info": { + "fr": "

Le login doit être unique sur une instance d'apixtribe.

Pour échanger en dehors d'une instance apixtribe on utilise la clé public du user ou pour un humain login@apixtribe.domain.xx avec le nom du domaine qui heberge l'instance

Ou encore login@domain.xx tout domain.xx utilisé pour heberger un espace web client /tribeid/www/

", + "en": "

Login have to be unique into an apixtribe instance

To exchange outside of an apixtribe instance, we use PublicKey or login@apixtribe.domain.xx or login@domainclient.xx where domain.xx is a apixtribe name server on internet and domain.xx is a tribeid name where a /tribeid/www is available on the net.

" + } + }, + { + "idfield": "BIOGRAPHY", + "desc": { + "fr": "Vous en quelques mots", + "en": "Few words" + }, + "placeholder": { + "fr": "", + "en": "" + }, + "rows": 2, + "tpl": "textarea" + }, + { + "nouserupdate": true, + "idfield": "PUBLICKEY", + "desc": { + "fr": "Votre clé public pour ce compte", + "en": "Your public key for this uuid" + }, + "info": { + "fr": "

Cette clé est générée par votre navigateur, garder précisuesement votre clé privée que seule vous connaissez. En cas de perte de cette clé tous vos actifs seront perdus.

Cette méthode nous permet de vous garantir un contrôle total décentralisé.

", + "en": "

This key was generated by your browser, keep the private key related to this public key.

We garanty your total control by this way

." + }, + "tpl": "textarea" + }, + { + "idfield": "IMGAVATAR", + "tpl": "inputimg", + "altimg": "image avatar", + "classimg": "rounded-circle img-responsive mt-2", + "width": 128, + "height:" + 128, + "classdivupload": "mt-2", + "classbtn": "btn-primary", + "desc": { + "fr": "changer votre avatar", + "en": "upload an avatar" + }, + "info": { + "fr": "Pour un meilleur rendu, une mage carré de 128pc en foat jpg", + "en": "For best results, use an image at least 128px by 128px in .jpg format" + }, + + }, + { + "idfield": "EMAIL", + "desc": { + "fr": "email", + "en": "email" + }, + "tpl": "input", + "type": "email", + "check": ["emailadress", "unique"], + "placeholder": { + "fr": "#@", + "en": "@" + } + }, + { + "idfield": "NAME", + "desc": { + "fr": "Nom", + "en": "Name" + }, + "tpl": "input", + "type": "text" + }, + { + "idfield": "NICKNAME", + "desc": { + "fr": "Prénom", + "en": "Nickname" + }, + "tpl": "input", + "type": "text" + }, + { + "idfield": "PSEUDO", + "desc": { + "fr": "pseudo", + "en": "pseudo" + }, + "info": { + "fr": "

Nom avec lequel vous souhaitez qu'on vous reconnaisse sur l'instance de l'apixtribe

Attention ce nom n'est unique que sur une instance d'apixtribe. Un même speudo peut-être utilisé sur un autre serveur pour garantir l'identité vérifié pseudo@ domaine de rattachement.

", + "en": "

Carrefull a pseudo is unique into an instance of apixtribe to be sure to contact the right person check pseudo@ domain

.

Pseudo can be changed that is not the case of login.

" + }, + "tpl": "input", + "type": "text" + }, + { + "idfield": "ADDRESS1", + "desc": { + "fr": "Adresse", + "en": "Address" + }, + "tpl": "input", + "type": "text", + "placeholder": { + "fr": "1 chemin du paradis", + "123 Main St" + } + }, + { + "idfield": "ADDRESS2", + "desc": { + "fr": "Adresse 2", + "en": "Address 2" + }, + "tpl": "input", + "type": "text", + "placeholder": { + "fr": "Appartement B", + "Apt B" + } + }, + { + "idfield": "CITY", + "desc": { + "fr": "Ville ", + "en": "CITY" + }, + "tpl": "input", + "type": "text" + }, + + { + "idfield": "ZIP", + "desc": { + "fr": "Code Postal", + "en": "ZIP" + }, + "tpl": "input", + "type": "text" + }, + { + "idfield": "COUNTRY", + "desc": { + "fr": "Pays", + "en": "Country" + }, + "tpl": "input", + "type": "text" + }, + { + "nouserupdate": true, + "idfield": "DATE_CREATE", + "desc": { + "fr": "Date de création", + "en": "Create Date" + }, + "tpl": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')" + }, + { + "nouserupdate": true, + "idfield": "DATE_UPDATE", + "desc": { + "fr": "Date mise à jour", + "en": "Update date" + }, + "tpl": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')" + }, + { + "nouserupdate": true, + "idfield": "DATE_LASTLOGIN", + "desc": { + "fr": "Date de derniére connexion", + "en": "Last date login" + }, + "tpl": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')" + }, + { + "idfield": "ACCESSRIGHTS", + "nouserupdate": true, + "desc": { + "fr": "Vos droits d'accès", + "en": "Your access rights" + }, + "default": { + "app": {}, + "data": { + "tribeidname": { + "users": "O" + } + } + }, + "tpl": "jsoneditor" + } +] \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/dataManagementBackup/object/users.json b/setup/data/domain/apixpress/referentials/dataManagementBackup/object/users.json new file mode 100755 index 0000000..0a14d3f --- /dev/null +++ b/setup/data/domain/apixpress/referentials/dataManagementBackup/object/users.json @@ -0,0 +1,231 @@ +[{ + "idfield": "UUID", + "nouserupdate": true, + "nouservisible": true, + "desc": { + "fr": "identifiant utilisateur", + "en": "user id" + }, + "desclong": { + "fr": "Identifiant unique généré via UUID v4", + "en": "unique Id from a UUID v4" + }, + "info": { + "fr": "

L'usage d'UUID v4 permet de générer un code unique sans centralisation, car il est basé sur un timestamp et une clé crypto ce qui donne un code du type 7d8291c0-e137-11e8-9f7b-1dc8e57bed33

", + "en": "

UUID v4 allow a client to generate a unique code without centralisation, base on a timestamp and a salt it looks like 7d8291c0-e137-11e8-9f7b-1dc8e57bed33

" + }, + "check": ["required", "unique"], + "type": "text", + "tpl": "input" + }, + { + "idfield": "LOGIN", + "nouserupdate": true, + "check": ["required", "unique"], + "desc": { + "fr": "login", + "en": "login" + }, + "type": "text", + "tpl": "input", + "info": { + "fr": "

Le login doit être unique sur une instance d'apixtribe.

Pour échanger en dehors d'une instance apixtribe on utilise la clé public du user ou pour un humain login@apixtribe.domain.xx avec le nom du domaine qui heberge l'instance

Ou encore login@domain.xx tout domain.xx utilisé pour heberger un espace web client /tribeid/www/

", + "en": "

Login have to be unique into an apixtribe instance

To exchange outside of an apixtribe instance, we use PublicKey or login@apixtribe.domain.xx or login@domainclient.xx where domain.xx is a apixtribe name server on internet and domain.xx is a tribeid name where a /tribeid/www is available on the net.

" + } + }, + { + "idfield": "BIOGRAPHY", + "desc": { + "fr": "Vous en quelques mots", + "en": "Few words" + }, + "placeholder": { + "fr": "", + "en": "" + }, + "rows": 2, + "tpl": "textarea" + }, + { + "nouserupdate": true, + "idfield": "PUBLICKEY", + "desc": { + "fr": "Votre clé public pour ce compte", + "en": "Your public key for this uuid" + }, + "info": { + "fr": "

Cette clé est générée par votre navigateur, garder précisuesement votre clé privée que seule vous connaissez. En cas de perte de cette clé tous vos actifs seront perdus.

Cette méthode nous permet de vous garantir un contrôle total décentralisé.

", + "en": "

This key was generated by your browser, keep the private key related to this public key.

We garanty your total control by this way

." + }, + "tpl": "textarea" + }, + { + "idfield": "IMGAVATAR", + "tpl": "inputimg", + "altimg": "image avatar", + "classimg": "rounded-circle img-responsive mt-2", + "width": 128, + "height:" + 128, + "classdivupload": "mt-2", + "classbtn": "btn-primary", + "desc": { + "fr": "changer votre avatar", + "en": "upload an avatar" + }, + "info": { + "fr": "Pour un meilleur rendu, une mage carré de 128pc en foat jpg", + "en": "For best results, use an image at least 128px by 128px in .jpg format" + }, + + }, + { + "idfield": "EMAIL", + "desc": { + "fr": "email", + "en": "email" + }, + "tpl": "input", + "type": "email", + "check": ["emailadress", "unique"], + "placeholder": { + "fr": "#@", + "en": "@" + } + }, + { + "idfield": "NAME", + "desc": { + "fr": "Nom", + "en": "Name" + }, + "tpl": "input", + "type": "text" + }, + { + "idfield": "NICKNAME", + "desc": { + "fr": "Prénom", + "en": "Nickname" + }, + "tpl": "input", + "type": "text" + }, + { + "idfield": "PSEUDO", + "desc": { + "fr": "pseudo", + "en": "pseudo" + }, + "info": { + "fr": "

Nom avec lequel vous souhaitez qu'on vous reconnaisse sur l'instance de l'apixtribe

Attention ce nom n'est unique que sur une instance d'apixtribe. Un même speudo peut-être utilisé sur un autre serveur pour garantir l'identité vérifié pseudo@ domaine de rattachement.

", + "en": "

Carrefull a pseudo is unique into an instance of apixtribe to be sure to contact the right person check pseudo@ domain

.

Pseudo can be changed that is not the case of login.

" + }, + "tpl": "input", + "type": "text" + }, + { + "idfield": "ADDRESS1", + "desc": { + "fr": "Adresse", + "en": "Address" + }, + "tpl": "input", + "type": "text", + "placeholder": { + "fr": "1 chemin du paradis", + "123 Main St" + } + }, + { + "idfield": "ADDRESS2", + "desc": { + "fr": "Adresse 2", + "en": "Address 2" + }, + "tpl": "input", + "type": "text", + "placeholder": { + "fr": "Appartement B", + "Apt B" + } + }, + { + "idfield": "CITY", + "desc": { + "fr": "Ville ", + "en": "CITY" + }, + "tpl": "input", + "type": "text" + }, + + { + "idfield": "ZIP", + "desc": { + "fr": "Code Postal", + "en": "ZIP" + }, + "tpl": "input", + "type": "text" + }, + { + "idfield": "COUNTRY", + "desc": { + "fr": "Pays", + "en": "Country" + }, + "tpl": "input", + "type": "text" + }, + { + "nouserupdate": true, + "idfield": "DATE_CREATE", + "desc": { + "fr": "Date de création", + "en": "Create Date" + }, + "tpl": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')" + }, + { + "nouserupdate": true, + "idfield": "DATE_UPDATE", + "desc": { + "fr": "Date mise à jour", + "en": "Update date" + }, + "tpl": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')" + }, + { + "nouserupdate": true, + "idfield": "DATE_LASTLOGIN", + "desc": { + "fr": "Date de derniére connexion", + "en": "Last date login" + }, + "tpl": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')" + }, + { + "idfield": "ACCESSRIGHTS", + "nouserupdate": true, + "desc": { + "fr": "Vos droits d'accès", + "en": "Your access rights" + }, + "default": { + "app": {}, + "data": { + "tribeidname": { + "users": "O" + } + } + }, + "tpl": "jsoneditor" + } +] \ No newline at end of file diff --git a/setup/data/domain/apixpress/referentials/fr/object/users.json b/setup/data/domain/apixpress/referentials/fr/object/users.json new file mode 100755 index 0000000..ea57621 --- /dev/null +++ b/setup/data/domain/apixpress/referentials/fr/object/users.json @@ -0,0 +1,93 @@ +[{ + "idfield": "UUID", + "desc": "identifiant utilisateur", + "nouservisible": true, + "check": [ + "required", + "unique" + ], + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "LOGIN", + "check": [ + "required", + "unique" + ], + "desc": "login", + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "EMAIL", + "desc": "email", + "type": "email", + "check": [ + "emailadress", + "unique" + ], + "placeholder": "@", + "tpl": "questionInputVertical" + }, + { + "idfield": "NAME", + "desc": "Nom", + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "NICKNAME", + "desc": "Prénom", + "type": "text", + "tpl": "questionInputVertical" + }, + { + "idfield": "PSEUDO", + "desc": "pseudo", + "type": "text", + "tpl": "questionInputVertical" + }, + { + "nouserupdate": true, + "idfield": "DATE_CREATE", + "desc": "Date de création", + "type": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')", + "tpl": "questionInputVertical" + }, + { + "nouserupdate": true, + "idfield": "DATE_UPDATE", + "desc": "Date mise à jour", + "type": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')", + "tpl": "questionInputVertical" + }, + { + "nouserupdate": true, + "idfield": "DATE_LASTLOGIN", + "desc": "Date de derniére connexion", + "type": "date", + "format": "YYYY-MM-DD", + "default": "moment(new Date()).format('YYYY-MM-DD')", + "tpl": "questionInputVertical" + }, + { + "idfield": "accessrights", + "type": "json", + "nouserupdate": true, + "desc": "Vos droits d'accès", + "default": { + "app": {}, + "data": { + "tribeidname": { + "users": "O" + } + } + }, + "tpl": "jsoneditor" + } +] \ No newline at end of file diff --git a/setup/data/domain/apixpress/users/searchindex/emails.json b/setup/data/domain/apixpress/users/searchindex/emails.json new file mode 100755 index 0000000..3ddb614 --- /dev/null +++ b/setup/data/domain/apixpress/users/searchindex/emails.json @@ -0,0 +1,3 @@ +{ + "phc@ndda.fr": "admin" +} \ No newline at end of file diff --git a/setup/data/domain/apixpress/users/searchindex/logins.json b/setup/data/domain/apixpress/users/searchindex/logins.json new file mode 100755 index 0000000..efc39c9 --- /dev/null +++ b/setup/data/domain/apixpress/users/searchindex/logins.json @@ -0,0 +1,3 @@ +{ + "admin": "admin" +} \ No newline at end of file diff --git a/setup/data/domain/apixpress/users/searchindex/uids.json b/setup/data/domain/apixpress/users/searchindex/uids.json new file mode 100755 index 0000000..dd37254 --- /dev/null +++ b/setup/data/domain/apixpress/users/searchindex/uids.json @@ -0,0 +1,19 @@ +{ + "admin": [ + "admin", + "phc@ndda.fr", + "$2b$10$hFV/33UixB3Cn.XzLIhmTeRYU2XThnxYuwCVIifwQ7v/yCtRLIsuq", + { + "app": { + "apixtribe:webapp": "admin" + }, + "data": { + "apixtribe": { + "users": "CRUDO", + "referentials": "CRUDO" + } + } + }, + "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHBpcmF0aW9uIjoiMjAyMS0wOS0wMlQxMjo0ODowMS41OTNaIiwiVVVJRCI6IjEyM2FiYyJ9.4daX42iXqoblGL0c1Ga-hs5tGIoJEuWBSKqCayA-qNk" + ] +} \ No newline at end of file diff --git a/setup/data/domain/apixpress/www/app/webapp/app_index_fr.html b/setup/data/domain/apixpress/www/app/webapp/app_index_fr.html new file mode 100755 index 0000000..1183554 --- /dev/null +++ b/setup/data/domain/apixpress/www/app/webapp/app_index_fr.html @@ -0,0 +1,48 @@ + + + + + + + + + Need-Data manager> + + + + + + + +
+ +
+ +
+ +
+ +

Content when js is desactivated

+ + +
+
+
+
+
+
+

+ © +

+
+
+
    +
+
+
+
+
+
+ +
+ \ No newline at end of file diff --git a/setup/data/domain/apixpress/www/app/webapp/css/app/styles.css b/setup/data/domain/apixpress/www/app/webapp/css/app/styles.css new file mode 100755 index 0000000..43249eb --- /dev/null +++ b/setup/data/domain/apixpress/www/app/webapp/css/app/styles.css @@ -0,0 +1,14213 @@ +@charset "UTF-8"; +/*Automaticaly generated do not change*/ +/*! + * AdminKit v2.3.0 (https://adminkit.io/) + * Copyright 2021 Paul Laros + * Copyright 2021 AdminKit + * Licensed under MIT (https://github.com/adminkit/adminkit/blob/master/LICENSE) + */ +:root { + --bs-blue: #3B7DDD; + --bs-indigo: #6610f2; + --bs-purple: #6f42c1; + --bs-pink: #e83e8c; + --bs-red: #dc3545; + --bs-orange: #fd7e14; + --bs-yellow: #ffc107; + --bs-green: #28a745; + --bs-teal: #20c997; + --bs-cyan: #17a2b8; + --bs-white: #fff; + --bs-gray: #6c757d; + --bs-gray-dark: #343a40; + --bs-gray-100: #f8f9fa; + --bs-gray-200: #e9ecef; + --bs-gray-300: #dee2e6; + --bs-gray-400: #ced4da; + --bs-gray-500: #adb5bd; + --bs-gray-600: #6c757d; + --bs-gray-700: #495057; + --bs-gray-800: #343a40; + --bs-gray-900: #212529; + --bs-primary: #3B7DDD; + --bs-secondary: #6c757d; + --bs-success: #28a745; + --bs-info: #17a2b8; + --bs-warning: #ffc107; + --bs-danger: #dc3545; + --bs-light: #f8f9fa; + --bs-dark: #212529; + --bs-primary-rgb: 59, 125, 221; + --bs-secondary-rgb: 108, 117, 125; + --bs-success-rgb: 40, 167, 69; + --bs-info-rgb: 23, 162, 184; + --bs-warning-rgb: 255, 193, 7; + --bs-danger-rgb: 220, 53, 69; + --bs-light-rgb: 248, 249, 250; + --bs-dark-rgb: 33, 37, 41; + --bs-white-rgb: 255, 255, 255; + --bs-black-rgb: 0, 0, 0; + --bs-body-color-rgb: 73, 80, 87; + --bs-body-bg-rgb: 247, 247, 252; + --bs-font-sans-serif: "Inter", "Helvetica Neue", Arial, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); + --bs-body-font-family: var(--bs-font-sans-serif); + --bs-body-font-size: 0.875rem; + --bs-body-font-weight: 400; + --bs-body-line-height: 1.5; + --bs-body-color: #495057; + --bs-body-bg: #F7F7FC; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +@media (prefers-reduced-motion: no-preference) { + :root { + scroll-behavior: smooth; + } +} + +body { + margin: 0; + font-family: var(--bs-body-font-family); + font-size: var(--bs-body-font-size); + font-weight: var(--bs-body-font-weight); + line-height: var(--bs-body-line-height); + color: var(--bs-body-color); + text-align: var(--bs-body-text-align); + background-color: var(--bs-body-bg); + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +hr { + margin: 1rem 0; + color: inherit; + background-color: currentColor; + border: 0; + opacity: 0.25; +} + +hr:not([size]) { + height: 1px; +} + +h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6 { + margin-top: 0; + margin-bottom: 0.5rem; + font-weight: 400; + line-height: 1.2; + color: #000; +} + +h1, .h1 { + font-size: 1.75rem; +} + +h2, .h2 { + font-size: 1.53125rem; +} + +h3, .h3 { + font-size: 1.3125rem; +} + +h4, .h4 { + font-size: 1.09375rem; +} + +h5, .h5 { + font-size: 0.875rem; +} + +h6, .h6 { + font-size: 0.875rem; +} + +p { + margin-top: 0; + margin-bottom: 1rem; +} + +abbr[title], +abbr[data-bs-original-title] { + text-decoration: underline dotted; + cursor: help; + text-decoration-skip-ink: none; +} + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit; +} + +ol, +ul { + padding-left: 2rem; +} + +ol, +ul, +dl { + margin-top: 0; + margin-bottom: 1rem; +} + +ol ol, +ul ul, +ol ul, +ul ol { + margin-bottom: 0; +} + +dt { + font-weight: 600; +} + +dd { + margin-bottom: .5rem; + margin-left: 0; +} + +blockquote { + margin: 0 0 1rem; +} + +b, +strong { + font-weight: bolder; +} + +small, .small { + font-size: 80%; +} + +mark, .mark { + padding: 0.2em; + background-color: #fcf8e3; +} + +sub, +sup { + position: relative; + font-size: 0.75em; + line-height: 0; + vertical-align: baseline; +} + +sub { + bottom: -.25em; +} + +sup { + top: -.5em; +} + +a { + color: #3B7DDD; + text-decoration: none; +} + +a:hover { + color: #2f64b1; + text-decoration: underline; +} + +a:not([href]):not([class]), a:not([href]):not([class]):hover { + color: inherit; + text-decoration: none; +} + +pre, +code, +kbd, +samp { + font-family: var(--bs-font-monospace); + font-size: 1em; + direction: ltr /* rtl:ignore */; + unicode-bidi: bidi-override; +} + +pre { + display: block; + margin-top: 0; + margin-bottom: 1rem; + overflow: auto; + font-size: 80%; +} + +pre code { + font-size: inherit; + color: inherit; + word-break: normal; +} + +code { + font-size: 80%; + color: #e83e8c; + word-wrap: break-word; +} + +a > code { + color: inherit; +} + +kbd { + padding: 0.2rem 0.4rem; + font-size: 80%; + color: #fff; + background-color: #212529; + border-radius: 0.1rem; +} + +kbd kbd { + padding: 0; + font-size: 1em; + font-weight: 600; +} + +figure { + margin: 0 0 1rem; +} + +img, +svg { + vertical-align: middle; +} + +table { + caption-side: bottom; + border-collapse: collapse; +} + +caption { + padding-top: 0.75rem; + padding-bottom: 0.75rem; + color: #6c757d; + text-align: left; +} + +th { + text-align: inherit; + text-align: -webkit-match-parent; +} + +thead, +tbody, +tfoot, +tr, +td, +th { + border-color: inherit; + border-style: solid; + border-width: 0; +} + +label { + display: inline-block; +} + +button { + border-radius: 0; +} + +button:focus:not(:focus-visible) { + outline: 0; +} + +input, +button, +select, +optgroup, +textarea { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +button, +select { + text-transform: none; +} + +[role="button"] { + cursor: pointer; +} + +select { + word-wrap: normal; +} + +select:disabled { + opacity: 1; +} + +[list]::-webkit-calendar-picker-indicator { + display: none; +} + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +button:not(:disabled), +[type="button"]:not(:disabled), +[type="reset"]:not(:disabled), +[type="submit"]:not(:disabled) { + cursor: pointer; +} + +::-moz-focus-inner { + padding: 0; + border-style: none; +} + +textarea { + resize: vertical; +} + +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} + +legend { + float: left; + width: 100%; + padding: 0; + margin-bottom: 0.5rem; + font-size: 1.5rem; + line-height: inherit; +} + +legend + * { + clear: left; +} + +::-webkit-datetime-edit-fields-wrapper, +::-webkit-datetime-edit-text, +::-webkit-datetime-edit-minute, +::-webkit-datetime-edit-hour-field, +::-webkit-datetime-edit-day-field, +::-webkit-datetime-edit-month-field, +::-webkit-datetime-edit-year-field { + padding: 0; +} + +::-webkit-inner-spin-button { + height: auto; +} + +[type="search"] { + outline-offset: -2px; + -webkit-appearance: textfield; +} + +/* rtl:raw: +[type="tel"], +[type="url"], +[type="email"], +[type="number"] { + direction: ltr; +} +*/ +::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-color-swatch-wrapper { + padding: 0; +} + +::file-selector-button { + font: inherit; +} + +::-webkit-file-upload-button { + font: inherit; + -webkit-appearance: button; +} + +output { + display: inline-block; +} + +iframe { + border: 0; +} + +summary { + display: list-item; + cursor: pointer; +} + +progress { + vertical-align: baseline; +} + +[hidden] { + display: none !important; +} + +.lead { + font-size: 1.09375rem; + font-weight: 300; +} + +.display-1 { + font-size: 6rem; + font-weight: 300; + line-height: 1.2; +} + +.display-2 { + font-size: 5.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-3 { + font-size: 4.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-4 { + font-size: 3.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-5 { + font-size: 3rem; + font-weight: 300; + line-height: 1.2; +} + +.display-6 { + font-size: 2.5rem; + font-weight: 300; + line-height: 1.2; +} + +.list-unstyled { + padding-left: 0; + list-style: none; +} + +.list-inline { + padding-left: 0; + list-style: none; +} + +.list-inline-item { + display: inline-block; +} + +.list-inline-item:not(:last-child) { + margin-right: 0.5rem; +} + +.initialism { + font-size: 80%; + text-transform: uppercase; +} + +.blockquote { + margin-bottom: 1rem; + font-size: 1.09375rem; +} + +.blockquote > :last-child { + margin-bottom: 0; +} + +.blockquote-footer { + margin-top: -1rem; + margin-bottom: 1rem; + font-size: 80%; + color: #6c757d; +} + +.blockquote-footer::before { + content: "\2014\00A0"; +} + +.img-fluid { + max-width: 100%; + height: auto; +} + +.img-thumbnail { + padding: 0.25rem; + background-color: #F7F7FC; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + max-width: 100%; + height: auto; +} + +.figure { + display: inline-block; +} + +.figure-img { + margin-bottom: 0.5rem; + line-height: 1; +} + +.figure-caption { + font-size: 80%; + color: #6c757d; +} + +.container, +.container-fluid, +.container-sm, +.container-md, +.container-lg, +.container-xl { + width: 100%; + padding-right: var(--bs-gutter-x, 0.75rem); + padding-left: var(--bs-gutter-x, 0.75rem); + margin-right: auto; + margin-left: auto; +} + +@media (min-width: 576px) { + .container, .container-sm { + max-width: 540px; + } +} + +@media (min-width: 768px) { + .container, .container-sm, .container-md { + max-width: 720px; + } +} + +@media (min-width: 992px) { + .container, .container-sm, .container-md, .container-lg { + max-width: 960px; + } +} + +@media (min-width: 1200px) { + .container, .container-sm, .container-md, .container-lg, .container-xl { + max-width: 1200px; + } +} + +.row { + --bs-gutter-x: 24px; + --bs-gutter-y: 0; + display: flex; + flex-wrap: wrap; + margin-top: calc(-1 * var(--bs-gutter-y)); + margin-right: calc(-.5 * var(--bs-gutter-x)); + margin-left: calc(-.5 * var(--bs-gutter-x)); +} + +.row > * { + flex-shrink: 0; + width: 100%; + max-width: 100%; + padding-right: calc(var(--bs-gutter-x) * .5); + padding-left: calc(var(--bs-gutter-x) * .5); + margin-top: var(--bs-gutter-y); +} + +.col { + flex: 1 0 0%; +} + +.row-cols-auto > * { + flex: 0 0 auto; + width: auto; +} + +.row-cols-1 > * { + flex: 0 0 auto; + width: 100%; +} + +.row-cols-2 > * { + flex: 0 0 auto; + width: 50%; +} + +.row-cols-3 > * { + flex: 0 0 auto; + width: 33.33333%; +} + +.row-cols-4 > * { + flex: 0 0 auto; + width: 25%; +} + +.row-cols-5 > * { + flex: 0 0 auto; + width: 20%; +} + +.row-cols-6 > * { + flex: 0 0 auto; + width: 16.66667%; +} + +.col-auto { + flex: 0 0 auto; + width: auto; +} + +.col-1 { + flex: 0 0 auto; + width: 8.33333%; +} + +.col-2 { + flex: 0 0 auto; + width: 16.66667%; +} + +.col-3 { + flex: 0 0 auto; + width: 25%; +} + +.col-4 { + flex: 0 0 auto; + width: 33.33333%; +} + +.col-5 { + flex: 0 0 auto; + width: 41.66667%; +} + +.col-6 { + flex: 0 0 auto; + width: 50%; +} + +.col-7 { + flex: 0 0 auto; + width: 58.33333%; +} + +.col-8 { + flex: 0 0 auto; + width: 66.66667%; +} + +.col-9 { + flex: 0 0 auto; + width: 75%; +} + +.col-10 { + flex: 0 0 auto; + width: 83.33333%; +} + +.col-11 { + flex: 0 0 auto; + width: 91.66667%; +} + +.col-12 { + flex: 0 0 auto; + width: 100%; +} + +.offset-1 { + margin-left: 8.33333%; +} + +.offset-2 { + margin-left: 16.66667%; +} + +.offset-3 { + margin-left: 25%; +} + +.offset-4 { + margin-left: 33.33333%; +} + +.offset-5 { + margin-left: 41.66667%; +} + +.offset-6 { + margin-left: 50%; +} + +.offset-7 { + margin-left: 58.33333%; +} + +.offset-8 { + margin-left: 66.66667%; +} + +.offset-9 { + margin-left: 75%; +} + +.offset-10 { + margin-left: 83.33333%; +} + +.offset-11 { + margin-left: 91.66667%; +} + +.g-0, +.gx-0 { + --bs-gutter-x: 0; +} + +.g-0, +.gy-0 { + --bs-gutter-y: 0; +} + +.g-1, +.gx-1 { + --bs-gutter-x: 0.25rem; +} + +.g-1, +.gy-1 { + --bs-gutter-y: 0.25rem; +} + +.g-2, +.gx-2 { + --bs-gutter-x: 0.5rem; +} + +.g-2, +.gy-2 { + --bs-gutter-y: 0.5rem; +} + +.g-3, +.gx-3 { + --bs-gutter-x: 1rem; +} + +.g-3, +.gy-3 { + --bs-gutter-y: 1rem; +} + +.g-4, +.gx-4 { + --bs-gutter-x: 1.5rem; +} + +.g-4, +.gy-4 { + --bs-gutter-y: 1.5rem; +} + +.g-5, +.gx-5 { + --bs-gutter-x: 3rem; +} + +.g-5, +.gy-5 { + --bs-gutter-y: 3rem; +} + +.g-6, +.gx-6 { + --bs-gutter-x: 4.5rem; +} + +.g-6, +.gy-6 { + --bs-gutter-y: 4.5rem; +} + +.g-7, +.gx-7 { + --bs-gutter-x: 6rem; +} + +.g-7, +.gy-7 { + --bs-gutter-y: 6rem; +} + +@media (min-width: 576px) { + .col-sm { + flex: 1 0 0%; + } + .row-cols-sm-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-sm-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-sm-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-sm-3 > * { + flex: 0 0 auto; + width: 33.33333%; + } + .row-cols-sm-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-sm-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-sm-6 > * { + flex: 0 0 auto; + width: 16.66667%; + } + .col-sm-auto { + flex: 0 0 auto; + width: auto; + } + .col-sm-1 { + flex: 0 0 auto; + width: 8.33333%; + } + .col-sm-2 { + flex: 0 0 auto; + width: 16.66667%; + } + .col-sm-3 { + flex: 0 0 auto; + width: 25%; + } + .col-sm-4 { + flex: 0 0 auto; + width: 33.33333%; + } + .col-sm-5 { + flex: 0 0 auto; + width: 41.66667%; + } + .col-sm-6 { + flex: 0 0 auto; + width: 50%; + } + .col-sm-7 { + flex: 0 0 auto; + width: 58.33333%; + } + .col-sm-8 { + flex: 0 0 auto; + width: 66.66667%; + } + .col-sm-9 { + flex: 0 0 auto; + width: 75%; + } + .col-sm-10 { + flex: 0 0 auto; + width: 83.33333%; + } + .col-sm-11 { + flex: 0 0 auto; + width: 91.66667%; + } + .col-sm-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-sm-0 { + margin-left: 0; + } + .offset-sm-1 { + margin-left: 8.33333%; + } + .offset-sm-2 { + margin-left: 16.66667%; + } + .offset-sm-3 { + margin-left: 25%; + } + .offset-sm-4 { + margin-left: 33.33333%; + } + .offset-sm-5 { + margin-left: 41.66667%; + } + .offset-sm-6 { + margin-left: 50%; + } + .offset-sm-7 { + margin-left: 58.33333%; + } + .offset-sm-8 { + margin-left: 66.66667%; + } + .offset-sm-9 { + margin-left: 75%; + } + .offset-sm-10 { + margin-left: 83.33333%; + } + .offset-sm-11 { + margin-left: 91.66667%; + } + .g-sm-0, + .gx-sm-0 { + --bs-gutter-x: 0; + } + .g-sm-0, + .gy-sm-0 { + --bs-gutter-y: 0; + } + .g-sm-1, + .gx-sm-1 { + --bs-gutter-x: 0.25rem; + } + .g-sm-1, + .gy-sm-1 { + --bs-gutter-y: 0.25rem; + } + .g-sm-2, + .gx-sm-2 { + --bs-gutter-x: 0.5rem; + } + .g-sm-2, + .gy-sm-2 { + --bs-gutter-y: 0.5rem; + } + .g-sm-3, + .gx-sm-3 { + --bs-gutter-x: 1rem; + } + .g-sm-3, + .gy-sm-3 { + --bs-gutter-y: 1rem; + } + .g-sm-4, + .gx-sm-4 { + --bs-gutter-x: 1.5rem; + } + .g-sm-4, + .gy-sm-4 { + --bs-gutter-y: 1.5rem; + } + .g-sm-5, + .gx-sm-5 { + --bs-gutter-x: 3rem; + } + .g-sm-5, + .gy-sm-5 { + --bs-gutter-y: 3rem; + } + .g-sm-6, + .gx-sm-6 { + --bs-gutter-x: 4.5rem; + } + .g-sm-6, + .gy-sm-6 { + --bs-gutter-y: 4.5rem; + } + .g-sm-7, + .gx-sm-7 { + --bs-gutter-x: 6rem; + } + .g-sm-7, + .gy-sm-7 { + --bs-gutter-y: 6rem; + } +} + +@media (min-width: 768px) { + .col-md { + flex: 1 0 0%; + } + .row-cols-md-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-md-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-md-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-md-3 > * { + flex: 0 0 auto; + width: 33.33333%; + } + .row-cols-md-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-md-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-md-6 > * { + flex: 0 0 auto; + width: 16.66667%; + } + .col-md-auto { + flex: 0 0 auto; + width: auto; + } + .col-md-1 { + flex: 0 0 auto; + width: 8.33333%; + } + .col-md-2 { + flex: 0 0 auto; + width: 16.66667%; + } + .col-md-3 { + flex: 0 0 auto; + width: 25%; + } + .col-md-4 { + flex: 0 0 auto; + width: 33.33333%; + } + .col-md-5 { + flex: 0 0 auto; + width: 41.66667%; + } + .col-md-6 { + flex: 0 0 auto; + width: 50%; + } + .col-md-7 { + flex: 0 0 auto; + width: 58.33333%; + } + .col-md-8 { + flex: 0 0 auto; + width: 66.66667%; + } + .col-md-9 { + flex: 0 0 auto; + width: 75%; + } + .col-md-10 { + flex: 0 0 auto; + width: 83.33333%; + } + .col-md-11 { + flex: 0 0 auto; + width: 91.66667%; + } + .col-md-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-md-0 { + margin-left: 0; + } + .offset-md-1 { + margin-left: 8.33333%; + } + .offset-md-2 { + margin-left: 16.66667%; + } + .offset-md-3 { + margin-left: 25%; + } + .offset-md-4 { + margin-left: 33.33333%; + } + .offset-md-5 { + margin-left: 41.66667%; + } + .offset-md-6 { + margin-left: 50%; + } + .offset-md-7 { + margin-left: 58.33333%; + } + .offset-md-8 { + margin-left: 66.66667%; + } + .offset-md-9 { + margin-left: 75%; + } + .offset-md-10 { + margin-left: 83.33333%; + } + .offset-md-11 { + margin-left: 91.66667%; + } + .g-md-0, + .gx-md-0 { + --bs-gutter-x: 0; + } + .g-md-0, + .gy-md-0 { + --bs-gutter-y: 0; + } + .g-md-1, + .gx-md-1 { + --bs-gutter-x: 0.25rem; + } + .g-md-1, + .gy-md-1 { + --bs-gutter-y: 0.25rem; + } + .g-md-2, + .gx-md-2 { + --bs-gutter-x: 0.5rem; + } + .g-md-2, + .gy-md-2 { + --bs-gutter-y: 0.5rem; + } + .g-md-3, + .gx-md-3 { + --bs-gutter-x: 1rem; + } + .g-md-3, + .gy-md-3 { + --bs-gutter-y: 1rem; + } + .g-md-4, + .gx-md-4 { + --bs-gutter-x: 1.5rem; + } + .g-md-4, + .gy-md-4 { + --bs-gutter-y: 1.5rem; + } + .g-md-5, + .gx-md-5 { + --bs-gutter-x: 3rem; + } + .g-md-5, + .gy-md-5 { + --bs-gutter-y: 3rem; + } + .g-md-6, + .gx-md-6 { + --bs-gutter-x: 4.5rem; + } + .g-md-6, + .gy-md-6 { + --bs-gutter-y: 4.5rem; + } + .g-md-7, + .gx-md-7 { + --bs-gutter-x: 6rem; + } + .g-md-7, + .gy-md-7 { + --bs-gutter-y: 6rem; + } +} + +@media (min-width: 992px) { + .col-lg { + flex: 1 0 0%; + } + .row-cols-lg-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-lg-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-lg-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-lg-3 > * { + flex: 0 0 auto; + width: 33.33333%; + } + .row-cols-lg-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-lg-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-lg-6 > * { + flex: 0 0 auto; + width: 16.66667%; + } + .col-lg-auto { + flex: 0 0 auto; + width: auto; + } + .col-lg-1 { + flex: 0 0 auto; + width: 8.33333%; + } + .col-lg-2 { + flex: 0 0 auto; + width: 16.66667%; + } + .col-lg-3 { + flex: 0 0 auto; + width: 25%; + } + .col-lg-4 { + flex: 0 0 auto; + width: 33.33333%; + } + .col-lg-5 { + flex: 0 0 auto; + width: 41.66667%; + } + .col-lg-6 { + flex: 0 0 auto; + width: 50%; + } + .col-lg-7 { + flex: 0 0 auto; + width: 58.33333%; + } + .col-lg-8 { + flex: 0 0 auto; + width: 66.66667%; + } + .col-lg-9 { + flex: 0 0 auto; + width: 75%; + } + .col-lg-10 { + flex: 0 0 auto; + width: 83.33333%; + } + .col-lg-11 { + flex: 0 0 auto; + width: 91.66667%; + } + .col-lg-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-lg-0 { + margin-left: 0; + } + .offset-lg-1 { + margin-left: 8.33333%; + } + .offset-lg-2 { + margin-left: 16.66667%; + } + .offset-lg-3 { + margin-left: 25%; + } + .offset-lg-4 { + margin-left: 33.33333%; + } + .offset-lg-5 { + margin-left: 41.66667%; + } + .offset-lg-6 { + margin-left: 50%; + } + .offset-lg-7 { + margin-left: 58.33333%; + } + .offset-lg-8 { + margin-left: 66.66667%; + } + .offset-lg-9 { + margin-left: 75%; + } + .offset-lg-10 { + margin-left: 83.33333%; + } + .offset-lg-11 { + margin-left: 91.66667%; + } + .g-lg-0, + .gx-lg-0 { + --bs-gutter-x: 0; + } + .g-lg-0, + .gy-lg-0 { + --bs-gutter-y: 0; + } + .g-lg-1, + .gx-lg-1 { + --bs-gutter-x: 0.25rem; + } + .g-lg-1, + .gy-lg-1 { + --bs-gutter-y: 0.25rem; + } + .g-lg-2, + .gx-lg-2 { + --bs-gutter-x: 0.5rem; + } + .g-lg-2, + .gy-lg-2 { + --bs-gutter-y: 0.5rem; + } + .g-lg-3, + .gx-lg-3 { + --bs-gutter-x: 1rem; + } + .g-lg-3, + .gy-lg-3 { + --bs-gutter-y: 1rem; + } + .g-lg-4, + .gx-lg-4 { + --bs-gutter-x: 1.5rem; + } + .g-lg-4, + .gy-lg-4 { + --bs-gutter-y: 1.5rem; + } + .g-lg-5, + .gx-lg-5 { + --bs-gutter-x: 3rem; + } + .g-lg-5, + .gy-lg-5 { + --bs-gutter-y: 3rem; + } + .g-lg-6, + .gx-lg-6 { + --bs-gutter-x: 4.5rem; + } + .g-lg-6, + .gy-lg-6 { + --bs-gutter-y: 4.5rem; + } + .g-lg-7, + .gx-lg-7 { + --bs-gutter-x: 6rem; + } + .g-lg-7, + .gy-lg-7 { + --bs-gutter-y: 6rem; + } +} + +@media (min-width: 1200px) { + .col-xl { + flex: 1 0 0%; + } + .row-cols-xl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xl-3 > * { + flex: 0 0 auto; + width: 33.33333%; + } + .row-cols-xl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xl-6 > * { + flex: 0 0 auto; + width: 16.66667%; + } + .col-xl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xl-1 { + flex: 0 0 auto; + width: 8.33333%; + } + .col-xl-2 { + flex: 0 0 auto; + width: 16.66667%; + } + .col-xl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xl-4 { + flex: 0 0 auto; + width: 33.33333%; + } + .col-xl-5 { + flex: 0 0 auto; + width: 41.66667%; + } + .col-xl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xl-7 { + flex: 0 0 auto; + width: 58.33333%; + } + .col-xl-8 { + flex: 0 0 auto; + width: 66.66667%; + } + .col-xl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xl-10 { + flex: 0 0 auto; + width: 83.33333%; + } + .col-xl-11 { + flex: 0 0 auto; + width: 91.66667%; + } + .col-xl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xl-0 { + margin-left: 0; + } + .offset-xl-1 { + margin-left: 8.33333%; + } + .offset-xl-2 { + margin-left: 16.66667%; + } + .offset-xl-3 { + margin-left: 25%; + } + .offset-xl-4 { + margin-left: 33.33333%; + } + .offset-xl-5 { + margin-left: 41.66667%; + } + .offset-xl-6 { + margin-left: 50%; + } + .offset-xl-7 { + margin-left: 58.33333%; + } + .offset-xl-8 { + margin-left: 66.66667%; + } + .offset-xl-9 { + margin-left: 75%; + } + .offset-xl-10 { + margin-left: 83.33333%; + } + .offset-xl-11 { + margin-left: 91.66667%; + } + .g-xl-0, + .gx-xl-0 { + --bs-gutter-x: 0; + } + .g-xl-0, + .gy-xl-0 { + --bs-gutter-y: 0; + } + .g-xl-1, + .gx-xl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xl-1, + .gy-xl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xl-2, + .gx-xl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xl-2, + .gy-xl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xl-3, + .gx-xl-3 { + --bs-gutter-x: 1rem; + } + .g-xl-3, + .gy-xl-3 { + --bs-gutter-y: 1rem; + } + .g-xl-4, + .gx-xl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xl-4, + .gy-xl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xl-5, + .gx-xl-5 { + --bs-gutter-x: 3rem; + } + .g-xl-5, + .gy-xl-5 { + --bs-gutter-y: 3rem; + } + .g-xl-6, + .gx-xl-6 { + --bs-gutter-x: 4.5rem; + } + .g-xl-6, + .gy-xl-6 { + --bs-gutter-y: 4.5rem; + } + .g-xl-7, + .gx-xl-7 { + --bs-gutter-x: 6rem; + } + .g-xl-7, + .gy-xl-7 { + --bs-gutter-y: 6rem; + } +} + +@media (min-width: 1440px) { + .col-xxl { + flex: 1 0 0%; + } + .row-cols-xxl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xxl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xxl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xxl-3 > * { + flex: 0 0 auto; + width: 33.33333%; + } + .row-cols-xxl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xxl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xxl-6 > * { + flex: 0 0 auto; + width: 16.66667%; + } + .col-xxl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xxl-1 { + flex: 0 0 auto; + width: 8.33333%; + } + .col-xxl-2 { + flex: 0 0 auto; + width: 16.66667%; + } + .col-xxl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xxl-4 { + flex: 0 0 auto; + width: 33.33333%; + } + .col-xxl-5 { + flex: 0 0 auto; + width: 41.66667%; + } + .col-xxl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xxl-7 { + flex: 0 0 auto; + width: 58.33333%; + } + .col-xxl-8 { + flex: 0 0 auto; + width: 66.66667%; + } + .col-xxl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xxl-10 { + flex: 0 0 auto; + width: 83.33333%; + } + .col-xxl-11 { + flex: 0 0 auto; + width: 91.66667%; + } + .col-xxl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xxl-0 { + margin-left: 0; + } + .offset-xxl-1 { + margin-left: 8.33333%; + } + .offset-xxl-2 { + margin-left: 16.66667%; + } + .offset-xxl-3 { + margin-left: 25%; + } + .offset-xxl-4 { + margin-left: 33.33333%; + } + .offset-xxl-5 { + margin-left: 41.66667%; + } + .offset-xxl-6 { + margin-left: 50%; + } + .offset-xxl-7 { + margin-left: 58.33333%; + } + .offset-xxl-8 { + margin-left: 66.66667%; + } + .offset-xxl-9 { + margin-left: 75%; + } + .offset-xxl-10 { + margin-left: 83.33333%; + } + .offset-xxl-11 { + margin-left: 91.66667%; + } + .g-xxl-0, + .gx-xxl-0 { + --bs-gutter-x: 0; + } + .g-xxl-0, + .gy-xxl-0 { + --bs-gutter-y: 0; + } + .g-xxl-1, + .gx-xxl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xxl-1, + .gy-xxl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xxl-2, + .gx-xxl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xxl-2, + .gy-xxl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xxl-3, + .gx-xxl-3 { + --bs-gutter-x: 1rem; + } + .g-xxl-3, + .gy-xxl-3 { + --bs-gutter-y: 1rem; + } + .g-xxl-4, + .gx-xxl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xxl-4, + .gy-xxl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xxl-5, + .gx-xxl-5 { + --bs-gutter-x: 3rem; + } + .g-xxl-5, + .gy-xxl-5 { + --bs-gutter-y: 3rem; + } + .g-xxl-6, + .gx-xxl-6 { + --bs-gutter-x: 4.5rem; + } + .g-xxl-6, + .gy-xxl-6 { + --bs-gutter-y: 4.5rem; + } + .g-xxl-7, + .gx-xxl-7 { + --bs-gutter-x: 6rem; + } + .g-xxl-7, + .gy-xxl-7 { + --bs-gutter-y: 6rem; + } +} + +.table { + --bs-table-bg: transparent; + --bs-table-accent-bg: transparent; + --bs-table-striped-color: #495057; + --bs-table-striped-bg: #f8f9fa; + --bs-table-active-color: #495057; + --bs-table-active-bg: rgba(0, 0, 0, 0.1); + --bs-table-hover-color: #495057; + --bs-table-hover-bg: rgba(0, 0, 0, 0.0375); + width: 100%; + margin-bottom: 1rem; + color: #495057; + vertical-align: top; + border-color: #dee2e6; +} + +.table > :not(caption) > * > * { + padding: 0.75rem 0.75rem; + background-color: var(--bs-table-bg); + border-bottom-width: 1px; + box-shadow: inset 0 0 0 9999px var(--bs-table-accent-bg); +} + +.table > tbody { + vertical-align: inherit; +} + +.table > thead { + vertical-align: bottom; +} + +.table > :not(:first-child) { + border-top: 2px solid currentColor; +} + +.caption-top { + caption-side: top; +} + +.table-sm > :not(caption) > * > * { + padding: 0.3rem 0.3rem; +} + +.table-bordered > :not(caption) > * { + border-width: 1px 0; +} + +.table-bordered > :not(caption) > * > * { + border-width: 0 1px; +} + +.table-borderless > :not(caption) > * > * { + border-bottom-width: 0; +} + +.table-borderless > :not(:first-child) { + border-top-width: 0; +} + +.table-striped > tbody > tr:nth-of-type(odd) > * { + --bs-table-accent-bg: var(--bs-table-striped-bg); + color: var(--bs-table-striped-color); +} + +.table-active { + --bs-table-accent-bg: var(--bs-table-active-bg); + color: var(--bs-table-active-color); +} + +.table-hover > tbody > tr:hover > * { + --bs-table-accent-bg: var(--bs-table-hover-bg); + color: var(--bs-table-hover-color); +} + +.table-primary { + --bs-table-bg: #d8e5f8; + --bs-table-striped-bg: #cddaec; + --bs-table-striped-color: #000; + --bs-table-active-bg: #c2cedf; + --bs-table-active-color: #000; + --bs-table-hover-bg: #c8d4e5; + --bs-table-hover-color: #000; + color: #000; + border-color: #c2cedf; +} + +.table-secondary { + --bs-table-bg: #e2e3e5; + --bs-table-striped-bg: #d7d8da; + --bs-table-striped-color: #000; + --bs-table-active-bg: #cbccce; + --bs-table-active-color: #000; + --bs-table-hover-bg: #d1d2d4; + --bs-table-hover-color: #000; + color: #000; + border-color: #cbccce; +} + +.table-success { + --bs-table-bg: #d4edda; + --bs-table-striped-bg: #c9e1cf; + --bs-table-striped-color: #000; + --bs-table-active-bg: #bfd5c4; + --bs-table-active-color: #000; + --bs-table-hover-bg: #c4dbca; + --bs-table-hover-color: #000; + color: #000; + border-color: #bfd5c4; +} + +.table-info { + --bs-table-bg: #d1ecf1; + --bs-table-striped-bg: #c7e0e5; + --bs-table-striped-color: #000; + --bs-table-active-bg: #bcd4d9; + --bs-table-active-color: #000; + --bs-table-hover-bg: #c1dadf; + --bs-table-hover-color: #000; + color: #000; + border-color: #bcd4d9; +} + +.table-warning { + --bs-table-bg: #fff3cd; + --bs-table-striped-bg: #f2e7c3; + --bs-table-striped-color: #000; + --bs-table-active-bg: #e6dbb9; + --bs-table-active-color: #000; + --bs-table-hover-bg: #ece1be; + --bs-table-hover-color: #000; + color: #000; + border-color: #e6dbb9; +} + +.table-danger { + --bs-table-bg: #f8d7da; + --bs-table-striped-bg: #eccccf; + --bs-table-striped-color: #000; + --bs-table-active-bg: #dfc2c4; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e5c7ca; + --bs-table-hover-color: #000; + color: #000; + border-color: #dfc2c4; +} + +.table-light { + --bs-table-bg: #f8f9fa; + --bs-table-striped-bg: #ecedee; + --bs-table-striped-color: #000; + --bs-table-active-bg: #dfe0e1; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e5e6e7; + --bs-table-hover-color: #000; + color: #000; + border-color: #dfe0e1; +} + +.table-dark { + --bs-table-bg: #212529; + --bs-table-striped-bg: #2c3034; + --bs-table-striped-color: #fff; + --bs-table-active-bg: #373b3e; + --bs-table-active-color: #fff; + --bs-table-hover-bg: #323539; + --bs-table-hover-color: #fff; + color: #fff; + border-color: #373b3e; +} + +.table-responsive { + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +@media (max-width: 575.98px) { + .table-responsive-sm { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} + +@media (max-width: 767.98px) { + .table-responsive-md { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} + +@media (max-width: 991.98px) { + .table-responsive-lg { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} + +@media (max-width: 1199.98px) { + .table-responsive-xl { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} + +@media (max-width: 1439.98px) { + .table-responsive-xxl { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} + +.form-label { + margin-bottom: 0.5rem; +} + +.col-form-label { + padding-top: calc(0.25rem + 1px); + padding-bottom: calc(0.25rem + 1px); + margin-bottom: 0; + font-size: inherit; + line-height: 1.5; +} + +.col-form-label-lg { + padding-top: calc(0.35rem + 1px); + padding-bottom: calc(0.35rem + 1px); + font-size: 0.925rem; +} + +.col-form-label-sm { + padding-top: calc(0.15rem + 1px); + padding-bottom: calc(0.15rem + 1px); + font-size: 0.75rem; +} + +.form-text { + margin-top: 0.25rem; + font-size: 80%; + color: #6c757d; +} + +.form-control { + display: block; + width: 100%; + padding: 0.25rem 0.7rem; + font-size: 0.875rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ced4da; + appearance: none; + border-radius: 0.2rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .form-control { + transition: none; + } +} + +.form-control[type="file"] { + overflow: hidden; +} + +.form-control[type="file"]:not(:disabled):not([readonly]) { + cursor: pointer; +} + +.form-control:focus { + color: #495057; + background-color: #fff; + border-color: #9dbeee; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.form-control::-webkit-date-and-time-value { + height: 1.5em; +} + +.form-control::placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control:disabled, .form-control[readonly] { + background-color: #e9ecef; + opacity: 1; +} + +.form-control::file-selector-button { + padding: 0.25rem 0.7rem; + margin: -0.25rem -0.7rem; + margin-inline-end: 0.7rem; + color: #495057; + background-color: #e9ecef; + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: 1px; + border-radius: 0; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .form-control::file-selector-button { + transition: none; + } +} + +.form-control:hover:not(:disabled):not([readonly])::file-selector-button { + background-color: #dde0e3; +} + +.form-control::-webkit-file-upload-button { + padding: 0.25rem 0.7rem; + margin: -0.25rem -0.7rem; + margin-inline-end: 0.7rem; + color: #495057; + background-color: #e9ecef; + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: 1px; + border-radius: 0; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .form-control::-webkit-file-upload-button { + transition: none; + } +} + +.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button { + background-color: #dde0e3; +} + +.form-control-plaintext { + display: block; + width: 100%; + padding: 0.25rem 0; + margin-bottom: 0; + line-height: 1.5; + color: #495057; + background-color: transparent; + border: solid transparent; + border-width: 1px 0; +} + +.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg { + padding-right: 0; + padding-left: 0; +} + +.form-control-sm { + min-height: calc(1.425rem + 2px); + padding: 0.15rem 0.5rem; + font-size: 0.75rem; + border-radius: 0.1rem; +} + +.form-control-sm::file-selector-button { + padding: 0.15rem 0.5rem; + margin: -0.15rem -0.5rem; + margin-inline-end: 0.5rem; +} + +.form-control-sm::-webkit-file-upload-button { + padding: 0.15rem 0.5rem; + margin: -0.15rem -0.5rem; + margin-inline-end: 0.5rem; +} + +.form-control-lg { + min-height: calc(2.0875rem + 2px); + padding: 0.35rem 1rem; + font-size: 0.925rem; + border-radius: 0.3rem; +} + +.form-control-lg::file-selector-button { + padding: 0.35rem 1rem; + margin: -0.35rem -1rem; + margin-inline-end: 1rem; +} + +.form-control-lg::-webkit-file-upload-button { + padding: 0.35rem 1rem; + margin: -0.35rem -1rem; + margin-inline-end: 1rem; +} + +textarea.form-control { + min-height: calc(1.8125rem + 2px); +} + +textarea.form-control-sm { + min-height: calc(1.425rem + 2px); +} + +textarea.form-control-lg { + min-height: calc(2.0875rem + 2px); +} + +.form-control-color { + width: 3rem; + height: auto; + padding: 0.25rem; +} + +.form-control-color:not(:disabled):not([readonly]) { + cursor: pointer; +} + +.form-control-color::-moz-color-swatch { + height: 1.5em; + border-radius: 0.2rem; +} + +.form-control-color::-webkit-color-swatch { + height: 1.5em; + border-radius: 0.2rem; +} + +.form-select { + display: block; + width: 100%; + padding: 0.25rem 2.1rem 0.25rem 0.7rem; + -moz-padding-start: calc(0.7rem - 3px); + font-size: 0.875rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right 0.7rem center; + background-size: 16px 12px; + border: 1px solid #ced4da; + border-radius: 0.2rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .form-select { + transition: none; + } +} + +.form-select:focus { + border-color: #9dbeee; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.form-select[multiple], .form-select[size]:not([size="1"]) { + padding-right: 0.7rem; + background-image: none; +} + +.form-select:disabled { + background-color: #e9ecef; +} + +.form-select:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 #495057; +} + +.form-select-sm { + padding-top: 0.15rem; + padding-bottom: 0.15rem; + padding-left: 0.5rem; + font-size: 0.75rem; + border-radius: 0.1rem; +} + +.form-select-lg { + padding-top: 0.35rem; + padding-bottom: 0.35rem; + padding-left: 1rem; + font-size: 0.925rem; + border-radius: 0.3rem; +} + +.form-check { + display: block; + min-height: 1.3125rem; + padding-left: 1.5em; + margin-bottom: 0.125rem; +} + +.form-check .form-check-input { + float: left; + margin-left: -1.5em; +} + +.form-check-input { + width: 1em; + height: 1em; + margin-top: 0.25em; + vertical-align: top; + background-color: #fff; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + border: 1px solid rgba(0, 0, 0, 0.25); + appearance: none; + color-adjust: exact; +} + +.form-check-input[type="checkbox"] { + border-radius: 0.25em; +} + +.form-check-input[type="radio"] { + border-radius: 50%; +} + +.form-check-input:active { + filter: brightness(90%); +} + +.form-check-input:focus { + border-color: #9dbeee; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.form-check-input:checked { + background-color: #3B7DDD; + border-color: #3B7DDD; +} + +.form-check-input:checked[type="checkbox"] { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e"); +} + +.form-check-input:checked[type="radio"] { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e"); +} + +.form-check-input[type="checkbox"]:indeterminate { + background-color: #3B7DDD; + border-color: #3B7DDD; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e"); +} + +.form-check-input:disabled { + pointer-events: none; + filter: none; + opacity: 0.5; +} + +.form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label { + opacity: 0.5; +} + +.form-switch { + padding-left: 2.5em; +} + +.form-switch .form-check-input { + width: 2em; + margin-left: -2.5em; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e"); + background-position: left center; + border-radius: 2em; + transition: background-position 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .form-switch .form-check-input { + transition: none; + } +} + +.form-switch .form-check-input:focus { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%239dbeee'/%3e%3c/svg%3e"); +} + +.form-switch .form-check-input:checked { + background-position: right center; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e"); +} + +.form-check-inline { + display: inline-block; + margin-right: 1rem; +} + +.btn-check { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} + +.btn-check[disabled] + .btn, .btn-check:disabled + .btn { + pointer-events: none; + filter: none; + opacity: 0.65; +} + +.form-range { + width: 100%; + height: 1.4rem; + padding: 0; + background-color: transparent; + appearance: none; +} + +.form-range:focus { + outline: 0; +} + +.form-range:focus::-webkit-slider-thumb { + box-shadow: 0 0 0 1px #F7F7FC, 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.form-range:focus::-moz-range-thumb { + box-shadow: 0 0 0 1px #F7F7FC, 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.form-range::-moz-focus-outer { + border: 0; +} + +.form-range::-webkit-slider-thumb { + width: 1rem; + height: 1rem; + margin-top: -0.25rem; + background-color: #3B7DDD; + border: 0; + border-radius: 1rem; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .form-range::-webkit-slider-thumb { + transition: none; + } +} + +.form-range::-webkit-slider-thumb:active { + background-color: #c4d8f5; +} + +.form-range::-webkit-slider-runnable-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} + +.form-range::-moz-range-thumb { + width: 1rem; + height: 1rem; + background-color: #3B7DDD; + border: 0; + border-radius: 1rem; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .form-range::-moz-range-thumb { + transition: none; + } +} + +.form-range::-moz-range-thumb:active { + background-color: #c4d8f5; +} + +.form-range::-moz-range-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} + +.form-range:disabled { + pointer-events: none; +} + +.form-range:disabled::-webkit-slider-thumb { + background-color: #adb5bd; +} + +.form-range:disabled::-moz-range-thumb { + background-color: #adb5bd; +} + +.form-floating { + position: relative; +} + +.form-floating > .form-control, +.form-floating > .form-select { + height: calc(3.5rem + 2px); + line-height: 1.25; +} + +.form-floating > label { + position: absolute; + top: 0; + left: 0; + height: 100%; + padding: 1rem 0.7rem; + pointer-events: none; + border: 1px solid transparent; + transform-origin: 0 0; + transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .form-floating > label { + transition: none; + } +} + +.form-floating > .form-control { + padding: 1rem 0.7rem; +} + +.form-floating > .form-control::placeholder { + color: transparent; +} + +.form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown) { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} + +.form-floating > .form-control:-webkit-autofill { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} + +.form-floating > .form-select { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} + +.form-floating > .form-control:focus ~ label, +.form-floating > .form-control:not(:placeholder-shown) ~ label, +.form-floating > .form-select ~ label { + opacity: 0.65; + transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); +} + +.form-floating > .form-control:-webkit-autofill ~ label { + opacity: 0.65; + transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); +} + +.input-group { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: stretch; + width: 100%; +} + +.input-group > .form-control, +.input-group > .form-select { + position: relative; + flex: 1 1 auto; + width: 1%; + min-width: 0; +} + +.input-group > .form-control:focus, +.input-group > .form-select:focus { + z-index: 3; +} + +.input-group .btn { + position: relative; + z-index: 2; +} + +.input-group .btn:focus { + z-index: 3; +} + +.input-group-text { + display: flex; + align-items: center; + padding: 0.25rem 0.7rem; + font-size: 0.875rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + text-align: center; + white-space: nowrap; + background-color: #e9ecef; + border: 1px solid #ced4da; + border-radius: 0.2rem; +} + +.input-group-lg > .form-control, +.input-group-lg > .form-select, +.input-group-lg > .input-group-text, +.input-group-lg > .btn { + padding: 0.35rem 1rem; + font-size: 0.925rem; + border-radius: 0.3rem; +} + +.input-group-sm > .form-control, +.input-group-sm > .form-select, +.input-group-sm > .input-group-text, +.input-group-sm > .btn { + padding: 0.15rem 0.5rem; + font-size: 0.75rem; + border-radius: 0.1rem; +} + +.input-group-lg > .form-select, +.input-group-sm > .form-select { + padding-right: 2.8rem; +} + +.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu), +.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n + 3) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group.has-validation > :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu), +.input-group.has-validation > .dropdown-toggle:nth-last-child(n + 4) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) { + margin-left: -1px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.valid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #28a745; +} + +.valid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: .1rem; + font-size: 0.75rem; + color: #000; + background-color: rgba(40, 167, 69, 0.9); + border-radius: 0.2rem; +} + +.was-validated :valid ~ .valid-feedback, +.was-validated :valid ~ .valid-tooltip, +.is-valid ~ .valid-feedback, +.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .form-control:valid, .form-control.is-valid { + border-color: #28a745; +} + +.was-validated .form-control:valid:focus, .form-control.is-valid:focus { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .form-select:valid, .form-select.is-valid { + border-color: #28a745; +} + +.was-validated .form-select:valid:focus, .form-select.is-valid:focus { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .form-check-input:valid, .form-check-input.is-valid { + border-color: #28a745; +} + +.was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked { + background-color: #28a745; +} + +.was-validated .form-check-input:valid:focus, .form-check-input.is-valid:focus { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label { + color: #28a745; +} + +.form-check-inline .form-check-input ~ .valid-feedback { + margin-left: .5em; +} + +.was-validated .input-group .form-control:valid, .input-group .form-control.is-valid, .was-validated +.input-group .form-select:valid, +.input-group .form-select.is-valid { + z-index: 1; +} + +.was-validated .input-group .form-control:valid:focus, .input-group .form-control.is-valid:focus, .was-validated +.input-group .form-select:valid:focus, +.input-group .form-select.is-valid:focus { + z-index: 3; +} + +.invalid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #dc3545; +} + +.invalid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: .1rem; + font-size: 0.75rem; + color: #fff; + background-color: rgba(220, 53, 69, 0.9); + border-radius: 0.2rem; +} + +.was-validated :invalid ~ .invalid-feedback, +.was-validated :invalid ~ .invalid-tooltip, +.is-invalid ~ .invalid-feedback, +.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .form-control:invalid, .form-control.is-invalid { + border-color: #dc3545; +} + +.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .form-select:invalid, .form-select.is-invalid { + border-color: #dc3545; +} + +.was-validated .form-select:invalid:focus, .form-select.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .form-check-input:invalid, .form-check-input.is-invalid { + border-color: #dc3545; +} + +.was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked { + background-color: #dc3545; +} + +.was-validated .form-check-input:invalid:focus, .form-check-input.is-invalid:focus { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label { + color: #dc3545; +} + +.form-check-inline .form-check-input ~ .invalid-feedback { + margin-left: .5em; +} + +.was-validated .input-group .form-control:invalid, .input-group .form-control.is-invalid, .was-validated +.input-group .form-select:invalid, +.input-group .form-select.is-invalid { + z-index: 2; +} + +.was-validated .input-group .form-control:invalid:focus, .input-group .form-control.is-invalid:focus, .was-validated +.input-group .form-select:invalid:focus, +.input-group .form-select.is-invalid:focus { + z-index: 3; +} + +.btn { + display: inline-block; + font-weight: 400; + line-height: 1.5; + color: #495057; + text-align: center; + vertical-align: middle; + cursor: pointer; + user-select: none; + background-color: transparent; + border: 1px solid transparent; + padding: 0.25rem 0.7rem; + font-size: 0.875rem; + border-radius: 0.2rem; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .btn { + transition: none; + } +} + +.btn:hover { + color: #495057; + text-decoration: none; +} + +.btn-check:focus + .btn, .btn:focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.btn:disabled, .btn.disabled, +fieldset:disabled .btn { + pointer-events: none; + opacity: 0.65; +} + +.btn-primary { + color: #000; + background-color: #3B7DDD; + border-color: #3B7DDD; +} + +.btn-primary:hover { + color: #000; + background-color: #5891e2; + border-color: #4f8ae0; +} + +.btn-check:focus + .btn-primary, .btn-primary:focus { + color: #000; + background-color: #5891e2; + border-color: #4f8ae0; + box-shadow: 0 0 0 0.2rem rgba(50, 106, 188, 0.5); +} + +.btn-check:checked + .btn-primary, +.btn-check:active + .btn-primary, .btn-primary:active, .btn-primary.active, +.show > .btn-primary.dropdown-toggle { + color: #000; + background-color: #6297e4; + border-color: #4f8ae0; +} + +.btn-check:checked + .btn-primary:focus, +.btn-check:active + .btn-primary:focus, .btn-primary:active:focus, .btn-primary.active:focus, +.show > .btn-primary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(50, 106, 188, 0.5); +} + +.btn-primary:disabled, .btn-primary.disabled { + color: #000; + background-color: #3B7DDD; + border-color: #3B7DDD; +} + +.btn-secondary { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-secondary:hover { + color: #fff; + background-color: #5c636a; + border-color: #565e64; +} + +.btn-check:focus + .btn-secondary, .btn-secondary:focus { + color: #fff; + background-color: #5c636a; + border-color: #565e64; + box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); +} + +.btn-check:checked + .btn-secondary, +.btn-check:active + .btn-secondary, .btn-secondary:active, .btn-secondary.active, +.show > .btn-secondary.dropdown-toggle { + color: #fff; + background-color: #565e64; + border-color: #51585e; +} + +.btn-check:checked + .btn-secondary:focus, +.btn-check:active + .btn-secondary:focus, .btn-secondary:active:focus, .btn-secondary.active:focus, +.show > .btn-secondary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); +} + +.btn-secondary:disabled, .btn-secondary.disabled { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-success { + color: #000; + background-color: #28a745; + border-color: #28a745; +} + +.btn-success:hover { + color: #000; + background-color: #48b461; + border-color: #3eb058; +} + +.btn-check:focus + .btn-success, .btn-success:focus { + color: #000; + background-color: #48b461; + border-color: #3eb058; + box-shadow: 0 0 0 0.2rem rgba(34, 142, 59, 0.5); +} + +.btn-check:checked + .btn-success, +.btn-check:active + .btn-success, .btn-success:active, .btn-success.active, +.show > .btn-success.dropdown-toggle { + color: #000; + background-color: #53b96a; + border-color: #3eb058; +} + +.btn-check:checked + .btn-success:focus, +.btn-check:active + .btn-success:focus, .btn-success:active:focus, .btn-success.active:focus, +.show > .btn-success.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(34, 142, 59, 0.5); +} + +.btn-success:disabled, .btn-success.disabled { + color: #000; + background-color: #28a745; + border-color: #28a745; +} + +.btn-info { + color: #000; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-info:hover { + color: #000; + background-color: #3ab0c3; + border-color: #2eabbf; +} + +.btn-check:focus + .btn-info, .btn-info:focus { + color: #000; + background-color: #3ab0c3; + border-color: #2eabbf; + box-shadow: 0 0 0 0.2rem rgba(20, 138, 156, 0.5); +} + +.btn-check:checked + .btn-info, +.btn-check:active + .btn-info, .btn-info:active, .btn-info.active, +.show > .btn-info.dropdown-toggle { + color: #000; + background-color: #45b5c6; + border-color: #2eabbf; +} + +.btn-check:checked + .btn-info:focus, +.btn-check:active + .btn-info:focus, .btn-info:active:focus, .btn-info.active:focus, +.show > .btn-info.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(20, 138, 156, 0.5); +} + +.btn-info:disabled, .btn-info.disabled { + color: #000; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-warning { + color: #000; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-warning:hover { + color: #000; + background-color: #ffca2c; + border-color: #ffc720; +} + +.btn-check:focus + .btn-warning, .btn-warning:focus { + color: #000; + background-color: #ffca2c; + border-color: #ffc720; + box-shadow: 0 0 0 0.2rem rgba(217, 164, 6, 0.5); +} + +.btn-check:checked + .btn-warning, +.btn-check:active + .btn-warning, .btn-warning:active, .btn-warning.active, +.show > .btn-warning.dropdown-toggle { + color: #000; + background-color: #ffcd39; + border-color: #ffc720; +} + +.btn-check:checked + .btn-warning:focus, +.btn-check:active + .btn-warning:focus, .btn-warning:active:focus, .btn-warning.active:focus, +.show > .btn-warning.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(217, 164, 6, 0.5); +} + +.btn-warning:disabled, .btn-warning.disabled { + color: #000; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-danger { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-danger:hover { + color: #fff; + background-color: #bb2d3b; + border-color: #b02a37; +} + +.btn-check:focus + .btn-danger, .btn-danger:focus { + color: #fff; + background-color: #bb2d3b; + border-color: #b02a37; + box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); +} + +.btn-check:checked + .btn-danger, +.btn-check:active + .btn-danger, .btn-danger:active, .btn-danger.active, +.show > .btn-danger.dropdown-toggle { + color: #fff; + background-color: #b02a37; + border-color: #a52834; +} + +.btn-check:checked + .btn-danger:focus, +.btn-check:active + .btn-danger:focus, .btn-danger:active:focus, .btn-danger.active:focus, +.show > .btn-danger.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); +} + +.btn-danger:disabled, .btn-danger.disabled { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-light { + color: #000; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-light:hover { + color: #000; + background-color: #f9fafb; + border-color: #f9fafb; +} + +.btn-check:focus + .btn-light, .btn-light:focus { + color: #000; + background-color: #f9fafb; + border-color: #f9fafb; + box-shadow: 0 0 0 0.2rem rgba(211, 212, 213, 0.5); +} + +.btn-check:checked + .btn-light, +.btn-check:active + .btn-light, .btn-light:active, .btn-light.active, +.show > .btn-light.dropdown-toggle { + color: #000; + background-color: #f9fafb; + border-color: #f9fafb; +} + +.btn-check:checked + .btn-light:focus, +.btn-check:active + .btn-light:focus, .btn-light:active:focus, .btn-light.active:focus, +.show > .btn-light.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(211, 212, 213, 0.5); +} + +.btn-light:disabled, .btn-light.disabled { + color: #000; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-dark { + color: #fff; + background-color: #212529; + border-color: #212529; +} + +.btn-dark:hover { + color: #fff; + background-color: #1c1f23; + border-color: #1a1e21; +} + +.btn-check:focus + .btn-dark, .btn-dark:focus { + color: #fff; + background-color: #1c1f23; + border-color: #1a1e21; + box-shadow: 0 0 0 0.2rem rgba(66, 70, 73, 0.5); +} + +.btn-check:checked + .btn-dark, +.btn-check:active + .btn-dark, .btn-dark:active, .btn-dark.active, +.show > .btn-dark.dropdown-toggle { + color: #fff; + background-color: #1a1e21; + border-color: #191c1f; +} + +.btn-check:checked + .btn-dark:focus, +.btn-check:active + .btn-dark:focus, .btn-dark:active:focus, .btn-dark.active:focus, +.show > .btn-dark.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(66, 70, 73, 0.5); +} + +.btn-dark:disabled, .btn-dark.disabled { + color: #fff; + background-color: #212529; + border-color: #212529; +} + +.btn-outline-primary { + color: #3B7DDD; + border-color: #3B7DDD; +} + +.btn-outline-primary:hover { + color: #000; + background-color: #3B7DDD; + border-color: #3B7DDD; +} + +.btn-check:focus + .btn-outline-primary, .btn-outline-primary:focus { + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.5); +} + +.btn-check:checked + .btn-outline-primary, +.btn-check:active + .btn-outline-primary, .btn-outline-primary:active, .btn-outline-primary.active, .btn-outline-primary.dropdown-toggle.show { + color: #000; + background-color: #3B7DDD; + border-color: #3B7DDD; +} + +.btn-check:checked + .btn-outline-primary:focus, +.btn-check:active + .btn-outline-primary:focus, .btn-outline-primary:active:focus, .btn-outline-primary.active:focus, .btn-outline-primary.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.5); +} + +.btn-outline-primary:disabled, .btn-outline-primary.disabled { + color: #3B7DDD; + background-color: transparent; +} + +.btn-outline-secondary { + color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:hover { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-check:focus + .btn-outline-secondary, .btn-outline-secondary:focus { + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.btn-check:checked + .btn-outline-secondary, +.btn-check:active + .btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-check:checked + .btn-outline-secondary:focus, +.btn-check:active + .btn-outline-secondary:focus, .btn-outline-secondary:active:focus, .btn-outline-secondary.active:focus, .btn-outline-secondary.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.btn-outline-secondary:disabled, .btn-outline-secondary.disabled { + color: #6c757d; + background-color: transparent; +} + +.btn-outline-success { + color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:hover { + color: #000; + background-color: #28a745; + border-color: #28a745; +} + +.btn-check:focus + .btn-outline-success, .btn-outline-success:focus { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.btn-check:checked + .btn-outline-success, +.btn-check:active + .btn-outline-success, .btn-outline-success:active, .btn-outline-success.active, .btn-outline-success.dropdown-toggle.show { + color: #000; + background-color: #28a745; + border-color: #28a745; +} + +.btn-check:checked + .btn-outline-success:focus, +.btn-check:active + .btn-outline-success:focus, .btn-outline-success:active:focus, .btn-outline-success.active:focus, .btn-outline-success.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.btn-outline-success:disabled, .btn-outline-success.disabled { + color: #28a745; + background-color: transparent; +} + +.btn-outline-info { + color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:hover { + color: #000; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-check:focus + .btn-outline-info, .btn-outline-info:focus { + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.btn-check:checked + .btn-outline-info, +.btn-check:active + .btn-outline-info, .btn-outline-info:active, .btn-outline-info.active, .btn-outline-info.dropdown-toggle.show { + color: #000; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-check:checked + .btn-outline-info:focus, +.btn-check:active + .btn-outline-info:focus, .btn-outline-info:active:focus, .btn-outline-info.active:focus, .btn-outline-info.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.btn-outline-info:disabled, .btn-outline-info.disabled { + color: #17a2b8; + background-color: transparent; +} + +.btn-outline-warning { + color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:hover { + color: #000; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-check:focus + .btn-outline-warning, .btn-outline-warning:focus { + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.btn-check:checked + .btn-outline-warning, +.btn-check:active + .btn-outline-warning, .btn-outline-warning:active, .btn-outline-warning.active, .btn-outline-warning.dropdown-toggle.show { + color: #000; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-check:checked + .btn-outline-warning:focus, +.btn-check:active + .btn-outline-warning:focus, .btn-outline-warning:active:focus, .btn-outline-warning.active:focus, .btn-outline-warning.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.btn-outline-warning:disabled, .btn-outline-warning.disabled { + color: #ffc107; + background-color: transparent; +} + +.btn-outline-danger { + color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:hover { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-check:focus + .btn-outline-danger, .btn-outline-danger:focus { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.btn-check:checked + .btn-outline-danger, +.btn-check:active + .btn-outline-danger, .btn-outline-danger:active, .btn-outline-danger.active, .btn-outline-danger.dropdown-toggle.show { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-check:checked + .btn-outline-danger:focus, +.btn-check:active + .btn-outline-danger:focus, .btn-outline-danger:active:focus, .btn-outline-danger.active:focus, .btn-outline-danger.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.btn-outline-danger:disabled, .btn-outline-danger.disabled { + color: #dc3545; + background-color: transparent; +} + +.btn-outline-light { + color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:hover { + color: #000; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-check:focus + .btn-outline-light, .btn-outline-light:focus { + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.btn-check:checked + .btn-outline-light, +.btn-check:active + .btn-outline-light, .btn-outline-light:active, .btn-outline-light.active, .btn-outline-light.dropdown-toggle.show { + color: #000; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-check:checked + .btn-outline-light:focus, +.btn-check:active + .btn-outline-light:focus, .btn-outline-light:active:focus, .btn-outline-light.active:focus, .btn-outline-light.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.btn-outline-light:disabled, .btn-outline-light.disabled { + color: #f8f9fa; + background-color: transparent; +} + +.btn-outline-dark { + color: #212529; + border-color: #212529; +} + +.btn-outline-dark:hover { + color: #fff; + background-color: #212529; + border-color: #212529; +} + +.btn-check:focus + .btn-outline-dark, .btn-outline-dark:focus { + box-shadow: 0 0 0 0.2rem rgba(33, 37, 41, 0.5); +} + +.btn-check:checked + .btn-outline-dark, +.btn-check:active + .btn-outline-dark, .btn-outline-dark:active, .btn-outline-dark.active, .btn-outline-dark.dropdown-toggle.show { + color: #fff; + background-color: #212529; + border-color: #212529; +} + +.btn-check:checked + .btn-outline-dark:focus, +.btn-check:active + .btn-outline-dark:focus, .btn-outline-dark:active:focus, .btn-outline-dark.active:focus, .btn-outline-dark.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(33, 37, 41, 0.5); +} + +.btn-outline-dark:disabled, .btn-outline-dark.disabled { + color: #212529; + background-color: transparent; +} + +.btn-link { + font-weight: 400; + color: #3B7DDD; + text-decoration: none; +} + +.btn-link:hover { + color: #2f64b1; + text-decoration: underline; +} + +.btn-link:focus { + text-decoration: underline; +} + +.btn-link:disabled, .btn-link.disabled { + color: #6c757d; +} + +.btn-lg, .btn-group-lg > .btn { + padding: 0.35rem 1rem; + font-size: 0.925rem; + border-radius: 0.3rem; +} + +.btn-sm, .btn-group-sm > .btn { + padding: 0.15rem 0.5rem; + font-size: 0.75rem; + border-radius: 0.1rem; +} + +.fade { + transition: opacity 0.15s linear; +} + +@media (prefers-reduced-motion: reduce) { + .fade { + transition: none; + } +} + +.fade:not(.show) { + opacity: 0; +} + +.collapse:not(.show) { + display: none; +} + +.collapsing { + height: 0; + overflow: hidden; + transition: height 0.35s ease; +} + +@media (prefers-reduced-motion: reduce) { + .collapsing { + transition: none; + } +} + +.collapsing.collapse-horizontal { + width: 0; + height: auto; + transition: width 0.35s ease; +} + +@media (prefers-reduced-motion: reduce) { + .collapsing.collapse-horizontal { + transition: none; + } +} + +.dropup, +.dropend, +.dropdown, +.dropstart { + position: relative; +} + +.dropdown-toggle { + white-space: nowrap; +} + +.dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid; + border-right: 0.3em solid transparent; + border-bottom: 0; + border-left: 0.3em solid transparent; +} + +.dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropdown-menu { + position: absolute; + z-index: 1000; + display: none; + min-width: 10rem; + padding: 0.5rem 0; + margin: 0; + font-size: 0.875rem; + color: #495057; + text-align: left; + list-style: none; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 0.2rem; +} + +.dropdown-menu[data-bs-popper] { + top: 100%; + left: 0; + margin-top: 0.125rem; +} + +.dropdown-menu-start { + --bs-position: start; +} + +.dropdown-menu-start[data-bs-popper] { + right: auto; + left: 0; +} + +.dropdown-menu-end { + --bs-position: end; +} + +.dropdown-menu-end[data-bs-popper] { + right: 0; + left: auto; +} + +@media (min-width: 576px) { + .dropdown-menu-sm-start { + --bs-position: start; + } + .dropdown-menu-sm-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-sm-end { + --bs-position: end; + } + .dropdown-menu-sm-end[data-bs-popper] { + right: 0; + left: auto; + } +} + +@media (min-width: 768px) { + .dropdown-menu-md-start { + --bs-position: start; + } + .dropdown-menu-md-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-md-end { + --bs-position: end; + } + .dropdown-menu-md-end[data-bs-popper] { + right: 0; + left: auto; + } +} + +@media (min-width: 992px) { + .dropdown-menu-lg-start { + --bs-position: start; + } + .dropdown-menu-lg-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-lg-end { + --bs-position: end; + } + .dropdown-menu-lg-end[data-bs-popper] { + right: 0; + left: auto; + } +} + +@media (min-width: 1200px) { + .dropdown-menu-xl-start { + --bs-position: start; + } + .dropdown-menu-xl-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-xl-end { + --bs-position: end; + } + .dropdown-menu-xl-end[data-bs-popper] { + right: 0; + left: auto; + } +} + +@media (min-width: 1440px) { + .dropdown-menu-xxl-start { + --bs-position: start; + } + .dropdown-menu-xxl-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-xxl-end { + --bs-position: end; + } + .dropdown-menu-xxl-end[data-bs-popper] { + right: 0; + left: auto; + } +} + +.dropup .dropdown-menu[data-bs-popper] { + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: 0.125rem; +} + +.dropup .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0; + border-right: 0.3em solid transparent; + border-bottom: 0.3em solid; + border-left: 0.3em solid transparent; +} + +.dropup .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropend .dropdown-menu[data-bs-popper] { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: 0.125rem; +} + +.dropend .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0; + border-bottom: 0.3em solid transparent; + border-left: 0.3em solid; +} + +.dropend .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropend .dropdown-toggle::after { + vertical-align: 0; +} + +.dropstart .dropdown-menu[data-bs-popper] { + top: 0; + right: 100%; + left: auto; + margin-top: 0; + margin-right: 0.125rem; +} + +.dropstart .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; +} + +.dropstart .dropdown-toggle::after { + display: none; +} + +.dropstart .dropdown-toggle::before { + display: inline-block; + margin-right: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0.3em solid; + border-bottom: 0.3em solid transparent; +} + +.dropstart .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropstart .dropdown-toggle::before { + vertical-align: 0; +} + +.dropdown-divider { + height: 0; + margin: 0.5rem 0; + overflow: hidden; + border-top: 1px solid rgba(0, 0, 0, 0.15); +} + +.dropdown-item { + display: block; + width: 100%; + padding: 0.35rem 1.5rem; + clear: both; + font-weight: 400; + color: #495057; + text-align: inherit; + white-space: nowrap; + background-color: transparent; + border: 0; +} + +.dropdown-item:hover, .dropdown-item:focus { + color: #42484e; + text-decoration: none; + background-color: #f8f9fa; +} + +.dropdown-item.active, .dropdown-item:active { + color: #fff; + text-decoration: none; + background-color: #3B7DDD; +} + +.dropdown-item.disabled, .dropdown-item:disabled { + color: #adb5bd; + pointer-events: none; + background-color: transparent; +} + +.dropdown-menu.show { + display: block; +} + +.dropdown-header { + display: block; + padding: 0.5rem 1.5rem; + margin-bottom: 0; + font-size: 0.75rem; + color: #6c757d; + white-space: nowrap; +} + +.dropdown-item-text { + display: block; + padding: 0.35rem 1.5rem; + color: #495057; +} + +.dropdown-menu-dark { + color: #dee2e6; + background-color: #343a40; + border-color: rgba(0, 0, 0, 0.15); +} + +.dropdown-menu-dark .dropdown-item { + color: #dee2e6; +} + +.dropdown-menu-dark .dropdown-item:hover, .dropdown-menu-dark .dropdown-item:focus { + color: #fff; + background-color: rgba(255, 255, 255, 0.15); +} + +.dropdown-menu-dark .dropdown-item.active, .dropdown-menu-dark .dropdown-item:active { + color: #fff; + background-color: #3B7DDD; +} + +.dropdown-menu-dark .dropdown-item.disabled, .dropdown-menu-dark .dropdown-item:disabled { + color: #adb5bd; +} + +.dropdown-menu-dark .dropdown-divider { + border-color: rgba(0, 0, 0, 0.15); +} + +.dropdown-menu-dark .dropdown-item-text { + color: #dee2e6; +} + +.dropdown-menu-dark .dropdown-header { + color: #adb5bd; +} + +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-flex; + vertical-align: middle; +} + +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + flex: 1 1 auto; +} + +.btn-group > .btn-check:checked + .btn, +.btn-group > .btn-check:focus + .btn, +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn-check:checked + .btn, +.btn-group-vertical > .btn-check:focus + .btn, +.btn-group-vertical > .btn:hover, +.btn-group-vertical > .btn:focus, +.btn-group-vertical > .btn:active, +.btn-group-vertical > .btn.active { + z-index: 1; +} + +.btn-toolbar { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} + +.btn-toolbar .input-group { + width: auto; +} + +.btn-group > .btn:not(:first-child), +.btn-group > .btn-group:not(:first-child) { + margin-left: -1px; +} + +.btn-group > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group > .btn-group:not(:last-child) > .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.btn-group > .btn:nth-child(n + 3), +.btn-group > :not(.btn-check) + .btn, +.btn-group > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.dropdown-toggle-split { + padding-right: 0.525rem; + padding-left: 0.525rem; +} + +.dropdown-toggle-split::after, +.dropup .dropdown-toggle-split::after, +.dropend .dropdown-toggle-split::after { + margin-left: 0; +} + +.dropstart .dropdown-toggle-split::before { + margin-right: 0; +} + +.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split { + padding-right: 0.375rem; + padding-left: 0.375rem; +} + +.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split { + padding-right: 0.75rem; + padding-left: 0.75rem; +} + +.btn-group-vertical { + flex-direction: column; + align-items: flex-start; + justify-content: center; +} + +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group { + width: 100%; +} + +.btn-group-vertical > .btn:not(:first-child), +.btn-group-vertical > .btn-group:not(:first-child) { + margin-top: -1px; +} + +.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group-vertical > .btn-group:not(:last-child) > .btn { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.btn-group-vertical > .btn ~ .btn, +.btn-group-vertical > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav { + display: flex; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav-link { + display: block; + padding: 0.5rem 1rem; + color: #3B7DDD; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .nav-link { + transition: none; + } +} + +.nav-link:hover, .nav-link:focus { + color: #2f64b1; + text-decoration: none; +} + +.nav-link.disabled { + color: #6c757d; + pointer-events: none; + cursor: default; +} + +.nav-tabs { + border-bottom: 1px solid #dee2e6; +} + +.nav-tabs .nav-link { + margin-bottom: -1px; + background: none; + border: 1px solid transparent; + border-top-left-radius: 0.2rem; + border-top-right-radius: 0.2rem; +} + +.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { + border-color: #e9ecef #e9ecef #dee2e6; + isolation: isolate; +} + +.nav-tabs .nav-link.disabled { + color: #6c757d; + background-color: transparent; + border-color: transparent; +} + +.nav-tabs .nav-link.active, +.nav-tabs .nav-item.show .nav-link { + color: #495057; + background-color: #F7F7FC; + border-color: #dee2e6 #dee2e6 #F7F7FC; +} + +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav-pills .nav-link { + background: none; + border: 0; + border-radius: 0.2rem; +} + +.nav-pills .nav-link.active, +.nav-pills .show > .nav-link { + color: #fff; + background-color: #3B7DDD; +} + +.nav-fill > .nav-link, +.nav-fill .nav-item { + flex: 1 1 auto; + text-align: center; +} + +.nav-justified > .nav-link, +.nav-justified .nav-item { + flex-basis: 0; + flex-grow: 1; + text-align: center; +} + +.nav-fill .nav-item .nav-link, +.nav-justified .nav-item .nav-link { + width: 100%; +} + +.tab-content > .tab-pane { + display: none; +} + +.tab-content > .active { + display: block; +} + +.navbar { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + padding-top: 0.875rem; + padding-right: 1.375rem; + padding-bottom: 0.875rem; + padding-left: 1.375rem; +} + +.navbar > .container, +.navbar > .container-fluid, .navbar > .container-sm, .navbar > .container-md, .navbar > .container-lg, .navbar > .container-xl { + display: flex; + flex-wrap: inherit; + align-items: center; + justify-content: space-between; +} + +.navbar-brand { + padding-top: 0.875rem; + padding-bottom: 0.875rem; + margin-right: 1rem; + font-size: 1.15rem; + white-space: nowrap; +} + +.navbar-brand:hover, .navbar-brand:focus { + text-decoration: none; +} + +.navbar-nav { + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.navbar-nav .nav-link { + padding-right: 0; + padding-left: 0; +} + +.navbar-nav .dropdown-menu { + position: static; +} + +.navbar-text { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.navbar-collapse { + flex-basis: 100%; + flex-grow: 1; + align-items: center; +} + +.navbar-toggler { + padding: 0.25rem 0.75rem; + font-size: 0.925rem; + line-height: 1; + background-color: transparent; + border: 1px solid transparent; + border-radius: 0.2rem; + transition: box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .navbar-toggler { + transition: none; + } +} + +.navbar-toggler:hover { + text-decoration: none; +} + +.navbar-toggler:focus { + text-decoration: none; + outline: 0; + box-shadow: 0 0 0 0.2rem; +} + +.navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + background-repeat: no-repeat; + background-position: center; + background-size: 100%; +} + +.navbar-nav-scroll { + max-height: var(--bs-scroll-height, 75vh); + overflow-y: auto; +} + +@media (min-width: 576px) { + .navbar-expand-sm { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-sm .navbar-nav { + flex-direction: row; + } + .navbar-expand-sm .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-sm .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-sm .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-sm .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-sm .navbar-toggler { + display: none; + } + .navbar-expand-sm .offcanvas-header { + display: none; + } + .navbar-expand-sm .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-sm .offcanvas-top, + .navbar-expand-sm .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-sm .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} + +@media (min-width: 768px) { + .navbar-expand-md { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-md .navbar-nav { + flex-direction: row; + } + .navbar-expand-md .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-md .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-md .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-md .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-md .navbar-toggler { + display: none; + } + .navbar-expand-md .offcanvas-header { + display: none; + } + .navbar-expand-md .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-md .offcanvas-top, + .navbar-expand-md .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-md .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} + +@media (min-width: 992px) { + .navbar-expand-lg { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-lg .navbar-nav { + flex-direction: row; + } + .navbar-expand-lg .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-lg .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-lg .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-lg .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-lg .navbar-toggler { + display: none; + } + .navbar-expand-lg .offcanvas-header { + display: none; + } + .navbar-expand-lg .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-lg .offcanvas-top, + .navbar-expand-lg .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-lg .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} + +@media (min-width: 1200px) { + .navbar-expand-xl { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-xl .navbar-nav { + flex-direction: row; + } + .navbar-expand-xl .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-xl .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-xl .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-xl .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-xl .navbar-toggler { + display: none; + } + .navbar-expand-xl .offcanvas-header { + display: none; + } + .navbar-expand-xl .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-xl .offcanvas-top, + .navbar-expand-xl .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-xl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} + +@media (min-width: 1440px) { + .navbar-expand-xxl { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-xxl .navbar-nav { + flex-direction: row; + } + .navbar-expand-xxl .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-xxl .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-xxl .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-xxl .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-xxl .navbar-toggler { + display: none; + } + .navbar-expand-xxl .offcanvas-header { + display: none; + } + .navbar-expand-xxl .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-xxl .offcanvas-top, + .navbar-expand-xxl .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-xxl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} + +.navbar-expand { + flex-wrap: nowrap; + justify-content: flex-start; +} + +.navbar-expand .navbar-nav { + flex-direction: row; +} + +.navbar-expand .navbar-nav .dropdown-menu { + position: absolute; +} + +.navbar-expand .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; +} + +.navbar-expand .navbar-nav-scroll { + overflow: visible; +} + +.navbar-expand .navbar-collapse { + display: flex !important; + flex-basis: auto; +} + +.navbar-expand .navbar-toggler { + display: none; +} + +.navbar-expand .offcanvas-header { + display: none; +} + +.navbar-expand .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; +} + +.navbar-expand .offcanvas-top, +.navbar-expand .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; +} + +.navbar-expand .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; +} + +.navbar-light .navbar-brand { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-nav .nav-link { + color: rgba(0, 0, 0, 0.55); +} + +.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus { + color: rgba(0, 0, 0, 0.7); +} + +.navbar-light .navbar-nav .nav-link.disabled { + color: rgba(0, 0, 0, 0.3); +} + +.navbar-light .navbar-nav .show > .nav-link, +.navbar-light .navbar-nav .nav-link.active { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-toggler { + color: rgba(0, 0, 0, 0.55); + border-color: rgba(0, 0, 0, 0.1); +} + +.navbar-light .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.navbar-light .navbar-text { + color: rgba(0, 0, 0, 0.55); +} + +.navbar-light .navbar-text a, +.navbar-light .navbar-text a:hover, +.navbar-light .navbar-text a:focus { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-dark .navbar-brand { + color: #fff; +} + +.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus { + color: #fff; +} + +.navbar-dark .navbar-nav .nav-link { + color: rgba(255, 255, 255, 0.55); +} + +.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus { + color: rgba(255, 255, 255, 0.75); +} + +.navbar-dark .navbar-nav .nav-link.disabled { + color: rgba(255, 255, 255, 0.25); +} + +.navbar-dark .navbar-nav .show > .nav-link, +.navbar-dark .navbar-nav .nav-link.active { + color: #fff; +} + +.navbar-dark .navbar-toggler { + color: rgba(255, 255, 255, 0.55); + border-color: rgba(255, 255, 255, 0.1); +} + +.navbar-dark .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.navbar-dark .navbar-text { + color: rgba(255, 255, 255, 0.55); +} + +.navbar-dark .navbar-text a, +.navbar-dark .navbar-text a:hover, +.navbar-dark .navbar-text a:focus { + color: #fff; +} + +.card { + position: relative; + display: flex; + flex-direction: column; + min-width: 0; + word-wrap: break-word; + background-color: #fff; + background-clip: border-box; + border: 0 solid transparent; + border-radius: 0.25rem; +} + +.card > hr { + margin-right: 0; + margin-left: 0; +} + +.card > .list-group { + border-top: inherit; + border-bottom: inherit; +} + +.card > .list-group:first-child { + border-top-width: 0; + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.card > .list-group:last-child { + border-bottom-width: 0; + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.card > .card-header + .list-group, +.card > .list-group + .card-footer { + border-top: 0; +} + +.card-body { + flex: 1 1 auto; + padding: 1.25rem 1.25rem; +} + +.card-title { + margin-bottom: 0.5rem; +} + +.card-subtitle { + margin-top: -0.25rem; + margin-bottom: 0; +} + +.card-text:last-child { + margin-bottom: 0; +} + +.card-link:hover { + text-decoration: none; +} + +.card-link + .card-link { + margin-left: 1.25rem; +} + +.card-header { + padding: 1rem 1.25rem; + margin-bottom: 0; + background-color: #fff; + border-bottom: 0 solid transparent; +} + +.card-header:first-child { + border-radius: 0.25rem 0.25rem 0 0; +} + +.card-footer { + padding: 1rem 1.25rem; + background-color: #fff; + border-top: 0 solid transparent; +} + +.card-footer:last-child { + border-radius: 0 0 0.25rem 0.25rem; +} + +.card-header-tabs { + margin-right: -0.625rem; + margin-bottom: -1rem; + margin-left: -0.625rem; + border-bottom: 0; +} + +.card-header-tabs .nav-link.active { + background-color: #fff; + border-bottom-color: #fff; +} + +.card-header-pills { + margin-right: -0.625rem; + margin-left: -0.625rem; +} + +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: 1rem; + border-radius: 0.25rem; +} + +.card-img, +.card-img-top, +.card-img-bottom { + width: 100%; +} + +.card-img, +.card-img-top { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.card-img, +.card-img-bottom { + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.card-group > .card { + margin-bottom: 12px; +} + +@media (min-width: 576px) { + .card-group { + display: flex; + flex-flow: row wrap; + } + .card-group > .card { + flex: 1 0 0%; + margin-bottom: 0; + } + .card-group > .card + .card { + margin-left: 0; + border-left: 0; + } + .card-group > .card:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-top, + .card-group > .card:not(:last-child) .card-header { + border-top-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-bottom, + .card-group > .card:not(:last-child) .card-footer { + border-bottom-right-radius: 0; + } + .card-group > .card:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-top, + .card-group > .card:not(:first-child) .card-header { + border-top-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-bottom, + .card-group > .card:not(:first-child) .card-footer { + border-bottom-left-radius: 0; + } +} + +.breadcrumb { + display: flex; + flex-wrap: wrap; + padding: 0 0; + margin-bottom: 1rem; + list-style: none; +} + +.breadcrumb-item + .breadcrumb-item { + padding-left: 0.5rem; +} + +.breadcrumb-item + .breadcrumb-item::before { + float: left; + padding-right: 0.5rem; + color: #6c757d; + content: var(--bs-breadcrumb-divider, "/") /* rtl: var(--bs-breadcrumb-divider, "/") */; +} + +.breadcrumb-item.active { + color: #6c757d; +} + +.badge { + display: inline-block; + padding: 0.3em 0.45em; + font-size: 80%; + font-weight: 600; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: 0.2rem; +} + +.badge:empty { + display: none; +} + +.btn .badge { + position: relative; + top: -1px; +} + +.alert { + position: relative; + padding: 0.95rem 0.95rem; + margin-bottom: 1rem; + border: 0 solid transparent; + border-radius: 0.2rem; +} + +.alert-heading { + color: inherit; +} + +.alert-link { + font-weight: 600; +} + +.alert-dismissible { + padding-right: 2.85rem; +} + +.alert-dismissible .btn-close { + position: absolute; + top: 0; + right: 0; + z-index: 2; + padding: 1.1875rem 0.95rem; +} + +.alert-primary { + color: #234b85; + background-color: #d8e5f8; + border-color: #c4d8f5; +} + +.alert-primary .alert-link { + color: #1c3c6a; +} + +.alert-secondary { + color: #41464b; + background-color: #e2e3e5; + border-color: #d3d6d8; +} + +.alert-secondary .alert-link { + color: #34383c; +} + +.alert-success { + color: #186429; + background-color: #d4edda; + border-color: #bfe5c7; +} + +.alert-success .alert-link { + color: #135021; +} + +.alert-info { + color: #0e616e; + background-color: #d1ecf1; + border-color: #b9e3ea; +} + +.alert-info .alert-link { + color: #0b4e58; +} + +.alert-warning { + color: #664d03; + background-color: #fff3cd; + border-color: #ffecb5; +} + +.alert-warning .alert-link { + color: #523e02; +} + +.alert-danger { + color: #842029; + background-color: #f8d7da; + border-color: #f5c2c7; +} + +.alert-danger .alert-link { + color: #6a1a21; +} + +.alert-light { + color: #636464; + background-color: #fefefe; + border-color: #fdfdfe; +} + +.alert-light .alert-link { + color: #4f5050; +} + +.alert-dark { + color: #141619; + background-color: #d3d3d4; + border-color: #bcbebf; +} + +.alert-dark .alert-link { + color: #101214; +} + +.list-group { + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + border-radius: 0.2rem; +} + +.list-group-numbered { + list-style-type: none; + counter-reset: section; +} + +.list-group-numbered > li::before { + content: counters(section, ".") ". "; + counter-increment: section; +} + +.list-group-item-action { + width: 100%; + color: #495057; + text-align: inherit; +} + +.list-group-item-action:hover, .list-group-item-action:focus { + z-index: 1; + color: #495057; + text-decoration: none; + background-color: #f8f9fa; +} + +.list-group-item-action:active { + color: #495057; + background-color: #e9ecef; +} + +.list-group-item { + position: relative; + display: block; + padding: 0.75rem 1.25rem; + color: #212529; + background-color: #fff; + border: 1px solid rgba(0, 0, 0, 0.125); +} + +.list-group-item:first-child { + border-top-left-radius: inherit; + border-top-right-radius: inherit; +} + +.list-group-item:last-child { + border-bottom-right-radius: inherit; + border-bottom-left-radius: inherit; +} + +.list-group-item.disabled, .list-group-item:disabled { + color: #6c757d; + pointer-events: none; + background-color: #fff; +} + +.list-group-item.active { + z-index: 2; + color: #fff; + background-color: #3B7DDD; + border-color: #3B7DDD; +} + +.list-group-item + .list-group-item { + border-top-width: 0; +} + +.list-group-item + .list-group-item.active { + margin-top: -1px; + border-top-width: 1px; +} + +.list-group-horizontal { + flex-direction: row; +} + +.list-group-horizontal > .list-group-item:first-child { + border-bottom-left-radius: 0.2rem; + border-top-right-radius: 0; +} + +.list-group-horizontal > .list-group-item:last-child { + border-top-right-radius: 0.2rem; + border-bottom-left-radius: 0; +} + +.list-group-horizontal > .list-group-item.active { + margin-top: 0; +} + +.list-group-horizontal > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; +} + +.list-group-horizontal > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; +} + +@media (min-width: 576px) { + .list-group-horizontal-sm { + flex-direction: row; + } + .list-group-horizontal-sm > .list-group-item:first-child { + border-bottom-left-radius: 0.2rem; + border-top-right-radius: 0; + } + .list-group-horizontal-sm > .list-group-item:last-child { + border-top-right-radius: 0.2rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-sm > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-sm > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-sm > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 768px) { + .list-group-horizontal-md { + flex-direction: row; + } + .list-group-horizontal-md > .list-group-item:first-child { + border-bottom-left-radius: 0.2rem; + border-top-right-radius: 0; + } + .list-group-horizontal-md > .list-group-item:last-child { + border-top-right-radius: 0.2rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-md > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-md > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-md > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 992px) { + .list-group-horizontal-lg { + flex-direction: row; + } + .list-group-horizontal-lg > .list-group-item:first-child { + border-bottom-left-radius: 0.2rem; + border-top-right-radius: 0; + } + .list-group-horizontal-lg > .list-group-item:last-child { + border-top-right-radius: 0.2rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-lg > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-lg > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-lg > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 1200px) { + .list-group-horizontal-xl { + flex-direction: row; + } + .list-group-horizontal-xl > .list-group-item:first-child { + border-bottom-left-radius: 0.2rem; + border-top-right-radius: 0; + } + .list-group-horizontal-xl > .list-group-item:last-child { + border-top-right-radius: 0.2rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-xl > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-xl > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-xl > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 1440px) { + .list-group-horizontal-xxl { + flex-direction: row; + } + .list-group-horizontal-xxl > .list-group-item:first-child { + border-bottom-left-radius: 0.2rem; + border-top-right-radius: 0; + } + .list-group-horizontal-xxl > .list-group-item:last-child { + border-top-right-radius: 0.2rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-xxl > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-xxl > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-xxl > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +.list-group-flush { + border-radius: 0; +} + +.list-group-flush > .list-group-item { + border-width: 0 0 1px; +} + +.list-group-flush > .list-group-item:last-child { + border-bottom-width: 0; +} + +.list-group-item-primary { + color: #234b85; + background-color: #d8e5f8; +} + +.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus { + color: #234b85; + background-color: #c2cedf; +} + +.list-group-item-primary.list-group-item-action.active { + color: #fff; + background-color: #234b85; + border-color: #234b85; +} + +.list-group-item-secondary { + color: #41464b; + background-color: #e2e3e5; +} + +.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus { + color: #41464b; + background-color: #cbccce; +} + +.list-group-item-secondary.list-group-item-action.active { + color: #fff; + background-color: #41464b; + border-color: #41464b; +} + +.list-group-item-success { + color: #186429; + background-color: #d4edda; +} + +.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus { + color: #186429; + background-color: #bfd5c4; +} + +.list-group-item-success.list-group-item-action.active { + color: #fff; + background-color: #186429; + border-color: #186429; +} + +.list-group-item-info { + color: #0e616e; + background-color: #d1ecf1; +} + +.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus { + color: #0e616e; + background-color: #bcd4d9; +} + +.list-group-item-info.list-group-item-action.active { + color: #fff; + background-color: #0e616e; + border-color: #0e616e; +} + +.list-group-item-warning { + color: #664d03; + background-color: #fff3cd; +} + +.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus { + color: #664d03; + background-color: #e6dbb9; +} + +.list-group-item-warning.list-group-item-action.active { + color: #fff; + background-color: #664d03; + border-color: #664d03; +} + +.list-group-item-danger { + color: #842029; + background-color: #f8d7da; +} + +.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus { + color: #842029; + background-color: #dfc2c4; +} + +.list-group-item-danger.list-group-item-action.active { + color: #fff; + background-color: #842029; + border-color: #842029; +} + +.list-group-item-light { + color: #636464; + background-color: #fefefe; +} + +.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus { + color: #636464; + background-color: #e5e5e5; +} + +.list-group-item-light.list-group-item-action.active { + color: #fff; + background-color: #636464; + border-color: #636464; +} + +.list-group-item-dark { + color: #141619; + background-color: #d3d3d4; +} + +.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus { + color: #141619; + background-color: #bebebf; +} + +.list-group-item-dark.list-group-item-action.active { + color: #fff; + background-color: #141619; + border-color: #141619; +} + +.btn-close { + box-sizing: content-box; + width: 1em; + height: 1em; + padding: 0.25em 0.25em; + color: #000; + background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat; + border: 0; + border-radius: 0.2rem; + opacity: 0.5; +} + +.btn-close:hover { + color: #000; + text-decoration: none; + opacity: 0.75; +} + +.btn-close:focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.25); + opacity: 1; +} + +.btn-close:disabled, .btn-close.disabled { + pointer-events: none; + user-select: none; + opacity: 0.25; +} + +.btn-close-white { + filter: invert(1) grayscale(100%) brightness(200%); +} + +.clearfix::after { + display: block; + clear: both; + content: ""; +} + +.link-primary { + color: #3B7DDD; +} + +.link-primary:hover, .link-primary:focus { + color: #6297e4; +} + +.link-secondary { + color: #6c757d; +} + +.link-secondary:hover, .link-secondary:focus { + color: #565e64; +} + +.link-success { + color: #28a745; +} + +.link-success:hover, .link-success:focus { + color: #53b96a; +} + +.link-info { + color: #17a2b8; +} + +.link-info:hover, .link-info:focus { + color: #45b5c6; +} + +.link-warning { + color: #ffc107; +} + +.link-warning:hover, .link-warning:focus { + color: #ffcd39; +} + +.link-danger { + color: #dc3545; +} + +.link-danger:hover, .link-danger:focus { + color: #b02a37; +} + +.link-light { + color: #f8f9fa; +} + +.link-light:hover, .link-light:focus { + color: #f9fafb; +} + +.link-dark { + color: #212529; +} + +.link-dark:hover, .link-dark:focus { + color: #1a1e21; +} + +.ratio { + position: relative; + width: 100%; +} + +.ratio::before { + display: block; + padding-top: var(--bs-aspect-ratio); + content: ""; +} + +.ratio > * { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.ratio-1x1 { + --bs-aspect-ratio: 100%; +} + +.ratio-4x3 { + --bs-aspect-ratio: calc(3 / 4 * 100%); +} + +.ratio-16x9 { + --bs-aspect-ratio: calc(9 / 16 * 100%); +} + +.ratio-21x9 { + --bs-aspect-ratio: calc(9 / 21 * 100%); +} + +.fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; +} + +.sticky-top { + position: sticky; + top: 0; + z-index: 1020; +} + +@media (min-width: 576px) { + .sticky-sm-top { + position: sticky; + top: 0; + z-index: 1020; + } +} + +@media (min-width: 768px) { + .sticky-md-top { + position: sticky; + top: 0; + z-index: 1020; + } +} + +@media (min-width: 992px) { + .sticky-lg-top { + position: sticky; + top: 0; + z-index: 1020; + } +} + +@media (min-width: 1200px) { + .sticky-xl-top { + position: sticky; + top: 0; + z-index: 1020; + } +} + +@media (min-width: 1440px) { + .sticky-xxl-top { + position: sticky; + top: 0; + z-index: 1020; + } +} + +.hstack { + display: flex; + flex-direction: row; + align-items: center; + align-self: stretch; +} + +.vstack { + display: flex; + flex: 1 1 auto; + flex-direction: column; + align-self: stretch; +} + +.visually-hidden, +.visually-hidden-focusable:not(:focus):not(:focus-within) { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; +} + +.stretched-link::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + content: ""; +} + +.text-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.vr { + display: inline-block; + align-self: stretch; + width: 1px; + min-height: 1em; + background-color: currentColor; + opacity: 0.25; +} + +.accordion-button { + position: relative; + display: flex; + align-items: center; + width: 100%; + padding: 1rem 1.25rem; + font-size: 0.875rem; + color: #495057; + text-align: left; + background-color: #F7F7FC; + border: 0; + border-radius: 0; + overflow-anchor: none; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease; +} + +@media (prefers-reduced-motion: reduce) { + .accordion-button { + transition: none; + } +} + +.accordion-button:not(.collapsed) { + color: #3571c7; + background-color: #ebf2fc; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.125); +} + +.accordion-button:not(.collapsed)::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%233571c7'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + transform: rotate(-180deg); +} + +.accordion-button::after { + flex-shrink: 0; + width: 1.25rem; + height: 1.25rem; + margin-left: auto; + content: ""; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23495057'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-size: 1.25rem; + transition: transform 0.2s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .accordion-button::after { + transition: none; + } +} + +.accordion-button:hover { + z-index: 2; +} + +.accordion-button:focus { + z-index: 3; + border-color: #9dbeee; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.accordion-header { + margin-bottom: 0; +} + +.accordion-item { + background-color: #F7F7FC; + border: 1px solid rgba(0, 0, 0, 0.125); +} + +.accordion-item:first-of-type { + border-top-left-radius: 0.2rem; + border-top-right-radius: 0.2rem; +} + +.accordion-item:first-of-type .accordion-button { + border-top-left-radius: calc(0.2rem - 1px); + border-top-right-radius: calc(0.2rem - 1px); +} + +.accordion-item:not(:first-of-type) { + border-top: 0; +} + +.accordion-item:last-of-type { + border-bottom-right-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; +} + +.accordion-item:last-of-type .accordion-button.collapsed { + border-bottom-right-radius: calc(0.2rem - 1px); + border-bottom-left-radius: calc(0.2rem - 1px); +} + +.accordion-item:last-of-type .accordion-collapse { + border-bottom-right-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; +} + +.accordion-body { + padding: 1rem 1.25rem; +} + +.accordion-flush .accordion-collapse { + border-width: 0; +} + +.accordion-flush .accordion-item { + border-right: 0; + border-left: 0; + border-radius: 0; +} + +.accordion-flush .accordion-item:first-child { + border-top: 0; +} + +.accordion-flush .accordion-item:last-child { + border-bottom: 0; +} + +.accordion-flush .accordion-item .accordion-button { + border-radius: 0; +} + +.modal { + position: fixed; + top: 0; + left: 0; + z-index: 1055; + display: none; + width: 100%; + height: 100%; + overflow-x: hidden; + overflow-y: auto; + outline: 0; +} + +.modal-dialog { + position: relative; + width: auto; + margin: 0.5rem; + pointer-events: none; +} + +.modal.fade .modal-dialog { + transition: transform 0.25s ease-out; + transform: translate(0, -50px); +} + +@media (prefers-reduced-motion: reduce) { + .modal.fade .modal-dialog { + transition: none; + } +} + +.modal.show .modal-dialog { + transform: none; +} + +.modal.modal-static .modal-dialog { + transform: scale(1.02); +} + +.modal-dialog-scrollable { + height: calc(100% - 1rem); +} + +.modal-dialog-scrollable .modal-content { + max-height: 100%; + overflow: hidden; +} + +.modal-dialog-scrollable .modal-body { + overflow-y: auto; +} + +.modal-dialog-centered { + display: flex; + align-items: center; + min-height: calc(100% - 1rem); +} + +.modal-content { + position: relative; + display: flex; + flex-direction: column; + width: 100%; + pointer-events: auto; + background-color: #fff; + background-clip: padding-box; + border: 0 solid rgba(0, 0, 0, 0.2); + border-radius: 0.3rem; + outline: 0; +} + +.modal-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1050; + width: 100vw; + height: 100vh; + background-color: #000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop.show { + opacity: 0.5; +} + +.modal-header { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: space-between; + padding: 1rem 1rem; + border-bottom: 1px solid #dee2e6; + border-top-left-radius: 0.3rem; + border-top-right-radius: 0.3rem; +} + +.modal-header .btn-close { + padding: 0.5rem 0.5rem; + margin: -0.5rem -0.5rem -0.5rem auto; +} + +.modal-title { + margin-bottom: 0; + line-height: 1.5; +} + +.modal-body { + position: relative; + flex: 1 1 auto; + padding: 1rem; +} + +.modal-footer { + display: flex; + flex-wrap: wrap; + flex-shrink: 0; + align-items: center; + justify-content: flex-end; + padding: 0.75rem; + border-top: 1px solid #dee2e6; + border-bottom-right-radius: 0.3rem; + border-bottom-left-radius: 0.3rem; +} + +.modal-footer > * { + margin: 0.25rem; +} + +@media (min-width: 576px) { + .modal-dialog { + max-width: 600px; + margin: 1.75rem auto; + } + .modal-dialog-scrollable { + height: calc(100% - 3.5rem); + } + .modal-dialog-centered { + min-height: calc(100% - 3.5rem); + } + .modal-sm { + max-width: 400px; + } +} + +@media (min-width: 992px) { + .modal-lg, + .modal-xl { + max-width: 900px; + } +} + +@media (min-width: 1200px) { + .modal-xl { + max-width: 1140px; + } +} + +.modal-fullscreen { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; +} + +.modal-fullscreen .modal-content { + height: 100%; + border: 0; + border-radius: 0; +} + +.modal-fullscreen .modal-header { + border-radius: 0; +} + +.modal-fullscreen .modal-body { + overflow-y: auto; +} + +.modal-fullscreen .modal-footer { + border-radius: 0; +} + +@media (max-width: 575.98px) { + .modal-fullscreen-sm-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-sm-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-sm-down .modal-header { + border-radius: 0; + } + .modal-fullscreen-sm-down .modal-body { + overflow-y: auto; + } + .modal-fullscreen-sm-down .modal-footer { + border-radius: 0; + } +} + +@media (max-width: 767.98px) { + .modal-fullscreen-md-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-md-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-md-down .modal-header { + border-radius: 0; + } + .modal-fullscreen-md-down .modal-body { + overflow-y: auto; + } + .modal-fullscreen-md-down .modal-footer { + border-radius: 0; + } +} + +@media (max-width: 991.98px) { + .modal-fullscreen-lg-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-lg-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-lg-down .modal-header { + border-radius: 0; + } + .modal-fullscreen-lg-down .modal-body { + overflow-y: auto; + } + .modal-fullscreen-lg-down .modal-footer { + border-radius: 0; + } +} + +@media (max-width: 1199.98px) { + .modal-fullscreen-xl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-xl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-xl-down .modal-header { + border-radius: 0; + } + .modal-fullscreen-xl-down .modal-body { + overflow-y: auto; + } + .modal-fullscreen-xl-down .modal-footer { + border-radius: 0; + } +} + +@media (max-width: 1439.98px) { + .modal-fullscreen-xxl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-xxl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-xxl-down .modal-header { + border-radius: 0; + } + .modal-fullscreen-xxl-down .modal-body { + overflow-y: auto; + } + .modal-fullscreen-xxl-down .modal-footer { + border-radius: 0; + } +} + +.align-baseline { + vertical-align: baseline !important; +} + +.align-top { + vertical-align: top !important; +} + +.align-middle { + vertical-align: middle !important; +} + +.align-bottom { + vertical-align: bottom !important; +} + +.align-text-bottom { + vertical-align: text-bottom !important; +} + +.align-text-top { + vertical-align: text-top !important; +} + +.float-start { + float: left !important; +} + +.float-end { + float: right !important; +} + +.float-none { + float: none !important; +} + +.opacity-0 { + opacity: 0 !important; +} + +.opacity-25 { + opacity: 0.25 !important; +} + +.opacity-50 { + opacity: 0.5 !important; +} + +.opacity-75 { + opacity: 0.75 !important; +} + +.opacity-100 { + opacity: 1 !important; +} + +.overflow-auto { + overflow: auto !important; +} + +.overflow-hidden { + overflow: hidden !important; +} + +.overflow-visible { + overflow: visible !important; +} + +.overflow-scroll { + overflow: scroll !important; +} + +.d-inline { + display: inline !important; +} + +.d-inline-block { + display: inline-block !important; +} + +.d-block { + display: block !important; +} + +.d-grid { + display: grid !important; +} + +.d-table { + display: table !important; +} + +.d-table-row { + display: table-row !important; +} + +.d-table-cell { + display: table-cell !important; +} + +.d-flex { + display: flex !important; +} + +.d-inline-flex { + display: inline-flex !important; +} + +.d-none { + display: none !important; +} + +.shadow { + box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.05) !important; +} + +.shadow-sm { + box-shadow: 0 0.05rem 0.2rem rgba(0, 0, 0, 0.05) !important; +} + +.shadow-lg { + box-shadow: 0 0.2rem 0.2rem rgba(0, 0, 0, 0.05) !important; +} + +.shadow-none { + box-shadow: none !important; +} + +.position-static { + position: static !important; +} + +.position-relative { + position: relative !important; +} + +.position-absolute { + position: absolute !important; +} + +.position-fixed { + position: fixed !important; +} + +.position-sticky { + position: sticky !important; +} + +.top-0 { + top: 0 !important; +} + +.top-50 { + top: 50% !important; +} + +.top-100 { + top: 100% !important; +} + +.bottom-0 { + bottom: 0 !important; +} + +.bottom-50 { + bottom: 50% !important; +} + +.bottom-100 { + bottom: 100% !important; +} + +.start-0 { + left: 0 !important; +} + +.start-50 { + left: 50% !important; +} + +.start-100 { + left: 100% !important; +} + +.end-0 { + right: 0 !important; +} + +.end-50 { + right: 50% !important; +} + +.end-100 { + right: 100% !important; +} + +.translate-middle { + transform: translate(-50%, -50%) !important; +} + +.translate-middle-x { + transform: translateX(-50%) !important; +} + +.translate-middle-y { + transform: translateY(-50%) !important; +} + +.border { + border: 1px solid #dee2e6 !important; +} + +.border-0 { + border: 0 !important; +} + +.border-top { + border-top: 1px solid #dee2e6 !important; +} + +.border-top-0 { + border-top: 0 !important; +} + +.border-end { + border-right: 1px solid #dee2e6 !important; +} + +.border-end-0 { + border-right: 0 !important; +} + +.border-bottom { + border-bottom: 1px solid #dee2e6 !important; +} + +.border-bottom-0 { + border-bottom: 0 !important; +} + +.border-start { + border-left: 1px solid #dee2e6 !important; +} + +.border-start-0 { + border-left: 0 !important; +} + +.border-primary { + border-color: #3B7DDD !important; +} + +.border-secondary { + border-color: #6c757d !important; +} + +.border-success { + border-color: #28a745 !important; +} + +.border-info { + border-color: #17a2b8 !important; +} + +.border-warning { + border-color: #ffc107 !important; +} + +.border-danger { + border-color: #dc3545 !important; +} + +.border-light { + border-color: #f8f9fa !important; +} + +.border-dark { + border-color: #212529 !important; +} + +.border-white { + border-color: #fff !important; +} + +.border-1 { + border-width: 1px !important; +} + +.border-2 { + border-width: 2px !important; +} + +.border-3 { + border-width: 3px !important; +} + +.border-4 { + border-width: 4px !important; +} + +.border-5 { + border-width: 5px !important; +} + +.w-25 { + width: 25% !important; +} + +.w-50 { + width: 50% !important; +} + +.w-75 { + width: 75% !important; +} + +.w-100 { + width: 100% !important; +} + +.w-auto { + width: auto !important; +} + +.mw-100 { + max-width: 100% !important; +} + +.vw-100 { + width: 100vw !important; +} + +.min-vw-100 { + min-width: 100vw !important; +} + +.h-25 { + height: 25% !important; +} + +.h-50 { + height: 50% !important; +} + +.h-75 { + height: 75% !important; +} + +.h-100 { + height: 100% !important; +} + +.h-auto { + height: auto !important; +} + +.mh-100 { + max-height: 100% !important; +} + +.vh-100 { + height: 100vh !important; +} + +.min-vh-100 { + min-height: 100vh !important; +} + +.flex-fill { + flex: 1 1 auto !important; +} + +.flex-row { + flex-direction: row !important; +} + +.flex-column { + flex-direction: column !important; +} + +.flex-row-reverse { + flex-direction: row-reverse !important; +} + +.flex-column-reverse { + flex-direction: column-reverse !important; +} + +.flex-grow-0 { + flex-grow: 0 !important; +} + +.flex-grow-1 { + flex-grow: 1 !important; +} + +.flex-shrink-0 { + flex-shrink: 0 !important; +} + +.flex-shrink-1 { + flex-shrink: 1 !important; +} + +.flex-wrap { + flex-wrap: wrap !important; +} + +.flex-nowrap { + flex-wrap: nowrap !important; +} + +.flex-wrap-reverse { + flex-wrap: wrap-reverse !important; +} + +.gap-0 { + gap: 0 !important; +} + +.gap-1 { + gap: 0.25rem !important; +} + +.gap-2 { + gap: 0.5rem !important; +} + +.gap-3 { + gap: 1rem !important; +} + +.gap-4 { + gap: 1.5rem !important; +} + +.gap-5 { + gap: 3rem !important; +} + +.gap-6 { + gap: 4.5rem !important; +} + +.gap-7 { + gap: 6rem !important; +} + +.justify-content-start { + justify-content: flex-start !important; +} + +.justify-content-end { + justify-content: flex-end !important; +} + +.justify-content-center { + justify-content: center !important; +} + +.justify-content-between { + justify-content: space-between !important; +} + +.justify-content-around { + justify-content: space-around !important; +} + +.justify-content-evenly { + justify-content: space-evenly !important; +} + +.align-items-start { + align-items: flex-start !important; +} + +.align-items-end { + align-items: flex-end !important; +} + +.align-items-center { + align-items: center !important; +} + +.align-items-baseline { + align-items: baseline !important; +} + +.align-items-stretch { + align-items: stretch !important; +} + +.align-content-start { + align-content: flex-start !important; +} + +.align-content-end { + align-content: flex-end !important; +} + +.align-content-center { + align-content: center !important; +} + +.align-content-between { + align-content: space-between !important; +} + +.align-content-around { + align-content: space-around !important; +} + +.align-content-stretch { + align-content: stretch !important; +} + +.align-self-auto { + align-self: auto !important; +} + +.align-self-start { + align-self: flex-start !important; +} + +.align-self-end { + align-self: flex-end !important; +} + +.align-self-center { + align-self: center !important; +} + +.align-self-baseline { + align-self: baseline !important; +} + +.align-self-stretch { + align-self: stretch !important; +} + +.order-first { + order: -1 !important; +} + +.order-0 { + order: 0 !important; +} + +.order-1 { + order: 1 !important; +} + +.order-2 { + order: 2 !important; +} + +.order-3 { + order: 3 !important; +} + +.order-4 { + order: 4 !important; +} + +.order-5 { + order: 5 !important; +} + +.order-last { + order: 6 !important; +} + +.m-0 { + margin: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.m-3 { + margin: 1rem !important; +} + +.m-4 { + margin: 1.5rem !important; +} + +.m-5 { + margin: 3rem !important; +} + +.m-6 { + margin: 4.5rem !important; +} + +.m-7 { + margin: 6rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mx-0 { + margin-right: 0 !important; + margin-left: 0 !important; +} + +.mx-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; +} + +.mx-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; +} + +.mx-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; +} + +.mx-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; +} + +.mx-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; +} + +.mx-6 { + margin-right: 4.5rem !important; + margin-left: 4.5rem !important; +} + +.mx-7 { + margin-right: 6rem !important; + margin-left: 6rem !important; +} + +.mx-auto { + margin-right: auto !important; + margin-left: auto !important; +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; +} + +.my-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; +} + +.my-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; +} + +.my-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; +} + +.my-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; +} + +.my-6 { + margin-top: 4.5rem !important; + margin-bottom: 4.5rem !important; +} + +.my-7 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; +} + +.my-auto { + margin-top: auto !important; + margin-bottom: auto !important; +} + +.mt-0 { + margin-top: 0 !important; +} + +.mt-1 { + margin-top: 0.25rem !important; +} + +.mt-2 { + margin-top: 0.5rem !important; +} + +.mt-3 { + margin-top: 1rem !important; +} + +.mt-4 { + margin-top: 1.5rem !important; +} + +.mt-5 { + margin-top: 3rem !important; +} + +.mt-6 { + margin-top: 4.5rem !important; +} + +.mt-7 { + margin-top: 6rem !important; +} + +.mt-auto { + margin-top: auto !important; +} + +.me-0 { + margin-right: 0 !important; +} + +.me-1 { + margin-right: 0.25rem !important; +} + +.me-2 { + margin-right: 0.5rem !important; +} + +.me-3 { + margin-right: 1rem !important; +} + +.me-4 { + margin-right: 1.5rem !important; +} + +.me-5 { + margin-right: 3rem !important; +} + +.me-6 { + margin-right: 4.5rem !important; +} + +.me-7 { + margin-right: 6rem !important; +} + +.me-auto { + margin-right: auto !important; +} + +.mb-0 { + margin-bottom: 0 !important; +} + +.mb-1 { + margin-bottom: 0.25rem !important; +} + +.mb-2 { + margin-bottom: 0.5rem !important; +} + +.mb-3 { + margin-bottom: 1rem !important; +} + +.mb-4 { + margin-bottom: 1.5rem !important; +} + +.mb-5 { + margin-bottom: 3rem !important; +} + +.mb-6 { + margin-bottom: 4.5rem !important; +} + +.mb-7 { + margin-bottom: 6rem !important; +} + +.mb-auto { + margin-bottom: auto !important; +} + +.ms-0 { + margin-left: 0 !important; +} + +.ms-1 { + margin-left: 0.25rem !important; +} + +.ms-2 { + margin-left: 0.5rem !important; +} + +.ms-3 { + margin-left: 1rem !important; +} + +.ms-4 { + margin-left: 1.5rem !important; +} + +.ms-5 { + margin-left: 3rem !important; +} + +.ms-6 { + margin-left: 4.5rem !important; +} + +.ms-7 { + margin-left: 6rem !important; +} + +.ms-auto { + margin-left: auto !important; +} + +.m-n1 { + margin: -0.25rem !important; +} + +.m-n2 { + margin: -0.5rem !important; +} + +.m-n3 { + margin: -1rem !important; +} + +.m-n4 { + margin: -1.5rem !important; +} + +.m-n5 { + margin: -3rem !important; +} + +.m-n6 { + margin: -4.5rem !important; +} + +.m-n7 { + margin: -6rem !important; +} + +.mx-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; +} + +.mx-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; +} + +.mx-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; +} + +.mx-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; +} + +.mx-n5 { + margin-right: -3rem !important; + margin-left: -3rem !important; +} + +.mx-n6 { + margin-right: -4.5rem !important; + margin-left: -4.5rem !important; +} + +.mx-n7 { + margin-right: -6rem !important; + margin-left: -6rem !important; +} + +.my-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; +} + +.my-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; +} + +.my-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; +} + +.my-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; +} + +.my-n5 { + margin-top: -3rem !important; + margin-bottom: -3rem !important; +} + +.my-n6 { + margin-top: -4.5rem !important; + margin-bottom: -4.5rem !important; +} + +.my-n7 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; +} + +.mt-n1 { + margin-top: -0.25rem !important; +} + +.mt-n2 { + margin-top: -0.5rem !important; +} + +.mt-n3 { + margin-top: -1rem !important; +} + +.mt-n4 { + margin-top: -1.5rem !important; +} + +.mt-n5 { + margin-top: -3rem !important; +} + +.mt-n6 { + margin-top: -4.5rem !important; +} + +.mt-n7 { + margin-top: -6rem !important; +} + +.me-n1 { + margin-right: -0.25rem !important; +} + +.me-n2 { + margin-right: -0.5rem !important; +} + +.me-n3 { + margin-right: -1rem !important; +} + +.me-n4 { + margin-right: -1.5rem !important; +} + +.me-n5 { + margin-right: -3rem !important; +} + +.me-n6 { + margin-right: -4.5rem !important; +} + +.me-n7 { + margin-right: -6rem !important; +} + +.mb-n1 { + margin-bottom: -0.25rem !important; +} + +.mb-n2 { + margin-bottom: -0.5rem !important; +} + +.mb-n3 { + margin-bottom: -1rem !important; +} + +.mb-n4 { + margin-bottom: -1.5rem !important; +} + +.mb-n5 { + margin-bottom: -3rem !important; +} + +.mb-n6 { + margin-bottom: -4.5rem !important; +} + +.mb-n7 { + margin-bottom: -6rem !important; +} + +.ms-n1 { + margin-left: -0.25rem !important; +} + +.ms-n2 { + margin-left: -0.5rem !important; +} + +.ms-n3 { + margin-left: -1rem !important; +} + +.ms-n4 { + margin-left: -1.5rem !important; +} + +.ms-n5 { + margin-left: -3rem !important; +} + +.ms-n6 { + margin-left: -4.5rem !important; +} + +.ms-n7 { + margin-left: -6rem !important; +} + +.p-0 { + padding: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.p-3 { + padding: 1rem !important; +} + +.p-4 { + padding: 1.5rem !important; +} + +.p-5 { + padding: 3rem !important; +} + +.p-6 { + padding: 4.5rem !important; +} + +.p-7 { + padding: 6rem !important; +} + +.px-0 { + padding-right: 0 !important; + padding-left: 0 !important; +} + +.px-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; +} + +.px-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; +} + +.px-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; +} + +.px-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; +} + +.px-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; +} + +.px-6 { + padding-right: 4.5rem !important; + padding-left: 4.5rem !important; +} + +.px-7 { + padding-right: 6rem !important; + padding-left: 6rem !important; +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.py-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; +} + +.py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; +} + +.py-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; +} + +.py-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; +} + +.py-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; +} + +.py-6 { + padding-top: 4.5rem !important; + padding-bottom: 4.5rem !important; +} + +.py-7 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; +} + +.pt-0 { + padding-top: 0 !important; +} + +.pt-1 { + padding-top: 0.25rem !important; +} + +.pt-2 { + padding-top: 0.5rem !important; +} + +.pt-3 { + padding-top: 1rem !important; +} + +.pt-4 { + padding-top: 1.5rem !important; +} + +.pt-5 { + padding-top: 3rem !important; +} + +.pt-6 { + padding-top: 4.5rem !important; +} + +.pt-7 { + padding-top: 6rem !important; +} + +.pe-0 { + padding-right: 0 !important; +} + +.pe-1 { + padding-right: 0.25rem !important; +} + +.pe-2 { + padding-right: 0.5rem !important; +} + +.pe-3 { + padding-right: 1rem !important; +} + +.pe-4 { + padding-right: 1.5rem !important; +} + +.pe-5 { + padding-right: 3rem !important; +} + +.pe-6 { + padding-right: 4.5rem !important; +} + +.pe-7 { + padding-right: 6rem !important; +} + +.pb-0 { + padding-bottom: 0 !important; +} + +.pb-1 { + padding-bottom: 0.25rem !important; +} + +.pb-2 { + padding-bottom: 0.5rem !important; +} + +.pb-3 { + padding-bottom: 1rem !important; +} + +.pb-4 { + padding-bottom: 1.5rem !important; +} + +.pb-5 { + padding-bottom: 3rem !important; +} + +.pb-6 { + padding-bottom: 4.5rem !important; +} + +.pb-7 { + padding-bottom: 6rem !important; +} + +.ps-0 { + padding-left: 0 !important; +} + +.ps-1 { + padding-left: 0.25rem !important; +} + +.ps-2 { + padding-left: 0.5rem !important; +} + +.ps-3 { + padding-left: 1rem !important; +} + +.ps-4 { + padding-left: 1.5rem !important; +} + +.ps-5 { + padding-left: 3rem !important; +} + +.ps-6 { + padding-left: 4.5rem !important; +} + +.ps-7 { + padding-left: 6rem !important; +} + +.font-monospace { + font-family: var(--bs-font-monospace) !important; +} + +.fs-1 { + font-size: 1.75rem !important; +} + +.fs-2 { + font-size: 1.53125rem !important; +} + +.fs-3 { + font-size: 1.3125rem !important; +} + +.fs-4 { + font-size: 1.09375rem !important; +} + +.fs-5 { + font-size: 0.875rem !important; +} + +.fs-6 { + font-size: 0.875rem !important; +} + +.fst-italic { + font-style: italic !important; +} + +.fst-normal { + font-style: normal !important; +} + +.fw-light { + font-weight: 300 !important; +} + +.fw-lighter { + font-weight: lighter !important; +} + +.fw-normal { + font-weight: 400 !important; +} + +.fw-bold { + font-weight: 600 !important; +} + +.fw-bolder { + font-weight: bolder !important; +} + +.lh-1 { + line-height: 1 !important; +} + +.lh-sm { + line-height: 1.5 !important; +} + +.lh-base { + line-height: 1.5 !important; +} + +.lh-lg { + line-height: 1.5 !important; +} + +.text-start { + text-align: left !important; +} + +.text-end { + text-align: right !important; +} + +.text-center { + text-align: center !important; +} + +.text-decoration-none { + text-decoration: none !important; +} + +.text-decoration-underline { + text-decoration: underline !important; +} + +.text-decoration-line-through { + text-decoration: line-through !important; +} + +.text-lowercase { + text-transform: lowercase !important; +} + +.text-uppercase { + text-transform: uppercase !important; +} + +.text-capitalize { + text-transform: capitalize !important; +} + +.text-wrap { + white-space: normal !important; +} + +.text-nowrap { + white-space: nowrap !important; +} + +/* rtl:begin:remove */ +.text-break { + word-wrap: break-word !important; + word-break: break-word !important; +} + +/* rtl:end:remove */ +.text-primary { + --bs-text-opacity: 1; + color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important; +} + +.text-secondary { + --bs-text-opacity: 1; + color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important; +} + +.text-success { + --bs-text-opacity: 1; + color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important; +} + +.text-info { + --bs-text-opacity: 1; + color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important; +} + +.text-warning { + --bs-text-opacity: 1; + color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important; +} + +.text-danger { + --bs-text-opacity: 1; + color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important; +} + +.text-light { + --bs-text-opacity: 1; + color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important; +} + +.text-dark { + --bs-text-opacity: 1; + color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important; +} + +.text-black { + --bs-text-opacity: 1; + color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important; +} + +.text-white { + --bs-text-opacity: 1; + color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important; +} + +.text-body { + --bs-text-opacity: 1; + color: rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important; +} + +.text-muted { + --bs-text-opacity: 1; + color: #6c757d !important; +} + +.text-black-50 { + --bs-text-opacity: 1; + color: rgba(0, 0, 0, 0.5) !important; +} + +.text-white-50 { + --bs-text-opacity: 1; + color: rgba(255, 255, 255, 0.5) !important; +} + +.text-reset { + --bs-text-opacity: 1; + color: inherit !important; +} + +.text-opacity-25 { + --bs-text-opacity: 0.25; +} + +.text-opacity-50 { + --bs-text-opacity: 0.5; +} + +.text-opacity-75 { + --bs-text-opacity: 0.75; +} + +.text-opacity-100 { + --bs-text-opacity: 1; +} + +.bg-primary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-secondary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-success { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-info { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-warning { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-danger { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-light { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-dark { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-black { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-white { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-body { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-transparent { + --bs-bg-opacity: 1; + background-color: transparent !important; +} + +.bg-opacity-10 { + --bs-bg-opacity: 0.1; +} + +.bg-opacity-25 { + --bs-bg-opacity: 0.25; +} + +.bg-opacity-50 { + --bs-bg-opacity: 0.5; +} + +.bg-opacity-75 { + --bs-bg-opacity: 0.75; +} + +.bg-opacity-100 { + --bs-bg-opacity: 1; +} + +.bg-gradient { + background-image: var(--bs-gradient) !important; +} + +.user-select-all { + user-select: all !important; +} + +.user-select-auto { + user-select: auto !important; +} + +.user-select-none { + user-select: none !important; +} + +.pe-none { + pointer-events: none !important; +} + +.pe-auto { + pointer-events: auto !important; +} + +.rounded { + border-radius: 0.2rem !important; +} + +.rounded-0 { + border-radius: 0 !important; +} + +.rounded-1 { + border-radius: 0.1rem !important; +} + +.rounded-2 { + border-radius: 0.2rem !important; +} + +.rounded-3 { + border-radius: 0.3rem !important; +} + +.rounded-circle { + border-radius: 50% !important; +} + +.rounded-pill { + border-radius: 50rem !important; +} + +.rounded-top { + border-top-left-radius: 0.2rem !important; + border-top-right-radius: 0.2rem !important; +} + +.rounded-end { + border-top-right-radius: 0.2rem !important; + border-bottom-right-radius: 0.2rem !important; +} + +.rounded-bottom { + border-bottom-right-radius: 0.2rem !important; + border-bottom-left-radius: 0.2rem !important; +} + +.rounded-start { + border-bottom-left-radius: 0.2rem !important; + border-top-left-radius: 0.2rem !important; +} + +.visible { + visibility: visible !important; +} + +.invisible { + visibility: hidden !important; +} + +@media (min-width: 576px) { + .float-sm-start { + float: left !important; + } + .float-sm-end { + float: right !important; + } + .float-sm-none { + float: none !important; + } + .d-sm-inline { + display: inline !important; + } + .d-sm-inline-block { + display: inline-block !important; + } + .d-sm-block { + display: block !important; + } + .d-sm-grid { + display: grid !important; + } + .d-sm-table { + display: table !important; + } + .d-sm-table-row { + display: table-row !important; + } + .d-sm-table-cell { + display: table-cell !important; + } + .d-sm-flex { + display: flex !important; + } + .d-sm-inline-flex { + display: inline-flex !important; + } + .d-sm-none { + display: none !important; + } + .flex-sm-fill { + flex: 1 1 auto !important; + } + .flex-sm-row { + flex-direction: row !important; + } + .flex-sm-column { + flex-direction: column !important; + } + .flex-sm-row-reverse { + flex-direction: row-reverse !important; + } + .flex-sm-column-reverse { + flex-direction: column-reverse !important; + } + .flex-sm-grow-0 { + flex-grow: 0 !important; + } + .flex-sm-grow-1 { + flex-grow: 1 !important; + } + .flex-sm-shrink-0 { + flex-shrink: 0 !important; + } + .flex-sm-shrink-1 { + flex-shrink: 1 !important; + } + .flex-sm-wrap { + flex-wrap: wrap !important; + } + .flex-sm-nowrap { + flex-wrap: nowrap !important; + } + .flex-sm-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .gap-sm-0 { + gap: 0 !important; + } + .gap-sm-1 { + gap: 0.25rem !important; + } + .gap-sm-2 { + gap: 0.5rem !important; + } + .gap-sm-3 { + gap: 1rem !important; + } + .gap-sm-4 { + gap: 1.5rem !important; + } + .gap-sm-5 { + gap: 3rem !important; + } + .gap-sm-6 { + gap: 4.5rem !important; + } + .gap-sm-7 { + gap: 6rem !important; + } + .justify-content-sm-start { + justify-content: flex-start !important; + } + .justify-content-sm-end { + justify-content: flex-end !important; + } + .justify-content-sm-center { + justify-content: center !important; + } + .justify-content-sm-between { + justify-content: space-between !important; + } + .justify-content-sm-around { + justify-content: space-around !important; + } + .justify-content-sm-evenly { + justify-content: space-evenly !important; + } + .align-items-sm-start { + align-items: flex-start !important; + } + .align-items-sm-end { + align-items: flex-end !important; + } + .align-items-sm-center { + align-items: center !important; + } + .align-items-sm-baseline { + align-items: baseline !important; + } + .align-items-sm-stretch { + align-items: stretch !important; + } + .align-content-sm-start { + align-content: flex-start !important; + } + .align-content-sm-end { + align-content: flex-end !important; + } + .align-content-sm-center { + align-content: center !important; + } + .align-content-sm-between { + align-content: space-between !important; + } + .align-content-sm-around { + align-content: space-around !important; + } + .align-content-sm-stretch { + align-content: stretch !important; + } + .align-self-sm-auto { + align-self: auto !important; + } + .align-self-sm-start { + align-self: flex-start !important; + } + .align-self-sm-end { + align-self: flex-end !important; + } + .align-self-sm-center { + align-self: center !important; + } + .align-self-sm-baseline { + align-self: baseline !important; + } + .align-self-sm-stretch { + align-self: stretch !important; + } + .order-sm-first { + order: -1 !important; + } + .order-sm-0 { + order: 0 !important; + } + .order-sm-1 { + order: 1 !important; + } + .order-sm-2 { + order: 2 !important; + } + .order-sm-3 { + order: 3 !important; + } + .order-sm-4 { + order: 4 !important; + } + .order-sm-5 { + order: 5 !important; + } + .order-sm-last { + order: 6 !important; + } + .m-sm-0 { + margin: 0 !important; + } + .m-sm-1 { + margin: 0.25rem !important; + } + .m-sm-2 { + margin: 0.5rem !important; + } + .m-sm-3 { + margin: 1rem !important; + } + .m-sm-4 { + margin: 1.5rem !important; + } + .m-sm-5 { + margin: 3rem !important; + } + .m-sm-6 { + margin: 4.5rem !important; + } + .m-sm-7 { + margin: 6rem !important; + } + .m-sm-auto { + margin: auto !important; + } + .mx-sm-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-sm-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-sm-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-sm-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-sm-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-sm-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-sm-6 { + margin-right: 4.5rem !important; + margin-left: 4.5rem !important; + } + .mx-sm-7 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-sm-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-sm-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-sm-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-sm-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-sm-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-sm-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-sm-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-sm-6 { + margin-top: 4.5rem !important; + margin-bottom: 4.5rem !important; + } + .my-sm-7 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-sm-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-sm-0 { + margin-top: 0 !important; + } + .mt-sm-1 { + margin-top: 0.25rem !important; + } + .mt-sm-2 { + margin-top: 0.5rem !important; + } + .mt-sm-3 { + margin-top: 1rem !important; + } + .mt-sm-4 { + margin-top: 1.5rem !important; + } + .mt-sm-5 { + margin-top: 3rem !important; + } + .mt-sm-6 { + margin-top: 4.5rem !important; + } + .mt-sm-7 { + margin-top: 6rem !important; + } + .mt-sm-auto { + margin-top: auto !important; + } + .me-sm-0 { + margin-right: 0 !important; + } + .me-sm-1 { + margin-right: 0.25rem !important; + } + .me-sm-2 { + margin-right: 0.5rem !important; + } + .me-sm-3 { + margin-right: 1rem !important; + } + .me-sm-4 { + margin-right: 1.5rem !important; + } + .me-sm-5 { + margin-right: 3rem !important; + } + .me-sm-6 { + margin-right: 4.5rem !important; + } + .me-sm-7 { + margin-right: 6rem !important; + } + .me-sm-auto { + margin-right: auto !important; + } + .mb-sm-0 { + margin-bottom: 0 !important; + } + .mb-sm-1 { + margin-bottom: 0.25rem !important; + } + .mb-sm-2 { + margin-bottom: 0.5rem !important; + } + .mb-sm-3 { + margin-bottom: 1rem !important; + } + .mb-sm-4 { + margin-bottom: 1.5rem !important; + } + .mb-sm-5 { + margin-bottom: 3rem !important; + } + .mb-sm-6 { + margin-bottom: 4.5rem !important; + } + .mb-sm-7 { + margin-bottom: 6rem !important; + } + .mb-sm-auto { + margin-bottom: auto !important; + } + .ms-sm-0 { + margin-left: 0 !important; + } + .ms-sm-1 { + margin-left: 0.25rem !important; + } + .ms-sm-2 { + margin-left: 0.5rem !important; + } + .ms-sm-3 { + margin-left: 1rem !important; + } + .ms-sm-4 { + margin-left: 1.5rem !important; + } + .ms-sm-5 { + margin-left: 3rem !important; + } + .ms-sm-6 { + margin-left: 4.5rem !important; + } + .ms-sm-7 { + margin-left: 6rem !important; + } + .ms-sm-auto { + margin-left: auto !important; + } + .m-sm-n1 { + margin: -0.25rem !important; + } + .m-sm-n2 { + margin: -0.5rem !important; + } + .m-sm-n3 { + margin: -1rem !important; + } + .m-sm-n4 { + margin: -1.5rem !important; + } + .m-sm-n5 { + margin: -3rem !important; + } + .m-sm-n6 { + margin: -4.5rem !important; + } + .m-sm-n7 { + margin: -6rem !important; + } + .mx-sm-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-sm-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-sm-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-sm-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-sm-n5 { + margin-right: -3rem !important; + margin-left: -3rem !important; + } + .mx-sm-n6 { + margin-right: -4.5rem !important; + margin-left: -4.5rem !important; + } + .mx-sm-n7 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .my-sm-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-sm-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-sm-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-sm-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-sm-n5 { + margin-top: -3rem !important; + margin-bottom: -3rem !important; + } + .my-sm-n6 { + margin-top: -4.5rem !important; + margin-bottom: -4.5rem !important; + } + .my-sm-n7 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .mt-sm-n1 { + margin-top: -0.25rem !important; + } + .mt-sm-n2 { + margin-top: -0.5rem !important; + } + .mt-sm-n3 { + margin-top: -1rem !important; + } + .mt-sm-n4 { + margin-top: -1.5rem !important; + } + .mt-sm-n5 { + margin-top: -3rem !important; + } + .mt-sm-n6 { + margin-top: -4.5rem !important; + } + .mt-sm-n7 { + margin-top: -6rem !important; + } + .me-sm-n1 { + margin-right: -0.25rem !important; + } + .me-sm-n2 { + margin-right: -0.5rem !important; + } + .me-sm-n3 { + margin-right: -1rem !important; + } + .me-sm-n4 { + margin-right: -1.5rem !important; + } + .me-sm-n5 { + margin-right: -3rem !important; + } + .me-sm-n6 { + margin-right: -4.5rem !important; + } + .me-sm-n7 { + margin-right: -6rem !important; + } + .mb-sm-n1 { + margin-bottom: -0.25rem !important; + } + .mb-sm-n2 { + margin-bottom: -0.5rem !important; + } + .mb-sm-n3 { + margin-bottom: -1rem !important; + } + .mb-sm-n4 { + margin-bottom: -1.5rem !important; + } + .mb-sm-n5 { + margin-bottom: -3rem !important; + } + .mb-sm-n6 { + margin-bottom: -4.5rem !important; + } + .mb-sm-n7 { + margin-bottom: -6rem !important; + } + .ms-sm-n1 { + margin-left: -0.25rem !important; + } + .ms-sm-n2 { + margin-left: -0.5rem !important; + } + .ms-sm-n3 { + margin-left: -1rem !important; + } + .ms-sm-n4 { + margin-left: -1.5rem !important; + } + .ms-sm-n5 { + margin-left: -3rem !important; + } + .ms-sm-n6 { + margin-left: -4.5rem !important; + } + .ms-sm-n7 { + margin-left: -6rem !important; + } + .p-sm-0 { + padding: 0 !important; + } + .p-sm-1 { + padding: 0.25rem !important; + } + .p-sm-2 { + padding: 0.5rem !important; + } + .p-sm-3 { + padding: 1rem !important; + } + .p-sm-4 { + padding: 1.5rem !important; + } + .p-sm-5 { + padding: 3rem !important; + } + .p-sm-6 { + padding: 4.5rem !important; + } + .p-sm-7 { + padding: 6rem !important; + } + .px-sm-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-sm-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-sm-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-sm-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-sm-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-sm-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .px-sm-6 { + padding-right: 4.5rem !important; + padding-left: 4.5rem !important; + } + .px-sm-7 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .py-sm-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-sm-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-sm-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-sm-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-sm-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-sm-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .py-sm-6 { + padding-top: 4.5rem !important; + padding-bottom: 4.5rem !important; + } + .py-sm-7 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .pt-sm-0 { + padding-top: 0 !important; + } + .pt-sm-1 { + padding-top: 0.25rem !important; + } + .pt-sm-2 { + padding-top: 0.5rem !important; + } + .pt-sm-3 { + padding-top: 1rem !important; + } + .pt-sm-4 { + padding-top: 1.5rem !important; + } + .pt-sm-5 { + padding-top: 3rem !important; + } + .pt-sm-6 { + padding-top: 4.5rem !important; + } + .pt-sm-7 { + padding-top: 6rem !important; + } + .pe-sm-0 { + padding-right: 0 !important; + } + .pe-sm-1 { + padding-right: 0.25rem !important; + } + .pe-sm-2 { + padding-right: 0.5rem !important; + } + .pe-sm-3 { + padding-right: 1rem !important; + } + .pe-sm-4 { + padding-right: 1.5rem !important; + } + .pe-sm-5 { + padding-right: 3rem !important; + } + .pe-sm-6 { + padding-right: 4.5rem !important; + } + .pe-sm-7 { + padding-right: 6rem !important; + } + .pb-sm-0 { + padding-bottom: 0 !important; + } + .pb-sm-1 { + padding-bottom: 0.25rem !important; + } + .pb-sm-2 { + padding-bottom: 0.5rem !important; + } + .pb-sm-3 { + padding-bottom: 1rem !important; + } + .pb-sm-4 { + padding-bottom: 1.5rem !important; + } + .pb-sm-5 { + padding-bottom: 3rem !important; + } + .pb-sm-6 { + padding-bottom: 4.5rem !important; + } + .pb-sm-7 { + padding-bottom: 6rem !important; + } + .ps-sm-0 { + padding-left: 0 !important; + } + .ps-sm-1 { + padding-left: 0.25rem !important; + } + .ps-sm-2 { + padding-left: 0.5rem !important; + } + .ps-sm-3 { + padding-left: 1rem !important; + } + .ps-sm-4 { + padding-left: 1.5rem !important; + } + .ps-sm-5 { + padding-left: 3rem !important; + } + .ps-sm-6 { + padding-left: 4.5rem !important; + } + .ps-sm-7 { + padding-left: 6rem !important; + } + .text-sm-start { + text-align: left !important; + } + .text-sm-end { + text-align: right !important; + } + .text-sm-center { + text-align: center !important; + } +} + +@media (min-width: 768px) { + .float-md-start { + float: left !important; + } + .float-md-end { + float: right !important; + } + .float-md-none { + float: none !important; + } + .d-md-inline { + display: inline !important; + } + .d-md-inline-block { + display: inline-block !important; + } + .d-md-block { + display: block !important; + } + .d-md-grid { + display: grid !important; + } + .d-md-table { + display: table !important; + } + .d-md-table-row { + display: table-row !important; + } + .d-md-table-cell { + display: table-cell !important; + } + .d-md-flex { + display: flex !important; + } + .d-md-inline-flex { + display: inline-flex !important; + } + .d-md-none { + display: none !important; + } + .flex-md-fill { + flex: 1 1 auto !important; + } + .flex-md-row { + flex-direction: row !important; + } + .flex-md-column { + flex-direction: column !important; + } + .flex-md-row-reverse { + flex-direction: row-reverse !important; + } + .flex-md-column-reverse { + flex-direction: column-reverse !important; + } + .flex-md-grow-0 { + flex-grow: 0 !important; + } + .flex-md-grow-1 { + flex-grow: 1 !important; + } + .flex-md-shrink-0 { + flex-shrink: 0 !important; + } + .flex-md-shrink-1 { + flex-shrink: 1 !important; + } + .flex-md-wrap { + flex-wrap: wrap !important; + } + .flex-md-nowrap { + flex-wrap: nowrap !important; + } + .flex-md-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .gap-md-0 { + gap: 0 !important; + } + .gap-md-1 { + gap: 0.25rem !important; + } + .gap-md-2 { + gap: 0.5rem !important; + } + .gap-md-3 { + gap: 1rem !important; + } + .gap-md-4 { + gap: 1.5rem !important; + } + .gap-md-5 { + gap: 3rem !important; + } + .gap-md-6 { + gap: 4.5rem !important; + } + .gap-md-7 { + gap: 6rem !important; + } + .justify-content-md-start { + justify-content: flex-start !important; + } + .justify-content-md-end { + justify-content: flex-end !important; + } + .justify-content-md-center { + justify-content: center !important; + } + .justify-content-md-between { + justify-content: space-between !important; + } + .justify-content-md-around { + justify-content: space-around !important; + } + .justify-content-md-evenly { + justify-content: space-evenly !important; + } + .align-items-md-start { + align-items: flex-start !important; + } + .align-items-md-end { + align-items: flex-end !important; + } + .align-items-md-center { + align-items: center !important; + } + .align-items-md-baseline { + align-items: baseline !important; + } + .align-items-md-stretch { + align-items: stretch !important; + } + .align-content-md-start { + align-content: flex-start !important; + } + .align-content-md-end { + align-content: flex-end !important; + } + .align-content-md-center { + align-content: center !important; + } + .align-content-md-between { + align-content: space-between !important; + } + .align-content-md-around { + align-content: space-around !important; + } + .align-content-md-stretch { + align-content: stretch !important; + } + .align-self-md-auto { + align-self: auto !important; + } + .align-self-md-start { + align-self: flex-start !important; + } + .align-self-md-end { + align-self: flex-end !important; + } + .align-self-md-center { + align-self: center !important; + } + .align-self-md-baseline { + align-self: baseline !important; + } + .align-self-md-stretch { + align-self: stretch !important; + } + .order-md-first { + order: -1 !important; + } + .order-md-0 { + order: 0 !important; + } + .order-md-1 { + order: 1 !important; + } + .order-md-2 { + order: 2 !important; + } + .order-md-3 { + order: 3 !important; + } + .order-md-4 { + order: 4 !important; + } + .order-md-5 { + order: 5 !important; + } + .order-md-last { + order: 6 !important; + } + .m-md-0 { + margin: 0 !important; + } + .m-md-1 { + margin: 0.25rem !important; + } + .m-md-2 { + margin: 0.5rem !important; + } + .m-md-3 { + margin: 1rem !important; + } + .m-md-4 { + margin: 1.5rem !important; + } + .m-md-5 { + margin: 3rem !important; + } + .m-md-6 { + margin: 4.5rem !important; + } + .m-md-7 { + margin: 6rem !important; + } + .m-md-auto { + margin: auto !important; + } + .mx-md-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-md-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-md-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-md-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-md-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-md-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-md-6 { + margin-right: 4.5rem !important; + margin-left: 4.5rem !important; + } + .mx-md-7 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-md-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-md-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-md-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-md-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-md-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-md-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-md-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-md-6 { + margin-top: 4.5rem !important; + margin-bottom: 4.5rem !important; + } + .my-md-7 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-md-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-md-0 { + margin-top: 0 !important; + } + .mt-md-1 { + margin-top: 0.25rem !important; + } + .mt-md-2 { + margin-top: 0.5rem !important; + } + .mt-md-3 { + margin-top: 1rem !important; + } + .mt-md-4 { + margin-top: 1.5rem !important; + } + .mt-md-5 { + margin-top: 3rem !important; + } + .mt-md-6 { + margin-top: 4.5rem !important; + } + .mt-md-7 { + margin-top: 6rem !important; + } + .mt-md-auto { + margin-top: auto !important; + } + .me-md-0 { + margin-right: 0 !important; + } + .me-md-1 { + margin-right: 0.25rem !important; + } + .me-md-2 { + margin-right: 0.5rem !important; + } + .me-md-3 { + margin-right: 1rem !important; + } + .me-md-4 { + margin-right: 1.5rem !important; + } + .me-md-5 { + margin-right: 3rem !important; + } + .me-md-6 { + margin-right: 4.5rem !important; + } + .me-md-7 { + margin-right: 6rem !important; + } + .me-md-auto { + margin-right: auto !important; + } + .mb-md-0 { + margin-bottom: 0 !important; + } + .mb-md-1 { + margin-bottom: 0.25rem !important; + } + .mb-md-2 { + margin-bottom: 0.5rem !important; + } + .mb-md-3 { + margin-bottom: 1rem !important; + } + .mb-md-4 { + margin-bottom: 1.5rem !important; + } + .mb-md-5 { + margin-bottom: 3rem !important; + } + .mb-md-6 { + margin-bottom: 4.5rem !important; + } + .mb-md-7 { + margin-bottom: 6rem !important; + } + .mb-md-auto { + margin-bottom: auto !important; + } + .ms-md-0 { + margin-left: 0 !important; + } + .ms-md-1 { + margin-left: 0.25rem !important; + } + .ms-md-2 { + margin-left: 0.5rem !important; + } + .ms-md-3 { + margin-left: 1rem !important; + } + .ms-md-4 { + margin-left: 1.5rem !important; + } + .ms-md-5 { + margin-left: 3rem !important; + } + .ms-md-6 { + margin-left: 4.5rem !important; + } + .ms-md-7 { + margin-left: 6rem !important; + } + .ms-md-auto { + margin-left: auto !important; + } + .m-md-n1 { + margin: -0.25rem !important; + } + .m-md-n2 { + margin: -0.5rem !important; + } + .m-md-n3 { + margin: -1rem !important; + } + .m-md-n4 { + margin: -1.5rem !important; + } + .m-md-n5 { + margin: -3rem !important; + } + .m-md-n6 { + margin: -4.5rem !important; + } + .m-md-n7 { + margin: -6rem !important; + } + .mx-md-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-md-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-md-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-md-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-md-n5 { + margin-right: -3rem !important; + margin-left: -3rem !important; + } + .mx-md-n6 { + margin-right: -4.5rem !important; + margin-left: -4.5rem !important; + } + .mx-md-n7 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .my-md-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-md-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-md-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-md-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-md-n5 { + margin-top: -3rem !important; + margin-bottom: -3rem !important; + } + .my-md-n6 { + margin-top: -4.5rem !important; + margin-bottom: -4.5rem !important; + } + .my-md-n7 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .mt-md-n1 { + margin-top: -0.25rem !important; + } + .mt-md-n2 { + margin-top: -0.5rem !important; + } + .mt-md-n3 { + margin-top: -1rem !important; + } + .mt-md-n4 { + margin-top: -1.5rem !important; + } + .mt-md-n5 { + margin-top: -3rem !important; + } + .mt-md-n6 { + margin-top: -4.5rem !important; + } + .mt-md-n7 { + margin-top: -6rem !important; + } + .me-md-n1 { + margin-right: -0.25rem !important; + } + .me-md-n2 { + margin-right: -0.5rem !important; + } + .me-md-n3 { + margin-right: -1rem !important; + } + .me-md-n4 { + margin-right: -1.5rem !important; + } + .me-md-n5 { + margin-right: -3rem !important; + } + .me-md-n6 { + margin-right: -4.5rem !important; + } + .me-md-n7 { + margin-right: -6rem !important; + } + .mb-md-n1 { + margin-bottom: -0.25rem !important; + } + .mb-md-n2 { + margin-bottom: -0.5rem !important; + } + .mb-md-n3 { + margin-bottom: -1rem !important; + } + .mb-md-n4 { + margin-bottom: -1.5rem !important; + } + .mb-md-n5 { + margin-bottom: -3rem !important; + } + .mb-md-n6 { + margin-bottom: -4.5rem !important; + } + .mb-md-n7 { + margin-bottom: -6rem !important; + } + .ms-md-n1 { + margin-left: -0.25rem !important; + } + .ms-md-n2 { + margin-left: -0.5rem !important; + } + .ms-md-n3 { + margin-left: -1rem !important; + } + .ms-md-n4 { + margin-left: -1.5rem !important; + } + .ms-md-n5 { + margin-left: -3rem !important; + } + .ms-md-n6 { + margin-left: -4.5rem !important; + } + .ms-md-n7 { + margin-left: -6rem !important; + } + .p-md-0 { + padding: 0 !important; + } + .p-md-1 { + padding: 0.25rem !important; + } + .p-md-2 { + padding: 0.5rem !important; + } + .p-md-3 { + padding: 1rem !important; + } + .p-md-4 { + padding: 1.5rem !important; + } + .p-md-5 { + padding: 3rem !important; + } + .p-md-6 { + padding: 4.5rem !important; + } + .p-md-7 { + padding: 6rem !important; + } + .px-md-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-md-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-md-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-md-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-md-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-md-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .px-md-6 { + padding-right: 4.5rem !important; + padding-left: 4.5rem !important; + } + .px-md-7 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .py-md-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-md-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-md-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-md-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-md-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-md-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .py-md-6 { + padding-top: 4.5rem !important; + padding-bottom: 4.5rem !important; + } + .py-md-7 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .pt-md-0 { + padding-top: 0 !important; + } + .pt-md-1 { + padding-top: 0.25rem !important; + } + .pt-md-2 { + padding-top: 0.5rem !important; + } + .pt-md-3 { + padding-top: 1rem !important; + } + .pt-md-4 { + padding-top: 1.5rem !important; + } + .pt-md-5 { + padding-top: 3rem !important; + } + .pt-md-6 { + padding-top: 4.5rem !important; + } + .pt-md-7 { + padding-top: 6rem !important; + } + .pe-md-0 { + padding-right: 0 !important; + } + .pe-md-1 { + padding-right: 0.25rem !important; + } + .pe-md-2 { + padding-right: 0.5rem !important; + } + .pe-md-3 { + padding-right: 1rem !important; + } + .pe-md-4 { + padding-right: 1.5rem !important; + } + .pe-md-5 { + padding-right: 3rem !important; + } + .pe-md-6 { + padding-right: 4.5rem !important; + } + .pe-md-7 { + padding-right: 6rem !important; + } + .pb-md-0 { + padding-bottom: 0 !important; + } + .pb-md-1 { + padding-bottom: 0.25rem !important; + } + .pb-md-2 { + padding-bottom: 0.5rem !important; + } + .pb-md-3 { + padding-bottom: 1rem !important; + } + .pb-md-4 { + padding-bottom: 1.5rem !important; + } + .pb-md-5 { + padding-bottom: 3rem !important; + } + .pb-md-6 { + padding-bottom: 4.5rem !important; + } + .pb-md-7 { + padding-bottom: 6rem !important; + } + .ps-md-0 { + padding-left: 0 !important; + } + .ps-md-1 { + padding-left: 0.25rem !important; + } + .ps-md-2 { + padding-left: 0.5rem !important; + } + .ps-md-3 { + padding-left: 1rem !important; + } + .ps-md-4 { + padding-left: 1.5rem !important; + } + .ps-md-5 { + padding-left: 3rem !important; + } + .ps-md-6 { + padding-left: 4.5rem !important; + } + .ps-md-7 { + padding-left: 6rem !important; + } + .text-md-start { + text-align: left !important; + } + .text-md-end { + text-align: right !important; + } + .text-md-center { + text-align: center !important; + } +} + +@media (min-width: 992px) { + .float-lg-start { + float: left !important; + } + .float-lg-end { + float: right !important; + } + .float-lg-none { + float: none !important; + } + .d-lg-inline { + display: inline !important; + } + .d-lg-inline-block { + display: inline-block !important; + } + .d-lg-block { + display: block !important; + } + .d-lg-grid { + display: grid !important; + } + .d-lg-table { + display: table !important; + } + .d-lg-table-row { + display: table-row !important; + } + .d-lg-table-cell { + display: table-cell !important; + } + .d-lg-flex { + display: flex !important; + } + .d-lg-inline-flex { + display: inline-flex !important; + } + .d-lg-none { + display: none !important; + } + .flex-lg-fill { + flex: 1 1 auto !important; + } + .flex-lg-row { + flex-direction: row !important; + } + .flex-lg-column { + flex-direction: column !important; + } + .flex-lg-row-reverse { + flex-direction: row-reverse !important; + } + .flex-lg-column-reverse { + flex-direction: column-reverse !important; + } + .flex-lg-grow-0 { + flex-grow: 0 !important; + } + .flex-lg-grow-1 { + flex-grow: 1 !important; + } + .flex-lg-shrink-0 { + flex-shrink: 0 !important; + } + .flex-lg-shrink-1 { + flex-shrink: 1 !important; + } + .flex-lg-wrap { + flex-wrap: wrap !important; + } + .flex-lg-nowrap { + flex-wrap: nowrap !important; + } + .flex-lg-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .gap-lg-0 { + gap: 0 !important; + } + .gap-lg-1 { + gap: 0.25rem !important; + } + .gap-lg-2 { + gap: 0.5rem !important; + } + .gap-lg-3 { + gap: 1rem !important; + } + .gap-lg-4 { + gap: 1.5rem !important; + } + .gap-lg-5 { + gap: 3rem !important; + } + .gap-lg-6 { + gap: 4.5rem !important; + } + .gap-lg-7 { + gap: 6rem !important; + } + .justify-content-lg-start { + justify-content: flex-start !important; + } + .justify-content-lg-end { + justify-content: flex-end !important; + } + .justify-content-lg-center { + justify-content: center !important; + } + .justify-content-lg-between { + justify-content: space-between !important; + } + .justify-content-lg-around { + justify-content: space-around !important; + } + .justify-content-lg-evenly { + justify-content: space-evenly !important; + } + .align-items-lg-start { + align-items: flex-start !important; + } + .align-items-lg-end { + align-items: flex-end !important; + } + .align-items-lg-center { + align-items: center !important; + } + .align-items-lg-baseline { + align-items: baseline !important; + } + .align-items-lg-stretch { + align-items: stretch !important; + } + .align-content-lg-start { + align-content: flex-start !important; + } + .align-content-lg-end { + align-content: flex-end !important; + } + .align-content-lg-center { + align-content: center !important; + } + .align-content-lg-between { + align-content: space-between !important; + } + .align-content-lg-around { + align-content: space-around !important; + } + .align-content-lg-stretch { + align-content: stretch !important; + } + .align-self-lg-auto { + align-self: auto !important; + } + .align-self-lg-start { + align-self: flex-start !important; + } + .align-self-lg-end { + align-self: flex-end !important; + } + .align-self-lg-center { + align-self: center !important; + } + .align-self-lg-baseline { + align-self: baseline !important; + } + .align-self-lg-stretch { + align-self: stretch !important; + } + .order-lg-first { + order: -1 !important; + } + .order-lg-0 { + order: 0 !important; + } + .order-lg-1 { + order: 1 !important; + } + .order-lg-2 { + order: 2 !important; + } + .order-lg-3 { + order: 3 !important; + } + .order-lg-4 { + order: 4 !important; + } + .order-lg-5 { + order: 5 !important; + } + .order-lg-last { + order: 6 !important; + } + .m-lg-0 { + margin: 0 !important; + } + .m-lg-1 { + margin: 0.25rem !important; + } + .m-lg-2 { + margin: 0.5rem !important; + } + .m-lg-3 { + margin: 1rem !important; + } + .m-lg-4 { + margin: 1.5rem !important; + } + .m-lg-5 { + margin: 3rem !important; + } + .m-lg-6 { + margin: 4.5rem !important; + } + .m-lg-7 { + margin: 6rem !important; + } + .m-lg-auto { + margin: auto !important; + } + .mx-lg-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-lg-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-lg-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-lg-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-lg-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-lg-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-lg-6 { + margin-right: 4.5rem !important; + margin-left: 4.5rem !important; + } + .mx-lg-7 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-lg-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-lg-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-lg-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-lg-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-lg-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-lg-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-lg-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-lg-6 { + margin-top: 4.5rem !important; + margin-bottom: 4.5rem !important; + } + .my-lg-7 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-lg-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-lg-0 { + margin-top: 0 !important; + } + .mt-lg-1 { + margin-top: 0.25rem !important; + } + .mt-lg-2 { + margin-top: 0.5rem !important; + } + .mt-lg-3 { + margin-top: 1rem !important; + } + .mt-lg-4 { + margin-top: 1.5rem !important; + } + .mt-lg-5 { + margin-top: 3rem !important; + } + .mt-lg-6 { + margin-top: 4.5rem !important; + } + .mt-lg-7 { + margin-top: 6rem !important; + } + .mt-lg-auto { + margin-top: auto !important; + } + .me-lg-0 { + margin-right: 0 !important; + } + .me-lg-1 { + margin-right: 0.25rem !important; + } + .me-lg-2 { + margin-right: 0.5rem !important; + } + .me-lg-3 { + margin-right: 1rem !important; + } + .me-lg-4 { + margin-right: 1.5rem !important; + } + .me-lg-5 { + margin-right: 3rem !important; + } + .me-lg-6 { + margin-right: 4.5rem !important; + } + .me-lg-7 { + margin-right: 6rem !important; + } + .me-lg-auto { + margin-right: auto !important; + } + .mb-lg-0 { + margin-bottom: 0 !important; + } + .mb-lg-1 { + margin-bottom: 0.25rem !important; + } + .mb-lg-2 { + margin-bottom: 0.5rem !important; + } + .mb-lg-3 { + margin-bottom: 1rem !important; + } + .mb-lg-4 { + margin-bottom: 1.5rem !important; + } + .mb-lg-5 { + margin-bottom: 3rem !important; + } + .mb-lg-6 { + margin-bottom: 4.5rem !important; + } + .mb-lg-7 { + margin-bottom: 6rem !important; + } + .mb-lg-auto { + margin-bottom: auto !important; + } + .ms-lg-0 { + margin-left: 0 !important; + } + .ms-lg-1 { + margin-left: 0.25rem !important; + } + .ms-lg-2 { + margin-left: 0.5rem !important; + } + .ms-lg-3 { + margin-left: 1rem !important; + } + .ms-lg-4 { + margin-left: 1.5rem !important; + } + .ms-lg-5 { + margin-left: 3rem !important; + } + .ms-lg-6 { + margin-left: 4.5rem !important; + } + .ms-lg-7 { + margin-left: 6rem !important; + } + .ms-lg-auto { + margin-left: auto !important; + } + .m-lg-n1 { + margin: -0.25rem !important; + } + .m-lg-n2 { + margin: -0.5rem !important; + } + .m-lg-n3 { + margin: -1rem !important; + } + .m-lg-n4 { + margin: -1.5rem !important; + } + .m-lg-n5 { + margin: -3rem !important; + } + .m-lg-n6 { + margin: -4.5rem !important; + } + .m-lg-n7 { + margin: -6rem !important; + } + .mx-lg-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-lg-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-lg-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-lg-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-lg-n5 { + margin-right: -3rem !important; + margin-left: -3rem !important; + } + .mx-lg-n6 { + margin-right: -4.5rem !important; + margin-left: -4.5rem !important; + } + .mx-lg-n7 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .my-lg-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-lg-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-lg-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-lg-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-lg-n5 { + margin-top: -3rem !important; + margin-bottom: -3rem !important; + } + .my-lg-n6 { + margin-top: -4.5rem !important; + margin-bottom: -4.5rem !important; + } + .my-lg-n7 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .mt-lg-n1 { + margin-top: -0.25rem !important; + } + .mt-lg-n2 { + margin-top: -0.5rem !important; + } + .mt-lg-n3 { + margin-top: -1rem !important; + } + .mt-lg-n4 { + margin-top: -1.5rem !important; + } + .mt-lg-n5 { + margin-top: -3rem !important; + } + .mt-lg-n6 { + margin-top: -4.5rem !important; + } + .mt-lg-n7 { + margin-top: -6rem !important; + } + .me-lg-n1 { + margin-right: -0.25rem !important; + } + .me-lg-n2 { + margin-right: -0.5rem !important; + } + .me-lg-n3 { + margin-right: -1rem !important; + } + .me-lg-n4 { + margin-right: -1.5rem !important; + } + .me-lg-n5 { + margin-right: -3rem !important; + } + .me-lg-n6 { + margin-right: -4.5rem !important; + } + .me-lg-n7 { + margin-right: -6rem !important; + } + .mb-lg-n1 { + margin-bottom: -0.25rem !important; + } + .mb-lg-n2 { + margin-bottom: -0.5rem !important; + } + .mb-lg-n3 { + margin-bottom: -1rem !important; + } + .mb-lg-n4 { + margin-bottom: -1.5rem !important; + } + .mb-lg-n5 { + margin-bottom: -3rem !important; + } + .mb-lg-n6 { + margin-bottom: -4.5rem !important; + } + .mb-lg-n7 { + margin-bottom: -6rem !important; + } + .ms-lg-n1 { + margin-left: -0.25rem !important; + } + .ms-lg-n2 { + margin-left: -0.5rem !important; + } + .ms-lg-n3 { + margin-left: -1rem !important; + } + .ms-lg-n4 { + margin-left: -1.5rem !important; + } + .ms-lg-n5 { + margin-left: -3rem !important; + } + .ms-lg-n6 { + margin-left: -4.5rem !important; + } + .ms-lg-n7 { + margin-left: -6rem !important; + } + .p-lg-0 { + padding: 0 !important; + } + .p-lg-1 { + padding: 0.25rem !important; + } + .p-lg-2 { + padding: 0.5rem !important; + } + .p-lg-3 { + padding: 1rem !important; + } + .p-lg-4 { + padding: 1.5rem !important; + } + .p-lg-5 { + padding: 3rem !important; + } + .p-lg-6 { + padding: 4.5rem !important; + } + .p-lg-7 { + padding: 6rem !important; + } + .px-lg-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-lg-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-lg-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-lg-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-lg-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-lg-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .px-lg-6 { + padding-right: 4.5rem !important; + padding-left: 4.5rem !important; + } + .px-lg-7 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .py-lg-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-lg-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-lg-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-lg-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-lg-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-lg-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .py-lg-6 { + padding-top: 4.5rem !important; + padding-bottom: 4.5rem !important; + } + .py-lg-7 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .pt-lg-0 { + padding-top: 0 !important; + } + .pt-lg-1 { + padding-top: 0.25rem !important; + } + .pt-lg-2 { + padding-top: 0.5rem !important; + } + .pt-lg-3 { + padding-top: 1rem !important; + } + .pt-lg-4 { + padding-top: 1.5rem !important; + } + .pt-lg-5 { + padding-top: 3rem !important; + } + .pt-lg-6 { + padding-top: 4.5rem !important; + } + .pt-lg-7 { + padding-top: 6rem !important; + } + .pe-lg-0 { + padding-right: 0 !important; + } + .pe-lg-1 { + padding-right: 0.25rem !important; + } + .pe-lg-2 { + padding-right: 0.5rem !important; + } + .pe-lg-3 { + padding-right: 1rem !important; + } + .pe-lg-4 { + padding-right: 1.5rem !important; + } + .pe-lg-5 { + padding-right: 3rem !important; + } + .pe-lg-6 { + padding-right: 4.5rem !important; + } + .pe-lg-7 { + padding-right: 6rem !important; + } + .pb-lg-0 { + padding-bottom: 0 !important; + } + .pb-lg-1 { + padding-bottom: 0.25rem !important; + } + .pb-lg-2 { + padding-bottom: 0.5rem !important; + } + .pb-lg-3 { + padding-bottom: 1rem !important; + } + .pb-lg-4 { + padding-bottom: 1.5rem !important; + } + .pb-lg-5 { + padding-bottom: 3rem !important; + } + .pb-lg-6 { + padding-bottom: 4.5rem !important; + } + .pb-lg-7 { + padding-bottom: 6rem !important; + } + .ps-lg-0 { + padding-left: 0 !important; + } + .ps-lg-1 { + padding-left: 0.25rem !important; + } + .ps-lg-2 { + padding-left: 0.5rem !important; + } + .ps-lg-3 { + padding-left: 1rem !important; + } + .ps-lg-4 { + padding-left: 1.5rem !important; + } + .ps-lg-5 { + padding-left: 3rem !important; + } + .ps-lg-6 { + padding-left: 4.5rem !important; + } + .ps-lg-7 { + padding-left: 6rem !important; + } + .text-lg-start { + text-align: left !important; + } + .text-lg-end { + text-align: right !important; + } + .text-lg-center { + text-align: center !important; + } +} + +@media (min-width: 1200px) { + .float-xl-start { + float: left !important; + } + .float-xl-end { + float: right !important; + } + .float-xl-none { + float: none !important; + } + .d-xl-inline { + display: inline !important; + } + .d-xl-inline-block { + display: inline-block !important; + } + .d-xl-block { + display: block !important; + } + .d-xl-grid { + display: grid !important; + } + .d-xl-table { + display: table !important; + } + .d-xl-table-row { + display: table-row !important; + } + .d-xl-table-cell { + display: table-cell !important; + } + .d-xl-flex { + display: flex !important; + } + .d-xl-inline-flex { + display: inline-flex !important; + } + .d-xl-none { + display: none !important; + } + .flex-xl-fill { + flex: 1 1 auto !important; + } + .flex-xl-row { + flex-direction: row !important; + } + .flex-xl-column { + flex-direction: column !important; + } + .flex-xl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xl-grow-0 { + flex-grow: 0 !important; + } + .flex-xl-grow-1 { + flex-grow: 1 !important; + } + .flex-xl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xl-wrap { + flex-wrap: wrap !important; + } + .flex-xl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .gap-xl-0 { + gap: 0 !important; + } + .gap-xl-1 { + gap: 0.25rem !important; + } + .gap-xl-2 { + gap: 0.5rem !important; + } + .gap-xl-3 { + gap: 1rem !important; + } + .gap-xl-4 { + gap: 1.5rem !important; + } + .gap-xl-5 { + gap: 3rem !important; + } + .gap-xl-6 { + gap: 4.5rem !important; + } + .gap-xl-7 { + gap: 6rem !important; + } + .justify-content-xl-start { + justify-content: flex-start !important; + } + .justify-content-xl-end { + justify-content: flex-end !important; + } + .justify-content-xl-center { + justify-content: center !important; + } + .justify-content-xl-between { + justify-content: space-between !important; + } + .justify-content-xl-around { + justify-content: space-around !important; + } + .justify-content-xl-evenly { + justify-content: space-evenly !important; + } + .align-items-xl-start { + align-items: flex-start !important; + } + .align-items-xl-end { + align-items: flex-end !important; + } + .align-items-xl-center { + align-items: center !important; + } + .align-items-xl-baseline { + align-items: baseline !important; + } + .align-items-xl-stretch { + align-items: stretch !important; + } + .align-content-xl-start { + align-content: flex-start !important; + } + .align-content-xl-end { + align-content: flex-end !important; + } + .align-content-xl-center { + align-content: center !important; + } + .align-content-xl-between { + align-content: space-between !important; + } + .align-content-xl-around { + align-content: space-around !important; + } + .align-content-xl-stretch { + align-content: stretch !important; + } + .align-self-xl-auto { + align-self: auto !important; + } + .align-self-xl-start { + align-self: flex-start !important; + } + .align-self-xl-end { + align-self: flex-end !important; + } + .align-self-xl-center { + align-self: center !important; + } + .align-self-xl-baseline { + align-self: baseline !important; + } + .align-self-xl-stretch { + align-self: stretch !important; + } + .order-xl-first { + order: -1 !important; + } + .order-xl-0 { + order: 0 !important; + } + .order-xl-1 { + order: 1 !important; + } + .order-xl-2 { + order: 2 !important; + } + .order-xl-3 { + order: 3 !important; + } + .order-xl-4 { + order: 4 !important; + } + .order-xl-5 { + order: 5 !important; + } + .order-xl-last { + order: 6 !important; + } + .m-xl-0 { + margin: 0 !important; + } + .m-xl-1 { + margin: 0.25rem !important; + } + .m-xl-2 { + margin: 0.5rem !important; + } + .m-xl-3 { + margin: 1rem !important; + } + .m-xl-4 { + margin: 1.5rem !important; + } + .m-xl-5 { + margin: 3rem !important; + } + .m-xl-6 { + margin: 4.5rem !important; + } + .m-xl-7 { + margin: 6rem !important; + } + .m-xl-auto { + margin: auto !important; + } + .mx-xl-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-xl-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-xl-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-xl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-xl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-xl-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-xl-6 { + margin-right: 4.5rem !important; + margin-left: 4.5rem !important; + } + .mx-xl-7 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-xl-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-xl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-xl-6 { + margin-top: 4.5rem !important; + margin-bottom: 4.5rem !important; + } + .my-xl-7 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-xl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xl-0 { + margin-top: 0 !important; + } + .mt-xl-1 { + margin-top: 0.25rem !important; + } + .mt-xl-2 { + margin-top: 0.5rem !important; + } + .mt-xl-3 { + margin-top: 1rem !important; + } + .mt-xl-4 { + margin-top: 1.5rem !important; + } + .mt-xl-5 { + margin-top: 3rem !important; + } + .mt-xl-6 { + margin-top: 4.5rem !important; + } + .mt-xl-7 { + margin-top: 6rem !important; + } + .mt-xl-auto { + margin-top: auto !important; + } + .me-xl-0 { + margin-right: 0 !important; + } + .me-xl-1 { + margin-right: 0.25rem !important; + } + .me-xl-2 { + margin-right: 0.5rem !important; + } + .me-xl-3 { + margin-right: 1rem !important; + } + .me-xl-4 { + margin-right: 1.5rem !important; + } + .me-xl-5 { + margin-right: 3rem !important; + } + .me-xl-6 { + margin-right: 4.5rem !important; + } + .me-xl-7 { + margin-right: 6rem !important; + } + .me-xl-auto { + margin-right: auto !important; + } + .mb-xl-0 { + margin-bottom: 0 !important; + } + .mb-xl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xl-3 { + margin-bottom: 1rem !important; + } + .mb-xl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xl-5 { + margin-bottom: 3rem !important; + } + .mb-xl-6 { + margin-bottom: 4.5rem !important; + } + .mb-xl-7 { + margin-bottom: 6rem !important; + } + .mb-xl-auto { + margin-bottom: auto !important; + } + .ms-xl-0 { + margin-left: 0 !important; + } + .ms-xl-1 { + margin-left: 0.25rem !important; + } + .ms-xl-2 { + margin-left: 0.5rem !important; + } + .ms-xl-3 { + margin-left: 1rem !important; + } + .ms-xl-4 { + margin-left: 1.5rem !important; + } + .ms-xl-5 { + margin-left: 3rem !important; + } + .ms-xl-6 { + margin-left: 4.5rem !important; + } + .ms-xl-7 { + margin-left: 6rem !important; + } + .ms-xl-auto { + margin-left: auto !important; + } + .m-xl-n1 { + margin: -0.25rem !important; + } + .m-xl-n2 { + margin: -0.5rem !important; + } + .m-xl-n3 { + margin: -1rem !important; + } + .m-xl-n4 { + margin: -1.5rem !important; + } + .m-xl-n5 { + margin: -3rem !important; + } + .m-xl-n6 { + margin: -4.5rem !important; + } + .m-xl-n7 { + margin: -6rem !important; + } + .mx-xl-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-xl-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-xl-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-xl-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-xl-n5 { + margin-right: -3rem !important; + margin-left: -3rem !important; + } + .mx-xl-n6 { + margin-right: -4.5rem !important; + margin-left: -4.5rem !important; + } + .mx-xl-n7 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .my-xl-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-xl-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-xl-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-xl-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-xl-n5 { + margin-top: -3rem !important; + margin-bottom: -3rem !important; + } + .my-xl-n6 { + margin-top: -4.5rem !important; + margin-bottom: -4.5rem !important; + } + .my-xl-n7 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .mt-xl-n1 { + margin-top: -0.25rem !important; + } + .mt-xl-n2 { + margin-top: -0.5rem !important; + } + .mt-xl-n3 { + margin-top: -1rem !important; + } + .mt-xl-n4 { + margin-top: -1.5rem !important; + } + .mt-xl-n5 { + margin-top: -3rem !important; + } + .mt-xl-n6 { + margin-top: -4.5rem !important; + } + .mt-xl-n7 { + margin-top: -6rem !important; + } + .me-xl-n1 { + margin-right: -0.25rem !important; + } + .me-xl-n2 { + margin-right: -0.5rem !important; + } + .me-xl-n3 { + margin-right: -1rem !important; + } + .me-xl-n4 { + margin-right: -1.5rem !important; + } + .me-xl-n5 { + margin-right: -3rem !important; + } + .me-xl-n6 { + margin-right: -4.5rem !important; + } + .me-xl-n7 { + margin-right: -6rem !important; + } + .mb-xl-n1 { + margin-bottom: -0.25rem !important; + } + .mb-xl-n2 { + margin-bottom: -0.5rem !important; + } + .mb-xl-n3 { + margin-bottom: -1rem !important; + } + .mb-xl-n4 { + margin-bottom: -1.5rem !important; + } + .mb-xl-n5 { + margin-bottom: -3rem !important; + } + .mb-xl-n6 { + margin-bottom: -4.5rem !important; + } + .mb-xl-n7 { + margin-bottom: -6rem !important; + } + .ms-xl-n1 { + margin-left: -0.25rem !important; + } + .ms-xl-n2 { + margin-left: -0.5rem !important; + } + .ms-xl-n3 { + margin-left: -1rem !important; + } + .ms-xl-n4 { + margin-left: -1.5rem !important; + } + .ms-xl-n5 { + margin-left: -3rem !important; + } + .ms-xl-n6 { + margin-left: -4.5rem !important; + } + .ms-xl-n7 { + margin-left: -6rem !important; + } + .p-xl-0 { + padding: 0 !important; + } + .p-xl-1 { + padding: 0.25rem !important; + } + .p-xl-2 { + padding: 0.5rem !important; + } + .p-xl-3 { + padding: 1rem !important; + } + .p-xl-4 { + padding: 1.5rem !important; + } + .p-xl-5 { + padding: 3rem !important; + } + .p-xl-6 { + padding: 4.5rem !important; + } + .p-xl-7 { + padding: 6rem !important; + } + .px-xl-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-xl-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-xl-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-xl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-xl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-xl-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .px-xl-6 { + padding-right: 4.5rem !important; + padding-left: 4.5rem !important; + } + .px-xl-7 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .py-xl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .py-xl-6 { + padding-top: 4.5rem !important; + padding-bottom: 4.5rem !important; + } + .py-xl-7 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .pt-xl-0 { + padding-top: 0 !important; + } + .pt-xl-1 { + padding-top: 0.25rem !important; + } + .pt-xl-2 { + padding-top: 0.5rem !important; + } + .pt-xl-3 { + padding-top: 1rem !important; + } + .pt-xl-4 { + padding-top: 1.5rem !important; + } + .pt-xl-5 { + padding-top: 3rem !important; + } + .pt-xl-6 { + padding-top: 4.5rem !important; + } + .pt-xl-7 { + padding-top: 6rem !important; + } + .pe-xl-0 { + padding-right: 0 !important; + } + .pe-xl-1 { + padding-right: 0.25rem !important; + } + .pe-xl-2 { + padding-right: 0.5rem !important; + } + .pe-xl-3 { + padding-right: 1rem !important; + } + .pe-xl-4 { + padding-right: 1.5rem !important; + } + .pe-xl-5 { + padding-right: 3rem !important; + } + .pe-xl-6 { + padding-right: 4.5rem !important; + } + .pe-xl-7 { + padding-right: 6rem !important; + } + .pb-xl-0 { + padding-bottom: 0 !important; + } + .pb-xl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xl-3 { + padding-bottom: 1rem !important; + } + .pb-xl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xl-5 { + padding-bottom: 3rem !important; + } + .pb-xl-6 { + padding-bottom: 4.5rem !important; + } + .pb-xl-7 { + padding-bottom: 6rem !important; + } + .ps-xl-0 { + padding-left: 0 !important; + } + .ps-xl-1 { + padding-left: 0.25rem !important; + } + .ps-xl-2 { + padding-left: 0.5rem !important; + } + .ps-xl-3 { + padding-left: 1rem !important; + } + .ps-xl-4 { + padding-left: 1.5rem !important; + } + .ps-xl-5 { + padding-left: 3rem !important; + } + .ps-xl-6 { + padding-left: 4.5rem !important; + } + .ps-xl-7 { + padding-left: 6rem !important; + } + .text-xl-start { + text-align: left !important; + } + .text-xl-end { + text-align: right !important; + } + .text-xl-center { + text-align: center !important; + } +} + +@media (min-width: 1440px) { + .float-xxl-start { + float: left !important; + } + .float-xxl-end { + float: right !important; + } + .float-xxl-none { + float: none !important; + } + .d-xxl-inline { + display: inline !important; + } + .d-xxl-inline-block { + display: inline-block !important; + } + .d-xxl-block { + display: block !important; + } + .d-xxl-grid { + display: grid !important; + } + .d-xxl-table { + display: table !important; + } + .d-xxl-table-row { + display: table-row !important; + } + .d-xxl-table-cell { + display: table-cell !important; + } + .d-xxl-flex { + display: flex !important; + } + .d-xxl-inline-flex { + display: inline-flex !important; + } + .d-xxl-none { + display: none !important; + } + .flex-xxl-fill { + flex: 1 1 auto !important; + } + .flex-xxl-row { + flex-direction: row !important; + } + .flex-xxl-column { + flex-direction: column !important; + } + .flex-xxl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xxl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xxl-grow-0 { + flex-grow: 0 !important; + } + .flex-xxl-grow-1 { + flex-grow: 1 !important; + } + .flex-xxl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xxl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xxl-wrap { + flex-wrap: wrap !important; + } + .flex-xxl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xxl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .gap-xxl-0 { + gap: 0 !important; + } + .gap-xxl-1 { + gap: 0.25rem !important; + } + .gap-xxl-2 { + gap: 0.5rem !important; + } + .gap-xxl-3 { + gap: 1rem !important; + } + .gap-xxl-4 { + gap: 1.5rem !important; + } + .gap-xxl-5 { + gap: 3rem !important; + } + .gap-xxl-6 { + gap: 4.5rem !important; + } + .gap-xxl-7 { + gap: 6rem !important; + } + .justify-content-xxl-start { + justify-content: flex-start !important; + } + .justify-content-xxl-end { + justify-content: flex-end !important; + } + .justify-content-xxl-center { + justify-content: center !important; + } + .justify-content-xxl-between { + justify-content: space-between !important; + } + .justify-content-xxl-around { + justify-content: space-around !important; + } + .justify-content-xxl-evenly { + justify-content: space-evenly !important; + } + .align-items-xxl-start { + align-items: flex-start !important; + } + .align-items-xxl-end { + align-items: flex-end !important; + } + .align-items-xxl-center { + align-items: center !important; + } + .align-items-xxl-baseline { + align-items: baseline !important; + } + .align-items-xxl-stretch { + align-items: stretch !important; + } + .align-content-xxl-start { + align-content: flex-start !important; + } + .align-content-xxl-end { + align-content: flex-end !important; + } + .align-content-xxl-center { + align-content: center !important; + } + .align-content-xxl-between { + align-content: space-between !important; + } + .align-content-xxl-around { + align-content: space-around !important; + } + .align-content-xxl-stretch { + align-content: stretch !important; + } + .align-self-xxl-auto { + align-self: auto !important; + } + .align-self-xxl-start { + align-self: flex-start !important; + } + .align-self-xxl-end { + align-self: flex-end !important; + } + .align-self-xxl-center { + align-self: center !important; + } + .align-self-xxl-baseline { + align-self: baseline !important; + } + .align-self-xxl-stretch { + align-self: stretch !important; + } + .order-xxl-first { + order: -1 !important; + } + .order-xxl-0 { + order: 0 !important; + } + .order-xxl-1 { + order: 1 !important; + } + .order-xxl-2 { + order: 2 !important; + } + .order-xxl-3 { + order: 3 !important; + } + .order-xxl-4 { + order: 4 !important; + } + .order-xxl-5 { + order: 5 !important; + } + .order-xxl-last { + order: 6 !important; + } + .m-xxl-0 { + margin: 0 !important; + } + .m-xxl-1 { + margin: 0.25rem !important; + } + .m-xxl-2 { + margin: 0.5rem !important; + } + .m-xxl-3 { + margin: 1rem !important; + } + .m-xxl-4 { + margin: 1.5rem !important; + } + .m-xxl-5 { + margin: 3rem !important; + } + .m-xxl-6 { + margin: 4.5rem !important; + } + .m-xxl-7 { + margin: 6rem !important; + } + .m-xxl-auto { + margin: auto !important; + } + .mx-xxl-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-xxl-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-xxl-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-xxl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-xxl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-xxl-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-xxl-6 { + margin-right: 4.5rem !important; + margin-left: 4.5rem !important; + } + .mx-xxl-7 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-xxl-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-xxl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xxl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xxl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xxl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xxl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xxl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-xxl-6 { + margin-top: 4.5rem !important; + margin-bottom: 4.5rem !important; + } + .my-xxl-7 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-xxl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xxl-0 { + margin-top: 0 !important; + } + .mt-xxl-1 { + margin-top: 0.25rem !important; + } + .mt-xxl-2 { + margin-top: 0.5rem !important; + } + .mt-xxl-3 { + margin-top: 1rem !important; + } + .mt-xxl-4 { + margin-top: 1.5rem !important; + } + .mt-xxl-5 { + margin-top: 3rem !important; + } + .mt-xxl-6 { + margin-top: 4.5rem !important; + } + .mt-xxl-7 { + margin-top: 6rem !important; + } + .mt-xxl-auto { + margin-top: auto !important; + } + .me-xxl-0 { + margin-right: 0 !important; + } + .me-xxl-1 { + margin-right: 0.25rem !important; + } + .me-xxl-2 { + margin-right: 0.5rem !important; + } + .me-xxl-3 { + margin-right: 1rem !important; + } + .me-xxl-4 { + margin-right: 1.5rem !important; + } + .me-xxl-5 { + margin-right: 3rem !important; + } + .me-xxl-6 { + margin-right: 4.5rem !important; + } + .me-xxl-7 { + margin-right: 6rem !important; + } + .me-xxl-auto { + margin-right: auto !important; + } + .mb-xxl-0 { + margin-bottom: 0 !important; + } + .mb-xxl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xxl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xxl-3 { + margin-bottom: 1rem !important; + } + .mb-xxl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xxl-5 { + margin-bottom: 3rem !important; + } + .mb-xxl-6 { + margin-bottom: 4.5rem !important; + } + .mb-xxl-7 { + margin-bottom: 6rem !important; + } + .mb-xxl-auto { + margin-bottom: auto !important; + } + .ms-xxl-0 { + margin-left: 0 !important; + } + .ms-xxl-1 { + margin-left: 0.25rem !important; + } + .ms-xxl-2 { + margin-left: 0.5rem !important; + } + .ms-xxl-3 { + margin-left: 1rem !important; + } + .ms-xxl-4 { + margin-left: 1.5rem !important; + } + .ms-xxl-5 { + margin-left: 3rem !important; + } + .ms-xxl-6 { + margin-left: 4.5rem !important; + } + .ms-xxl-7 { + margin-left: 6rem !important; + } + .ms-xxl-auto { + margin-left: auto !important; + } + .m-xxl-n1 { + margin: -0.25rem !important; + } + .m-xxl-n2 { + margin: -0.5rem !important; + } + .m-xxl-n3 { + margin: -1rem !important; + } + .m-xxl-n4 { + margin: -1.5rem !important; + } + .m-xxl-n5 { + margin: -3rem !important; + } + .m-xxl-n6 { + margin: -4.5rem !important; + } + .m-xxl-n7 { + margin: -6rem !important; + } + .mx-xxl-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-xxl-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-xxl-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-xxl-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-xxl-n5 { + margin-right: -3rem !important; + margin-left: -3rem !important; + } + .mx-xxl-n6 { + margin-right: -4.5rem !important; + margin-left: -4.5rem !important; + } + .mx-xxl-n7 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .my-xxl-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-xxl-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-xxl-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-xxl-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-xxl-n5 { + margin-top: -3rem !important; + margin-bottom: -3rem !important; + } + .my-xxl-n6 { + margin-top: -4.5rem !important; + margin-bottom: -4.5rem !important; + } + .my-xxl-n7 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .mt-xxl-n1 { + margin-top: -0.25rem !important; + } + .mt-xxl-n2 { + margin-top: -0.5rem !important; + } + .mt-xxl-n3 { + margin-top: -1rem !important; + } + .mt-xxl-n4 { + margin-top: -1.5rem !important; + } + .mt-xxl-n5 { + margin-top: -3rem !important; + } + .mt-xxl-n6 { + margin-top: -4.5rem !important; + } + .mt-xxl-n7 { + margin-top: -6rem !important; + } + .me-xxl-n1 { + margin-right: -0.25rem !important; + } + .me-xxl-n2 { + margin-right: -0.5rem !important; + } + .me-xxl-n3 { + margin-right: -1rem !important; + } + .me-xxl-n4 { + margin-right: -1.5rem !important; + } + .me-xxl-n5 { + margin-right: -3rem !important; + } + .me-xxl-n6 { + margin-right: -4.5rem !important; + } + .me-xxl-n7 { + margin-right: -6rem !important; + } + .mb-xxl-n1 { + margin-bottom: -0.25rem !important; + } + .mb-xxl-n2 { + margin-bottom: -0.5rem !important; + } + .mb-xxl-n3 { + margin-bottom: -1rem !important; + } + .mb-xxl-n4 { + margin-bottom: -1.5rem !important; + } + .mb-xxl-n5 { + margin-bottom: -3rem !important; + } + .mb-xxl-n6 { + margin-bottom: -4.5rem !important; + } + .mb-xxl-n7 { + margin-bottom: -6rem !important; + } + .ms-xxl-n1 { + margin-left: -0.25rem !important; + } + .ms-xxl-n2 { + margin-left: -0.5rem !important; + } + .ms-xxl-n3 { + margin-left: -1rem !important; + } + .ms-xxl-n4 { + margin-left: -1.5rem !important; + } + .ms-xxl-n5 { + margin-left: -3rem !important; + } + .ms-xxl-n6 { + margin-left: -4.5rem !important; + } + .ms-xxl-n7 { + margin-left: -6rem !important; + } + .p-xxl-0 { + padding: 0 !important; + } + .p-xxl-1 { + padding: 0.25rem !important; + } + .p-xxl-2 { + padding: 0.5rem !important; + } + .p-xxl-3 { + padding: 1rem !important; + } + .p-xxl-4 { + padding: 1.5rem !important; + } + .p-xxl-5 { + padding: 3rem !important; + } + .p-xxl-6 { + padding: 4.5rem !important; + } + .p-xxl-7 { + padding: 6rem !important; + } + .px-xxl-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-xxl-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-xxl-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-xxl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-xxl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-xxl-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .px-xxl-6 { + padding-right: 4.5rem !important; + padding-left: 4.5rem !important; + } + .px-xxl-7 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .py-xxl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xxl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xxl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xxl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xxl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xxl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .py-xxl-6 { + padding-top: 4.5rem !important; + padding-bottom: 4.5rem !important; + } + .py-xxl-7 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .pt-xxl-0 { + padding-top: 0 !important; + } + .pt-xxl-1 { + padding-top: 0.25rem !important; + } + .pt-xxl-2 { + padding-top: 0.5rem !important; + } + .pt-xxl-3 { + padding-top: 1rem !important; + } + .pt-xxl-4 { + padding-top: 1.5rem !important; + } + .pt-xxl-5 { + padding-top: 3rem !important; + } + .pt-xxl-6 { + padding-top: 4.5rem !important; + } + .pt-xxl-7 { + padding-top: 6rem !important; + } + .pe-xxl-0 { + padding-right: 0 !important; + } + .pe-xxl-1 { + padding-right: 0.25rem !important; + } + .pe-xxl-2 { + padding-right: 0.5rem !important; + } + .pe-xxl-3 { + padding-right: 1rem !important; + } + .pe-xxl-4 { + padding-right: 1.5rem !important; + } + .pe-xxl-5 { + padding-right: 3rem !important; + } + .pe-xxl-6 { + padding-right: 4.5rem !important; + } + .pe-xxl-7 { + padding-right: 6rem !important; + } + .pb-xxl-0 { + padding-bottom: 0 !important; + } + .pb-xxl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xxl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xxl-3 { + padding-bottom: 1rem !important; + } + .pb-xxl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xxl-5 { + padding-bottom: 3rem !important; + } + .pb-xxl-6 { + padding-bottom: 4.5rem !important; + } + .pb-xxl-7 { + padding-bottom: 6rem !important; + } + .ps-xxl-0 { + padding-left: 0 !important; + } + .ps-xxl-1 { + padding-left: 0.25rem !important; + } + .ps-xxl-2 { + padding-left: 0.5rem !important; + } + .ps-xxl-3 { + padding-left: 1rem !important; + } + .ps-xxl-4 { + padding-left: 1.5rem !important; + } + .ps-xxl-5 { + padding-left: 3rem !important; + } + .ps-xxl-6 { + padding-left: 4.5rem !important; + } + .ps-xxl-7 { + padding-left: 6rem !important; + } + .text-xxl-start { + text-align: left !important; + } + .text-xxl-end { + text-align: right !important; + } + .text-xxl-center { + text-align: center !important; + } +} + +@media print { + .d-print-inline { + display: inline !important; + } + .d-print-inline-block { + display: inline-block !important; + } + .d-print-block { + display: block !important; + } + .d-print-grid { + display: grid !important; + } + .d-print-table { + display: table !important; + } + .d-print-table-row { + display: table-row !important; + } + .d-print-table-cell { + display: table-cell !important; + } + .d-print-flex { + display: flex !important; + } + .d-print-inline-flex { + display: inline-flex !important; + } + .d-print-none { + display: none !important; + } +} + +.accordion .card:not(:last-child) { + margin-bottom: 0; +} + +.accordion .card-header { + border-bottom: 0; +} + +.accordion .card-body { + border-top: 1px solid transparent; +} + +.accordion .card-title a { + color: #495057; +} + +.alert { + padding: 0; + display: flex; +} + +.alert-outline { + color: #495057; + background: #fff; +} + +.alert-outline hr { + border-top-color: #ced4da; +} + +.alert-outline .alert-message { + border-top-right-radius: 0.2rem; + border-bottom-right-radius: 0.2rem; + border-top-left-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; + border: 1px solid #ced4da; +} + +.alert-outline .alert-message:not(:nth-child(2)) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-left: 0; +} + +.alert-outline .alert-icon { + border-top-left-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; + color: #fff; +} + +.alert-outline.alert-primary .alert-icon { + background-color: #3B7DDD; +} + +.alert-outline.alert-secondary .alert-icon { + background-color: #6c757d; +} + +.alert-outline.alert-success .alert-icon { + background-color: #28a745; +} + +.alert-outline.alert-info .alert-icon { + background-color: #17a2b8; +} + +.alert-outline.alert-warning .alert-icon { + background-color: #ffc107; +} + +.alert-outline.alert-danger .alert-icon { + background-color: #dc3545; +} + +.alert-outline.alert-light .alert-icon { + background-color: #f8f9fa; +} + +.alert-outline.alert-dark .alert-icon { + background-color: #212529; +} + +.alert-message { + padding: 0.95rem 0.95rem; + width: 100%; + box-sizing: border-box; +} + +.avatar { + width: 40px; + height: 40px; +} + +.avatar-title { + display: flex; + width: 100%; + height: 100%; + align-items: center; + justify-content: center; + color: #3B7DDD; +} + +.btn .feather { + width: 14px; + height: 14px; +} + +.btn-primary, .btn-primary:focus, .btn-primary.focus, .btn-primary.disabled, .btn-primary:disabled, +.show > .btn-primary.dropdown-toggle { + color: #fff; +} + +.btn-primary:hover:not(:disabled):not(.disabled), .btn-primary.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-secondary, .btn-secondary:focus, .btn-secondary.focus, .btn-secondary.disabled, .btn-secondary:disabled, +.show > .btn-secondary.dropdown-toggle { + color: #fff; +} + +.btn-secondary:hover:not(:disabled):not(.disabled), .btn-secondary.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-success, .btn-success:focus, .btn-success.focus, .btn-success.disabled, .btn-success:disabled, +.show > .btn-success.dropdown-toggle { + color: #fff; +} + +.btn-success:hover:not(:disabled):not(.disabled), .btn-success.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-info, .btn-info:focus, .btn-info.focus, .btn-info.disabled, .btn-info:disabled, +.show > .btn-info.dropdown-toggle { + color: #fff; +} + +.btn-info:hover:not(:disabled):not(.disabled), .btn-info.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-warning, .btn-warning:focus, .btn-warning.focus, .btn-warning.disabled, .btn-warning:disabled, +.show > .btn-warning.dropdown-toggle { + color: #fff; +} + +.btn-warning:hover:not(:disabled):not(.disabled), .btn-warning.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-danger, .btn-danger:focus, .btn-danger.focus, .btn-danger.disabled, .btn-danger:disabled, +.show > .btn-danger.dropdown-toggle { + color: #fff; +} + +.btn-danger:hover:not(:disabled):not(.disabled), .btn-danger.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-light, .btn-light:focus, .btn-light.focus, .btn-light.disabled, .btn-light:disabled, +.show > .btn-light.dropdown-toggle { + color: #fff; +} + +.btn-light:hover:not(:disabled):not(.disabled), .btn-light.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-dark, .btn-dark:focus, .btn-dark.focus, .btn-dark.disabled, .btn-dark:disabled, +.show > .btn-dark.dropdown-toggle { + color: #fff; +} + +.btn-dark:hover:not(:disabled):not(.disabled), .btn-dark.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-facebook { + color: #fff; + background-color: #3b5998; + border-color: #3b5998; +} + +.btn-facebook:hover { + color: #fff; + background-color: #324c81; + border-color: #2f477a; +} + +.btn-check:focus + .btn-facebook, .btn-facebook:focus { + color: #fff; + background-color: #324c81; + border-color: #2f477a; + box-shadow: 0 0 0 0.2rem rgba(88, 114, 167, 0.5); +} + +.btn-check:checked + .btn-facebook, +.btn-check:active + .btn-facebook, .btn-facebook:active, .btn-facebook.active, +.show > .btn-facebook.dropdown-toggle { + color: #fff; + background-color: #2f477a; + border-color: #2c4372; +} + +.btn-check:checked + .btn-facebook:focus, +.btn-check:active + .btn-facebook:focus, .btn-facebook:active:focus, .btn-facebook.active:focus, +.show > .btn-facebook.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(88, 114, 167, 0.5); +} + +.btn-facebook:disabled, .btn-facebook.disabled { + color: #fff; + background-color: #3b5998; + border-color: #3b5998; +} + +.btn-facebook, .btn-facebook:focus, .btn-facebook.focus, .btn-facebook.disabled, .btn-facebook:disabled, +.show > .btn-facebook.dropdown-toggle { + color: #fff; +} + +.btn-facebook:hover:not(:disabled):not(.disabled), .btn-facebook.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-twitter { + color: #000; + background-color: #1da1f2; + border-color: #1da1f2; +} + +.btn-twitter:hover { + color: #000; + background-color: #3faff4; + border-color: #34aaf3; +} + +.btn-check:focus + .btn-twitter, .btn-twitter:focus { + color: #000; + background-color: #3faff4; + border-color: #34aaf3; + box-shadow: 0 0 0 0.2rem rgba(25, 137, 206, 0.5); +} + +.btn-check:checked + .btn-twitter, +.btn-check:active + .btn-twitter, .btn-twitter:active, .btn-twitter.active, +.show > .btn-twitter.dropdown-toggle { + color: #000; + background-color: #4ab4f5; + border-color: #34aaf3; +} + +.btn-check:checked + .btn-twitter:focus, +.btn-check:active + .btn-twitter:focus, .btn-twitter:active:focus, .btn-twitter.active:focus, +.show > .btn-twitter.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(25, 137, 206, 0.5); +} + +.btn-twitter:disabled, .btn-twitter.disabled { + color: #000; + background-color: #1da1f2; + border-color: #1da1f2; +} + +.btn-twitter, .btn-twitter:focus, .btn-twitter.focus, .btn-twitter.disabled, .btn-twitter:disabled, +.show > .btn-twitter.dropdown-toggle { + color: #fff; +} + +.btn-twitter:hover:not(:disabled):not(.disabled), .btn-twitter.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-google { + color: #000; + background-color: #dc4e41; + border-color: #dc4e41; +} + +.btn-google:hover { + color: #000; + background-color: #e1695e; + border-color: #e06054; +} + +.btn-check:focus + .btn-google, .btn-google:focus { + color: #000; + background-color: #e1695e; + border-color: #e06054; + box-shadow: 0 0 0 0.2rem rgba(187, 66, 55, 0.5); +} + +.btn-check:checked + .btn-google, +.btn-check:active + .btn-google, .btn-google:active, .btn-google.active, +.show > .btn-google.dropdown-toggle { + color: #000; + background-color: #e37167; + border-color: #e06054; +} + +.btn-check:checked + .btn-google:focus, +.btn-check:active + .btn-google:focus, .btn-google:active:focus, .btn-google.active:focus, +.show > .btn-google.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(187, 66, 55, 0.5); +} + +.btn-google:disabled, .btn-google.disabled { + color: #000; + background-color: #dc4e41; + border-color: #dc4e41; +} + +.btn-google, .btn-google:focus, .btn-google.focus, .btn-google.disabled, .btn-google:disabled, +.show > .btn-google.dropdown-toggle { + color: #fff; +} + +.btn-google:hover:not(:disabled):not(.disabled), .btn-google.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-youtube { + color: #000; + background-color: #f00; + border-color: #f00; +} + +.btn-youtube:hover { + color: #000; + background-color: #ff2626; + border-color: #ff1a1a; +} + +.btn-check:focus + .btn-youtube, .btn-youtube:focus { + color: #000; + background-color: #ff2626; + border-color: #ff1a1a; + box-shadow: 0 0 0 0.2rem rgba(217, 0, 0, 0.5); +} + +.btn-check:checked + .btn-youtube, +.btn-check:active + .btn-youtube, .btn-youtube:active, .btn-youtube.active, +.show > .btn-youtube.dropdown-toggle { + color: #000; + background-color: #ff3333; + border-color: #ff1a1a; +} + +.btn-check:checked + .btn-youtube:focus, +.btn-check:active + .btn-youtube:focus, .btn-youtube:active:focus, .btn-youtube.active:focus, +.show > .btn-youtube.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(217, 0, 0, 0.5); +} + +.btn-youtube:disabled, .btn-youtube.disabled { + color: #000; + background-color: #f00; + border-color: #f00; +} + +.btn-youtube, .btn-youtube:focus, .btn-youtube.focus, .btn-youtube.disabled, .btn-youtube:disabled, +.show > .btn-youtube.dropdown-toggle { + color: #fff; +} + +.btn-youtube:hover:not(:disabled):not(.disabled), .btn-youtube.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-vimeo { + color: #000; + background-color: #1ab7ea; + border-color: #1ab7ea; +} + +.btn-vimeo:hover { + color: #000; + background-color: #3cc2ed; + border-color: #31beec; +} + +.btn-check:focus + .btn-vimeo, .btn-vimeo:focus { + color: #000; + background-color: #3cc2ed; + border-color: #31beec; + box-shadow: 0 0 0 0.2rem rgba(22, 156, 199, 0.5); +} + +.btn-check:checked + .btn-vimeo, +.btn-check:active + .btn-vimeo, .btn-vimeo:active, .btn-vimeo.active, +.show > .btn-vimeo.dropdown-toggle { + color: #000; + background-color: #48c5ee; + border-color: #31beec; +} + +.btn-check:checked + .btn-vimeo:focus, +.btn-check:active + .btn-vimeo:focus, .btn-vimeo:active:focus, .btn-vimeo.active:focus, +.show > .btn-vimeo.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(22, 156, 199, 0.5); +} + +.btn-vimeo:disabled, .btn-vimeo.disabled { + color: #000; + background-color: #1ab7ea; + border-color: #1ab7ea; +} + +.btn-vimeo, .btn-vimeo:focus, .btn-vimeo.focus, .btn-vimeo.disabled, .btn-vimeo:disabled, +.show > .btn-vimeo.dropdown-toggle { + color: #fff; +} + +.btn-vimeo:hover:not(:disabled):not(.disabled), .btn-vimeo.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-dribbble { + color: #000; + background-color: #ea4c89; + border-color: #ea4c89; +} + +.btn-dribbble:hover { + color: #000; + background-color: #ed679b; + border-color: #ec5e95; +} + +.btn-check:focus + .btn-dribbble, .btn-dribbble:focus { + color: #000; + background-color: #ed679b; + border-color: #ec5e95; + box-shadow: 0 0 0 0.2rem rgba(199, 65, 116, 0.5); +} + +.btn-check:checked + .btn-dribbble, +.btn-check:active + .btn-dribbble, .btn-dribbble:active, .btn-dribbble.active, +.show > .btn-dribbble.dropdown-toggle { + color: #000; + background-color: #ee70a1; + border-color: #ec5e95; +} + +.btn-check:checked + .btn-dribbble:focus, +.btn-check:active + .btn-dribbble:focus, .btn-dribbble:active:focus, .btn-dribbble.active:focus, +.show > .btn-dribbble.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(199, 65, 116, 0.5); +} + +.btn-dribbble:disabled, .btn-dribbble.disabled { + color: #000; + background-color: #ea4c89; + border-color: #ea4c89; +} + +.btn-dribbble, .btn-dribbble:focus, .btn-dribbble.focus, .btn-dribbble.disabled, .btn-dribbble:disabled, +.show > .btn-dribbble.dropdown-toggle { + color: #fff; +} + +.btn-dribbble:hover:not(:disabled):not(.disabled), .btn-dribbble.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-github { + color: #fff; + background-color: #181717; + border-color: #181717; +} + +.btn-github:hover { + color: #fff; + background-color: #141414; + border-color: #131212; +} + +.btn-check:focus + .btn-github, .btn-github:focus { + color: #fff; + background-color: #141414; + border-color: #131212; + box-shadow: 0 0 0 0.2rem rgba(59, 58, 58, 0.5); +} + +.btn-check:checked + .btn-github, +.btn-check:active + .btn-github, .btn-github:active, .btn-github.active, +.show > .btn-github.dropdown-toggle { + color: #fff; + background-color: #131212; + border-color: #121111; +} + +.btn-check:checked + .btn-github:focus, +.btn-check:active + .btn-github:focus, .btn-github:active:focus, .btn-github.active:focus, +.show > .btn-github.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(59, 58, 58, 0.5); +} + +.btn-github:disabled, .btn-github.disabled { + color: #fff; + background-color: #181717; + border-color: #181717; +} + +.btn-github, .btn-github:focus, .btn-github.focus, .btn-github.disabled, .btn-github:disabled, +.show > .btn-github.dropdown-toggle { + color: #fff; +} + +.btn-github:hover:not(:disabled):not(.disabled), .btn-github.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-instagram { + color: #000; + background-color: #e4405f; + border-color: #e4405f; +} + +.btn-instagram:hover { + color: #000; + background-color: #e85d77; + border-color: #e7536f; +} + +.btn-check:focus + .btn-instagram, .btn-instagram:focus { + color: #000; + background-color: #e85d77; + border-color: #e7536f; + box-shadow: 0 0 0 0.2rem rgba(194, 54, 81, 0.5); +} + +.btn-check:checked + .btn-instagram, +.btn-check:active + .btn-instagram, .btn-instagram:active, .btn-instagram.active, +.show > .btn-instagram.dropdown-toggle { + color: #000; + background-color: #e9667f; + border-color: #e7536f; +} + +.btn-check:checked + .btn-instagram:focus, +.btn-check:active + .btn-instagram:focus, .btn-instagram:active:focus, .btn-instagram.active:focus, +.show > .btn-instagram.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(194, 54, 81, 0.5); +} + +.btn-instagram:disabled, .btn-instagram.disabled { + color: #000; + background-color: #e4405f; + border-color: #e4405f; +} + +.btn-instagram, .btn-instagram:focus, .btn-instagram.focus, .btn-instagram.disabled, .btn-instagram:disabled, +.show > .btn-instagram.dropdown-toggle { + color: #fff; +} + +.btn-instagram:hover:not(:disabled):not(.disabled), .btn-instagram.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-pinterest { + color: #fff; + background-color: #bd081c; + border-color: #bd081c; +} + +.btn-pinterest:hover { + color: #fff; + background-color: #a10718; + border-color: #970616; +} + +.btn-check:focus + .btn-pinterest, .btn-pinterest:focus { + color: #fff; + background-color: #a10718; + border-color: #970616; + box-shadow: 0 0 0 0.2rem rgba(199, 45, 62, 0.5); +} + +.btn-check:checked + .btn-pinterest, +.btn-check:active + .btn-pinterest, .btn-pinterest:active, .btn-pinterest.active, +.show > .btn-pinterest.dropdown-toggle { + color: #fff; + background-color: #970616; + border-color: #8e0615; +} + +.btn-check:checked + .btn-pinterest:focus, +.btn-check:active + .btn-pinterest:focus, .btn-pinterest:active:focus, .btn-pinterest.active:focus, +.show > .btn-pinterest.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(199, 45, 62, 0.5); +} + +.btn-pinterest:disabled, .btn-pinterest.disabled { + color: #fff; + background-color: #bd081c; + border-color: #bd081c; +} + +.btn-pinterest, .btn-pinterest:focus, .btn-pinterest.focus, .btn-pinterest.disabled, .btn-pinterest:disabled, +.show > .btn-pinterest.dropdown-toggle { + color: #fff; +} + +.btn-pinterest:hover:not(:disabled):not(.disabled), .btn-pinterest.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-flickr { + color: #fff; + background-color: #0063dc; + border-color: #0063dc; +} + +.btn-flickr:hover { + color: #fff; + background-color: #0054bb; + border-color: #004fb0; +} + +.btn-check:focus + .btn-flickr, .btn-flickr:focus { + color: #fff; + background-color: #0054bb; + border-color: #004fb0; + box-shadow: 0 0 0 0.2rem rgba(38, 122, 225, 0.5); +} + +.btn-check:checked + .btn-flickr, +.btn-check:active + .btn-flickr, .btn-flickr:active, .btn-flickr.active, +.show > .btn-flickr.dropdown-toggle { + color: #fff; + background-color: #004fb0; + border-color: #004aa5; +} + +.btn-check:checked + .btn-flickr:focus, +.btn-check:active + .btn-flickr:focus, .btn-flickr:active:focus, .btn-flickr.active:focus, +.show > .btn-flickr.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(38, 122, 225, 0.5); +} + +.btn-flickr:disabled, .btn-flickr.disabled { + color: #fff; + background-color: #0063dc; + border-color: #0063dc; +} + +.btn-flickr, .btn-flickr:focus, .btn-flickr.focus, .btn-flickr.disabled, .btn-flickr:disabled, +.show > .btn-flickr.dropdown-toggle { + color: #fff; +} + +.btn-flickr:hover:not(:disabled):not(.disabled), .btn-flickr.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-bitbucket { + color: #fff; + background-color: #0052cc; + border-color: #0052cc; +} + +.btn-bitbucket:hover { + color: #fff; + background-color: #0046ad; + border-color: #0042a3; +} + +.btn-check:focus + .btn-bitbucket, .btn-bitbucket:focus { + color: #fff; + background-color: #0046ad; + border-color: #0042a3; + box-shadow: 0 0 0 0.2rem rgba(38, 108, 212, 0.5); +} + +.btn-check:checked + .btn-bitbucket, +.btn-check:active + .btn-bitbucket, .btn-bitbucket:active, .btn-bitbucket.active, +.show > .btn-bitbucket.dropdown-toggle { + color: #fff; + background-color: #0042a3; + border-color: #003e99; +} + +.btn-check:checked + .btn-bitbucket:focus, +.btn-check:active + .btn-bitbucket:focus, .btn-bitbucket:active:focus, .btn-bitbucket.active:focus, +.show > .btn-bitbucket.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(38, 108, 212, 0.5); +} + +.btn-bitbucket:disabled, .btn-bitbucket.disabled { + color: #fff; + background-color: #0052cc; + border-color: #0052cc; +} + +.btn-bitbucket, .btn-bitbucket:focus, .btn-bitbucket.focus, .btn-bitbucket.disabled, .btn-bitbucket:disabled, +.show > .btn-bitbucket.dropdown-toggle { + color: #fff; +} + +.btn-bitbucket:hover:not(:disabled):not(.disabled), .btn-bitbucket.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-light, .btn-light:focus, .btn-light.focus, .btn-light.disabled, .btn-light:disabled, +.show > .btn-light.dropdown-toggle, +.btn-white, +.btn-white:focus, +.btn-white.focus, +.btn-white.disabled, +.btn-white:disabled, +.show > +.btn-white.dropdown-toggle { + color: #343a40; +} + +.btn-light:hover:not(:disabled):not(.disabled), .btn-light.hover:not(:disabled):not(.disabled), +.btn-white:hover:not(:disabled):not(.disabled), +.btn-white.hover:not(:disabled):not(.disabled) { + color: #343a40; +} + +.card { + margin-bottom: 24px; + box-shadow: 0 0 0.875rem 0 rgba(33, 37, 41, 0.05); +} + +.card-header { + border-bottom-width: 1px; +} + +.card-actions a { + color: #495057; + text-decoration: none; +} + +.card-actions svg { + width: 16px; + height: 16px; +} + +.card-actions .dropdown { + line-height: 1.4; +} + +.card-title { + font-size: 0.875rem; + font-weight: 400; + color: #495057; +} + +.card-subtitle { + font-weight: 400; +} + +.card-table { + margin-bottom: 0; +} + +.card-table tr td:first-child, +.card-table tr th:first-child { + padding-left: 1.25rem; +} + +.card-table tr td:last-child, +.card-table tr th:last-child { + padding-right: 1.25rem; +} + +.card-img, +.card-img-top, +.card-img-bottom { + max-width: 100%; + height: auto; +} + +@media all and (-ms-high-contrast: none) { + .card-img, + .card-img-top, + .card-img-bottom { + height: 100%; + } +} + +.chart { + margin: auto; + position: relative; + width: 100%; + min-height: 300px; +} + +.chart-xs { + min-height: 200px; +} + +.chart-sm { + min-height: 252px; +} + +.chart-lg { + min-height: 350px; +} + +.chart-xl { + min-height: 500px; +} + +.chart canvas { + max-width: 100%; +} + +.content { + padding: 1.5rem 1.5rem 0.75rem; + flex: 1; + width: 100vw; + max-width: 100vw; + direction: ltr; +} + +@media (min-width: 768px) { + .content { + width: auto; + max-width: auto; + } +} + +@media (min-width: 992px) { + .content { + padding: 2.5rem 2.5rem 1rem; + } +} + +.navbar-nav .dropdown-menu { + box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.05); +} + +.dropdown .dropdown-menu.show { + animation-name: dropdownAnimation; + animation-duration: .25s; + animation-iteration-count: 1; + animation-timing-function: ease; + animation-fill-mode: forwards; +} + +@keyframes dropdownAnimation { + from { + opacity: 0; + transform: translateY(-8px); + } + to { + opacity: 1; + transform: translate(0); + } +} + +.dropdown-toggle:after { + border: solid; + border-width: 0 2px 2px 0; + display: inline-block; + padding: 2px; + transform: rotate(45deg); +} + +.dropdown-item { + transition: background 0.1s ease-in-out, color 0.1s ease-in-out; +} + +.dropdown-menu { + top: auto; +} + +.dropdown-menu-lg { + min-width: 20rem; +} + +.dropdown .list-group .list-group-item { + border-width: 0; + border-bottom-width: 1px; + margin-bottom: 0; +} + +.dropdown .list-group .list-group-item:first-child, .dropdown .list-group .list-group-item:last-child { + border-radius: 0; +} + +.dropdown .list-group .list-group-item:hover { + background: #f8f9fa; +} + +.dropdown-menu-header { + padding: 0.75rem; + text-align: center; + font-weight: 600; + border-bottom: 1px solid #dee2e6; +} + +.dropdown-menu-footer { + padding: 0.5rem; + text-align: center; + display: block; + font-size: 0.75rem; +} + +.feather { + width: 18px; + height: 18px; + stroke-width: 1.5; +} + +.feather-sm { + width: 14px; + height: 14px; +} + +.feather-lg { + width: 36px; + height: 36px; +} + +footer.footer { + padding: 1rem 0.875rem; + direction: ltr; + background: #fff; +} + +footer.footer ul { + margin-bottom: 0; +} + +@media (max-width: 767.98px) { + footer.footer { + width: 100vw; + } +} + +.input-group-navbar .form-control, +.input-group-navbar .btn { + height: calc(2.0875rem + 2px); + background: #F7F7FC; + box-shadow: none; + border: 0; + padding: 0.35rem 0.75rem; +} + +.input-group-navbar .form-control:focus, +.input-group-navbar .btn:focus { + background: #F7F7FC; + box-shadow: none; + outline: 0; +} + +.input-group-navbar .btn { + color: #6c757d; +} + +.input-group-navbar .btn .feather { + width: 20px; + height: 20px; +} + +.hamburger, +.hamburger:before, +.hamburger:after { + cursor: pointer; + border-radius: 1px; + height: 3px; + width: 24px; + background: #495057; + display: block; + content: ''; + transition: background 0.1s ease-in-out, color 0.1s ease-in-out; +} + +.hamburger { + position: relative; +} + +.hamburger:before { + top: -7.5px; + width: 24px; + position: absolute; +} + +.hamburger:after { + bottom: -7.5px; + width: 16px; + position: absolute; +} + +.sidebar-toggle:hover .hamburger, +.sidebar-toggle:hover .hamburger:before, +.sidebar-toggle:hover .hamburger:after { + background: #3B7DDD; +} + +.hamburger-right, .hamburger-right:before, .hamburger-right:after { + right: 0; +} + +a.list-group-item { + text-decoration: none; +} + +.main { + display: flex; + width: 100%; + min-width: 0; + min-height: 100vh; + transition: margin-left 0.35s ease-in-out, left 0.35s ease-in-out, margin-right 0.35s ease-in-out, right 0.35s ease-in-out; + background: #F7F7FC; + flex-direction: column; + overflow: hidden; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +@media (min-width: 992px) { + .main { + box-shadow: inset 0.75rem 0px 1.5rem 0px rgba(0, 0, 0, 0.075); + } +} + +.navbar { + border-bottom: 0; + box-shadow: 0 0 2rem 0 rgba(33, 37, 41, 0.1); +} + +@media (max-width: 767.98px) { + .navbar { + width: 100vw; + } +} + +.navbar .avatar { + margin-top: -15px; + margin-bottom: -15px; +} + +.navbar-nav { + direction: ltr; +} + +.navbar-align { + margin-left: auto; +} + +.navbar-bg { + background: #fff; +} + +.navbar-brand { + font-weight: 400; + font-size: 1.15rem; + padding: 0.875rem 0; + color: #f8f9fa; + display: block; +} + +.navbar-brand svg, +.navbar-brand .feather { + color: #3B7DDD; + height: 24px; + width: 24px; + margin-left: -0.15rem; + margin-right: 0.375rem; + margin-top: -0.375rem; +} + +.nav-icon, +.nav-flag { + padding: .1rem .8rem; + display: block; + font-size: 1.5rem; + color: #6c757d; + transition: background 0.1s ease-in-out, color 0.1s ease-in-out; + line-height: 1.4; +} + +.nav-icon:after, +.nav-flag:after { + display: none !important; +} + +.nav-icon:hover, .nav-icon.active, +.nav-flag:hover, +.nav-flag.active { + color: #3B7DDD; +} + +.nav-icon svg, +.nav-icon .feather, +.nav-flag svg, +.nav-flag .feather { + width: 20px; + height: 20px; +} + +.nav-item .indicator { + background: #3B7DDD; + box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.05); + border-radius: 50%; + display: block; + height: 18px; + width: 18px; + padding: 1px; + position: absolute; + top: 0; + right: -8px; + text-align: center; + transition: top .1s ease-out; + font-size: 0.675rem; + color: #fff; +} + +.nav-item:hover .indicator { + top: -4px; +} + +.nav-item a:focus { + outline: 0; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .navbar .avatar { + max-height: 47px; + } +} + +@media (max-width: 575.98px) { + .navbar { + padding: 0.75rem; + } + .nav-icon { + padding: .1rem .75rem; + } + .dropdown, + .dropleft, + .dropright, + .dropup { + position: inherit; + } + .navbar-expand .navbar-nav .dropdown-menu-lg { + min-width: 100%; + } + .nav-item .nav-link:after { + display: none; + } +} + +.nav-flag img { + border-radius: 50%; + width: 20px; + height: 20px; + object-fit: cover; +} + +.navbar input { + direction: ltr; +} + +body, html, #root { + height: 100%; +} + +body { + overflow-y: scroll; + opacity: 1 !important; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + html { + overflow-x: hidden; + } +} + +.sidebar { + min-width: 260px; + max-width: 260px; + transition: margin-left 0.35s ease-in-out, left 0.35s ease-in-out, margin-right 0.35s ease-in-out, right 0.35s ease-in-out; + direction: ltr; + background: #222E3C; +} + +.sidebar-content { + transition: margin-left 0.35s ease-in-out, left 0.35s ease-in-out, margin-right 0.35s ease-in-out, right 0.35s ease-in-out; + display: flex; + height: 100vh; + flex-direction: column; + background: #222E3C; +} + +.sidebar-nav { + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.sidebar-link, +a.sidebar-link { + display: block; + padding: 0.625rem 1.625rem; + font-weight: 400; + transition: background .1s ease-in-out; + position: relative; + text-decoration: none; + cursor: pointer; + border-left-style: solid; + border-left-width: 3px; + color: rgba(233, 236, 239, 0.5); + background: #222E3C; + border-left-color: transparent; +} + +.sidebar-link i, +.sidebar-link svg, +a.sidebar-link i, +a.sidebar-link svg { + margin-right: .75rem; + color: rgba(233, 236, 239, 0.5); +} + +.sidebar-link:focus { + outline: 0; +} + +.sidebar-link:hover { + color: rgba(233, 236, 239, 0.75); + background: #222E3C; + border-left-color: transparent; +} + +.sidebar-link:hover i, +.sidebar-link:hover svg { + color: rgba(233, 236, 239, 0.75); +} + +.sidebar-item.active > .sidebar-link, +.sidebar-item.active .sidebar-link:hover { + color: #e9ecef; + background: linear-gradient(90deg, rgba(59, 125, 221, 0.1) 0%, rgba(59, 125, 221, 0.0875) 50%, rgba(0, 0, 0, 0) 100%); + border-left-color: #3B7DDD; +} + +.sidebar-item.active > .sidebar-link i, +.sidebar-item.active > .sidebar-link svg, +.sidebar-item.active .sidebar-link:hover i, +.sidebar-item.active .sidebar-link:hover svg { + color: #e9ecef; +} + +.sidebar-dropdown .sidebar-link { + padding: 0.625rem 1.5rem 0.625rem 3.25rem; + font-weight: 400; + font-size: 90%; + border-left: 0; + color: #adb5bd; + background: transparent; +} + +.sidebar-dropdown .sidebar-link:before { + content: "→"; + display: inline-block; + position: relative; + left: -14px; + transition: all .1s ease; + transform: translateX(0); +} + +.sidebar-dropdown .sidebar-item .sidebar-link:hover { + font-weight: 400; + border-left: 0; + color: #e9ecef; + background: transparent; +} + +.sidebar-dropdown .sidebar-item .sidebar-link:hover:hover:before { + transform: translateX(4px); +} + +.sidebar-dropdown .sidebar-item.active .sidebar-link { + font-weight: 400; + border-left: 0; + color: #518be1; + background: transparent; +} + +.sidebar [data-bs-toggle="collapse"] { + position: relative; +} + +.sidebar [data-bs-toggle="collapse"]:after { + content: " "; + border: solid; + border-width: 0 .075rem .075rem 0; + display: inline-block; + padding: 2px; + transform: rotate(45deg); + position: absolute; + top: 1.2rem; + right: 1.5rem; + transition: all .2s ease-out; +} + +.sidebar [aria-expanded="true"]:after, +.sidebar [data-bs-toggle="collapse"]:not(.collapsed):after { + transform: rotate(-135deg); + top: 1.4rem; +} + +.sidebar-brand { + font-weight: 600; + font-size: 1.15rem; + padding: 1.15rem 1.5rem; + display: block; + color: #f8f9fa; +} + +.sidebar-brand:hover { + text-decoration: none; + color: #f8f9fa; +} + +.sidebar-brand:focus { + outline: 0; +} + +.sidebar-toggle { + cursor: pointer; + width: 26px; + height: 26px; +} + +.sidebar.collapsed { + margin-left: -260px; +} + +@media (min-width: 1px) and (max-width: 991.98px) { + .sidebar { + margin-left: -260px; + } + .sidebar.collapsed { + margin-left: 0; + } +} + +.sidebar-toggle { + margin-right: 1rem; +} + +.sidebar-header { + background: transparent; + padding: 1.5rem 1.5rem 0.375rem; + font-size: 0.75rem; + color: #ced4da; +} + +.sidebar-badge { + position: absolute; + right: 15px; + top: 14px; + z-index: 1; +} + +.sidebar-cta-content { + padding: 1.5rem; + margin: 1.75rem; + border-radius: 0.3rem; + background: #2B3947; + color: #e9ecef; +} + +.min-vw-50 { + min-width: 50vw !important; +} + +.min-vh-50 { + min-height: 50vh !important; +} + +.vw-50 { + width: 50vw !important; +} + +.vh-50 { + height: 50vh !important; +} + +.table thead, .table tbody, .table tfoot, .table tr, .table td, .table th { + border-color: #dee2e6; +} + +.table > :not(:last-child) > :last-child > * { + border-color: #dee2e6; +} + +.table > tbody > tr > td { + vertical-align: middle; +} + +.text-sm { + font-size: 0.75rem; +} + +.text-lg { + font-size: 0.925rem; +} + +b, +strong { + font-weight: 600; +} + +pre.snippet { + white-space: pre-wrap; + word-wrap: break-word; + text-align: justify; +} + +a { + cursor: pointer; +} + +.wrapper { + align-items: stretch; + display: flex; + width: 100%; + background: #222E3C; +} + +.bg-primary-light { + background: #d3e2f7; +} + +.bg-secondary-light { + background: #caced1; +} + +.bg-success-light { + background: #9be7ac; +} + +.bg-info-light { + background: #90e4f1; +} + +.bg-warning-light { + background: #ffeeba; +} + +.bg-danger-light { + background: #f6cdd1; +} + +.bg-light-light { + background: white; +} + +.bg-dark-light { + background: #717e8c; +} + +.bg-primary-dark { + background: #0f2c56; +} + +.bg-secondary-dark { + background: #191b1d; +} + +.bg-success-dark { + background: #06170a; +} + +.bg-info-dark { + background: #031619; +} + +.bg-warning-dark { + background: #543f00; +} + +.bg-danger-dark { + background: #510e14; +} + +.bg-light-dark { + background: #90a0b0; +} + +.bg-dark-dark { + background: black; +} + +.rounded-lg { + border-radius: 0.3rem !important; +} + +.rounded-top-lg { + border-top-left-radius: 0.3rem !important; + border-top-right-radius: 0.3rem !important; +} + +.rounded-right-lg { + border-top-right-radius: 0.3rem !important; + border-bottom-right-radius: 0.3rem !important; +} + +.rounded-bottom-lg { + border-bottom-right-radius: 0.3rem !important; + border-bottom-left-radius: 0.3rem !important; +} + +.rounded-left-lg { + border-top-left-radius: 0.3rem !important; + border-bottom-left-radius: 0.3rem !important; +} + +.rounded-sm { + border-radius: 0.1rem !important; +} + +.rounded-top-sm { + border-top-left-radius: 0.1rem !important; + border-top-right-radius: 0.1rem !important; +} + +.rounded-right-sm { + border-top-right-radius: 0.1rem !important; + border-bottom-right-radius: 0.1rem !important; +} + +.rounded-bottom-sm { + border-bottom-right-radius: 0.1rem !important; + border-bottom-left-radius: 0.1rem !important; +} + +.rounded-left-sm { + border-top-left-radius: 0.1rem !important; + border-bottom-left-radius: 0.1rem !important; +} + +.cursor-grab { + cursor: move; + cursor: grab; + cursor: -moz-grab; + cursor: -webkit-grab; +} + +.cursor-pointer { + cursor: pointer; +} + +.overflow-scroll { + overflow: scroll; +} + +.overflow-hidden { + overflow: hidden; +} + +.overflow-auto { + overflow: auto; +} + +.overflow-visible { + overflow: visible; +} + +[data-simplebar] { + position: relative; + flex-direction: column; + flex-wrap: wrap; + justify-content: flex-start; + align-content: flex-start; + align-items: flex-start; +} + +.simplebar-wrapper { + overflow: hidden; + width: inherit; + height: inherit; + max-width: inherit; + max-height: inherit; +} + +.simplebar-mask { + direction: inherit; + position: absolute; + overflow: hidden; + padding: 0; + margin: 0; + left: 0; + top: 0; + bottom: 0; + right: 0; + width: auto !important; + height: auto !important; + z-index: 0; +} + +.simplebar-offset { + direction: inherit !important; + box-sizing: inherit !important; + resize: none !important; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + padding: 0; + margin: 0; + -webkit-overflow-scrolling: touch; +} + +.simplebar-content-wrapper { + direction: inherit; + box-sizing: border-box !important; + position: relative; + display: block; + height: 100%; + /* Required for horizontal native scrollbar to not appear if parent is taller than natural height */ + width: auto; + max-width: 100%; + /* Not required for horizontal scroll to trigger */ + max-height: 100%; + /* Needed for vertical scroll to trigger */ + scrollbar-width: none; + -ms-overflow-style: none; +} + +.simplebar-content-wrapper::-webkit-scrollbar, +.simplebar-hide-scrollbar::-webkit-scrollbar { + width: 0; + height: 0; +} + +.simplebar-content:before, +.simplebar-content:after { + content: ' '; + display: table; +} + +.simplebar-placeholder { + max-height: 100%; + max-width: 100%; + width: 100%; + pointer-events: none; +} + +.simplebar-height-auto-observer-wrapper { + box-sizing: inherit !important; + height: 100%; + width: 100%; + max-width: 1px; + position: relative; + float: left; + max-height: 1px; + overflow: hidden; + z-index: -1; + padding: 0; + margin: 0; + pointer-events: none; + flex-grow: inherit; + flex-shrink: 0; + flex-basis: 0; +} + +.simplebar-height-auto-observer { + box-sizing: inherit; + display: block; + opacity: 0; + position: absolute; + top: 0; + left: 0; + height: 1000%; + width: 1000%; + min-height: 1px; + min-width: 1px; + overflow: hidden; + pointer-events: none; + z-index: -1; +} + +.simplebar-track { + z-index: 1; + position: absolute; + right: 0; + bottom: 0; + pointer-events: none; + overflow: hidden; +} + +[data-simplebar].simplebar-dragging .simplebar-content { + pointer-events: none; + user-select: none; + -webkit-user-select: none; +} + +[data-simplebar].simplebar-dragging .simplebar-track { + pointer-events: all; +} + +.simplebar-scrollbar { + position: absolute; + left: 0; + right: 0; + min-height: 10px; +} + +.simplebar-scrollbar:before { + position: absolute; + content: ''; + background: black; + border-radius: 7px; + left: 2px; + right: 2px; + opacity: 0; + transition: opacity 0.2s linear; +} + +.simplebar-scrollbar.simplebar-visible:before { + /* When hovered, remove all transitions from drag handle */ + opacity: 0.5; + transition: opacity 0s linear; +} + +.simplebar-track.simplebar-vertical { + top: 0; + width: 11px; +} + +.simplebar-track.simplebar-vertical .simplebar-scrollbar:before { + top: 2px; + bottom: 2px; +} + +.simplebar-track.simplebar-horizontal { + left: 0; + height: 11px; +} + +.simplebar-track.simplebar-horizontal .simplebar-scrollbar:before { + height: 100%; + left: 2px; + right: 2px; +} + +.simplebar-track.simplebar-horizontal .simplebar-scrollbar { + right: auto; + left: 0; + top: 2px; + height: 7px; + min-height: 0; + min-width: 10px; + width: auto; +} + +/* Rtl support */ +[data-simplebar-direction='rtl'] .simplebar-track.simplebar-vertical { + right: auto; + left: 0; +} + +.hs-dummy-scrollbar-size { + direction: rtl; + position: fixed; + opacity: 0; + visibility: hidden; + height: 500px; + width: 500px; + overflow-y: hidden; + overflow-x: scroll; +} + +.simplebar-hide-scrollbar { + position: fixed; + left: 0; + visibility: hidden; + overflow-y: scroll; + scrollbar-width: none; + -ms-overflow-style: none; +} + +.flatpickr-calendar { + background: transparent; + opacity: 0; + display: none; + text-align: center; + visibility: hidden; + padding: 0; + -webkit-animation: none; + animation: none; + direction: ltr; + border: 0; + font-size: 14px; + line-height: 24px; + border-radius: 5px; + position: absolute; + width: 307.875px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + -ms-touch-action: manipulation; + touch-action: manipulation; + background: #fff; + -webkit-box-shadow: 1px 0 0 #e6e6e6, -1px 0 0 #e6e6e6, 0 1px 0 #e6e6e6, 0 -1px 0 #e6e6e6, 0 3px 13px rgba(0, 0, 0, 0.08); + box-shadow: 1px 0 0 #e6e6e6, -1px 0 0 #e6e6e6, 0 1px 0 #e6e6e6, 0 -1px 0 #e6e6e6, 0 3px 13px rgba(0, 0, 0, 0.08); +} + +.flatpickr-calendar.open, +.flatpickr-calendar.inline { + opacity: 1; + max-height: 640px; + visibility: visible; +} + +.flatpickr-calendar.open { + display: inline-block; + z-index: 99999; +} + +.flatpickr-calendar.animate.open { + -webkit-animation: fpFadeInDown 300ms cubic-bezier(0.23, 1, 0.32, 1); + animation: fpFadeInDown 300ms cubic-bezier(0.23, 1, 0.32, 1); +} + +.flatpickr-calendar.inline { + display: block; + position: relative; + top: 2px; +} + +.flatpickr-calendar.static { + position: absolute; + top: calc(100% + 2px); +} + +.flatpickr-calendar.static.open { + z-index: 999; + display: block; +} + +.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+1) .flatpickr-day.inRange:nth-child(7n+7) { + -webkit-box-shadow: none !important; + box-shadow: none !important; +} + +.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+2) .flatpickr-day.inRange:nth-child(7n+1) { + -webkit-box-shadow: -2px 0 0 #e6e6e6, 5px 0 0 #e6e6e6; + box-shadow: -2px 0 0 #e6e6e6, 5px 0 0 #e6e6e6; +} + +.flatpickr-calendar .hasWeeks .dayContainer, +.flatpickr-calendar .hasTime .dayContainer { + border-bottom: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.flatpickr-calendar .hasWeeks .dayContainer { + border-left: 0; +} + +.flatpickr-calendar.hasTime .flatpickr-time { + height: 40px; + border-top: 1px solid #e6e6e6; +} + +.flatpickr-calendar.noCalendar.hasTime .flatpickr-time { + height: auto; +} + +.flatpickr-calendar:before, +.flatpickr-calendar:after { + position: absolute; + display: block; + pointer-events: none; + border: solid transparent; + content: ''; + height: 0; + width: 0; + left: 22px; +} + +.flatpickr-calendar.rightMost:before, +.flatpickr-calendar.arrowRight:before, +.flatpickr-calendar.rightMost:after, +.flatpickr-calendar.arrowRight:after { + left: auto; + right: 22px; +} + +.flatpickr-calendar.arrowCenter:before, +.flatpickr-calendar.arrowCenter:after { + left: 50%; + right: 50%; +} + +.flatpickr-calendar:before { + border-width: 5px; + margin: 0 -5px; +} + +.flatpickr-calendar:after { + border-width: 4px; + margin: 0 -4px; +} + +.flatpickr-calendar.arrowTop:before, +.flatpickr-calendar.arrowTop:after { + bottom: 100%; +} + +.flatpickr-calendar.arrowTop:before { + border-bottom-color: #e6e6e6; +} + +.flatpickr-calendar.arrowTop:after { + border-bottom-color: #fff; +} + +.flatpickr-calendar.arrowBottom:before, +.flatpickr-calendar.arrowBottom:after { + top: 100%; +} + +.flatpickr-calendar.arrowBottom:before { + border-top-color: #e6e6e6; +} + +.flatpickr-calendar.arrowBottom:after { + border-top-color: #fff; +} + +.flatpickr-calendar:focus { + outline: 0; +} + +.flatpickr-wrapper { + position: relative; + display: inline-block; +} + +.flatpickr-months { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +.flatpickr-months .flatpickr-month { + background: transparent; + color: rgba(0, 0, 0, 0.9); + fill: rgba(0, 0, 0, 0.9); + height: 34px; + line-height: 1; + text-align: center; + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + overflow: hidden; + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.flatpickr-months .flatpickr-prev-month, +.flatpickr-months .flatpickr-next-month { + text-decoration: none; + cursor: pointer; + position: absolute; + top: 0; + height: 34px; + padding: 10px; + z-index: 3; + color: rgba(0, 0, 0, 0.9); + fill: rgba(0, 0, 0, 0.9); +} + +.flatpickr-months .flatpickr-prev-month.flatpickr-disabled, +.flatpickr-months .flatpickr-next-month.flatpickr-disabled { + display: none; +} + +.flatpickr-months .flatpickr-prev-month i, +.flatpickr-months .flatpickr-next-month i { + position: relative; +} + +.flatpickr-months .flatpickr-prev-month.flatpickr-prev-month, +.flatpickr-months .flatpickr-next-month.flatpickr-prev-month { + /* + /*rtl:begin:ignore*/ + /* + */ + left: 0; + /* + /*rtl:end:ignore*/ + /* + */ +} + +/* + /*rtl:begin:ignore*/ +/* + /*rtl:end:ignore*/ +.flatpickr-months .flatpickr-prev-month.flatpickr-next-month, +.flatpickr-months .flatpickr-next-month.flatpickr-next-month { + /* + /*rtl:begin:ignore*/ + /* + */ + right: 0; + /* + /*rtl:end:ignore*/ + /* + */ +} + +/* + /*rtl:begin:ignore*/ +/* + /*rtl:end:ignore*/ +.flatpickr-months .flatpickr-prev-month:hover, +.flatpickr-months .flatpickr-next-month:hover { + color: #959ea9; +} + +.flatpickr-months .flatpickr-prev-month:hover svg, +.flatpickr-months .flatpickr-next-month:hover svg { + fill: #f64747; +} + +.flatpickr-months .flatpickr-prev-month svg, +.flatpickr-months .flatpickr-next-month svg { + width: 14px; + height: 14px; +} + +.flatpickr-months .flatpickr-prev-month svg path, +.flatpickr-months .flatpickr-next-month svg path { + -webkit-transition: fill 0.1s; + transition: fill 0.1s; + fill: inherit; +} + +.numInputWrapper { + position: relative; + height: auto; +} + +.numInputWrapper input, +.numInputWrapper span { + display: inline-block; +} + +.numInputWrapper input { + width: 100%; +} + +.numInputWrapper input::-ms-clear { + display: none; +} + +.numInputWrapper input::-webkit-outer-spin-button, +.numInputWrapper input::-webkit-inner-spin-button { + margin: 0; + -webkit-appearance: none; +} + +.numInputWrapper span { + position: absolute; + right: 0; + width: 14px; + padding: 0 4px 0 2px; + height: 50%; + line-height: 50%; + opacity: 0; + cursor: pointer; + border: 1px solid rgba(57, 57, 57, 0.15); + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.numInputWrapper span:hover { + background: rgba(0, 0, 0, 0.1); +} + +.numInputWrapper span:active { + background: rgba(0, 0, 0, 0.2); +} + +.numInputWrapper span:after { + display: block; + content: ""; + position: absolute; +} + +.numInputWrapper span.arrowUp { + top: 0; + border-bottom: 0; +} + +.numInputWrapper span.arrowUp:after { + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-bottom: 4px solid rgba(57, 57, 57, 0.6); + top: 26%; +} + +.numInputWrapper span.arrowDown { + top: 50%; +} + +.numInputWrapper span.arrowDown:after { + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid rgba(57, 57, 57, 0.6); + top: 40%; +} + +.numInputWrapper span svg { + width: inherit; + height: auto; +} + +.numInputWrapper span svg path { + fill: rgba(0, 0, 0, 0.5); +} + +.numInputWrapper:hover { + background: rgba(0, 0, 0, 0.05); +} + +.numInputWrapper:hover span { + opacity: 1; +} + +.flatpickr-current-month { + font-size: 135%; + line-height: inherit; + font-weight: 300; + color: inherit; + position: absolute; + width: 75%; + left: 12.5%; + padding: 7.48px 0 0 0; + line-height: 1; + height: 34px; + display: inline-block; + text-align: center; + -webkit-transform: translate3d(0px, 0px, 0px); + transform: translate3d(0px, 0px, 0px); +} + +.flatpickr-current-month span.cur-month { + font-family: inherit; + font-weight: 700; + color: inherit; + display: inline-block; + margin-left: 0.5ch; + padding: 0; +} + +.flatpickr-current-month span.cur-month:hover { + background: rgba(0, 0, 0, 0.05); +} + +.flatpickr-current-month .numInputWrapper { + width: 6ch; + width: 7ch\0; + display: inline-block; +} + +.flatpickr-current-month .numInputWrapper span.arrowUp:after { + border-bottom-color: rgba(0, 0, 0, 0.9); +} + +.flatpickr-current-month .numInputWrapper span.arrowDown:after { + border-top-color: rgba(0, 0, 0, 0.9); +} + +.flatpickr-current-month input.cur-year { + background: transparent; + -webkit-box-sizing: border-box; + box-sizing: border-box; + color: inherit; + cursor: text; + padding: 0 0 0 0.5ch; + margin: 0; + display: inline-block; + font-size: inherit; + font-family: inherit; + font-weight: 300; + line-height: inherit; + height: auto; + border: 0; + border-radius: 0; + vertical-align: initial; + -webkit-appearance: textfield; + -moz-appearance: textfield; + appearance: textfield; +} + +.flatpickr-current-month input.cur-year:focus { + outline: 0; +} + +.flatpickr-current-month input.cur-year[disabled], +.flatpickr-current-month input.cur-year[disabled]:hover { + font-size: 100%; + color: rgba(0, 0, 0, 0.5); + background: transparent; + pointer-events: none; +} + +.flatpickr-current-month .flatpickr-monthDropdown-months { + appearance: menulist; + background: transparent; + border: none; + border-radius: 0; + box-sizing: border-box; + color: inherit; + cursor: pointer; + font-size: inherit; + font-family: inherit; + font-weight: 300; + height: auto; + line-height: inherit; + margin: -1px 0 0 0; + outline: none; + padding: 0 0 0 0.5ch; + position: relative; + vertical-align: initial; + -webkit-box-sizing: border-box; + -webkit-appearance: menulist; + -moz-appearance: menulist; + width: auto; +} + +.flatpickr-current-month .flatpickr-monthDropdown-months:focus, +.flatpickr-current-month .flatpickr-monthDropdown-months:active { + outline: none; +} + +.flatpickr-current-month .flatpickr-monthDropdown-months:hover { + background: rgba(0, 0, 0, 0.05); +} + +.flatpickr-current-month .flatpickr-monthDropdown-months .flatpickr-monthDropdown-month { + background-color: transparent; + outline: none; + padding: 0; +} + +.flatpickr-weekdays { + background: transparent; + text-align: center; + overflow: hidden; + width: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + height: 28px; +} + +.flatpickr-weekdays .flatpickr-weekdaycontainer { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} + +span.flatpickr-weekday { + cursor: default; + font-size: 90%; + background: transparent; + color: rgba(0, 0, 0, 0.54); + line-height: 1; + margin: 0; + text-align: center; + display: block; + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + font-weight: bolder; +} + +.dayContainer, +.flatpickr-weeks { + padding: 1px 0 0 0; +} + +.flatpickr-days { + position: relative; + overflow: hidden; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: start; + -webkit-align-items: flex-start; + -ms-flex-align: start; + align-items: flex-start; + width: 307.875px; +} + +.flatpickr-days:focus { + outline: 0; +} + +.dayContainer { + padding: 0; + outline: 0; + text-align: left; + width: 307.875px; + min-width: 307.875px; + max-width: 307.875px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + display: inline-block; + display: -ms-flexbox; + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-wrap: wrap; + -ms-flex-pack: justify; + -webkit-justify-content: space-around; + justify-content: space-around; + -webkit-transform: translate3d(0px, 0px, 0px); + transform: translate3d(0px, 0px, 0px); + opacity: 1; +} + +.dayContainer + .dayContainer { + -webkit-box-shadow: -1px 0 0 #e6e6e6; + box-shadow: -1px 0 0 #e6e6e6; +} + +.flatpickr-day { + background: none; + border: 1px solid transparent; + border-radius: 150px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + color: #393939; + cursor: pointer; + font-weight: 400; + width: 14.2857143%; + -webkit-flex-basis: 14.2857143%; + -ms-flex-preferred-size: 14.2857143%; + flex-basis: 14.2857143%; + max-width: 39px; + height: 39px; + line-height: 39px; + margin: 0; + display: inline-block; + position: relative; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + text-align: center; +} + +.flatpickr-day.inRange, +.flatpickr-day.prevMonthDay.inRange, +.flatpickr-day.nextMonthDay.inRange, +.flatpickr-day.today.inRange, +.flatpickr-day.prevMonthDay.today.inRange, +.flatpickr-day.nextMonthDay.today.inRange, +.flatpickr-day:hover, +.flatpickr-day.prevMonthDay:hover, +.flatpickr-day.nextMonthDay:hover, +.flatpickr-day:focus, +.flatpickr-day.prevMonthDay:focus, +.flatpickr-day.nextMonthDay:focus { + cursor: pointer; + outline: 0; + background: #e6e6e6; + border-color: #e6e6e6; +} + +.flatpickr-day.today { + border-color: #959ea9; +} + +.flatpickr-day.today:hover, +.flatpickr-day.today:focus { + border-color: #959ea9; + background: #959ea9; + color: #fff; +} + +.flatpickr-day.selected, +.flatpickr-day.startRange, +.flatpickr-day.endRange, +.flatpickr-day.selected.inRange, +.flatpickr-day.startRange.inRange, +.flatpickr-day.endRange.inRange, +.flatpickr-day.selected:focus, +.flatpickr-day.startRange:focus, +.flatpickr-day.endRange:focus, +.flatpickr-day.selected:hover, +.flatpickr-day.startRange:hover, +.flatpickr-day.endRange:hover, +.flatpickr-day.selected.prevMonthDay, +.flatpickr-day.startRange.prevMonthDay, +.flatpickr-day.endRange.prevMonthDay, +.flatpickr-day.selected.nextMonthDay, +.flatpickr-day.startRange.nextMonthDay, +.flatpickr-day.endRange.nextMonthDay { + background: #569ff7; + -webkit-box-shadow: none; + box-shadow: none; + color: #fff; + border-color: #569ff7; +} + +.flatpickr-day.selected.startRange, +.flatpickr-day.startRange.startRange, +.flatpickr-day.endRange.startRange { + border-radius: 50px 0 0 50px; +} + +.flatpickr-day.selected.endRange, +.flatpickr-day.startRange.endRange, +.flatpickr-day.endRange.endRange { + border-radius: 0 50px 50px 0; +} + +.flatpickr-day.selected.startRange + .endRange:not(:nth-child(7n+1)), +.flatpickr-day.startRange.startRange + .endRange:not(:nth-child(7n+1)), +.flatpickr-day.endRange.startRange + .endRange:not(:nth-child(7n+1)) { + -webkit-box-shadow: -10px 0 0 #569ff7; + box-shadow: -10px 0 0 #569ff7; +} + +.flatpickr-day.selected.startRange.endRange, +.flatpickr-day.startRange.startRange.endRange, +.flatpickr-day.endRange.startRange.endRange { + border-radius: 50px; +} + +.flatpickr-day.inRange { + border-radius: 0; + -webkit-box-shadow: -5px 0 0 #e6e6e6, 5px 0 0 #e6e6e6; + box-shadow: -5px 0 0 #e6e6e6, 5px 0 0 #e6e6e6; +} + +.flatpickr-day.flatpickr-disabled, +.flatpickr-day.flatpickr-disabled:hover, +.flatpickr-day.prevMonthDay, +.flatpickr-day.nextMonthDay, +.flatpickr-day.notAllowed, +.flatpickr-day.notAllowed.prevMonthDay, +.flatpickr-day.notAllowed.nextMonthDay { + color: rgba(57, 57, 57, 0.3); + background: transparent; + border-color: transparent; + cursor: default; +} + +.flatpickr-day.flatpickr-disabled, +.flatpickr-day.flatpickr-disabled:hover { + cursor: not-allowed; + color: rgba(57, 57, 57, 0.1); +} + +.flatpickr-day.week.selected { + border-radius: 0; + -webkit-box-shadow: -5px 0 0 #569ff7, 5px 0 0 #569ff7; + box-shadow: -5px 0 0 #569ff7, 5px 0 0 #569ff7; +} + +.flatpickr-day.hidden { + visibility: hidden; +} + +.rangeMode .flatpickr-day { + margin-top: 1px; +} + +.flatpickr-weekwrapper { + float: left; +} + +.flatpickr-weekwrapper .flatpickr-weeks { + padding: 0 12px; + -webkit-box-shadow: 1px 0 0 #e6e6e6; + box-shadow: 1px 0 0 #e6e6e6; +} + +.flatpickr-weekwrapper .flatpickr-weekday { + float: none; + width: 100%; + line-height: 28px; +} + +.flatpickr-weekwrapper span.flatpickr-day, +.flatpickr-weekwrapper span.flatpickr-day:hover { + display: block; + width: 100%; + max-width: none; + color: rgba(57, 57, 57, 0.3); + background: transparent; + cursor: default; + border: none; +} + +.flatpickr-innerContainer { + display: block; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-sizing: border-box; + box-sizing: border-box; + overflow: hidden; +} + +.flatpickr-rContainer { + display: inline-block; + padding: 0; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.flatpickr-time { + text-align: center; + outline: 0; + display: block; + height: 0; + line-height: 40px; + max-height: 40px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + overflow: hidden; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +.flatpickr-time:after { + content: ""; + display: table; + clear: both; +} + +.flatpickr-time .numInputWrapper { + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + width: 40%; + height: 40px; + float: left; +} + +.flatpickr-time .numInputWrapper span.arrowUp:after { + border-bottom-color: #393939; +} + +.flatpickr-time .numInputWrapper span.arrowDown:after { + border-top-color: #393939; +} + +.flatpickr-time.hasSeconds .numInputWrapper { + width: 26%; +} + +.flatpickr-time.time24hr .numInputWrapper { + width: 49%; +} + +.flatpickr-time input { + background: transparent; + -webkit-box-shadow: none; + box-shadow: none; + border: 0; + border-radius: 0; + text-align: center; + margin: 0; + padding: 0; + height: inherit; + line-height: inherit; + color: #393939; + font-size: 14px; + position: relative; + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-appearance: textfield; + -moz-appearance: textfield; + appearance: textfield; +} + +.flatpickr-time input.flatpickr-hour { + font-weight: bold; +} + +.flatpickr-time input.flatpickr-minute, +.flatpickr-time input.flatpickr-second { + font-weight: 400; +} + +.flatpickr-time input:focus { + outline: 0; + border: 0; +} + +.flatpickr-time .flatpickr-time-separator, +.flatpickr-time .flatpickr-am-pm { + height: inherit; + float: left; + line-height: inherit; + color: #393939; + font-weight: bold; + width: 2%; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-align-self: center; + -ms-flex-item-align: center; + align-self: center; +} + +.flatpickr-time .flatpickr-am-pm { + outline: 0; + width: 18%; + cursor: pointer; + text-align: center; + font-weight: 400; +} + +.flatpickr-time input:hover, +.flatpickr-time .flatpickr-am-pm:hover, +.flatpickr-time input:focus, +.flatpickr-time .flatpickr-am-pm:focus { + background: #eee; +} + +.flatpickr-input[readonly] { + cursor: pointer; +} + +@-webkit-keyframes fpFadeInDown { + from { + opacity: 0; + -webkit-transform: translate3d(0, -20px, 0); + transform: translate3d(0, -20px, 0); + } + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fpFadeInDown { + from { + opacity: 0; + -webkit-transform: translate3d(0, -20px, 0); + transform: translate3d(0, -20px, 0); + } + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.simplebar-scrollbar:before { + background: #fff; +} + +.simplebar-content { + display: flex; + flex-direction: column; + height: 100vh; + padding-bottom: 0 !important; +} + +[data-simplebar] { + position: sticky; + top: 0; + left: 0; + width: 260px; +} + +.flatpickr-calendar.inline { + background: transparent; + box-shadow: none; + width: 100%; +} + +.flatpickr-calendar.inline .flatpickr-days { + width: 100%; +} + +.flatpickr-calendar.inline .dayContainer { + width: 100%; + min-width: 100%; + max-width: 100%; +} + +.flatpickr-calendar.inline .flatpickr-day { + border-radius: 0.2rem; + max-width: inherit; + height: 45px; + line-height: 45px; +} + +.flatpickr-calendar.inline .flatpickr-day.today { + border: 0; +} + +.flatpickr-calendar.inline .flatpickr-day.today:before { + content: ""; + display: inline-block; + border-color: rgba(0, 0, 0, 0.2) transparent #3B7DDD; + border-style: solid; + border-width: 0 0 7px 7px; + position: absolute; + bottom: 4px; + right: 4px; +} + +.flatpickr-calendar.inline .flatpickr-day.today.selected:before { + border-color: rgba(0, 0, 0, 0.2) transparent #fff; +} + +.flatpickr-calendar.inline .flatpickr-day.today:hover { + background: #e6e6e6; + color: #000; +} + +.flatpickr-calendar.inline .flatpickr-day.selected, .flatpickr-calendar.inline .flatpickr-day.selected:hover, .flatpickr-calendar.inline .flatpickr-day.selected:focus { + border-radius: 0.2rem; + background: #3B7DDD; + color: #fff; +} + +.flatpickr-calendar.inline .flatpickr-weekdays { + height: 45px; +} + +.flatpickr-calendar.inline .flatpickr-weekday { + height: 45px; + line-height: 45px; +} + +.flatpickr-calendar.inline .flatpickr-months .flatpickr-month { + height: 45px; +} + +.flatpickr-calendar.inline .flatpickr-months .flatpickr-prev-month, +.flatpickr-calendar.inline .flatpickr-months .flatpickr-next-month { + height: 45px; +} + +.flatpickr-calendar.inline .flatpickr-current-month { + padding-top: 0; + line-height: 45px; + height: 45px; +} + +.flatpickr-calendar.inline .flatpickr-current-month .flatpickr-monthDropdown-months { + appearance: none; +} + +.flatpickr-calendar.inline .flatpickr-current-month .flatpickr-monthDropdown-months, +.flatpickr-calendar.inline .flatpickr-current-month input.cur-year { + font-weight: 400; + font-size: 1.09375rem; +} + +.flatpickr-calendar.inline .flatpickr-prev-month, +.flatpickr-calendar.inline .flatpickr-next-month { + width: 45px; + border-radius: 0.2rem; +} + +.flatpickr-calendar.inline .flatpickr-prev-month:hover, +.flatpickr-calendar.inline .flatpickr-next-month:hover { + background: #e6e6e6; + color: #000; +} + +/*# sourceMappingURL=styles.css.map */ \ No newline at end of file diff --git a/setup/data/domain/apixpress/www/app/webapp/css/fullscreen/styles.css b/setup/data/domain/apixpress/www/app/webapp/css/fullscreen/styles.css new file mode 100755 index 0000000..43249eb --- /dev/null +++ b/setup/data/domain/apixpress/www/app/webapp/css/fullscreen/styles.css @@ -0,0 +1,14213 @@ +@charset "UTF-8"; +/*Automaticaly generated do not change*/ +/*! + * AdminKit v2.3.0 (https://adminkit.io/) + * Copyright 2021 Paul Laros + * Copyright 2021 AdminKit + * Licensed under MIT (https://github.com/adminkit/adminkit/blob/master/LICENSE) + */ +:root { + --bs-blue: #3B7DDD; + --bs-indigo: #6610f2; + --bs-purple: #6f42c1; + --bs-pink: #e83e8c; + --bs-red: #dc3545; + --bs-orange: #fd7e14; + --bs-yellow: #ffc107; + --bs-green: #28a745; + --bs-teal: #20c997; + --bs-cyan: #17a2b8; + --bs-white: #fff; + --bs-gray: #6c757d; + --bs-gray-dark: #343a40; + --bs-gray-100: #f8f9fa; + --bs-gray-200: #e9ecef; + --bs-gray-300: #dee2e6; + --bs-gray-400: #ced4da; + --bs-gray-500: #adb5bd; + --bs-gray-600: #6c757d; + --bs-gray-700: #495057; + --bs-gray-800: #343a40; + --bs-gray-900: #212529; + --bs-primary: #3B7DDD; + --bs-secondary: #6c757d; + --bs-success: #28a745; + --bs-info: #17a2b8; + --bs-warning: #ffc107; + --bs-danger: #dc3545; + --bs-light: #f8f9fa; + --bs-dark: #212529; + --bs-primary-rgb: 59, 125, 221; + --bs-secondary-rgb: 108, 117, 125; + --bs-success-rgb: 40, 167, 69; + --bs-info-rgb: 23, 162, 184; + --bs-warning-rgb: 255, 193, 7; + --bs-danger-rgb: 220, 53, 69; + --bs-light-rgb: 248, 249, 250; + --bs-dark-rgb: 33, 37, 41; + --bs-white-rgb: 255, 255, 255; + --bs-black-rgb: 0, 0, 0; + --bs-body-color-rgb: 73, 80, 87; + --bs-body-bg-rgb: 247, 247, 252; + --bs-font-sans-serif: "Inter", "Helvetica Neue", Arial, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); + --bs-body-font-family: var(--bs-font-sans-serif); + --bs-body-font-size: 0.875rem; + --bs-body-font-weight: 400; + --bs-body-line-height: 1.5; + --bs-body-color: #495057; + --bs-body-bg: #F7F7FC; +} + +*, +*::before, +*::after { + box-sizing: border-box; +} + +@media (prefers-reduced-motion: no-preference) { + :root { + scroll-behavior: smooth; + } +} + +body { + margin: 0; + font-family: var(--bs-body-font-family); + font-size: var(--bs-body-font-size); + font-weight: var(--bs-body-font-weight); + line-height: var(--bs-body-line-height); + color: var(--bs-body-color); + text-align: var(--bs-body-text-align); + background-color: var(--bs-body-bg); + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} + +hr { + margin: 1rem 0; + color: inherit; + background-color: currentColor; + border: 0; + opacity: 0.25; +} + +hr:not([size]) { + height: 1px; +} + +h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6 { + margin-top: 0; + margin-bottom: 0.5rem; + font-weight: 400; + line-height: 1.2; + color: #000; +} + +h1, .h1 { + font-size: 1.75rem; +} + +h2, .h2 { + font-size: 1.53125rem; +} + +h3, .h3 { + font-size: 1.3125rem; +} + +h4, .h4 { + font-size: 1.09375rem; +} + +h5, .h5 { + font-size: 0.875rem; +} + +h6, .h6 { + font-size: 0.875rem; +} + +p { + margin-top: 0; + margin-bottom: 1rem; +} + +abbr[title], +abbr[data-bs-original-title] { + text-decoration: underline dotted; + cursor: help; + text-decoration-skip-ink: none; +} + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit; +} + +ol, +ul { + padding-left: 2rem; +} + +ol, +ul, +dl { + margin-top: 0; + margin-bottom: 1rem; +} + +ol ol, +ul ul, +ol ul, +ul ol { + margin-bottom: 0; +} + +dt { + font-weight: 600; +} + +dd { + margin-bottom: .5rem; + margin-left: 0; +} + +blockquote { + margin: 0 0 1rem; +} + +b, +strong { + font-weight: bolder; +} + +small, .small { + font-size: 80%; +} + +mark, .mark { + padding: 0.2em; + background-color: #fcf8e3; +} + +sub, +sup { + position: relative; + font-size: 0.75em; + line-height: 0; + vertical-align: baseline; +} + +sub { + bottom: -.25em; +} + +sup { + top: -.5em; +} + +a { + color: #3B7DDD; + text-decoration: none; +} + +a:hover { + color: #2f64b1; + text-decoration: underline; +} + +a:not([href]):not([class]), a:not([href]):not([class]):hover { + color: inherit; + text-decoration: none; +} + +pre, +code, +kbd, +samp { + font-family: var(--bs-font-monospace); + font-size: 1em; + direction: ltr /* rtl:ignore */; + unicode-bidi: bidi-override; +} + +pre { + display: block; + margin-top: 0; + margin-bottom: 1rem; + overflow: auto; + font-size: 80%; +} + +pre code { + font-size: inherit; + color: inherit; + word-break: normal; +} + +code { + font-size: 80%; + color: #e83e8c; + word-wrap: break-word; +} + +a > code { + color: inherit; +} + +kbd { + padding: 0.2rem 0.4rem; + font-size: 80%; + color: #fff; + background-color: #212529; + border-radius: 0.1rem; +} + +kbd kbd { + padding: 0; + font-size: 1em; + font-weight: 600; +} + +figure { + margin: 0 0 1rem; +} + +img, +svg { + vertical-align: middle; +} + +table { + caption-side: bottom; + border-collapse: collapse; +} + +caption { + padding-top: 0.75rem; + padding-bottom: 0.75rem; + color: #6c757d; + text-align: left; +} + +th { + text-align: inherit; + text-align: -webkit-match-parent; +} + +thead, +tbody, +tfoot, +tr, +td, +th { + border-color: inherit; + border-style: solid; + border-width: 0; +} + +label { + display: inline-block; +} + +button { + border-radius: 0; +} + +button:focus:not(:focus-visible) { + outline: 0; +} + +input, +button, +select, +optgroup, +textarea { + margin: 0; + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +button, +select { + text-transform: none; +} + +[role="button"] { + cursor: pointer; +} + +select { + word-wrap: normal; +} + +select:disabled { + opacity: 1; +} + +[list]::-webkit-calendar-picker-indicator { + display: none; +} + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +button:not(:disabled), +[type="button"]:not(:disabled), +[type="reset"]:not(:disabled), +[type="submit"]:not(:disabled) { + cursor: pointer; +} + +::-moz-focus-inner { + padding: 0; + border-style: none; +} + +textarea { + resize: vertical; +} + +fieldset { + min-width: 0; + padding: 0; + margin: 0; + border: 0; +} + +legend { + float: left; + width: 100%; + padding: 0; + margin-bottom: 0.5rem; + font-size: 1.5rem; + line-height: inherit; +} + +legend + * { + clear: left; +} + +::-webkit-datetime-edit-fields-wrapper, +::-webkit-datetime-edit-text, +::-webkit-datetime-edit-minute, +::-webkit-datetime-edit-hour-field, +::-webkit-datetime-edit-day-field, +::-webkit-datetime-edit-month-field, +::-webkit-datetime-edit-year-field { + padding: 0; +} + +::-webkit-inner-spin-button { + height: auto; +} + +[type="search"] { + outline-offset: -2px; + -webkit-appearance: textfield; +} + +/* rtl:raw: +[type="tel"], +[type="url"], +[type="email"], +[type="number"] { + direction: ltr; +} +*/ +::-webkit-search-decoration { + -webkit-appearance: none; +} + +::-webkit-color-swatch-wrapper { + padding: 0; +} + +::file-selector-button { + font: inherit; +} + +::-webkit-file-upload-button { + font: inherit; + -webkit-appearance: button; +} + +output { + display: inline-block; +} + +iframe { + border: 0; +} + +summary { + display: list-item; + cursor: pointer; +} + +progress { + vertical-align: baseline; +} + +[hidden] { + display: none !important; +} + +.lead { + font-size: 1.09375rem; + font-weight: 300; +} + +.display-1 { + font-size: 6rem; + font-weight: 300; + line-height: 1.2; +} + +.display-2 { + font-size: 5.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-3 { + font-size: 4.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-4 { + font-size: 3.5rem; + font-weight: 300; + line-height: 1.2; +} + +.display-5 { + font-size: 3rem; + font-weight: 300; + line-height: 1.2; +} + +.display-6 { + font-size: 2.5rem; + font-weight: 300; + line-height: 1.2; +} + +.list-unstyled { + padding-left: 0; + list-style: none; +} + +.list-inline { + padding-left: 0; + list-style: none; +} + +.list-inline-item { + display: inline-block; +} + +.list-inline-item:not(:last-child) { + margin-right: 0.5rem; +} + +.initialism { + font-size: 80%; + text-transform: uppercase; +} + +.blockquote { + margin-bottom: 1rem; + font-size: 1.09375rem; +} + +.blockquote > :last-child { + margin-bottom: 0; +} + +.blockquote-footer { + margin-top: -1rem; + margin-bottom: 1rem; + font-size: 80%; + color: #6c757d; +} + +.blockquote-footer::before { + content: "\2014\00A0"; +} + +.img-fluid { + max-width: 100%; + height: auto; +} + +.img-thumbnail { + padding: 0.25rem; + background-color: #F7F7FC; + border: 1px solid #dee2e6; + border-radius: 0.2rem; + max-width: 100%; + height: auto; +} + +.figure { + display: inline-block; +} + +.figure-img { + margin-bottom: 0.5rem; + line-height: 1; +} + +.figure-caption { + font-size: 80%; + color: #6c757d; +} + +.container, +.container-fluid, +.container-sm, +.container-md, +.container-lg, +.container-xl { + width: 100%; + padding-right: var(--bs-gutter-x, 0.75rem); + padding-left: var(--bs-gutter-x, 0.75rem); + margin-right: auto; + margin-left: auto; +} + +@media (min-width: 576px) { + .container, .container-sm { + max-width: 540px; + } +} + +@media (min-width: 768px) { + .container, .container-sm, .container-md { + max-width: 720px; + } +} + +@media (min-width: 992px) { + .container, .container-sm, .container-md, .container-lg { + max-width: 960px; + } +} + +@media (min-width: 1200px) { + .container, .container-sm, .container-md, .container-lg, .container-xl { + max-width: 1200px; + } +} + +.row { + --bs-gutter-x: 24px; + --bs-gutter-y: 0; + display: flex; + flex-wrap: wrap; + margin-top: calc(-1 * var(--bs-gutter-y)); + margin-right: calc(-.5 * var(--bs-gutter-x)); + margin-left: calc(-.5 * var(--bs-gutter-x)); +} + +.row > * { + flex-shrink: 0; + width: 100%; + max-width: 100%; + padding-right: calc(var(--bs-gutter-x) * .5); + padding-left: calc(var(--bs-gutter-x) * .5); + margin-top: var(--bs-gutter-y); +} + +.col { + flex: 1 0 0%; +} + +.row-cols-auto > * { + flex: 0 0 auto; + width: auto; +} + +.row-cols-1 > * { + flex: 0 0 auto; + width: 100%; +} + +.row-cols-2 > * { + flex: 0 0 auto; + width: 50%; +} + +.row-cols-3 > * { + flex: 0 0 auto; + width: 33.33333%; +} + +.row-cols-4 > * { + flex: 0 0 auto; + width: 25%; +} + +.row-cols-5 > * { + flex: 0 0 auto; + width: 20%; +} + +.row-cols-6 > * { + flex: 0 0 auto; + width: 16.66667%; +} + +.col-auto { + flex: 0 0 auto; + width: auto; +} + +.col-1 { + flex: 0 0 auto; + width: 8.33333%; +} + +.col-2 { + flex: 0 0 auto; + width: 16.66667%; +} + +.col-3 { + flex: 0 0 auto; + width: 25%; +} + +.col-4 { + flex: 0 0 auto; + width: 33.33333%; +} + +.col-5 { + flex: 0 0 auto; + width: 41.66667%; +} + +.col-6 { + flex: 0 0 auto; + width: 50%; +} + +.col-7 { + flex: 0 0 auto; + width: 58.33333%; +} + +.col-8 { + flex: 0 0 auto; + width: 66.66667%; +} + +.col-9 { + flex: 0 0 auto; + width: 75%; +} + +.col-10 { + flex: 0 0 auto; + width: 83.33333%; +} + +.col-11 { + flex: 0 0 auto; + width: 91.66667%; +} + +.col-12 { + flex: 0 0 auto; + width: 100%; +} + +.offset-1 { + margin-left: 8.33333%; +} + +.offset-2 { + margin-left: 16.66667%; +} + +.offset-3 { + margin-left: 25%; +} + +.offset-4 { + margin-left: 33.33333%; +} + +.offset-5 { + margin-left: 41.66667%; +} + +.offset-6 { + margin-left: 50%; +} + +.offset-7 { + margin-left: 58.33333%; +} + +.offset-8 { + margin-left: 66.66667%; +} + +.offset-9 { + margin-left: 75%; +} + +.offset-10 { + margin-left: 83.33333%; +} + +.offset-11 { + margin-left: 91.66667%; +} + +.g-0, +.gx-0 { + --bs-gutter-x: 0; +} + +.g-0, +.gy-0 { + --bs-gutter-y: 0; +} + +.g-1, +.gx-1 { + --bs-gutter-x: 0.25rem; +} + +.g-1, +.gy-1 { + --bs-gutter-y: 0.25rem; +} + +.g-2, +.gx-2 { + --bs-gutter-x: 0.5rem; +} + +.g-2, +.gy-2 { + --bs-gutter-y: 0.5rem; +} + +.g-3, +.gx-3 { + --bs-gutter-x: 1rem; +} + +.g-3, +.gy-3 { + --bs-gutter-y: 1rem; +} + +.g-4, +.gx-4 { + --bs-gutter-x: 1.5rem; +} + +.g-4, +.gy-4 { + --bs-gutter-y: 1.5rem; +} + +.g-5, +.gx-5 { + --bs-gutter-x: 3rem; +} + +.g-5, +.gy-5 { + --bs-gutter-y: 3rem; +} + +.g-6, +.gx-6 { + --bs-gutter-x: 4.5rem; +} + +.g-6, +.gy-6 { + --bs-gutter-y: 4.5rem; +} + +.g-7, +.gx-7 { + --bs-gutter-x: 6rem; +} + +.g-7, +.gy-7 { + --bs-gutter-y: 6rem; +} + +@media (min-width: 576px) { + .col-sm { + flex: 1 0 0%; + } + .row-cols-sm-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-sm-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-sm-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-sm-3 > * { + flex: 0 0 auto; + width: 33.33333%; + } + .row-cols-sm-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-sm-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-sm-6 > * { + flex: 0 0 auto; + width: 16.66667%; + } + .col-sm-auto { + flex: 0 0 auto; + width: auto; + } + .col-sm-1 { + flex: 0 0 auto; + width: 8.33333%; + } + .col-sm-2 { + flex: 0 0 auto; + width: 16.66667%; + } + .col-sm-3 { + flex: 0 0 auto; + width: 25%; + } + .col-sm-4 { + flex: 0 0 auto; + width: 33.33333%; + } + .col-sm-5 { + flex: 0 0 auto; + width: 41.66667%; + } + .col-sm-6 { + flex: 0 0 auto; + width: 50%; + } + .col-sm-7 { + flex: 0 0 auto; + width: 58.33333%; + } + .col-sm-8 { + flex: 0 0 auto; + width: 66.66667%; + } + .col-sm-9 { + flex: 0 0 auto; + width: 75%; + } + .col-sm-10 { + flex: 0 0 auto; + width: 83.33333%; + } + .col-sm-11 { + flex: 0 0 auto; + width: 91.66667%; + } + .col-sm-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-sm-0 { + margin-left: 0; + } + .offset-sm-1 { + margin-left: 8.33333%; + } + .offset-sm-2 { + margin-left: 16.66667%; + } + .offset-sm-3 { + margin-left: 25%; + } + .offset-sm-4 { + margin-left: 33.33333%; + } + .offset-sm-5 { + margin-left: 41.66667%; + } + .offset-sm-6 { + margin-left: 50%; + } + .offset-sm-7 { + margin-left: 58.33333%; + } + .offset-sm-8 { + margin-left: 66.66667%; + } + .offset-sm-9 { + margin-left: 75%; + } + .offset-sm-10 { + margin-left: 83.33333%; + } + .offset-sm-11 { + margin-left: 91.66667%; + } + .g-sm-0, + .gx-sm-0 { + --bs-gutter-x: 0; + } + .g-sm-0, + .gy-sm-0 { + --bs-gutter-y: 0; + } + .g-sm-1, + .gx-sm-1 { + --bs-gutter-x: 0.25rem; + } + .g-sm-1, + .gy-sm-1 { + --bs-gutter-y: 0.25rem; + } + .g-sm-2, + .gx-sm-2 { + --bs-gutter-x: 0.5rem; + } + .g-sm-2, + .gy-sm-2 { + --bs-gutter-y: 0.5rem; + } + .g-sm-3, + .gx-sm-3 { + --bs-gutter-x: 1rem; + } + .g-sm-3, + .gy-sm-3 { + --bs-gutter-y: 1rem; + } + .g-sm-4, + .gx-sm-4 { + --bs-gutter-x: 1.5rem; + } + .g-sm-4, + .gy-sm-4 { + --bs-gutter-y: 1.5rem; + } + .g-sm-5, + .gx-sm-5 { + --bs-gutter-x: 3rem; + } + .g-sm-5, + .gy-sm-5 { + --bs-gutter-y: 3rem; + } + .g-sm-6, + .gx-sm-6 { + --bs-gutter-x: 4.5rem; + } + .g-sm-6, + .gy-sm-6 { + --bs-gutter-y: 4.5rem; + } + .g-sm-7, + .gx-sm-7 { + --bs-gutter-x: 6rem; + } + .g-sm-7, + .gy-sm-7 { + --bs-gutter-y: 6rem; + } +} + +@media (min-width: 768px) { + .col-md { + flex: 1 0 0%; + } + .row-cols-md-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-md-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-md-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-md-3 > * { + flex: 0 0 auto; + width: 33.33333%; + } + .row-cols-md-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-md-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-md-6 > * { + flex: 0 0 auto; + width: 16.66667%; + } + .col-md-auto { + flex: 0 0 auto; + width: auto; + } + .col-md-1 { + flex: 0 0 auto; + width: 8.33333%; + } + .col-md-2 { + flex: 0 0 auto; + width: 16.66667%; + } + .col-md-3 { + flex: 0 0 auto; + width: 25%; + } + .col-md-4 { + flex: 0 0 auto; + width: 33.33333%; + } + .col-md-5 { + flex: 0 0 auto; + width: 41.66667%; + } + .col-md-6 { + flex: 0 0 auto; + width: 50%; + } + .col-md-7 { + flex: 0 0 auto; + width: 58.33333%; + } + .col-md-8 { + flex: 0 0 auto; + width: 66.66667%; + } + .col-md-9 { + flex: 0 0 auto; + width: 75%; + } + .col-md-10 { + flex: 0 0 auto; + width: 83.33333%; + } + .col-md-11 { + flex: 0 0 auto; + width: 91.66667%; + } + .col-md-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-md-0 { + margin-left: 0; + } + .offset-md-1 { + margin-left: 8.33333%; + } + .offset-md-2 { + margin-left: 16.66667%; + } + .offset-md-3 { + margin-left: 25%; + } + .offset-md-4 { + margin-left: 33.33333%; + } + .offset-md-5 { + margin-left: 41.66667%; + } + .offset-md-6 { + margin-left: 50%; + } + .offset-md-7 { + margin-left: 58.33333%; + } + .offset-md-8 { + margin-left: 66.66667%; + } + .offset-md-9 { + margin-left: 75%; + } + .offset-md-10 { + margin-left: 83.33333%; + } + .offset-md-11 { + margin-left: 91.66667%; + } + .g-md-0, + .gx-md-0 { + --bs-gutter-x: 0; + } + .g-md-0, + .gy-md-0 { + --bs-gutter-y: 0; + } + .g-md-1, + .gx-md-1 { + --bs-gutter-x: 0.25rem; + } + .g-md-1, + .gy-md-1 { + --bs-gutter-y: 0.25rem; + } + .g-md-2, + .gx-md-2 { + --bs-gutter-x: 0.5rem; + } + .g-md-2, + .gy-md-2 { + --bs-gutter-y: 0.5rem; + } + .g-md-3, + .gx-md-3 { + --bs-gutter-x: 1rem; + } + .g-md-3, + .gy-md-3 { + --bs-gutter-y: 1rem; + } + .g-md-4, + .gx-md-4 { + --bs-gutter-x: 1.5rem; + } + .g-md-4, + .gy-md-4 { + --bs-gutter-y: 1.5rem; + } + .g-md-5, + .gx-md-5 { + --bs-gutter-x: 3rem; + } + .g-md-5, + .gy-md-5 { + --bs-gutter-y: 3rem; + } + .g-md-6, + .gx-md-6 { + --bs-gutter-x: 4.5rem; + } + .g-md-6, + .gy-md-6 { + --bs-gutter-y: 4.5rem; + } + .g-md-7, + .gx-md-7 { + --bs-gutter-x: 6rem; + } + .g-md-7, + .gy-md-7 { + --bs-gutter-y: 6rem; + } +} + +@media (min-width: 992px) { + .col-lg { + flex: 1 0 0%; + } + .row-cols-lg-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-lg-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-lg-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-lg-3 > * { + flex: 0 0 auto; + width: 33.33333%; + } + .row-cols-lg-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-lg-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-lg-6 > * { + flex: 0 0 auto; + width: 16.66667%; + } + .col-lg-auto { + flex: 0 0 auto; + width: auto; + } + .col-lg-1 { + flex: 0 0 auto; + width: 8.33333%; + } + .col-lg-2 { + flex: 0 0 auto; + width: 16.66667%; + } + .col-lg-3 { + flex: 0 0 auto; + width: 25%; + } + .col-lg-4 { + flex: 0 0 auto; + width: 33.33333%; + } + .col-lg-5 { + flex: 0 0 auto; + width: 41.66667%; + } + .col-lg-6 { + flex: 0 0 auto; + width: 50%; + } + .col-lg-7 { + flex: 0 0 auto; + width: 58.33333%; + } + .col-lg-8 { + flex: 0 0 auto; + width: 66.66667%; + } + .col-lg-9 { + flex: 0 0 auto; + width: 75%; + } + .col-lg-10 { + flex: 0 0 auto; + width: 83.33333%; + } + .col-lg-11 { + flex: 0 0 auto; + width: 91.66667%; + } + .col-lg-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-lg-0 { + margin-left: 0; + } + .offset-lg-1 { + margin-left: 8.33333%; + } + .offset-lg-2 { + margin-left: 16.66667%; + } + .offset-lg-3 { + margin-left: 25%; + } + .offset-lg-4 { + margin-left: 33.33333%; + } + .offset-lg-5 { + margin-left: 41.66667%; + } + .offset-lg-6 { + margin-left: 50%; + } + .offset-lg-7 { + margin-left: 58.33333%; + } + .offset-lg-8 { + margin-left: 66.66667%; + } + .offset-lg-9 { + margin-left: 75%; + } + .offset-lg-10 { + margin-left: 83.33333%; + } + .offset-lg-11 { + margin-left: 91.66667%; + } + .g-lg-0, + .gx-lg-0 { + --bs-gutter-x: 0; + } + .g-lg-0, + .gy-lg-0 { + --bs-gutter-y: 0; + } + .g-lg-1, + .gx-lg-1 { + --bs-gutter-x: 0.25rem; + } + .g-lg-1, + .gy-lg-1 { + --bs-gutter-y: 0.25rem; + } + .g-lg-2, + .gx-lg-2 { + --bs-gutter-x: 0.5rem; + } + .g-lg-2, + .gy-lg-2 { + --bs-gutter-y: 0.5rem; + } + .g-lg-3, + .gx-lg-3 { + --bs-gutter-x: 1rem; + } + .g-lg-3, + .gy-lg-3 { + --bs-gutter-y: 1rem; + } + .g-lg-4, + .gx-lg-4 { + --bs-gutter-x: 1.5rem; + } + .g-lg-4, + .gy-lg-4 { + --bs-gutter-y: 1.5rem; + } + .g-lg-5, + .gx-lg-5 { + --bs-gutter-x: 3rem; + } + .g-lg-5, + .gy-lg-5 { + --bs-gutter-y: 3rem; + } + .g-lg-6, + .gx-lg-6 { + --bs-gutter-x: 4.5rem; + } + .g-lg-6, + .gy-lg-6 { + --bs-gutter-y: 4.5rem; + } + .g-lg-7, + .gx-lg-7 { + --bs-gutter-x: 6rem; + } + .g-lg-7, + .gy-lg-7 { + --bs-gutter-y: 6rem; + } +} + +@media (min-width: 1200px) { + .col-xl { + flex: 1 0 0%; + } + .row-cols-xl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xl-3 > * { + flex: 0 0 auto; + width: 33.33333%; + } + .row-cols-xl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xl-6 > * { + flex: 0 0 auto; + width: 16.66667%; + } + .col-xl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xl-1 { + flex: 0 0 auto; + width: 8.33333%; + } + .col-xl-2 { + flex: 0 0 auto; + width: 16.66667%; + } + .col-xl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xl-4 { + flex: 0 0 auto; + width: 33.33333%; + } + .col-xl-5 { + flex: 0 0 auto; + width: 41.66667%; + } + .col-xl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xl-7 { + flex: 0 0 auto; + width: 58.33333%; + } + .col-xl-8 { + flex: 0 0 auto; + width: 66.66667%; + } + .col-xl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xl-10 { + flex: 0 0 auto; + width: 83.33333%; + } + .col-xl-11 { + flex: 0 0 auto; + width: 91.66667%; + } + .col-xl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xl-0 { + margin-left: 0; + } + .offset-xl-1 { + margin-left: 8.33333%; + } + .offset-xl-2 { + margin-left: 16.66667%; + } + .offset-xl-3 { + margin-left: 25%; + } + .offset-xl-4 { + margin-left: 33.33333%; + } + .offset-xl-5 { + margin-left: 41.66667%; + } + .offset-xl-6 { + margin-left: 50%; + } + .offset-xl-7 { + margin-left: 58.33333%; + } + .offset-xl-8 { + margin-left: 66.66667%; + } + .offset-xl-9 { + margin-left: 75%; + } + .offset-xl-10 { + margin-left: 83.33333%; + } + .offset-xl-11 { + margin-left: 91.66667%; + } + .g-xl-0, + .gx-xl-0 { + --bs-gutter-x: 0; + } + .g-xl-0, + .gy-xl-0 { + --bs-gutter-y: 0; + } + .g-xl-1, + .gx-xl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xl-1, + .gy-xl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xl-2, + .gx-xl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xl-2, + .gy-xl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xl-3, + .gx-xl-3 { + --bs-gutter-x: 1rem; + } + .g-xl-3, + .gy-xl-3 { + --bs-gutter-y: 1rem; + } + .g-xl-4, + .gx-xl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xl-4, + .gy-xl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xl-5, + .gx-xl-5 { + --bs-gutter-x: 3rem; + } + .g-xl-5, + .gy-xl-5 { + --bs-gutter-y: 3rem; + } + .g-xl-6, + .gx-xl-6 { + --bs-gutter-x: 4.5rem; + } + .g-xl-6, + .gy-xl-6 { + --bs-gutter-y: 4.5rem; + } + .g-xl-7, + .gx-xl-7 { + --bs-gutter-x: 6rem; + } + .g-xl-7, + .gy-xl-7 { + --bs-gutter-y: 6rem; + } +} + +@media (min-width: 1440px) { + .col-xxl { + flex: 1 0 0%; + } + .row-cols-xxl-auto > * { + flex: 0 0 auto; + width: auto; + } + .row-cols-xxl-1 > * { + flex: 0 0 auto; + width: 100%; + } + .row-cols-xxl-2 > * { + flex: 0 0 auto; + width: 50%; + } + .row-cols-xxl-3 > * { + flex: 0 0 auto; + width: 33.33333%; + } + .row-cols-xxl-4 > * { + flex: 0 0 auto; + width: 25%; + } + .row-cols-xxl-5 > * { + flex: 0 0 auto; + width: 20%; + } + .row-cols-xxl-6 > * { + flex: 0 0 auto; + width: 16.66667%; + } + .col-xxl-auto { + flex: 0 0 auto; + width: auto; + } + .col-xxl-1 { + flex: 0 0 auto; + width: 8.33333%; + } + .col-xxl-2 { + flex: 0 0 auto; + width: 16.66667%; + } + .col-xxl-3 { + flex: 0 0 auto; + width: 25%; + } + .col-xxl-4 { + flex: 0 0 auto; + width: 33.33333%; + } + .col-xxl-5 { + flex: 0 0 auto; + width: 41.66667%; + } + .col-xxl-6 { + flex: 0 0 auto; + width: 50%; + } + .col-xxl-7 { + flex: 0 0 auto; + width: 58.33333%; + } + .col-xxl-8 { + flex: 0 0 auto; + width: 66.66667%; + } + .col-xxl-9 { + flex: 0 0 auto; + width: 75%; + } + .col-xxl-10 { + flex: 0 0 auto; + width: 83.33333%; + } + .col-xxl-11 { + flex: 0 0 auto; + width: 91.66667%; + } + .col-xxl-12 { + flex: 0 0 auto; + width: 100%; + } + .offset-xxl-0 { + margin-left: 0; + } + .offset-xxl-1 { + margin-left: 8.33333%; + } + .offset-xxl-2 { + margin-left: 16.66667%; + } + .offset-xxl-3 { + margin-left: 25%; + } + .offset-xxl-4 { + margin-left: 33.33333%; + } + .offset-xxl-5 { + margin-left: 41.66667%; + } + .offset-xxl-6 { + margin-left: 50%; + } + .offset-xxl-7 { + margin-left: 58.33333%; + } + .offset-xxl-8 { + margin-left: 66.66667%; + } + .offset-xxl-9 { + margin-left: 75%; + } + .offset-xxl-10 { + margin-left: 83.33333%; + } + .offset-xxl-11 { + margin-left: 91.66667%; + } + .g-xxl-0, + .gx-xxl-0 { + --bs-gutter-x: 0; + } + .g-xxl-0, + .gy-xxl-0 { + --bs-gutter-y: 0; + } + .g-xxl-1, + .gx-xxl-1 { + --bs-gutter-x: 0.25rem; + } + .g-xxl-1, + .gy-xxl-1 { + --bs-gutter-y: 0.25rem; + } + .g-xxl-2, + .gx-xxl-2 { + --bs-gutter-x: 0.5rem; + } + .g-xxl-2, + .gy-xxl-2 { + --bs-gutter-y: 0.5rem; + } + .g-xxl-3, + .gx-xxl-3 { + --bs-gutter-x: 1rem; + } + .g-xxl-3, + .gy-xxl-3 { + --bs-gutter-y: 1rem; + } + .g-xxl-4, + .gx-xxl-4 { + --bs-gutter-x: 1.5rem; + } + .g-xxl-4, + .gy-xxl-4 { + --bs-gutter-y: 1.5rem; + } + .g-xxl-5, + .gx-xxl-5 { + --bs-gutter-x: 3rem; + } + .g-xxl-5, + .gy-xxl-5 { + --bs-gutter-y: 3rem; + } + .g-xxl-6, + .gx-xxl-6 { + --bs-gutter-x: 4.5rem; + } + .g-xxl-6, + .gy-xxl-6 { + --bs-gutter-y: 4.5rem; + } + .g-xxl-7, + .gx-xxl-7 { + --bs-gutter-x: 6rem; + } + .g-xxl-7, + .gy-xxl-7 { + --bs-gutter-y: 6rem; + } +} + +.table { + --bs-table-bg: transparent; + --bs-table-accent-bg: transparent; + --bs-table-striped-color: #495057; + --bs-table-striped-bg: #f8f9fa; + --bs-table-active-color: #495057; + --bs-table-active-bg: rgba(0, 0, 0, 0.1); + --bs-table-hover-color: #495057; + --bs-table-hover-bg: rgba(0, 0, 0, 0.0375); + width: 100%; + margin-bottom: 1rem; + color: #495057; + vertical-align: top; + border-color: #dee2e6; +} + +.table > :not(caption) > * > * { + padding: 0.75rem 0.75rem; + background-color: var(--bs-table-bg); + border-bottom-width: 1px; + box-shadow: inset 0 0 0 9999px var(--bs-table-accent-bg); +} + +.table > tbody { + vertical-align: inherit; +} + +.table > thead { + vertical-align: bottom; +} + +.table > :not(:first-child) { + border-top: 2px solid currentColor; +} + +.caption-top { + caption-side: top; +} + +.table-sm > :not(caption) > * > * { + padding: 0.3rem 0.3rem; +} + +.table-bordered > :not(caption) > * { + border-width: 1px 0; +} + +.table-bordered > :not(caption) > * > * { + border-width: 0 1px; +} + +.table-borderless > :not(caption) > * > * { + border-bottom-width: 0; +} + +.table-borderless > :not(:first-child) { + border-top-width: 0; +} + +.table-striped > tbody > tr:nth-of-type(odd) > * { + --bs-table-accent-bg: var(--bs-table-striped-bg); + color: var(--bs-table-striped-color); +} + +.table-active { + --bs-table-accent-bg: var(--bs-table-active-bg); + color: var(--bs-table-active-color); +} + +.table-hover > tbody > tr:hover > * { + --bs-table-accent-bg: var(--bs-table-hover-bg); + color: var(--bs-table-hover-color); +} + +.table-primary { + --bs-table-bg: #d8e5f8; + --bs-table-striped-bg: #cddaec; + --bs-table-striped-color: #000; + --bs-table-active-bg: #c2cedf; + --bs-table-active-color: #000; + --bs-table-hover-bg: #c8d4e5; + --bs-table-hover-color: #000; + color: #000; + border-color: #c2cedf; +} + +.table-secondary { + --bs-table-bg: #e2e3e5; + --bs-table-striped-bg: #d7d8da; + --bs-table-striped-color: #000; + --bs-table-active-bg: #cbccce; + --bs-table-active-color: #000; + --bs-table-hover-bg: #d1d2d4; + --bs-table-hover-color: #000; + color: #000; + border-color: #cbccce; +} + +.table-success { + --bs-table-bg: #d4edda; + --bs-table-striped-bg: #c9e1cf; + --bs-table-striped-color: #000; + --bs-table-active-bg: #bfd5c4; + --bs-table-active-color: #000; + --bs-table-hover-bg: #c4dbca; + --bs-table-hover-color: #000; + color: #000; + border-color: #bfd5c4; +} + +.table-info { + --bs-table-bg: #d1ecf1; + --bs-table-striped-bg: #c7e0e5; + --bs-table-striped-color: #000; + --bs-table-active-bg: #bcd4d9; + --bs-table-active-color: #000; + --bs-table-hover-bg: #c1dadf; + --bs-table-hover-color: #000; + color: #000; + border-color: #bcd4d9; +} + +.table-warning { + --bs-table-bg: #fff3cd; + --bs-table-striped-bg: #f2e7c3; + --bs-table-striped-color: #000; + --bs-table-active-bg: #e6dbb9; + --bs-table-active-color: #000; + --bs-table-hover-bg: #ece1be; + --bs-table-hover-color: #000; + color: #000; + border-color: #e6dbb9; +} + +.table-danger { + --bs-table-bg: #f8d7da; + --bs-table-striped-bg: #eccccf; + --bs-table-striped-color: #000; + --bs-table-active-bg: #dfc2c4; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e5c7ca; + --bs-table-hover-color: #000; + color: #000; + border-color: #dfc2c4; +} + +.table-light { + --bs-table-bg: #f8f9fa; + --bs-table-striped-bg: #ecedee; + --bs-table-striped-color: #000; + --bs-table-active-bg: #dfe0e1; + --bs-table-active-color: #000; + --bs-table-hover-bg: #e5e6e7; + --bs-table-hover-color: #000; + color: #000; + border-color: #dfe0e1; +} + +.table-dark { + --bs-table-bg: #212529; + --bs-table-striped-bg: #2c3034; + --bs-table-striped-color: #fff; + --bs-table-active-bg: #373b3e; + --bs-table-active-color: #fff; + --bs-table-hover-bg: #323539; + --bs-table-hover-color: #fff; + color: #fff; + border-color: #373b3e; +} + +.table-responsive { + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} + +@media (max-width: 575.98px) { + .table-responsive-sm { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} + +@media (max-width: 767.98px) { + .table-responsive-md { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} + +@media (max-width: 991.98px) { + .table-responsive-lg { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} + +@media (max-width: 1199.98px) { + .table-responsive-xl { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} + +@media (max-width: 1439.98px) { + .table-responsive-xxl { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } +} + +.form-label { + margin-bottom: 0.5rem; +} + +.col-form-label { + padding-top: calc(0.25rem + 1px); + padding-bottom: calc(0.25rem + 1px); + margin-bottom: 0; + font-size: inherit; + line-height: 1.5; +} + +.col-form-label-lg { + padding-top: calc(0.35rem + 1px); + padding-bottom: calc(0.35rem + 1px); + font-size: 0.925rem; +} + +.col-form-label-sm { + padding-top: calc(0.15rem + 1px); + padding-bottom: calc(0.15rem + 1px); + font-size: 0.75rem; +} + +.form-text { + margin-top: 0.25rem; + font-size: 80%; + color: #6c757d; +} + +.form-control { + display: block; + width: 100%; + padding: 0.25rem 0.7rem; + font-size: 0.875rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + background-clip: padding-box; + border: 1px solid #ced4da; + appearance: none; + border-radius: 0.2rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .form-control { + transition: none; + } +} + +.form-control[type="file"] { + overflow: hidden; +} + +.form-control[type="file"]:not(:disabled):not([readonly]) { + cursor: pointer; +} + +.form-control:focus { + color: #495057; + background-color: #fff; + border-color: #9dbeee; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.form-control::-webkit-date-and-time-value { + height: 1.5em; +} + +.form-control::placeholder { + color: #6c757d; + opacity: 1; +} + +.form-control:disabled, .form-control[readonly] { + background-color: #e9ecef; + opacity: 1; +} + +.form-control::file-selector-button { + padding: 0.25rem 0.7rem; + margin: -0.25rem -0.7rem; + margin-inline-end: 0.7rem; + color: #495057; + background-color: #e9ecef; + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: 1px; + border-radius: 0; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .form-control::file-selector-button { + transition: none; + } +} + +.form-control:hover:not(:disabled):not([readonly])::file-selector-button { + background-color: #dde0e3; +} + +.form-control::-webkit-file-upload-button { + padding: 0.25rem 0.7rem; + margin: -0.25rem -0.7rem; + margin-inline-end: 0.7rem; + color: #495057; + background-color: #e9ecef; + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: 1px; + border-radius: 0; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .form-control::-webkit-file-upload-button { + transition: none; + } +} + +.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button { + background-color: #dde0e3; +} + +.form-control-plaintext { + display: block; + width: 100%; + padding: 0.25rem 0; + margin-bottom: 0; + line-height: 1.5; + color: #495057; + background-color: transparent; + border: solid transparent; + border-width: 1px 0; +} + +.form-control-plaintext.form-control-sm, .form-control-plaintext.form-control-lg { + padding-right: 0; + padding-left: 0; +} + +.form-control-sm { + min-height: calc(1.425rem + 2px); + padding: 0.15rem 0.5rem; + font-size: 0.75rem; + border-radius: 0.1rem; +} + +.form-control-sm::file-selector-button { + padding: 0.15rem 0.5rem; + margin: -0.15rem -0.5rem; + margin-inline-end: 0.5rem; +} + +.form-control-sm::-webkit-file-upload-button { + padding: 0.15rem 0.5rem; + margin: -0.15rem -0.5rem; + margin-inline-end: 0.5rem; +} + +.form-control-lg { + min-height: calc(2.0875rem + 2px); + padding: 0.35rem 1rem; + font-size: 0.925rem; + border-radius: 0.3rem; +} + +.form-control-lg::file-selector-button { + padding: 0.35rem 1rem; + margin: -0.35rem -1rem; + margin-inline-end: 1rem; +} + +.form-control-lg::-webkit-file-upload-button { + padding: 0.35rem 1rem; + margin: -0.35rem -1rem; + margin-inline-end: 1rem; +} + +textarea.form-control { + min-height: calc(1.8125rem + 2px); +} + +textarea.form-control-sm { + min-height: calc(1.425rem + 2px); +} + +textarea.form-control-lg { + min-height: calc(2.0875rem + 2px); +} + +.form-control-color { + width: 3rem; + height: auto; + padding: 0.25rem; +} + +.form-control-color:not(:disabled):not([readonly]) { + cursor: pointer; +} + +.form-control-color::-moz-color-swatch { + height: 1.5em; + border-radius: 0.2rem; +} + +.form-control-color::-webkit-color-swatch { + height: 1.5em; + border-radius: 0.2rem; +} + +.form-select { + display: block; + width: 100%; + padding: 0.25rem 2.1rem 0.25rem 0.7rem; + -moz-padding-start: calc(0.7rem - 3px); + font-size: 0.875rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + background-color: #fff; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-position: right 0.7rem center; + background-size: 16px 12px; + border: 1px solid #ced4da; + border-radius: 0.2rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .form-select { + transition: none; + } +} + +.form-select:focus { + border-color: #9dbeee; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.form-select[multiple], .form-select[size]:not([size="1"]) { + padding-right: 0.7rem; + background-image: none; +} + +.form-select:disabled { + background-color: #e9ecef; +} + +.form-select:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 #495057; +} + +.form-select-sm { + padding-top: 0.15rem; + padding-bottom: 0.15rem; + padding-left: 0.5rem; + font-size: 0.75rem; + border-radius: 0.1rem; +} + +.form-select-lg { + padding-top: 0.35rem; + padding-bottom: 0.35rem; + padding-left: 1rem; + font-size: 0.925rem; + border-radius: 0.3rem; +} + +.form-check { + display: block; + min-height: 1.3125rem; + padding-left: 1.5em; + margin-bottom: 0.125rem; +} + +.form-check .form-check-input { + float: left; + margin-left: -1.5em; +} + +.form-check-input { + width: 1em; + height: 1em; + margin-top: 0.25em; + vertical-align: top; + background-color: #fff; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + border: 1px solid rgba(0, 0, 0, 0.25); + appearance: none; + color-adjust: exact; +} + +.form-check-input[type="checkbox"] { + border-radius: 0.25em; +} + +.form-check-input[type="radio"] { + border-radius: 50%; +} + +.form-check-input:active { + filter: brightness(90%); +} + +.form-check-input:focus { + border-color: #9dbeee; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.form-check-input:checked { + background-color: #3B7DDD; + border-color: #3B7DDD; +} + +.form-check-input:checked[type="checkbox"] { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e"); +} + +.form-check-input:checked[type="radio"] { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e"); +} + +.form-check-input[type="checkbox"]:indeterminate { + background-color: #3B7DDD; + border-color: #3B7DDD; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e"); +} + +.form-check-input:disabled { + pointer-events: none; + filter: none; + opacity: 0.5; +} + +.form-check-input[disabled] ~ .form-check-label, .form-check-input:disabled ~ .form-check-label { + opacity: 0.5; +} + +.form-switch { + padding-left: 2.5em; +} + +.form-switch .form-check-input { + width: 2em; + margin-left: -2.5em; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e"); + background-position: left center; + border-radius: 2em; + transition: background-position 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .form-switch .form-check-input { + transition: none; + } +} + +.form-switch .form-check-input:focus { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%239dbeee'/%3e%3c/svg%3e"); +} + +.form-switch .form-check-input:checked { + background-position: right center; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e"); +} + +.form-check-inline { + display: inline-block; + margin-right: 1rem; +} + +.btn-check { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; +} + +.btn-check[disabled] + .btn, .btn-check:disabled + .btn { + pointer-events: none; + filter: none; + opacity: 0.65; +} + +.form-range { + width: 100%; + height: 1.4rem; + padding: 0; + background-color: transparent; + appearance: none; +} + +.form-range:focus { + outline: 0; +} + +.form-range:focus::-webkit-slider-thumb { + box-shadow: 0 0 0 1px #F7F7FC, 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.form-range:focus::-moz-range-thumb { + box-shadow: 0 0 0 1px #F7F7FC, 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.form-range::-moz-focus-outer { + border: 0; +} + +.form-range::-webkit-slider-thumb { + width: 1rem; + height: 1rem; + margin-top: -0.25rem; + background-color: #3B7DDD; + border: 0; + border-radius: 1rem; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .form-range::-webkit-slider-thumb { + transition: none; + } +} + +.form-range::-webkit-slider-thumb:active { + background-color: #c4d8f5; +} + +.form-range::-webkit-slider-runnable-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} + +.form-range::-moz-range-thumb { + width: 1rem; + height: 1rem; + background-color: #3B7DDD; + border: 0; + border-radius: 1rem; + transition: background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; + appearance: none; +} + +@media (prefers-reduced-motion: reduce) { + .form-range::-moz-range-thumb { + transition: none; + } +} + +.form-range::-moz-range-thumb:active { + background-color: #c4d8f5; +} + +.form-range::-moz-range-track { + width: 100%; + height: 0.5rem; + color: transparent; + cursor: pointer; + background-color: #dee2e6; + border-color: transparent; + border-radius: 1rem; +} + +.form-range:disabled { + pointer-events: none; +} + +.form-range:disabled::-webkit-slider-thumb { + background-color: #adb5bd; +} + +.form-range:disabled::-moz-range-thumb { + background-color: #adb5bd; +} + +.form-floating { + position: relative; +} + +.form-floating > .form-control, +.form-floating > .form-select { + height: calc(3.5rem + 2px); + line-height: 1.25; +} + +.form-floating > label { + position: absolute; + top: 0; + left: 0; + height: 100%; + padding: 1rem 0.7rem; + pointer-events: none; + border: 1px solid transparent; + transform-origin: 0 0; + transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .form-floating > label { + transition: none; + } +} + +.form-floating > .form-control { + padding: 1rem 0.7rem; +} + +.form-floating > .form-control::placeholder { + color: transparent; +} + +.form-floating > .form-control:focus, .form-floating > .form-control:not(:placeholder-shown) { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} + +.form-floating > .form-control:-webkit-autofill { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} + +.form-floating > .form-select { + padding-top: 1.625rem; + padding-bottom: 0.625rem; +} + +.form-floating > .form-control:focus ~ label, +.form-floating > .form-control:not(:placeholder-shown) ~ label, +.form-floating > .form-select ~ label { + opacity: 0.65; + transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); +} + +.form-floating > .form-control:-webkit-autofill ~ label { + opacity: 0.65; + transform: scale(0.85) translateY(-0.5rem) translateX(0.15rem); +} + +.input-group { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: stretch; + width: 100%; +} + +.input-group > .form-control, +.input-group > .form-select { + position: relative; + flex: 1 1 auto; + width: 1%; + min-width: 0; +} + +.input-group > .form-control:focus, +.input-group > .form-select:focus { + z-index: 3; +} + +.input-group .btn { + position: relative; + z-index: 2; +} + +.input-group .btn:focus { + z-index: 3; +} + +.input-group-text { + display: flex; + align-items: center; + padding: 0.25rem 0.7rem; + font-size: 0.875rem; + font-weight: 400; + line-height: 1.5; + color: #495057; + text-align: center; + white-space: nowrap; + background-color: #e9ecef; + border: 1px solid #ced4da; + border-radius: 0.2rem; +} + +.input-group-lg > .form-control, +.input-group-lg > .form-select, +.input-group-lg > .input-group-text, +.input-group-lg > .btn { + padding: 0.35rem 1rem; + font-size: 0.925rem; + border-radius: 0.3rem; +} + +.input-group-sm > .form-control, +.input-group-sm > .form-select, +.input-group-sm > .input-group-text, +.input-group-sm > .btn { + padding: 0.15rem 0.5rem; + font-size: 0.75rem; + border-radius: 0.1rem; +} + +.input-group-lg > .form-select, +.input-group-sm > .form-select { + padding-right: 2.8rem; +} + +.input-group:not(.has-validation) > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu), +.input-group:not(.has-validation) > .dropdown-toggle:nth-last-child(n + 3) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group.has-validation > :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu), +.input-group.has-validation > .dropdown-toggle:nth-last-child(n + 4) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) { + margin-left: -1px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.valid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #28a745; +} + +.valid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: .1rem; + font-size: 0.75rem; + color: #000; + background-color: rgba(40, 167, 69, 0.9); + border-radius: 0.2rem; +} + +.was-validated :valid ~ .valid-feedback, +.was-validated :valid ~ .valid-tooltip, +.is-valid ~ .valid-feedback, +.is-valid ~ .valid-tooltip { + display: block; +} + +.was-validated .form-control:valid, .form-control.is-valid { + border-color: #28a745; +} + +.was-validated .form-control:valid:focus, .form-control.is-valid:focus { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .form-select:valid, .form-select.is-valid { + border-color: #28a745; +} + +.was-validated .form-select:valid:focus, .form-select.is-valid:focus { + border-color: #28a745; + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .form-check-input:valid, .form-check-input.is-valid { + border-color: #28a745; +} + +.was-validated .form-check-input:valid:checked, .form-check-input.is-valid:checked { + background-color: #28a745; +} + +.was-validated .form-check-input:valid:focus, .form-check-input.is-valid:focus { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.25); +} + +.was-validated .form-check-input:valid ~ .form-check-label, .form-check-input.is-valid ~ .form-check-label { + color: #28a745; +} + +.form-check-inline .form-check-input ~ .valid-feedback { + margin-left: .5em; +} + +.was-validated .input-group .form-control:valid, .input-group .form-control.is-valid, .was-validated +.input-group .form-select:valid, +.input-group .form-select.is-valid { + z-index: 1; +} + +.was-validated .input-group .form-control:valid:focus, .input-group .form-control.is-valid:focus, .was-validated +.input-group .form-select:valid:focus, +.input-group .form-select.is-valid:focus { + z-index: 3; +} + +.invalid-feedback { + display: none; + width: 100%; + margin-top: 0.25rem; + font-size: 80%; + color: #dc3545; +} + +.invalid-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; + padding: 0.25rem 0.5rem; + margin-top: .1rem; + font-size: 0.75rem; + color: #fff; + background-color: rgba(220, 53, 69, 0.9); + border-radius: 0.2rem; +} + +.was-validated :invalid ~ .invalid-feedback, +.was-validated :invalid ~ .invalid-tooltip, +.is-invalid ~ .invalid-feedback, +.is-invalid ~ .invalid-tooltip { + display: block; +} + +.was-validated .form-control:invalid, .form-control.is-invalid { + border-color: #dc3545; +} + +.was-validated .form-control:invalid:focus, .form-control.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .form-select:invalid, .form-select.is-invalid { + border-color: #dc3545; +} + +.was-validated .form-select:invalid:focus, .form-select.is-invalid:focus { + border-color: #dc3545; + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .form-check-input:invalid, .form-check-input.is-invalid { + border-color: #dc3545; +} + +.was-validated .form-check-input:invalid:checked, .form-check-input.is-invalid:checked { + background-color: #dc3545; +} + +.was-validated .form-check-input:invalid:focus, .form-check-input.is-invalid:focus { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); +} + +.was-validated .form-check-input:invalid ~ .form-check-label, .form-check-input.is-invalid ~ .form-check-label { + color: #dc3545; +} + +.form-check-inline .form-check-input ~ .invalid-feedback { + margin-left: .5em; +} + +.was-validated .input-group .form-control:invalid, .input-group .form-control.is-invalid, .was-validated +.input-group .form-select:invalid, +.input-group .form-select.is-invalid { + z-index: 2; +} + +.was-validated .input-group .form-control:invalid:focus, .input-group .form-control.is-invalid:focus, .was-validated +.input-group .form-select:invalid:focus, +.input-group .form-select.is-invalid:focus { + z-index: 3; +} + +.btn { + display: inline-block; + font-weight: 400; + line-height: 1.5; + color: #495057; + text-align: center; + vertical-align: middle; + cursor: pointer; + user-select: none; + background-color: transparent; + border: 1px solid transparent; + padding: 0.25rem 0.7rem; + font-size: 0.875rem; + border-radius: 0.2rem; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .btn { + transition: none; + } +} + +.btn:hover { + color: #495057; + text-decoration: none; +} + +.btn-check:focus + .btn, .btn:focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.btn:disabled, .btn.disabled, +fieldset:disabled .btn { + pointer-events: none; + opacity: 0.65; +} + +.btn-primary { + color: #000; + background-color: #3B7DDD; + border-color: #3B7DDD; +} + +.btn-primary:hover { + color: #000; + background-color: #5891e2; + border-color: #4f8ae0; +} + +.btn-check:focus + .btn-primary, .btn-primary:focus { + color: #000; + background-color: #5891e2; + border-color: #4f8ae0; + box-shadow: 0 0 0 0.2rem rgba(50, 106, 188, 0.5); +} + +.btn-check:checked + .btn-primary, +.btn-check:active + .btn-primary, .btn-primary:active, .btn-primary.active, +.show > .btn-primary.dropdown-toggle { + color: #000; + background-color: #6297e4; + border-color: #4f8ae0; +} + +.btn-check:checked + .btn-primary:focus, +.btn-check:active + .btn-primary:focus, .btn-primary:active:focus, .btn-primary.active:focus, +.show > .btn-primary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(50, 106, 188, 0.5); +} + +.btn-primary:disabled, .btn-primary.disabled { + color: #000; + background-color: #3B7DDD; + border-color: #3B7DDD; +} + +.btn-secondary { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-secondary:hover { + color: #fff; + background-color: #5c636a; + border-color: #565e64; +} + +.btn-check:focus + .btn-secondary, .btn-secondary:focus { + color: #fff; + background-color: #5c636a; + border-color: #565e64; + box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); +} + +.btn-check:checked + .btn-secondary, +.btn-check:active + .btn-secondary, .btn-secondary:active, .btn-secondary.active, +.show > .btn-secondary.dropdown-toggle { + color: #fff; + background-color: #565e64; + border-color: #51585e; +} + +.btn-check:checked + .btn-secondary:focus, +.btn-check:active + .btn-secondary:focus, .btn-secondary:active:focus, .btn-secondary.active:focus, +.show > .btn-secondary.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(130, 138, 145, 0.5); +} + +.btn-secondary:disabled, .btn-secondary.disabled { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-success { + color: #000; + background-color: #28a745; + border-color: #28a745; +} + +.btn-success:hover { + color: #000; + background-color: #48b461; + border-color: #3eb058; +} + +.btn-check:focus + .btn-success, .btn-success:focus { + color: #000; + background-color: #48b461; + border-color: #3eb058; + box-shadow: 0 0 0 0.2rem rgba(34, 142, 59, 0.5); +} + +.btn-check:checked + .btn-success, +.btn-check:active + .btn-success, .btn-success:active, .btn-success.active, +.show > .btn-success.dropdown-toggle { + color: #000; + background-color: #53b96a; + border-color: #3eb058; +} + +.btn-check:checked + .btn-success:focus, +.btn-check:active + .btn-success:focus, .btn-success:active:focus, .btn-success.active:focus, +.show > .btn-success.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(34, 142, 59, 0.5); +} + +.btn-success:disabled, .btn-success.disabled { + color: #000; + background-color: #28a745; + border-color: #28a745; +} + +.btn-info { + color: #000; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-info:hover { + color: #000; + background-color: #3ab0c3; + border-color: #2eabbf; +} + +.btn-check:focus + .btn-info, .btn-info:focus { + color: #000; + background-color: #3ab0c3; + border-color: #2eabbf; + box-shadow: 0 0 0 0.2rem rgba(20, 138, 156, 0.5); +} + +.btn-check:checked + .btn-info, +.btn-check:active + .btn-info, .btn-info:active, .btn-info.active, +.show > .btn-info.dropdown-toggle { + color: #000; + background-color: #45b5c6; + border-color: #2eabbf; +} + +.btn-check:checked + .btn-info:focus, +.btn-check:active + .btn-info:focus, .btn-info:active:focus, .btn-info.active:focus, +.show > .btn-info.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(20, 138, 156, 0.5); +} + +.btn-info:disabled, .btn-info.disabled { + color: #000; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-warning { + color: #000; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-warning:hover { + color: #000; + background-color: #ffca2c; + border-color: #ffc720; +} + +.btn-check:focus + .btn-warning, .btn-warning:focus { + color: #000; + background-color: #ffca2c; + border-color: #ffc720; + box-shadow: 0 0 0 0.2rem rgba(217, 164, 6, 0.5); +} + +.btn-check:checked + .btn-warning, +.btn-check:active + .btn-warning, .btn-warning:active, .btn-warning.active, +.show > .btn-warning.dropdown-toggle { + color: #000; + background-color: #ffcd39; + border-color: #ffc720; +} + +.btn-check:checked + .btn-warning:focus, +.btn-check:active + .btn-warning:focus, .btn-warning:active:focus, .btn-warning.active:focus, +.show > .btn-warning.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(217, 164, 6, 0.5); +} + +.btn-warning:disabled, .btn-warning.disabled { + color: #000; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-danger { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-danger:hover { + color: #fff; + background-color: #bb2d3b; + border-color: #b02a37; +} + +.btn-check:focus + .btn-danger, .btn-danger:focus { + color: #fff; + background-color: #bb2d3b; + border-color: #b02a37; + box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); +} + +.btn-check:checked + .btn-danger, +.btn-check:active + .btn-danger, .btn-danger:active, .btn-danger.active, +.show > .btn-danger.dropdown-toggle { + color: #fff; + background-color: #b02a37; + border-color: #a52834; +} + +.btn-check:checked + .btn-danger:focus, +.btn-check:active + .btn-danger:focus, .btn-danger:active:focus, .btn-danger.active:focus, +.show > .btn-danger.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(225, 83, 97, 0.5); +} + +.btn-danger:disabled, .btn-danger.disabled { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-light { + color: #000; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-light:hover { + color: #000; + background-color: #f9fafb; + border-color: #f9fafb; +} + +.btn-check:focus + .btn-light, .btn-light:focus { + color: #000; + background-color: #f9fafb; + border-color: #f9fafb; + box-shadow: 0 0 0 0.2rem rgba(211, 212, 213, 0.5); +} + +.btn-check:checked + .btn-light, +.btn-check:active + .btn-light, .btn-light:active, .btn-light.active, +.show > .btn-light.dropdown-toggle { + color: #000; + background-color: #f9fafb; + border-color: #f9fafb; +} + +.btn-check:checked + .btn-light:focus, +.btn-check:active + .btn-light:focus, .btn-light:active:focus, .btn-light.active:focus, +.show > .btn-light.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(211, 212, 213, 0.5); +} + +.btn-light:disabled, .btn-light.disabled { + color: #000; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-dark { + color: #fff; + background-color: #212529; + border-color: #212529; +} + +.btn-dark:hover { + color: #fff; + background-color: #1c1f23; + border-color: #1a1e21; +} + +.btn-check:focus + .btn-dark, .btn-dark:focus { + color: #fff; + background-color: #1c1f23; + border-color: #1a1e21; + box-shadow: 0 0 0 0.2rem rgba(66, 70, 73, 0.5); +} + +.btn-check:checked + .btn-dark, +.btn-check:active + .btn-dark, .btn-dark:active, .btn-dark.active, +.show > .btn-dark.dropdown-toggle { + color: #fff; + background-color: #1a1e21; + border-color: #191c1f; +} + +.btn-check:checked + .btn-dark:focus, +.btn-check:active + .btn-dark:focus, .btn-dark:active:focus, .btn-dark.active:focus, +.show > .btn-dark.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(66, 70, 73, 0.5); +} + +.btn-dark:disabled, .btn-dark.disabled { + color: #fff; + background-color: #212529; + border-color: #212529; +} + +.btn-outline-primary { + color: #3B7DDD; + border-color: #3B7DDD; +} + +.btn-outline-primary:hover { + color: #000; + background-color: #3B7DDD; + border-color: #3B7DDD; +} + +.btn-check:focus + .btn-outline-primary, .btn-outline-primary:focus { + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.5); +} + +.btn-check:checked + .btn-outline-primary, +.btn-check:active + .btn-outline-primary, .btn-outline-primary:active, .btn-outline-primary.active, .btn-outline-primary.dropdown-toggle.show { + color: #000; + background-color: #3B7DDD; + border-color: #3B7DDD; +} + +.btn-check:checked + .btn-outline-primary:focus, +.btn-check:active + .btn-outline-primary:focus, .btn-outline-primary:active:focus, .btn-outline-primary.active:focus, .btn-outline-primary.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.5); +} + +.btn-outline-primary:disabled, .btn-outline-primary.disabled { + color: #3B7DDD; + background-color: transparent; +} + +.btn-outline-secondary { + color: #6c757d; + border-color: #6c757d; +} + +.btn-outline-secondary:hover { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-check:focus + .btn-outline-secondary, .btn-outline-secondary:focus { + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.btn-check:checked + .btn-outline-secondary, +.btn-check:active + .btn-outline-secondary, .btn-outline-secondary:active, .btn-outline-secondary.active, .btn-outline-secondary.dropdown-toggle.show { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; +} + +.btn-check:checked + .btn-outline-secondary:focus, +.btn-check:active + .btn-outline-secondary:focus, .btn-outline-secondary:active:focus, .btn-outline-secondary.active:focus, .btn-outline-secondary.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(108, 117, 125, 0.5); +} + +.btn-outline-secondary:disabled, .btn-outline-secondary.disabled { + color: #6c757d; + background-color: transparent; +} + +.btn-outline-success { + color: #28a745; + border-color: #28a745; +} + +.btn-outline-success:hover { + color: #000; + background-color: #28a745; + border-color: #28a745; +} + +.btn-check:focus + .btn-outline-success, .btn-outline-success:focus { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.btn-check:checked + .btn-outline-success, +.btn-check:active + .btn-outline-success, .btn-outline-success:active, .btn-outline-success.active, .btn-outline-success.dropdown-toggle.show { + color: #000; + background-color: #28a745; + border-color: #28a745; +} + +.btn-check:checked + .btn-outline-success:focus, +.btn-check:active + .btn-outline-success:focus, .btn-outline-success:active:focus, .btn-outline-success.active:focus, .btn-outline-success.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(40, 167, 69, 0.5); +} + +.btn-outline-success:disabled, .btn-outline-success.disabled { + color: #28a745; + background-color: transparent; +} + +.btn-outline-info { + color: #17a2b8; + border-color: #17a2b8; +} + +.btn-outline-info:hover { + color: #000; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-check:focus + .btn-outline-info, .btn-outline-info:focus { + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.btn-check:checked + .btn-outline-info, +.btn-check:active + .btn-outline-info, .btn-outline-info:active, .btn-outline-info.active, .btn-outline-info.dropdown-toggle.show { + color: #000; + background-color: #17a2b8; + border-color: #17a2b8; +} + +.btn-check:checked + .btn-outline-info:focus, +.btn-check:active + .btn-outline-info:focus, .btn-outline-info:active:focus, .btn-outline-info.active:focus, .btn-outline-info.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(23, 162, 184, 0.5); +} + +.btn-outline-info:disabled, .btn-outline-info.disabled { + color: #17a2b8; + background-color: transparent; +} + +.btn-outline-warning { + color: #ffc107; + border-color: #ffc107; +} + +.btn-outline-warning:hover { + color: #000; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-check:focus + .btn-outline-warning, .btn-outline-warning:focus { + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.btn-check:checked + .btn-outline-warning, +.btn-check:active + .btn-outline-warning, .btn-outline-warning:active, .btn-outline-warning.active, .btn-outline-warning.dropdown-toggle.show { + color: #000; + background-color: #ffc107; + border-color: #ffc107; +} + +.btn-check:checked + .btn-outline-warning:focus, +.btn-check:active + .btn-outline-warning:focus, .btn-outline-warning:active:focus, .btn-outline-warning.active:focus, .btn-outline-warning.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(255, 193, 7, 0.5); +} + +.btn-outline-warning:disabled, .btn-outline-warning.disabled { + color: #ffc107; + background-color: transparent; +} + +.btn-outline-danger { + color: #dc3545; + border-color: #dc3545; +} + +.btn-outline-danger:hover { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-check:focus + .btn-outline-danger, .btn-outline-danger:focus { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.btn-check:checked + .btn-outline-danger, +.btn-check:active + .btn-outline-danger, .btn-outline-danger:active, .btn-outline-danger.active, .btn-outline-danger.dropdown-toggle.show { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; +} + +.btn-check:checked + .btn-outline-danger:focus, +.btn-check:active + .btn-outline-danger:focus, .btn-outline-danger:active:focus, .btn-outline-danger.active:focus, .btn-outline-danger.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.5); +} + +.btn-outline-danger:disabled, .btn-outline-danger.disabled { + color: #dc3545; + background-color: transparent; +} + +.btn-outline-light { + color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-outline-light:hover { + color: #000; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-check:focus + .btn-outline-light, .btn-outline-light:focus { + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.btn-check:checked + .btn-outline-light, +.btn-check:active + .btn-outline-light, .btn-outline-light:active, .btn-outline-light.active, .btn-outline-light.dropdown-toggle.show { + color: #000; + background-color: #f8f9fa; + border-color: #f8f9fa; +} + +.btn-check:checked + .btn-outline-light:focus, +.btn-check:active + .btn-outline-light:focus, .btn-outline-light:active:focus, .btn-outline-light.active:focus, .btn-outline-light.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(248, 249, 250, 0.5); +} + +.btn-outline-light:disabled, .btn-outline-light.disabled { + color: #f8f9fa; + background-color: transparent; +} + +.btn-outline-dark { + color: #212529; + border-color: #212529; +} + +.btn-outline-dark:hover { + color: #fff; + background-color: #212529; + border-color: #212529; +} + +.btn-check:focus + .btn-outline-dark, .btn-outline-dark:focus { + box-shadow: 0 0 0 0.2rem rgba(33, 37, 41, 0.5); +} + +.btn-check:checked + .btn-outline-dark, +.btn-check:active + .btn-outline-dark, .btn-outline-dark:active, .btn-outline-dark.active, .btn-outline-dark.dropdown-toggle.show { + color: #fff; + background-color: #212529; + border-color: #212529; +} + +.btn-check:checked + .btn-outline-dark:focus, +.btn-check:active + .btn-outline-dark:focus, .btn-outline-dark:active:focus, .btn-outline-dark.active:focus, .btn-outline-dark.dropdown-toggle.show:focus { + box-shadow: 0 0 0 0.2rem rgba(33, 37, 41, 0.5); +} + +.btn-outline-dark:disabled, .btn-outline-dark.disabled { + color: #212529; + background-color: transparent; +} + +.btn-link { + font-weight: 400; + color: #3B7DDD; + text-decoration: none; +} + +.btn-link:hover { + color: #2f64b1; + text-decoration: underline; +} + +.btn-link:focus { + text-decoration: underline; +} + +.btn-link:disabled, .btn-link.disabled { + color: #6c757d; +} + +.btn-lg, .btn-group-lg > .btn { + padding: 0.35rem 1rem; + font-size: 0.925rem; + border-radius: 0.3rem; +} + +.btn-sm, .btn-group-sm > .btn { + padding: 0.15rem 0.5rem; + font-size: 0.75rem; + border-radius: 0.1rem; +} + +.fade { + transition: opacity 0.15s linear; +} + +@media (prefers-reduced-motion: reduce) { + .fade { + transition: none; + } +} + +.fade:not(.show) { + opacity: 0; +} + +.collapse:not(.show) { + display: none; +} + +.collapsing { + height: 0; + overflow: hidden; + transition: height 0.35s ease; +} + +@media (prefers-reduced-motion: reduce) { + .collapsing { + transition: none; + } +} + +.collapsing.collapse-horizontal { + width: 0; + height: auto; + transition: width 0.35s ease; +} + +@media (prefers-reduced-motion: reduce) { + .collapsing.collapse-horizontal { + transition: none; + } +} + +.dropup, +.dropend, +.dropdown, +.dropstart { + position: relative; +} + +.dropdown-toggle { + white-space: nowrap; +} + +.dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid; + border-right: 0.3em solid transparent; + border-bottom: 0; + border-left: 0.3em solid transparent; +} + +.dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropdown-menu { + position: absolute; + z-index: 1000; + display: none; + min-width: 10rem; + padding: 0.5rem 0; + margin: 0; + font-size: 0.875rem; + color: #495057; + text-align: left; + list-style: none; + background-color: #fff; + background-clip: padding-box; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 0.2rem; +} + +.dropdown-menu[data-bs-popper] { + top: 100%; + left: 0; + margin-top: 0.125rem; +} + +.dropdown-menu-start { + --bs-position: start; +} + +.dropdown-menu-start[data-bs-popper] { + right: auto; + left: 0; +} + +.dropdown-menu-end { + --bs-position: end; +} + +.dropdown-menu-end[data-bs-popper] { + right: 0; + left: auto; +} + +@media (min-width: 576px) { + .dropdown-menu-sm-start { + --bs-position: start; + } + .dropdown-menu-sm-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-sm-end { + --bs-position: end; + } + .dropdown-menu-sm-end[data-bs-popper] { + right: 0; + left: auto; + } +} + +@media (min-width: 768px) { + .dropdown-menu-md-start { + --bs-position: start; + } + .dropdown-menu-md-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-md-end { + --bs-position: end; + } + .dropdown-menu-md-end[data-bs-popper] { + right: 0; + left: auto; + } +} + +@media (min-width: 992px) { + .dropdown-menu-lg-start { + --bs-position: start; + } + .dropdown-menu-lg-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-lg-end { + --bs-position: end; + } + .dropdown-menu-lg-end[data-bs-popper] { + right: 0; + left: auto; + } +} + +@media (min-width: 1200px) { + .dropdown-menu-xl-start { + --bs-position: start; + } + .dropdown-menu-xl-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-xl-end { + --bs-position: end; + } + .dropdown-menu-xl-end[data-bs-popper] { + right: 0; + left: auto; + } +} + +@media (min-width: 1440px) { + .dropdown-menu-xxl-start { + --bs-position: start; + } + .dropdown-menu-xxl-start[data-bs-popper] { + right: auto; + left: 0; + } + .dropdown-menu-xxl-end { + --bs-position: end; + } + .dropdown-menu-xxl-end[data-bs-popper] { + right: 0; + left: auto; + } +} + +.dropup .dropdown-menu[data-bs-popper] { + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: 0.125rem; +} + +.dropup .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0; + border-right: 0.3em solid transparent; + border-bottom: 0.3em solid; + border-left: 0.3em solid transparent; +} + +.dropup .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropend .dropdown-menu[data-bs-popper] { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: 0.125rem; +} + +.dropend .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0; + border-bottom: 0.3em solid transparent; + border-left: 0.3em solid; +} + +.dropend .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropend .dropdown-toggle::after { + vertical-align: 0; +} + +.dropstart .dropdown-menu[data-bs-popper] { + top: 0; + right: 100%; + left: auto; + margin-top: 0; + margin-right: 0.125rem; +} + +.dropstart .dropdown-toggle::after { + display: inline-block; + margin-left: 0.255em; + vertical-align: 0.255em; + content: ""; +} + +.dropstart .dropdown-toggle::after { + display: none; +} + +.dropstart .dropdown-toggle::before { + display: inline-block; + margin-right: 0.255em; + vertical-align: 0.255em; + content: ""; + border-top: 0.3em solid transparent; + border-right: 0.3em solid; + border-bottom: 0.3em solid transparent; +} + +.dropstart .dropdown-toggle:empty::after { + margin-left: 0; +} + +.dropstart .dropdown-toggle::before { + vertical-align: 0; +} + +.dropdown-divider { + height: 0; + margin: 0.5rem 0; + overflow: hidden; + border-top: 1px solid rgba(0, 0, 0, 0.15); +} + +.dropdown-item { + display: block; + width: 100%; + padding: 0.35rem 1.5rem; + clear: both; + font-weight: 400; + color: #495057; + text-align: inherit; + white-space: nowrap; + background-color: transparent; + border: 0; +} + +.dropdown-item:hover, .dropdown-item:focus { + color: #42484e; + text-decoration: none; + background-color: #f8f9fa; +} + +.dropdown-item.active, .dropdown-item:active { + color: #fff; + text-decoration: none; + background-color: #3B7DDD; +} + +.dropdown-item.disabled, .dropdown-item:disabled { + color: #adb5bd; + pointer-events: none; + background-color: transparent; +} + +.dropdown-menu.show { + display: block; +} + +.dropdown-header { + display: block; + padding: 0.5rem 1.5rem; + margin-bottom: 0; + font-size: 0.75rem; + color: #6c757d; + white-space: nowrap; +} + +.dropdown-item-text { + display: block; + padding: 0.35rem 1.5rem; + color: #495057; +} + +.dropdown-menu-dark { + color: #dee2e6; + background-color: #343a40; + border-color: rgba(0, 0, 0, 0.15); +} + +.dropdown-menu-dark .dropdown-item { + color: #dee2e6; +} + +.dropdown-menu-dark .dropdown-item:hover, .dropdown-menu-dark .dropdown-item:focus { + color: #fff; + background-color: rgba(255, 255, 255, 0.15); +} + +.dropdown-menu-dark .dropdown-item.active, .dropdown-menu-dark .dropdown-item:active { + color: #fff; + background-color: #3B7DDD; +} + +.dropdown-menu-dark .dropdown-item.disabled, .dropdown-menu-dark .dropdown-item:disabled { + color: #adb5bd; +} + +.dropdown-menu-dark .dropdown-divider { + border-color: rgba(0, 0, 0, 0.15); +} + +.dropdown-menu-dark .dropdown-item-text { + color: #dee2e6; +} + +.dropdown-menu-dark .dropdown-header { + color: #adb5bd; +} + +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-flex; + vertical-align: middle; +} + +.btn-group > .btn, +.btn-group-vertical > .btn { + position: relative; + flex: 1 1 auto; +} + +.btn-group > .btn-check:checked + .btn, +.btn-group > .btn-check:focus + .btn, +.btn-group > .btn:hover, +.btn-group > .btn:focus, +.btn-group > .btn:active, +.btn-group > .btn.active, +.btn-group-vertical > .btn-check:checked + .btn, +.btn-group-vertical > .btn-check:focus + .btn, +.btn-group-vertical > .btn:hover, +.btn-group-vertical > .btn:focus, +.btn-group-vertical > .btn:active, +.btn-group-vertical > .btn.active { + z-index: 1; +} + +.btn-toolbar { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; +} + +.btn-toolbar .input-group { + width: auto; +} + +.btn-group > .btn:not(:first-child), +.btn-group > .btn-group:not(:first-child) { + margin-left: -1px; +} + +.btn-group > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group > .btn-group:not(:last-child) > .btn { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.btn-group > .btn:nth-child(n + 3), +.btn-group > :not(.btn-check) + .btn, +.btn-group > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +.dropdown-toggle-split { + padding-right: 0.525rem; + padding-left: 0.525rem; +} + +.dropdown-toggle-split::after, +.dropup .dropdown-toggle-split::after, +.dropend .dropdown-toggle-split::after { + margin-left: 0; +} + +.dropstart .dropdown-toggle-split::before { + margin-right: 0; +} + +.btn-sm + .dropdown-toggle-split, .btn-group-sm > .btn + .dropdown-toggle-split { + padding-right: 0.375rem; + padding-left: 0.375rem; +} + +.btn-lg + .dropdown-toggle-split, .btn-group-lg > .btn + .dropdown-toggle-split { + padding-right: 0.75rem; + padding-left: 0.75rem; +} + +.btn-group-vertical { + flex-direction: column; + align-items: flex-start; + justify-content: center; +} + +.btn-group-vertical > .btn, +.btn-group-vertical > .btn-group { + width: 100%; +} + +.btn-group-vertical > .btn:not(:first-child), +.btn-group-vertical > .btn-group:not(:first-child) { + margin-top: -1px; +} + +.btn-group-vertical > .btn:not(:last-child):not(.dropdown-toggle), +.btn-group-vertical > .btn-group:not(:last-child) > .btn { + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.btn-group-vertical > .btn ~ .btn, +.btn-group-vertical > .btn-group:not(:first-child) > .btn { + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav { + display: flex; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav-link { + display: block; + padding: 0.5rem 1rem; + color: #3B7DDD; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .nav-link { + transition: none; + } +} + +.nav-link:hover, .nav-link:focus { + color: #2f64b1; + text-decoration: none; +} + +.nav-link.disabled { + color: #6c757d; + pointer-events: none; + cursor: default; +} + +.nav-tabs { + border-bottom: 1px solid #dee2e6; +} + +.nav-tabs .nav-link { + margin-bottom: -1px; + background: none; + border: 1px solid transparent; + border-top-left-radius: 0.2rem; + border-top-right-radius: 0.2rem; +} + +.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus { + border-color: #e9ecef #e9ecef #dee2e6; + isolation: isolate; +} + +.nav-tabs .nav-link.disabled { + color: #6c757d; + background-color: transparent; + border-color: transparent; +} + +.nav-tabs .nav-link.active, +.nav-tabs .nav-item.show .nav-link { + color: #495057; + background-color: #F7F7FC; + border-color: #dee2e6 #dee2e6 #F7F7FC; +} + +.nav-tabs .dropdown-menu { + margin-top: -1px; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.nav-pills .nav-link { + background: none; + border: 0; + border-radius: 0.2rem; +} + +.nav-pills .nav-link.active, +.nav-pills .show > .nav-link { + color: #fff; + background-color: #3B7DDD; +} + +.nav-fill > .nav-link, +.nav-fill .nav-item { + flex: 1 1 auto; + text-align: center; +} + +.nav-justified > .nav-link, +.nav-justified .nav-item { + flex-basis: 0; + flex-grow: 1; + text-align: center; +} + +.nav-fill .nav-item .nav-link, +.nav-justified .nav-item .nav-link { + width: 100%; +} + +.tab-content > .tab-pane { + display: none; +} + +.tab-content > .active { + display: block; +} + +.navbar { + position: relative; + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + padding-top: 0.875rem; + padding-right: 1.375rem; + padding-bottom: 0.875rem; + padding-left: 1.375rem; +} + +.navbar > .container, +.navbar > .container-fluid, .navbar > .container-sm, .navbar > .container-md, .navbar > .container-lg, .navbar > .container-xl { + display: flex; + flex-wrap: inherit; + align-items: center; + justify-content: space-between; +} + +.navbar-brand { + padding-top: 0.875rem; + padding-bottom: 0.875rem; + margin-right: 1rem; + font-size: 1.15rem; + white-space: nowrap; +} + +.navbar-brand:hover, .navbar-brand:focus { + text-decoration: none; +} + +.navbar-nav { + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.navbar-nav .nav-link { + padding-right: 0; + padding-left: 0; +} + +.navbar-nav .dropdown-menu { + position: static; +} + +.navbar-text { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.navbar-collapse { + flex-basis: 100%; + flex-grow: 1; + align-items: center; +} + +.navbar-toggler { + padding: 0.25rem 0.75rem; + font-size: 0.925rem; + line-height: 1; + background-color: transparent; + border: 1px solid transparent; + border-radius: 0.2rem; + transition: box-shadow 0.15s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .navbar-toggler { + transition: none; + } +} + +.navbar-toggler:hover { + text-decoration: none; +} + +.navbar-toggler:focus { + text-decoration: none; + outline: 0; + box-shadow: 0 0 0 0.2rem; +} + +.navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + background-repeat: no-repeat; + background-position: center; + background-size: 100%; +} + +.navbar-nav-scroll { + max-height: var(--bs-scroll-height, 75vh); + overflow-y: auto; +} + +@media (min-width: 576px) { + .navbar-expand-sm { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-sm .navbar-nav { + flex-direction: row; + } + .navbar-expand-sm .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-sm .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-sm .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-sm .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-sm .navbar-toggler { + display: none; + } + .navbar-expand-sm .offcanvas-header { + display: none; + } + .navbar-expand-sm .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-sm .offcanvas-top, + .navbar-expand-sm .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-sm .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} + +@media (min-width: 768px) { + .navbar-expand-md { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-md .navbar-nav { + flex-direction: row; + } + .navbar-expand-md .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-md .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-md .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-md .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-md .navbar-toggler { + display: none; + } + .navbar-expand-md .offcanvas-header { + display: none; + } + .navbar-expand-md .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-md .offcanvas-top, + .navbar-expand-md .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-md .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} + +@media (min-width: 992px) { + .navbar-expand-lg { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-lg .navbar-nav { + flex-direction: row; + } + .navbar-expand-lg .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-lg .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-lg .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-lg .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-lg .navbar-toggler { + display: none; + } + .navbar-expand-lg .offcanvas-header { + display: none; + } + .navbar-expand-lg .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-lg .offcanvas-top, + .navbar-expand-lg .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-lg .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} + +@media (min-width: 1200px) { + .navbar-expand-xl { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-xl .navbar-nav { + flex-direction: row; + } + .navbar-expand-xl .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-xl .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-xl .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-xl .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-xl .navbar-toggler { + display: none; + } + .navbar-expand-xl .offcanvas-header { + display: none; + } + .navbar-expand-xl .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-xl .offcanvas-top, + .navbar-expand-xl .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-xl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} + +@media (min-width: 1440px) { + .navbar-expand-xxl { + flex-wrap: nowrap; + justify-content: flex-start; + } + .navbar-expand-xxl .navbar-nav { + flex-direction: row; + } + .navbar-expand-xxl .navbar-nav .dropdown-menu { + position: absolute; + } + .navbar-expand-xxl .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; + } + .navbar-expand-xxl .navbar-nav-scroll { + overflow: visible; + } + .navbar-expand-xxl .navbar-collapse { + display: flex !important; + flex-basis: auto; + } + .navbar-expand-xxl .navbar-toggler { + display: none; + } + .navbar-expand-xxl .offcanvas-header { + display: none; + } + .navbar-expand-xxl .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; + } + .navbar-expand-xxl .offcanvas-top, + .navbar-expand-xxl .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; + } + .navbar-expand-xxl .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } +} + +.navbar-expand { + flex-wrap: nowrap; + justify-content: flex-start; +} + +.navbar-expand .navbar-nav { + flex-direction: row; +} + +.navbar-expand .navbar-nav .dropdown-menu { + position: absolute; +} + +.navbar-expand .navbar-nav .nav-link { + padding-right: 0.5rem; + padding-left: 0.5rem; +} + +.navbar-expand .navbar-nav-scroll { + overflow: visible; +} + +.navbar-expand .navbar-collapse { + display: flex !important; + flex-basis: auto; +} + +.navbar-expand .navbar-toggler { + display: none; +} + +.navbar-expand .offcanvas-header { + display: none; +} + +.navbar-expand .offcanvas { + position: inherit; + bottom: 0; + z-index: 1000; + flex-grow: 1; + visibility: visible !important; + background-color: transparent; + border-right: 0; + border-left: 0; + transition: none; + transform: none; +} + +.navbar-expand .offcanvas-top, +.navbar-expand .offcanvas-bottom { + height: auto; + border-top: 0; + border-bottom: 0; +} + +.navbar-expand .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; +} + +.navbar-light .navbar-brand { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-brand:hover, .navbar-light .navbar-brand:focus { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-nav .nav-link { + color: rgba(0, 0, 0, 0.55); +} + +.navbar-light .navbar-nav .nav-link:hover, .navbar-light .navbar-nav .nav-link:focus { + color: rgba(0, 0, 0, 0.7); +} + +.navbar-light .navbar-nav .nav-link.disabled { + color: rgba(0, 0, 0, 0.3); +} + +.navbar-light .navbar-nav .show > .nav-link, +.navbar-light .navbar-nav .nav-link.active { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-light .navbar-toggler { + color: rgba(0, 0, 0, 0.55); + border-color: rgba(0, 0, 0, 0.1); +} + +.navbar-light .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%280, 0, 0, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.navbar-light .navbar-text { + color: rgba(0, 0, 0, 0.55); +} + +.navbar-light .navbar-text a, +.navbar-light .navbar-text a:hover, +.navbar-light .navbar-text a:focus { + color: rgba(0, 0, 0, 0.9); +} + +.navbar-dark .navbar-brand { + color: #fff; +} + +.navbar-dark .navbar-brand:hover, .navbar-dark .navbar-brand:focus { + color: #fff; +} + +.navbar-dark .navbar-nav .nav-link { + color: rgba(255, 255, 255, 0.55); +} + +.navbar-dark .navbar-nav .nav-link:hover, .navbar-dark .navbar-nav .nav-link:focus { + color: rgba(255, 255, 255, 0.75); +} + +.navbar-dark .navbar-nav .nav-link.disabled { + color: rgba(255, 255, 255, 0.25); +} + +.navbar-dark .navbar-nav .show > .nav-link, +.navbar-dark .navbar-nav .nav-link.active { + color: #fff; +} + +.navbar-dark .navbar-toggler { + color: rgba(255, 255, 255, 0.55); + border-color: rgba(255, 255, 255, 0.1); +} + +.navbar-dark .navbar-toggler-icon { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"); +} + +.navbar-dark .navbar-text { + color: rgba(255, 255, 255, 0.55); +} + +.navbar-dark .navbar-text a, +.navbar-dark .navbar-text a:hover, +.navbar-dark .navbar-text a:focus { + color: #fff; +} + +.card { + position: relative; + display: flex; + flex-direction: column; + min-width: 0; + word-wrap: break-word; + background-color: #fff; + background-clip: border-box; + border: 0 solid transparent; + border-radius: 0.25rem; +} + +.card > hr { + margin-right: 0; + margin-left: 0; +} + +.card > .list-group { + border-top: inherit; + border-bottom: inherit; +} + +.card > .list-group:first-child { + border-top-width: 0; + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.card > .list-group:last-child { + border-bottom-width: 0; + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.card > .card-header + .list-group, +.card > .list-group + .card-footer { + border-top: 0; +} + +.card-body { + flex: 1 1 auto; + padding: 1.25rem 1.25rem; +} + +.card-title { + margin-bottom: 0.5rem; +} + +.card-subtitle { + margin-top: -0.25rem; + margin-bottom: 0; +} + +.card-text:last-child { + margin-bottom: 0; +} + +.card-link:hover { + text-decoration: none; +} + +.card-link + .card-link { + margin-left: 1.25rem; +} + +.card-header { + padding: 1rem 1.25rem; + margin-bottom: 0; + background-color: #fff; + border-bottom: 0 solid transparent; +} + +.card-header:first-child { + border-radius: 0.25rem 0.25rem 0 0; +} + +.card-footer { + padding: 1rem 1.25rem; + background-color: #fff; + border-top: 0 solid transparent; +} + +.card-footer:last-child { + border-radius: 0 0 0.25rem 0.25rem; +} + +.card-header-tabs { + margin-right: -0.625rem; + margin-bottom: -1rem; + margin-left: -0.625rem; + border-bottom: 0; +} + +.card-header-tabs .nav-link.active { + background-color: #fff; + border-bottom-color: #fff; +} + +.card-header-pills { + margin-right: -0.625rem; + margin-left: -0.625rem; +} + +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: 1rem; + border-radius: 0.25rem; +} + +.card-img, +.card-img-top, +.card-img-bottom { + width: 100%; +} + +.card-img, +.card-img-top { + border-top-left-radius: 0.25rem; + border-top-right-radius: 0.25rem; +} + +.card-img, +.card-img-bottom { + border-bottom-right-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.card-group > .card { + margin-bottom: 12px; +} + +@media (min-width: 576px) { + .card-group { + display: flex; + flex-flow: row wrap; + } + .card-group > .card { + flex: 1 0 0%; + margin-bottom: 0; + } + .card-group > .card + .card { + margin-left: 0; + border-left: 0; + } + .card-group > .card:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-top, + .card-group > .card:not(:last-child) .card-header { + border-top-right-radius: 0; + } + .card-group > .card:not(:last-child) .card-img-bottom, + .card-group > .card:not(:last-child) .card-footer { + border-bottom-right-radius: 0; + } + .card-group > .card:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-top, + .card-group > .card:not(:first-child) .card-header { + border-top-left-radius: 0; + } + .card-group > .card:not(:first-child) .card-img-bottom, + .card-group > .card:not(:first-child) .card-footer { + border-bottom-left-radius: 0; + } +} + +.breadcrumb { + display: flex; + flex-wrap: wrap; + padding: 0 0; + margin-bottom: 1rem; + list-style: none; +} + +.breadcrumb-item + .breadcrumb-item { + padding-left: 0.5rem; +} + +.breadcrumb-item + .breadcrumb-item::before { + float: left; + padding-right: 0.5rem; + color: #6c757d; + content: var(--bs-breadcrumb-divider, "/") /* rtl: var(--bs-breadcrumb-divider, "/") */; +} + +.breadcrumb-item.active { + color: #6c757d; +} + +.badge { + display: inline-block; + padding: 0.3em 0.45em; + font-size: 80%; + font-weight: 600; + line-height: 1; + color: #fff; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: 0.2rem; +} + +.badge:empty { + display: none; +} + +.btn .badge { + position: relative; + top: -1px; +} + +.alert { + position: relative; + padding: 0.95rem 0.95rem; + margin-bottom: 1rem; + border: 0 solid transparent; + border-radius: 0.2rem; +} + +.alert-heading { + color: inherit; +} + +.alert-link { + font-weight: 600; +} + +.alert-dismissible { + padding-right: 2.85rem; +} + +.alert-dismissible .btn-close { + position: absolute; + top: 0; + right: 0; + z-index: 2; + padding: 1.1875rem 0.95rem; +} + +.alert-primary { + color: #234b85; + background-color: #d8e5f8; + border-color: #c4d8f5; +} + +.alert-primary .alert-link { + color: #1c3c6a; +} + +.alert-secondary { + color: #41464b; + background-color: #e2e3e5; + border-color: #d3d6d8; +} + +.alert-secondary .alert-link { + color: #34383c; +} + +.alert-success { + color: #186429; + background-color: #d4edda; + border-color: #bfe5c7; +} + +.alert-success .alert-link { + color: #135021; +} + +.alert-info { + color: #0e616e; + background-color: #d1ecf1; + border-color: #b9e3ea; +} + +.alert-info .alert-link { + color: #0b4e58; +} + +.alert-warning { + color: #664d03; + background-color: #fff3cd; + border-color: #ffecb5; +} + +.alert-warning .alert-link { + color: #523e02; +} + +.alert-danger { + color: #842029; + background-color: #f8d7da; + border-color: #f5c2c7; +} + +.alert-danger .alert-link { + color: #6a1a21; +} + +.alert-light { + color: #636464; + background-color: #fefefe; + border-color: #fdfdfe; +} + +.alert-light .alert-link { + color: #4f5050; +} + +.alert-dark { + color: #141619; + background-color: #d3d3d4; + border-color: #bcbebf; +} + +.alert-dark .alert-link { + color: #101214; +} + +.list-group { + display: flex; + flex-direction: column; + padding-left: 0; + margin-bottom: 0; + border-radius: 0.2rem; +} + +.list-group-numbered { + list-style-type: none; + counter-reset: section; +} + +.list-group-numbered > li::before { + content: counters(section, ".") ". "; + counter-increment: section; +} + +.list-group-item-action { + width: 100%; + color: #495057; + text-align: inherit; +} + +.list-group-item-action:hover, .list-group-item-action:focus { + z-index: 1; + color: #495057; + text-decoration: none; + background-color: #f8f9fa; +} + +.list-group-item-action:active { + color: #495057; + background-color: #e9ecef; +} + +.list-group-item { + position: relative; + display: block; + padding: 0.75rem 1.25rem; + color: #212529; + background-color: #fff; + border: 1px solid rgba(0, 0, 0, 0.125); +} + +.list-group-item:first-child { + border-top-left-radius: inherit; + border-top-right-radius: inherit; +} + +.list-group-item:last-child { + border-bottom-right-radius: inherit; + border-bottom-left-radius: inherit; +} + +.list-group-item.disabled, .list-group-item:disabled { + color: #6c757d; + pointer-events: none; + background-color: #fff; +} + +.list-group-item.active { + z-index: 2; + color: #fff; + background-color: #3B7DDD; + border-color: #3B7DDD; +} + +.list-group-item + .list-group-item { + border-top-width: 0; +} + +.list-group-item + .list-group-item.active { + margin-top: -1px; + border-top-width: 1px; +} + +.list-group-horizontal { + flex-direction: row; +} + +.list-group-horizontal > .list-group-item:first-child { + border-bottom-left-radius: 0.2rem; + border-top-right-radius: 0; +} + +.list-group-horizontal > .list-group-item:last-child { + border-top-right-radius: 0.2rem; + border-bottom-left-radius: 0; +} + +.list-group-horizontal > .list-group-item.active { + margin-top: 0; +} + +.list-group-horizontal > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; +} + +.list-group-horizontal > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; +} + +@media (min-width: 576px) { + .list-group-horizontal-sm { + flex-direction: row; + } + .list-group-horizontal-sm > .list-group-item:first-child { + border-bottom-left-radius: 0.2rem; + border-top-right-radius: 0; + } + .list-group-horizontal-sm > .list-group-item:last-child { + border-top-right-radius: 0.2rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-sm > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-sm > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-sm > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 768px) { + .list-group-horizontal-md { + flex-direction: row; + } + .list-group-horizontal-md > .list-group-item:first-child { + border-bottom-left-radius: 0.2rem; + border-top-right-radius: 0; + } + .list-group-horizontal-md > .list-group-item:last-child { + border-top-right-radius: 0.2rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-md > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-md > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-md > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 992px) { + .list-group-horizontal-lg { + flex-direction: row; + } + .list-group-horizontal-lg > .list-group-item:first-child { + border-bottom-left-radius: 0.2rem; + border-top-right-radius: 0; + } + .list-group-horizontal-lg > .list-group-item:last-child { + border-top-right-radius: 0.2rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-lg > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-lg > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-lg > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 1200px) { + .list-group-horizontal-xl { + flex-direction: row; + } + .list-group-horizontal-xl > .list-group-item:first-child { + border-bottom-left-radius: 0.2rem; + border-top-right-radius: 0; + } + .list-group-horizontal-xl > .list-group-item:last-child { + border-top-right-radius: 0.2rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-xl > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-xl > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-xl > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +@media (min-width: 1440px) { + .list-group-horizontal-xxl { + flex-direction: row; + } + .list-group-horizontal-xxl > .list-group-item:first-child { + border-bottom-left-radius: 0.2rem; + border-top-right-radius: 0; + } + .list-group-horizontal-xxl > .list-group-item:last-child { + border-top-right-radius: 0.2rem; + border-bottom-left-radius: 0; + } + .list-group-horizontal-xxl > .list-group-item.active { + margin-top: 0; + } + .list-group-horizontal-xxl > .list-group-item + .list-group-item { + border-top-width: 1px; + border-left-width: 0; + } + .list-group-horizontal-xxl > .list-group-item + .list-group-item.active { + margin-left: -1px; + border-left-width: 1px; + } +} + +.list-group-flush { + border-radius: 0; +} + +.list-group-flush > .list-group-item { + border-width: 0 0 1px; +} + +.list-group-flush > .list-group-item:last-child { + border-bottom-width: 0; +} + +.list-group-item-primary { + color: #234b85; + background-color: #d8e5f8; +} + +.list-group-item-primary.list-group-item-action:hover, .list-group-item-primary.list-group-item-action:focus { + color: #234b85; + background-color: #c2cedf; +} + +.list-group-item-primary.list-group-item-action.active { + color: #fff; + background-color: #234b85; + border-color: #234b85; +} + +.list-group-item-secondary { + color: #41464b; + background-color: #e2e3e5; +} + +.list-group-item-secondary.list-group-item-action:hover, .list-group-item-secondary.list-group-item-action:focus { + color: #41464b; + background-color: #cbccce; +} + +.list-group-item-secondary.list-group-item-action.active { + color: #fff; + background-color: #41464b; + border-color: #41464b; +} + +.list-group-item-success { + color: #186429; + background-color: #d4edda; +} + +.list-group-item-success.list-group-item-action:hover, .list-group-item-success.list-group-item-action:focus { + color: #186429; + background-color: #bfd5c4; +} + +.list-group-item-success.list-group-item-action.active { + color: #fff; + background-color: #186429; + border-color: #186429; +} + +.list-group-item-info { + color: #0e616e; + background-color: #d1ecf1; +} + +.list-group-item-info.list-group-item-action:hover, .list-group-item-info.list-group-item-action:focus { + color: #0e616e; + background-color: #bcd4d9; +} + +.list-group-item-info.list-group-item-action.active { + color: #fff; + background-color: #0e616e; + border-color: #0e616e; +} + +.list-group-item-warning { + color: #664d03; + background-color: #fff3cd; +} + +.list-group-item-warning.list-group-item-action:hover, .list-group-item-warning.list-group-item-action:focus { + color: #664d03; + background-color: #e6dbb9; +} + +.list-group-item-warning.list-group-item-action.active { + color: #fff; + background-color: #664d03; + border-color: #664d03; +} + +.list-group-item-danger { + color: #842029; + background-color: #f8d7da; +} + +.list-group-item-danger.list-group-item-action:hover, .list-group-item-danger.list-group-item-action:focus { + color: #842029; + background-color: #dfc2c4; +} + +.list-group-item-danger.list-group-item-action.active { + color: #fff; + background-color: #842029; + border-color: #842029; +} + +.list-group-item-light { + color: #636464; + background-color: #fefefe; +} + +.list-group-item-light.list-group-item-action:hover, .list-group-item-light.list-group-item-action:focus { + color: #636464; + background-color: #e5e5e5; +} + +.list-group-item-light.list-group-item-action.active { + color: #fff; + background-color: #636464; + border-color: #636464; +} + +.list-group-item-dark { + color: #141619; + background-color: #d3d3d4; +} + +.list-group-item-dark.list-group-item-action:hover, .list-group-item-dark.list-group-item-action:focus { + color: #141619; + background-color: #bebebf; +} + +.list-group-item-dark.list-group-item-action.active { + color: #fff; + background-color: #141619; + border-color: #141619; +} + +.btn-close { + box-sizing: content-box; + width: 1em; + height: 1em; + padding: 0.25em 0.25em; + color: #000; + background: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat; + border: 0; + border-radius: 0.2rem; + opacity: 0.5; +} + +.btn-close:hover { + color: #000; + text-decoration: none; + opacity: 0.75; +} + +.btn-close:focus { + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.25); + opacity: 1; +} + +.btn-close:disabled, .btn-close.disabled { + pointer-events: none; + user-select: none; + opacity: 0.25; +} + +.btn-close-white { + filter: invert(1) grayscale(100%) brightness(200%); +} + +.clearfix::after { + display: block; + clear: both; + content: ""; +} + +.link-primary { + color: #3B7DDD; +} + +.link-primary:hover, .link-primary:focus { + color: #6297e4; +} + +.link-secondary { + color: #6c757d; +} + +.link-secondary:hover, .link-secondary:focus { + color: #565e64; +} + +.link-success { + color: #28a745; +} + +.link-success:hover, .link-success:focus { + color: #53b96a; +} + +.link-info { + color: #17a2b8; +} + +.link-info:hover, .link-info:focus { + color: #45b5c6; +} + +.link-warning { + color: #ffc107; +} + +.link-warning:hover, .link-warning:focus { + color: #ffcd39; +} + +.link-danger { + color: #dc3545; +} + +.link-danger:hover, .link-danger:focus { + color: #b02a37; +} + +.link-light { + color: #f8f9fa; +} + +.link-light:hover, .link-light:focus { + color: #f9fafb; +} + +.link-dark { + color: #212529; +} + +.link-dark:hover, .link-dark:focus { + color: #1a1e21; +} + +.ratio { + position: relative; + width: 100%; +} + +.ratio::before { + display: block; + padding-top: var(--bs-aspect-ratio); + content: ""; +} + +.ratio > * { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.ratio-1x1 { + --bs-aspect-ratio: 100%; +} + +.ratio-4x3 { + --bs-aspect-ratio: calc(3 / 4 * 100%); +} + +.ratio-16x9 { + --bs-aspect-ratio: calc(9 / 16 * 100%); +} + +.ratio-21x9 { + --bs-aspect-ratio: calc(9 / 21 * 100%); +} + +.fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: 1030; +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: 1030; +} + +.sticky-top { + position: sticky; + top: 0; + z-index: 1020; +} + +@media (min-width: 576px) { + .sticky-sm-top { + position: sticky; + top: 0; + z-index: 1020; + } +} + +@media (min-width: 768px) { + .sticky-md-top { + position: sticky; + top: 0; + z-index: 1020; + } +} + +@media (min-width: 992px) { + .sticky-lg-top { + position: sticky; + top: 0; + z-index: 1020; + } +} + +@media (min-width: 1200px) { + .sticky-xl-top { + position: sticky; + top: 0; + z-index: 1020; + } +} + +@media (min-width: 1440px) { + .sticky-xxl-top { + position: sticky; + top: 0; + z-index: 1020; + } +} + +.hstack { + display: flex; + flex-direction: row; + align-items: center; + align-self: stretch; +} + +.vstack { + display: flex; + flex: 1 1 auto; + flex-direction: column; + align-self: stretch; +} + +.visually-hidden, +.visually-hidden-focusable:not(:focus):not(:focus-within) { + position: absolute !important; + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; +} + +.stretched-link::after { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + content: ""; +} + +.text-truncate { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.vr { + display: inline-block; + align-self: stretch; + width: 1px; + min-height: 1em; + background-color: currentColor; + opacity: 0.25; +} + +.accordion-button { + position: relative; + display: flex; + align-items: center; + width: 100%; + padding: 1rem 1.25rem; + font-size: 0.875rem; + color: #495057; + text-align: left; + background-color: #F7F7FC; + border: 0; + border-radius: 0; + overflow-anchor: none; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease; +} + +@media (prefers-reduced-motion: reduce) { + .accordion-button { + transition: none; + } +} + +.accordion-button:not(.collapsed) { + color: #3571c7; + background-color: #ebf2fc; + box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.125); +} + +.accordion-button:not(.collapsed)::after { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%233571c7'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + transform: rotate(-180deg); +} + +.accordion-button::after { + flex-shrink: 0; + width: 1.25rem; + height: 1.25rem; + margin-left: auto; + content: ""; + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23495057'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e"); + background-repeat: no-repeat; + background-size: 1.25rem; + transition: transform 0.2s ease-in-out; +} + +@media (prefers-reduced-motion: reduce) { + .accordion-button::after { + transition: none; + } +} + +.accordion-button:hover { + z-index: 2; +} + +.accordion-button:focus { + z-index: 3; + border-color: #9dbeee; + outline: 0; + box-shadow: 0 0 0 0.2rem rgba(59, 125, 221, 0.25); +} + +.accordion-header { + margin-bottom: 0; +} + +.accordion-item { + background-color: #F7F7FC; + border: 1px solid rgba(0, 0, 0, 0.125); +} + +.accordion-item:first-of-type { + border-top-left-radius: 0.2rem; + border-top-right-radius: 0.2rem; +} + +.accordion-item:first-of-type .accordion-button { + border-top-left-radius: calc(0.2rem - 1px); + border-top-right-radius: calc(0.2rem - 1px); +} + +.accordion-item:not(:first-of-type) { + border-top: 0; +} + +.accordion-item:last-of-type { + border-bottom-right-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; +} + +.accordion-item:last-of-type .accordion-button.collapsed { + border-bottom-right-radius: calc(0.2rem - 1px); + border-bottom-left-radius: calc(0.2rem - 1px); +} + +.accordion-item:last-of-type .accordion-collapse { + border-bottom-right-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; +} + +.accordion-body { + padding: 1rem 1.25rem; +} + +.accordion-flush .accordion-collapse { + border-width: 0; +} + +.accordion-flush .accordion-item { + border-right: 0; + border-left: 0; + border-radius: 0; +} + +.accordion-flush .accordion-item:first-child { + border-top: 0; +} + +.accordion-flush .accordion-item:last-child { + border-bottom: 0; +} + +.accordion-flush .accordion-item .accordion-button { + border-radius: 0; +} + +.modal { + position: fixed; + top: 0; + left: 0; + z-index: 1055; + display: none; + width: 100%; + height: 100%; + overflow-x: hidden; + overflow-y: auto; + outline: 0; +} + +.modal-dialog { + position: relative; + width: auto; + margin: 0.5rem; + pointer-events: none; +} + +.modal.fade .modal-dialog { + transition: transform 0.25s ease-out; + transform: translate(0, -50px); +} + +@media (prefers-reduced-motion: reduce) { + .modal.fade .modal-dialog { + transition: none; + } +} + +.modal.show .modal-dialog { + transform: none; +} + +.modal.modal-static .modal-dialog { + transform: scale(1.02); +} + +.modal-dialog-scrollable { + height: calc(100% - 1rem); +} + +.modal-dialog-scrollable .modal-content { + max-height: 100%; + overflow: hidden; +} + +.modal-dialog-scrollable .modal-body { + overflow-y: auto; +} + +.modal-dialog-centered { + display: flex; + align-items: center; + min-height: calc(100% - 1rem); +} + +.modal-content { + position: relative; + display: flex; + flex-direction: column; + width: 100%; + pointer-events: auto; + background-color: #fff; + background-clip: padding-box; + border: 0 solid rgba(0, 0, 0, 0.2); + border-radius: 0.3rem; + outline: 0; +} + +.modal-backdrop { + position: fixed; + top: 0; + left: 0; + z-index: 1050; + width: 100vw; + height: 100vh; + background-color: #000; +} + +.modal-backdrop.fade { + opacity: 0; +} + +.modal-backdrop.show { + opacity: 0.5; +} + +.modal-header { + display: flex; + flex-shrink: 0; + align-items: center; + justify-content: space-between; + padding: 1rem 1rem; + border-bottom: 1px solid #dee2e6; + border-top-left-radius: 0.3rem; + border-top-right-radius: 0.3rem; +} + +.modal-header .btn-close { + padding: 0.5rem 0.5rem; + margin: -0.5rem -0.5rem -0.5rem auto; +} + +.modal-title { + margin-bottom: 0; + line-height: 1.5; +} + +.modal-body { + position: relative; + flex: 1 1 auto; + padding: 1rem; +} + +.modal-footer { + display: flex; + flex-wrap: wrap; + flex-shrink: 0; + align-items: center; + justify-content: flex-end; + padding: 0.75rem; + border-top: 1px solid #dee2e6; + border-bottom-right-radius: 0.3rem; + border-bottom-left-radius: 0.3rem; +} + +.modal-footer > * { + margin: 0.25rem; +} + +@media (min-width: 576px) { + .modal-dialog { + max-width: 600px; + margin: 1.75rem auto; + } + .modal-dialog-scrollable { + height: calc(100% - 3.5rem); + } + .modal-dialog-centered { + min-height: calc(100% - 3.5rem); + } + .modal-sm { + max-width: 400px; + } +} + +@media (min-width: 992px) { + .modal-lg, + .modal-xl { + max-width: 900px; + } +} + +@media (min-width: 1200px) { + .modal-xl { + max-width: 1140px; + } +} + +.modal-fullscreen { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; +} + +.modal-fullscreen .modal-content { + height: 100%; + border: 0; + border-radius: 0; +} + +.modal-fullscreen .modal-header { + border-radius: 0; +} + +.modal-fullscreen .modal-body { + overflow-y: auto; +} + +.modal-fullscreen .modal-footer { + border-radius: 0; +} + +@media (max-width: 575.98px) { + .modal-fullscreen-sm-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-sm-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-sm-down .modal-header { + border-radius: 0; + } + .modal-fullscreen-sm-down .modal-body { + overflow-y: auto; + } + .modal-fullscreen-sm-down .modal-footer { + border-radius: 0; + } +} + +@media (max-width: 767.98px) { + .modal-fullscreen-md-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-md-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-md-down .modal-header { + border-radius: 0; + } + .modal-fullscreen-md-down .modal-body { + overflow-y: auto; + } + .modal-fullscreen-md-down .modal-footer { + border-radius: 0; + } +} + +@media (max-width: 991.98px) { + .modal-fullscreen-lg-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-lg-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-lg-down .modal-header { + border-radius: 0; + } + .modal-fullscreen-lg-down .modal-body { + overflow-y: auto; + } + .modal-fullscreen-lg-down .modal-footer { + border-radius: 0; + } +} + +@media (max-width: 1199.98px) { + .modal-fullscreen-xl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-xl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-xl-down .modal-header { + border-radius: 0; + } + .modal-fullscreen-xl-down .modal-body { + overflow-y: auto; + } + .modal-fullscreen-xl-down .modal-footer { + border-radius: 0; + } +} + +@media (max-width: 1439.98px) { + .modal-fullscreen-xxl-down { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + } + .modal-fullscreen-xxl-down .modal-content { + height: 100%; + border: 0; + border-radius: 0; + } + .modal-fullscreen-xxl-down .modal-header { + border-radius: 0; + } + .modal-fullscreen-xxl-down .modal-body { + overflow-y: auto; + } + .modal-fullscreen-xxl-down .modal-footer { + border-radius: 0; + } +} + +.align-baseline { + vertical-align: baseline !important; +} + +.align-top { + vertical-align: top !important; +} + +.align-middle { + vertical-align: middle !important; +} + +.align-bottom { + vertical-align: bottom !important; +} + +.align-text-bottom { + vertical-align: text-bottom !important; +} + +.align-text-top { + vertical-align: text-top !important; +} + +.float-start { + float: left !important; +} + +.float-end { + float: right !important; +} + +.float-none { + float: none !important; +} + +.opacity-0 { + opacity: 0 !important; +} + +.opacity-25 { + opacity: 0.25 !important; +} + +.opacity-50 { + opacity: 0.5 !important; +} + +.opacity-75 { + opacity: 0.75 !important; +} + +.opacity-100 { + opacity: 1 !important; +} + +.overflow-auto { + overflow: auto !important; +} + +.overflow-hidden { + overflow: hidden !important; +} + +.overflow-visible { + overflow: visible !important; +} + +.overflow-scroll { + overflow: scroll !important; +} + +.d-inline { + display: inline !important; +} + +.d-inline-block { + display: inline-block !important; +} + +.d-block { + display: block !important; +} + +.d-grid { + display: grid !important; +} + +.d-table { + display: table !important; +} + +.d-table-row { + display: table-row !important; +} + +.d-table-cell { + display: table-cell !important; +} + +.d-flex { + display: flex !important; +} + +.d-inline-flex { + display: inline-flex !important; +} + +.d-none { + display: none !important; +} + +.shadow { + box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.05) !important; +} + +.shadow-sm { + box-shadow: 0 0.05rem 0.2rem rgba(0, 0, 0, 0.05) !important; +} + +.shadow-lg { + box-shadow: 0 0.2rem 0.2rem rgba(0, 0, 0, 0.05) !important; +} + +.shadow-none { + box-shadow: none !important; +} + +.position-static { + position: static !important; +} + +.position-relative { + position: relative !important; +} + +.position-absolute { + position: absolute !important; +} + +.position-fixed { + position: fixed !important; +} + +.position-sticky { + position: sticky !important; +} + +.top-0 { + top: 0 !important; +} + +.top-50 { + top: 50% !important; +} + +.top-100 { + top: 100% !important; +} + +.bottom-0 { + bottom: 0 !important; +} + +.bottom-50 { + bottom: 50% !important; +} + +.bottom-100 { + bottom: 100% !important; +} + +.start-0 { + left: 0 !important; +} + +.start-50 { + left: 50% !important; +} + +.start-100 { + left: 100% !important; +} + +.end-0 { + right: 0 !important; +} + +.end-50 { + right: 50% !important; +} + +.end-100 { + right: 100% !important; +} + +.translate-middle { + transform: translate(-50%, -50%) !important; +} + +.translate-middle-x { + transform: translateX(-50%) !important; +} + +.translate-middle-y { + transform: translateY(-50%) !important; +} + +.border { + border: 1px solid #dee2e6 !important; +} + +.border-0 { + border: 0 !important; +} + +.border-top { + border-top: 1px solid #dee2e6 !important; +} + +.border-top-0 { + border-top: 0 !important; +} + +.border-end { + border-right: 1px solid #dee2e6 !important; +} + +.border-end-0 { + border-right: 0 !important; +} + +.border-bottom { + border-bottom: 1px solid #dee2e6 !important; +} + +.border-bottom-0 { + border-bottom: 0 !important; +} + +.border-start { + border-left: 1px solid #dee2e6 !important; +} + +.border-start-0 { + border-left: 0 !important; +} + +.border-primary { + border-color: #3B7DDD !important; +} + +.border-secondary { + border-color: #6c757d !important; +} + +.border-success { + border-color: #28a745 !important; +} + +.border-info { + border-color: #17a2b8 !important; +} + +.border-warning { + border-color: #ffc107 !important; +} + +.border-danger { + border-color: #dc3545 !important; +} + +.border-light { + border-color: #f8f9fa !important; +} + +.border-dark { + border-color: #212529 !important; +} + +.border-white { + border-color: #fff !important; +} + +.border-1 { + border-width: 1px !important; +} + +.border-2 { + border-width: 2px !important; +} + +.border-3 { + border-width: 3px !important; +} + +.border-4 { + border-width: 4px !important; +} + +.border-5 { + border-width: 5px !important; +} + +.w-25 { + width: 25% !important; +} + +.w-50 { + width: 50% !important; +} + +.w-75 { + width: 75% !important; +} + +.w-100 { + width: 100% !important; +} + +.w-auto { + width: auto !important; +} + +.mw-100 { + max-width: 100% !important; +} + +.vw-100 { + width: 100vw !important; +} + +.min-vw-100 { + min-width: 100vw !important; +} + +.h-25 { + height: 25% !important; +} + +.h-50 { + height: 50% !important; +} + +.h-75 { + height: 75% !important; +} + +.h-100 { + height: 100% !important; +} + +.h-auto { + height: auto !important; +} + +.mh-100 { + max-height: 100% !important; +} + +.vh-100 { + height: 100vh !important; +} + +.min-vh-100 { + min-height: 100vh !important; +} + +.flex-fill { + flex: 1 1 auto !important; +} + +.flex-row { + flex-direction: row !important; +} + +.flex-column { + flex-direction: column !important; +} + +.flex-row-reverse { + flex-direction: row-reverse !important; +} + +.flex-column-reverse { + flex-direction: column-reverse !important; +} + +.flex-grow-0 { + flex-grow: 0 !important; +} + +.flex-grow-1 { + flex-grow: 1 !important; +} + +.flex-shrink-0 { + flex-shrink: 0 !important; +} + +.flex-shrink-1 { + flex-shrink: 1 !important; +} + +.flex-wrap { + flex-wrap: wrap !important; +} + +.flex-nowrap { + flex-wrap: nowrap !important; +} + +.flex-wrap-reverse { + flex-wrap: wrap-reverse !important; +} + +.gap-0 { + gap: 0 !important; +} + +.gap-1 { + gap: 0.25rem !important; +} + +.gap-2 { + gap: 0.5rem !important; +} + +.gap-3 { + gap: 1rem !important; +} + +.gap-4 { + gap: 1.5rem !important; +} + +.gap-5 { + gap: 3rem !important; +} + +.gap-6 { + gap: 4.5rem !important; +} + +.gap-7 { + gap: 6rem !important; +} + +.justify-content-start { + justify-content: flex-start !important; +} + +.justify-content-end { + justify-content: flex-end !important; +} + +.justify-content-center { + justify-content: center !important; +} + +.justify-content-between { + justify-content: space-between !important; +} + +.justify-content-around { + justify-content: space-around !important; +} + +.justify-content-evenly { + justify-content: space-evenly !important; +} + +.align-items-start { + align-items: flex-start !important; +} + +.align-items-end { + align-items: flex-end !important; +} + +.align-items-center { + align-items: center !important; +} + +.align-items-baseline { + align-items: baseline !important; +} + +.align-items-stretch { + align-items: stretch !important; +} + +.align-content-start { + align-content: flex-start !important; +} + +.align-content-end { + align-content: flex-end !important; +} + +.align-content-center { + align-content: center !important; +} + +.align-content-between { + align-content: space-between !important; +} + +.align-content-around { + align-content: space-around !important; +} + +.align-content-stretch { + align-content: stretch !important; +} + +.align-self-auto { + align-self: auto !important; +} + +.align-self-start { + align-self: flex-start !important; +} + +.align-self-end { + align-self: flex-end !important; +} + +.align-self-center { + align-self: center !important; +} + +.align-self-baseline { + align-self: baseline !important; +} + +.align-self-stretch { + align-self: stretch !important; +} + +.order-first { + order: -1 !important; +} + +.order-0 { + order: 0 !important; +} + +.order-1 { + order: 1 !important; +} + +.order-2 { + order: 2 !important; +} + +.order-3 { + order: 3 !important; +} + +.order-4 { + order: 4 !important; +} + +.order-5 { + order: 5 !important; +} + +.order-last { + order: 6 !important; +} + +.m-0 { + margin: 0 !important; +} + +.m-1 { + margin: 0.25rem !important; +} + +.m-2 { + margin: 0.5rem !important; +} + +.m-3 { + margin: 1rem !important; +} + +.m-4 { + margin: 1.5rem !important; +} + +.m-5 { + margin: 3rem !important; +} + +.m-6 { + margin: 4.5rem !important; +} + +.m-7 { + margin: 6rem !important; +} + +.m-auto { + margin: auto !important; +} + +.mx-0 { + margin-right: 0 !important; + margin-left: 0 !important; +} + +.mx-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; +} + +.mx-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; +} + +.mx-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; +} + +.mx-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; +} + +.mx-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; +} + +.mx-6 { + margin-right: 4.5rem !important; + margin-left: 4.5rem !important; +} + +.mx-7 { + margin-right: 6rem !important; + margin-left: 6rem !important; +} + +.mx-auto { + margin-right: auto !important; + margin-left: auto !important; +} + +.my-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; +} + +.my-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; +} + +.my-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; +} + +.my-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; +} + +.my-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; +} + +.my-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; +} + +.my-6 { + margin-top: 4.5rem !important; + margin-bottom: 4.5rem !important; +} + +.my-7 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; +} + +.my-auto { + margin-top: auto !important; + margin-bottom: auto !important; +} + +.mt-0 { + margin-top: 0 !important; +} + +.mt-1 { + margin-top: 0.25rem !important; +} + +.mt-2 { + margin-top: 0.5rem !important; +} + +.mt-3 { + margin-top: 1rem !important; +} + +.mt-4 { + margin-top: 1.5rem !important; +} + +.mt-5 { + margin-top: 3rem !important; +} + +.mt-6 { + margin-top: 4.5rem !important; +} + +.mt-7 { + margin-top: 6rem !important; +} + +.mt-auto { + margin-top: auto !important; +} + +.me-0 { + margin-right: 0 !important; +} + +.me-1 { + margin-right: 0.25rem !important; +} + +.me-2 { + margin-right: 0.5rem !important; +} + +.me-3 { + margin-right: 1rem !important; +} + +.me-4 { + margin-right: 1.5rem !important; +} + +.me-5 { + margin-right: 3rem !important; +} + +.me-6 { + margin-right: 4.5rem !important; +} + +.me-7 { + margin-right: 6rem !important; +} + +.me-auto { + margin-right: auto !important; +} + +.mb-0 { + margin-bottom: 0 !important; +} + +.mb-1 { + margin-bottom: 0.25rem !important; +} + +.mb-2 { + margin-bottom: 0.5rem !important; +} + +.mb-3 { + margin-bottom: 1rem !important; +} + +.mb-4 { + margin-bottom: 1.5rem !important; +} + +.mb-5 { + margin-bottom: 3rem !important; +} + +.mb-6 { + margin-bottom: 4.5rem !important; +} + +.mb-7 { + margin-bottom: 6rem !important; +} + +.mb-auto { + margin-bottom: auto !important; +} + +.ms-0 { + margin-left: 0 !important; +} + +.ms-1 { + margin-left: 0.25rem !important; +} + +.ms-2 { + margin-left: 0.5rem !important; +} + +.ms-3 { + margin-left: 1rem !important; +} + +.ms-4 { + margin-left: 1.5rem !important; +} + +.ms-5 { + margin-left: 3rem !important; +} + +.ms-6 { + margin-left: 4.5rem !important; +} + +.ms-7 { + margin-left: 6rem !important; +} + +.ms-auto { + margin-left: auto !important; +} + +.m-n1 { + margin: -0.25rem !important; +} + +.m-n2 { + margin: -0.5rem !important; +} + +.m-n3 { + margin: -1rem !important; +} + +.m-n4 { + margin: -1.5rem !important; +} + +.m-n5 { + margin: -3rem !important; +} + +.m-n6 { + margin: -4.5rem !important; +} + +.m-n7 { + margin: -6rem !important; +} + +.mx-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; +} + +.mx-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; +} + +.mx-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; +} + +.mx-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; +} + +.mx-n5 { + margin-right: -3rem !important; + margin-left: -3rem !important; +} + +.mx-n6 { + margin-right: -4.5rem !important; + margin-left: -4.5rem !important; +} + +.mx-n7 { + margin-right: -6rem !important; + margin-left: -6rem !important; +} + +.my-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; +} + +.my-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; +} + +.my-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; +} + +.my-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; +} + +.my-n5 { + margin-top: -3rem !important; + margin-bottom: -3rem !important; +} + +.my-n6 { + margin-top: -4.5rem !important; + margin-bottom: -4.5rem !important; +} + +.my-n7 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; +} + +.mt-n1 { + margin-top: -0.25rem !important; +} + +.mt-n2 { + margin-top: -0.5rem !important; +} + +.mt-n3 { + margin-top: -1rem !important; +} + +.mt-n4 { + margin-top: -1.5rem !important; +} + +.mt-n5 { + margin-top: -3rem !important; +} + +.mt-n6 { + margin-top: -4.5rem !important; +} + +.mt-n7 { + margin-top: -6rem !important; +} + +.me-n1 { + margin-right: -0.25rem !important; +} + +.me-n2 { + margin-right: -0.5rem !important; +} + +.me-n3 { + margin-right: -1rem !important; +} + +.me-n4 { + margin-right: -1.5rem !important; +} + +.me-n5 { + margin-right: -3rem !important; +} + +.me-n6 { + margin-right: -4.5rem !important; +} + +.me-n7 { + margin-right: -6rem !important; +} + +.mb-n1 { + margin-bottom: -0.25rem !important; +} + +.mb-n2 { + margin-bottom: -0.5rem !important; +} + +.mb-n3 { + margin-bottom: -1rem !important; +} + +.mb-n4 { + margin-bottom: -1.5rem !important; +} + +.mb-n5 { + margin-bottom: -3rem !important; +} + +.mb-n6 { + margin-bottom: -4.5rem !important; +} + +.mb-n7 { + margin-bottom: -6rem !important; +} + +.ms-n1 { + margin-left: -0.25rem !important; +} + +.ms-n2 { + margin-left: -0.5rem !important; +} + +.ms-n3 { + margin-left: -1rem !important; +} + +.ms-n4 { + margin-left: -1.5rem !important; +} + +.ms-n5 { + margin-left: -3rem !important; +} + +.ms-n6 { + margin-left: -4.5rem !important; +} + +.ms-n7 { + margin-left: -6rem !important; +} + +.p-0 { + padding: 0 !important; +} + +.p-1 { + padding: 0.25rem !important; +} + +.p-2 { + padding: 0.5rem !important; +} + +.p-3 { + padding: 1rem !important; +} + +.p-4 { + padding: 1.5rem !important; +} + +.p-5 { + padding: 3rem !important; +} + +.p-6 { + padding: 4.5rem !important; +} + +.p-7 { + padding: 6rem !important; +} + +.px-0 { + padding-right: 0 !important; + padding-left: 0 !important; +} + +.px-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; +} + +.px-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; +} + +.px-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; +} + +.px-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; +} + +.px-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; +} + +.px-6 { + padding-right: 4.5rem !important; + padding-left: 4.5rem !important; +} + +.px-7 { + padding-right: 6rem !important; + padding-left: 6rem !important; +} + +.py-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; +} + +.py-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; +} + +.py-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; +} + +.py-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; +} + +.py-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; +} + +.py-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; +} + +.py-6 { + padding-top: 4.5rem !important; + padding-bottom: 4.5rem !important; +} + +.py-7 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; +} + +.pt-0 { + padding-top: 0 !important; +} + +.pt-1 { + padding-top: 0.25rem !important; +} + +.pt-2 { + padding-top: 0.5rem !important; +} + +.pt-3 { + padding-top: 1rem !important; +} + +.pt-4 { + padding-top: 1.5rem !important; +} + +.pt-5 { + padding-top: 3rem !important; +} + +.pt-6 { + padding-top: 4.5rem !important; +} + +.pt-7 { + padding-top: 6rem !important; +} + +.pe-0 { + padding-right: 0 !important; +} + +.pe-1 { + padding-right: 0.25rem !important; +} + +.pe-2 { + padding-right: 0.5rem !important; +} + +.pe-3 { + padding-right: 1rem !important; +} + +.pe-4 { + padding-right: 1.5rem !important; +} + +.pe-5 { + padding-right: 3rem !important; +} + +.pe-6 { + padding-right: 4.5rem !important; +} + +.pe-7 { + padding-right: 6rem !important; +} + +.pb-0 { + padding-bottom: 0 !important; +} + +.pb-1 { + padding-bottom: 0.25rem !important; +} + +.pb-2 { + padding-bottom: 0.5rem !important; +} + +.pb-3 { + padding-bottom: 1rem !important; +} + +.pb-4 { + padding-bottom: 1.5rem !important; +} + +.pb-5 { + padding-bottom: 3rem !important; +} + +.pb-6 { + padding-bottom: 4.5rem !important; +} + +.pb-7 { + padding-bottom: 6rem !important; +} + +.ps-0 { + padding-left: 0 !important; +} + +.ps-1 { + padding-left: 0.25rem !important; +} + +.ps-2 { + padding-left: 0.5rem !important; +} + +.ps-3 { + padding-left: 1rem !important; +} + +.ps-4 { + padding-left: 1.5rem !important; +} + +.ps-5 { + padding-left: 3rem !important; +} + +.ps-6 { + padding-left: 4.5rem !important; +} + +.ps-7 { + padding-left: 6rem !important; +} + +.font-monospace { + font-family: var(--bs-font-monospace) !important; +} + +.fs-1 { + font-size: 1.75rem !important; +} + +.fs-2 { + font-size: 1.53125rem !important; +} + +.fs-3 { + font-size: 1.3125rem !important; +} + +.fs-4 { + font-size: 1.09375rem !important; +} + +.fs-5 { + font-size: 0.875rem !important; +} + +.fs-6 { + font-size: 0.875rem !important; +} + +.fst-italic { + font-style: italic !important; +} + +.fst-normal { + font-style: normal !important; +} + +.fw-light { + font-weight: 300 !important; +} + +.fw-lighter { + font-weight: lighter !important; +} + +.fw-normal { + font-weight: 400 !important; +} + +.fw-bold { + font-weight: 600 !important; +} + +.fw-bolder { + font-weight: bolder !important; +} + +.lh-1 { + line-height: 1 !important; +} + +.lh-sm { + line-height: 1.5 !important; +} + +.lh-base { + line-height: 1.5 !important; +} + +.lh-lg { + line-height: 1.5 !important; +} + +.text-start { + text-align: left !important; +} + +.text-end { + text-align: right !important; +} + +.text-center { + text-align: center !important; +} + +.text-decoration-none { + text-decoration: none !important; +} + +.text-decoration-underline { + text-decoration: underline !important; +} + +.text-decoration-line-through { + text-decoration: line-through !important; +} + +.text-lowercase { + text-transform: lowercase !important; +} + +.text-uppercase { + text-transform: uppercase !important; +} + +.text-capitalize { + text-transform: capitalize !important; +} + +.text-wrap { + white-space: normal !important; +} + +.text-nowrap { + white-space: nowrap !important; +} + +/* rtl:begin:remove */ +.text-break { + word-wrap: break-word !important; + word-break: break-word !important; +} + +/* rtl:end:remove */ +.text-primary { + --bs-text-opacity: 1; + color: rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important; +} + +.text-secondary { + --bs-text-opacity: 1; + color: rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important; +} + +.text-success { + --bs-text-opacity: 1; + color: rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important; +} + +.text-info { + --bs-text-opacity: 1; + color: rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important; +} + +.text-warning { + --bs-text-opacity: 1; + color: rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important; +} + +.text-danger { + --bs-text-opacity: 1; + color: rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important; +} + +.text-light { + --bs-text-opacity: 1; + color: rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important; +} + +.text-dark { + --bs-text-opacity: 1; + color: rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important; +} + +.text-black { + --bs-text-opacity: 1; + color: rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important; +} + +.text-white { + --bs-text-opacity: 1; + color: rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important; +} + +.text-body { + --bs-text-opacity: 1; + color: rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important; +} + +.text-muted { + --bs-text-opacity: 1; + color: #6c757d !important; +} + +.text-black-50 { + --bs-text-opacity: 1; + color: rgba(0, 0, 0, 0.5) !important; +} + +.text-white-50 { + --bs-text-opacity: 1; + color: rgba(255, 255, 255, 0.5) !important; +} + +.text-reset { + --bs-text-opacity: 1; + color: inherit !important; +} + +.text-opacity-25 { + --bs-text-opacity: 0.25; +} + +.text-opacity-50 { + --bs-text-opacity: 0.5; +} + +.text-opacity-75 { + --bs-text-opacity: 0.75; +} + +.text-opacity-100 { + --bs-text-opacity: 1; +} + +.bg-primary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-secondary { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-success { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-info { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-warning { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-danger { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-light { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-dark { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-black { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-white { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-body { + --bs-bg-opacity: 1; + background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important; +} + +.bg-transparent { + --bs-bg-opacity: 1; + background-color: transparent !important; +} + +.bg-opacity-10 { + --bs-bg-opacity: 0.1; +} + +.bg-opacity-25 { + --bs-bg-opacity: 0.25; +} + +.bg-opacity-50 { + --bs-bg-opacity: 0.5; +} + +.bg-opacity-75 { + --bs-bg-opacity: 0.75; +} + +.bg-opacity-100 { + --bs-bg-opacity: 1; +} + +.bg-gradient { + background-image: var(--bs-gradient) !important; +} + +.user-select-all { + user-select: all !important; +} + +.user-select-auto { + user-select: auto !important; +} + +.user-select-none { + user-select: none !important; +} + +.pe-none { + pointer-events: none !important; +} + +.pe-auto { + pointer-events: auto !important; +} + +.rounded { + border-radius: 0.2rem !important; +} + +.rounded-0 { + border-radius: 0 !important; +} + +.rounded-1 { + border-radius: 0.1rem !important; +} + +.rounded-2 { + border-radius: 0.2rem !important; +} + +.rounded-3 { + border-radius: 0.3rem !important; +} + +.rounded-circle { + border-radius: 50% !important; +} + +.rounded-pill { + border-radius: 50rem !important; +} + +.rounded-top { + border-top-left-radius: 0.2rem !important; + border-top-right-radius: 0.2rem !important; +} + +.rounded-end { + border-top-right-radius: 0.2rem !important; + border-bottom-right-radius: 0.2rem !important; +} + +.rounded-bottom { + border-bottom-right-radius: 0.2rem !important; + border-bottom-left-radius: 0.2rem !important; +} + +.rounded-start { + border-bottom-left-radius: 0.2rem !important; + border-top-left-radius: 0.2rem !important; +} + +.visible { + visibility: visible !important; +} + +.invisible { + visibility: hidden !important; +} + +@media (min-width: 576px) { + .float-sm-start { + float: left !important; + } + .float-sm-end { + float: right !important; + } + .float-sm-none { + float: none !important; + } + .d-sm-inline { + display: inline !important; + } + .d-sm-inline-block { + display: inline-block !important; + } + .d-sm-block { + display: block !important; + } + .d-sm-grid { + display: grid !important; + } + .d-sm-table { + display: table !important; + } + .d-sm-table-row { + display: table-row !important; + } + .d-sm-table-cell { + display: table-cell !important; + } + .d-sm-flex { + display: flex !important; + } + .d-sm-inline-flex { + display: inline-flex !important; + } + .d-sm-none { + display: none !important; + } + .flex-sm-fill { + flex: 1 1 auto !important; + } + .flex-sm-row { + flex-direction: row !important; + } + .flex-sm-column { + flex-direction: column !important; + } + .flex-sm-row-reverse { + flex-direction: row-reverse !important; + } + .flex-sm-column-reverse { + flex-direction: column-reverse !important; + } + .flex-sm-grow-0 { + flex-grow: 0 !important; + } + .flex-sm-grow-1 { + flex-grow: 1 !important; + } + .flex-sm-shrink-0 { + flex-shrink: 0 !important; + } + .flex-sm-shrink-1 { + flex-shrink: 1 !important; + } + .flex-sm-wrap { + flex-wrap: wrap !important; + } + .flex-sm-nowrap { + flex-wrap: nowrap !important; + } + .flex-sm-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .gap-sm-0 { + gap: 0 !important; + } + .gap-sm-1 { + gap: 0.25rem !important; + } + .gap-sm-2 { + gap: 0.5rem !important; + } + .gap-sm-3 { + gap: 1rem !important; + } + .gap-sm-4 { + gap: 1.5rem !important; + } + .gap-sm-5 { + gap: 3rem !important; + } + .gap-sm-6 { + gap: 4.5rem !important; + } + .gap-sm-7 { + gap: 6rem !important; + } + .justify-content-sm-start { + justify-content: flex-start !important; + } + .justify-content-sm-end { + justify-content: flex-end !important; + } + .justify-content-sm-center { + justify-content: center !important; + } + .justify-content-sm-between { + justify-content: space-between !important; + } + .justify-content-sm-around { + justify-content: space-around !important; + } + .justify-content-sm-evenly { + justify-content: space-evenly !important; + } + .align-items-sm-start { + align-items: flex-start !important; + } + .align-items-sm-end { + align-items: flex-end !important; + } + .align-items-sm-center { + align-items: center !important; + } + .align-items-sm-baseline { + align-items: baseline !important; + } + .align-items-sm-stretch { + align-items: stretch !important; + } + .align-content-sm-start { + align-content: flex-start !important; + } + .align-content-sm-end { + align-content: flex-end !important; + } + .align-content-sm-center { + align-content: center !important; + } + .align-content-sm-between { + align-content: space-between !important; + } + .align-content-sm-around { + align-content: space-around !important; + } + .align-content-sm-stretch { + align-content: stretch !important; + } + .align-self-sm-auto { + align-self: auto !important; + } + .align-self-sm-start { + align-self: flex-start !important; + } + .align-self-sm-end { + align-self: flex-end !important; + } + .align-self-sm-center { + align-self: center !important; + } + .align-self-sm-baseline { + align-self: baseline !important; + } + .align-self-sm-stretch { + align-self: stretch !important; + } + .order-sm-first { + order: -1 !important; + } + .order-sm-0 { + order: 0 !important; + } + .order-sm-1 { + order: 1 !important; + } + .order-sm-2 { + order: 2 !important; + } + .order-sm-3 { + order: 3 !important; + } + .order-sm-4 { + order: 4 !important; + } + .order-sm-5 { + order: 5 !important; + } + .order-sm-last { + order: 6 !important; + } + .m-sm-0 { + margin: 0 !important; + } + .m-sm-1 { + margin: 0.25rem !important; + } + .m-sm-2 { + margin: 0.5rem !important; + } + .m-sm-3 { + margin: 1rem !important; + } + .m-sm-4 { + margin: 1.5rem !important; + } + .m-sm-5 { + margin: 3rem !important; + } + .m-sm-6 { + margin: 4.5rem !important; + } + .m-sm-7 { + margin: 6rem !important; + } + .m-sm-auto { + margin: auto !important; + } + .mx-sm-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-sm-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-sm-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-sm-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-sm-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-sm-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-sm-6 { + margin-right: 4.5rem !important; + margin-left: 4.5rem !important; + } + .mx-sm-7 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-sm-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-sm-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-sm-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-sm-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-sm-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-sm-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-sm-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-sm-6 { + margin-top: 4.5rem !important; + margin-bottom: 4.5rem !important; + } + .my-sm-7 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-sm-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-sm-0 { + margin-top: 0 !important; + } + .mt-sm-1 { + margin-top: 0.25rem !important; + } + .mt-sm-2 { + margin-top: 0.5rem !important; + } + .mt-sm-3 { + margin-top: 1rem !important; + } + .mt-sm-4 { + margin-top: 1.5rem !important; + } + .mt-sm-5 { + margin-top: 3rem !important; + } + .mt-sm-6 { + margin-top: 4.5rem !important; + } + .mt-sm-7 { + margin-top: 6rem !important; + } + .mt-sm-auto { + margin-top: auto !important; + } + .me-sm-0 { + margin-right: 0 !important; + } + .me-sm-1 { + margin-right: 0.25rem !important; + } + .me-sm-2 { + margin-right: 0.5rem !important; + } + .me-sm-3 { + margin-right: 1rem !important; + } + .me-sm-4 { + margin-right: 1.5rem !important; + } + .me-sm-5 { + margin-right: 3rem !important; + } + .me-sm-6 { + margin-right: 4.5rem !important; + } + .me-sm-7 { + margin-right: 6rem !important; + } + .me-sm-auto { + margin-right: auto !important; + } + .mb-sm-0 { + margin-bottom: 0 !important; + } + .mb-sm-1 { + margin-bottom: 0.25rem !important; + } + .mb-sm-2 { + margin-bottom: 0.5rem !important; + } + .mb-sm-3 { + margin-bottom: 1rem !important; + } + .mb-sm-4 { + margin-bottom: 1.5rem !important; + } + .mb-sm-5 { + margin-bottom: 3rem !important; + } + .mb-sm-6 { + margin-bottom: 4.5rem !important; + } + .mb-sm-7 { + margin-bottom: 6rem !important; + } + .mb-sm-auto { + margin-bottom: auto !important; + } + .ms-sm-0 { + margin-left: 0 !important; + } + .ms-sm-1 { + margin-left: 0.25rem !important; + } + .ms-sm-2 { + margin-left: 0.5rem !important; + } + .ms-sm-3 { + margin-left: 1rem !important; + } + .ms-sm-4 { + margin-left: 1.5rem !important; + } + .ms-sm-5 { + margin-left: 3rem !important; + } + .ms-sm-6 { + margin-left: 4.5rem !important; + } + .ms-sm-7 { + margin-left: 6rem !important; + } + .ms-sm-auto { + margin-left: auto !important; + } + .m-sm-n1 { + margin: -0.25rem !important; + } + .m-sm-n2 { + margin: -0.5rem !important; + } + .m-sm-n3 { + margin: -1rem !important; + } + .m-sm-n4 { + margin: -1.5rem !important; + } + .m-sm-n5 { + margin: -3rem !important; + } + .m-sm-n6 { + margin: -4.5rem !important; + } + .m-sm-n7 { + margin: -6rem !important; + } + .mx-sm-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-sm-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-sm-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-sm-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-sm-n5 { + margin-right: -3rem !important; + margin-left: -3rem !important; + } + .mx-sm-n6 { + margin-right: -4.5rem !important; + margin-left: -4.5rem !important; + } + .mx-sm-n7 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .my-sm-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-sm-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-sm-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-sm-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-sm-n5 { + margin-top: -3rem !important; + margin-bottom: -3rem !important; + } + .my-sm-n6 { + margin-top: -4.5rem !important; + margin-bottom: -4.5rem !important; + } + .my-sm-n7 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .mt-sm-n1 { + margin-top: -0.25rem !important; + } + .mt-sm-n2 { + margin-top: -0.5rem !important; + } + .mt-sm-n3 { + margin-top: -1rem !important; + } + .mt-sm-n4 { + margin-top: -1.5rem !important; + } + .mt-sm-n5 { + margin-top: -3rem !important; + } + .mt-sm-n6 { + margin-top: -4.5rem !important; + } + .mt-sm-n7 { + margin-top: -6rem !important; + } + .me-sm-n1 { + margin-right: -0.25rem !important; + } + .me-sm-n2 { + margin-right: -0.5rem !important; + } + .me-sm-n3 { + margin-right: -1rem !important; + } + .me-sm-n4 { + margin-right: -1.5rem !important; + } + .me-sm-n5 { + margin-right: -3rem !important; + } + .me-sm-n6 { + margin-right: -4.5rem !important; + } + .me-sm-n7 { + margin-right: -6rem !important; + } + .mb-sm-n1 { + margin-bottom: -0.25rem !important; + } + .mb-sm-n2 { + margin-bottom: -0.5rem !important; + } + .mb-sm-n3 { + margin-bottom: -1rem !important; + } + .mb-sm-n4 { + margin-bottom: -1.5rem !important; + } + .mb-sm-n5 { + margin-bottom: -3rem !important; + } + .mb-sm-n6 { + margin-bottom: -4.5rem !important; + } + .mb-sm-n7 { + margin-bottom: -6rem !important; + } + .ms-sm-n1 { + margin-left: -0.25rem !important; + } + .ms-sm-n2 { + margin-left: -0.5rem !important; + } + .ms-sm-n3 { + margin-left: -1rem !important; + } + .ms-sm-n4 { + margin-left: -1.5rem !important; + } + .ms-sm-n5 { + margin-left: -3rem !important; + } + .ms-sm-n6 { + margin-left: -4.5rem !important; + } + .ms-sm-n7 { + margin-left: -6rem !important; + } + .p-sm-0 { + padding: 0 !important; + } + .p-sm-1 { + padding: 0.25rem !important; + } + .p-sm-2 { + padding: 0.5rem !important; + } + .p-sm-3 { + padding: 1rem !important; + } + .p-sm-4 { + padding: 1.5rem !important; + } + .p-sm-5 { + padding: 3rem !important; + } + .p-sm-6 { + padding: 4.5rem !important; + } + .p-sm-7 { + padding: 6rem !important; + } + .px-sm-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-sm-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-sm-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-sm-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-sm-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-sm-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .px-sm-6 { + padding-right: 4.5rem !important; + padding-left: 4.5rem !important; + } + .px-sm-7 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .py-sm-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-sm-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-sm-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-sm-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-sm-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-sm-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .py-sm-6 { + padding-top: 4.5rem !important; + padding-bottom: 4.5rem !important; + } + .py-sm-7 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .pt-sm-0 { + padding-top: 0 !important; + } + .pt-sm-1 { + padding-top: 0.25rem !important; + } + .pt-sm-2 { + padding-top: 0.5rem !important; + } + .pt-sm-3 { + padding-top: 1rem !important; + } + .pt-sm-4 { + padding-top: 1.5rem !important; + } + .pt-sm-5 { + padding-top: 3rem !important; + } + .pt-sm-6 { + padding-top: 4.5rem !important; + } + .pt-sm-7 { + padding-top: 6rem !important; + } + .pe-sm-0 { + padding-right: 0 !important; + } + .pe-sm-1 { + padding-right: 0.25rem !important; + } + .pe-sm-2 { + padding-right: 0.5rem !important; + } + .pe-sm-3 { + padding-right: 1rem !important; + } + .pe-sm-4 { + padding-right: 1.5rem !important; + } + .pe-sm-5 { + padding-right: 3rem !important; + } + .pe-sm-6 { + padding-right: 4.5rem !important; + } + .pe-sm-7 { + padding-right: 6rem !important; + } + .pb-sm-0 { + padding-bottom: 0 !important; + } + .pb-sm-1 { + padding-bottom: 0.25rem !important; + } + .pb-sm-2 { + padding-bottom: 0.5rem !important; + } + .pb-sm-3 { + padding-bottom: 1rem !important; + } + .pb-sm-4 { + padding-bottom: 1.5rem !important; + } + .pb-sm-5 { + padding-bottom: 3rem !important; + } + .pb-sm-6 { + padding-bottom: 4.5rem !important; + } + .pb-sm-7 { + padding-bottom: 6rem !important; + } + .ps-sm-0 { + padding-left: 0 !important; + } + .ps-sm-1 { + padding-left: 0.25rem !important; + } + .ps-sm-2 { + padding-left: 0.5rem !important; + } + .ps-sm-3 { + padding-left: 1rem !important; + } + .ps-sm-4 { + padding-left: 1.5rem !important; + } + .ps-sm-5 { + padding-left: 3rem !important; + } + .ps-sm-6 { + padding-left: 4.5rem !important; + } + .ps-sm-7 { + padding-left: 6rem !important; + } + .text-sm-start { + text-align: left !important; + } + .text-sm-end { + text-align: right !important; + } + .text-sm-center { + text-align: center !important; + } +} + +@media (min-width: 768px) { + .float-md-start { + float: left !important; + } + .float-md-end { + float: right !important; + } + .float-md-none { + float: none !important; + } + .d-md-inline { + display: inline !important; + } + .d-md-inline-block { + display: inline-block !important; + } + .d-md-block { + display: block !important; + } + .d-md-grid { + display: grid !important; + } + .d-md-table { + display: table !important; + } + .d-md-table-row { + display: table-row !important; + } + .d-md-table-cell { + display: table-cell !important; + } + .d-md-flex { + display: flex !important; + } + .d-md-inline-flex { + display: inline-flex !important; + } + .d-md-none { + display: none !important; + } + .flex-md-fill { + flex: 1 1 auto !important; + } + .flex-md-row { + flex-direction: row !important; + } + .flex-md-column { + flex-direction: column !important; + } + .flex-md-row-reverse { + flex-direction: row-reverse !important; + } + .flex-md-column-reverse { + flex-direction: column-reverse !important; + } + .flex-md-grow-0 { + flex-grow: 0 !important; + } + .flex-md-grow-1 { + flex-grow: 1 !important; + } + .flex-md-shrink-0 { + flex-shrink: 0 !important; + } + .flex-md-shrink-1 { + flex-shrink: 1 !important; + } + .flex-md-wrap { + flex-wrap: wrap !important; + } + .flex-md-nowrap { + flex-wrap: nowrap !important; + } + .flex-md-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .gap-md-0 { + gap: 0 !important; + } + .gap-md-1 { + gap: 0.25rem !important; + } + .gap-md-2 { + gap: 0.5rem !important; + } + .gap-md-3 { + gap: 1rem !important; + } + .gap-md-4 { + gap: 1.5rem !important; + } + .gap-md-5 { + gap: 3rem !important; + } + .gap-md-6 { + gap: 4.5rem !important; + } + .gap-md-7 { + gap: 6rem !important; + } + .justify-content-md-start { + justify-content: flex-start !important; + } + .justify-content-md-end { + justify-content: flex-end !important; + } + .justify-content-md-center { + justify-content: center !important; + } + .justify-content-md-between { + justify-content: space-between !important; + } + .justify-content-md-around { + justify-content: space-around !important; + } + .justify-content-md-evenly { + justify-content: space-evenly !important; + } + .align-items-md-start { + align-items: flex-start !important; + } + .align-items-md-end { + align-items: flex-end !important; + } + .align-items-md-center { + align-items: center !important; + } + .align-items-md-baseline { + align-items: baseline !important; + } + .align-items-md-stretch { + align-items: stretch !important; + } + .align-content-md-start { + align-content: flex-start !important; + } + .align-content-md-end { + align-content: flex-end !important; + } + .align-content-md-center { + align-content: center !important; + } + .align-content-md-between { + align-content: space-between !important; + } + .align-content-md-around { + align-content: space-around !important; + } + .align-content-md-stretch { + align-content: stretch !important; + } + .align-self-md-auto { + align-self: auto !important; + } + .align-self-md-start { + align-self: flex-start !important; + } + .align-self-md-end { + align-self: flex-end !important; + } + .align-self-md-center { + align-self: center !important; + } + .align-self-md-baseline { + align-self: baseline !important; + } + .align-self-md-stretch { + align-self: stretch !important; + } + .order-md-first { + order: -1 !important; + } + .order-md-0 { + order: 0 !important; + } + .order-md-1 { + order: 1 !important; + } + .order-md-2 { + order: 2 !important; + } + .order-md-3 { + order: 3 !important; + } + .order-md-4 { + order: 4 !important; + } + .order-md-5 { + order: 5 !important; + } + .order-md-last { + order: 6 !important; + } + .m-md-0 { + margin: 0 !important; + } + .m-md-1 { + margin: 0.25rem !important; + } + .m-md-2 { + margin: 0.5rem !important; + } + .m-md-3 { + margin: 1rem !important; + } + .m-md-4 { + margin: 1.5rem !important; + } + .m-md-5 { + margin: 3rem !important; + } + .m-md-6 { + margin: 4.5rem !important; + } + .m-md-7 { + margin: 6rem !important; + } + .m-md-auto { + margin: auto !important; + } + .mx-md-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-md-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-md-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-md-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-md-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-md-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-md-6 { + margin-right: 4.5rem !important; + margin-left: 4.5rem !important; + } + .mx-md-7 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-md-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-md-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-md-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-md-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-md-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-md-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-md-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-md-6 { + margin-top: 4.5rem !important; + margin-bottom: 4.5rem !important; + } + .my-md-7 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-md-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-md-0 { + margin-top: 0 !important; + } + .mt-md-1 { + margin-top: 0.25rem !important; + } + .mt-md-2 { + margin-top: 0.5rem !important; + } + .mt-md-3 { + margin-top: 1rem !important; + } + .mt-md-4 { + margin-top: 1.5rem !important; + } + .mt-md-5 { + margin-top: 3rem !important; + } + .mt-md-6 { + margin-top: 4.5rem !important; + } + .mt-md-7 { + margin-top: 6rem !important; + } + .mt-md-auto { + margin-top: auto !important; + } + .me-md-0 { + margin-right: 0 !important; + } + .me-md-1 { + margin-right: 0.25rem !important; + } + .me-md-2 { + margin-right: 0.5rem !important; + } + .me-md-3 { + margin-right: 1rem !important; + } + .me-md-4 { + margin-right: 1.5rem !important; + } + .me-md-5 { + margin-right: 3rem !important; + } + .me-md-6 { + margin-right: 4.5rem !important; + } + .me-md-7 { + margin-right: 6rem !important; + } + .me-md-auto { + margin-right: auto !important; + } + .mb-md-0 { + margin-bottom: 0 !important; + } + .mb-md-1 { + margin-bottom: 0.25rem !important; + } + .mb-md-2 { + margin-bottom: 0.5rem !important; + } + .mb-md-3 { + margin-bottom: 1rem !important; + } + .mb-md-4 { + margin-bottom: 1.5rem !important; + } + .mb-md-5 { + margin-bottom: 3rem !important; + } + .mb-md-6 { + margin-bottom: 4.5rem !important; + } + .mb-md-7 { + margin-bottom: 6rem !important; + } + .mb-md-auto { + margin-bottom: auto !important; + } + .ms-md-0 { + margin-left: 0 !important; + } + .ms-md-1 { + margin-left: 0.25rem !important; + } + .ms-md-2 { + margin-left: 0.5rem !important; + } + .ms-md-3 { + margin-left: 1rem !important; + } + .ms-md-4 { + margin-left: 1.5rem !important; + } + .ms-md-5 { + margin-left: 3rem !important; + } + .ms-md-6 { + margin-left: 4.5rem !important; + } + .ms-md-7 { + margin-left: 6rem !important; + } + .ms-md-auto { + margin-left: auto !important; + } + .m-md-n1 { + margin: -0.25rem !important; + } + .m-md-n2 { + margin: -0.5rem !important; + } + .m-md-n3 { + margin: -1rem !important; + } + .m-md-n4 { + margin: -1.5rem !important; + } + .m-md-n5 { + margin: -3rem !important; + } + .m-md-n6 { + margin: -4.5rem !important; + } + .m-md-n7 { + margin: -6rem !important; + } + .mx-md-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-md-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-md-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-md-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-md-n5 { + margin-right: -3rem !important; + margin-left: -3rem !important; + } + .mx-md-n6 { + margin-right: -4.5rem !important; + margin-left: -4.5rem !important; + } + .mx-md-n7 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .my-md-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-md-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-md-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-md-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-md-n5 { + margin-top: -3rem !important; + margin-bottom: -3rem !important; + } + .my-md-n6 { + margin-top: -4.5rem !important; + margin-bottom: -4.5rem !important; + } + .my-md-n7 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .mt-md-n1 { + margin-top: -0.25rem !important; + } + .mt-md-n2 { + margin-top: -0.5rem !important; + } + .mt-md-n3 { + margin-top: -1rem !important; + } + .mt-md-n4 { + margin-top: -1.5rem !important; + } + .mt-md-n5 { + margin-top: -3rem !important; + } + .mt-md-n6 { + margin-top: -4.5rem !important; + } + .mt-md-n7 { + margin-top: -6rem !important; + } + .me-md-n1 { + margin-right: -0.25rem !important; + } + .me-md-n2 { + margin-right: -0.5rem !important; + } + .me-md-n3 { + margin-right: -1rem !important; + } + .me-md-n4 { + margin-right: -1.5rem !important; + } + .me-md-n5 { + margin-right: -3rem !important; + } + .me-md-n6 { + margin-right: -4.5rem !important; + } + .me-md-n7 { + margin-right: -6rem !important; + } + .mb-md-n1 { + margin-bottom: -0.25rem !important; + } + .mb-md-n2 { + margin-bottom: -0.5rem !important; + } + .mb-md-n3 { + margin-bottom: -1rem !important; + } + .mb-md-n4 { + margin-bottom: -1.5rem !important; + } + .mb-md-n5 { + margin-bottom: -3rem !important; + } + .mb-md-n6 { + margin-bottom: -4.5rem !important; + } + .mb-md-n7 { + margin-bottom: -6rem !important; + } + .ms-md-n1 { + margin-left: -0.25rem !important; + } + .ms-md-n2 { + margin-left: -0.5rem !important; + } + .ms-md-n3 { + margin-left: -1rem !important; + } + .ms-md-n4 { + margin-left: -1.5rem !important; + } + .ms-md-n5 { + margin-left: -3rem !important; + } + .ms-md-n6 { + margin-left: -4.5rem !important; + } + .ms-md-n7 { + margin-left: -6rem !important; + } + .p-md-0 { + padding: 0 !important; + } + .p-md-1 { + padding: 0.25rem !important; + } + .p-md-2 { + padding: 0.5rem !important; + } + .p-md-3 { + padding: 1rem !important; + } + .p-md-4 { + padding: 1.5rem !important; + } + .p-md-5 { + padding: 3rem !important; + } + .p-md-6 { + padding: 4.5rem !important; + } + .p-md-7 { + padding: 6rem !important; + } + .px-md-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-md-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-md-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-md-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-md-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-md-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .px-md-6 { + padding-right: 4.5rem !important; + padding-left: 4.5rem !important; + } + .px-md-7 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .py-md-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-md-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-md-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-md-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-md-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-md-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .py-md-6 { + padding-top: 4.5rem !important; + padding-bottom: 4.5rem !important; + } + .py-md-7 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .pt-md-0 { + padding-top: 0 !important; + } + .pt-md-1 { + padding-top: 0.25rem !important; + } + .pt-md-2 { + padding-top: 0.5rem !important; + } + .pt-md-3 { + padding-top: 1rem !important; + } + .pt-md-4 { + padding-top: 1.5rem !important; + } + .pt-md-5 { + padding-top: 3rem !important; + } + .pt-md-6 { + padding-top: 4.5rem !important; + } + .pt-md-7 { + padding-top: 6rem !important; + } + .pe-md-0 { + padding-right: 0 !important; + } + .pe-md-1 { + padding-right: 0.25rem !important; + } + .pe-md-2 { + padding-right: 0.5rem !important; + } + .pe-md-3 { + padding-right: 1rem !important; + } + .pe-md-4 { + padding-right: 1.5rem !important; + } + .pe-md-5 { + padding-right: 3rem !important; + } + .pe-md-6 { + padding-right: 4.5rem !important; + } + .pe-md-7 { + padding-right: 6rem !important; + } + .pb-md-0 { + padding-bottom: 0 !important; + } + .pb-md-1 { + padding-bottom: 0.25rem !important; + } + .pb-md-2 { + padding-bottom: 0.5rem !important; + } + .pb-md-3 { + padding-bottom: 1rem !important; + } + .pb-md-4 { + padding-bottom: 1.5rem !important; + } + .pb-md-5 { + padding-bottom: 3rem !important; + } + .pb-md-6 { + padding-bottom: 4.5rem !important; + } + .pb-md-7 { + padding-bottom: 6rem !important; + } + .ps-md-0 { + padding-left: 0 !important; + } + .ps-md-1 { + padding-left: 0.25rem !important; + } + .ps-md-2 { + padding-left: 0.5rem !important; + } + .ps-md-3 { + padding-left: 1rem !important; + } + .ps-md-4 { + padding-left: 1.5rem !important; + } + .ps-md-5 { + padding-left: 3rem !important; + } + .ps-md-6 { + padding-left: 4.5rem !important; + } + .ps-md-7 { + padding-left: 6rem !important; + } + .text-md-start { + text-align: left !important; + } + .text-md-end { + text-align: right !important; + } + .text-md-center { + text-align: center !important; + } +} + +@media (min-width: 992px) { + .float-lg-start { + float: left !important; + } + .float-lg-end { + float: right !important; + } + .float-lg-none { + float: none !important; + } + .d-lg-inline { + display: inline !important; + } + .d-lg-inline-block { + display: inline-block !important; + } + .d-lg-block { + display: block !important; + } + .d-lg-grid { + display: grid !important; + } + .d-lg-table { + display: table !important; + } + .d-lg-table-row { + display: table-row !important; + } + .d-lg-table-cell { + display: table-cell !important; + } + .d-lg-flex { + display: flex !important; + } + .d-lg-inline-flex { + display: inline-flex !important; + } + .d-lg-none { + display: none !important; + } + .flex-lg-fill { + flex: 1 1 auto !important; + } + .flex-lg-row { + flex-direction: row !important; + } + .flex-lg-column { + flex-direction: column !important; + } + .flex-lg-row-reverse { + flex-direction: row-reverse !important; + } + .flex-lg-column-reverse { + flex-direction: column-reverse !important; + } + .flex-lg-grow-0 { + flex-grow: 0 !important; + } + .flex-lg-grow-1 { + flex-grow: 1 !important; + } + .flex-lg-shrink-0 { + flex-shrink: 0 !important; + } + .flex-lg-shrink-1 { + flex-shrink: 1 !important; + } + .flex-lg-wrap { + flex-wrap: wrap !important; + } + .flex-lg-nowrap { + flex-wrap: nowrap !important; + } + .flex-lg-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .gap-lg-0 { + gap: 0 !important; + } + .gap-lg-1 { + gap: 0.25rem !important; + } + .gap-lg-2 { + gap: 0.5rem !important; + } + .gap-lg-3 { + gap: 1rem !important; + } + .gap-lg-4 { + gap: 1.5rem !important; + } + .gap-lg-5 { + gap: 3rem !important; + } + .gap-lg-6 { + gap: 4.5rem !important; + } + .gap-lg-7 { + gap: 6rem !important; + } + .justify-content-lg-start { + justify-content: flex-start !important; + } + .justify-content-lg-end { + justify-content: flex-end !important; + } + .justify-content-lg-center { + justify-content: center !important; + } + .justify-content-lg-between { + justify-content: space-between !important; + } + .justify-content-lg-around { + justify-content: space-around !important; + } + .justify-content-lg-evenly { + justify-content: space-evenly !important; + } + .align-items-lg-start { + align-items: flex-start !important; + } + .align-items-lg-end { + align-items: flex-end !important; + } + .align-items-lg-center { + align-items: center !important; + } + .align-items-lg-baseline { + align-items: baseline !important; + } + .align-items-lg-stretch { + align-items: stretch !important; + } + .align-content-lg-start { + align-content: flex-start !important; + } + .align-content-lg-end { + align-content: flex-end !important; + } + .align-content-lg-center { + align-content: center !important; + } + .align-content-lg-between { + align-content: space-between !important; + } + .align-content-lg-around { + align-content: space-around !important; + } + .align-content-lg-stretch { + align-content: stretch !important; + } + .align-self-lg-auto { + align-self: auto !important; + } + .align-self-lg-start { + align-self: flex-start !important; + } + .align-self-lg-end { + align-self: flex-end !important; + } + .align-self-lg-center { + align-self: center !important; + } + .align-self-lg-baseline { + align-self: baseline !important; + } + .align-self-lg-stretch { + align-self: stretch !important; + } + .order-lg-first { + order: -1 !important; + } + .order-lg-0 { + order: 0 !important; + } + .order-lg-1 { + order: 1 !important; + } + .order-lg-2 { + order: 2 !important; + } + .order-lg-3 { + order: 3 !important; + } + .order-lg-4 { + order: 4 !important; + } + .order-lg-5 { + order: 5 !important; + } + .order-lg-last { + order: 6 !important; + } + .m-lg-0 { + margin: 0 !important; + } + .m-lg-1 { + margin: 0.25rem !important; + } + .m-lg-2 { + margin: 0.5rem !important; + } + .m-lg-3 { + margin: 1rem !important; + } + .m-lg-4 { + margin: 1.5rem !important; + } + .m-lg-5 { + margin: 3rem !important; + } + .m-lg-6 { + margin: 4.5rem !important; + } + .m-lg-7 { + margin: 6rem !important; + } + .m-lg-auto { + margin: auto !important; + } + .mx-lg-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-lg-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-lg-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-lg-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-lg-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-lg-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-lg-6 { + margin-right: 4.5rem !important; + margin-left: 4.5rem !important; + } + .mx-lg-7 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-lg-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-lg-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-lg-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-lg-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-lg-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-lg-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-lg-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-lg-6 { + margin-top: 4.5rem !important; + margin-bottom: 4.5rem !important; + } + .my-lg-7 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-lg-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-lg-0 { + margin-top: 0 !important; + } + .mt-lg-1 { + margin-top: 0.25rem !important; + } + .mt-lg-2 { + margin-top: 0.5rem !important; + } + .mt-lg-3 { + margin-top: 1rem !important; + } + .mt-lg-4 { + margin-top: 1.5rem !important; + } + .mt-lg-5 { + margin-top: 3rem !important; + } + .mt-lg-6 { + margin-top: 4.5rem !important; + } + .mt-lg-7 { + margin-top: 6rem !important; + } + .mt-lg-auto { + margin-top: auto !important; + } + .me-lg-0 { + margin-right: 0 !important; + } + .me-lg-1 { + margin-right: 0.25rem !important; + } + .me-lg-2 { + margin-right: 0.5rem !important; + } + .me-lg-3 { + margin-right: 1rem !important; + } + .me-lg-4 { + margin-right: 1.5rem !important; + } + .me-lg-5 { + margin-right: 3rem !important; + } + .me-lg-6 { + margin-right: 4.5rem !important; + } + .me-lg-7 { + margin-right: 6rem !important; + } + .me-lg-auto { + margin-right: auto !important; + } + .mb-lg-0 { + margin-bottom: 0 !important; + } + .mb-lg-1 { + margin-bottom: 0.25rem !important; + } + .mb-lg-2 { + margin-bottom: 0.5rem !important; + } + .mb-lg-3 { + margin-bottom: 1rem !important; + } + .mb-lg-4 { + margin-bottom: 1.5rem !important; + } + .mb-lg-5 { + margin-bottom: 3rem !important; + } + .mb-lg-6 { + margin-bottom: 4.5rem !important; + } + .mb-lg-7 { + margin-bottom: 6rem !important; + } + .mb-lg-auto { + margin-bottom: auto !important; + } + .ms-lg-0 { + margin-left: 0 !important; + } + .ms-lg-1 { + margin-left: 0.25rem !important; + } + .ms-lg-2 { + margin-left: 0.5rem !important; + } + .ms-lg-3 { + margin-left: 1rem !important; + } + .ms-lg-4 { + margin-left: 1.5rem !important; + } + .ms-lg-5 { + margin-left: 3rem !important; + } + .ms-lg-6 { + margin-left: 4.5rem !important; + } + .ms-lg-7 { + margin-left: 6rem !important; + } + .ms-lg-auto { + margin-left: auto !important; + } + .m-lg-n1 { + margin: -0.25rem !important; + } + .m-lg-n2 { + margin: -0.5rem !important; + } + .m-lg-n3 { + margin: -1rem !important; + } + .m-lg-n4 { + margin: -1.5rem !important; + } + .m-lg-n5 { + margin: -3rem !important; + } + .m-lg-n6 { + margin: -4.5rem !important; + } + .m-lg-n7 { + margin: -6rem !important; + } + .mx-lg-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-lg-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-lg-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-lg-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-lg-n5 { + margin-right: -3rem !important; + margin-left: -3rem !important; + } + .mx-lg-n6 { + margin-right: -4.5rem !important; + margin-left: -4.5rem !important; + } + .mx-lg-n7 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .my-lg-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-lg-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-lg-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-lg-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-lg-n5 { + margin-top: -3rem !important; + margin-bottom: -3rem !important; + } + .my-lg-n6 { + margin-top: -4.5rem !important; + margin-bottom: -4.5rem !important; + } + .my-lg-n7 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .mt-lg-n1 { + margin-top: -0.25rem !important; + } + .mt-lg-n2 { + margin-top: -0.5rem !important; + } + .mt-lg-n3 { + margin-top: -1rem !important; + } + .mt-lg-n4 { + margin-top: -1.5rem !important; + } + .mt-lg-n5 { + margin-top: -3rem !important; + } + .mt-lg-n6 { + margin-top: -4.5rem !important; + } + .mt-lg-n7 { + margin-top: -6rem !important; + } + .me-lg-n1 { + margin-right: -0.25rem !important; + } + .me-lg-n2 { + margin-right: -0.5rem !important; + } + .me-lg-n3 { + margin-right: -1rem !important; + } + .me-lg-n4 { + margin-right: -1.5rem !important; + } + .me-lg-n5 { + margin-right: -3rem !important; + } + .me-lg-n6 { + margin-right: -4.5rem !important; + } + .me-lg-n7 { + margin-right: -6rem !important; + } + .mb-lg-n1 { + margin-bottom: -0.25rem !important; + } + .mb-lg-n2 { + margin-bottom: -0.5rem !important; + } + .mb-lg-n3 { + margin-bottom: -1rem !important; + } + .mb-lg-n4 { + margin-bottom: -1.5rem !important; + } + .mb-lg-n5 { + margin-bottom: -3rem !important; + } + .mb-lg-n6 { + margin-bottom: -4.5rem !important; + } + .mb-lg-n7 { + margin-bottom: -6rem !important; + } + .ms-lg-n1 { + margin-left: -0.25rem !important; + } + .ms-lg-n2 { + margin-left: -0.5rem !important; + } + .ms-lg-n3 { + margin-left: -1rem !important; + } + .ms-lg-n4 { + margin-left: -1.5rem !important; + } + .ms-lg-n5 { + margin-left: -3rem !important; + } + .ms-lg-n6 { + margin-left: -4.5rem !important; + } + .ms-lg-n7 { + margin-left: -6rem !important; + } + .p-lg-0 { + padding: 0 !important; + } + .p-lg-1 { + padding: 0.25rem !important; + } + .p-lg-2 { + padding: 0.5rem !important; + } + .p-lg-3 { + padding: 1rem !important; + } + .p-lg-4 { + padding: 1.5rem !important; + } + .p-lg-5 { + padding: 3rem !important; + } + .p-lg-6 { + padding: 4.5rem !important; + } + .p-lg-7 { + padding: 6rem !important; + } + .px-lg-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-lg-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-lg-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-lg-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-lg-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-lg-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .px-lg-6 { + padding-right: 4.5rem !important; + padding-left: 4.5rem !important; + } + .px-lg-7 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .py-lg-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-lg-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-lg-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-lg-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-lg-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-lg-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .py-lg-6 { + padding-top: 4.5rem !important; + padding-bottom: 4.5rem !important; + } + .py-lg-7 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .pt-lg-0 { + padding-top: 0 !important; + } + .pt-lg-1 { + padding-top: 0.25rem !important; + } + .pt-lg-2 { + padding-top: 0.5rem !important; + } + .pt-lg-3 { + padding-top: 1rem !important; + } + .pt-lg-4 { + padding-top: 1.5rem !important; + } + .pt-lg-5 { + padding-top: 3rem !important; + } + .pt-lg-6 { + padding-top: 4.5rem !important; + } + .pt-lg-7 { + padding-top: 6rem !important; + } + .pe-lg-0 { + padding-right: 0 !important; + } + .pe-lg-1 { + padding-right: 0.25rem !important; + } + .pe-lg-2 { + padding-right: 0.5rem !important; + } + .pe-lg-3 { + padding-right: 1rem !important; + } + .pe-lg-4 { + padding-right: 1.5rem !important; + } + .pe-lg-5 { + padding-right: 3rem !important; + } + .pe-lg-6 { + padding-right: 4.5rem !important; + } + .pe-lg-7 { + padding-right: 6rem !important; + } + .pb-lg-0 { + padding-bottom: 0 !important; + } + .pb-lg-1 { + padding-bottom: 0.25rem !important; + } + .pb-lg-2 { + padding-bottom: 0.5rem !important; + } + .pb-lg-3 { + padding-bottom: 1rem !important; + } + .pb-lg-4 { + padding-bottom: 1.5rem !important; + } + .pb-lg-5 { + padding-bottom: 3rem !important; + } + .pb-lg-6 { + padding-bottom: 4.5rem !important; + } + .pb-lg-7 { + padding-bottom: 6rem !important; + } + .ps-lg-0 { + padding-left: 0 !important; + } + .ps-lg-1 { + padding-left: 0.25rem !important; + } + .ps-lg-2 { + padding-left: 0.5rem !important; + } + .ps-lg-3 { + padding-left: 1rem !important; + } + .ps-lg-4 { + padding-left: 1.5rem !important; + } + .ps-lg-5 { + padding-left: 3rem !important; + } + .ps-lg-6 { + padding-left: 4.5rem !important; + } + .ps-lg-7 { + padding-left: 6rem !important; + } + .text-lg-start { + text-align: left !important; + } + .text-lg-end { + text-align: right !important; + } + .text-lg-center { + text-align: center !important; + } +} + +@media (min-width: 1200px) { + .float-xl-start { + float: left !important; + } + .float-xl-end { + float: right !important; + } + .float-xl-none { + float: none !important; + } + .d-xl-inline { + display: inline !important; + } + .d-xl-inline-block { + display: inline-block !important; + } + .d-xl-block { + display: block !important; + } + .d-xl-grid { + display: grid !important; + } + .d-xl-table { + display: table !important; + } + .d-xl-table-row { + display: table-row !important; + } + .d-xl-table-cell { + display: table-cell !important; + } + .d-xl-flex { + display: flex !important; + } + .d-xl-inline-flex { + display: inline-flex !important; + } + .d-xl-none { + display: none !important; + } + .flex-xl-fill { + flex: 1 1 auto !important; + } + .flex-xl-row { + flex-direction: row !important; + } + .flex-xl-column { + flex-direction: column !important; + } + .flex-xl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xl-grow-0 { + flex-grow: 0 !important; + } + .flex-xl-grow-1 { + flex-grow: 1 !important; + } + .flex-xl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xl-wrap { + flex-wrap: wrap !important; + } + .flex-xl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .gap-xl-0 { + gap: 0 !important; + } + .gap-xl-1 { + gap: 0.25rem !important; + } + .gap-xl-2 { + gap: 0.5rem !important; + } + .gap-xl-3 { + gap: 1rem !important; + } + .gap-xl-4 { + gap: 1.5rem !important; + } + .gap-xl-5 { + gap: 3rem !important; + } + .gap-xl-6 { + gap: 4.5rem !important; + } + .gap-xl-7 { + gap: 6rem !important; + } + .justify-content-xl-start { + justify-content: flex-start !important; + } + .justify-content-xl-end { + justify-content: flex-end !important; + } + .justify-content-xl-center { + justify-content: center !important; + } + .justify-content-xl-between { + justify-content: space-between !important; + } + .justify-content-xl-around { + justify-content: space-around !important; + } + .justify-content-xl-evenly { + justify-content: space-evenly !important; + } + .align-items-xl-start { + align-items: flex-start !important; + } + .align-items-xl-end { + align-items: flex-end !important; + } + .align-items-xl-center { + align-items: center !important; + } + .align-items-xl-baseline { + align-items: baseline !important; + } + .align-items-xl-stretch { + align-items: stretch !important; + } + .align-content-xl-start { + align-content: flex-start !important; + } + .align-content-xl-end { + align-content: flex-end !important; + } + .align-content-xl-center { + align-content: center !important; + } + .align-content-xl-between { + align-content: space-between !important; + } + .align-content-xl-around { + align-content: space-around !important; + } + .align-content-xl-stretch { + align-content: stretch !important; + } + .align-self-xl-auto { + align-self: auto !important; + } + .align-self-xl-start { + align-self: flex-start !important; + } + .align-self-xl-end { + align-self: flex-end !important; + } + .align-self-xl-center { + align-self: center !important; + } + .align-self-xl-baseline { + align-self: baseline !important; + } + .align-self-xl-stretch { + align-self: stretch !important; + } + .order-xl-first { + order: -1 !important; + } + .order-xl-0 { + order: 0 !important; + } + .order-xl-1 { + order: 1 !important; + } + .order-xl-2 { + order: 2 !important; + } + .order-xl-3 { + order: 3 !important; + } + .order-xl-4 { + order: 4 !important; + } + .order-xl-5 { + order: 5 !important; + } + .order-xl-last { + order: 6 !important; + } + .m-xl-0 { + margin: 0 !important; + } + .m-xl-1 { + margin: 0.25rem !important; + } + .m-xl-2 { + margin: 0.5rem !important; + } + .m-xl-3 { + margin: 1rem !important; + } + .m-xl-4 { + margin: 1.5rem !important; + } + .m-xl-5 { + margin: 3rem !important; + } + .m-xl-6 { + margin: 4.5rem !important; + } + .m-xl-7 { + margin: 6rem !important; + } + .m-xl-auto { + margin: auto !important; + } + .mx-xl-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-xl-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-xl-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-xl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-xl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-xl-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-xl-6 { + margin-right: 4.5rem !important; + margin-left: 4.5rem !important; + } + .mx-xl-7 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-xl-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-xl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-xl-6 { + margin-top: 4.5rem !important; + margin-bottom: 4.5rem !important; + } + .my-xl-7 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-xl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xl-0 { + margin-top: 0 !important; + } + .mt-xl-1 { + margin-top: 0.25rem !important; + } + .mt-xl-2 { + margin-top: 0.5rem !important; + } + .mt-xl-3 { + margin-top: 1rem !important; + } + .mt-xl-4 { + margin-top: 1.5rem !important; + } + .mt-xl-5 { + margin-top: 3rem !important; + } + .mt-xl-6 { + margin-top: 4.5rem !important; + } + .mt-xl-7 { + margin-top: 6rem !important; + } + .mt-xl-auto { + margin-top: auto !important; + } + .me-xl-0 { + margin-right: 0 !important; + } + .me-xl-1 { + margin-right: 0.25rem !important; + } + .me-xl-2 { + margin-right: 0.5rem !important; + } + .me-xl-3 { + margin-right: 1rem !important; + } + .me-xl-4 { + margin-right: 1.5rem !important; + } + .me-xl-5 { + margin-right: 3rem !important; + } + .me-xl-6 { + margin-right: 4.5rem !important; + } + .me-xl-7 { + margin-right: 6rem !important; + } + .me-xl-auto { + margin-right: auto !important; + } + .mb-xl-0 { + margin-bottom: 0 !important; + } + .mb-xl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xl-3 { + margin-bottom: 1rem !important; + } + .mb-xl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xl-5 { + margin-bottom: 3rem !important; + } + .mb-xl-6 { + margin-bottom: 4.5rem !important; + } + .mb-xl-7 { + margin-bottom: 6rem !important; + } + .mb-xl-auto { + margin-bottom: auto !important; + } + .ms-xl-0 { + margin-left: 0 !important; + } + .ms-xl-1 { + margin-left: 0.25rem !important; + } + .ms-xl-2 { + margin-left: 0.5rem !important; + } + .ms-xl-3 { + margin-left: 1rem !important; + } + .ms-xl-4 { + margin-left: 1.5rem !important; + } + .ms-xl-5 { + margin-left: 3rem !important; + } + .ms-xl-6 { + margin-left: 4.5rem !important; + } + .ms-xl-7 { + margin-left: 6rem !important; + } + .ms-xl-auto { + margin-left: auto !important; + } + .m-xl-n1 { + margin: -0.25rem !important; + } + .m-xl-n2 { + margin: -0.5rem !important; + } + .m-xl-n3 { + margin: -1rem !important; + } + .m-xl-n4 { + margin: -1.5rem !important; + } + .m-xl-n5 { + margin: -3rem !important; + } + .m-xl-n6 { + margin: -4.5rem !important; + } + .m-xl-n7 { + margin: -6rem !important; + } + .mx-xl-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-xl-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-xl-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-xl-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-xl-n5 { + margin-right: -3rem !important; + margin-left: -3rem !important; + } + .mx-xl-n6 { + margin-right: -4.5rem !important; + margin-left: -4.5rem !important; + } + .mx-xl-n7 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .my-xl-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-xl-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-xl-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-xl-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-xl-n5 { + margin-top: -3rem !important; + margin-bottom: -3rem !important; + } + .my-xl-n6 { + margin-top: -4.5rem !important; + margin-bottom: -4.5rem !important; + } + .my-xl-n7 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .mt-xl-n1 { + margin-top: -0.25rem !important; + } + .mt-xl-n2 { + margin-top: -0.5rem !important; + } + .mt-xl-n3 { + margin-top: -1rem !important; + } + .mt-xl-n4 { + margin-top: -1.5rem !important; + } + .mt-xl-n5 { + margin-top: -3rem !important; + } + .mt-xl-n6 { + margin-top: -4.5rem !important; + } + .mt-xl-n7 { + margin-top: -6rem !important; + } + .me-xl-n1 { + margin-right: -0.25rem !important; + } + .me-xl-n2 { + margin-right: -0.5rem !important; + } + .me-xl-n3 { + margin-right: -1rem !important; + } + .me-xl-n4 { + margin-right: -1.5rem !important; + } + .me-xl-n5 { + margin-right: -3rem !important; + } + .me-xl-n6 { + margin-right: -4.5rem !important; + } + .me-xl-n7 { + margin-right: -6rem !important; + } + .mb-xl-n1 { + margin-bottom: -0.25rem !important; + } + .mb-xl-n2 { + margin-bottom: -0.5rem !important; + } + .mb-xl-n3 { + margin-bottom: -1rem !important; + } + .mb-xl-n4 { + margin-bottom: -1.5rem !important; + } + .mb-xl-n5 { + margin-bottom: -3rem !important; + } + .mb-xl-n6 { + margin-bottom: -4.5rem !important; + } + .mb-xl-n7 { + margin-bottom: -6rem !important; + } + .ms-xl-n1 { + margin-left: -0.25rem !important; + } + .ms-xl-n2 { + margin-left: -0.5rem !important; + } + .ms-xl-n3 { + margin-left: -1rem !important; + } + .ms-xl-n4 { + margin-left: -1.5rem !important; + } + .ms-xl-n5 { + margin-left: -3rem !important; + } + .ms-xl-n6 { + margin-left: -4.5rem !important; + } + .ms-xl-n7 { + margin-left: -6rem !important; + } + .p-xl-0 { + padding: 0 !important; + } + .p-xl-1 { + padding: 0.25rem !important; + } + .p-xl-2 { + padding: 0.5rem !important; + } + .p-xl-3 { + padding: 1rem !important; + } + .p-xl-4 { + padding: 1.5rem !important; + } + .p-xl-5 { + padding: 3rem !important; + } + .p-xl-6 { + padding: 4.5rem !important; + } + .p-xl-7 { + padding: 6rem !important; + } + .px-xl-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-xl-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-xl-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-xl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-xl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-xl-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .px-xl-6 { + padding-right: 4.5rem !important; + padding-left: 4.5rem !important; + } + .px-xl-7 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .py-xl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .py-xl-6 { + padding-top: 4.5rem !important; + padding-bottom: 4.5rem !important; + } + .py-xl-7 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .pt-xl-0 { + padding-top: 0 !important; + } + .pt-xl-1 { + padding-top: 0.25rem !important; + } + .pt-xl-2 { + padding-top: 0.5rem !important; + } + .pt-xl-3 { + padding-top: 1rem !important; + } + .pt-xl-4 { + padding-top: 1.5rem !important; + } + .pt-xl-5 { + padding-top: 3rem !important; + } + .pt-xl-6 { + padding-top: 4.5rem !important; + } + .pt-xl-7 { + padding-top: 6rem !important; + } + .pe-xl-0 { + padding-right: 0 !important; + } + .pe-xl-1 { + padding-right: 0.25rem !important; + } + .pe-xl-2 { + padding-right: 0.5rem !important; + } + .pe-xl-3 { + padding-right: 1rem !important; + } + .pe-xl-4 { + padding-right: 1.5rem !important; + } + .pe-xl-5 { + padding-right: 3rem !important; + } + .pe-xl-6 { + padding-right: 4.5rem !important; + } + .pe-xl-7 { + padding-right: 6rem !important; + } + .pb-xl-0 { + padding-bottom: 0 !important; + } + .pb-xl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xl-3 { + padding-bottom: 1rem !important; + } + .pb-xl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xl-5 { + padding-bottom: 3rem !important; + } + .pb-xl-6 { + padding-bottom: 4.5rem !important; + } + .pb-xl-7 { + padding-bottom: 6rem !important; + } + .ps-xl-0 { + padding-left: 0 !important; + } + .ps-xl-1 { + padding-left: 0.25rem !important; + } + .ps-xl-2 { + padding-left: 0.5rem !important; + } + .ps-xl-3 { + padding-left: 1rem !important; + } + .ps-xl-4 { + padding-left: 1.5rem !important; + } + .ps-xl-5 { + padding-left: 3rem !important; + } + .ps-xl-6 { + padding-left: 4.5rem !important; + } + .ps-xl-7 { + padding-left: 6rem !important; + } + .text-xl-start { + text-align: left !important; + } + .text-xl-end { + text-align: right !important; + } + .text-xl-center { + text-align: center !important; + } +} + +@media (min-width: 1440px) { + .float-xxl-start { + float: left !important; + } + .float-xxl-end { + float: right !important; + } + .float-xxl-none { + float: none !important; + } + .d-xxl-inline { + display: inline !important; + } + .d-xxl-inline-block { + display: inline-block !important; + } + .d-xxl-block { + display: block !important; + } + .d-xxl-grid { + display: grid !important; + } + .d-xxl-table { + display: table !important; + } + .d-xxl-table-row { + display: table-row !important; + } + .d-xxl-table-cell { + display: table-cell !important; + } + .d-xxl-flex { + display: flex !important; + } + .d-xxl-inline-flex { + display: inline-flex !important; + } + .d-xxl-none { + display: none !important; + } + .flex-xxl-fill { + flex: 1 1 auto !important; + } + .flex-xxl-row { + flex-direction: row !important; + } + .flex-xxl-column { + flex-direction: column !important; + } + .flex-xxl-row-reverse { + flex-direction: row-reverse !important; + } + .flex-xxl-column-reverse { + flex-direction: column-reverse !important; + } + .flex-xxl-grow-0 { + flex-grow: 0 !important; + } + .flex-xxl-grow-1 { + flex-grow: 1 !important; + } + .flex-xxl-shrink-0 { + flex-shrink: 0 !important; + } + .flex-xxl-shrink-1 { + flex-shrink: 1 !important; + } + .flex-xxl-wrap { + flex-wrap: wrap !important; + } + .flex-xxl-nowrap { + flex-wrap: nowrap !important; + } + .flex-xxl-wrap-reverse { + flex-wrap: wrap-reverse !important; + } + .gap-xxl-0 { + gap: 0 !important; + } + .gap-xxl-1 { + gap: 0.25rem !important; + } + .gap-xxl-2 { + gap: 0.5rem !important; + } + .gap-xxl-3 { + gap: 1rem !important; + } + .gap-xxl-4 { + gap: 1.5rem !important; + } + .gap-xxl-5 { + gap: 3rem !important; + } + .gap-xxl-6 { + gap: 4.5rem !important; + } + .gap-xxl-7 { + gap: 6rem !important; + } + .justify-content-xxl-start { + justify-content: flex-start !important; + } + .justify-content-xxl-end { + justify-content: flex-end !important; + } + .justify-content-xxl-center { + justify-content: center !important; + } + .justify-content-xxl-between { + justify-content: space-between !important; + } + .justify-content-xxl-around { + justify-content: space-around !important; + } + .justify-content-xxl-evenly { + justify-content: space-evenly !important; + } + .align-items-xxl-start { + align-items: flex-start !important; + } + .align-items-xxl-end { + align-items: flex-end !important; + } + .align-items-xxl-center { + align-items: center !important; + } + .align-items-xxl-baseline { + align-items: baseline !important; + } + .align-items-xxl-stretch { + align-items: stretch !important; + } + .align-content-xxl-start { + align-content: flex-start !important; + } + .align-content-xxl-end { + align-content: flex-end !important; + } + .align-content-xxl-center { + align-content: center !important; + } + .align-content-xxl-between { + align-content: space-between !important; + } + .align-content-xxl-around { + align-content: space-around !important; + } + .align-content-xxl-stretch { + align-content: stretch !important; + } + .align-self-xxl-auto { + align-self: auto !important; + } + .align-self-xxl-start { + align-self: flex-start !important; + } + .align-self-xxl-end { + align-self: flex-end !important; + } + .align-self-xxl-center { + align-self: center !important; + } + .align-self-xxl-baseline { + align-self: baseline !important; + } + .align-self-xxl-stretch { + align-self: stretch !important; + } + .order-xxl-first { + order: -1 !important; + } + .order-xxl-0 { + order: 0 !important; + } + .order-xxl-1 { + order: 1 !important; + } + .order-xxl-2 { + order: 2 !important; + } + .order-xxl-3 { + order: 3 !important; + } + .order-xxl-4 { + order: 4 !important; + } + .order-xxl-5 { + order: 5 !important; + } + .order-xxl-last { + order: 6 !important; + } + .m-xxl-0 { + margin: 0 !important; + } + .m-xxl-1 { + margin: 0.25rem !important; + } + .m-xxl-2 { + margin: 0.5rem !important; + } + .m-xxl-3 { + margin: 1rem !important; + } + .m-xxl-4 { + margin: 1.5rem !important; + } + .m-xxl-5 { + margin: 3rem !important; + } + .m-xxl-6 { + margin: 4.5rem !important; + } + .m-xxl-7 { + margin: 6rem !important; + } + .m-xxl-auto { + margin: auto !important; + } + .mx-xxl-0 { + margin-right: 0 !important; + margin-left: 0 !important; + } + .mx-xxl-1 { + margin-right: 0.25rem !important; + margin-left: 0.25rem !important; + } + .mx-xxl-2 { + margin-right: 0.5rem !important; + margin-left: 0.5rem !important; + } + .mx-xxl-3 { + margin-right: 1rem !important; + margin-left: 1rem !important; + } + .mx-xxl-4 { + margin-right: 1.5rem !important; + margin-left: 1.5rem !important; + } + .mx-xxl-5 { + margin-right: 3rem !important; + margin-left: 3rem !important; + } + .mx-xxl-6 { + margin-right: 4.5rem !important; + margin-left: 4.5rem !important; + } + .mx-xxl-7 { + margin-right: 6rem !important; + margin-left: 6rem !important; + } + .mx-xxl-auto { + margin-right: auto !important; + margin-left: auto !important; + } + .my-xxl-0 { + margin-top: 0 !important; + margin-bottom: 0 !important; + } + .my-xxl-1 { + margin-top: 0.25rem !important; + margin-bottom: 0.25rem !important; + } + .my-xxl-2 { + margin-top: 0.5rem !important; + margin-bottom: 0.5rem !important; + } + .my-xxl-3 { + margin-top: 1rem !important; + margin-bottom: 1rem !important; + } + .my-xxl-4 { + margin-top: 1.5rem !important; + margin-bottom: 1.5rem !important; + } + .my-xxl-5 { + margin-top: 3rem !important; + margin-bottom: 3rem !important; + } + .my-xxl-6 { + margin-top: 4.5rem !important; + margin-bottom: 4.5rem !important; + } + .my-xxl-7 { + margin-top: 6rem !important; + margin-bottom: 6rem !important; + } + .my-xxl-auto { + margin-top: auto !important; + margin-bottom: auto !important; + } + .mt-xxl-0 { + margin-top: 0 !important; + } + .mt-xxl-1 { + margin-top: 0.25rem !important; + } + .mt-xxl-2 { + margin-top: 0.5rem !important; + } + .mt-xxl-3 { + margin-top: 1rem !important; + } + .mt-xxl-4 { + margin-top: 1.5rem !important; + } + .mt-xxl-5 { + margin-top: 3rem !important; + } + .mt-xxl-6 { + margin-top: 4.5rem !important; + } + .mt-xxl-7 { + margin-top: 6rem !important; + } + .mt-xxl-auto { + margin-top: auto !important; + } + .me-xxl-0 { + margin-right: 0 !important; + } + .me-xxl-1 { + margin-right: 0.25rem !important; + } + .me-xxl-2 { + margin-right: 0.5rem !important; + } + .me-xxl-3 { + margin-right: 1rem !important; + } + .me-xxl-4 { + margin-right: 1.5rem !important; + } + .me-xxl-5 { + margin-right: 3rem !important; + } + .me-xxl-6 { + margin-right: 4.5rem !important; + } + .me-xxl-7 { + margin-right: 6rem !important; + } + .me-xxl-auto { + margin-right: auto !important; + } + .mb-xxl-0 { + margin-bottom: 0 !important; + } + .mb-xxl-1 { + margin-bottom: 0.25rem !important; + } + .mb-xxl-2 { + margin-bottom: 0.5rem !important; + } + .mb-xxl-3 { + margin-bottom: 1rem !important; + } + .mb-xxl-4 { + margin-bottom: 1.5rem !important; + } + .mb-xxl-5 { + margin-bottom: 3rem !important; + } + .mb-xxl-6 { + margin-bottom: 4.5rem !important; + } + .mb-xxl-7 { + margin-bottom: 6rem !important; + } + .mb-xxl-auto { + margin-bottom: auto !important; + } + .ms-xxl-0 { + margin-left: 0 !important; + } + .ms-xxl-1 { + margin-left: 0.25rem !important; + } + .ms-xxl-2 { + margin-left: 0.5rem !important; + } + .ms-xxl-3 { + margin-left: 1rem !important; + } + .ms-xxl-4 { + margin-left: 1.5rem !important; + } + .ms-xxl-5 { + margin-left: 3rem !important; + } + .ms-xxl-6 { + margin-left: 4.5rem !important; + } + .ms-xxl-7 { + margin-left: 6rem !important; + } + .ms-xxl-auto { + margin-left: auto !important; + } + .m-xxl-n1 { + margin: -0.25rem !important; + } + .m-xxl-n2 { + margin: -0.5rem !important; + } + .m-xxl-n3 { + margin: -1rem !important; + } + .m-xxl-n4 { + margin: -1.5rem !important; + } + .m-xxl-n5 { + margin: -3rem !important; + } + .m-xxl-n6 { + margin: -4.5rem !important; + } + .m-xxl-n7 { + margin: -6rem !important; + } + .mx-xxl-n1 { + margin-right: -0.25rem !important; + margin-left: -0.25rem !important; + } + .mx-xxl-n2 { + margin-right: -0.5rem !important; + margin-left: -0.5rem !important; + } + .mx-xxl-n3 { + margin-right: -1rem !important; + margin-left: -1rem !important; + } + .mx-xxl-n4 { + margin-right: -1.5rem !important; + margin-left: -1.5rem !important; + } + .mx-xxl-n5 { + margin-right: -3rem !important; + margin-left: -3rem !important; + } + .mx-xxl-n6 { + margin-right: -4.5rem !important; + margin-left: -4.5rem !important; + } + .mx-xxl-n7 { + margin-right: -6rem !important; + margin-left: -6rem !important; + } + .my-xxl-n1 { + margin-top: -0.25rem !important; + margin-bottom: -0.25rem !important; + } + .my-xxl-n2 { + margin-top: -0.5rem !important; + margin-bottom: -0.5rem !important; + } + .my-xxl-n3 { + margin-top: -1rem !important; + margin-bottom: -1rem !important; + } + .my-xxl-n4 { + margin-top: -1.5rem !important; + margin-bottom: -1.5rem !important; + } + .my-xxl-n5 { + margin-top: -3rem !important; + margin-bottom: -3rem !important; + } + .my-xxl-n6 { + margin-top: -4.5rem !important; + margin-bottom: -4.5rem !important; + } + .my-xxl-n7 { + margin-top: -6rem !important; + margin-bottom: -6rem !important; + } + .mt-xxl-n1 { + margin-top: -0.25rem !important; + } + .mt-xxl-n2 { + margin-top: -0.5rem !important; + } + .mt-xxl-n3 { + margin-top: -1rem !important; + } + .mt-xxl-n4 { + margin-top: -1.5rem !important; + } + .mt-xxl-n5 { + margin-top: -3rem !important; + } + .mt-xxl-n6 { + margin-top: -4.5rem !important; + } + .mt-xxl-n7 { + margin-top: -6rem !important; + } + .me-xxl-n1 { + margin-right: -0.25rem !important; + } + .me-xxl-n2 { + margin-right: -0.5rem !important; + } + .me-xxl-n3 { + margin-right: -1rem !important; + } + .me-xxl-n4 { + margin-right: -1.5rem !important; + } + .me-xxl-n5 { + margin-right: -3rem !important; + } + .me-xxl-n6 { + margin-right: -4.5rem !important; + } + .me-xxl-n7 { + margin-right: -6rem !important; + } + .mb-xxl-n1 { + margin-bottom: -0.25rem !important; + } + .mb-xxl-n2 { + margin-bottom: -0.5rem !important; + } + .mb-xxl-n3 { + margin-bottom: -1rem !important; + } + .mb-xxl-n4 { + margin-bottom: -1.5rem !important; + } + .mb-xxl-n5 { + margin-bottom: -3rem !important; + } + .mb-xxl-n6 { + margin-bottom: -4.5rem !important; + } + .mb-xxl-n7 { + margin-bottom: -6rem !important; + } + .ms-xxl-n1 { + margin-left: -0.25rem !important; + } + .ms-xxl-n2 { + margin-left: -0.5rem !important; + } + .ms-xxl-n3 { + margin-left: -1rem !important; + } + .ms-xxl-n4 { + margin-left: -1.5rem !important; + } + .ms-xxl-n5 { + margin-left: -3rem !important; + } + .ms-xxl-n6 { + margin-left: -4.5rem !important; + } + .ms-xxl-n7 { + margin-left: -6rem !important; + } + .p-xxl-0 { + padding: 0 !important; + } + .p-xxl-1 { + padding: 0.25rem !important; + } + .p-xxl-2 { + padding: 0.5rem !important; + } + .p-xxl-3 { + padding: 1rem !important; + } + .p-xxl-4 { + padding: 1.5rem !important; + } + .p-xxl-5 { + padding: 3rem !important; + } + .p-xxl-6 { + padding: 4.5rem !important; + } + .p-xxl-7 { + padding: 6rem !important; + } + .px-xxl-0 { + padding-right: 0 !important; + padding-left: 0 !important; + } + .px-xxl-1 { + padding-right: 0.25rem !important; + padding-left: 0.25rem !important; + } + .px-xxl-2 { + padding-right: 0.5rem !important; + padding-left: 0.5rem !important; + } + .px-xxl-3 { + padding-right: 1rem !important; + padding-left: 1rem !important; + } + .px-xxl-4 { + padding-right: 1.5rem !important; + padding-left: 1.5rem !important; + } + .px-xxl-5 { + padding-right: 3rem !important; + padding-left: 3rem !important; + } + .px-xxl-6 { + padding-right: 4.5rem !important; + padding-left: 4.5rem !important; + } + .px-xxl-7 { + padding-right: 6rem !important; + padding-left: 6rem !important; + } + .py-xxl-0 { + padding-top: 0 !important; + padding-bottom: 0 !important; + } + .py-xxl-1 { + padding-top: 0.25rem !important; + padding-bottom: 0.25rem !important; + } + .py-xxl-2 { + padding-top: 0.5rem !important; + padding-bottom: 0.5rem !important; + } + .py-xxl-3 { + padding-top: 1rem !important; + padding-bottom: 1rem !important; + } + .py-xxl-4 { + padding-top: 1.5rem !important; + padding-bottom: 1.5rem !important; + } + .py-xxl-5 { + padding-top: 3rem !important; + padding-bottom: 3rem !important; + } + .py-xxl-6 { + padding-top: 4.5rem !important; + padding-bottom: 4.5rem !important; + } + .py-xxl-7 { + padding-top: 6rem !important; + padding-bottom: 6rem !important; + } + .pt-xxl-0 { + padding-top: 0 !important; + } + .pt-xxl-1 { + padding-top: 0.25rem !important; + } + .pt-xxl-2 { + padding-top: 0.5rem !important; + } + .pt-xxl-3 { + padding-top: 1rem !important; + } + .pt-xxl-4 { + padding-top: 1.5rem !important; + } + .pt-xxl-5 { + padding-top: 3rem !important; + } + .pt-xxl-6 { + padding-top: 4.5rem !important; + } + .pt-xxl-7 { + padding-top: 6rem !important; + } + .pe-xxl-0 { + padding-right: 0 !important; + } + .pe-xxl-1 { + padding-right: 0.25rem !important; + } + .pe-xxl-2 { + padding-right: 0.5rem !important; + } + .pe-xxl-3 { + padding-right: 1rem !important; + } + .pe-xxl-4 { + padding-right: 1.5rem !important; + } + .pe-xxl-5 { + padding-right: 3rem !important; + } + .pe-xxl-6 { + padding-right: 4.5rem !important; + } + .pe-xxl-7 { + padding-right: 6rem !important; + } + .pb-xxl-0 { + padding-bottom: 0 !important; + } + .pb-xxl-1 { + padding-bottom: 0.25rem !important; + } + .pb-xxl-2 { + padding-bottom: 0.5rem !important; + } + .pb-xxl-3 { + padding-bottom: 1rem !important; + } + .pb-xxl-4 { + padding-bottom: 1.5rem !important; + } + .pb-xxl-5 { + padding-bottom: 3rem !important; + } + .pb-xxl-6 { + padding-bottom: 4.5rem !important; + } + .pb-xxl-7 { + padding-bottom: 6rem !important; + } + .ps-xxl-0 { + padding-left: 0 !important; + } + .ps-xxl-1 { + padding-left: 0.25rem !important; + } + .ps-xxl-2 { + padding-left: 0.5rem !important; + } + .ps-xxl-3 { + padding-left: 1rem !important; + } + .ps-xxl-4 { + padding-left: 1.5rem !important; + } + .ps-xxl-5 { + padding-left: 3rem !important; + } + .ps-xxl-6 { + padding-left: 4.5rem !important; + } + .ps-xxl-7 { + padding-left: 6rem !important; + } + .text-xxl-start { + text-align: left !important; + } + .text-xxl-end { + text-align: right !important; + } + .text-xxl-center { + text-align: center !important; + } +} + +@media print { + .d-print-inline { + display: inline !important; + } + .d-print-inline-block { + display: inline-block !important; + } + .d-print-block { + display: block !important; + } + .d-print-grid { + display: grid !important; + } + .d-print-table { + display: table !important; + } + .d-print-table-row { + display: table-row !important; + } + .d-print-table-cell { + display: table-cell !important; + } + .d-print-flex { + display: flex !important; + } + .d-print-inline-flex { + display: inline-flex !important; + } + .d-print-none { + display: none !important; + } +} + +.accordion .card:not(:last-child) { + margin-bottom: 0; +} + +.accordion .card-header { + border-bottom: 0; +} + +.accordion .card-body { + border-top: 1px solid transparent; +} + +.accordion .card-title a { + color: #495057; +} + +.alert { + padding: 0; + display: flex; +} + +.alert-outline { + color: #495057; + background: #fff; +} + +.alert-outline hr { + border-top-color: #ced4da; +} + +.alert-outline .alert-message { + border-top-right-radius: 0.2rem; + border-bottom-right-radius: 0.2rem; + border-top-left-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; + border: 1px solid #ced4da; +} + +.alert-outline .alert-message:not(:nth-child(2)) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + border-left: 0; +} + +.alert-outline .alert-icon { + border-top-left-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; + color: #fff; +} + +.alert-outline.alert-primary .alert-icon { + background-color: #3B7DDD; +} + +.alert-outline.alert-secondary .alert-icon { + background-color: #6c757d; +} + +.alert-outline.alert-success .alert-icon { + background-color: #28a745; +} + +.alert-outline.alert-info .alert-icon { + background-color: #17a2b8; +} + +.alert-outline.alert-warning .alert-icon { + background-color: #ffc107; +} + +.alert-outline.alert-danger .alert-icon { + background-color: #dc3545; +} + +.alert-outline.alert-light .alert-icon { + background-color: #f8f9fa; +} + +.alert-outline.alert-dark .alert-icon { + background-color: #212529; +} + +.alert-message { + padding: 0.95rem 0.95rem; + width: 100%; + box-sizing: border-box; +} + +.avatar { + width: 40px; + height: 40px; +} + +.avatar-title { + display: flex; + width: 100%; + height: 100%; + align-items: center; + justify-content: center; + color: #3B7DDD; +} + +.btn .feather { + width: 14px; + height: 14px; +} + +.btn-primary, .btn-primary:focus, .btn-primary.focus, .btn-primary.disabled, .btn-primary:disabled, +.show > .btn-primary.dropdown-toggle { + color: #fff; +} + +.btn-primary:hover:not(:disabled):not(.disabled), .btn-primary.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-secondary, .btn-secondary:focus, .btn-secondary.focus, .btn-secondary.disabled, .btn-secondary:disabled, +.show > .btn-secondary.dropdown-toggle { + color: #fff; +} + +.btn-secondary:hover:not(:disabled):not(.disabled), .btn-secondary.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-success, .btn-success:focus, .btn-success.focus, .btn-success.disabled, .btn-success:disabled, +.show > .btn-success.dropdown-toggle { + color: #fff; +} + +.btn-success:hover:not(:disabled):not(.disabled), .btn-success.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-info, .btn-info:focus, .btn-info.focus, .btn-info.disabled, .btn-info:disabled, +.show > .btn-info.dropdown-toggle { + color: #fff; +} + +.btn-info:hover:not(:disabled):not(.disabled), .btn-info.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-warning, .btn-warning:focus, .btn-warning.focus, .btn-warning.disabled, .btn-warning:disabled, +.show > .btn-warning.dropdown-toggle { + color: #fff; +} + +.btn-warning:hover:not(:disabled):not(.disabled), .btn-warning.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-danger, .btn-danger:focus, .btn-danger.focus, .btn-danger.disabled, .btn-danger:disabled, +.show > .btn-danger.dropdown-toggle { + color: #fff; +} + +.btn-danger:hover:not(:disabled):not(.disabled), .btn-danger.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-light, .btn-light:focus, .btn-light.focus, .btn-light.disabled, .btn-light:disabled, +.show > .btn-light.dropdown-toggle { + color: #fff; +} + +.btn-light:hover:not(:disabled):not(.disabled), .btn-light.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-dark, .btn-dark:focus, .btn-dark.focus, .btn-dark.disabled, .btn-dark:disabled, +.show > .btn-dark.dropdown-toggle { + color: #fff; +} + +.btn-dark:hover:not(:disabled):not(.disabled), .btn-dark.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-facebook { + color: #fff; + background-color: #3b5998; + border-color: #3b5998; +} + +.btn-facebook:hover { + color: #fff; + background-color: #324c81; + border-color: #2f477a; +} + +.btn-check:focus + .btn-facebook, .btn-facebook:focus { + color: #fff; + background-color: #324c81; + border-color: #2f477a; + box-shadow: 0 0 0 0.2rem rgba(88, 114, 167, 0.5); +} + +.btn-check:checked + .btn-facebook, +.btn-check:active + .btn-facebook, .btn-facebook:active, .btn-facebook.active, +.show > .btn-facebook.dropdown-toggle { + color: #fff; + background-color: #2f477a; + border-color: #2c4372; +} + +.btn-check:checked + .btn-facebook:focus, +.btn-check:active + .btn-facebook:focus, .btn-facebook:active:focus, .btn-facebook.active:focus, +.show > .btn-facebook.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(88, 114, 167, 0.5); +} + +.btn-facebook:disabled, .btn-facebook.disabled { + color: #fff; + background-color: #3b5998; + border-color: #3b5998; +} + +.btn-facebook, .btn-facebook:focus, .btn-facebook.focus, .btn-facebook.disabled, .btn-facebook:disabled, +.show > .btn-facebook.dropdown-toggle { + color: #fff; +} + +.btn-facebook:hover:not(:disabled):not(.disabled), .btn-facebook.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-twitter { + color: #000; + background-color: #1da1f2; + border-color: #1da1f2; +} + +.btn-twitter:hover { + color: #000; + background-color: #3faff4; + border-color: #34aaf3; +} + +.btn-check:focus + .btn-twitter, .btn-twitter:focus { + color: #000; + background-color: #3faff4; + border-color: #34aaf3; + box-shadow: 0 0 0 0.2rem rgba(25, 137, 206, 0.5); +} + +.btn-check:checked + .btn-twitter, +.btn-check:active + .btn-twitter, .btn-twitter:active, .btn-twitter.active, +.show > .btn-twitter.dropdown-toggle { + color: #000; + background-color: #4ab4f5; + border-color: #34aaf3; +} + +.btn-check:checked + .btn-twitter:focus, +.btn-check:active + .btn-twitter:focus, .btn-twitter:active:focus, .btn-twitter.active:focus, +.show > .btn-twitter.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(25, 137, 206, 0.5); +} + +.btn-twitter:disabled, .btn-twitter.disabled { + color: #000; + background-color: #1da1f2; + border-color: #1da1f2; +} + +.btn-twitter, .btn-twitter:focus, .btn-twitter.focus, .btn-twitter.disabled, .btn-twitter:disabled, +.show > .btn-twitter.dropdown-toggle { + color: #fff; +} + +.btn-twitter:hover:not(:disabled):not(.disabled), .btn-twitter.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-google { + color: #000; + background-color: #dc4e41; + border-color: #dc4e41; +} + +.btn-google:hover { + color: #000; + background-color: #e1695e; + border-color: #e06054; +} + +.btn-check:focus + .btn-google, .btn-google:focus { + color: #000; + background-color: #e1695e; + border-color: #e06054; + box-shadow: 0 0 0 0.2rem rgba(187, 66, 55, 0.5); +} + +.btn-check:checked + .btn-google, +.btn-check:active + .btn-google, .btn-google:active, .btn-google.active, +.show > .btn-google.dropdown-toggle { + color: #000; + background-color: #e37167; + border-color: #e06054; +} + +.btn-check:checked + .btn-google:focus, +.btn-check:active + .btn-google:focus, .btn-google:active:focus, .btn-google.active:focus, +.show > .btn-google.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(187, 66, 55, 0.5); +} + +.btn-google:disabled, .btn-google.disabled { + color: #000; + background-color: #dc4e41; + border-color: #dc4e41; +} + +.btn-google, .btn-google:focus, .btn-google.focus, .btn-google.disabled, .btn-google:disabled, +.show > .btn-google.dropdown-toggle { + color: #fff; +} + +.btn-google:hover:not(:disabled):not(.disabled), .btn-google.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-youtube { + color: #000; + background-color: #f00; + border-color: #f00; +} + +.btn-youtube:hover { + color: #000; + background-color: #ff2626; + border-color: #ff1a1a; +} + +.btn-check:focus + .btn-youtube, .btn-youtube:focus { + color: #000; + background-color: #ff2626; + border-color: #ff1a1a; + box-shadow: 0 0 0 0.2rem rgba(217, 0, 0, 0.5); +} + +.btn-check:checked + .btn-youtube, +.btn-check:active + .btn-youtube, .btn-youtube:active, .btn-youtube.active, +.show > .btn-youtube.dropdown-toggle { + color: #000; + background-color: #ff3333; + border-color: #ff1a1a; +} + +.btn-check:checked + .btn-youtube:focus, +.btn-check:active + .btn-youtube:focus, .btn-youtube:active:focus, .btn-youtube.active:focus, +.show > .btn-youtube.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(217, 0, 0, 0.5); +} + +.btn-youtube:disabled, .btn-youtube.disabled { + color: #000; + background-color: #f00; + border-color: #f00; +} + +.btn-youtube, .btn-youtube:focus, .btn-youtube.focus, .btn-youtube.disabled, .btn-youtube:disabled, +.show > .btn-youtube.dropdown-toggle { + color: #fff; +} + +.btn-youtube:hover:not(:disabled):not(.disabled), .btn-youtube.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-vimeo { + color: #000; + background-color: #1ab7ea; + border-color: #1ab7ea; +} + +.btn-vimeo:hover { + color: #000; + background-color: #3cc2ed; + border-color: #31beec; +} + +.btn-check:focus + .btn-vimeo, .btn-vimeo:focus { + color: #000; + background-color: #3cc2ed; + border-color: #31beec; + box-shadow: 0 0 0 0.2rem rgba(22, 156, 199, 0.5); +} + +.btn-check:checked + .btn-vimeo, +.btn-check:active + .btn-vimeo, .btn-vimeo:active, .btn-vimeo.active, +.show > .btn-vimeo.dropdown-toggle { + color: #000; + background-color: #48c5ee; + border-color: #31beec; +} + +.btn-check:checked + .btn-vimeo:focus, +.btn-check:active + .btn-vimeo:focus, .btn-vimeo:active:focus, .btn-vimeo.active:focus, +.show > .btn-vimeo.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(22, 156, 199, 0.5); +} + +.btn-vimeo:disabled, .btn-vimeo.disabled { + color: #000; + background-color: #1ab7ea; + border-color: #1ab7ea; +} + +.btn-vimeo, .btn-vimeo:focus, .btn-vimeo.focus, .btn-vimeo.disabled, .btn-vimeo:disabled, +.show > .btn-vimeo.dropdown-toggle { + color: #fff; +} + +.btn-vimeo:hover:not(:disabled):not(.disabled), .btn-vimeo.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-dribbble { + color: #000; + background-color: #ea4c89; + border-color: #ea4c89; +} + +.btn-dribbble:hover { + color: #000; + background-color: #ed679b; + border-color: #ec5e95; +} + +.btn-check:focus + .btn-dribbble, .btn-dribbble:focus { + color: #000; + background-color: #ed679b; + border-color: #ec5e95; + box-shadow: 0 0 0 0.2rem rgba(199, 65, 116, 0.5); +} + +.btn-check:checked + .btn-dribbble, +.btn-check:active + .btn-dribbble, .btn-dribbble:active, .btn-dribbble.active, +.show > .btn-dribbble.dropdown-toggle { + color: #000; + background-color: #ee70a1; + border-color: #ec5e95; +} + +.btn-check:checked + .btn-dribbble:focus, +.btn-check:active + .btn-dribbble:focus, .btn-dribbble:active:focus, .btn-dribbble.active:focus, +.show > .btn-dribbble.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(199, 65, 116, 0.5); +} + +.btn-dribbble:disabled, .btn-dribbble.disabled { + color: #000; + background-color: #ea4c89; + border-color: #ea4c89; +} + +.btn-dribbble, .btn-dribbble:focus, .btn-dribbble.focus, .btn-dribbble.disabled, .btn-dribbble:disabled, +.show > .btn-dribbble.dropdown-toggle { + color: #fff; +} + +.btn-dribbble:hover:not(:disabled):not(.disabled), .btn-dribbble.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-github { + color: #fff; + background-color: #181717; + border-color: #181717; +} + +.btn-github:hover { + color: #fff; + background-color: #141414; + border-color: #131212; +} + +.btn-check:focus + .btn-github, .btn-github:focus { + color: #fff; + background-color: #141414; + border-color: #131212; + box-shadow: 0 0 0 0.2rem rgba(59, 58, 58, 0.5); +} + +.btn-check:checked + .btn-github, +.btn-check:active + .btn-github, .btn-github:active, .btn-github.active, +.show > .btn-github.dropdown-toggle { + color: #fff; + background-color: #131212; + border-color: #121111; +} + +.btn-check:checked + .btn-github:focus, +.btn-check:active + .btn-github:focus, .btn-github:active:focus, .btn-github.active:focus, +.show > .btn-github.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(59, 58, 58, 0.5); +} + +.btn-github:disabled, .btn-github.disabled { + color: #fff; + background-color: #181717; + border-color: #181717; +} + +.btn-github, .btn-github:focus, .btn-github.focus, .btn-github.disabled, .btn-github:disabled, +.show > .btn-github.dropdown-toggle { + color: #fff; +} + +.btn-github:hover:not(:disabled):not(.disabled), .btn-github.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-instagram { + color: #000; + background-color: #e4405f; + border-color: #e4405f; +} + +.btn-instagram:hover { + color: #000; + background-color: #e85d77; + border-color: #e7536f; +} + +.btn-check:focus + .btn-instagram, .btn-instagram:focus { + color: #000; + background-color: #e85d77; + border-color: #e7536f; + box-shadow: 0 0 0 0.2rem rgba(194, 54, 81, 0.5); +} + +.btn-check:checked + .btn-instagram, +.btn-check:active + .btn-instagram, .btn-instagram:active, .btn-instagram.active, +.show > .btn-instagram.dropdown-toggle { + color: #000; + background-color: #e9667f; + border-color: #e7536f; +} + +.btn-check:checked + .btn-instagram:focus, +.btn-check:active + .btn-instagram:focus, .btn-instagram:active:focus, .btn-instagram.active:focus, +.show > .btn-instagram.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(194, 54, 81, 0.5); +} + +.btn-instagram:disabled, .btn-instagram.disabled { + color: #000; + background-color: #e4405f; + border-color: #e4405f; +} + +.btn-instagram, .btn-instagram:focus, .btn-instagram.focus, .btn-instagram.disabled, .btn-instagram:disabled, +.show > .btn-instagram.dropdown-toggle { + color: #fff; +} + +.btn-instagram:hover:not(:disabled):not(.disabled), .btn-instagram.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-pinterest { + color: #fff; + background-color: #bd081c; + border-color: #bd081c; +} + +.btn-pinterest:hover { + color: #fff; + background-color: #a10718; + border-color: #970616; +} + +.btn-check:focus + .btn-pinterest, .btn-pinterest:focus { + color: #fff; + background-color: #a10718; + border-color: #970616; + box-shadow: 0 0 0 0.2rem rgba(199, 45, 62, 0.5); +} + +.btn-check:checked + .btn-pinterest, +.btn-check:active + .btn-pinterest, .btn-pinterest:active, .btn-pinterest.active, +.show > .btn-pinterest.dropdown-toggle { + color: #fff; + background-color: #970616; + border-color: #8e0615; +} + +.btn-check:checked + .btn-pinterest:focus, +.btn-check:active + .btn-pinterest:focus, .btn-pinterest:active:focus, .btn-pinterest.active:focus, +.show > .btn-pinterest.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(199, 45, 62, 0.5); +} + +.btn-pinterest:disabled, .btn-pinterest.disabled { + color: #fff; + background-color: #bd081c; + border-color: #bd081c; +} + +.btn-pinterest, .btn-pinterest:focus, .btn-pinterest.focus, .btn-pinterest.disabled, .btn-pinterest:disabled, +.show > .btn-pinterest.dropdown-toggle { + color: #fff; +} + +.btn-pinterest:hover:not(:disabled):not(.disabled), .btn-pinterest.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-flickr { + color: #fff; + background-color: #0063dc; + border-color: #0063dc; +} + +.btn-flickr:hover { + color: #fff; + background-color: #0054bb; + border-color: #004fb0; +} + +.btn-check:focus + .btn-flickr, .btn-flickr:focus { + color: #fff; + background-color: #0054bb; + border-color: #004fb0; + box-shadow: 0 0 0 0.2rem rgba(38, 122, 225, 0.5); +} + +.btn-check:checked + .btn-flickr, +.btn-check:active + .btn-flickr, .btn-flickr:active, .btn-flickr.active, +.show > .btn-flickr.dropdown-toggle { + color: #fff; + background-color: #004fb0; + border-color: #004aa5; +} + +.btn-check:checked + .btn-flickr:focus, +.btn-check:active + .btn-flickr:focus, .btn-flickr:active:focus, .btn-flickr.active:focus, +.show > .btn-flickr.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(38, 122, 225, 0.5); +} + +.btn-flickr:disabled, .btn-flickr.disabled { + color: #fff; + background-color: #0063dc; + border-color: #0063dc; +} + +.btn-flickr, .btn-flickr:focus, .btn-flickr.focus, .btn-flickr.disabled, .btn-flickr:disabled, +.show > .btn-flickr.dropdown-toggle { + color: #fff; +} + +.btn-flickr:hover:not(:disabled):not(.disabled), .btn-flickr.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-bitbucket { + color: #fff; + background-color: #0052cc; + border-color: #0052cc; +} + +.btn-bitbucket:hover { + color: #fff; + background-color: #0046ad; + border-color: #0042a3; +} + +.btn-check:focus + .btn-bitbucket, .btn-bitbucket:focus { + color: #fff; + background-color: #0046ad; + border-color: #0042a3; + box-shadow: 0 0 0 0.2rem rgba(38, 108, 212, 0.5); +} + +.btn-check:checked + .btn-bitbucket, +.btn-check:active + .btn-bitbucket, .btn-bitbucket:active, .btn-bitbucket.active, +.show > .btn-bitbucket.dropdown-toggle { + color: #fff; + background-color: #0042a3; + border-color: #003e99; +} + +.btn-check:checked + .btn-bitbucket:focus, +.btn-check:active + .btn-bitbucket:focus, .btn-bitbucket:active:focus, .btn-bitbucket.active:focus, +.show > .btn-bitbucket.dropdown-toggle:focus { + box-shadow: 0 0 0 0.2rem rgba(38, 108, 212, 0.5); +} + +.btn-bitbucket:disabled, .btn-bitbucket.disabled { + color: #fff; + background-color: #0052cc; + border-color: #0052cc; +} + +.btn-bitbucket, .btn-bitbucket:focus, .btn-bitbucket.focus, .btn-bitbucket.disabled, .btn-bitbucket:disabled, +.show > .btn-bitbucket.dropdown-toggle { + color: #fff; +} + +.btn-bitbucket:hover:not(:disabled):not(.disabled), .btn-bitbucket.hover:not(:disabled):not(.disabled) { + color: #fff; +} + +.btn-light, .btn-light:focus, .btn-light.focus, .btn-light.disabled, .btn-light:disabled, +.show > .btn-light.dropdown-toggle, +.btn-white, +.btn-white:focus, +.btn-white.focus, +.btn-white.disabled, +.btn-white:disabled, +.show > +.btn-white.dropdown-toggle { + color: #343a40; +} + +.btn-light:hover:not(:disabled):not(.disabled), .btn-light.hover:not(:disabled):not(.disabled), +.btn-white:hover:not(:disabled):not(.disabled), +.btn-white.hover:not(:disabled):not(.disabled) { + color: #343a40; +} + +.card { + margin-bottom: 24px; + box-shadow: 0 0 0.875rem 0 rgba(33, 37, 41, 0.05); +} + +.card-header { + border-bottom-width: 1px; +} + +.card-actions a { + color: #495057; + text-decoration: none; +} + +.card-actions svg { + width: 16px; + height: 16px; +} + +.card-actions .dropdown { + line-height: 1.4; +} + +.card-title { + font-size: 0.875rem; + font-weight: 400; + color: #495057; +} + +.card-subtitle { + font-weight: 400; +} + +.card-table { + margin-bottom: 0; +} + +.card-table tr td:first-child, +.card-table tr th:first-child { + padding-left: 1.25rem; +} + +.card-table tr td:last-child, +.card-table tr th:last-child { + padding-right: 1.25rem; +} + +.card-img, +.card-img-top, +.card-img-bottom { + max-width: 100%; + height: auto; +} + +@media all and (-ms-high-contrast: none) { + .card-img, + .card-img-top, + .card-img-bottom { + height: 100%; + } +} + +.chart { + margin: auto; + position: relative; + width: 100%; + min-height: 300px; +} + +.chart-xs { + min-height: 200px; +} + +.chart-sm { + min-height: 252px; +} + +.chart-lg { + min-height: 350px; +} + +.chart-xl { + min-height: 500px; +} + +.chart canvas { + max-width: 100%; +} + +.content { + padding: 1.5rem 1.5rem 0.75rem; + flex: 1; + width: 100vw; + max-width: 100vw; + direction: ltr; +} + +@media (min-width: 768px) { + .content { + width: auto; + max-width: auto; + } +} + +@media (min-width: 992px) { + .content { + padding: 2.5rem 2.5rem 1rem; + } +} + +.navbar-nav .dropdown-menu { + box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.05); +} + +.dropdown .dropdown-menu.show { + animation-name: dropdownAnimation; + animation-duration: .25s; + animation-iteration-count: 1; + animation-timing-function: ease; + animation-fill-mode: forwards; +} + +@keyframes dropdownAnimation { + from { + opacity: 0; + transform: translateY(-8px); + } + to { + opacity: 1; + transform: translate(0); + } +} + +.dropdown-toggle:after { + border: solid; + border-width: 0 2px 2px 0; + display: inline-block; + padding: 2px; + transform: rotate(45deg); +} + +.dropdown-item { + transition: background 0.1s ease-in-out, color 0.1s ease-in-out; +} + +.dropdown-menu { + top: auto; +} + +.dropdown-menu-lg { + min-width: 20rem; +} + +.dropdown .list-group .list-group-item { + border-width: 0; + border-bottom-width: 1px; + margin-bottom: 0; +} + +.dropdown .list-group .list-group-item:first-child, .dropdown .list-group .list-group-item:last-child { + border-radius: 0; +} + +.dropdown .list-group .list-group-item:hover { + background: #f8f9fa; +} + +.dropdown-menu-header { + padding: 0.75rem; + text-align: center; + font-weight: 600; + border-bottom: 1px solid #dee2e6; +} + +.dropdown-menu-footer { + padding: 0.5rem; + text-align: center; + display: block; + font-size: 0.75rem; +} + +.feather { + width: 18px; + height: 18px; + stroke-width: 1.5; +} + +.feather-sm { + width: 14px; + height: 14px; +} + +.feather-lg { + width: 36px; + height: 36px; +} + +footer.footer { + padding: 1rem 0.875rem; + direction: ltr; + background: #fff; +} + +footer.footer ul { + margin-bottom: 0; +} + +@media (max-width: 767.98px) { + footer.footer { + width: 100vw; + } +} + +.input-group-navbar .form-control, +.input-group-navbar .btn { + height: calc(2.0875rem + 2px); + background: #F7F7FC; + box-shadow: none; + border: 0; + padding: 0.35rem 0.75rem; +} + +.input-group-navbar .form-control:focus, +.input-group-navbar .btn:focus { + background: #F7F7FC; + box-shadow: none; + outline: 0; +} + +.input-group-navbar .btn { + color: #6c757d; +} + +.input-group-navbar .btn .feather { + width: 20px; + height: 20px; +} + +.hamburger, +.hamburger:before, +.hamburger:after { + cursor: pointer; + border-radius: 1px; + height: 3px; + width: 24px; + background: #495057; + display: block; + content: ''; + transition: background 0.1s ease-in-out, color 0.1s ease-in-out; +} + +.hamburger { + position: relative; +} + +.hamburger:before { + top: -7.5px; + width: 24px; + position: absolute; +} + +.hamburger:after { + bottom: -7.5px; + width: 16px; + position: absolute; +} + +.sidebar-toggle:hover .hamburger, +.sidebar-toggle:hover .hamburger:before, +.sidebar-toggle:hover .hamburger:after { + background: #3B7DDD; +} + +.hamburger-right, .hamburger-right:before, .hamburger-right:after { + right: 0; +} + +a.list-group-item { + text-decoration: none; +} + +.main { + display: flex; + width: 100%; + min-width: 0; + min-height: 100vh; + transition: margin-left 0.35s ease-in-out, left 0.35s ease-in-out, margin-right 0.35s ease-in-out, right 0.35s ease-in-out; + background: #F7F7FC; + flex-direction: column; + overflow: hidden; + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} + +@media (min-width: 992px) { + .main { + box-shadow: inset 0.75rem 0px 1.5rem 0px rgba(0, 0, 0, 0.075); + } +} + +.navbar { + border-bottom: 0; + box-shadow: 0 0 2rem 0 rgba(33, 37, 41, 0.1); +} + +@media (max-width: 767.98px) { + .navbar { + width: 100vw; + } +} + +.navbar .avatar { + margin-top: -15px; + margin-bottom: -15px; +} + +.navbar-nav { + direction: ltr; +} + +.navbar-align { + margin-left: auto; +} + +.navbar-bg { + background: #fff; +} + +.navbar-brand { + font-weight: 400; + font-size: 1.15rem; + padding: 0.875rem 0; + color: #f8f9fa; + display: block; +} + +.navbar-brand svg, +.navbar-brand .feather { + color: #3B7DDD; + height: 24px; + width: 24px; + margin-left: -0.15rem; + margin-right: 0.375rem; + margin-top: -0.375rem; +} + +.nav-icon, +.nav-flag { + padding: .1rem .8rem; + display: block; + font-size: 1.5rem; + color: #6c757d; + transition: background 0.1s ease-in-out, color 0.1s ease-in-out; + line-height: 1.4; +} + +.nav-icon:after, +.nav-flag:after { + display: none !important; +} + +.nav-icon:hover, .nav-icon.active, +.nav-flag:hover, +.nav-flag.active { + color: #3B7DDD; +} + +.nav-icon svg, +.nav-icon .feather, +.nav-flag svg, +.nav-flag .feather { + width: 20px; + height: 20px; +} + +.nav-item .indicator { + background: #3B7DDD; + box-shadow: 0 0.1rem 0.2rem rgba(0, 0, 0, 0.05); + border-radius: 50%; + display: block; + height: 18px; + width: 18px; + padding: 1px; + position: absolute; + top: 0; + right: -8px; + text-align: center; + transition: top .1s ease-out; + font-size: 0.675rem; + color: #fff; +} + +.nav-item:hover .indicator { + top: -4px; +} + +.nav-item a:focus { + outline: 0; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .navbar .avatar { + max-height: 47px; + } +} + +@media (max-width: 575.98px) { + .navbar { + padding: 0.75rem; + } + .nav-icon { + padding: .1rem .75rem; + } + .dropdown, + .dropleft, + .dropright, + .dropup { + position: inherit; + } + .navbar-expand .navbar-nav .dropdown-menu-lg { + min-width: 100%; + } + .nav-item .nav-link:after { + display: none; + } +} + +.nav-flag img { + border-radius: 50%; + width: 20px; + height: 20px; + object-fit: cover; +} + +.navbar input { + direction: ltr; +} + +body, html, #root { + height: 100%; +} + +body { + overflow-y: scroll; + opacity: 1 !important; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + html { + overflow-x: hidden; + } +} + +.sidebar { + min-width: 260px; + max-width: 260px; + transition: margin-left 0.35s ease-in-out, left 0.35s ease-in-out, margin-right 0.35s ease-in-out, right 0.35s ease-in-out; + direction: ltr; + background: #222E3C; +} + +.sidebar-content { + transition: margin-left 0.35s ease-in-out, left 0.35s ease-in-out, margin-right 0.35s ease-in-out, right 0.35s ease-in-out; + display: flex; + height: 100vh; + flex-direction: column; + background: #222E3C; +} + +.sidebar-nav { + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.sidebar-link, +a.sidebar-link { + display: block; + padding: 0.625rem 1.625rem; + font-weight: 400; + transition: background .1s ease-in-out; + position: relative; + text-decoration: none; + cursor: pointer; + border-left-style: solid; + border-left-width: 3px; + color: rgba(233, 236, 239, 0.5); + background: #222E3C; + border-left-color: transparent; +} + +.sidebar-link i, +.sidebar-link svg, +a.sidebar-link i, +a.sidebar-link svg { + margin-right: .75rem; + color: rgba(233, 236, 239, 0.5); +} + +.sidebar-link:focus { + outline: 0; +} + +.sidebar-link:hover { + color: rgba(233, 236, 239, 0.75); + background: #222E3C; + border-left-color: transparent; +} + +.sidebar-link:hover i, +.sidebar-link:hover svg { + color: rgba(233, 236, 239, 0.75); +} + +.sidebar-item.active > .sidebar-link, +.sidebar-item.active .sidebar-link:hover { + color: #e9ecef; + background: linear-gradient(90deg, rgba(59, 125, 221, 0.1) 0%, rgba(59, 125, 221, 0.0875) 50%, rgba(0, 0, 0, 0) 100%); + border-left-color: #3B7DDD; +} + +.sidebar-item.active > .sidebar-link i, +.sidebar-item.active > .sidebar-link svg, +.sidebar-item.active .sidebar-link:hover i, +.sidebar-item.active .sidebar-link:hover svg { + color: #e9ecef; +} + +.sidebar-dropdown .sidebar-link { + padding: 0.625rem 1.5rem 0.625rem 3.25rem; + font-weight: 400; + font-size: 90%; + border-left: 0; + color: #adb5bd; + background: transparent; +} + +.sidebar-dropdown .sidebar-link:before { + content: "→"; + display: inline-block; + position: relative; + left: -14px; + transition: all .1s ease; + transform: translateX(0); +} + +.sidebar-dropdown .sidebar-item .sidebar-link:hover { + font-weight: 400; + border-left: 0; + color: #e9ecef; + background: transparent; +} + +.sidebar-dropdown .sidebar-item .sidebar-link:hover:hover:before { + transform: translateX(4px); +} + +.sidebar-dropdown .sidebar-item.active .sidebar-link { + font-weight: 400; + border-left: 0; + color: #518be1; + background: transparent; +} + +.sidebar [data-bs-toggle="collapse"] { + position: relative; +} + +.sidebar [data-bs-toggle="collapse"]:after { + content: " "; + border: solid; + border-width: 0 .075rem .075rem 0; + display: inline-block; + padding: 2px; + transform: rotate(45deg); + position: absolute; + top: 1.2rem; + right: 1.5rem; + transition: all .2s ease-out; +} + +.sidebar [aria-expanded="true"]:after, +.sidebar [data-bs-toggle="collapse"]:not(.collapsed):after { + transform: rotate(-135deg); + top: 1.4rem; +} + +.sidebar-brand { + font-weight: 600; + font-size: 1.15rem; + padding: 1.15rem 1.5rem; + display: block; + color: #f8f9fa; +} + +.sidebar-brand:hover { + text-decoration: none; + color: #f8f9fa; +} + +.sidebar-brand:focus { + outline: 0; +} + +.sidebar-toggle { + cursor: pointer; + width: 26px; + height: 26px; +} + +.sidebar.collapsed { + margin-left: -260px; +} + +@media (min-width: 1px) and (max-width: 991.98px) { + .sidebar { + margin-left: -260px; + } + .sidebar.collapsed { + margin-left: 0; + } +} + +.sidebar-toggle { + margin-right: 1rem; +} + +.sidebar-header { + background: transparent; + padding: 1.5rem 1.5rem 0.375rem; + font-size: 0.75rem; + color: #ced4da; +} + +.sidebar-badge { + position: absolute; + right: 15px; + top: 14px; + z-index: 1; +} + +.sidebar-cta-content { + padding: 1.5rem; + margin: 1.75rem; + border-radius: 0.3rem; + background: #2B3947; + color: #e9ecef; +} + +.min-vw-50 { + min-width: 50vw !important; +} + +.min-vh-50 { + min-height: 50vh !important; +} + +.vw-50 { + width: 50vw !important; +} + +.vh-50 { + height: 50vh !important; +} + +.table thead, .table tbody, .table tfoot, .table tr, .table td, .table th { + border-color: #dee2e6; +} + +.table > :not(:last-child) > :last-child > * { + border-color: #dee2e6; +} + +.table > tbody > tr > td { + vertical-align: middle; +} + +.text-sm { + font-size: 0.75rem; +} + +.text-lg { + font-size: 0.925rem; +} + +b, +strong { + font-weight: 600; +} + +pre.snippet { + white-space: pre-wrap; + word-wrap: break-word; + text-align: justify; +} + +a { + cursor: pointer; +} + +.wrapper { + align-items: stretch; + display: flex; + width: 100%; + background: #222E3C; +} + +.bg-primary-light { + background: #d3e2f7; +} + +.bg-secondary-light { + background: #caced1; +} + +.bg-success-light { + background: #9be7ac; +} + +.bg-info-light { + background: #90e4f1; +} + +.bg-warning-light { + background: #ffeeba; +} + +.bg-danger-light { + background: #f6cdd1; +} + +.bg-light-light { + background: white; +} + +.bg-dark-light { + background: #717e8c; +} + +.bg-primary-dark { + background: #0f2c56; +} + +.bg-secondary-dark { + background: #191b1d; +} + +.bg-success-dark { + background: #06170a; +} + +.bg-info-dark { + background: #031619; +} + +.bg-warning-dark { + background: #543f00; +} + +.bg-danger-dark { + background: #510e14; +} + +.bg-light-dark { + background: #90a0b0; +} + +.bg-dark-dark { + background: black; +} + +.rounded-lg { + border-radius: 0.3rem !important; +} + +.rounded-top-lg { + border-top-left-radius: 0.3rem !important; + border-top-right-radius: 0.3rem !important; +} + +.rounded-right-lg { + border-top-right-radius: 0.3rem !important; + border-bottom-right-radius: 0.3rem !important; +} + +.rounded-bottom-lg { + border-bottom-right-radius: 0.3rem !important; + border-bottom-left-radius: 0.3rem !important; +} + +.rounded-left-lg { + border-top-left-radius: 0.3rem !important; + border-bottom-left-radius: 0.3rem !important; +} + +.rounded-sm { + border-radius: 0.1rem !important; +} + +.rounded-top-sm { + border-top-left-radius: 0.1rem !important; + border-top-right-radius: 0.1rem !important; +} + +.rounded-right-sm { + border-top-right-radius: 0.1rem !important; + border-bottom-right-radius: 0.1rem !important; +} + +.rounded-bottom-sm { + border-bottom-right-radius: 0.1rem !important; + border-bottom-left-radius: 0.1rem !important; +} + +.rounded-left-sm { + border-top-left-radius: 0.1rem !important; + border-bottom-left-radius: 0.1rem !important; +} + +.cursor-grab { + cursor: move; + cursor: grab; + cursor: -moz-grab; + cursor: -webkit-grab; +} + +.cursor-pointer { + cursor: pointer; +} + +.overflow-scroll { + overflow: scroll; +} + +.overflow-hidden { + overflow: hidden; +} + +.overflow-auto { + overflow: auto; +} + +.overflow-visible { + overflow: visible; +} + +[data-simplebar] { + position: relative; + flex-direction: column; + flex-wrap: wrap; + justify-content: flex-start; + align-content: flex-start; + align-items: flex-start; +} + +.simplebar-wrapper { + overflow: hidden; + width: inherit; + height: inherit; + max-width: inherit; + max-height: inherit; +} + +.simplebar-mask { + direction: inherit; + position: absolute; + overflow: hidden; + padding: 0; + margin: 0; + left: 0; + top: 0; + bottom: 0; + right: 0; + width: auto !important; + height: auto !important; + z-index: 0; +} + +.simplebar-offset { + direction: inherit !important; + box-sizing: inherit !important; + resize: none !important; + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + padding: 0; + margin: 0; + -webkit-overflow-scrolling: touch; +} + +.simplebar-content-wrapper { + direction: inherit; + box-sizing: border-box !important; + position: relative; + display: block; + height: 100%; + /* Required for horizontal native scrollbar to not appear if parent is taller than natural height */ + width: auto; + max-width: 100%; + /* Not required for horizontal scroll to trigger */ + max-height: 100%; + /* Needed for vertical scroll to trigger */ + scrollbar-width: none; + -ms-overflow-style: none; +} + +.simplebar-content-wrapper::-webkit-scrollbar, +.simplebar-hide-scrollbar::-webkit-scrollbar { + width: 0; + height: 0; +} + +.simplebar-content:before, +.simplebar-content:after { + content: ' '; + display: table; +} + +.simplebar-placeholder { + max-height: 100%; + max-width: 100%; + width: 100%; + pointer-events: none; +} + +.simplebar-height-auto-observer-wrapper { + box-sizing: inherit !important; + height: 100%; + width: 100%; + max-width: 1px; + position: relative; + float: left; + max-height: 1px; + overflow: hidden; + z-index: -1; + padding: 0; + margin: 0; + pointer-events: none; + flex-grow: inherit; + flex-shrink: 0; + flex-basis: 0; +} + +.simplebar-height-auto-observer { + box-sizing: inherit; + display: block; + opacity: 0; + position: absolute; + top: 0; + left: 0; + height: 1000%; + width: 1000%; + min-height: 1px; + min-width: 1px; + overflow: hidden; + pointer-events: none; + z-index: -1; +} + +.simplebar-track { + z-index: 1; + position: absolute; + right: 0; + bottom: 0; + pointer-events: none; + overflow: hidden; +} + +[data-simplebar].simplebar-dragging .simplebar-content { + pointer-events: none; + user-select: none; + -webkit-user-select: none; +} + +[data-simplebar].simplebar-dragging .simplebar-track { + pointer-events: all; +} + +.simplebar-scrollbar { + position: absolute; + left: 0; + right: 0; + min-height: 10px; +} + +.simplebar-scrollbar:before { + position: absolute; + content: ''; + background: black; + border-radius: 7px; + left: 2px; + right: 2px; + opacity: 0; + transition: opacity 0.2s linear; +} + +.simplebar-scrollbar.simplebar-visible:before { + /* When hovered, remove all transitions from drag handle */ + opacity: 0.5; + transition: opacity 0s linear; +} + +.simplebar-track.simplebar-vertical { + top: 0; + width: 11px; +} + +.simplebar-track.simplebar-vertical .simplebar-scrollbar:before { + top: 2px; + bottom: 2px; +} + +.simplebar-track.simplebar-horizontal { + left: 0; + height: 11px; +} + +.simplebar-track.simplebar-horizontal .simplebar-scrollbar:before { + height: 100%; + left: 2px; + right: 2px; +} + +.simplebar-track.simplebar-horizontal .simplebar-scrollbar { + right: auto; + left: 0; + top: 2px; + height: 7px; + min-height: 0; + min-width: 10px; + width: auto; +} + +/* Rtl support */ +[data-simplebar-direction='rtl'] .simplebar-track.simplebar-vertical { + right: auto; + left: 0; +} + +.hs-dummy-scrollbar-size { + direction: rtl; + position: fixed; + opacity: 0; + visibility: hidden; + height: 500px; + width: 500px; + overflow-y: hidden; + overflow-x: scroll; +} + +.simplebar-hide-scrollbar { + position: fixed; + left: 0; + visibility: hidden; + overflow-y: scroll; + scrollbar-width: none; + -ms-overflow-style: none; +} + +.flatpickr-calendar { + background: transparent; + opacity: 0; + display: none; + text-align: center; + visibility: hidden; + padding: 0; + -webkit-animation: none; + animation: none; + direction: ltr; + border: 0; + font-size: 14px; + line-height: 24px; + border-radius: 5px; + position: absolute; + width: 307.875px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + -ms-touch-action: manipulation; + touch-action: manipulation; + background: #fff; + -webkit-box-shadow: 1px 0 0 #e6e6e6, -1px 0 0 #e6e6e6, 0 1px 0 #e6e6e6, 0 -1px 0 #e6e6e6, 0 3px 13px rgba(0, 0, 0, 0.08); + box-shadow: 1px 0 0 #e6e6e6, -1px 0 0 #e6e6e6, 0 1px 0 #e6e6e6, 0 -1px 0 #e6e6e6, 0 3px 13px rgba(0, 0, 0, 0.08); +} + +.flatpickr-calendar.open, +.flatpickr-calendar.inline { + opacity: 1; + max-height: 640px; + visibility: visible; +} + +.flatpickr-calendar.open { + display: inline-block; + z-index: 99999; +} + +.flatpickr-calendar.animate.open { + -webkit-animation: fpFadeInDown 300ms cubic-bezier(0.23, 1, 0.32, 1); + animation: fpFadeInDown 300ms cubic-bezier(0.23, 1, 0.32, 1); +} + +.flatpickr-calendar.inline { + display: block; + position: relative; + top: 2px; +} + +.flatpickr-calendar.static { + position: absolute; + top: calc(100% + 2px); +} + +.flatpickr-calendar.static.open { + z-index: 999; + display: block; +} + +.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+1) .flatpickr-day.inRange:nth-child(7n+7) { + -webkit-box-shadow: none !important; + box-shadow: none !important; +} + +.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+2) .flatpickr-day.inRange:nth-child(7n+1) { + -webkit-box-shadow: -2px 0 0 #e6e6e6, 5px 0 0 #e6e6e6; + box-shadow: -2px 0 0 #e6e6e6, 5px 0 0 #e6e6e6; +} + +.flatpickr-calendar .hasWeeks .dayContainer, +.flatpickr-calendar .hasTime .dayContainer { + border-bottom: 0; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; +} + +.flatpickr-calendar .hasWeeks .dayContainer { + border-left: 0; +} + +.flatpickr-calendar.hasTime .flatpickr-time { + height: 40px; + border-top: 1px solid #e6e6e6; +} + +.flatpickr-calendar.noCalendar.hasTime .flatpickr-time { + height: auto; +} + +.flatpickr-calendar:before, +.flatpickr-calendar:after { + position: absolute; + display: block; + pointer-events: none; + border: solid transparent; + content: ''; + height: 0; + width: 0; + left: 22px; +} + +.flatpickr-calendar.rightMost:before, +.flatpickr-calendar.arrowRight:before, +.flatpickr-calendar.rightMost:after, +.flatpickr-calendar.arrowRight:after { + left: auto; + right: 22px; +} + +.flatpickr-calendar.arrowCenter:before, +.flatpickr-calendar.arrowCenter:after { + left: 50%; + right: 50%; +} + +.flatpickr-calendar:before { + border-width: 5px; + margin: 0 -5px; +} + +.flatpickr-calendar:after { + border-width: 4px; + margin: 0 -4px; +} + +.flatpickr-calendar.arrowTop:before, +.flatpickr-calendar.arrowTop:after { + bottom: 100%; +} + +.flatpickr-calendar.arrowTop:before { + border-bottom-color: #e6e6e6; +} + +.flatpickr-calendar.arrowTop:after { + border-bottom-color: #fff; +} + +.flatpickr-calendar.arrowBottom:before, +.flatpickr-calendar.arrowBottom:after { + top: 100%; +} + +.flatpickr-calendar.arrowBottom:before { + border-top-color: #e6e6e6; +} + +.flatpickr-calendar.arrowBottom:after { + border-top-color: #fff; +} + +.flatpickr-calendar:focus { + outline: 0; +} + +.flatpickr-wrapper { + position: relative; + display: inline-block; +} + +.flatpickr-months { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +.flatpickr-months .flatpickr-month { + background: transparent; + color: rgba(0, 0, 0, 0.9); + fill: rgba(0, 0, 0, 0.9); + height: 34px; + line-height: 1; + text-align: center; + position: relative; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + overflow: hidden; + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.flatpickr-months .flatpickr-prev-month, +.flatpickr-months .flatpickr-next-month { + text-decoration: none; + cursor: pointer; + position: absolute; + top: 0; + height: 34px; + padding: 10px; + z-index: 3; + color: rgba(0, 0, 0, 0.9); + fill: rgba(0, 0, 0, 0.9); +} + +.flatpickr-months .flatpickr-prev-month.flatpickr-disabled, +.flatpickr-months .flatpickr-next-month.flatpickr-disabled { + display: none; +} + +.flatpickr-months .flatpickr-prev-month i, +.flatpickr-months .flatpickr-next-month i { + position: relative; +} + +.flatpickr-months .flatpickr-prev-month.flatpickr-prev-month, +.flatpickr-months .flatpickr-next-month.flatpickr-prev-month { + /* + /*rtl:begin:ignore*/ + /* + */ + left: 0; + /* + /*rtl:end:ignore*/ + /* + */ +} + +/* + /*rtl:begin:ignore*/ +/* + /*rtl:end:ignore*/ +.flatpickr-months .flatpickr-prev-month.flatpickr-next-month, +.flatpickr-months .flatpickr-next-month.flatpickr-next-month { + /* + /*rtl:begin:ignore*/ + /* + */ + right: 0; + /* + /*rtl:end:ignore*/ + /* + */ +} + +/* + /*rtl:begin:ignore*/ +/* + /*rtl:end:ignore*/ +.flatpickr-months .flatpickr-prev-month:hover, +.flatpickr-months .flatpickr-next-month:hover { + color: #959ea9; +} + +.flatpickr-months .flatpickr-prev-month:hover svg, +.flatpickr-months .flatpickr-next-month:hover svg { + fill: #f64747; +} + +.flatpickr-months .flatpickr-prev-month svg, +.flatpickr-months .flatpickr-next-month svg { + width: 14px; + height: 14px; +} + +.flatpickr-months .flatpickr-prev-month svg path, +.flatpickr-months .flatpickr-next-month svg path { + -webkit-transition: fill 0.1s; + transition: fill 0.1s; + fill: inherit; +} + +.numInputWrapper { + position: relative; + height: auto; +} + +.numInputWrapper input, +.numInputWrapper span { + display: inline-block; +} + +.numInputWrapper input { + width: 100%; +} + +.numInputWrapper input::-ms-clear { + display: none; +} + +.numInputWrapper input::-webkit-outer-spin-button, +.numInputWrapper input::-webkit-inner-spin-button { + margin: 0; + -webkit-appearance: none; +} + +.numInputWrapper span { + position: absolute; + right: 0; + width: 14px; + padding: 0 4px 0 2px; + height: 50%; + line-height: 50%; + opacity: 0; + cursor: pointer; + border: 1px solid rgba(57, 57, 57, 0.15); + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.numInputWrapper span:hover { + background: rgba(0, 0, 0, 0.1); +} + +.numInputWrapper span:active { + background: rgba(0, 0, 0, 0.2); +} + +.numInputWrapper span:after { + display: block; + content: ""; + position: absolute; +} + +.numInputWrapper span.arrowUp { + top: 0; + border-bottom: 0; +} + +.numInputWrapper span.arrowUp:after { + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-bottom: 4px solid rgba(57, 57, 57, 0.6); + top: 26%; +} + +.numInputWrapper span.arrowDown { + top: 50%; +} + +.numInputWrapper span.arrowDown:after { + border-left: 4px solid transparent; + border-right: 4px solid transparent; + border-top: 4px solid rgba(57, 57, 57, 0.6); + top: 40%; +} + +.numInputWrapper span svg { + width: inherit; + height: auto; +} + +.numInputWrapper span svg path { + fill: rgba(0, 0, 0, 0.5); +} + +.numInputWrapper:hover { + background: rgba(0, 0, 0, 0.05); +} + +.numInputWrapper:hover span { + opacity: 1; +} + +.flatpickr-current-month { + font-size: 135%; + line-height: inherit; + font-weight: 300; + color: inherit; + position: absolute; + width: 75%; + left: 12.5%; + padding: 7.48px 0 0 0; + line-height: 1; + height: 34px; + display: inline-block; + text-align: center; + -webkit-transform: translate3d(0px, 0px, 0px); + transform: translate3d(0px, 0px, 0px); +} + +.flatpickr-current-month span.cur-month { + font-family: inherit; + font-weight: 700; + color: inherit; + display: inline-block; + margin-left: 0.5ch; + padding: 0; +} + +.flatpickr-current-month span.cur-month:hover { + background: rgba(0, 0, 0, 0.05); +} + +.flatpickr-current-month .numInputWrapper { + width: 6ch; + width: 7ch\0; + display: inline-block; +} + +.flatpickr-current-month .numInputWrapper span.arrowUp:after { + border-bottom-color: rgba(0, 0, 0, 0.9); +} + +.flatpickr-current-month .numInputWrapper span.arrowDown:after { + border-top-color: rgba(0, 0, 0, 0.9); +} + +.flatpickr-current-month input.cur-year { + background: transparent; + -webkit-box-sizing: border-box; + box-sizing: border-box; + color: inherit; + cursor: text; + padding: 0 0 0 0.5ch; + margin: 0; + display: inline-block; + font-size: inherit; + font-family: inherit; + font-weight: 300; + line-height: inherit; + height: auto; + border: 0; + border-radius: 0; + vertical-align: initial; + -webkit-appearance: textfield; + -moz-appearance: textfield; + appearance: textfield; +} + +.flatpickr-current-month input.cur-year:focus { + outline: 0; +} + +.flatpickr-current-month input.cur-year[disabled], +.flatpickr-current-month input.cur-year[disabled]:hover { + font-size: 100%; + color: rgba(0, 0, 0, 0.5); + background: transparent; + pointer-events: none; +} + +.flatpickr-current-month .flatpickr-monthDropdown-months { + appearance: menulist; + background: transparent; + border: none; + border-radius: 0; + box-sizing: border-box; + color: inherit; + cursor: pointer; + font-size: inherit; + font-family: inherit; + font-weight: 300; + height: auto; + line-height: inherit; + margin: -1px 0 0 0; + outline: none; + padding: 0 0 0 0.5ch; + position: relative; + vertical-align: initial; + -webkit-box-sizing: border-box; + -webkit-appearance: menulist; + -moz-appearance: menulist; + width: auto; +} + +.flatpickr-current-month .flatpickr-monthDropdown-months:focus, +.flatpickr-current-month .flatpickr-monthDropdown-months:active { + outline: none; +} + +.flatpickr-current-month .flatpickr-monthDropdown-months:hover { + background: rgba(0, 0, 0, 0.05); +} + +.flatpickr-current-month .flatpickr-monthDropdown-months .flatpickr-monthDropdown-month { + background-color: transparent; + outline: none; + padding: 0; +} + +.flatpickr-weekdays { + background: transparent; + text-align: center; + overflow: hidden; + width: 100%; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + -ms-flex-align: center; + align-items: center; + height: 28px; +} + +.flatpickr-weekdays .flatpickr-weekdaycontainer { + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} + +span.flatpickr-weekday { + cursor: default; + font-size: 90%; + background: transparent; + color: rgba(0, 0, 0, 0.54); + line-height: 1; + margin: 0; + text-align: center; + display: block; + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + font-weight: bolder; +} + +.dayContainer, +.flatpickr-weeks { + padding: 1px 0 0 0; +} + +.flatpickr-days { + position: relative; + overflow: hidden; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-align: start; + -webkit-align-items: flex-start; + -ms-flex-align: start; + align-items: flex-start; + width: 307.875px; +} + +.flatpickr-days:focus { + outline: 0; +} + +.dayContainer { + padding: 0; + outline: 0; + text-align: left; + width: 307.875px; + min-width: 307.875px; + max-width: 307.875px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + display: inline-block; + display: -ms-flexbox; + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-flex-wrap: wrap; + flex-wrap: wrap; + -ms-flex-wrap: wrap; + -ms-flex-pack: justify; + -webkit-justify-content: space-around; + justify-content: space-around; + -webkit-transform: translate3d(0px, 0px, 0px); + transform: translate3d(0px, 0px, 0px); + opacity: 1; +} + +.dayContainer + .dayContainer { + -webkit-box-shadow: -1px 0 0 #e6e6e6; + box-shadow: -1px 0 0 #e6e6e6; +} + +.flatpickr-day { + background: none; + border: 1px solid transparent; + border-radius: 150px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + color: #393939; + cursor: pointer; + font-weight: 400; + width: 14.2857143%; + -webkit-flex-basis: 14.2857143%; + -ms-flex-preferred-size: 14.2857143%; + flex-basis: 14.2857143%; + max-width: 39px; + height: 39px; + line-height: 39px; + margin: 0; + display: inline-block; + position: relative; + -webkit-box-pack: center; + -webkit-justify-content: center; + -ms-flex-pack: center; + justify-content: center; + text-align: center; +} + +.flatpickr-day.inRange, +.flatpickr-day.prevMonthDay.inRange, +.flatpickr-day.nextMonthDay.inRange, +.flatpickr-day.today.inRange, +.flatpickr-day.prevMonthDay.today.inRange, +.flatpickr-day.nextMonthDay.today.inRange, +.flatpickr-day:hover, +.flatpickr-day.prevMonthDay:hover, +.flatpickr-day.nextMonthDay:hover, +.flatpickr-day:focus, +.flatpickr-day.prevMonthDay:focus, +.flatpickr-day.nextMonthDay:focus { + cursor: pointer; + outline: 0; + background: #e6e6e6; + border-color: #e6e6e6; +} + +.flatpickr-day.today { + border-color: #959ea9; +} + +.flatpickr-day.today:hover, +.flatpickr-day.today:focus { + border-color: #959ea9; + background: #959ea9; + color: #fff; +} + +.flatpickr-day.selected, +.flatpickr-day.startRange, +.flatpickr-day.endRange, +.flatpickr-day.selected.inRange, +.flatpickr-day.startRange.inRange, +.flatpickr-day.endRange.inRange, +.flatpickr-day.selected:focus, +.flatpickr-day.startRange:focus, +.flatpickr-day.endRange:focus, +.flatpickr-day.selected:hover, +.flatpickr-day.startRange:hover, +.flatpickr-day.endRange:hover, +.flatpickr-day.selected.prevMonthDay, +.flatpickr-day.startRange.prevMonthDay, +.flatpickr-day.endRange.prevMonthDay, +.flatpickr-day.selected.nextMonthDay, +.flatpickr-day.startRange.nextMonthDay, +.flatpickr-day.endRange.nextMonthDay { + background: #569ff7; + -webkit-box-shadow: none; + box-shadow: none; + color: #fff; + border-color: #569ff7; +} + +.flatpickr-day.selected.startRange, +.flatpickr-day.startRange.startRange, +.flatpickr-day.endRange.startRange { + border-radius: 50px 0 0 50px; +} + +.flatpickr-day.selected.endRange, +.flatpickr-day.startRange.endRange, +.flatpickr-day.endRange.endRange { + border-radius: 0 50px 50px 0; +} + +.flatpickr-day.selected.startRange + .endRange:not(:nth-child(7n+1)), +.flatpickr-day.startRange.startRange + .endRange:not(:nth-child(7n+1)), +.flatpickr-day.endRange.startRange + .endRange:not(:nth-child(7n+1)) { + -webkit-box-shadow: -10px 0 0 #569ff7; + box-shadow: -10px 0 0 #569ff7; +} + +.flatpickr-day.selected.startRange.endRange, +.flatpickr-day.startRange.startRange.endRange, +.flatpickr-day.endRange.startRange.endRange { + border-radius: 50px; +} + +.flatpickr-day.inRange { + border-radius: 0; + -webkit-box-shadow: -5px 0 0 #e6e6e6, 5px 0 0 #e6e6e6; + box-shadow: -5px 0 0 #e6e6e6, 5px 0 0 #e6e6e6; +} + +.flatpickr-day.flatpickr-disabled, +.flatpickr-day.flatpickr-disabled:hover, +.flatpickr-day.prevMonthDay, +.flatpickr-day.nextMonthDay, +.flatpickr-day.notAllowed, +.flatpickr-day.notAllowed.prevMonthDay, +.flatpickr-day.notAllowed.nextMonthDay { + color: rgba(57, 57, 57, 0.3); + background: transparent; + border-color: transparent; + cursor: default; +} + +.flatpickr-day.flatpickr-disabled, +.flatpickr-day.flatpickr-disabled:hover { + cursor: not-allowed; + color: rgba(57, 57, 57, 0.1); +} + +.flatpickr-day.week.selected { + border-radius: 0; + -webkit-box-shadow: -5px 0 0 #569ff7, 5px 0 0 #569ff7; + box-shadow: -5px 0 0 #569ff7, 5px 0 0 #569ff7; +} + +.flatpickr-day.hidden { + visibility: hidden; +} + +.rangeMode .flatpickr-day { + margin-top: 1px; +} + +.flatpickr-weekwrapper { + float: left; +} + +.flatpickr-weekwrapper .flatpickr-weeks { + padding: 0 12px; + -webkit-box-shadow: 1px 0 0 #e6e6e6; + box-shadow: 1px 0 0 #e6e6e6; +} + +.flatpickr-weekwrapper .flatpickr-weekday { + float: none; + width: 100%; + line-height: 28px; +} + +.flatpickr-weekwrapper span.flatpickr-day, +.flatpickr-weekwrapper span.flatpickr-day:hover { + display: block; + width: 100%; + max-width: none; + color: rgba(57, 57, 57, 0.3); + background: transparent; + cursor: default; + border: none; +} + +.flatpickr-innerContainer { + display: block; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; + -webkit-box-sizing: border-box; + box-sizing: border-box; + overflow: hidden; +} + +.flatpickr-rContainer { + display: inline-block; + padding: 0; + -webkit-box-sizing: border-box; + box-sizing: border-box; +} + +.flatpickr-time { + text-align: center; + outline: 0; + display: block; + height: 0; + line-height: 40px; + max-height: 40px; + -webkit-box-sizing: border-box; + box-sizing: border-box; + overflow: hidden; + display: -webkit-box; + display: -webkit-flex; + display: -ms-flexbox; + display: flex; +} + +.flatpickr-time:after { + content: ""; + display: table; + clear: both; +} + +.flatpickr-time .numInputWrapper { + -webkit-box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + width: 40%; + height: 40px; + float: left; +} + +.flatpickr-time .numInputWrapper span.arrowUp:after { + border-bottom-color: #393939; +} + +.flatpickr-time .numInputWrapper span.arrowDown:after { + border-top-color: #393939; +} + +.flatpickr-time.hasSeconds .numInputWrapper { + width: 26%; +} + +.flatpickr-time.time24hr .numInputWrapper { + width: 49%; +} + +.flatpickr-time input { + background: transparent; + -webkit-box-shadow: none; + box-shadow: none; + border: 0; + border-radius: 0; + text-align: center; + margin: 0; + padding: 0; + height: inherit; + line-height: inherit; + color: #393939; + font-size: 14px; + position: relative; + -webkit-box-sizing: border-box; + box-sizing: border-box; + -webkit-appearance: textfield; + -moz-appearance: textfield; + appearance: textfield; +} + +.flatpickr-time input.flatpickr-hour { + font-weight: bold; +} + +.flatpickr-time input.flatpickr-minute, +.flatpickr-time input.flatpickr-second { + font-weight: 400; +} + +.flatpickr-time input:focus { + outline: 0; + border: 0; +} + +.flatpickr-time .flatpickr-time-separator, +.flatpickr-time .flatpickr-am-pm { + height: inherit; + float: left; + line-height: inherit; + color: #393939; + font-weight: bold; + width: 2%; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + -webkit-align-self: center; + -ms-flex-item-align: center; + align-self: center; +} + +.flatpickr-time .flatpickr-am-pm { + outline: 0; + width: 18%; + cursor: pointer; + text-align: center; + font-weight: 400; +} + +.flatpickr-time input:hover, +.flatpickr-time .flatpickr-am-pm:hover, +.flatpickr-time input:focus, +.flatpickr-time .flatpickr-am-pm:focus { + background: #eee; +} + +.flatpickr-input[readonly] { + cursor: pointer; +} + +@-webkit-keyframes fpFadeInDown { + from { + opacity: 0; + -webkit-transform: translate3d(0, -20px, 0); + transform: translate3d(0, -20px, 0); + } + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes fpFadeInDown { + from { + opacity: 0; + -webkit-transform: translate3d(0, -20px, 0); + transform: translate3d(0, -20px, 0); + } + to { + opacity: 1; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +.simplebar-scrollbar:before { + background: #fff; +} + +.simplebar-content { + display: flex; + flex-direction: column; + height: 100vh; + padding-bottom: 0 !important; +} + +[data-simplebar] { + position: sticky; + top: 0; + left: 0; + width: 260px; +} + +.flatpickr-calendar.inline { + background: transparent; + box-shadow: none; + width: 100%; +} + +.flatpickr-calendar.inline .flatpickr-days { + width: 100%; +} + +.flatpickr-calendar.inline .dayContainer { + width: 100%; + min-width: 100%; + max-width: 100%; +} + +.flatpickr-calendar.inline .flatpickr-day { + border-radius: 0.2rem; + max-width: inherit; + height: 45px; + line-height: 45px; +} + +.flatpickr-calendar.inline .flatpickr-day.today { + border: 0; +} + +.flatpickr-calendar.inline .flatpickr-day.today:before { + content: ""; + display: inline-block; + border-color: rgba(0, 0, 0, 0.2) transparent #3B7DDD; + border-style: solid; + border-width: 0 0 7px 7px; + position: absolute; + bottom: 4px; + right: 4px; +} + +.flatpickr-calendar.inline .flatpickr-day.today.selected:before { + border-color: rgba(0, 0, 0, 0.2) transparent #fff; +} + +.flatpickr-calendar.inline .flatpickr-day.today:hover { + background: #e6e6e6; + color: #000; +} + +.flatpickr-calendar.inline .flatpickr-day.selected, .flatpickr-calendar.inline .flatpickr-day.selected:hover, .flatpickr-calendar.inline .flatpickr-day.selected:focus { + border-radius: 0.2rem; + background: #3B7DDD; + color: #fff; +} + +.flatpickr-calendar.inline .flatpickr-weekdays { + height: 45px; +} + +.flatpickr-calendar.inline .flatpickr-weekday { + height: 45px; + line-height: 45px; +} + +.flatpickr-calendar.inline .flatpickr-months .flatpickr-month { + height: 45px; +} + +.flatpickr-calendar.inline .flatpickr-months .flatpickr-prev-month, +.flatpickr-calendar.inline .flatpickr-months .flatpickr-next-month { + height: 45px; +} + +.flatpickr-calendar.inline .flatpickr-current-month { + padding-top: 0; + line-height: 45px; + height: 45px; +} + +.flatpickr-calendar.inline .flatpickr-current-month .flatpickr-monthDropdown-months { + appearance: none; +} + +.flatpickr-calendar.inline .flatpickr-current-month .flatpickr-monthDropdown-months, +.flatpickr-calendar.inline .flatpickr-current-month input.cur-year { + font-weight: 400; + font-size: 1.09375rem; +} + +.flatpickr-calendar.inline .flatpickr-prev-month, +.flatpickr-calendar.inline .flatpickr-next-month { + width: 45px; + border-radius: 0.2rem; +} + +.flatpickr-calendar.inline .flatpickr-prev-month:hover, +.flatpickr-calendar.inline .flatpickr-next-month:hover { + background: #e6e6e6; + color: #000; +} + +/*# sourceMappingURL=styles.css.map */ \ No newline at end of file diff --git a/setup/data/domain/apixpress/www/app/webapp/css/simplebar.min.css b/setup/data/domain/apixpress/www/app/webapp/css/simplebar.min.css new file mode 100755 index 0000000..2d54e12 --- /dev/null +++ b/setup/data/domain/apixpress/www/app/webapp/css/simplebar.min.css @@ -0,0 +1 @@ +[data-simplebar]{position:relative;flex-direction:column;flex-wrap:wrap;justify-content:flex-start;align-content:flex-start;align-items:flex-start}.simplebar-wrapper{overflow:hidden;width:inherit;height:inherit;max-width:inherit;max-height:inherit}.simplebar-mask{direction:inherit;position:absolute;overflow:hidden;padding:0;margin:0;left:0;top:0;bottom:0;right:0;width:auto!important;height:auto!important;z-index:0}.simplebar-offset{direction:inherit!important;box-sizing:inherit!important;resize:none!important;position:absolute;top:0;left:0;bottom:0;right:0;padding:0;margin:0;-webkit-overflow-scrolling:touch}.simplebar-content-wrapper{direction:inherit;box-sizing:border-box!important;position:relative;display:block;height:100%;width:auto;max-width:100%;max-height:100%;scrollbar-width:none;-ms-overflow-style:none}.simplebar-content-wrapper::-webkit-scrollbar,.simplebar-hide-scrollbar::-webkit-scrollbar{width:0;height:0}.simplebar-content:after,.simplebar-content:before{content:' ';display:table}.simplebar-placeholder{max-height:100%;max-width:100%;width:100%;pointer-events:none}.simplebar-height-auto-observer-wrapper{box-sizing:inherit!important;height:100%;width:100%;max-width:1px;position:relative;float:left;max-height:1px;overflow:hidden;z-index:-1;padding:0;margin:0;pointer-events:none;flex-grow:inherit;flex-shrink:0;flex-basis:0}.simplebar-height-auto-observer{box-sizing:inherit;display:block;opacity:0;position:absolute;top:0;left:0;height:1000%;width:1000%;min-height:1px;min-width:1px;overflow:hidden;pointer-events:none;z-index:-1}.simplebar-track{z-index:1;position:absolute;right:0;bottom:0;pointer-events:none;overflow:hidden}[data-simplebar].simplebar-dragging .simplebar-content{pointer-events:none;user-select:none;-webkit-user-select:none}[data-simplebar].simplebar-dragging .simplebar-track{pointer-events:all}.simplebar-scrollbar{position:absolute;left:0;right:0;min-height:10px}.simplebar-scrollbar:before{position:absolute;content:'';background:#000;border-radius:7px;left:2px;right:2px;opacity:0;transition:opacity .2s linear}.simplebar-scrollbar.simplebar-visible:before{opacity:.5;transition:opacity 0s linear}.simplebar-track.simplebar-vertical{top:0;width:11px}.simplebar-track.simplebar-vertical .simplebar-scrollbar:before{top:2px;bottom:2px}.simplebar-track.simplebar-horizontal{left:0;height:11px}.simplebar-track.simplebar-horizontal .simplebar-scrollbar:before{height:100%;left:2px;right:2px}.simplebar-track.simplebar-horizontal .simplebar-scrollbar{right:auto;left:0;top:2px;height:7px;min-height:0;min-width:10px;width:auto}[data-simplebar-direction=rtl] .simplebar-track.simplebar-vertical{right:auto;left:0}.hs-dummy-scrollbar-size{direction:rtl;position:fixed;opacity:0;visibility:hidden;height:500px;width:500px;overflow-y:hidden;overflow-x:scroll}.simplebar-hide-scrollbar{position:fixed;left:0;visibility:hidden;overflow-y:scroll;scrollbar-width:none;-ms-overflow-style:none} diff --git a/setup/data/domain/apixpress/www/app/webapp/fullscreen_auth_fr.html b/setup/data/domain/apixpress/www/app/webapp/fullscreen_auth_fr.html new file mode 100755 index 0000000..92dedde --- /dev/null +++ b/setup/data/domain/apixpress/www/app/webapp/fullscreen_auth_fr.html @@ -0,0 +1,169 @@ + + + + + + + + + apixtribe> + + + + + +
+
+
+
+ +
+
+
+

Need-Data

+

+ Votre hébergement apixtribe en toute confidentialité. +

+
+
+
+
+
+ logo apixtribe +
+
+
+ + +
+
+ + + + Mot de passe oublié? + +
+
+ +
+
+ +

+
+
+

+ + Rejoindre un espace + +

+
+
+
+
+
+
+

Mot de passe oublié

+

+ Indiquez votre email. Si vous n'avez pas indiqué d'email, vos données sont definitivement perdues, c'est le prix de votre anonymat. +

+
+
+
+
+
+
+ + +
+
+ +

+
+
+
+
+
+
+
+
+
+

S'inscrire à votre communauté

+

+ Vous devez disposez du nom de la communauté qui vous invite à ouvrir un compte chez elle.
Pour créer une communauté, sur cet hébergement: contact@need-data.com.
En savoir plus sur Anomymat & apixtribe. +

+
+
+
+
+
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +

+

+ + S'authentifier + +

+
+
+
+
+
+
+
+ +
+
+
+
+ +
+ \ No newline at end of file diff --git a/setup/data/domain/apixpress/www/app/webapp/js/auth.js b/setup/data/domain/apixpress/www/app/webapp/js/auth.js new file mode 100755 index 0000000..1ea4364 --- /dev/null +++ b/setup/data/domain/apixpress/www/app/webapp/js/auth.js @@ -0,0 +1,216 @@ +"use strict"; +var pwa = pwa || {}; +/* +Manage user authentification and registration +________________________ +pwa.auth.route() + manage from state.json route if authenticated or not + redirect public page or app page +________________________ +pwa.auth.screenlogin() + show login modal +________________________ +pwa.auth.getlinkwithoutpsw() + special get with token and uuid workeable for 24h this link is une onetime +_________________________ +pwa.auth.isAuthenticate() + test if token is still ok or not return false/true +_________________________ +pwa.auth.authentification({LOGIN,PASSWORD}) + if ok => load pwa.state.data.app .headers .userlogin +_________________________ +pwa.auth.login() + Manage login modal to get login psw value and submit it to pwa.auth.authentification() +_________________________ +pwa.auth.logout() + Remove localstorage and reload +_________________________ +pwa.auth.register() + @TODO +__________________________ +pwa.auth.forgetpsw() + Request to send an email with a unique get link to access from this link to the app + +*/ +/*MODULEJS*/ +//--## +pwa.auth = {}; +// Refresh browser state if exist else get pwa.state defaults +//pwa.state.ready( pwa.auth.check ); + +pwa.auth.check = () => { + if( pwa.state.data.login.isAuthenticated ) { + if( !pwa.auth.isAuthenticate() ) { + // Then reinit local storage and refresh page + pwa.state.data.login.isAuthenticated = false; + pwa.state.save(); + //alert( 'reload page cause no more auth' ) + window.location.reload(); + }; + } +}; +pwa.auth.route = ( destination ) => { + console.log( 'auth.route to', destination ); + //if check Authenticated && exist #signin button[data-routeto] then redirect browser to button[data-routeto] + //else manage component action auth + if( pwa.state && pwa.state.data && pwa.state.data.login && pwa.state.data.login.isAuthenticated ) { + if( destination ) + window.location.pathname = `${pwa.state.data.ctx.urlbase}/${destination}`; + } else { + [ "#signin", "#resetpsw", "#register" ].forEach( e => { + if( e == destination ) { + document.querySelector( e ) + .classList.remove( 'd-none' ); + } else { + document.querySelector( e ) + .classList.add( 'd-none' ); + } + } ) + } +} +pwa.auth.isAuthenticate = async function () { + // in any request, if middleware isAuthenticated return false + // then headers Xuuid is set to 1 + // then try pwa.auth.isAuthenticate if rememberMe auto reconnect + // if jwt is ok then return true in other case => false + // this is the first test then depending of action see ACCESSRIGHTS of user + console.log( 'lance isauth', { + headers: pwa.state.data.headers.xpaganid + } ) + //alert( 'uuid ' + pwa.state.data.headers.xpaganid ) + console.log( `https://${pwa.state.data.ctx.urlbackoffice}/users/isauth`, { + headers: pwa.state.data.headers + } ) + try { + const repisauth = await axios.get( `https://${pwa.state.data.ctx.urlbackoffice}/users/isauth`, { + headers: pwa.state.data.headers + } ) + console.log( repisauth ) + console.log( 'isAauthenticate: yes' ) + return true; + } catch ( err ) { + if( err.response ) { console.log( "response err ", err.response.data ) } + if( err.request ) { console.log( "request err", err.request ) } + console.log( 'isAuthenticate: no' ) + pwa.state.data.headers.xpaganid = "1"; + if( pwa.state.data.login.rememberMe.login ) { + if( await pwa.auth.authentification( pwa.state.data.login.rememberMe ) ) { + return await pwa.auth.isAuthenticate(); + }; + } + return false; + } +}; +pwa.auth.authentification = async function ( data ) { + // Core client function to chech auth from login & psw + // In case of 403 error lauch pwa.authentification(pwa.app.rememberMe) + // in case of sucess update paw.state.data.login + console.groupCollapsed( "Post Authentification for standard on : https://" + pwa.state.data.ctx.urlbackoffice + "/users/login param data", data ) + + console.log( 'header de login', pwa.state.data.headers ) + let auth; + try { + auth = await axios.post( `https://${pwa.state.data.ctx.urlbackoffice }/users/login`, data, { + headers: pwa.state.data.headers + } ); + console.log( "retour de login successfull ", auth ); + //Maj variable globale authentifié + pwa.state.data.headers.xpaganid = auth.data.payload.data.UUID; + pwa.state.data.headers.xauth = auth.data.payload.data.TOKEN; + pwa.state.data.headers.xtribe = auth.data.payload.data.tribeid; + pwa.state.data.headers.xworkon = auth.data.payload.data.tribeid; + // Save local authentification uuid/token info user + pwa.state.data.login.user = auth.data.payload.data; + //request a refresh after a login + pwa.state.data.ctx.refreshstorage = true; + pwa.state.save(); + //alert( 'pwa.state.save() fait avec uuid' + pwa.state.data.headers.xpaganid ) + console.groupEnd(); + return true; + } catch ( err ) { + if( err.response ) { console.log( "resp", err.response.data ) } + if( err.request ) { console.log( "req", err.request.data ) } + console.log( 'erreur de login reinit de rememberMe', err ) + pwa.state.data.login.rememberMe = {}; + document.querySelector( "#signin p.msginfo" ) + .innerHTML = document.querySelector( "#signin [data-msgko]" ) + .getAttribute( 'data-msgko' ); + console.groupEnd(); + return false; + } +}; +pwa.auth.logout = function () { + console.log( "remove ", pwa.state.data.ctx.website ); + localStorage.removeItem( pwa.state.data.ctx.website ); + window.location.href = "/"; +} +pwa.auth.login = async function () { + /* + Check login/psw + see auth.mustache & data_auth_lg.json for parameters + Context info used: + #signin p.msginfo contain message interaction with user + #signin data-msgok data-msgko + #signin button[data-routeto] is a redirection if authentification is successful + */ + document.querySelector( '#signin p.msginfo' ) + .innerHTML = ""; + const data = { + LOGIN: document.querySelector( "#signin input[name='login']" ) + .value, + PASSWORD: document.querySelector( "#signin input[name='password']" ) + .value + } + console.log( 'check password', checkdata.test.password( "", data.PASSWORD ) ) + if( data.LOGIN.length < 4 || !checkdata.test.password( "", data.PASSWORD ) ) { + /*$("#loginpart p.msginfo") + .html("") + .fadeOut(2000)*/ + document.querySelector( '#signin p.msginfo' ) + .innerHTML = document.querySelector( '#signin [data-msgko]' ) + .getAttribute( 'data-msgko' ); + } else { + if( document.querySelector( "[name='rememberme']" ) + .checked ) { + pwa.state.data.login.rememberMe = data; + } + if( await pwa.auth.authentification( data ) ) { + console.log( 'Authentification VALIDE' ) + document.querySelector( '#signin p.msginfo' ) + .innerHTML = document.querySelector( "#signin [data-msgok]" ) + .getAttribute( 'data-msgok' ); + //state l'état isAuthenticated et check la route + pwa.state.data.login.isAuthenticated = true; + pwa.state.save(); + console.log( pwa.state.data.login ) + console.log( 'Auth ok route to ', document.querySelector( '#signin button[data-routeto]' ) + .getAttribute( 'data-routeto' ) ); + pwa.auth.route( document.querySelector( '#signin button[data-routeto]' ) + .getAttribute( 'data-routeto' ) ); + } + } +}; +pwa.auth.register = async function ( event ) { + event.preventDefault(); + // gérer la cration du user +} +pwa.auth.forgetpsw = async function ( event ) { + event.preventDefault(); + const tribeid = $( ".loginregister" ) + .getAttribute( "data-tribeid" ); + const email = $( '.forgetpsw .email' ) + .val(); + console.log( `Reinit email: ${email} for tribeid: ${tribeid}` ) + try { + console.log( `https://${pwa.state.data.ctx.urlbackoffice }/users/getlinkwithoutpsw/${email}` ) + const reinit = await axios.get( `https://${pwa.state.data.ctx.urlbackoffice }/users/getlinkwithoutpsw/${email}`, { + headers: pwa.state.data.headers + } ) + $( "#forgetpswpart p.msginfo" ) + .html( "Regardez votre boite email" ); + return true; + } catch ( er ) { + console.log( "Pb d'accès au back check apiamaildigit" ) + return false; + } +}; diff --git a/setup/data/domain/apixpress/www/app/webapp/js/axios.min.js b/setup/data/domain/apixpress/www/app/webapp/js/axios.min.js new file mode 100755 index 0000000..c7b4b0d --- /dev/null +++ b/setup/data/domain/apixpress/www/app/webapp/js/axios.min.js @@ -0,0 +1,9 @@ +/* axios v0.18.1 | (c) 2019 by Matt Zabriskie */ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.axios=t():e.axios=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var o=n[r]={exports:{},id:r,loaded:!1};return e[r].call(o.exports,o,o.exports,t),o.loaded=!0,o.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){e.exports=n(1)},function(e,t,n){"use strict";function r(e){var t=new i(e),n=s(i.prototype.request,t);return o.extend(n,i.prototype,t),o.extend(n,t),n}var o=n(2),s=n(3),i=n(5),u=n(6),a=r(u);a.Axios=i,a.create=function(e){return r(o.merge(u,e))},a.Cancel=n(22),a.CancelToken=n(23),a.isCancel=n(19),a.all=function(e){return Promise.all(e)},a.spread=n(24),e.exports=a,e.exports.default=a},function(e,t,n){"use strict";function r(e){return"[object Array]"===R.call(e)}function o(e){return"[object ArrayBuffer]"===R.call(e)}function s(e){return"undefined"!=typeof FormData&&e instanceof FormData}function i(e){var t;return t="undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function u(e){return"string"==typeof e}function a(e){return"number"==typeof e}function c(e){return"undefined"==typeof e}function f(e){return null!==e&&"object"==typeof e}function p(e){return"[object Date]"===R.call(e)}function d(e){return"[object File]"===R.call(e)}function l(e){return"[object Blob]"===R.call(e)}function h(e){return"[object Function]"===R.call(e)}function m(e){return f(e)&&h(e.pipe)}function y(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function g(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function x(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function v(e,t){if(null!==e&&"undefined"!=typeof e)if("object"!=typeof e&&(e=[e]),r(e))for(var n=0,o=e.length;n + * @license MIT + */ +e.exports=function(e){return null!=e&&null!=e.constructor&&"function"==typeof e.constructor.isBuffer&&e.constructor.isBuffer(e)}},function(e,t,n){"use strict";function r(e){this.defaults=e,this.interceptors={request:new i,response:new i}}var o=n(6),s=n(2),i=n(16),u=n(17);r.prototype.request=function(e){"string"==typeof e&&(e=s.merge({url:arguments[0]},arguments[1])),e=s.merge(o,{method:"get"},this.defaults,e),e.method=e.method.toLowerCase();var t=[u,void 0],n=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)n=n.then(t.shift(),t.shift());return n},s.forEach(["delete","get","head","options"],function(e){r.prototype[e]=function(t,n){return this.request(s.merge(n||{},{method:e,url:t}))}}),s.forEach(["post","put","patch"],function(e){r.prototype[e]=function(t,n,r){return this.request(s.merge(r||{},{method:e,url:t,data:n}))}}),e.exports=r},function(e,t,n){"use strict";function r(e,t){!s.isUndefined(e)&&s.isUndefined(e["Content-Type"])&&(e["Content-Type"]=t)}function o(){var e;return"undefined"!=typeof XMLHttpRequest?e=n(8):"undefined"!=typeof process&&(e=n(8)),e}var s=n(2),i=n(7),u={"Content-Type":"application/x-www-form-urlencoded"},a={adapter:o(),transformRequest:[function(e,t){return i(t,"Content-Type"),s.isFormData(e)||s.isArrayBuffer(e)||s.isBuffer(e)||s.isStream(e)||s.isFile(e)||s.isBlob(e)?e:s.isArrayBufferView(e)?e.buffer:s.isURLSearchParams(e)?(r(t,"application/x-www-form-urlencoded;charset=utf-8"),e.toString()):s.isObject(e)?(r(t,"application/json;charset=utf-8"),JSON.stringify(e)):e}],transformResponse:[function(e){if("string"==typeof e)try{e=JSON.parse(e)}catch(e){}return e}],timeout:0,xsrfCookieName:"XSRF-TOKEN",xsrfHeaderName:"X-XSRF-TOKEN",maxContentLength:-1,validateStatus:function(e){return e>=200&&e<300}};a.headers={common:{Accept:"application/json, text/plain, */*"}},s.forEach(["delete","get","head"],function(e){a.headers[e]={}}),s.forEach(["post","put","patch"],function(e){a.headers[e]=s.merge(u)}),e.exports=a},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t){r.forEach(e,function(n,r){r!==t&&r.toUpperCase()===t.toUpperCase()&&(e[t]=n,delete e[r])})}},function(e,t,n){"use strict";var r=n(2),o=n(9),s=n(12),i=n(13),u=n(14),a=n(10);e.exports=function(e){return new Promise(function(t,c){var f=e.data,p=e.headers;r.isFormData(f)&&delete p["Content-Type"];var d=new XMLHttpRequest;if(e.auth){var l=e.auth.username||"",h=e.auth.password||"";p.Authorization="Basic "+btoa(l+":"+h)}if(d.open(e.method.toUpperCase(),s(e.url,e.params,e.paramsSerializer),!0),d.timeout=e.timeout,d.onreadystatechange=function(){if(d&&4===d.readyState&&(0!==d.status||d.responseURL&&0===d.responseURL.indexOf("file:"))){var n="getAllResponseHeaders"in d?i(d.getAllResponseHeaders()):null,r=e.responseType&&"text"!==e.responseType?d.response:d.responseText,s={data:r,status:d.status,statusText:d.statusText,headers:n,config:e,request:d};o(t,c,s),d=null}},d.onerror=function(){c(a("Network Error",e,null,d)),d=null},d.ontimeout=function(){c(a("timeout of "+e.timeout+"ms exceeded",e,"ECONNABORTED",d)),d=null},r.isStandardBrowserEnv()){var m=n(15),y=(e.withCredentials||u(e.url))&&e.xsrfCookieName?m.read(e.xsrfCookieName):void 0;y&&(p[e.xsrfHeaderName]=y)}if("setRequestHeader"in d&&r.forEach(p,function(e,t){"undefined"==typeof f&&"content-type"===t.toLowerCase()?delete p[t]:d.setRequestHeader(t,e)}),e.withCredentials&&(d.withCredentials=!0),e.responseType)try{d.responseType=e.responseType}catch(t){if("json"!==e.responseType)throw t}"function"==typeof e.onDownloadProgress&&d.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&d.upload&&d.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){d&&(d.abort(),c(e),d=null)}),void 0===f&&(f=null),d.send(f)})}},function(e,t,n){"use strict";var r=n(10);e.exports=function(e,t,n){var o=n.config.validateStatus;n.status&&o&&!o(n.status)?t(r("Request failed with status code "+n.status,n.config,null,n.request,n)):e(n)}},function(e,t,n){"use strict";var r=n(11);e.exports=function(e,t,n,o,s){var i=new Error(e);return r(i,t,n,o,s)}},function(e,t){"use strict";e.exports=function(e,t,n,r,o){return e.config=t,n&&(e.code=n),e.request=r,e.response=o,e}},function(e,t,n){"use strict";function r(e){return encodeURIComponent(e).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,"+").replace(/%5B/gi,"[").replace(/%5D/gi,"]")}var o=n(2);e.exports=function(e,t,n){if(!t)return e;var s;if(n)s=n(t);else if(o.isURLSearchParams(t))s=t.toString();else{var i=[];o.forEach(t,function(e,t){null!==e&&"undefined"!=typeof e&&(o.isArray(e)?t+="[]":e=[e],o.forEach(e,function(e){o.isDate(e)?e=e.toISOString():o.isObject(e)&&(e=JSON.stringify(e)),i.push(r(t)+"="+r(e))}))}),s=i.join("&")}return s&&(e+=(e.indexOf("?")===-1?"?":"&")+s),e}},function(e,t,n){"use strict";var r=n(2),o=["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","user-agent"];e.exports=function(e){var t,n,s,i={};return e?(r.forEach(e.split("\n"),function(e){if(s=e.indexOf(":"),t=r.trim(e.substr(0,s)).toLowerCase(),n=r.trim(e.substr(s+1)),t){if(i[t]&&o.indexOf(t)>=0)return;"set-cookie"===t?i[t]=(i[t]?i[t]:[]).concat([n]):i[t]=i[t]?i[t]+", "+n:n}}),i):i}},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){function e(e){var t=e;return n&&(o.setAttribute("href",t),t=o.href),o.setAttribute("href",t),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}var t,n=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a");return t=e(window.location.href),function(n){var o=r.isString(n)?e(n):n;return o.protocol===t.protocol&&o.host===t.host}}():function(){return function(){return!0}}()},function(e,t,n){"use strict";var r=n(2);e.exports=r.isStandardBrowserEnv()?function(){return{write:function(e,t,n,o,s,i){var u=[];u.push(e+"="+encodeURIComponent(t)),r.isNumber(n)&&u.push("expires="+new Date(n).toGMTString()),r.isString(o)&&u.push("path="+o),r.isString(s)&&u.push("domain="+s),i===!0&&u.push("secure"),document.cookie=u.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},function(e,t,n){"use strict";function r(){this.handlers=[]}var o=n(2);r.prototype.use=function(e,t){return this.handlers.push({fulfilled:e,rejected:t}),this.handlers.length-1},r.prototype.eject=function(e){this.handlers[e]&&(this.handlers[e]=null)},r.prototype.forEach=function(e){o.forEach(this.handlers,function(t){null!==t&&e(t)})},e.exports=r},function(e,t,n){"use strict";function r(e){e.cancelToken&&e.cancelToken.throwIfRequested()}var o=n(2),s=n(18),i=n(19),u=n(6),a=n(20),c=n(21);e.exports=function(e){r(e),e.baseURL&&!a(e.url)&&(e.url=c(e.baseURL,e.url)),e.headers=e.headers||{},e.data=s(e.data,e.headers,e.transformRequest),e.headers=o.merge(e.headers.common||{},e.headers[e.method]||{},e.headers||{}),o.forEach(["delete","get","head","post","put","patch","common"],function(t){delete e.headers[t]});var t=e.adapter||u.adapter;return t(e).then(function(t){return r(e),t.data=s(t.data,t.headers,e.transformResponse),t},function(t){return i(t)||(r(e),t&&t.response&&(t.response.data=s(t.response.data,t.response.headers,e.transformResponse))),Promise.reject(t)})}},function(e,t,n){"use strict";var r=n(2);e.exports=function(e,t,n){return r.forEach(n,function(n){e=n(e,t)}),e}},function(e,t){"use strict";e.exports=function(e){return!(!e||!e.__CANCEL__)}},function(e,t){"use strict";e.exports=function(e){return/^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(e)}},function(e,t){"use strict";e.exports=function(e,t){return t?e.replace(/\/+$/,"")+"/"+t.replace(/^\/+/,""):e}},function(e,t){"use strict";function n(e){this.message=e}n.prototype.toString=function(){return"Cancel"+(this.message?": "+this.message:"")},n.prototype.__CANCEL__=!0,e.exports=n},function(e,t,n){"use strict";function r(e){if("function"!=typeof e)throw new TypeError("executor must be a function.");var t;this.promise=new Promise(function(e){t=e});var n=this;e(function(e){n.reason||(n.reason=new o(e),t(n.reason))})}var o=n(22);r.prototype.throwIfRequested=function(){if(this.reason)throw this.reason},r.source=function(){var e,t=new r(function(t){e=t});return{token:t,cancel:e}},e.exports=r},function(e,t){"use strict";e.exports=function(e){return function(t){return e.apply(null,t)}}}])}); +//# sourceMappingURL=axios.min.map \ No newline at end of file diff --git a/setup/data/domain/apixpress/www/app/webapp/js/bootstrap.js b/setup/data/domain/apixpress/www/app/webapp/js/bootstrap.js new file mode 100755 index 0000000..26962e4 --- /dev/null +++ b/setup/data/domain/apixpress/www/app/webapp/js/bootstrap.js @@ -0,0 +1,5046 @@ +/*! + * Bootstrap v5.1.3 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@popperjs/core')) : + typeof define === 'function' && define.amd ? define(['@popperjs/core'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bootstrap = factory(global.Popper)); +})(this, (function (Popper) { 'use strict'; + + function _interopNamespace(e) { + if (e && e.__esModule) return e; + const n = Object.create(null); + if (e) { + for (const k in e) { + if (k !== 'default') { + const d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: () => e[k] + }); + } + } + } + n.default = e; + return Object.freeze(n); + } + + const Popper__namespace = /*#__PURE__*/_interopNamespace(Popper); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): util/index.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + const MAX_UID = 1000000; + const MILLISECONDS_MULTIPLIER = 1000; + const TRANSITION_END = 'transitionend'; // Shoutout AngusCroll (https://goo.gl/pxwQGp) + + const toType = obj => { + if (obj === null || obj === undefined) { + return `${obj}`; + } + + return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase(); + }; + /** + * -------------------------------------------------------------------------- + * Public Util Api + * -------------------------------------------------------------------------- + */ + + + const getUID = prefix => { + do { + prefix += Math.floor(Math.random() * MAX_UID); + } while (document.getElementById(prefix)); + + return prefix; + }; + + const getSelector = element => { + let selector = element.getAttribute('data-bs-target'); + + if (!selector || selector === '#') { + let hrefAttr = element.getAttribute('href'); // The only valid content that could double as a selector are IDs or classes, + // so everything starting with `#` or `.`. If a "real" URL is used as the selector, + // `document.querySelector` will rightfully complain it is invalid. + // See https://github.com/twbs/bootstrap/issues/32273 + + if (!hrefAttr || !hrefAttr.includes('#') && !hrefAttr.startsWith('.')) { + return null; + } // Just in case some CMS puts out a full URL with the anchor appended + + + if (hrefAttr.includes('#') && !hrefAttr.startsWith('#')) { + hrefAttr = `#${hrefAttr.split('#')[1]}`; + } + + selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : null; + } + + return selector; + }; + + const getSelectorFromElement = element => { + const selector = getSelector(element); + + if (selector) { + return document.querySelector(selector) ? selector : null; + } + + return null; + }; + + const getElementFromSelector = element => { + const selector = getSelector(element); + return selector ? document.querySelector(selector) : null; + }; + + const getTransitionDurationFromElement = element => { + if (!element) { + return 0; + } // Get transition-duration of the element + + + let { + transitionDuration, + transitionDelay + } = window.getComputedStyle(element); + const floatTransitionDuration = Number.parseFloat(transitionDuration); + const floatTransitionDelay = Number.parseFloat(transitionDelay); // Return 0 if element or transition duration is not found + + if (!floatTransitionDuration && !floatTransitionDelay) { + return 0; + } // If multiple durations are defined, take the first + + + transitionDuration = transitionDuration.split(',')[0]; + transitionDelay = transitionDelay.split(',')[0]; + return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER; + }; + + const triggerTransitionEnd = element => { + element.dispatchEvent(new Event(TRANSITION_END)); + }; + + const isElement = obj => { + if (!obj || typeof obj !== 'object') { + return false; + } + + if (typeof obj.jquery !== 'undefined') { + obj = obj[0]; + } + + return typeof obj.nodeType !== 'undefined'; + }; + + const getElement = obj => { + if (isElement(obj)) { + // it's a jQuery object or a node element + return obj.jquery ? obj[0] : obj; + } + + if (typeof obj === 'string' && obj.length > 0) { + return document.querySelector(obj); + } + + return null; + }; + + const typeCheckConfig = (componentName, config, configTypes) => { + Object.keys(configTypes).forEach(property => { + const expectedTypes = configTypes[property]; + const value = config[property]; + const valueType = value && isElement(value) ? 'element' : toType(value); + + if (!new RegExp(expectedTypes).test(valueType)) { + throw new TypeError(`${componentName.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`); + } + }); + }; + + const isVisible = element => { + if (!isElement(element) || element.getClientRects().length === 0) { + return false; + } + + return getComputedStyle(element).getPropertyValue('visibility') === 'visible'; + }; + + const isDisabled = element => { + if (!element || element.nodeType !== Node.ELEMENT_NODE) { + return true; + } + + if (element.classList.contains('disabled')) { + return true; + } + + if (typeof element.disabled !== 'undefined') { + return element.disabled; + } + + return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'; + }; + + const findShadowRoot = element => { + if (!document.documentElement.attachShadow) { + return null; + } // Can find the shadow root otherwise it'll return the document + + + if (typeof element.getRootNode === 'function') { + const root = element.getRootNode(); + return root instanceof ShadowRoot ? root : null; + } + + if (element instanceof ShadowRoot) { + return element; + } // when we don't find a shadow root + + + if (!element.parentNode) { + return null; + } + + return findShadowRoot(element.parentNode); + }; + + const noop = () => {}; + /** + * Trick to restart an element's animation + * + * @param {HTMLElement} element + * @return void + * + * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation + */ + + + const reflow = element => { + // eslint-disable-next-line no-unused-expressions + element.offsetHeight; + }; + + const getjQuery = () => { + const { + jQuery + } = window; + + if (jQuery && !document.body.hasAttribute('data-bs-no-jquery')) { + return jQuery; + } + + return null; + }; + + const DOMContentLoadedCallbacks = []; + + const onDOMContentLoaded = callback => { + if (document.readyState === 'loading') { + // add listener on the first call when the document is in loading state + if (!DOMContentLoadedCallbacks.length) { + document.addEventListener('DOMContentLoaded', () => { + DOMContentLoadedCallbacks.forEach(callback => callback()); + }); + } + + DOMContentLoadedCallbacks.push(callback); + } else { + callback(); + } + }; + + const isRTL = () => document.documentElement.dir === 'rtl'; + + const defineJQueryPlugin = plugin => { + onDOMContentLoaded(() => { + const $ = getjQuery(); + /* istanbul ignore if */ + + if ($) { + const name = plugin.NAME; + const JQUERY_NO_CONFLICT = $.fn[name]; + $.fn[name] = plugin.jQueryInterface; + $.fn[name].Constructor = plugin; + + $.fn[name].noConflict = () => { + $.fn[name] = JQUERY_NO_CONFLICT; + return plugin.jQueryInterface; + }; + } + }); + }; + + const execute = callback => { + if (typeof callback === 'function') { + callback(); + } + }; + + const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => { + if (!waitForTransition) { + execute(callback); + return; + } + + const durationPadding = 5; + const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding; + let called = false; + + const handler = ({ + target + }) => { + if (target !== transitionElement) { + return; + } + + called = true; + transitionElement.removeEventListener(TRANSITION_END, handler); + execute(callback); + }; + + transitionElement.addEventListener(TRANSITION_END, handler); + setTimeout(() => { + if (!called) { + triggerTransitionEnd(transitionElement); + } + }, emulatedDuration); + }; + /** + * Return the previous/next element of a list. + * + * @param {array} list The list of elements + * @param activeElement The active element + * @param shouldGetNext Choose to get next or previous element + * @param isCycleAllowed + * @return {Element|elem} The proper element + */ + + + const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => { + let index = list.indexOf(activeElement); // if the element does not exist in the list return an element depending on the direction and if cycle is allowed + + if (index === -1) { + return list[!shouldGetNext && isCycleAllowed ? list.length - 1 : 0]; + } + + const listLength = list.length; + index += shouldGetNext ? 1 : -1; + + if (isCycleAllowed) { + index = (index + listLength) % listLength; + } + + return list[Math.max(0, Math.min(index, listLength - 1))]; + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): dom/event-handler.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const namespaceRegex = /[^.]*(?=\..*)\.|.*/; + const stripNameRegex = /\..*/; + const stripUidRegex = /::\d+$/; + const eventRegistry = {}; // Events storage + + let uidEvent = 1; + const customEvents = { + mouseenter: 'mouseover', + mouseleave: 'mouseout' + }; + const customEventsRegex = /^(mouseenter|mouseleave)/i; + const nativeEvents = new Set(['click', 'dblclick', 'mouseup', 'mousedown', 'contextmenu', 'mousewheel', 'DOMMouseScroll', 'mouseover', 'mouseout', 'mousemove', 'selectstart', 'selectend', 'keydown', 'keypress', 'keyup', 'orientationchange', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel', 'gesturestart', 'gesturechange', 'gestureend', 'focus', 'blur', 'change', 'reset', 'select', 'submit', 'focusin', 'focusout', 'load', 'unload', 'beforeunload', 'resize', 'move', 'DOMContentLoaded', 'readystatechange', 'error', 'abort', 'scroll']); + /** + * ------------------------------------------------------------------------ + * Private methods + * ------------------------------------------------------------------------ + */ + + function getUidEvent(element, uid) { + return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++; + } + + function getEvent(element) { + const uid = getUidEvent(element); + element.uidEvent = uid; + eventRegistry[uid] = eventRegistry[uid] || {}; + return eventRegistry[uid]; + } + + function bootstrapHandler(element, fn) { + return function handler(event) { + event.delegateTarget = element; + + if (handler.oneOff) { + EventHandler.off(element, event.type, fn); + } + + return fn.apply(element, [event]); + }; + } + + function bootstrapDelegationHandler(element, selector, fn) { + return function handler(event) { + const domElements = element.querySelectorAll(selector); + + for (let { + target + } = event; target && target !== this; target = target.parentNode) { + for (let i = domElements.length; i--;) { + if (domElements[i] === target) { + event.delegateTarget = target; + + if (handler.oneOff) { + EventHandler.off(element, event.type, selector, fn); + } + + return fn.apply(target, [event]); + } + } + } // To please ESLint + + + return null; + }; + } + + function findHandler(events, handler, delegationSelector = null) { + const uidEventList = Object.keys(events); + + for (let i = 0, len = uidEventList.length; i < len; i++) { + const event = events[uidEventList[i]]; + + if (event.originalHandler === handler && event.delegationSelector === delegationSelector) { + return event; + } + } + + return null; + } + + function normalizeParams(originalTypeEvent, handler, delegationFn) { + const delegation = typeof handler === 'string'; + const originalHandler = delegation ? delegationFn : handler; + let typeEvent = getTypeEvent(originalTypeEvent); + const isNative = nativeEvents.has(typeEvent); + + if (!isNative) { + typeEvent = originalTypeEvent; + } + + return [delegation, originalHandler, typeEvent]; + } + + function addHandler(element, originalTypeEvent, handler, delegationFn, oneOff) { + if (typeof originalTypeEvent !== 'string' || !element) { + return; + } + + if (!handler) { + handler = delegationFn; + delegationFn = null; + } // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position + // this prevents the handler from being dispatched the same way as mouseover or mouseout does + + + if (customEventsRegex.test(originalTypeEvent)) { + const wrapFn = fn => { + return function (event) { + if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) { + return fn.call(this, event); + } + }; + }; + + if (delegationFn) { + delegationFn = wrapFn(delegationFn); + } else { + handler = wrapFn(handler); + } + } + + const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn); + const events = getEvent(element); + const handlers = events[typeEvent] || (events[typeEvent] = {}); + const previousFn = findHandler(handlers, originalHandler, delegation ? handler : null); + + if (previousFn) { + previousFn.oneOff = previousFn.oneOff && oneOff; + return; + } + + const uid = getUidEvent(originalHandler, originalTypeEvent.replace(namespaceRegex, '')); + const fn = delegation ? bootstrapDelegationHandler(element, handler, delegationFn) : bootstrapHandler(element, handler); + fn.delegationSelector = delegation ? handler : null; + fn.originalHandler = originalHandler; + fn.oneOff = oneOff; + fn.uidEvent = uid; + handlers[uid] = fn; + element.addEventListener(typeEvent, fn, delegation); + } + + function removeHandler(element, events, typeEvent, handler, delegationSelector) { + const fn = findHandler(events[typeEvent], handler, delegationSelector); + + if (!fn) { + return; + } + + element.removeEventListener(typeEvent, fn, Boolean(delegationSelector)); + delete events[typeEvent][fn.uidEvent]; + } + + function removeNamespacedHandlers(element, events, typeEvent, namespace) { + const storeElementEvent = events[typeEvent] || {}; + Object.keys(storeElementEvent).forEach(handlerKey => { + if (handlerKey.includes(namespace)) { + const event = storeElementEvent[handlerKey]; + removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector); + } + }); + } + + function getTypeEvent(event) { + // allow to get the native events from namespaced events ('click.bs.button' --> 'click') + event = event.replace(stripNameRegex, ''); + return customEvents[event] || event; + } + + const EventHandler = { + on(element, event, handler, delegationFn) { + addHandler(element, event, handler, delegationFn, false); + }, + + one(element, event, handler, delegationFn) { + addHandler(element, event, handler, delegationFn, true); + }, + + off(element, originalTypeEvent, handler, delegationFn) { + if (typeof originalTypeEvent !== 'string' || !element) { + return; + } + + const [delegation, originalHandler, typeEvent] = normalizeParams(originalTypeEvent, handler, delegationFn); + const inNamespace = typeEvent !== originalTypeEvent; + const events = getEvent(element); + const isNamespace = originalTypeEvent.startsWith('.'); + + if (typeof originalHandler !== 'undefined') { + // Simplest case: handler is passed, remove that listener ONLY. + if (!events || !events[typeEvent]) { + return; + } + + removeHandler(element, events, typeEvent, originalHandler, delegation ? handler : null); + return; + } + + if (isNamespace) { + Object.keys(events).forEach(elementEvent => { + removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1)); + }); + } + + const storeElementEvent = events[typeEvent] || {}; + Object.keys(storeElementEvent).forEach(keyHandlers => { + const handlerKey = keyHandlers.replace(stripUidRegex, ''); + + if (!inNamespace || originalTypeEvent.includes(handlerKey)) { + const event = storeElementEvent[keyHandlers]; + removeHandler(element, events, typeEvent, event.originalHandler, event.delegationSelector); + } + }); + }, + + trigger(element, event, args) { + if (typeof event !== 'string' || !element) { + return null; + } + + const $ = getjQuery(); + const typeEvent = getTypeEvent(event); + const inNamespace = event !== typeEvent; + const isNative = nativeEvents.has(typeEvent); + let jQueryEvent; + let bubbles = true; + let nativeDispatch = true; + let defaultPrevented = false; + let evt = null; + + if (inNamespace && $) { + jQueryEvent = $.Event(event, args); + $(element).trigger(jQueryEvent); + bubbles = !jQueryEvent.isPropagationStopped(); + nativeDispatch = !jQueryEvent.isImmediatePropagationStopped(); + defaultPrevented = jQueryEvent.isDefaultPrevented(); + } + + if (isNative) { + evt = document.createEvent('HTMLEvents'); + evt.initEvent(typeEvent, bubbles, true); + } else { + evt = new CustomEvent(event, { + bubbles, + cancelable: true + }); + } // merge custom information in our event + + + if (typeof args !== 'undefined') { + Object.keys(args).forEach(key => { + Object.defineProperty(evt, key, { + get() { + return args[key]; + } + + }); + }); + } + + if (defaultPrevented) { + evt.preventDefault(); + } + + if (nativeDispatch) { + element.dispatchEvent(evt); + } + + if (evt.defaultPrevented && typeof jQueryEvent !== 'undefined') { + jQueryEvent.preventDefault(); + } + + return evt; + } + + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): dom/data.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + const elementMap = new Map(); + const Data = { + set(element, key, instance) { + if (!elementMap.has(element)) { + elementMap.set(element, new Map()); + } + + const instanceMap = elementMap.get(element); // make it clear we only want one instance per element + // can be removed later when multiple key/instances are fine to be used + + if (!instanceMap.has(key) && instanceMap.size !== 0) { + // eslint-disable-next-line no-console + console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`); + return; + } + + instanceMap.set(key, instance); + }, + + get(element, key) { + if (elementMap.has(element)) { + return elementMap.get(element).get(key) || null; + } + + return null; + }, + + remove(element, key) { + if (!elementMap.has(element)) { + return; + } + + const instanceMap = elementMap.get(element); + instanceMap.delete(key); // free up element references if there are no instances left for an element + + if (instanceMap.size === 0) { + elementMap.delete(element); + } + } + + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): base-component.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const VERSION = '5.1.3'; + + class BaseComponent { + constructor(element) { + element = getElement(element); + + if (!element) { + return; + } + + this._element = element; + Data.set(this._element, this.constructor.DATA_KEY, this); + } + + dispose() { + Data.remove(this._element, this.constructor.DATA_KEY); + EventHandler.off(this._element, this.constructor.EVENT_KEY); + Object.getOwnPropertyNames(this).forEach(propertyName => { + this[propertyName] = null; + }); + } + + _queueCallback(callback, element, isAnimated = true) { + executeAfterTransition(callback, element, isAnimated); + } + /** Static */ + + + static getInstance(element) { + return Data.get(getElement(element), this.DATA_KEY); + } + + static getOrCreateInstance(element, config = {}) { + return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null); + } + + static get VERSION() { + return VERSION; + } + + static get NAME() { + throw new Error('You have to implement the static method "NAME", for each component!'); + } + + static get DATA_KEY() { + return `bs.${this.NAME}`; + } + + static get EVENT_KEY() { + return `.${this.DATA_KEY}`; + } + + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): util/component-functions.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + const enableDismissTrigger = (component, method = 'hide') => { + const clickEvent = `click.dismiss${component.EVENT_KEY}`; + const name = component.NAME; + EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) { + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + + if (isDisabled(this)) { + return; + } + + const target = getElementFromSelector(this) || this.closest(`.${name}`); + const instance = component.getOrCreateInstance(target); // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method + + instance[method](); + }); + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): alert.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const NAME$d = 'alert'; + const DATA_KEY$c = 'bs.alert'; + const EVENT_KEY$c = `.${DATA_KEY$c}`; + const EVENT_CLOSE = `close${EVENT_KEY$c}`; + const EVENT_CLOSED = `closed${EVENT_KEY$c}`; + const CLASS_NAME_FADE$5 = 'fade'; + const CLASS_NAME_SHOW$8 = 'show'; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + class Alert extends BaseComponent { + // Getters + static get NAME() { + return NAME$d; + } // Public + + + close() { + const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE); + + if (closeEvent.defaultPrevented) { + return; + } + + this._element.classList.remove(CLASS_NAME_SHOW$8); + + const isAnimated = this._element.classList.contains(CLASS_NAME_FADE$5); + + this._queueCallback(() => this._destroyElement(), this._element, isAnimated); + } // Private + + + _destroyElement() { + this._element.remove(); + + EventHandler.trigger(this._element, EVENT_CLOSED); + this.dispose(); + } // Static + + + static jQueryInterface(config) { + return this.each(function () { + const data = Alert.getOrCreateInstance(this); + + if (typeof config !== 'string') { + return; + } + + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + + data[config](this); + }); + } + + } + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + enableDismissTrigger(Alert, 'close'); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + * add .Alert to jQuery only if jQuery is present + */ + + defineJQueryPlugin(Alert); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): button.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const NAME$c = 'button'; + const DATA_KEY$b = 'bs.button'; + const EVENT_KEY$b = `.${DATA_KEY$b}`; + const DATA_API_KEY$7 = '.data-api'; + const CLASS_NAME_ACTIVE$3 = 'active'; + const SELECTOR_DATA_TOGGLE$5 = '[data-bs-toggle="button"]'; + const EVENT_CLICK_DATA_API$6 = `click${EVENT_KEY$b}${DATA_API_KEY$7}`; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + class Button extends BaseComponent { + // Getters + static get NAME() { + return NAME$c; + } // Public + + + toggle() { + // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method + this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE$3)); + } // Static + + + static jQueryInterface(config) { + return this.each(function () { + const data = Button.getOrCreateInstance(this); + + if (config === 'toggle') { + data[config](); + } + }); + } + + } + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + EventHandler.on(document, EVENT_CLICK_DATA_API$6, SELECTOR_DATA_TOGGLE$5, event => { + event.preventDefault(); + const button = event.target.closest(SELECTOR_DATA_TOGGLE$5); + const data = Button.getOrCreateInstance(button); + data.toggle(); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + * add .Button to jQuery only if jQuery is present + */ + + defineJQueryPlugin(Button); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): dom/manipulator.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + function normalizeData(val) { + if (val === 'true') { + return true; + } + + if (val === 'false') { + return false; + } + + if (val === Number(val).toString()) { + return Number(val); + } + + if (val === '' || val === 'null') { + return null; + } + + return val; + } + + function normalizeDataKey(key) { + return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`); + } + + const Manipulator = { + setDataAttribute(element, key, value) { + element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value); + }, + + removeDataAttribute(element, key) { + element.removeAttribute(`data-bs-${normalizeDataKey(key)}`); + }, + + getDataAttributes(element) { + if (!element) { + return {}; + } + + const attributes = {}; + Object.keys(element.dataset).filter(key => key.startsWith('bs')).forEach(key => { + let pureKey = key.replace(/^bs/, ''); + pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length); + attributes[pureKey] = normalizeData(element.dataset[key]); + }); + return attributes; + }, + + getDataAttribute(element, key) { + return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`)); + }, + + offset(element) { + const rect = element.getBoundingClientRect(); + return { + top: rect.top + window.pageYOffset, + left: rect.left + window.pageXOffset + }; + }, + + position(element) { + return { + top: element.offsetTop, + left: element.offsetLeft + }; + } + + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): dom/selector-engine.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + const NODE_TEXT = 3; + const SelectorEngine = { + find(selector, element = document.documentElement) { + return [].concat(...Element.prototype.querySelectorAll.call(element, selector)); + }, + + findOne(selector, element = document.documentElement) { + return Element.prototype.querySelector.call(element, selector); + }, + + children(element, selector) { + return [].concat(...element.children).filter(child => child.matches(selector)); + }, + + parents(element, selector) { + const parents = []; + let ancestor = element.parentNode; + + while (ancestor && ancestor.nodeType === Node.ELEMENT_NODE && ancestor.nodeType !== NODE_TEXT) { + if (ancestor.matches(selector)) { + parents.push(ancestor); + } + + ancestor = ancestor.parentNode; + } + + return parents; + }, + + prev(element, selector) { + let previous = element.previousElementSibling; + + while (previous) { + if (previous.matches(selector)) { + return [previous]; + } + + previous = previous.previousElementSibling; + } + + return []; + }, + + next(element, selector) { + let next = element.nextElementSibling; + + while (next) { + if (next.matches(selector)) { + return [next]; + } + + next = next.nextElementSibling; + } + + return []; + }, + + focusableChildren(element) { + const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable="true"]'].map(selector => `${selector}:not([tabindex^="-"])`).join(', '); + return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el)); + } + + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): carousel.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const NAME$b = 'carousel'; + const DATA_KEY$a = 'bs.carousel'; + const EVENT_KEY$a = `.${DATA_KEY$a}`; + const DATA_API_KEY$6 = '.data-api'; + const ARROW_LEFT_KEY = 'ArrowLeft'; + const ARROW_RIGHT_KEY = 'ArrowRight'; + const TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch + + const SWIPE_THRESHOLD = 40; + const Default$a = { + interval: 5000, + keyboard: true, + slide: false, + pause: 'hover', + wrap: true, + touch: true + }; + const DefaultType$a = { + interval: '(number|boolean)', + keyboard: 'boolean', + slide: '(boolean|string)', + pause: '(string|boolean)', + wrap: 'boolean', + touch: 'boolean' + }; + const ORDER_NEXT = 'next'; + const ORDER_PREV = 'prev'; + const DIRECTION_LEFT = 'left'; + const DIRECTION_RIGHT = 'right'; + const KEY_TO_DIRECTION = { + [ARROW_LEFT_KEY]: DIRECTION_RIGHT, + [ARROW_RIGHT_KEY]: DIRECTION_LEFT + }; + const EVENT_SLIDE = `slide${EVENT_KEY$a}`; + const EVENT_SLID = `slid${EVENT_KEY$a}`; + const EVENT_KEYDOWN = `keydown${EVENT_KEY$a}`; + const EVENT_MOUSEENTER = `mouseenter${EVENT_KEY$a}`; + const EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY$a}`; + const EVENT_TOUCHSTART = `touchstart${EVENT_KEY$a}`; + const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY$a}`; + const EVENT_TOUCHEND = `touchend${EVENT_KEY$a}`; + const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY$a}`; + const EVENT_POINTERUP = `pointerup${EVENT_KEY$a}`; + const EVENT_DRAG_START = `dragstart${EVENT_KEY$a}`; + const EVENT_LOAD_DATA_API$2 = `load${EVENT_KEY$a}${DATA_API_KEY$6}`; + const EVENT_CLICK_DATA_API$5 = `click${EVENT_KEY$a}${DATA_API_KEY$6}`; + const CLASS_NAME_CAROUSEL = 'carousel'; + const CLASS_NAME_ACTIVE$2 = 'active'; + const CLASS_NAME_SLIDE = 'slide'; + const CLASS_NAME_END = 'carousel-item-end'; + const CLASS_NAME_START = 'carousel-item-start'; + const CLASS_NAME_NEXT = 'carousel-item-next'; + const CLASS_NAME_PREV = 'carousel-item-prev'; + const CLASS_NAME_POINTER_EVENT = 'pointer-event'; + const SELECTOR_ACTIVE$1 = '.active'; + const SELECTOR_ACTIVE_ITEM = '.active.carousel-item'; + const SELECTOR_ITEM = '.carousel-item'; + const SELECTOR_ITEM_IMG = '.carousel-item img'; + const SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev'; + const SELECTOR_INDICATORS = '.carousel-indicators'; + const SELECTOR_INDICATOR = '[data-bs-target]'; + const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'; + const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]'; + const POINTER_TYPE_TOUCH = 'touch'; + const POINTER_TYPE_PEN = 'pen'; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + class Carousel extends BaseComponent { + constructor(element, config) { + super(element); + this._items = null; + this._interval = null; + this._activeElement = null; + this._isPaused = false; + this._isSliding = false; + this.touchTimeout = null; + this.touchStartX = 0; + this.touchDeltaX = 0; + this._config = this._getConfig(config); + this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element); + this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0; + this._pointerEvent = Boolean(window.PointerEvent); + + this._addEventListeners(); + } // Getters + + + static get Default() { + return Default$a; + } + + static get NAME() { + return NAME$b; + } // Public + + + next() { + this._slide(ORDER_NEXT); + } + + nextWhenVisible() { + // Don't call next when the page isn't visible + // or the carousel or its parent isn't visible + if (!document.hidden && isVisible(this._element)) { + this.next(); + } + } + + prev() { + this._slide(ORDER_PREV); + } + + pause(event) { + if (!event) { + this._isPaused = true; + } + + if (SelectorEngine.findOne(SELECTOR_NEXT_PREV, this._element)) { + triggerTransitionEnd(this._element); + this.cycle(true); + } + + clearInterval(this._interval); + this._interval = null; + } + + cycle(event) { + if (!event) { + this._isPaused = false; + } + + if (this._interval) { + clearInterval(this._interval); + this._interval = null; + } + + if (this._config && this._config.interval && !this._isPaused) { + this._updateInterval(); + + this._interval = setInterval((document.visibilityState ? this.nextWhenVisible : this.next).bind(this), this._config.interval); + } + } + + to(index) { + this._activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element); + + const activeIndex = this._getItemIndex(this._activeElement); + + if (index > this._items.length - 1 || index < 0) { + return; + } + + if (this._isSliding) { + EventHandler.one(this._element, EVENT_SLID, () => this.to(index)); + return; + } + + if (activeIndex === index) { + this.pause(); + this.cycle(); + return; + } + + const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV; + + this._slide(order, this._items[index]); + } // Private + + + _getConfig(config) { + config = { ...Default$a, + ...Manipulator.getDataAttributes(this._element), + ...(typeof config === 'object' ? config : {}) + }; + typeCheckConfig(NAME$b, config, DefaultType$a); + return config; + } + + _handleSwipe() { + const absDeltax = Math.abs(this.touchDeltaX); + + if (absDeltax <= SWIPE_THRESHOLD) { + return; + } + + const direction = absDeltax / this.touchDeltaX; + this.touchDeltaX = 0; + + if (!direction) { + return; + } + + this._slide(direction > 0 ? DIRECTION_RIGHT : DIRECTION_LEFT); + } + + _addEventListeners() { + if (this._config.keyboard) { + EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event)); + } + + if (this._config.pause === 'hover') { + EventHandler.on(this._element, EVENT_MOUSEENTER, event => this.pause(event)); + EventHandler.on(this._element, EVENT_MOUSELEAVE, event => this.cycle(event)); + } + + if (this._config.touch && this._touchSupported) { + this._addTouchEventListeners(); + } + } + + _addTouchEventListeners() { + const hasPointerPenTouch = event => { + return this._pointerEvent && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH); + }; + + const start = event => { + if (hasPointerPenTouch(event)) { + this.touchStartX = event.clientX; + } else if (!this._pointerEvent) { + this.touchStartX = event.touches[0].clientX; + } + }; + + const move = event => { + // ensure swiping with one touch and not pinching + this.touchDeltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this.touchStartX; + }; + + const end = event => { + if (hasPointerPenTouch(event)) { + this.touchDeltaX = event.clientX - this.touchStartX; + } + + this._handleSwipe(); + + if (this._config.pause === 'hover') { + // If it's a touch-enabled device, mouseenter/leave are fired as + // part of the mouse compatibility events on first tap - the carousel + // would stop cycling until user tapped out of it; + // here, we listen for touchend, explicitly pause the carousel + // (as if it's the second time we tap on it, mouseenter compat event + // is NOT fired) and after a timeout (to allow for mouse compatibility + // events to fire) we explicitly restart cycling + this.pause(); + + if (this.touchTimeout) { + clearTimeout(this.touchTimeout); + } + + this.touchTimeout = setTimeout(event => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval); + } + }; + + SelectorEngine.find(SELECTOR_ITEM_IMG, this._element).forEach(itemImg => { + EventHandler.on(itemImg, EVENT_DRAG_START, event => event.preventDefault()); + }); + + if (this._pointerEvent) { + EventHandler.on(this._element, EVENT_POINTERDOWN, event => start(event)); + EventHandler.on(this._element, EVENT_POINTERUP, event => end(event)); + + this._element.classList.add(CLASS_NAME_POINTER_EVENT); + } else { + EventHandler.on(this._element, EVENT_TOUCHSTART, event => start(event)); + EventHandler.on(this._element, EVENT_TOUCHMOVE, event => move(event)); + EventHandler.on(this._element, EVENT_TOUCHEND, event => end(event)); + } + } + + _keydown(event) { + if (/input|textarea/i.test(event.target.tagName)) { + return; + } + + const direction = KEY_TO_DIRECTION[event.key]; + + if (direction) { + event.preventDefault(); + + this._slide(direction); + } + } + + _getItemIndex(element) { + this._items = element && element.parentNode ? SelectorEngine.find(SELECTOR_ITEM, element.parentNode) : []; + return this._items.indexOf(element); + } + + _getItemByOrder(order, activeElement) { + const isNext = order === ORDER_NEXT; + return getNextActiveElement(this._items, activeElement, isNext, this._config.wrap); + } + + _triggerSlideEvent(relatedTarget, eventDirectionName) { + const targetIndex = this._getItemIndex(relatedTarget); + + const fromIndex = this._getItemIndex(SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)); + + return EventHandler.trigger(this._element, EVENT_SLIDE, { + relatedTarget, + direction: eventDirectionName, + from: fromIndex, + to: targetIndex + }); + } + + _setActiveIndicatorElement(element) { + if (this._indicatorsElement) { + const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE$1, this._indicatorsElement); + activeIndicator.classList.remove(CLASS_NAME_ACTIVE$2); + activeIndicator.removeAttribute('aria-current'); + const indicators = SelectorEngine.find(SELECTOR_INDICATOR, this._indicatorsElement); + + for (let i = 0; i < indicators.length; i++) { + if (Number.parseInt(indicators[i].getAttribute('data-bs-slide-to'), 10) === this._getItemIndex(element)) { + indicators[i].classList.add(CLASS_NAME_ACTIVE$2); + indicators[i].setAttribute('aria-current', 'true'); + break; + } + } + } + } + + _updateInterval() { + const element = this._activeElement || SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element); + + if (!element) { + return; + } + + const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10); + + if (elementInterval) { + this._config.defaultInterval = this._config.defaultInterval || this._config.interval; + this._config.interval = elementInterval; + } else { + this._config.interval = this._config.defaultInterval || this._config.interval; + } + } + + _slide(directionOrOrder, element) { + const order = this._directionToOrder(directionOrOrder); + + const activeElement = SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element); + + const activeElementIndex = this._getItemIndex(activeElement); + + const nextElement = element || this._getItemByOrder(order, activeElement); + + const nextElementIndex = this._getItemIndex(nextElement); + + const isCycling = Boolean(this._interval); + const isNext = order === ORDER_NEXT; + const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END; + const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV; + + const eventDirectionName = this._orderToDirection(order); + + if (nextElement && nextElement.classList.contains(CLASS_NAME_ACTIVE$2)) { + this._isSliding = false; + return; + } + + if (this._isSliding) { + return; + } + + const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName); + + if (slideEvent.defaultPrevented) { + return; + } + + if (!activeElement || !nextElement) { + // Some weirdness is happening, so we bail + return; + } + + this._isSliding = true; + + if (isCycling) { + this.pause(); + } + + this._setActiveIndicatorElement(nextElement); + + this._activeElement = nextElement; + + const triggerSlidEvent = () => { + EventHandler.trigger(this._element, EVENT_SLID, { + relatedTarget: nextElement, + direction: eventDirectionName, + from: activeElementIndex, + to: nextElementIndex + }); + }; + + if (this._element.classList.contains(CLASS_NAME_SLIDE)) { + nextElement.classList.add(orderClassName); + reflow(nextElement); + activeElement.classList.add(directionalClassName); + nextElement.classList.add(directionalClassName); + + const completeCallBack = () => { + nextElement.classList.remove(directionalClassName, orderClassName); + nextElement.classList.add(CLASS_NAME_ACTIVE$2); + activeElement.classList.remove(CLASS_NAME_ACTIVE$2, orderClassName, directionalClassName); + this._isSliding = false; + setTimeout(triggerSlidEvent, 0); + }; + + this._queueCallback(completeCallBack, activeElement, true); + } else { + activeElement.classList.remove(CLASS_NAME_ACTIVE$2); + nextElement.classList.add(CLASS_NAME_ACTIVE$2); + this._isSliding = false; + triggerSlidEvent(); + } + + if (isCycling) { + this.cycle(); + } + } + + _directionToOrder(direction) { + if (![DIRECTION_RIGHT, DIRECTION_LEFT].includes(direction)) { + return direction; + } + + if (isRTL()) { + return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT; + } + + return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV; + } + + _orderToDirection(order) { + if (![ORDER_NEXT, ORDER_PREV].includes(order)) { + return order; + } + + if (isRTL()) { + return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + + return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT; + } // Static + + + static carouselInterface(element, config) { + const data = Carousel.getOrCreateInstance(element, config); + let { + _config + } = data; + + if (typeof config === 'object') { + _config = { ..._config, + ...config + }; + } + + const action = typeof config === 'string' ? config : _config.slide; + + if (typeof config === 'number') { + data.to(config); + } else if (typeof action === 'string') { + if (typeof data[action] === 'undefined') { + throw new TypeError(`No method named "${action}"`); + } + + data[action](); + } else if (_config.interval && _config.ride) { + data.pause(); + data.cycle(); + } + } + + static jQueryInterface(config) { + return this.each(function () { + Carousel.carouselInterface(this, config); + }); + } + + static dataApiClickHandler(event) { + const target = getElementFromSelector(this); + + if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) { + return; + } + + const config = { ...Manipulator.getDataAttributes(target), + ...Manipulator.getDataAttributes(this) + }; + const slideIndex = this.getAttribute('data-bs-slide-to'); + + if (slideIndex) { + config.interval = false; + } + + Carousel.carouselInterface(target, config); + + if (slideIndex) { + Carousel.getInstance(target).to(slideIndex); + } + + event.preventDefault(); + } + + } + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + EventHandler.on(document, EVENT_CLICK_DATA_API$5, SELECTOR_DATA_SLIDE, Carousel.dataApiClickHandler); + EventHandler.on(window, EVENT_LOAD_DATA_API$2, () => { + const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE); + + for (let i = 0, len = carousels.length; i < len; i++) { + Carousel.carouselInterface(carousels[i], Carousel.getInstance(carousels[i])); + } + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + * add .Carousel to jQuery only if jQuery is present + */ + + defineJQueryPlugin(Carousel); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): collapse.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const NAME$a = 'collapse'; + const DATA_KEY$9 = 'bs.collapse'; + const EVENT_KEY$9 = `.${DATA_KEY$9}`; + const DATA_API_KEY$5 = '.data-api'; + const Default$9 = { + toggle: true, + parent: null + }; + const DefaultType$9 = { + toggle: 'boolean', + parent: '(null|element)' + }; + const EVENT_SHOW$5 = `show${EVENT_KEY$9}`; + const EVENT_SHOWN$5 = `shown${EVENT_KEY$9}`; + const EVENT_HIDE$5 = `hide${EVENT_KEY$9}`; + const EVENT_HIDDEN$5 = `hidden${EVENT_KEY$9}`; + const EVENT_CLICK_DATA_API$4 = `click${EVENT_KEY$9}${DATA_API_KEY$5}`; + const CLASS_NAME_SHOW$7 = 'show'; + const CLASS_NAME_COLLAPSE = 'collapse'; + const CLASS_NAME_COLLAPSING = 'collapsing'; + const CLASS_NAME_COLLAPSED = 'collapsed'; + const CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`; + const CLASS_NAME_HORIZONTAL = 'collapse-horizontal'; + const WIDTH = 'width'; + const HEIGHT = 'height'; + const SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'; + const SELECTOR_DATA_TOGGLE$4 = '[data-bs-toggle="collapse"]'; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + class Collapse extends BaseComponent { + constructor(element, config) { + super(element); + this._isTransitioning = false; + this._config = this._getConfig(config); + this._triggerArray = []; + const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE$4); + + for (let i = 0, len = toggleList.length; i < len; i++) { + const elem = toggleList[i]; + const selector = getSelectorFromElement(elem); + const filterElement = SelectorEngine.find(selector).filter(foundElem => foundElem === this._element); + + if (selector !== null && filterElement.length) { + this._selector = selector; + + this._triggerArray.push(elem); + } + } + + this._initializeChildren(); + + if (!this._config.parent) { + this._addAriaAndCollapsedClass(this._triggerArray, this._isShown()); + } + + if (this._config.toggle) { + this.toggle(); + } + } // Getters + + + static get Default() { + return Default$9; + } + + static get NAME() { + return NAME$a; + } // Public + + + toggle() { + if (this._isShown()) { + this.hide(); + } else { + this.show(); + } + } + + show() { + if (this._isTransitioning || this._isShown()) { + return; + } + + let actives = []; + let activesData; + + if (this._config.parent) { + const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent); + actives = SelectorEngine.find(SELECTOR_ACTIVES, this._config.parent).filter(elem => !children.includes(elem)); // remove children if greater depth + } + + const container = SelectorEngine.findOne(this._selector); + + if (actives.length) { + const tempActiveData = actives.find(elem => container !== elem); + activesData = tempActiveData ? Collapse.getInstance(tempActiveData) : null; + + if (activesData && activesData._isTransitioning) { + return; + } + } + + const startEvent = EventHandler.trigger(this._element, EVENT_SHOW$5); + + if (startEvent.defaultPrevented) { + return; + } + + actives.forEach(elemActive => { + if (container !== elemActive) { + Collapse.getOrCreateInstance(elemActive, { + toggle: false + }).hide(); + } + + if (!activesData) { + Data.set(elemActive, DATA_KEY$9, null); + } + }); + + const dimension = this._getDimension(); + + this._element.classList.remove(CLASS_NAME_COLLAPSE); + + this._element.classList.add(CLASS_NAME_COLLAPSING); + + this._element.style[dimension] = 0; + + this._addAriaAndCollapsedClass(this._triggerArray, true); + + this._isTransitioning = true; + + const complete = () => { + this._isTransitioning = false; + + this._element.classList.remove(CLASS_NAME_COLLAPSING); + + this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7); + + this._element.style[dimension] = ''; + EventHandler.trigger(this._element, EVENT_SHOWN$5); + }; + + const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1); + const scrollSize = `scroll${capitalizedDimension}`; + + this._queueCallback(complete, this._element, true); + + this._element.style[dimension] = `${this._element[scrollSize]}px`; + } + + hide() { + if (this._isTransitioning || !this._isShown()) { + return; + } + + const startEvent = EventHandler.trigger(this._element, EVENT_HIDE$5); + + if (startEvent.defaultPrevented) { + return; + } + + const dimension = this._getDimension(); + + this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`; + reflow(this._element); + + this._element.classList.add(CLASS_NAME_COLLAPSING); + + this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7); + + const triggerArrayLength = this._triggerArray.length; + + for (let i = 0; i < triggerArrayLength; i++) { + const trigger = this._triggerArray[i]; + const elem = getElementFromSelector(trigger); + + if (elem && !this._isShown(elem)) { + this._addAriaAndCollapsedClass([trigger], false); + } + } + + this._isTransitioning = true; + + const complete = () => { + this._isTransitioning = false; + + this._element.classList.remove(CLASS_NAME_COLLAPSING); + + this._element.classList.add(CLASS_NAME_COLLAPSE); + + EventHandler.trigger(this._element, EVENT_HIDDEN$5); + }; + + this._element.style[dimension] = ''; + + this._queueCallback(complete, this._element, true); + } + + _isShown(element = this._element) { + return element.classList.contains(CLASS_NAME_SHOW$7); + } // Private + + + _getConfig(config) { + config = { ...Default$9, + ...Manipulator.getDataAttributes(this._element), + ...config + }; + config.toggle = Boolean(config.toggle); // Coerce string values + + config.parent = getElement(config.parent); + typeCheckConfig(NAME$a, config, DefaultType$9); + return config; + } + + _getDimension() { + return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT; + } + + _initializeChildren() { + if (!this._config.parent) { + return; + } + + const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent); + SelectorEngine.find(SELECTOR_DATA_TOGGLE$4, this._config.parent).filter(elem => !children.includes(elem)).forEach(element => { + const selected = getElementFromSelector(element); + + if (selected) { + this._addAriaAndCollapsedClass([element], this._isShown(selected)); + } + }); + } + + _addAriaAndCollapsedClass(triggerArray, isOpen) { + if (!triggerArray.length) { + return; + } + + triggerArray.forEach(elem => { + if (isOpen) { + elem.classList.remove(CLASS_NAME_COLLAPSED); + } else { + elem.classList.add(CLASS_NAME_COLLAPSED); + } + + elem.setAttribute('aria-expanded', isOpen); + }); + } // Static + + + static jQueryInterface(config) { + return this.each(function () { + const _config = {}; + + if (typeof config === 'string' && /show|hide/.test(config)) { + _config.toggle = false; + } + + const data = Collapse.getOrCreateInstance(this, _config); + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + + data[config](); + } + }); + } + + } + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + EventHandler.on(document, EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$4, function (event) { + // preventDefault only for elements (which change the URL) not inside the collapsible element + if (event.target.tagName === 'A' || event.delegateTarget && event.delegateTarget.tagName === 'A') { + event.preventDefault(); + } + + const selector = getSelectorFromElement(this); + const selectorElements = SelectorEngine.find(selector); + selectorElements.forEach(element => { + Collapse.getOrCreateInstance(element, { + toggle: false + }).toggle(); + }); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + * add .Collapse to jQuery only if jQuery is present + */ + + defineJQueryPlugin(Collapse); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): dropdown.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const NAME$9 = 'dropdown'; + const DATA_KEY$8 = 'bs.dropdown'; + const EVENT_KEY$8 = `.${DATA_KEY$8}`; + const DATA_API_KEY$4 = '.data-api'; + const ESCAPE_KEY$2 = 'Escape'; + const SPACE_KEY = 'Space'; + const TAB_KEY$1 = 'Tab'; + const ARROW_UP_KEY = 'ArrowUp'; + const ARROW_DOWN_KEY = 'ArrowDown'; + const RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button + + const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEY}|${ARROW_DOWN_KEY}|${ESCAPE_KEY$2}`); + const EVENT_HIDE$4 = `hide${EVENT_KEY$8}`; + const EVENT_HIDDEN$4 = `hidden${EVENT_KEY$8}`; + const EVENT_SHOW$4 = `show${EVENT_KEY$8}`; + const EVENT_SHOWN$4 = `shown${EVENT_KEY$8}`; + const EVENT_CLICK_DATA_API$3 = `click${EVENT_KEY$8}${DATA_API_KEY$4}`; + const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY$8}${DATA_API_KEY$4}`; + const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY$8}${DATA_API_KEY$4}`; + const CLASS_NAME_SHOW$6 = 'show'; + const CLASS_NAME_DROPUP = 'dropup'; + const CLASS_NAME_DROPEND = 'dropend'; + const CLASS_NAME_DROPSTART = 'dropstart'; + const CLASS_NAME_NAVBAR = 'navbar'; + const SELECTOR_DATA_TOGGLE$3 = '[data-bs-toggle="dropdown"]'; + const SELECTOR_MENU = '.dropdown-menu'; + const SELECTOR_NAVBAR_NAV = '.navbar-nav'; + const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'; + const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'; + const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'; + const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'; + const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'; + const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'; + const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'; + const Default$8 = { + offset: [0, 2], + boundary: 'clippingParents', + reference: 'toggle', + display: 'dynamic', + popperConfig: null, + autoClose: true + }; + const DefaultType$8 = { + offset: '(array|string|function)', + boundary: '(string|element)', + reference: '(string|element|object)', + display: 'string', + popperConfig: '(null|object|function)', + autoClose: '(boolean|string)' + }; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + class Dropdown extends BaseComponent { + constructor(element, config) { + super(element); + this._popper = null; + this._config = this._getConfig(config); + this._menu = this._getMenuElement(); + this._inNavbar = this._detectNavbar(); + } // Getters + + + static get Default() { + return Default$8; + } + + static get DefaultType() { + return DefaultType$8; + } + + static get NAME() { + return NAME$9; + } // Public + + + toggle() { + return this._isShown() ? this.hide() : this.show(); + } + + show() { + if (isDisabled(this._element) || this._isShown(this._menu)) { + return; + } + + const relatedTarget = { + relatedTarget: this._element + }; + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$4, relatedTarget); + + if (showEvent.defaultPrevented) { + return; + } + + const parent = Dropdown.getParentFromElement(this._element); // Totally disable Popper for Dropdowns in Navbar + + if (this._inNavbar) { + Manipulator.setDataAttribute(this._menu, 'popper', 'none'); + } else { + this._createPopper(parent); + } // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + + + if ('ontouchstart' in document.documentElement && !parent.closest(SELECTOR_NAVBAR_NAV)) { + [].concat(...document.body.children).forEach(elem => EventHandler.on(elem, 'mouseover', noop)); + } + + this._element.focus(); + + this._element.setAttribute('aria-expanded', true); + + this._menu.classList.add(CLASS_NAME_SHOW$6); + + this._element.classList.add(CLASS_NAME_SHOW$6); + + EventHandler.trigger(this._element, EVENT_SHOWN$4, relatedTarget); + } + + hide() { + if (isDisabled(this._element) || !this._isShown(this._menu)) { + return; + } + + const relatedTarget = { + relatedTarget: this._element + }; + + this._completeHide(relatedTarget); + } + + dispose() { + if (this._popper) { + this._popper.destroy(); + } + + super.dispose(); + } + + update() { + this._inNavbar = this._detectNavbar(); + + if (this._popper) { + this._popper.update(); + } + } // Private + + + _completeHide(relatedTarget) { + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$4, relatedTarget); + + if (hideEvent.defaultPrevented) { + return; + } // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + + + if ('ontouchstart' in document.documentElement) { + [].concat(...document.body.children).forEach(elem => EventHandler.off(elem, 'mouseover', noop)); + } + + if (this._popper) { + this._popper.destroy(); + } + + this._menu.classList.remove(CLASS_NAME_SHOW$6); + + this._element.classList.remove(CLASS_NAME_SHOW$6); + + this._element.setAttribute('aria-expanded', 'false'); + + Manipulator.removeDataAttribute(this._menu, 'popper'); + EventHandler.trigger(this._element, EVENT_HIDDEN$4, relatedTarget); + } + + _getConfig(config) { + config = { ...this.constructor.Default, + ...Manipulator.getDataAttributes(this._element), + ...config + }; + typeCheckConfig(NAME$9, config, this.constructor.DefaultType); + + if (typeof config.reference === 'object' && !isElement(config.reference) && typeof config.reference.getBoundingClientRect !== 'function') { + // Popper virtual elements require a getBoundingClientRect method + throw new TypeError(`${NAME$9.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`); + } + + return config; + } + + _createPopper(parent) { + if (typeof Popper__namespace === 'undefined') { + throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)'); + } + + let referenceElement = this._element; + + if (this._config.reference === 'parent') { + referenceElement = parent; + } else if (isElement(this._config.reference)) { + referenceElement = getElement(this._config.reference); + } else if (typeof this._config.reference === 'object') { + referenceElement = this._config.reference; + } + + const popperConfig = this._getPopperConfig(); + + const isDisplayStatic = popperConfig.modifiers.find(modifier => modifier.name === 'applyStyles' && modifier.enabled === false); + this._popper = Popper__namespace.createPopper(referenceElement, this._menu, popperConfig); + + if (isDisplayStatic) { + Manipulator.setDataAttribute(this._menu, 'popper', 'static'); + } + } + + _isShown(element = this._element) { + return element.classList.contains(CLASS_NAME_SHOW$6); + } + + _getMenuElement() { + return SelectorEngine.next(this._element, SELECTOR_MENU)[0]; + } + + _getPlacement() { + const parentDropdown = this._element.parentNode; + + if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) { + return PLACEMENT_RIGHT; + } + + if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) { + return PLACEMENT_LEFT; + } // We need to trim the value because custom properties can also include spaces + + + const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'; + + if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) { + return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP; + } + + return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM; + } + + _detectNavbar() { + return this._element.closest(`.${CLASS_NAME_NAVBAR}`) !== null; + } + + _getOffset() { + const { + offset + } = this._config; + + if (typeof offset === 'string') { + return offset.split(',').map(val => Number.parseInt(val, 10)); + } + + if (typeof offset === 'function') { + return popperData => offset(popperData, this._element); + } + + return offset; + } + + _getPopperConfig() { + const defaultBsPopperConfig = { + placement: this._getPlacement(), + modifiers: [{ + name: 'preventOverflow', + options: { + boundary: this._config.boundary + } + }, { + name: 'offset', + options: { + offset: this._getOffset() + } + }] + }; // Disable Popper if we have a static display + + if (this._config.display === 'static') { + defaultBsPopperConfig.modifiers = [{ + name: 'applyStyles', + enabled: false + }]; + } + + return { ...defaultBsPopperConfig, + ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig) + }; + } + + _selectMenuItem({ + key, + target + }) { + const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(isVisible); + + if (!items.length) { + return; + } // if target isn't included in items (e.g. when expanding the dropdown) + // allow cycling to get the last item in case key equals ARROW_UP_KEY + + + getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus(); + } // Static + + + static jQueryInterface(config) { + return this.each(function () { + const data = Dropdown.getOrCreateInstance(this, config); + + if (typeof config !== 'string') { + return; + } + + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + + data[config](); + }); + } + + static clearMenus(event) { + if (event && (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1)) { + return; + } + + const toggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE$3); + + for (let i = 0, len = toggles.length; i < len; i++) { + const context = Dropdown.getInstance(toggles[i]); + + if (!context || context._config.autoClose === false) { + continue; + } + + if (!context._isShown()) { + continue; + } + + const relatedTarget = { + relatedTarget: context._element + }; + + if (event) { + const composedPath = event.composedPath(); + const isMenuTarget = composedPath.includes(context._menu); + + if (composedPath.includes(context._element) || context._config.autoClose === 'inside' && !isMenuTarget || context._config.autoClose === 'outside' && isMenuTarget) { + continue; + } // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu + + + if (context._menu.contains(event.target) && (event.type === 'keyup' && event.key === TAB_KEY$1 || /input|select|option|textarea|form/i.test(event.target.tagName))) { + continue; + } + + if (event.type === 'click') { + relatedTarget.clickEvent = event; + } + } + + context._completeHide(relatedTarget); + } + } + + static getParentFromElement(element) { + return getElementFromSelector(element) || element.parentNode; + } + + static dataApiKeydownHandler(event) { + // If not input/textarea: + // - And not a key in REGEXP_KEYDOWN => not a dropdown command + // If input/textarea: + // - If space key => not a dropdown command + // - If key is other than escape + // - If key is not up or down => not a dropdown command + // - If trigger inside the menu => not a dropdown command + if (/input|textarea/i.test(event.target.tagName) ? event.key === SPACE_KEY || event.key !== ESCAPE_KEY$2 && (event.key !== ARROW_DOWN_KEY && event.key !== ARROW_UP_KEY || event.target.closest(SELECTOR_MENU)) : !REGEXP_KEYDOWN.test(event.key)) { + return; + } + + const isActive = this.classList.contains(CLASS_NAME_SHOW$6); + + if (!isActive && event.key === ESCAPE_KEY$2) { + return; + } + + event.preventDefault(); + event.stopPropagation(); + + if (isDisabled(this)) { + return; + } + + const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE$3) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE$3)[0]; + const instance = Dropdown.getOrCreateInstance(getToggleButton); + + if (event.key === ESCAPE_KEY$2) { + instance.hide(); + return; + } + + if (event.key === ARROW_UP_KEY || event.key === ARROW_DOWN_KEY) { + if (!isActive) { + instance.show(); + } + + instance._selectMenuItem(event); + + return; + } + + if (!isActive || event.key === SPACE_KEY) { + Dropdown.clearMenus(); + } + } + + } + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$3, Dropdown.dataApiKeydownHandler); + EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler); + EventHandler.on(document, EVENT_CLICK_DATA_API$3, Dropdown.clearMenus); + EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus); + EventHandler.on(document, EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$3, function (event) { + event.preventDefault(); + Dropdown.getOrCreateInstance(this).toggle(); + }); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + * add .Dropdown to jQuery only if jQuery is present + */ + + defineJQueryPlugin(Dropdown); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): util/scrollBar.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'; + const SELECTOR_STICKY_CONTENT = '.sticky-top'; + + class ScrollBarHelper { + constructor() { + this._element = document.body; + } + + getWidth() { + // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes + const documentWidth = document.documentElement.clientWidth; + return Math.abs(window.innerWidth - documentWidth); + } + + hide() { + const width = this.getWidth(); + + this._disableOverFlow(); // give padding to element to balance the hidden scrollbar width + + + this._setElementAttributes(this._element, 'paddingRight', calculatedValue => calculatedValue + width); // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth + + + this._setElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight', calculatedValue => calculatedValue + width); + + this._setElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight', calculatedValue => calculatedValue - width); + } + + _disableOverFlow() { + this._saveInitialAttribute(this._element, 'overflow'); + + this._element.style.overflow = 'hidden'; + } + + _setElementAttributes(selector, styleProp, callback) { + const scrollbarWidth = this.getWidth(); + + const manipulationCallBack = element => { + if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) { + return; + } + + this._saveInitialAttribute(element, styleProp); + + const calculatedValue = window.getComputedStyle(element)[styleProp]; + element.style[styleProp] = `${callback(Number.parseFloat(calculatedValue))}px`; + }; + + this._applyManipulationCallback(selector, manipulationCallBack); + } + + reset() { + this._resetElementAttributes(this._element, 'overflow'); + + this._resetElementAttributes(this._element, 'paddingRight'); + + this._resetElementAttributes(SELECTOR_FIXED_CONTENT, 'paddingRight'); + + this._resetElementAttributes(SELECTOR_STICKY_CONTENT, 'marginRight'); + } + + _saveInitialAttribute(element, styleProp) { + const actualValue = element.style[styleProp]; + + if (actualValue) { + Manipulator.setDataAttribute(element, styleProp, actualValue); + } + } + + _resetElementAttributes(selector, styleProp) { + const manipulationCallBack = element => { + const value = Manipulator.getDataAttribute(element, styleProp); + + if (typeof value === 'undefined') { + element.style.removeProperty(styleProp); + } else { + Manipulator.removeDataAttribute(element, styleProp); + element.style[styleProp] = value; + } + }; + + this._applyManipulationCallback(selector, manipulationCallBack); + } + + _applyManipulationCallback(selector, callBack) { + if (isElement(selector)) { + callBack(selector); + } else { + SelectorEngine.find(selector, this._element).forEach(callBack); + } + } + + isOverflowing() { + return this.getWidth() > 0; + } + + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): util/backdrop.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + const Default$7 = { + className: 'modal-backdrop', + isVisible: true, + // if false, we use the backdrop helper without adding any element to the dom + isAnimated: false, + rootElement: 'body', + // give the choice to place backdrop under different elements + clickCallback: null + }; + const DefaultType$7 = { + className: 'string', + isVisible: 'boolean', + isAnimated: 'boolean', + rootElement: '(element|string)', + clickCallback: '(function|null)' + }; + const NAME$8 = 'backdrop'; + const CLASS_NAME_FADE$4 = 'fade'; + const CLASS_NAME_SHOW$5 = 'show'; + const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$8}`; + + class Backdrop { + constructor(config) { + this._config = this._getConfig(config); + this._isAppended = false; + this._element = null; + } + + show(callback) { + if (!this._config.isVisible) { + execute(callback); + return; + } + + this._append(); + + if (this._config.isAnimated) { + reflow(this._getElement()); + } + + this._getElement().classList.add(CLASS_NAME_SHOW$5); + + this._emulateAnimation(() => { + execute(callback); + }); + } + + hide(callback) { + if (!this._config.isVisible) { + execute(callback); + return; + } + + this._getElement().classList.remove(CLASS_NAME_SHOW$5); + + this._emulateAnimation(() => { + this.dispose(); + execute(callback); + }); + } // Private + + + _getElement() { + if (!this._element) { + const backdrop = document.createElement('div'); + backdrop.className = this._config.className; + + if (this._config.isAnimated) { + backdrop.classList.add(CLASS_NAME_FADE$4); + } + + this._element = backdrop; + } + + return this._element; + } + + _getConfig(config) { + config = { ...Default$7, + ...(typeof config === 'object' ? config : {}) + }; // use getElement() with the default "body" to get a fresh Element on each instantiation + + config.rootElement = getElement(config.rootElement); + typeCheckConfig(NAME$8, config, DefaultType$7); + return config; + } + + _append() { + if (this._isAppended) { + return; + } + + this._config.rootElement.append(this._getElement()); + + EventHandler.on(this._getElement(), EVENT_MOUSEDOWN, () => { + execute(this._config.clickCallback); + }); + this._isAppended = true; + } + + dispose() { + if (!this._isAppended) { + return; + } + + EventHandler.off(this._element, EVENT_MOUSEDOWN); + + this._element.remove(); + + this._isAppended = false; + } + + _emulateAnimation(callback) { + executeAfterTransition(callback, this._getElement(), this._config.isAnimated); + } + + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): util/focustrap.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + const Default$6 = { + trapElement: null, + // The element to trap focus inside of + autofocus: true + }; + const DefaultType$6 = { + trapElement: 'element', + autofocus: 'boolean' + }; + const NAME$7 = 'focustrap'; + const DATA_KEY$7 = 'bs.focustrap'; + const EVENT_KEY$7 = `.${DATA_KEY$7}`; + const EVENT_FOCUSIN$1 = `focusin${EVENT_KEY$7}`; + const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$7}`; + const TAB_KEY = 'Tab'; + const TAB_NAV_FORWARD = 'forward'; + const TAB_NAV_BACKWARD = 'backward'; + + class FocusTrap { + constructor(config) { + this._config = this._getConfig(config); + this._isActive = false; + this._lastTabNavDirection = null; + } + + activate() { + const { + trapElement, + autofocus + } = this._config; + + if (this._isActive) { + return; + } + + if (autofocus) { + trapElement.focus(); + } + + EventHandler.off(document, EVENT_KEY$7); // guard against infinite focus loop + + EventHandler.on(document, EVENT_FOCUSIN$1, event => this._handleFocusin(event)); + EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event)); + this._isActive = true; + } + + deactivate() { + if (!this._isActive) { + return; + } + + this._isActive = false; + EventHandler.off(document, EVENT_KEY$7); + } // Private + + + _handleFocusin(event) { + const { + target + } = event; + const { + trapElement + } = this._config; + + if (target === document || target === trapElement || trapElement.contains(target)) { + return; + } + + const elements = SelectorEngine.focusableChildren(trapElement); + + if (elements.length === 0) { + trapElement.focus(); + } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) { + elements[elements.length - 1].focus(); + } else { + elements[0].focus(); + } + } + + _handleKeydown(event) { + if (event.key !== TAB_KEY) { + return; + } + + this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD; + } + + _getConfig(config) { + config = { ...Default$6, + ...(typeof config === 'object' ? config : {}) + }; + typeCheckConfig(NAME$7, config, DefaultType$6); + return config; + } + + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): modal.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const NAME$6 = 'modal'; + const DATA_KEY$6 = 'bs.modal'; + const EVENT_KEY$6 = `.${DATA_KEY$6}`; + const DATA_API_KEY$3 = '.data-api'; + const ESCAPE_KEY$1 = 'Escape'; + const Default$5 = { + backdrop: true, + keyboard: true, + focus: true + }; + const DefaultType$5 = { + backdrop: '(boolean|string)', + keyboard: 'boolean', + focus: 'boolean' + }; + const EVENT_HIDE$3 = `hide${EVENT_KEY$6}`; + const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY$6}`; + const EVENT_HIDDEN$3 = `hidden${EVENT_KEY$6}`; + const EVENT_SHOW$3 = `show${EVENT_KEY$6}`; + const EVENT_SHOWN$3 = `shown${EVENT_KEY$6}`; + const EVENT_RESIZE = `resize${EVENT_KEY$6}`; + const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY$6}`; + const EVENT_KEYDOWN_DISMISS$1 = `keydown.dismiss${EVENT_KEY$6}`; + const EVENT_MOUSEUP_DISMISS = `mouseup.dismiss${EVENT_KEY$6}`; + const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY$6}`; + const EVENT_CLICK_DATA_API$2 = `click${EVENT_KEY$6}${DATA_API_KEY$3}`; + const CLASS_NAME_OPEN = 'modal-open'; + const CLASS_NAME_FADE$3 = 'fade'; + const CLASS_NAME_SHOW$4 = 'show'; + const CLASS_NAME_STATIC = 'modal-static'; + const OPEN_SELECTOR$1 = '.modal.show'; + const SELECTOR_DIALOG = '.modal-dialog'; + const SELECTOR_MODAL_BODY = '.modal-body'; + const SELECTOR_DATA_TOGGLE$2 = '[data-bs-toggle="modal"]'; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + class Modal extends BaseComponent { + constructor(element, config) { + super(element); + this._config = this._getConfig(config); + this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element); + this._backdrop = this._initializeBackDrop(); + this._focustrap = this._initializeFocusTrap(); + this._isShown = false; + this._ignoreBackdropClick = false; + this._isTransitioning = false; + this._scrollBar = new ScrollBarHelper(); + } // Getters + + + static get Default() { + return Default$5; + } + + static get NAME() { + return NAME$6; + } // Public + + + toggle(relatedTarget) { + return this._isShown ? this.hide() : this.show(relatedTarget); + } + + show(relatedTarget) { + if (this._isShown || this._isTransitioning) { + return; + } + + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$3, { + relatedTarget + }); + + if (showEvent.defaultPrevented) { + return; + } + + this._isShown = true; + + if (this._isAnimated()) { + this._isTransitioning = true; + } + + this._scrollBar.hide(); + + document.body.classList.add(CLASS_NAME_OPEN); + + this._adjustDialog(); + + this._setEscapeEvent(); + + this._setResizeEvent(); + + EventHandler.on(this._dialog, EVENT_MOUSEDOWN_DISMISS, () => { + EventHandler.one(this._element, EVENT_MOUSEUP_DISMISS, event => { + if (event.target === this._element) { + this._ignoreBackdropClick = true; + } + }); + }); + + this._showBackdrop(() => this._showElement(relatedTarget)); + } + + hide() { + if (!this._isShown || this._isTransitioning) { + return; + } + + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$3); + + if (hideEvent.defaultPrevented) { + return; + } + + this._isShown = false; + + const isAnimated = this._isAnimated(); + + if (isAnimated) { + this._isTransitioning = true; + } + + this._setEscapeEvent(); + + this._setResizeEvent(); + + this._focustrap.deactivate(); + + this._element.classList.remove(CLASS_NAME_SHOW$4); + + EventHandler.off(this._element, EVENT_CLICK_DISMISS); + EventHandler.off(this._dialog, EVENT_MOUSEDOWN_DISMISS); + + this._queueCallback(() => this._hideModal(), this._element, isAnimated); + } + + dispose() { + [window, this._dialog].forEach(htmlElement => EventHandler.off(htmlElement, EVENT_KEY$6)); + + this._backdrop.dispose(); + + this._focustrap.deactivate(); + + super.dispose(); + } + + handleUpdate() { + this._adjustDialog(); + } // Private + + + _initializeBackDrop() { + return new Backdrop({ + isVisible: Boolean(this._config.backdrop), + // 'static' option will be translated to true, and booleans will keep their value + isAnimated: this._isAnimated() + }); + } + + _initializeFocusTrap() { + return new FocusTrap({ + trapElement: this._element + }); + } + + _getConfig(config) { + config = { ...Default$5, + ...Manipulator.getDataAttributes(this._element), + ...(typeof config === 'object' ? config : {}) + }; + typeCheckConfig(NAME$6, config, DefaultType$5); + return config; + } + + _showElement(relatedTarget) { + const isAnimated = this._isAnimated(); + + const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog); + + if (!this._element.parentNode || this._element.parentNode.nodeType !== Node.ELEMENT_NODE) { + // Don't move modal's DOM position + document.body.append(this._element); + } + + this._element.style.display = 'block'; + + this._element.removeAttribute('aria-hidden'); + + this._element.setAttribute('aria-modal', true); + + this._element.setAttribute('role', 'dialog'); + + this._element.scrollTop = 0; + + if (modalBody) { + modalBody.scrollTop = 0; + } + + if (isAnimated) { + reflow(this._element); + } + + this._element.classList.add(CLASS_NAME_SHOW$4); + + const transitionComplete = () => { + if (this._config.focus) { + this._focustrap.activate(); + } + + this._isTransitioning = false; + EventHandler.trigger(this._element, EVENT_SHOWN$3, { + relatedTarget + }); + }; + + this._queueCallback(transitionComplete, this._dialog, isAnimated); + } + + _setEscapeEvent() { + if (this._isShown) { + EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS$1, event => { + if (this._config.keyboard && event.key === ESCAPE_KEY$1) { + event.preventDefault(); + this.hide(); + } else if (!this._config.keyboard && event.key === ESCAPE_KEY$1) { + this._triggerBackdropTransition(); + } + }); + } else { + EventHandler.off(this._element, EVENT_KEYDOWN_DISMISS$1); + } + } + + _setResizeEvent() { + if (this._isShown) { + EventHandler.on(window, EVENT_RESIZE, () => this._adjustDialog()); + } else { + EventHandler.off(window, EVENT_RESIZE); + } + } + + _hideModal() { + this._element.style.display = 'none'; + + this._element.setAttribute('aria-hidden', true); + + this._element.removeAttribute('aria-modal'); + + this._element.removeAttribute('role'); + + this._isTransitioning = false; + + this._backdrop.hide(() => { + document.body.classList.remove(CLASS_NAME_OPEN); + + this._resetAdjustments(); + + this._scrollBar.reset(); + + EventHandler.trigger(this._element, EVENT_HIDDEN$3); + }); + } + + _showBackdrop(callback) { + EventHandler.on(this._element, EVENT_CLICK_DISMISS, event => { + if (this._ignoreBackdropClick) { + this._ignoreBackdropClick = false; + return; + } + + if (event.target !== event.currentTarget) { + return; + } + + if (this._config.backdrop === true) { + this.hide(); + } else if (this._config.backdrop === 'static') { + this._triggerBackdropTransition(); + } + }); + + this._backdrop.show(callback); + } + + _isAnimated() { + return this._element.classList.contains(CLASS_NAME_FADE$3); + } + + _triggerBackdropTransition() { + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED); + + if (hideEvent.defaultPrevented) { + return; + } + + const { + classList, + scrollHeight, + style + } = this._element; + const isModalOverflowing = scrollHeight > document.documentElement.clientHeight; // return if the following background transition hasn't yet completed + + if (!isModalOverflowing && style.overflowY === 'hidden' || classList.contains(CLASS_NAME_STATIC)) { + return; + } + + if (!isModalOverflowing) { + style.overflowY = 'hidden'; + } + + classList.add(CLASS_NAME_STATIC); + + this._queueCallback(() => { + classList.remove(CLASS_NAME_STATIC); + + if (!isModalOverflowing) { + this._queueCallback(() => { + style.overflowY = ''; + }, this._dialog); + } + }, this._dialog); + + this._element.focus(); + } // ---------------------------------------------------------------------- + // the following methods are used to handle overflowing modals + // ---------------------------------------------------------------------- + + + _adjustDialog() { + const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; + + const scrollbarWidth = this._scrollBar.getWidth(); + + const isBodyOverflowing = scrollbarWidth > 0; + + if (!isBodyOverflowing && isModalOverflowing && !isRTL() || isBodyOverflowing && !isModalOverflowing && isRTL()) { + this._element.style.paddingLeft = `${scrollbarWidth}px`; + } + + if (isBodyOverflowing && !isModalOverflowing && !isRTL() || !isBodyOverflowing && isModalOverflowing && isRTL()) { + this._element.style.paddingRight = `${scrollbarWidth}px`; + } + } + + _resetAdjustments() { + this._element.style.paddingLeft = ''; + this._element.style.paddingRight = ''; + } // Static + + + static jQueryInterface(config, relatedTarget) { + return this.each(function () { + const data = Modal.getOrCreateInstance(this, config); + + if (typeof config !== 'string') { + return; + } + + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + + data[config](relatedTarget); + }); + } + + } + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + EventHandler.on(document, EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$2, function (event) { + const target = getElementFromSelector(this); + + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + + EventHandler.one(target, EVENT_SHOW$3, showEvent => { + if (showEvent.defaultPrevented) { + // only register focus restorer if modal will actually get shown + return; + } + + EventHandler.one(target, EVENT_HIDDEN$3, () => { + if (isVisible(this)) { + this.focus(); + } + }); + }); // avoid conflict when clicking moddal toggler while another one is open + + const allReadyOpen = SelectorEngine.findOne(OPEN_SELECTOR$1); + + if (allReadyOpen) { + Modal.getInstance(allReadyOpen).hide(); + } + + const data = Modal.getOrCreateInstance(target); + data.toggle(this); + }); + enableDismissTrigger(Modal); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + * add .Modal to jQuery only if jQuery is present + */ + + defineJQueryPlugin(Modal); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): offcanvas.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const NAME$5 = 'offcanvas'; + const DATA_KEY$5 = 'bs.offcanvas'; + const EVENT_KEY$5 = `.${DATA_KEY$5}`; + const DATA_API_KEY$2 = '.data-api'; + const EVENT_LOAD_DATA_API$1 = `load${EVENT_KEY$5}${DATA_API_KEY$2}`; + const ESCAPE_KEY = 'Escape'; + const Default$4 = { + backdrop: true, + keyboard: true, + scroll: false + }; + const DefaultType$4 = { + backdrop: 'boolean', + keyboard: 'boolean', + scroll: 'boolean' + }; + const CLASS_NAME_SHOW$3 = 'show'; + const CLASS_NAME_BACKDROP = 'offcanvas-backdrop'; + const OPEN_SELECTOR = '.offcanvas.show'; + const EVENT_SHOW$2 = `show${EVENT_KEY$5}`; + const EVENT_SHOWN$2 = `shown${EVENT_KEY$5}`; + const EVENT_HIDE$2 = `hide${EVENT_KEY$5}`; + const EVENT_HIDDEN$2 = `hidden${EVENT_KEY$5}`; + const EVENT_CLICK_DATA_API$1 = `click${EVENT_KEY$5}${DATA_API_KEY$2}`; + const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY$5}`; + const SELECTOR_DATA_TOGGLE$1 = '[data-bs-toggle="offcanvas"]'; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + class Offcanvas extends BaseComponent { + constructor(element, config) { + super(element); + this._config = this._getConfig(config); + this._isShown = false; + this._backdrop = this._initializeBackDrop(); + this._focustrap = this._initializeFocusTrap(); + + this._addEventListeners(); + } // Getters + + + static get NAME() { + return NAME$5; + } + + static get Default() { + return Default$4; + } // Public + + + toggle(relatedTarget) { + return this._isShown ? this.hide() : this.show(relatedTarget); + } + + show(relatedTarget) { + if (this._isShown) { + return; + } + + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$2, { + relatedTarget + }); + + if (showEvent.defaultPrevented) { + return; + } + + this._isShown = true; + this._element.style.visibility = 'visible'; + + this._backdrop.show(); + + if (!this._config.scroll) { + new ScrollBarHelper().hide(); + } + + this._element.removeAttribute('aria-hidden'); + + this._element.setAttribute('aria-modal', true); + + this._element.setAttribute('role', 'dialog'); + + this._element.classList.add(CLASS_NAME_SHOW$3); + + const completeCallBack = () => { + if (!this._config.scroll) { + this._focustrap.activate(); + } + + EventHandler.trigger(this._element, EVENT_SHOWN$2, { + relatedTarget + }); + }; + + this._queueCallback(completeCallBack, this._element, true); + } + + hide() { + if (!this._isShown) { + return; + } + + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$2); + + if (hideEvent.defaultPrevented) { + return; + } + + this._focustrap.deactivate(); + + this._element.blur(); + + this._isShown = false; + + this._element.classList.remove(CLASS_NAME_SHOW$3); + + this._backdrop.hide(); + + const completeCallback = () => { + this._element.setAttribute('aria-hidden', true); + + this._element.removeAttribute('aria-modal'); + + this._element.removeAttribute('role'); + + this._element.style.visibility = 'hidden'; + + if (!this._config.scroll) { + new ScrollBarHelper().reset(); + } + + EventHandler.trigger(this._element, EVENT_HIDDEN$2); + }; + + this._queueCallback(completeCallback, this._element, true); + } + + dispose() { + this._backdrop.dispose(); + + this._focustrap.deactivate(); + + super.dispose(); + } // Private + + + _getConfig(config) { + config = { ...Default$4, + ...Manipulator.getDataAttributes(this._element), + ...(typeof config === 'object' ? config : {}) + }; + typeCheckConfig(NAME$5, config, DefaultType$4); + return config; + } + + _initializeBackDrop() { + return new Backdrop({ + className: CLASS_NAME_BACKDROP, + isVisible: this._config.backdrop, + isAnimated: true, + rootElement: this._element.parentNode, + clickCallback: () => this.hide() + }); + } + + _initializeFocusTrap() { + return new FocusTrap({ + trapElement: this._element + }); + } + + _addEventListeners() { + EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => { + if (this._config.keyboard && event.key === ESCAPE_KEY) { + this.hide(); + } + }); + } // Static + + + static jQueryInterface(config) { + return this.each(function () { + const data = Offcanvas.getOrCreateInstance(this, config); + + if (typeof config !== 'string') { + return; + } + + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + + data[config](this); + }); + } + + } + /** + * ------------------------------------------------------------------------ + * Data Api implementation + * ------------------------------------------------------------------------ + */ + + + EventHandler.on(document, EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE$1, function (event) { + const target = getElementFromSelector(this); + + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + + if (isDisabled(this)) { + return; + } + + EventHandler.one(target, EVENT_HIDDEN$2, () => { + // focus on trigger when it is closed + if (isVisible(this)) { + this.focus(); + } + }); // avoid conflict when clicking a toggler of an offcanvas, while another is open + + const allReadyOpen = SelectorEngine.findOne(OPEN_SELECTOR); + + if (allReadyOpen && allReadyOpen !== target) { + Offcanvas.getInstance(allReadyOpen).hide(); + } + + const data = Offcanvas.getOrCreateInstance(target); + data.toggle(this); + }); + EventHandler.on(window, EVENT_LOAD_DATA_API$1, () => SelectorEngine.find(OPEN_SELECTOR).forEach(el => Offcanvas.getOrCreateInstance(el).show())); + enableDismissTrigger(Offcanvas); + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + */ + + defineJQueryPlugin(Offcanvas); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): util/sanitizer.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']); + const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i; + /** + * A pattern that recognizes a commonly useful subset of URLs that are safe. + * + * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts + */ + + const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i; + /** + * A pattern that matches safe data URLs. Only matches image, video and audio types. + * + * Shoutout to Angular https://github.com/angular/angular/blob/12.2.x/packages/core/src/sanitization/url_sanitizer.ts + */ + + const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i; + + const allowedAttribute = (attribute, allowedAttributeList) => { + const attributeName = attribute.nodeName.toLowerCase(); + + if (allowedAttributeList.includes(attributeName)) { + if (uriAttributes.has(attributeName)) { + return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue) || DATA_URL_PATTERN.test(attribute.nodeValue)); + } + + return true; + } + + const regExp = allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp); // Check if a regular expression validates the attribute. + + for (let i = 0, len = regExp.length; i < len; i++) { + if (regExp[i].test(attributeName)) { + return true; + } + } + + return false; + }; + + const DefaultAllowlist = { + // Global attributes allowed on any supplied element below. + '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN], + a: ['target', 'href', 'title', 'rel'], + area: [], + b: [], + br: [], + col: [], + code: [], + div: [], + em: [], + hr: [], + h1: [], + h2: [], + h3: [], + h4: [], + h5: [], + h6: [], + i: [], + img: ['src', 'srcset', 'alt', 'title', 'width', 'height'], + li: [], + ol: [], + p: [], + pre: [], + s: [], + small: [], + span: [], + sub: [], + sup: [], + strong: [], + u: [], + ul: [] + }; + function sanitizeHtml(unsafeHtml, allowList, sanitizeFn) { + if (!unsafeHtml.length) { + return unsafeHtml; + } + + if (sanitizeFn && typeof sanitizeFn === 'function') { + return sanitizeFn(unsafeHtml); + } + + const domParser = new window.DOMParser(); + const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html'); + const elements = [].concat(...createdDocument.body.querySelectorAll('*')); + + for (let i = 0, len = elements.length; i < len; i++) { + const element = elements[i]; + const elementName = element.nodeName.toLowerCase(); + + if (!Object.keys(allowList).includes(elementName)) { + element.remove(); + continue; + } + + const attributeList = [].concat(...element.attributes); + const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []); + attributeList.forEach(attribute => { + if (!allowedAttribute(attribute, allowedAttributes)) { + element.removeAttribute(attribute.nodeName); + } + }); + } + + return createdDocument.body.innerHTML; + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): tooltip.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const NAME$4 = 'tooltip'; + const DATA_KEY$4 = 'bs.tooltip'; + const EVENT_KEY$4 = `.${DATA_KEY$4}`; + const CLASS_PREFIX$1 = 'bs-tooltip'; + const DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']); + const DefaultType$3 = { + animation: 'boolean', + template: 'string', + title: '(string|element|function)', + trigger: 'string', + delay: '(number|object)', + html: 'boolean', + selector: '(string|boolean)', + placement: '(string|function)', + offset: '(array|string|function)', + container: '(string|element|boolean)', + fallbackPlacements: 'array', + boundary: '(string|element)', + customClass: '(string|function)', + sanitize: 'boolean', + sanitizeFn: '(null|function)', + allowList: 'object', + popperConfig: '(null|object|function)' + }; + const AttachmentMap = { + AUTO: 'auto', + TOP: 'top', + RIGHT: isRTL() ? 'left' : 'right', + BOTTOM: 'bottom', + LEFT: isRTL() ? 'right' : 'left' + }; + const Default$3 = { + animation: true, + template: '', + trigger: 'hover focus', + title: '', + delay: 0, + html: false, + selector: false, + placement: 'top', + offset: [0, 0], + container: false, + fallbackPlacements: ['top', 'right', 'bottom', 'left'], + boundary: 'clippingParents', + customClass: '', + sanitize: true, + sanitizeFn: null, + allowList: DefaultAllowlist, + popperConfig: null + }; + const Event$2 = { + HIDE: `hide${EVENT_KEY$4}`, + HIDDEN: `hidden${EVENT_KEY$4}`, + SHOW: `show${EVENT_KEY$4}`, + SHOWN: `shown${EVENT_KEY$4}`, + INSERTED: `inserted${EVENT_KEY$4}`, + CLICK: `click${EVENT_KEY$4}`, + FOCUSIN: `focusin${EVENT_KEY$4}`, + FOCUSOUT: `focusout${EVENT_KEY$4}`, + MOUSEENTER: `mouseenter${EVENT_KEY$4}`, + MOUSELEAVE: `mouseleave${EVENT_KEY$4}` + }; + const CLASS_NAME_FADE$2 = 'fade'; + const CLASS_NAME_MODAL = 'modal'; + const CLASS_NAME_SHOW$2 = 'show'; + const HOVER_STATE_SHOW = 'show'; + const HOVER_STATE_OUT = 'out'; + const SELECTOR_TOOLTIP_INNER = '.tooltip-inner'; + const SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`; + const EVENT_MODAL_HIDE = 'hide.bs.modal'; + const TRIGGER_HOVER = 'hover'; + const TRIGGER_FOCUS = 'focus'; + const TRIGGER_CLICK = 'click'; + const TRIGGER_MANUAL = 'manual'; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + class Tooltip extends BaseComponent { + constructor(element, config) { + if (typeof Popper__namespace === 'undefined') { + throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org)'); + } + + super(element); // private + + this._isEnabled = true; + this._timeout = 0; + this._hoverState = ''; + this._activeTrigger = {}; + this._popper = null; // Protected + + this._config = this._getConfig(config); + this.tip = null; + + this._setListeners(); + } // Getters + + + static get Default() { + return Default$3; + } + + static get NAME() { + return NAME$4; + } + + static get Event() { + return Event$2; + } + + static get DefaultType() { + return DefaultType$3; + } // Public + + + enable() { + this._isEnabled = true; + } + + disable() { + this._isEnabled = false; + } + + toggleEnabled() { + this._isEnabled = !this._isEnabled; + } + + toggle(event) { + if (!this._isEnabled) { + return; + } + + if (event) { + const context = this._initializeOnDelegatedTarget(event); + + context._activeTrigger.click = !context._activeTrigger.click; + + if (context._isWithActiveTrigger()) { + context._enter(null, context); + } else { + context._leave(null, context); + } + } else { + if (this.getTipElement().classList.contains(CLASS_NAME_SHOW$2)) { + this._leave(null, this); + + return; + } + + this._enter(null, this); + } + } + + dispose() { + clearTimeout(this._timeout); + EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); + + if (this.tip) { + this.tip.remove(); + } + + this._disposePopper(); + + super.dispose(); + } + + show() { + if (this._element.style.display === 'none') { + throw new Error('Please use show on visible elements'); + } + + if (!(this.isWithContent() && this._isEnabled)) { + return; + } + + const showEvent = EventHandler.trigger(this._element, this.constructor.Event.SHOW); + const shadowRoot = findShadowRoot(this._element); + const isInTheDom = shadowRoot === null ? this._element.ownerDocument.documentElement.contains(this._element) : shadowRoot.contains(this._element); + + if (showEvent.defaultPrevented || !isInTheDom) { + return; + } // A trick to recreate a tooltip in case a new title is given by using the NOT documented `data-bs-original-title` + // This will be removed later in favor of a `setContent` method + + + if (this.constructor.NAME === 'tooltip' && this.tip && this.getTitle() !== this.tip.querySelector(SELECTOR_TOOLTIP_INNER).innerHTML) { + this._disposePopper(); + + this.tip.remove(); + this.tip = null; + } + + const tip = this.getTipElement(); + const tipId = getUID(this.constructor.NAME); + tip.setAttribute('id', tipId); + + this._element.setAttribute('aria-describedby', tipId); + + if (this._config.animation) { + tip.classList.add(CLASS_NAME_FADE$2); + } + + const placement = typeof this._config.placement === 'function' ? this._config.placement.call(this, tip, this._element) : this._config.placement; + + const attachment = this._getAttachment(placement); + + this._addAttachmentClass(attachment); + + const { + container + } = this._config; + Data.set(tip, this.constructor.DATA_KEY, this); + + if (!this._element.ownerDocument.documentElement.contains(this.tip)) { + container.append(tip); + EventHandler.trigger(this._element, this.constructor.Event.INSERTED); + } + + if (this._popper) { + this._popper.update(); + } else { + this._popper = Popper__namespace.createPopper(this._element, tip, this._getPopperConfig(attachment)); + } + + tip.classList.add(CLASS_NAME_SHOW$2); + + const customClass = this._resolvePossibleFunction(this._config.customClass); + + if (customClass) { + tip.classList.add(...customClass.split(' ')); + } // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + + + if ('ontouchstart' in document.documentElement) { + [].concat(...document.body.children).forEach(element => { + EventHandler.on(element, 'mouseover', noop); + }); + } + + const complete = () => { + const prevHoverState = this._hoverState; + this._hoverState = null; + EventHandler.trigger(this._element, this.constructor.Event.SHOWN); + + if (prevHoverState === HOVER_STATE_OUT) { + this._leave(null, this); + } + }; + + const isAnimated = this.tip.classList.contains(CLASS_NAME_FADE$2); + + this._queueCallback(complete, this.tip, isAnimated); + } + + hide() { + if (!this._popper) { + return; + } + + const tip = this.getTipElement(); + + const complete = () => { + if (this._isWithActiveTrigger()) { + return; + } + + if (this._hoverState !== HOVER_STATE_SHOW) { + tip.remove(); + } + + this._cleanTipClass(); + + this._element.removeAttribute('aria-describedby'); + + EventHandler.trigger(this._element, this.constructor.Event.HIDDEN); + + this._disposePopper(); + }; + + const hideEvent = EventHandler.trigger(this._element, this.constructor.Event.HIDE); + + if (hideEvent.defaultPrevented) { + return; + } + + tip.classList.remove(CLASS_NAME_SHOW$2); // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + + if ('ontouchstart' in document.documentElement) { + [].concat(...document.body.children).forEach(element => EventHandler.off(element, 'mouseover', noop)); + } + + this._activeTrigger[TRIGGER_CLICK] = false; + this._activeTrigger[TRIGGER_FOCUS] = false; + this._activeTrigger[TRIGGER_HOVER] = false; + const isAnimated = this.tip.classList.contains(CLASS_NAME_FADE$2); + + this._queueCallback(complete, this.tip, isAnimated); + + this._hoverState = ''; + } + + update() { + if (this._popper !== null) { + this._popper.update(); + } + } // Protected + + + isWithContent() { + return Boolean(this.getTitle()); + } + + getTipElement() { + if (this.tip) { + return this.tip; + } + + const element = document.createElement('div'); + element.innerHTML = this._config.template; + const tip = element.children[0]; + this.setContent(tip); + tip.classList.remove(CLASS_NAME_FADE$2, CLASS_NAME_SHOW$2); + this.tip = tip; + return this.tip; + } + + setContent(tip) { + this._sanitizeAndSetContent(tip, this.getTitle(), SELECTOR_TOOLTIP_INNER); + } + + _sanitizeAndSetContent(template, content, selector) { + const templateElement = SelectorEngine.findOne(selector, template); + + if (!content && templateElement) { + templateElement.remove(); + return; + } // we use append for html objects to maintain js events + + + this.setElementContent(templateElement, content); + } + + setElementContent(element, content) { + if (element === null) { + return; + } + + if (isElement(content)) { + content = getElement(content); // content is a DOM node or a jQuery + + if (this._config.html) { + if (content.parentNode !== element) { + element.innerHTML = ''; + element.append(content); + } + } else { + element.textContent = content.textContent; + } + + return; + } + + if (this._config.html) { + if (this._config.sanitize) { + content = sanitizeHtml(content, this._config.allowList, this._config.sanitizeFn); + } + + element.innerHTML = content; + } else { + element.textContent = content; + } + } + + getTitle() { + const title = this._element.getAttribute('data-bs-original-title') || this._config.title; + + return this._resolvePossibleFunction(title); + } + + updateAttachment(attachment) { + if (attachment === 'right') { + return 'end'; + } + + if (attachment === 'left') { + return 'start'; + } + + return attachment; + } // Private + + + _initializeOnDelegatedTarget(event, context) { + return context || this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig()); + } + + _getOffset() { + const { + offset + } = this._config; + + if (typeof offset === 'string') { + return offset.split(',').map(val => Number.parseInt(val, 10)); + } + + if (typeof offset === 'function') { + return popperData => offset(popperData, this._element); + } + + return offset; + } + + _resolvePossibleFunction(content) { + return typeof content === 'function' ? content.call(this._element) : content; + } + + _getPopperConfig(attachment) { + const defaultBsPopperConfig = { + placement: attachment, + modifiers: [{ + name: 'flip', + options: { + fallbackPlacements: this._config.fallbackPlacements + } + }, { + name: 'offset', + options: { + offset: this._getOffset() + } + }, { + name: 'preventOverflow', + options: { + boundary: this._config.boundary + } + }, { + name: 'arrow', + options: { + element: `.${this.constructor.NAME}-arrow` + } + }, { + name: 'onChange', + enabled: true, + phase: 'afterWrite', + fn: data => this._handlePopperPlacementChange(data) + }], + onFirstUpdate: data => { + if (data.options.placement !== data.placement) { + this._handlePopperPlacementChange(data); + } + } + }; + return { ...defaultBsPopperConfig, + ...(typeof this._config.popperConfig === 'function' ? this._config.popperConfig(defaultBsPopperConfig) : this._config.popperConfig) + }; + } + + _addAttachmentClass(attachment) { + this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(attachment)}`); + } + + _getAttachment(placement) { + return AttachmentMap[placement.toUpperCase()]; + } + + _setListeners() { + const triggers = this._config.trigger.split(' '); + + triggers.forEach(trigger => { + if (trigger === 'click') { + EventHandler.on(this._element, this.constructor.Event.CLICK, this._config.selector, event => this.toggle(event)); + } else if (trigger !== TRIGGER_MANUAL) { + const eventIn = trigger === TRIGGER_HOVER ? this.constructor.Event.MOUSEENTER : this.constructor.Event.FOCUSIN; + const eventOut = trigger === TRIGGER_HOVER ? this.constructor.Event.MOUSELEAVE : this.constructor.Event.FOCUSOUT; + EventHandler.on(this._element, eventIn, this._config.selector, event => this._enter(event)); + EventHandler.on(this._element, eventOut, this._config.selector, event => this._leave(event)); + } + }); + + this._hideModalHandler = () => { + if (this._element) { + this.hide(); + } + }; + + EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); + + if (this._config.selector) { + this._config = { ...this._config, + trigger: 'manual', + selector: '' + }; + } else { + this._fixTitle(); + } + } + + _fixTitle() { + const title = this._element.getAttribute('title'); + + const originalTitleType = typeof this._element.getAttribute('data-bs-original-title'); + + if (title || originalTitleType !== 'string') { + this._element.setAttribute('data-bs-original-title', title || ''); + + if (title && !this._element.getAttribute('aria-label') && !this._element.textContent) { + this._element.setAttribute('aria-label', title); + } + + this._element.setAttribute('title', ''); + } + } + + _enter(event, context) { + context = this._initializeOnDelegatedTarget(event, context); + + if (event) { + context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true; + } + + if (context.getTipElement().classList.contains(CLASS_NAME_SHOW$2) || context._hoverState === HOVER_STATE_SHOW) { + context._hoverState = HOVER_STATE_SHOW; + return; + } + + clearTimeout(context._timeout); + context._hoverState = HOVER_STATE_SHOW; + + if (!context._config.delay || !context._config.delay.show) { + context.show(); + return; + } + + context._timeout = setTimeout(() => { + if (context._hoverState === HOVER_STATE_SHOW) { + context.show(); + } + }, context._config.delay.show); + } + + _leave(event, context) { + context = this._initializeOnDelegatedTarget(event, context); + + if (event) { + context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget); + } + + if (context._isWithActiveTrigger()) { + return; + } + + clearTimeout(context._timeout); + context._hoverState = HOVER_STATE_OUT; + + if (!context._config.delay || !context._config.delay.hide) { + context.hide(); + return; + } + + context._timeout = setTimeout(() => { + if (context._hoverState === HOVER_STATE_OUT) { + context.hide(); + } + }, context._config.delay.hide); + } + + _isWithActiveTrigger() { + for (const trigger in this._activeTrigger) { + if (this._activeTrigger[trigger]) { + return true; + } + } + + return false; + } + + _getConfig(config) { + const dataAttributes = Manipulator.getDataAttributes(this._element); + Object.keys(dataAttributes).forEach(dataAttr => { + if (DISALLOWED_ATTRIBUTES.has(dataAttr)) { + delete dataAttributes[dataAttr]; + } + }); + config = { ...this.constructor.Default, + ...dataAttributes, + ...(typeof config === 'object' && config ? config : {}) + }; + config.container = config.container === false ? document.body : getElement(config.container); + + if (typeof config.delay === 'number') { + config.delay = { + show: config.delay, + hide: config.delay + }; + } + + if (typeof config.title === 'number') { + config.title = config.title.toString(); + } + + if (typeof config.content === 'number') { + config.content = config.content.toString(); + } + + typeCheckConfig(NAME$4, config, this.constructor.DefaultType); + + if (config.sanitize) { + config.template = sanitizeHtml(config.template, config.allowList, config.sanitizeFn); + } + + return config; + } + + _getDelegateConfig() { + const config = {}; + + for (const key in this._config) { + if (this.constructor.Default[key] !== this._config[key]) { + config[key] = this._config[key]; + } + } // In the future can be replaced with: + // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]]) + // `Object.fromEntries(keysWithDifferentValues)` + + + return config; + } + + _cleanTipClass() { + const tip = this.getTipElement(); + const basicClassPrefixRegex = new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`, 'g'); + const tabClass = tip.getAttribute('class').match(basicClassPrefixRegex); + + if (tabClass !== null && tabClass.length > 0) { + tabClass.map(token => token.trim()).forEach(tClass => tip.classList.remove(tClass)); + } + } + + _getBasicClassPrefix() { + return CLASS_PREFIX$1; + } + + _handlePopperPlacementChange(popperData) { + const { + state + } = popperData; + + if (!state) { + return; + } + + this.tip = state.elements.popper; + + this._cleanTipClass(); + + this._addAttachmentClass(this._getAttachment(state.placement)); + } + + _disposePopper() { + if (this._popper) { + this._popper.destroy(); + + this._popper = null; + } + } // Static + + + static jQueryInterface(config) { + return this.each(function () { + const data = Tooltip.getOrCreateInstance(this, config); + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + + data[config](); + } + }); + } + + } + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + * add .Tooltip to jQuery only if jQuery is present + */ + + + defineJQueryPlugin(Tooltip); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): popover.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const NAME$3 = 'popover'; + const DATA_KEY$3 = 'bs.popover'; + const EVENT_KEY$3 = `.${DATA_KEY$3}`; + const CLASS_PREFIX = 'bs-popover'; + const Default$2 = { ...Tooltip.Default, + placement: 'right', + offset: [0, 8], + trigger: 'click', + content: '', + template: '' + }; + const DefaultType$2 = { ...Tooltip.DefaultType, + content: '(string|element|function)' + }; + const Event$1 = { + HIDE: `hide${EVENT_KEY$3}`, + HIDDEN: `hidden${EVENT_KEY$3}`, + SHOW: `show${EVENT_KEY$3}`, + SHOWN: `shown${EVENT_KEY$3}`, + INSERTED: `inserted${EVENT_KEY$3}`, + CLICK: `click${EVENT_KEY$3}`, + FOCUSIN: `focusin${EVENT_KEY$3}`, + FOCUSOUT: `focusout${EVENT_KEY$3}`, + MOUSEENTER: `mouseenter${EVENT_KEY$3}`, + MOUSELEAVE: `mouseleave${EVENT_KEY$3}` + }; + const SELECTOR_TITLE = '.popover-header'; + const SELECTOR_CONTENT = '.popover-body'; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + class Popover extends Tooltip { + // Getters + static get Default() { + return Default$2; + } + + static get NAME() { + return NAME$3; + } + + static get Event() { + return Event$1; + } + + static get DefaultType() { + return DefaultType$2; + } // Overrides + + + isWithContent() { + return this.getTitle() || this._getContent(); + } + + setContent(tip) { + this._sanitizeAndSetContent(tip, this.getTitle(), SELECTOR_TITLE); + + this._sanitizeAndSetContent(tip, this._getContent(), SELECTOR_CONTENT); + } // Private + + + _getContent() { + return this._resolvePossibleFunction(this._config.content); + } + + _getBasicClassPrefix() { + return CLASS_PREFIX; + } // Static + + + static jQueryInterface(config) { + return this.each(function () { + const data = Popover.getOrCreateInstance(this, config); + + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + + data[config](); + } + }); + } + + } + /** + * ------------------------------------------------------------------------ + * jQuery + * ------------------------------------------------------------------------ + * add .Popover to jQuery only if jQuery is present + */ + + + defineJQueryPlugin(Popover); + + /** + * -------------------------------------------------------------------------- + * Bootstrap (v5.1.3): scrollspy.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + /** + * ------------------------------------------------------------------------ + * Constants + * ------------------------------------------------------------------------ + */ + + const NAME$2 = 'scrollspy'; + const DATA_KEY$2 = 'bs.scrollspy'; + const EVENT_KEY$2 = `.${DATA_KEY$2}`; + const DATA_API_KEY$1 = '.data-api'; + const Default$1 = { + offset: 10, + method: 'auto', + target: '' + }; + const DefaultType$1 = { + offset: 'number', + method: 'string', + target: '(string|element)' + }; + const EVENT_ACTIVATE = `activate${EVENT_KEY$2}`; + const EVENT_SCROLL = `scroll${EVENT_KEY$2}`; + const EVENT_LOAD_DATA_API = `load${EVENT_KEY$2}${DATA_API_KEY$1}`; + const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'; + const CLASS_NAME_ACTIVE$1 = 'active'; + const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]'; + const SELECTOR_NAV_LIST_GROUP$1 = '.nav, .list-group'; + const SELECTOR_NAV_LINKS = '.nav-link'; + const SELECTOR_NAV_ITEMS = '.nav-item'; + const SELECTOR_LIST_ITEMS = '.list-group-item'; + const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}, .${CLASS_NAME_DROPDOWN_ITEM}`; + const SELECTOR_DROPDOWN$1 = '.dropdown'; + const SELECTOR_DROPDOWN_TOGGLE$1 = '.dropdown-toggle'; + const METHOD_OFFSET = 'offset'; + const METHOD_POSITION = 'position'; + /** + * ------------------------------------------------------------------------ + * Class Definition + * ------------------------------------------------------------------------ + */ + + class ScrollSpy extends BaseComponent { + constructor(element, config) { + super(element); + this._scrollElement = this._element.tagName === 'BODY' ? window : this._element; + this._config = this._getConfig(config); + this._offsets = []; + this._targets = []; + this._activeTarget = null; + this._scrollHeight = 0; + EventHandler.on(this._scrollElement, EVENT_SCROLL, () => this._process()); + this.refresh(); + + this._process(); + } // Getters + + + static get Default() { + return Default$1; + } + + static get NAME() { + return NAME$2; + } // Public + + + refresh() { + const autoMethod = this._scrollElement === this._scrollElement.window ? METHOD_OFFSET : METHOD_POSITION; + const offsetMethod = this._config.method === 'auto' ? autoMethod : this._config.method; + const offsetBase = offsetMethod === METHOD_POSITION ? this._getScrollTop() : 0; + this._offsets = []; + this._targets = []; + this._scrollHeight = this._getScrollHeight(); + const targets = SelectorEngine.find(SELECTOR_LINK_ITEMS, this._config.target); + targets.map(element => { + const targetSelector = getSelectorFromElement(element); + const target = targetSelector ? SelectorEngine.findOne(targetSelector) : null; + + if (target) { + const targetBCR = target.getBoundingClientRect(); + + if (targetBCR.width || targetBCR.height) { + return [Manipulator[offsetMethod](target).top + offsetBase, targetSelector]; + } + } + + return null; + }).filter(item => item).sort((a, b) => a[0] - b[0]).forEach(item => { + this._offsets.push(item[0]); + + this._targets.push(item[1]); + }); + } + + dispose() { + EventHandler.off(this._scrollElement, EVENT_KEY$2); + super.dispose(); + } // Private + + + _getConfig(config) { + config = { ...Default$1, + ...Manipulator.getDataAttributes(this._element), + ...(typeof config === 'object' && config ? config : {}) + }; + config.target = getElement(config.target) || document.documentElement; + typeCheckConfig(NAME$2, config, DefaultType$1); + return config; + } + + _getScrollTop() { + return this._scrollElement === window ? this._scrollElement.pageYOffset : this._scrollElement.scrollTop; + } + + _getScrollHeight() { + return this._scrollElement.scrollHeight || Math.max(document.body.scrollHeight, document.documentElement.scrollHeight); + } + + _getOffsetHeight() { + return this._scrollElement === window ? window.innerHeight : this._scrollElement.getBoundingClientRect().height; + } + + _process() { + const scrollTop = this._getScrollTop() + this._config.offset; + + const scrollHeight = this._getScrollHeight(); + + const maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight(); + + if (this._scrollHeight !== scrollHeight) { + this.refresh(); + } + + if (scrollTop >= maxScroll) { + const target = this._targets[this._targets.length - 1]; + + if (this._activeTarget !== target) { + this._activate(target); + } + + return; + } + + if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) { + this._activeTarget = null; + + this._clear(); + + return; + } + + for (let i = this._offsets.length; i--;) { + const isActiveTarget = this._activeTarget !== this._targets[i] && scrollTop >= this._offsets[i] && (typeof this._offsets[i + 1] === 'undefined' || scrollTop < this._offsets[i + 1]); + + if (isActiveTarget) { + this._activate(this._targets[i]); + } + } + } + + _activate(target) { + this._activeTarget = target; + + this._clear(); + + const queries = SELECTOR_LINK_ITEMS.split(',').map(selector => `${selector}[data-bs-target="${target}"],${selector}[href="${target}"]`); + const link = SelectorEngine.findOne(queries.join(','), this._config.target); + link.classList.add(CLASS_NAME_ACTIVE$1); + + if (link.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) { + SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE$1, link.closest(SELECTOR_DROPDOWN$1)).classList.add(CLASS_NAME_ACTIVE$1); + } else { + SelectorEngine.parents(link, SELECTOR_NAV_LIST_GROUP$1).forEach(listGroup => { + // Set triggered links parents as active + // With both