second commit
@@ -0,0 +1,674 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
state the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or school,
|
||||||
|
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||||
|
For more information on this, and how to apply and follow the GNU GPL, see
|
||||||
|
<https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
||||||
@@ -1 +1,20 @@
|
|||||||
# django-relay-controller
|
# RelayController
|
||||||
|
|
||||||
|
Application Django avec Django Channels et Redis pour la gestion et le contrôle de relais et capteurs en temps réel.
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
RelayController est une application de contrôle de relais électriques et de capteurs (débitmètres, etc.) utilisant :
|
||||||
|
- **Django** : framework web backend
|
||||||
|
- **Django Channels** : support WebSocket pour la communication bidirectionnelle en temps réel
|
||||||
|
- **Redis** : broker de messages et stockage de session
|
||||||
|
- **GPIO** : interfaçage matériel (Raspberry Pi, etc.)
|
||||||
|
|
||||||
|
## Fonctionnalités principales
|
||||||
|
|
||||||
|
- **Gestion des relais** : activation/désactivation avec durée programmable
|
||||||
|
- **Capteurs de débit** (YF-S201) : mesure et publication du débit en temps réel
|
||||||
|
- **Communication WebSocket** : mise à jour instantanée des états via Redis
|
||||||
|
- **Historique des états** : enregistrement des événements et durées d'activation
|
||||||
|
- **Contrôle à distance** : interface web pour piloter les appareils
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "System Packages Installation: # $0" 1>&2
|
||||||
|
echo
|
||||||
|
|
||||||
|
sudo apt update
|
||||||
|
#sudo apt upgrade
|
||||||
|
|
||||||
|
sudo apt install build-essential openssl git
|
||||||
|
sudo apt install python3-dev python3-pip python3-venv redis supervisor
|
||||||
|
sudo apt install default-libmysqlclient-dev libpq-dev
|
||||||
|
sudo apt install i2c-tools python3-smbus
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
echo "Mkcert Installation: # $0" 1>&2
|
||||||
|
echo
|
||||||
|
|
||||||
|
sudo apt-get -y install ca-certificates libnss3-tools
|
||||||
|
ROOT="$(pwd)"
|
||||||
|
|
||||||
|
get_primary_ip() {
|
||||||
|
# Test eth0 first
|
||||||
|
if ip -4 addr show dev eth0 >/dev/null 2>&1; then
|
||||||
|
ip -4 -o addr show dev eth0 | awk '{print $4}' | cut -d/ -f1 | head -n1
|
||||||
|
else
|
||||||
|
ip -4 -o addr show scope global | awk '{print $4 " " $2}' | grep -v lo | head -n1 | cut -d/ -f1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
IP="$(get_primary_ip)"
|
||||||
|
CERTS="${ROOT}/certs"
|
||||||
|
|
||||||
|
DOMAIN_SERVER="relay.local"
|
||||||
|
MKCERT_VERSION="v1.4.4"
|
||||||
|
LOCAL_DOMAINS="127.0.0.1 localhost $IP ${DOMAIN_SERVER}"
|
||||||
|
|
||||||
|
# --- mkcert installation ---
|
||||||
|
echo "==== mkcert installation ===="
|
||||||
|
# Déduire URL binaire selon architecture
|
||||||
|
ARCH="$(uname -m)"
|
||||||
|
case "$ARCH" in
|
||||||
|
aarch64|arm64) ARCH_TAG="linux-arm64" ;;
|
||||||
|
armv7l|armv7) ARCH_TAG="linux-arm" ;;
|
||||||
|
x86_64) ARCH_TAG="linux-amd64" ;;
|
||||||
|
*) ARCH_TAG="linux-amd64" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
MKCERT_BINARY_NAME="mkcert-${MKCERT_VERSION}-${ARCH_TAG}"
|
||||||
|
|
||||||
|
#https://github.com/FiloSottile/mkcert/releases/download/v1.4.4/mkcert-v1.4.4-linux-arm64
|
||||||
|
MKCERT_URL="https://github.com/FiloSottile/mkcert/releases/download/${MKCERT_VERSION}/${MKCERT_BINARY_NAME}"
|
||||||
|
echo "Téléchargement: $MKCERT_URL"
|
||||||
|
wget "$MKCERT_URL"
|
||||||
|
sudo mv "$MKCERT_BINARY_NAME" /usr/local/bin/mkcert
|
||||||
|
chmod +x /usr/local/bin/mkcert
|
||||||
|
|
||||||
|
# Installer racine mkcert si nécessaire
|
||||||
|
if ! mkcert -CAROOT >/dev/null 2>&1; then
|
||||||
|
mkcert -install || true
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==== Génération des certificats pour: $LOCAL_DOMAINS ===="
|
||||||
|
mkdir -p "$CERTS"
|
||||||
|
pushd "$CERTS" >/dev/null
|
||||||
|
# mkcert supporte listes d'arguments ; on passe en tant que mots
|
||||||
|
# Note: si trop long, mkcert créera wildcard/local CA selon besoin
|
||||||
|
mkcert -cert-file "${DOMAIN_SERVER}.pem" -key-file "${DOMAIN_SERVER}-key.pem" $LOCAL_DOMAINS
|
||||||
|
popd >/dev/null
|
||||||
|
|
||||||
|
echo "==== Copier certificat racine local pour navigateur ===="
|
||||||
|
LOCAL_CERTS_PATH="$HOME/.local/share/mkcert/rootCA.pem"
|
||||||
|
|
||||||
|
if [ -f "$LOCAL_CERTS_PATH" ]; then
|
||||||
|
cp "$LOCAL_CERTS_PATH" "$CERTS/${DOMAIN_SERVER}-root-cert.pem"
|
||||||
|
echo "Certificat copié: $CERTS/${DOMAIN_SERVER}-root-cert.pem"
|
||||||
|
else
|
||||||
|
echo "Root CA mkcert introuvable à $LOCAL_CERTS_PATH"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "==== Mise à jour /etc/hosts ===="
|
||||||
|
# On ajoute une ligne unique contenant IP puis tous les domaines
|
||||||
|
HOSTS_LINE="$IP $DOMAIN_SERVER"
|
||||||
|
if ! grep -qE "^${IP}[[:space:]]+${DOMAIN_SERVER}(\s|$)" /etc/hosts; then
|
||||||
|
printf "%s\n" "$HOSTS_LINE" | sudo tee -a /etc/hosts >/dev/null
|
||||||
|
echo "/etc/hosts mis à jour"
|
||||||
|
else
|
||||||
|
echo "/etc/hosts contient déjà une entrée pour $IP"
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
After Width: | Height: | Size: 123 KiB |
|
After Width: | Height: | Size: 236 KiB |
@@ -0,0 +1,29 @@
|
|||||||
|
[group:relay]
|
||||||
|
programs = dashboard, workers
|
||||||
|
|
||||||
|
[program:dashboard]
|
||||||
|
process_name=%(program_name)s
|
||||||
|
priority=900
|
||||||
|
directory=/home/rpi4/workspace/django-relay-controller/relaycontroller
|
||||||
|
command=/home/rpi4/workspace/django-relay-controller/relaycontroller/runserver.sh
|
||||||
|
user=rpi4
|
||||||
|
group=rpi4
|
||||||
|
stopasgroup=true
|
||||||
|
killasgroup=true
|
||||||
|
stopsignal=SIGINT
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
|
||||||
|
[program:workers]
|
||||||
|
process_name=%(program_name)s
|
||||||
|
priority=999
|
||||||
|
directory=/home/rpi4/workspace/django-relay-controller/relaycontroller
|
||||||
|
command=/home/rpi4/workspace/django-relay-controller/relaycontroller/workers.sh start
|
||||||
|
user=rpi4
|
||||||
|
group=rpi4
|
||||||
|
stopasgroup=true
|
||||||
|
killasgroup=true
|
||||||
|
stopsignal=SIGINT
|
||||||
|
autostart=true
|
||||||
|
autorestart=true
|
||||||
|
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
django
|
||||||
|
pillow
|
||||||
|
django-timezone-field
|
||||||
|
django-celery-beat
|
||||||
|
django-resized
|
||||||
|
django-celery-results
|
||||||
|
channels[daphne]
|
||||||
|
channels-redis
|
||||||
|
twisted[tls,http2]
|
||||||
|
celery[redis]
|
||||||
|
PyYaml
|
||||||
|
python-decouple
|
||||||
|
python-dateutil
|
||||||
|
psutil
|
||||||
|
paho-mqtt
|
||||||
|
requests
|
||||||
|
mysqlclient
|
||||||
|
psycopg2
|
||||||
|
smbus2
|
||||||
|
RPI.GPIO
|
||||||
|
OPI.GPIO
|
||||||
|
pi74HC595
|
||||||
|
RPLCD
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[inet_http_server]
|
||||||
|
port=*:9001
|
||||||
|
username=root
|
||||||
|
password=toor
|
||||||
|
After Width: | Height: | Size: 71 KiB |
@@ -0,0 +1,110 @@
|
|||||||
|
####
|
||||||
|
# django app
|
||||||
|
DEBUG=True
|
||||||
|
IS_LOGGING=False
|
||||||
|
APP_DATAS=relaycontroller
|
||||||
|
RAMDISK_DEVICE=/mnt/ramdisk
|
||||||
|
MKCERT_VERSION=mkcert-v1.4.4
|
||||||
|
|
||||||
|
DJANGO_APP=relaycontroller
|
||||||
|
APP_TITLE=Controleur de relais
|
||||||
|
APP_SUB_TITLE=Dev
|
||||||
|
|
||||||
|
LANGUAGE_CODE=fr-FR
|
||||||
|
LOCALE_CODE=fr_FR
|
||||||
|
LOCALE_LC_ALL=fr_FR.UTF-8
|
||||||
|
TIME_ZONE=Europe/Paris
|
||||||
|
|
||||||
|
# RPI PINOUT BOARD MODE
|
||||||
|
|
||||||
|
# shiftout 74HC595
|
||||||
|
# gpio16
|
||||||
|
CTL_DATA_PIN=36
|
||||||
|
# gpio20
|
||||||
|
CTL_LATCH_PIN=38
|
||||||
|
# gpio21
|
||||||
|
CTL_CLOCK_PIN=40
|
||||||
|
CTL_NUMBER=2
|
||||||
|
|
||||||
|
# YF_S201
|
||||||
|
WATERFLOW_PIN=7
|
||||||
|
|
||||||
|
####
|
||||||
|
# django email
|
||||||
|
#
|
||||||
|
DEFAULT_TO_EMAIL=postmaster@mysite.net
|
||||||
|
DEFAULT_FROM_EMAIL=postmaster@mysite.net
|
||||||
|
DEFAULT_EMAIL_CONTACT=postmaster@mysite.net
|
||||||
|
|
||||||
|
EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
|
||||||
|
EMAIL_HOST=ssl0.ovh.net
|
||||||
|
EMAIL_PORT=587
|
||||||
|
EMAIL_HOST_USER=xxx@yyy.net
|
||||||
|
EMAIL_HOST_PASSWORD=123456
|
||||||
|
EMAIL_USE_TLS=True
|
||||||
|
|
||||||
|
LOGGING_FILE=relay.log
|
||||||
|
SECRET_KEY=django-insecure-u=^w_n16w@b83oa+93a8^j_€g-e%!e1m(pc&7hzm(y95d*+gnf
|
||||||
|
USER=rpi4
|
||||||
|
GROUP=rpi4
|
||||||
|
|
||||||
|
DOMAIN_SERVER=relay.local
|
||||||
|
ALLOWED_HOSTS=127.0.0.1,localhost,192.168.1.37
|
||||||
|
CSRF_TRUSTED_ORIGINS=http://127.0.0.1:8020,http://localhost:8020,http://192.168.1.37:8020
|
||||||
|
|
||||||
|
####
|
||||||
|
# server app
|
||||||
|
SERVER_HOST_IP=0.0.0.0
|
||||||
|
SERVER_HOST_PORT=8020
|
||||||
|
|
||||||
|
####
|
||||||
|
# redis
|
||||||
|
#
|
||||||
|
REDIS_HOST=127.0.0.1
|
||||||
|
REDIS_PORT=6379
|
||||||
|
|
||||||
|
####
|
||||||
|
# database: sqlite3 | mariadb | postgrey
|
||||||
|
#
|
||||||
|
# sqlite3
|
||||||
|
SQLITE3=default
|
||||||
|
SQLITE3_PATH=
|
||||||
|
|
||||||
|
# mariadb
|
||||||
|
MARIADB=None
|
||||||
|
DATABASE_MARIADB_HOST=127.0.0.1
|
||||||
|
DATABASE_MARIADB_PORT=3306
|
||||||
|
|
||||||
|
# postgrey
|
||||||
|
POSTGRES=None
|
||||||
|
DATABASE_POSTGRES_HOST=127.0.0.1
|
||||||
|
DATABASE_POSTGRES_PORT=5432
|
||||||
|
|
||||||
|
####
|
||||||
|
# database
|
||||||
|
#
|
||||||
|
DATABASE_NAME=relay
|
||||||
|
DATABASE_USER=relay
|
||||||
|
DATABASE_PASSWORD=relay
|
||||||
|
|
||||||
|
####
|
||||||
|
# mosquitto
|
||||||
|
MQTT_ORIGINE=ctrl
|
||||||
|
MQTT_HOST=192.168.1.4
|
||||||
|
MQTT_PORT=1883
|
||||||
|
MQTT_USERNAME=
|
||||||
|
MQTT_PASSWORD=
|
||||||
|
MQTT_CA_CERT=
|
||||||
|
|
||||||
|
|
||||||
|
####
|
||||||
|
# default login:pass
|
||||||
|
#
|
||||||
|
SUPERADMIN=superadmin
|
||||||
|
SUPERADMIN_PASS=superadmin
|
||||||
|
SUPERADMIN_MAIL=superadmin@relay.net
|
||||||
|
|
||||||
|
DEFAULT_USER=relay
|
||||||
|
DEFAULT_USER_PASS=relay
|
||||||
|
DEFAULT_USER_MAIL=relay@local.net
|
||||||
|
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
from .celerymodule import appc as celery_app
|
||||||
|
|
||||||
|
__all__ = ('celery_app',)
|
||||||
|
__version__ = "0.5"
|
||||||
|
default_app_config = 'home.apps.CoreConfig'
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
class CoreConfig(AppConfig):
|
||||||
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
|
name = 'home'
|
||||||
|
verbose_name = _('Controleur de relais')
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
"""
|
||||||
|
ASGI config for home_automation project.
|
||||||
|
|
||||||
|
It exposes the ASGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'home.settings')
|
||||||
|
|
||||||
|
from django.core.asgi import get_asgi_application
|
||||||
|
django_asgi_app = get_asgi_application()
|
||||||
|
|
||||||
|
from channels.auth import AuthMiddlewareStack
|
||||||
|
from channels.routing import ProtocolTypeRouter, URLRouter
|
||||||
|
from channels.security.websocket import AllowedHostsOriginValidator
|
||||||
|
|
||||||
|
import relay.routing
|
||||||
|
|
||||||
|
|
||||||
|
application = ProtocolTypeRouter({
|
||||||
|
"http": django_asgi_app,
|
||||||
|
'websocket': AllowedHostsOriginValidator(
|
||||||
|
AuthMiddlewareStack(
|
||||||
|
URLRouter(relay.routing.websocket_urlpatterns)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
})
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#
|
||||||
|
# encoding: utf-8
|
||||||
|
import os
|
||||||
|
from celery import Celery
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'home.settings')
|
||||||
|
|
||||||
|
appc = Celery('home')
|
||||||
|
appc.config_from_object('django.conf:settings', namespace='CELERY')
|
||||||
|
appc.autodiscover_tasks()
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#
|
||||||
|
# encoding: utf-8
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
def params(request):
|
||||||
|
return {
|
||||||
|
'APP_TITLE': settings.APP_TITLE,
|
||||||
|
'APP_SUB_TITLE': settings.APP_SUB_TITLE,
|
||||||
|
'self_url': request.build_absolute_uri(),
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2026-02-24 08:51+0100\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
#: home/apps.py:7
|
||||||
|
msgid "Automation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/management/commands/init_data.py:63
|
||||||
|
msgid "Base configuration"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/management/commands/init_data.py:144
|
||||||
|
msgid "Non"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/management/commands/init_data.py:145
|
||||||
|
#: home/management/commands/init_data.py:148
|
||||||
|
msgid "Salon"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/management/commands/init_data.py:146
|
||||||
|
msgid "Cellier"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/management/commands/init_data.py:147
|
||||||
|
msgid "Cuisine"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/management/commands/init_data.py:149
|
||||||
|
msgid "Entrée"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/management/commands/init_data.py:150
|
||||||
|
msgid "Repas"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/management/commands/init_data.py:151
|
||||||
|
msgid "Chambre 1"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/management/commands/init_data.py:152
|
||||||
|
msgid "Chambre 2"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/management/commands/init_data.py:153
|
||||||
|
msgid "Chambre 3"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/inc/404.html:9
|
||||||
|
msgid "Error: missing page."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/inc/404.html:17
|
||||||
|
msgid "This page does not exist.<br>Please re-enter a new address."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/inc/500.html:9
|
||||||
|
msgid "System error"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: home/templates/inc/500.html:17
|
||||||
|
msgid ""
|
||||||
|
"This page server can't run correctly.<br>Please contact the site "
|
||||||
|
"administrator."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/admin/base_site.html:4
|
||||||
|
msgid "Django site admin"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates/admin/base_site.html:10
|
||||||
|
msgid "Django administration"
|
||||||
|
msgstr ""
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
#
|
||||||
|
# encoding: utf-8
|
||||||
|
#import re
|
||||||
|
#from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.management import BaseCommand
|
||||||
|
from django_celery_beat.models import IntervalSchedule, CrontabSchedule, SolarSchedule
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from relay import models
|
||||||
|
from modules import utils
|
||||||
|
|
||||||
|
|
||||||
|
def create_user():
|
||||||
|
try:
|
||||||
|
User = get_user_model()
|
||||||
|
if User.objects.count() == 0:
|
||||||
|
for email, username, password, is_superuser in settings.ADMINS:
|
||||||
|
if is_superuser:
|
||||||
|
User.objects.create_superuser(
|
||||||
|
email=email,
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
is_active=True,
|
||||||
|
is_superuser=is_superuser,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
User.objects.create_user(
|
||||||
|
email=email,
|
||||||
|
username=username,
|
||||||
|
password=password,
|
||||||
|
is_active=True,
|
||||||
|
)
|
||||||
|
print(f'Creating {username} user with {password} password and email: {email} superuser: {is_superuser}')
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Creating user error {e}')
|
||||||
|
|
||||||
|
def create_schedule():
|
||||||
|
try:
|
||||||
|
for n in [1, 2, 5, 10, 15, 20, 30, 40, 45, 50]:
|
||||||
|
IntervalSchedule.objects.create(every=n, period='minutes')
|
||||||
|
print('Creating IntervalSchedule minutes')
|
||||||
|
|
||||||
|
for n in [1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]:
|
||||||
|
IntervalSchedule.objects.create(every=n, period='hours')
|
||||||
|
print('Creating IntervalSchedule hours')
|
||||||
|
|
||||||
|
for n in [1, 2, 3, 7, 15, 30, 60, 90, 180, 360]:
|
||||||
|
IntervalSchedule.objects.create(every=n, period='days')
|
||||||
|
print('Creating IntervalSchedule days')
|
||||||
|
|
||||||
|
CrontabSchedule.objects.create(minute='0', hour='4', day_of_week='*', timezone=settings.TIME_ZONE)
|
||||||
|
CrontabSchedule.objects.create(minute='0', hour='4', day_of_week='*/3', timezone=settings.TIME_ZONE)
|
||||||
|
CrontabSchedule.objects.create(minute='15', hour='4', day_of_week='*/3', timezone=settings.TIME_ZONE)
|
||||||
|
CrontabSchedule.objects.create(minute='30', hour='4', day_of_week='*/3', timezone=settings.TIME_ZONE)
|
||||||
|
CrontabSchedule.objects.create(minute='0', hour='18', day_of_week='*', timezone=settings.TIME_ZONE)
|
||||||
|
CrontabSchedule.objects.create(minute='15', hour='18', day_of_week='*/3', timezone=settings.TIME_ZONE)
|
||||||
|
CrontabSchedule.objects.create(minute='30', hour='18', day_of_week='*/3', timezone=settings.TIME_ZONE)
|
||||||
|
print('Creating CrontabSchedule')
|
||||||
|
|
||||||
|
SolarSchedule.objects.create(event='sunset', latitude=43.8, longitude=2.3)
|
||||||
|
SolarSchedule.objects.create(event='sunrise', latitude=43.8, longitude=2.3)
|
||||||
|
print('Creating SolarSchedule')
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Creating schedule error {e}')
|
||||||
|
|
||||||
|
|
||||||
|
def create_device_type():
|
||||||
|
try:
|
||||||
|
data = dict(
|
||||||
|
name = 'Relais à sortie décalée',
|
||||||
|
code = 'relay_shiftout',
|
||||||
|
)
|
||||||
|
models.DeviceType.objects.create(**data)
|
||||||
|
print(f'Creating DeviceType')
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Creating DeviceType error {e}')
|
||||||
|
|
||||||
|
|
||||||
|
def create_relay():
|
||||||
|
try:
|
||||||
|
device_type = models.DeviceType.objects.filter(code__exact='relay_shiftout').first()
|
||||||
|
for i in range(settings.CTL_RELAY_NUMBER):
|
||||||
|
data = dict(
|
||||||
|
label = f'Relay:{i}',
|
||||||
|
uuid = utils.get_device_uuid(12),
|
||||||
|
device_type = device_type,
|
||||||
|
index = i,
|
||||||
|
)
|
||||||
|
models.Device.objects.create(**data)
|
||||||
|
print('Creating Device', data)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Creating Device error {e}')
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
try:
|
||||||
|
create_user()
|
||||||
|
create_schedule()
|
||||||
|
create_device_type()
|
||||||
|
create_relay()
|
||||||
|
except Exception as e:
|
||||||
|
print(f'Creating monitor error {e}')
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
#
|
||||||
|
# encoding: utf-8
|
||||||
|
from django.core.management import BaseCommand
|
||||||
|
from django.urls import get_resolver
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def handle(self, *args, **kwargs):
|
||||||
|
|
||||||
|
def show_urls(urllist, depth=0):
|
||||||
|
for entry in urllist:
|
||||||
|
print(entry.pattern)
|
||||||
|
if hasattr(entry, 'url_patterns'):
|
||||||
|
show_urls(entry.url_patterns, depth + 1)
|
||||||
|
|
||||||
|
show_urls(get_resolver().url_patterns)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
'''
|
||||||
|
Created on 19 janv. 2026
|
||||||
|
|
||||||
|
@author: denis
|
||||||
|
'''
|
||||||
|
import os
|
||||||
|
os.environ['BOARD_DEVICE']="RPI"
|
||||||
|
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.conf import settings
|
||||||
|
from modules import gpiolib as gpio, devices as dev
|
||||||
|
|
||||||
|
RELAY_KEY = 'Relay_'
|
||||||
|
RELAY_MSG = 'Vanne'
|
||||||
|
# devices
|
||||||
|
DEVICES = []
|
||||||
|
for i in range(settings.RELAY_NUMBER):
|
||||||
|
active = 1
|
||||||
|
DEVICES.append( { 'type': 'RELAY_SHIFTOUT', 'index': i, 'key': f'{RELAY_KEY}{i}', 'label': f'{RELAY_MSG} {i}', 'status': 0, 'active': active, } )
|
||||||
|
|
||||||
|
DEVICES_REGISTERED = DEVICES
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
super(Command, self).add_arguments(parser)
|
||||||
|
#parser.add_argument("--task", action="store", dest="task", default='start_all')
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
try:
|
||||||
|
shift_out_register = gpio.ShiftOutRegister74HC595(
|
||||||
|
latch_pin=settings.CTL_LATCH_PIN,
|
||||||
|
clock_pin=settings.CTL_CLOCK_PIN,
|
||||||
|
data_pin=settings.CTL_DATA_PIN,
|
||||||
|
number=settings.CTL_NUMBER,
|
||||||
|
)
|
||||||
|
|
||||||
|
for device in settings.DEVICES_REGISTERED:
|
||||||
|
relay = dev.Relay(shift_out_register, device)
|
||||||
|
relay.relay_start(duration=5)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print("Command", e)
|
||||||
|
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#
|
||||||
|
# encoding: utf-8
|
||||||
|
from uuid import uuid4
|
||||||
|
from django.core.management import BaseCommand
|
||||||
|
from django.core.management.utils import get_random_string;
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
super().add_arguments(parser)
|
||||||
|
parser.add_argument("--app", type=str, default='django', help=f"Default application django/reductstore")
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
if options.get('app')=='django':
|
||||||
|
chars = "abcdefghijklmnopqrstuvwxyz0123456789!@#€%^&*(-_=+)"
|
||||||
|
|
||||||
|
sk = get_random_string(50, chars)
|
||||||
|
|
||||||
|
print(f'django-insecure-{sk}')
|
||||||
|
elif options.get('app')=='reductstore':
|
||||||
|
print(f'monitor-{uuid4()}')
|
||||||
|
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
'''
|
||||||
|
Created on 19 janv. 2026
|
||||||
|
|
||||||
|
@author: denis
|
||||||
|
'''
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from relay import tasks as relay_tasks
|
||||||
|
from home import tasks as mqtt_tasks
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = "Démarre les tâches Celery."
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
super(Command, self).add_arguments(parser)
|
||||||
|
#parser.add_argument("--task", action="store", dest="task", default='start_all')
|
||||||
|
|
||||||
|
def handle(self, *args, **options): # @UnusedVariable
|
||||||
|
#task = options['task']
|
||||||
|
try:
|
||||||
|
mqtt_tasks.start_mqtt_worker.delay() # @UndefinedVariable
|
||||||
|
print("task start_mqtt_worker ...")
|
||||||
|
|
||||||
|
relay_tasks.relay_start_all.delay() # @UndefinedVariable
|
||||||
|
print("task relay_start_all ...")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(e)
|
||||||
|
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
from django.conf import settings
|
||||||
|
from django.utils import translation
|
||||||
|
|
||||||
|
def SetDefaultLangMiddleware(get_response):
|
||||||
|
|
||||||
|
def middleware(request):
|
||||||
|
if not request.COOKIES.get('django_language'):
|
||||||
|
request.COOKIES['django_language'] = settings.LANGUAGE_CODE
|
||||||
|
translation.activate(settings.LANGUAGE_CODE)
|
||||||
|
elif request.COOKIES['django_language'] != settings.LANGUAGE_CODE:
|
||||||
|
request.COOKIES['django_language'] = settings.LANGUAGE_CODE
|
||||||
|
translation.activate(settings.LANGUAGE_CODE)
|
||||||
|
response = get_response(request)
|
||||||
|
return response
|
||||||
|
return middleware
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
'''
|
||||||
|
Created on 23 janv. 2026
|
||||||
|
|
||||||
|
@author: denis
|
||||||
|
'''
|
||||||
|
import json
|
||||||
|
from threading import Thread, Event
|
||||||
|
from celery import Task
|
||||||
|
from celery.exceptions import Ignore
|
||||||
|
from celery.utils.log import get_task_logger
|
||||||
|
from redis import Redis
|
||||||
|
from django.conf import settings
|
||||||
|
from modules.mqttc import MqttBase as MqttClient
|
||||||
|
|
||||||
|
|
||||||
|
RELAY_SUB_TOPIC = "relay/+/#"
|
||||||
|
ZIGBEE_SUB_TOPIC = "zigbee2mqtt/#"
|
||||||
|
|
||||||
|
|
||||||
|
class Mqttc:
|
||||||
|
task = None
|
||||||
|
conf = dict(
|
||||||
|
host=settings.MQTT_HOST,
|
||||||
|
port=settings.MQTT_PORT,
|
||||||
|
username=settings.MQTT_USERNAME,
|
||||||
|
password=settings.MQTT_PASSWORD,
|
||||||
|
ca_cert=settings.MQTT_CA_CERT,
|
||||||
|
keepalive=60,
|
||||||
|
topic_base=f"{settings.MQTT_ORIGINE}",
|
||||||
|
topic_subs=[
|
||||||
|
[RELAY_SUB_TOPIC, 0],
|
||||||
|
#[ZIGBEE_SUB_TOPIC, 0],
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
logger = get_task_logger(__name__)
|
||||||
|
redis = Redis(host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=0, decode_responses=True)
|
||||||
|
mqttc = Mqttc()
|
||||||
|
|
||||||
|
|
||||||
|
class MqttProcess(Task):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
self.stop_event = Event()
|
||||||
|
self.mqtt = MqttClient(on_messages=self._on_mqtt_message, **mqttc.conf)
|
||||||
|
|
||||||
|
|
||||||
|
def __call__(self, *args, **kwargs):
|
||||||
|
return self.start(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def start(self, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
self.mqtt.startMQTT()
|
||||||
|
self.start_redis_subscriber()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
raise Ignore()
|
||||||
|
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
try:
|
||||||
|
self.stop_event.set()
|
||||||
|
self.mqtt.stopMQTT()
|
||||||
|
logger.info(f"Listening stop.")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
|
||||||
|
|
||||||
|
def start_redis_subscriber(self):
|
||||||
|
self.redis_subscriber = Thread(target=self._listen_to_redis, daemon=True)
|
||||||
|
self.redis_subscriber.start()
|
||||||
|
|
||||||
|
|
||||||
|
def _on_mqtt_message(self, topic, payload):
|
||||||
|
try:
|
||||||
|
#logger.info(f"---- on_mqtt_message {topic}: {payload}")
|
||||||
|
if topic.startswith(RELAY_SUB_TOPIC[:-3]):
|
||||||
|
uuid = topic.split('/')[1]
|
||||||
|
redis.publish(f'relay_{uuid}', json.dumps({"type": "mqtt", "topic": topic, "payload": payload}))
|
||||||
|
else:
|
||||||
|
redis.publish('mqtt_message', json.dumps({"type": "mqtt", "topic": topic, "payload": payload}))
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f'on_mqtt_message: {e}')
|
||||||
|
logger.error(topic)
|
||||||
|
logger.error(payload)
|
||||||
|
|
||||||
|
def _listen_to_redis(self):
|
||||||
|
try:
|
||||||
|
pubsub = redis.pubsub()
|
||||||
|
pubsub.subscribe(f"mqtt_pub")
|
||||||
|
logger.info(f"---- listen mqtt_message via redis")
|
||||||
|
|
||||||
|
for message in pubsub.listen():
|
||||||
|
if self.stop_event.is_set():
|
||||||
|
break
|
||||||
|
data = json.loads(str(message.get('data')))
|
||||||
|
if not isinstance(data, dict):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if data.get("type") == "mqtt":
|
||||||
|
self.mqtt._publish_message(data["topic"], **data["payload"])
|
||||||
|
finally:
|
||||||
|
pubsub.unsubscribe()
|
||||||
|
pubsub.close()
|
||||||
|
|
||||||
@@ -0,0 +1,384 @@
|
|||||||
|
"""
|
||||||
|
Django settings for monitoring project.
|
||||||
|
|
||||||
|
Generated by 'django-admin startproject' using Django 5.1.6.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/5.1/topics/settings/
|
||||||
|
|
||||||
|
For the full list of settings and their values, see
|
||||||
|
https://docs.djangoproject.com/en/5.1/ref/settings/
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.contrib.messages import constants as message_constants
|
||||||
|
from pathlib import Path
|
||||||
|
from decouple import config, Csv
|
||||||
|
|
||||||
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
PACKAGE_DIR = BASE_DIR.parent
|
||||||
|
|
||||||
|
APP_DATAS = PACKAGE_DIR / config('APP_DATAS')
|
||||||
|
print("Django application data:", APP_DATAS)
|
||||||
|
|
||||||
|
|
||||||
|
# Quick-start development settings - unsuitable for production
|
||||||
|
# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/
|
||||||
|
|
||||||
|
DJANGO_APP = config('DJANGO_APP')
|
||||||
|
APP_NAME = DJANGO_APP
|
||||||
|
|
||||||
|
# Quick-start development settings - unsuitable for production
|
||||||
|
# See https://docs.djangoproject.com/en/3.2/howto/deployment/checklist/
|
||||||
|
SECRET_KEY = config("SECRET_KEY")
|
||||||
|
|
||||||
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
|
DEBUG = config('DEBUG', cast=bool)
|
||||||
|
|
||||||
|
DOMAIN_SERVER = config("DOMAIN_SERVER")
|
||||||
|
ALLOWED_HOSTS = config('ALLOWED_HOSTS', cast=Csv())
|
||||||
|
ALLOWED_HOSTS += [DOMAIN_SERVER, '*']
|
||||||
|
|
||||||
|
CSRF_TRUSTED_ORIGINS = config('CSRF_TRUSTED_ORIGINS', cast=Csv())
|
||||||
|
CSRF_TRUSTED_ORIGINS += [f'http://{DOMAIN_SERVER}', f'https://{DOMAIN_SERVER}']
|
||||||
|
|
||||||
|
SECURE_CROSS_ORIGIN_OPENER_POLICY = 'same-origin'
|
||||||
|
X_FRAME_OPTIONS = 'SAMEORIGIN'
|
||||||
|
|
||||||
|
|
||||||
|
# Application definition
|
||||||
|
INSTALLED_APPS = [
|
||||||
|
'daphne',
|
||||||
|
'channels',
|
||||||
|
'django.contrib.admin',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'django.contrib.staticfiles',
|
||||||
|
'django_celery_beat',
|
||||||
|
'django_celery_results',
|
||||||
|
'celery',
|
||||||
|
'home',
|
||||||
|
'relay',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
AUTHENTICATION_BACKENDS = (
|
||||||
|
'django.contrib.auth.backends.ModelBackend',
|
||||||
|
#'contrib.auth.EmailBackend',
|
||||||
|
)
|
||||||
|
|
||||||
|
MIDDLEWARE = [
|
||||||
|
'django.middleware.security.SecurityMiddleware',
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
'django.middleware.locale.LocaleMiddleware',
|
||||||
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||||
|
'home.middleware.SetDefaultLangMiddleware',
|
||||||
|
]
|
||||||
|
|
||||||
|
ROOT_URLCONF = 'home.urls'
|
||||||
|
|
||||||
|
TEMPLATES = [
|
||||||
|
{
|
||||||
|
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||||
|
'DIRS': [BASE_DIR / 'templates', ],
|
||||||
|
'APP_DIRS': True,
|
||||||
|
'OPTIONS': {
|
||||||
|
'context_processors': [
|
||||||
|
'django.template.context_processors.debug',
|
||||||
|
'django.template.context_processors.request',
|
||||||
|
'django.contrib.auth.context_processors.auth',
|
||||||
|
'django.contrib.messages.context_processors.messages',
|
||||||
|
'home.context_processors.params',
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
WSGI_APPLICATION = 'home.wsgi.application'
|
||||||
|
ASGI_APPLICATION = 'home.asgi.application'
|
||||||
|
|
||||||
|
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
|
||||||
|
|
||||||
|
# Redis
|
||||||
|
#
|
||||||
|
REDIS_HOST=config("REDIS_HOST")
|
||||||
|
REDIS_PORT=int(config("REDIS_PORT"))
|
||||||
|
|
||||||
|
CHANNEL_LAYERS = {
|
||||||
|
'default': {
|
||||||
|
'BACKEND': 'channels_redis.core.RedisChannelLayer',
|
||||||
|
'CONFIG': {
|
||||||
|
"hosts": [(REDIS_HOST, REDIS_PORT)],
|
||||||
|
"capacity": 5000, # default 100
|
||||||
|
"expiry": 10, # default 60
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Database
|
||||||
|
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases
|
||||||
|
|
||||||
|
DATABASE_NAME = config('DATABASE_NAME')
|
||||||
|
DATABASE_USER = config('DATABASE_USER')
|
||||||
|
DATABASE_PASSWORD = config('DATABASE_PASSWORD')
|
||||||
|
|
||||||
|
SQLITE3=config('SQLITE3')
|
||||||
|
SQLITE3_PATH=config('SQLITE3_PATH')
|
||||||
|
MARIADB=config('MARIADB')
|
||||||
|
POSTGRES=config('POSTGRES')
|
||||||
|
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
SQLITE3: {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': f'{SQLITE3_PATH}db.sqlite3',
|
||||||
|
"OPTIONS": {
|
||||||
|
"timeout": 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MARIADB: {
|
||||||
|
'ENGINE': 'django.db.backends.mysql',
|
||||||
|
'OPTIONS' : {
|
||||||
|
"init_command": "SET foreign_key_checks = 0;SET sql_mode='STRICT_TRANS_TABLES';",
|
||||||
|
'charset': 'utf8mb4',
|
||||||
|
},
|
||||||
|
'NAME': DATABASE_NAME,
|
||||||
|
'USER': DATABASE_USER,
|
||||||
|
'PASSWORD': DATABASE_PASSWORD,
|
||||||
|
'HOST': config("DATABASE_MARIADB_HOST"),
|
||||||
|
'PORT': config("DATABASE_MARIADB_PORT", cast=int),
|
||||||
|
},
|
||||||
|
POSTGRES: {
|
||||||
|
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||||
|
'NAME': DATABASE_NAME,
|
||||||
|
'USER': DATABASE_USER,
|
||||||
|
'PASSWORD': DATABASE_PASSWORD,
|
||||||
|
'HOST': config("DATABASE_POSTGRES_HOST"),
|
||||||
|
'PORT': config("DATABASE_POSTGRES_PORT", cast=int),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Password validation
|
||||||
|
# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators
|
||||||
|
|
||||||
|
AUTH_PASSWORD_VALIDATORS = [
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# Internationalization
|
||||||
|
# https://docs.djangoproject.com/en/5.1/topics/i18n/
|
||||||
|
#LANGUAGE_CODE = 'en-US'
|
||||||
|
LANGUAGE_CODE = config('LANGUAGE_CODE')
|
||||||
|
|
||||||
|
LANGUAGES = (
|
||||||
|
('fr', 'Français'),
|
||||||
|
('en', 'English'),
|
||||||
|
)
|
||||||
|
|
||||||
|
TIME_ZONE = config('TIME_ZONE')
|
||||||
|
USE_I18N = True
|
||||||
|
USE_L10N = True
|
||||||
|
USE_TZ = True
|
||||||
|
|
||||||
|
LOCALE_CODE = config('LOCALE_CODE')
|
||||||
|
LOCALE_LC_ALL = config('LOCALE_LC_ALL')
|
||||||
|
|
||||||
|
LOCALE_PATHS = (
|
||||||
|
BASE_DIR / 'home' / 'locale',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Static files (CSS, JavaScript, Images)
|
||||||
|
# https://docs.djangoproject.com/en/5.1/howto/static-files/
|
||||||
|
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
STATIC_ROOT = APP_DATAS / 'staticfiles'
|
||||||
|
|
||||||
|
MEDIA_URL = '/media/'
|
||||||
|
MEDIA_ROOT = APP_DATAS / 'media'
|
||||||
|
|
||||||
|
"""
|
||||||
|
STATICFILES_DIRS = [
|
||||||
|
BASE_DIR / 'xxx',
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Default primary key field type
|
||||||
|
# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
|
|
||||||
|
## LOGGING
|
||||||
|
# CRITICAL=50, ERROR=40, WARN=30, INFO=20, DEBUG=10 and NOTSET=0
|
||||||
|
|
||||||
|
LOGGING_FILE = config('LOGGING_FILE')
|
||||||
|
IS_LOGGING = config('IS_LOGGING', cast=bool)
|
||||||
|
|
||||||
|
LOGGING = None if not IS_LOGGING else {
|
||||||
|
'version': 1,
|
||||||
|
'disable_existing_loggers': False,
|
||||||
|
'formatters': {
|
||||||
|
'simple': {
|
||||||
|
'format': '%(asctime)s - %(message)s'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'handlers': {
|
||||||
|
'file': {
|
||||||
|
'level': 'INFO',
|
||||||
|
'class':'logging.handlers.RotatingFileHandler',
|
||||||
|
'filename': LOGGING_FILE,
|
||||||
|
'maxBytes': 1024*1024*15, # 15MB
|
||||||
|
'backupCount': 10,
|
||||||
|
'formatter': 'simple',
|
||||||
|
},
|
||||||
|
'null': {'class': 'logging.NullHandler', },
|
||||||
|
'console': {'class': 'logging.StreamHandler',},
|
||||||
|
},
|
||||||
|
'loggers': {
|
||||||
|
"django": {"handlers": ["null"], "level": "ERROR", "propagate": False,},
|
||||||
|
"uvicorn": {"handlers": ["null"], "level": "ERROR", "propagate": False,},
|
||||||
|
"daphne": {"handlers": ["null"], "level": "ERROR", "propagate": False,},
|
||||||
|
'axes': {"handlers": ['file',],"level": "INFO", "propagate": True, },
|
||||||
|
"relay": {"handlers": ["null"], "level": "INFO", "propagate": False,},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
# ACCOUNT
|
||||||
|
#
|
||||||
|
LOGIN_URL = 'login'
|
||||||
|
LOGIN_REDIRECT_URL = '/'
|
||||||
|
LOGOUT_REDIRECT_URL = "/"
|
||||||
|
|
||||||
|
##
|
||||||
|
# application
|
||||||
|
SUPERADMIN_MAIL = config('SUPERADMIN_MAIL')
|
||||||
|
DEFAULT_USER_MAIL = config('DEFAULT_USER_MAIL')
|
||||||
|
ADMINS = [
|
||||||
|
(SUPERADMIN_MAIL, config('SUPERADMIN'), config('SUPERADMIN_PASS'), True),
|
||||||
|
(DEFAULT_USER_MAIL, config('DEFAULT_USER'), config('DEFAULT_USER_PASS'), False),
|
||||||
|
]
|
||||||
|
MANAGERS = ADMINS
|
||||||
|
|
||||||
|
# w3 css
|
||||||
|
MESSAGE_TAGS = {
|
||||||
|
message_constants.DEBUG: 'w3-purple',
|
||||||
|
message_constants.INFO: 'w3-blue',
|
||||||
|
message_constants.SUCCESS: 'w3-green',
|
||||||
|
message_constants.WARNING: 'w3-orange',
|
||||||
|
message_constants.ERROR: 'w3-red',
|
||||||
|
}
|
||||||
|
|
||||||
|
# Default css classes for widgets and labels
|
||||||
|
DEFAULT_CSS = {
|
||||||
|
'error': 'w3-panel w3-red', # displayed in the label
|
||||||
|
'errorlist': 'w3-padding-8 w3-red', # encloses the error list
|
||||||
|
'required': 'w3-text-indigo', # used in the label and label + input enclosing box. NB: w3-validate only works if the input precedes the label!
|
||||||
|
'label': 'w3-label',
|
||||||
|
'Textarea': 'w3-input w3-border',
|
||||||
|
'TextInput': 'w3-input w3-border',
|
||||||
|
'Select': 'w3-select w3-border',
|
||||||
|
}
|
||||||
|
|
||||||
|
# django mail
|
||||||
|
#
|
||||||
|
DEFAULT_TO_EMAIL = config("DEFAULT_TO_EMAIL")
|
||||||
|
DEFAULT_FROM_EMAIL = config("DEFAULT_FROM_EMAIL")
|
||||||
|
DEFAULT_EMAIL_CONTACT = config("DEFAULT_EMAIL_CONTACT")
|
||||||
|
|
||||||
|
EMAIL_BACKEND = config("EMAIL_BACKEND")
|
||||||
|
EMAIL_HOST = config("EMAIL_HOST")
|
||||||
|
EMAIL_PORT = config("EMAIL_PORT", cast=int)
|
||||||
|
EMAIL_HOST_USER = config("EMAIL_HOST_USER")
|
||||||
|
EMAIL_HOST_PASSWORD = config("EMAIL_HOST_PASSWORD")
|
||||||
|
EMAIL_USE_TLS = config('EMAIL_USE_TLS', cast=bool)
|
||||||
|
|
||||||
|
## CELERY tasks
|
||||||
|
#
|
||||||
|
#from celery.schedules import crontab
|
||||||
|
REDIS_HOST_PORT = f'{config("REDIS_HOST")}:{config("REDIS_PORT")}'
|
||||||
|
CELERY_RESULT_BACKEND = f"redis://{REDIS_HOST_PORT}/1"
|
||||||
|
CELERY_BROKER_URL = f"redis://{REDIS_HOST_PORT}/0"
|
||||||
|
CELERY_TASK_RESULT_EXPIRES=3600
|
||||||
|
CELERY_BROKER_CONNECTION_RETRY_ON_STARTUP = False
|
||||||
|
CELERY_TIMEZONE=TIME_ZONE
|
||||||
|
|
||||||
|
DJANGO_CELERY_BEAT_TZ_AWARE = False
|
||||||
|
CELERY_ENABLE_UTC = False
|
||||||
|
CELERY_TASK_TRACK_STARTED = True
|
||||||
|
CELERY_TASK_TIME_LIMIT = 30 * 60
|
||||||
|
CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'
|
||||||
|
CELERY_ACCEPT_CONTENT = ['application/json']
|
||||||
|
CELERY_RESULT_SERIALIZER = 'json'
|
||||||
|
CELERY_TASK_SERIALIZER = 'json'
|
||||||
|
|
||||||
|
CELERY_RESULT_EXTENDED = True
|
||||||
|
CELERY_RESULT_BACKEND = 'django-db'
|
||||||
|
DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH=191
|
||||||
|
|
||||||
|
## mqtt
|
||||||
|
#
|
||||||
|
MQTT_TOPIC_PREFIX = MQTT_ORIGINE = config('MQTT_ORIGINE')
|
||||||
|
MQTT_HOST = config('MQTT_HOST')
|
||||||
|
MQTT_PORT = config('MQTT_PORT', cast=int)
|
||||||
|
MQTT_USERNAME = config('MQTT_USERNAME')
|
||||||
|
MQTT_PASSWORD = config('MQTT_PASSWORD')
|
||||||
|
MQTT_CA_CERT = config('MQTT_CA_CERT')
|
||||||
|
|
||||||
|
|
||||||
|
## servers app
|
||||||
|
#
|
||||||
|
USER = config('USER')
|
||||||
|
GROUP = config('GROUP')
|
||||||
|
SERVER_HOST_PORT = config('SERVER_HOST_PORT', cast=int)
|
||||||
|
SERVER_HOST_IP = config('SERVER_HOST_IP')
|
||||||
|
|
||||||
|
# ws
|
||||||
|
RELAY_WEBSOCKET_ROUTE = 'ws/relay'
|
||||||
|
|
||||||
|
# app
|
||||||
|
#
|
||||||
|
RAMDISK_DEVICE = config('RAMDISK_DEVICE')
|
||||||
|
|
||||||
|
DATA_UPLOAD_MAX_NUMBER_FIELDS = 10240
|
||||||
|
APP_TITLE = config("APP_TITLE")
|
||||||
|
APP_SUB_TITLE = config("APP_SUB_TITLE")
|
||||||
|
DATETIME_FORMAT = '%d-%m-%Y-%m %H:%M:%S'
|
||||||
|
|
||||||
|
# devices
|
||||||
|
|
||||||
|
# shiftout 74HC595
|
||||||
|
CTL_DATA_PIN = config('CTL_DATA_PIN', cast=int)
|
||||||
|
CTL_LATCH_PIN = config('CTL_LATCH_PIN', cast=int)
|
||||||
|
CTL_CLOCK_PIN = config('CTL_CLOCK_PIN', cast=int)
|
||||||
|
CTL_NUMBER = config('CTL_NUMBER', cast=int)
|
||||||
|
CTL_RELAY_NUMBER = 8 * CTL_NUMBER
|
||||||
|
|
||||||
|
# YF_S201
|
||||||
|
WATERFLOW_PIN = config('WATERFLOW_PIN', cast=int)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
/* custom.css */
|
||||||
|
.w3-div-center { margin: 0 auto; }
|
||||||
|
.w3-hidden { display: none; }
|
||||||
|
.w3-no-border { border: 0px; }
|
||||||
|
.w3-no-resize { resize: none; }
|
||||||
|
.w3-resize-vertical { resize: vertical; }
|
||||||
|
.w3-resize-horizontal { resize: horiziontal; }
|
||||||
|
.w3-text-upper { text-transform: uppercase; }
|
||||||
|
.w3-transparent { background: transparent; }
|
||||||
|
.w3-nbsp { white-space: nowrap; }
|
||||||
|
a.w3-word-wrap { word-wrap: break-word; }
|
||||||
|
.w3-scroll-x { overflow-x: auto; overflow-y: hidden; }
|
||||||
|
.w3-scroll-y { overflow-x: hidden; overflow-y: auto; }
|
||||||
|
.w3-scroll { overflow: auto; }
|
||||||
|
|
||||||
|
.w3-show-off { display: none; }
|
||||||
|
.w3-show-on { display: block; }
|
||||||
|
.w3-inline { display:inline-block; vertical-align: middle;}
|
||||||
|
|
||||||
|
.w3-dropup { width:100%; overflow:hidden; display:inline-block; }
|
||||||
|
.w3-dropup-item { float:left; width:auto; border:none; display:block; outline:0; }
|
||||||
|
.w3-dropup .w3-dropup-content { display: none; position: absolute; bottom: 3.0em; z-index: 1; }
|
||||||
|
|
||||||
|
|
||||||
|
a.w3-no-deco:link,
|
||||||
|
a.w3-no-deco:visited { color: inherit; text-decoration: grey; }
|
||||||
|
a.w3-no-deco:hover { background-color: transparent; }
|
||||||
|
ul.w3-no-deco { list-style-type: none; }
|
||||||
|
hr.w3-bar-item.divider { margin: 0 .1em; padding: 0.025em; }
|
||||||
|
|
||||||
|
.zindex-0 { z-index: 0; }
|
||||||
|
.zindex-1 { z-index: 10; }
|
||||||
|
.zindex-2 { z-index: 100; }
|
||||||
|
.zindex-3 { z-index: 200; }
|
||||||
|
.zindex-4 { z-index: 400; }
|
||||||
|
|
||||||
|
.w3-no-padding,.w3-padding-0{ padding: 0; }
|
||||||
|
.w3-padding-01 { padding: .1em; }
|
||||||
|
.w3-padding-02 { padding: .2em; }
|
||||||
|
.w3-padding-1 { padding: .25em; }
|
||||||
|
.w3-padding-2 { padding: .5em; }
|
||||||
|
.w3-padding-3 { padding: .75em; }
|
||||||
|
.w3-padding-4 { padding: 1em; }
|
||||||
|
.w3-padding-5 { padding: 1.5em; }
|
||||||
|
.w3-padding-6 { padding: 2em; }
|
||||||
|
|
||||||
|
.w3-margin-auto { margin: 0 auto; }
|
||||||
|
.w3-no-margin, .w3-margin-0 { margin: 0; }
|
||||||
|
.w3-margin-01 { margin: .1em; }
|
||||||
|
.w3-margin-02 { margin: .2em; }
|
||||||
|
.w3-margin-1 { margin: .25em; }
|
||||||
|
.w3-margin-2 { margin: .5em; }
|
||||||
|
.w3-margin-3 { margin: .75em; }
|
||||||
|
.w3-margin-4 { margin: 1em; }
|
||||||
|
.w3-margin-5 { margin: 1.5em; }
|
||||||
|
.w3-margin-6 { margin: 2em; }
|
||||||
|
|
||||||
|
.w3-margin-left-1 { margin-left: .25em; }
|
||||||
|
.w3-margin-left-2 { margin-left: .5em; }
|
||||||
|
.w3-margin-left-3 { margin-left: .75em; }
|
||||||
|
.w3-margin-left-4 { margin-left: 1em; }
|
||||||
|
.w3-margin-left-5 { margin-left: 1.5em; }
|
||||||
|
.w3-margin-left-6 { margin-left: 2em; }
|
||||||
|
|
||||||
|
.w3-margin-right-1 { margin-right: .25em; }
|
||||||
|
.w3-margin-right-2 { margin-right: .5em; }
|
||||||
|
.w3-margin-right-3 { margin-right: .75em; }
|
||||||
|
.w3-margin-right-4 { margin-right: 1em; }
|
||||||
|
.w3-margin-right-5 { margin-right: 1.5em; }
|
||||||
|
.w3-margin-right-6 { margin-right: 2em; }
|
||||||
|
|
||||||
|
.w3-margin-top-1 { margin-top: .25em; }
|
||||||
|
.w3-margin-top-2 { margin-top: .5em; }
|
||||||
|
.w3-margin-top-3 { margin-top: .75em; }
|
||||||
|
.w3-margin-top-4 { margin-top: 1em; }
|
||||||
|
.w3-margin-top-5 { margin-top: 1.5em; }
|
||||||
|
.w3-margin-top-6 { margin-top: 2em; }
|
||||||
|
|
||||||
|
.w3-margin-bottom-1 { margin-bottom: .25em; }
|
||||||
|
.w3-margin-bottom-2 { margin-bottom: .5em; }
|
||||||
|
.w3-margin-bottom-3 { margin-bottom: .75em; }
|
||||||
|
.w3-margin-bottom-4 { margin-bottom: 1em; }
|
||||||
|
.w3-margin-bottom-5 { margin-bottom: 1.5em; }
|
||||||
|
.w3-margin-bottom-6 { margin-bottom: 25em; }
|
||||||
|
|
||||||
|
.w1 { width: 1%; }
|
||||||
|
.w4 { width: 4%; }
|
||||||
|
.w5 { width: 5%; }
|
||||||
|
.w9 { width: 9%; }
|
||||||
|
.w10 { width: 10%; }
|
||||||
|
.w11 { width: 11%; }
|
||||||
|
.w15 { width: 15%; }
|
||||||
|
.w20 { width: 20%; }
|
||||||
|
.w25 { width: 25%; }
|
||||||
|
.w30 { width: 30%; }
|
||||||
|
.w35 { width: 35%; }
|
||||||
|
.w40 { width: 40%; }
|
||||||
|
.w45 { width: 45%; }
|
||||||
|
.w50 { width: 50%; }
|
||||||
|
.w55 { width: 55%; }
|
||||||
|
.w60 { width: 60%; }
|
||||||
|
.w65 { width: 55%; }
|
||||||
|
.w70 { width: 70%; }
|
||||||
|
.w75 { width: 75%; }
|
||||||
|
.w80 { width: 80%; }
|
||||||
|
.w85 { width: 85%; }
|
||||||
|
.w90 { width: 90%; }
|
||||||
|
.w95 { width: 95%; }
|
||||||
|
.w100 { width: 100%; }
|
||||||
|
|
||||||
|
.w3-dark-low,.w3-hover-dark-low:hover,.w3-dark-low,.w3-hover-dark-low:hover{color:#fff!important;background-color:#111!important}
|
||||||
|
.w3-dark-medium,.w3-hover-dark-medium:hover,.w3-dark-medium,.w3-hover-dark-medium:hover{color:#fff!important;background-color:#222!important}
|
||||||
|
.w3-dark-light,.w3-hover-dark-light:hover,.w3-dark-light,.w3-hover-dark-light:hover{color:#fff!important;background-color:#333!important}
|
||||||
|
.w3-dark-xlight,.w3-hover-dark-xlight:hover,.w3-dark-xlight,.w3-hover-dark-xlight:hover{color:#fff!important;background-color:#444!important}
|
||||||
|
.w3-dark-xxlight,.w3-hover-dark-xxlight:hover,.w3-dark-xxlight,.w3-hover-dark-xxlight:hover{color:#fff!important;background-color:#555!important}
|
||||||
|
.w3-dark-hight,.w3-hover-dark-hight:hover,.w3-dark-hight,.w3-hover-dark-hight:hover{color:#fff!important;background-color:#666!important}
|
||||||
|
|
||||||
|
.w3-theme-light {color:#000 !important; background-color:#f5f7f8 !important}
|
||||||
|
.w3-theme-dark {color:#fff !important; background-color:#303e45 !important}
|
||||||
|
.w3-theme-action {color:#fff !important; background-color:#303e45 !important}
|
||||||
|
.w3-theme {color:#fff !important; background-color:#607d8b !important}
|
||||||
|
.w3-text-theme {color:#607d8b !important}
|
||||||
|
.w3-border-theme {border-color:#607d8b !important}
|
||||||
|
.w3-hover-theme:hover {color:#fff !important; background-color:#607d8b !important}
|
||||||
|
.w3-hover-text-theme:hover {color:#607d8b !important}
|
||||||
|
.w3-hover-border-theme:hover {border-color:#607d8b !important}
|
||||||
|
|
||||||
|
|
||||||
|
.w3-flex-container, .w3-flex-container-row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: start;
|
||||||
|
align-content: start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.w3-flex-container-col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: start;
|
||||||
|
align-content: start;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
.w3-flex-container-center {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
align-content: center;
|
||||||
|
align-items: top;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w3-flex-item { order: 0; flex: 0 1 auto; align-self: auto; margin: .25em;}
|
||||||
|
.w3-flex-wrap { display: flex; flex-wrap: wrap; }
|
||||||
|
.w3-flex-wrap.align { align-items: center; justify-content: center; }
|
||||||
|
|
||||||
|
.cursor-alias {cursor: alias;}
|
||||||
|
.cursor-all-scroll {cursor: all-scroll;}
|
||||||
|
.cursor-auto {cursor: auto;}
|
||||||
|
.cursor-cell {cursor: cell;}
|
||||||
|
.cursor-context-menu {cursor: context-menu;}
|
||||||
|
.cursor-col-resize {cursor: col-resize;}
|
||||||
|
.cursor-copy {cursor: copy;}
|
||||||
|
.cursor-crosshair {cursor: crosshair;}
|
||||||
|
.cursor-default {cursor: default;}
|
||||||
|
.cursor-e-resize {cursor: e-resize;}
|
||||||
|
.cursor-ew-resize {cursor: ew-resize;}
|
||||||
|
.cursor-grab {cursor: -webkit-grab; cursor: grab;}
|
||||||
|
.cursor-grabbing {cursor: -webkit-grabbing; cursor: grabbing;}
|
||||||
|
.cursor-help {cursor: help;}
|
||||||
|
.cursor-move {cursor: move;}
|
||||||
|
.cursor-n-resize {cursor: n-resize;}
|
||||||
|
.cursor-ne-resize {cursor: ne-resize;}
|
||||||
|
.cursor-nesw-resize {cursor: nesw-resize;}
|
||||||
|
.cursor-ns-resize {cursor: ns-resize;}
|
||||||
|
.cursor-nw-resize {cursor: nw-resize;}
|
||||||
|
.cursor-nwse-resize {cursor: nwse-resize;}
|
||||||
|
.cursor-no-drop {cursor: no-drop;}
|
||||||
|
.cursor-none {cursor: none;}
|
||||||
|
.cursor-not-allowed {cursor: not-allowed;}
|
||||||
|
.cursor-pointer {cursor: pointer;}
|
||||||
|
.cursor-progress {cursor: progress;}
|
||||||
|
.cursor-row-resize {cursor: row-resize;}
|
||||||
|
.cursor-s-resize {cursor: s-resize;}
|
||||||
|
.cursor-se-resize {cursor: se-resize;}
|
||||||
|
.cursor-sw-resize {cursor: sw-resize;}
|
||||||
|
.cursor-text {cursor: text;}
|
||||||
|
.cursor-w-resize {cursor: w-resize;}
|
||||||
|
.cursor-wait {cursor: wait;}
|
||||||
|
.cursor-zoom-in {cursor: zoom-in;}
|
||||||
|
.cursor-zoom-out {cursor: zoom-out;}
|
||||||
|
|
||||||
|
|
||||||
|
/* Extra small devices (phones, 600px and down) */
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
div.main-layout {background: transparent; margin:0.5em auto; width:100%; font-size: 1em; min-width:300px;}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Small devices (portrait tablets and large phones, 600px and up) */
|
||||||
|
@media only screen and (min-width: 600px) {
|
||||||
|
div.main-layout {background: transparent; margin:1em auto; width:95%; font-size: 1.1em; min-width:300px;}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Medium devices (landscape tablets, 768px and up) */
|
||||||
|
@media only screen and (min-width: 768px) {
|
||||||
|
div.main-layout {background: transparent; width:85%;font-size: 1.3em;}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Large devices (laptops/desktops, 992px and up) */
|
||||||
|
@media only screen and (min-width: 992px) {
|
||||||
|
div.main-layout {background: transparent; width:75%;}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Extra large devices (large laptops and desktops, 1200px and up) */
|
||||||
|
@media only screen and (min-width: 1200px) {
|
||||||
|
div.main-layout {background: transparent; width:70%; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
/* W3.CSS 5.02 March 31 2025 by Jan Egil and Borge Refsnes */
|
||||||
|
html{box-sizing:border-box}*,*:before,*:after{box-sizing:inherit}
|
||||||
|
/* Extract from normalize.css by Nicolas Gallagher and Jonathan Neal git.io/normalize */
|
||||||
|
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}
|
||||||
|
article,aside,details,figcaption,figure,footer,header,main,menu,nav,section{display:block}summary{display:list-item}
|
||||||
|
audio,canvas,progress,video{display:inline-block}progress{vertical-align:baseline}
|
||||||
|
audio:not([controls]){display:none;height:0}[hidden],template{display:none}
|
||||||
|
a{background-color:transparent}a:active,a:hover{outline-width:0}
|
||||||
|
abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}
|
||||||
|
b,strong{font-weight:bolder}dfn{font-style:italic}mark{background:#ff0;color:#000}
|
||||||
|
small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}
|
||||||
|
sub{bottom:-0.25em}sup{top:-0.5em}figure{margin:1em 40px}img{border-style:none}
|
||||||
|
code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}hr{box-sizing:content-box;height:0;overflow:visible}
|
||||||
|
button,input,select,textarea,optgroup{font:inherit;margin:0}optgroup{font-weight:bold}
|
||||||
|
button,input{overflow:visible}button,select{text-transform:none}
|
||||||
|
button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}
|
||||||
|
button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{border-style:none;padding:0}
|
||||||
|
button:-moz-focusring,[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring{outline:1px dotted ButtonText}
|
||||||
|
fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:.35em .625em .75em}
|
||||||
|
legend{color:inherit;display:table;max-width:100%;padding:0;white-space:normal}textarea{overflow:auto}
|
||||||
|
[type=checkbox],[type=radio]{padding:0}
|
||||||
|
[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}
|
||||||
|
[type=search]{-webkit-appearance:textfield;outline-offset:-2px}
|
||||||
|
[type=search]::-webkit-search-decoration{-webkit-appearance:none}
|
||||||
|
::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}
|
||||||
|
/* End extract */
|
||||||
|
html,body{font-family:Verdana,sans-serif;font-size:15px;line-height:1.5}html{overflow-x:hidden}
|
||||||
|
h1{font-size:36px}h2{font-size:30px}h3{font-size:24px}h4{font-size:20px}h5{font-size:18px}h6{font-size:16px}
|
||||||
|
.w3-serif{font-family:serif}.w3-sans-serif{font-family:sans-serif}.w3-cursive{font-family:cursive}.w3-monospace{font-family:monospace}
|
||||||
|
h1,h2,h3,h4,h5,h6{font-family:"Segoe UI",Arial,sans-serif;font-weight:400;margin:10px 0}.w3-wide{letter-spacing:4px}
|
||||||
|
hr{border:0;border-top:1px solid #eee;margin:20px 0}
|
||||||
|
.w3-image{max-width:100%;height:auto}img{vertical-align:middle}a{color:inherit}
|
||||||
|
.w3-table,.w3-table-all{border-collapse:collapse;border-spacing:0;width:100%;display:table}.w3-table-all{border:1px solid #ccc}
|
||||||
|
.w3-bordered tr,.w3-table-all tr{border-bottom:1px solid #ddd}.w3-striped tbody tr:nth-child(even){background-color:#f1f1f1}
|
||||||
|
.w3-table-all tr:nth-child(odd){background-color:#fff}.w3-table-all tr:nth-child(even){background-color:#f1f1f1}
|
||||||
|
.w3-hoverable tbody tr:hover,.w3-ul.w3-hoverable li:hover{background-color:#ccc}.w3-centered tr th,.w3-centered tr td{text-align:center}
|
||||||
|
.w3-table td,.w3-table th,.w3-table-all td,.w3-table-all th{padding:8px 8px;display:table-cell;text-align:left;vertical-align:top}
|
||||||
|
.w3-table th:first-child,.w3-table td:first-child,.w3-table-all th:first-child,.w3-table-all td:first-child{padding-left:16px}
|
||||||
|
.w3-btn,.w3-button{border:none;display:inline-block;padding:8px 16px;vertical-align:middle;overflow:hidden;text-decoration:none;color:inherit;background-color:inherit;text-align:center;cursor:pointer;white-space:nowrap}
|
||||||
|
.w3-btn:hover{box-shadow:0 8px 16px 0 rgba(0,0,0,0.2),0 6px 20px 0 rgba(0,0,0,0.19)}
|
||||||
|
.w3-btn,.w3-button{-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}
|
||||||
|
.w3-disabled,.w3-btn:disabled,.w3-button:disabled{cursor:not-allowed;opacity:0.3}.w3-disabled *,:disabled *{pointer-events:none}
|
||||||
|
.w3-btn.w3-disabled:hover,.w3-btn:disabled:hover{box-shadow:none}
|
||||||
|
.w3-badge,.w3-tag{background-color:#000;color:#fff;display:inline-block;padding-left:8px;padding-right:8px;text-align:center}.w3-badge{border-radius:50%}
|
||||||
|
.w3-ul{list-style-type:none;padding:0;margin:0}.w3-ul li{padding:8px 16px;border-bottom:1px solid #ddd}.w3-ul li:last-child{border-bottom:none}
|
||||||
|
.w3-tooltip,.w3-display-container{position:relative}.w3-tooltip .w3-text{display:none}.w3-tooltip:hover .w3-text{display:inline-block}
|
||||||
|
.w3-ripple:active{opacity:0.5}.w3-ripple{transition:opacity 0s}
|
||||||
|
.w3-input{padding:8px;display:block;border:none;border-bottom:1px solid #ccc;width:100%}
|
||||||
|
.w3-select{padding:9px 0;width:100%;border:none;border-bottom:1px solid #ccc}
|
||||||
|
.w3-dropdown-click,.w3-dropdown-hover{position:relative;display:inline-block;cursor:pointer}
|
||||||
|
.w3-dropdown-hover:hover .w3-dropdown-content{display:block}
|
||||||
|
.w3-dropdown-hover:first-child,.w3-dropdown-click:hover{background-color:#ccc;color:#000}
|
||||||
|
.w3-dropdown-hover:hover > .w3-button:first-child,.w3-dropdown-click:hover > .w3-button:first-child{background-color:#ccc;color:#000}
|
||||||
|
.w3-dropdown-content{cursor:auto;color:#000;background-color:#fff;display:none;position:absolute;min-width:160px;margin:0;padding:0;z-index:1}
|
||||||
|
.w3-check,.w3-radio{width:24px;height:24px;position:relative;top:6px}
|
||||||
|
.w3-sidebar{height:100%;width:200px;background-color:#fff;position:fixed!important;z-index:1;overflow:auto}
|
||||||
|
.w3-bar-block .w3-dropdown-hover,.w3-bar-block .w3-dropdown-click{width:100%}
|
||||||
|
.w3-bar-block .w3-dropdown-hover .w3-dropdown-content,.w3-bar-block .w3-dropdown-click .w3-dropdown-content{min-width:100%}
|
||||||
|
.w3-bar-block .w3-dropdown-hover .w3-button,.w3-bar-block .w3-dropdown-click .w3-button{width:100%;text-align:left;padding:8px 16px}
|
||||||
|
.w3-main,#main{transition:margin-left .4s}
|
||||||
|
.w3-modal{z-index:3;display:none;padding-top:100px;position:fixed;left:0;top:0;width:100%;height:100%;overflow:auto;background-color:rgb(0,0,0);background-color:rgba(0,0,0,0.4)}
|
||||||
|
.w3-modal-content{margin:auto;background-color:#fff;position:relative;padding:0;outline:0;width:600px}
|
||||||
|
.w3-bar{width:100%;overflow:hidden}.w3-center .w3-bar{display:inline-block;width:auto}
|
||||||
|
.w3-bar .w3-bar-item{padding:8px 16px;float:left;width:auto;border:none;display:block;outline:0}
|
||||||
|
.w3-bar .w3-dropdown-hover,.w3-bar .w3-dropdown-click{position:static;float:left}
|
||||||
|
.w3-bar .w3-button{white-space:normal}
|
||||||
|
.w3-bar-block .w3-bar-item{width:100%;display:block;padding:8px 16px;text-align:left;border:none;white-space:normal;float:none;outline:0}
|
||||||
|
.w3-bar-block.w3-center .w3-bar-item{text-align:center}.w3-block{display:block;width:100%}
|
||||||
|
.w3-responsive{display:block;overflow-x:auto}
|
||||||
|
.w3-container:after,.w3-container:before,.w3-panel:after,.w3-panel:before,.w3-row:after,.w3-row:before,.w3-row-padding:after,.w3-row-padding:before,
|
||||||
|
.w3-cell-row:before,.w3-cell-row:after,.w3-clear:after,.w3-clear:before,.w3-bar:before,.w3-bar:after{content:"";display:table;clear:both}
|
||||||
|
.w3-col,.w3-half,.w3-third,.w3-twothird,.w3-threequarter,.w3-quarter{float:left;width:100%}
|
||||||
|
.w3-col.s1{width:8.33333%}.w3-col.s2{width:16.66666%}.w3-col.s3{width:24.99999%}.w3-col.s4{width:33.33333%}
|
||||||
|
.w3-col.s5{width:41.66666%}.w3-col.s6{width:49.99999%}.w3-col.s7{width:58.33333%}.w3-col.s8{width:66.66666%}
|
||||||
|
.w3-col.s9{width:74.99999%}.w3-col.s10{width:83.33333%}.w3-col.s11{width:91.66666%}.w3-col.s12{width:99.99999%}
|
||||||
|
@media (min-width:601px){.w3-col.m1{width:8.33333%}.w3-col.m2{width:16.66666%}.w3-col.m3,.w3-quarter{width:24.99999%}.w3-col.m4,.w3-third{width:33.33333%}
|
||||||
|
.w3-col.m5{width:41.66666%}.w3-col.m6,.w3-half{width:49.99999%}.w3-col.m7{width:58.33333%}.w3-col.m8,.w3-twothird{width:66.66666%}
|
||||||
|
.w3-col.m9,.w3-threequarter{width:74.99999%}.w3-col.m10{width:83.33333%}.w3-col.m11{width:91.66666%}.w3-col.m12{width:99.99999%}}
|
||||||
|
@media (min-width:993px){.w3-col.l1{width:8.33333%}.w3-col.l2{width:16.66666%}.w3-col.l3{width:24.99999%}.w3-col.l4{width:33.33333%}
|
||||||
|
.w3-col.l5{width:41.66666%}.w3-col.l6{width:49.99999%}.w3-col.l7{width:58.33333%}.w3-col.l8{width:66.66666%}
|
||||||
|
.w3-col.l9{width:74.99999%}.w3-col.l10{width:83.33333%}.w3-col.l11{width:91.66666%}.w3-col.l12{width:99.99999%}}
|
||||||
|
.w3-rest{overflow:hidden}.w3-stretch{margin-left:-16px;margin-right:-16px}
|
||||||
|
.w3-content,.w3-auto{margin-left:auto;margin-right:auto}.w3-content{max-width:980px}.w3-auto{max-width:1140px}
|
||||||
|
.w3-cell-row{display:table;width:100%}.w3-cell{display:table-cell}
|
||||||
|
.w3-cell-top{vertical-align:top}.w3-cell-middle{vertical-align:middle}.w3-cell-bottom{vertical-align:bottom}
|
||||||
|
.w3-hide{display:none!important}.w3-show-block,.w3-show{display:block!important}.w3-show-inline-block{display:inline-block!important}
|
||||||
|
@media (max-width:1205px){.w3-auto{max-width:95%}}
|
||||||
|
@media (max-width:600px){.w3-modal-content{margin:0 10px;width:auto!important}.w3-modal{padding-top:30px}
|
||||||
|
.w3-dropdown-hover.w3-mobile .w3-dropdown-content,.w3-dropdown-click.w3-mobile .w3-dropdown-content{position:relative}
|
||||||
|
.w3-hide-small{display:none!important}.w3-mobile{display:block;width:100%!important}.w3-bar-item.w3-mobile,.w3-dropdown-hover.w3-mobile,.w3-dropdown-click.w3-mobile{text-align:center}
|
||||||
|
.w3-dropdown-hover.w3-mobile,.w3-dropdown-hover.w3-mobile .w3-btn,.w3-dropdown-hover.w3-mobile .w3-button,.w3-dropdown-click.w3-mobile,.w3-dropdown-click.w3-mobile .w3-btn,.w3-dropdown-click.w3-mobile .w3-button{width:100%}}
|
||||||
|
@media (max-width:768px){.w3-modal-content{width:500px}.w3-modal{padding-top:50px}}
|
||||||
|
@media (min-width:993px){.w3-modal-content{width:900px}.w3-hide-large{display:none!important}.w3-sidebar.w3-collapse{display:block!important}}
|
||||||
|
@media (max-width:992px) and (min-width:601px){.w3-hide-medium{display:none!important}}
|
||||||
|
@media (max-width:992px){.w3-sidebar.w3-collapse{display:none}.w3-main{margin-left:0!important;margin-right:0!important}.w3-auto{max-width:100%}}
|
||||||
|
.w3-top,.w3-bottom{position:fixed;width:100%;z-index:1}.w3-top{top:0}.w3-bottom{bottom:0}
|
||||||
|
.w3-overlay{position:fixed;display:none;width:100%;height:100%;top:0;left:0;right:0;bottom:0;background-color:rgba(0,0,0,0.5);z-index:2}
|
||||||
|
.w3-display-topleft{position:absolute;left:0;top:0}.w3-display-topright{position:absolute;right:0;top:0}
|
||||||
|
.w3-display-bottomleft{position:absolute;left:0;bottom:0}.w3-display-bottomright{position:absolute;right:0;bottom:0}
|
||||||
|
.w3-display-middle{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%)}
|
||||||
|
.w3-display-left{position:absolute;top:50%;left:0%;transform:translate(0%,-50%);-ms-transform:translate(-0%,-50%)}
|
||||||
|
.w3-display-right{position:absolute;top:50%;right:0%;transform:translate(0%,-50%);-ms-transform:translate(0%,-50%)}
|
||||||
|
.w3-display-topmiddle{position:absolute;left:50%;top:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
||||||
|
.w3-display-bottommiddle{position:absolute;left:50%;bottom:0;transform:translate(-50%,0%);-ms-transform:translate(-50%,0%)}
|
||||||
|
.w3-display-container:hover .w3-display-hover{display:block}.w3-display-container:hover span.w3-display-hover{display:inline-block}.w3-display-hover{display:none}
|
||||||
|
.w3-display-position{position:absolute}
|
||||||
|
.w3-circle{border-radius:50%}
|
||||||
|
.w3-round-small{border-radius:2px}.w3-round,.w3-round-medium{border-radius:4px}.w3-round-large{border-radius:8px}.w3-round-xlarge{border-radius:16px}.w3-round-xxlarge{border-radius:32px}
|
||||||
|
.w3-row-padding,.w3-row-padding>.w3-half,.w3-row-padding>.w3-third,.w3-row-padding>.w3-twothird,.w3-row-padding>.w3-threequarter,.w3-row-padding>.w3-quarter,.w3-row-padding>.w3-col{padding:0 8px}
|
||||||
|
.w3-container,.w3-panel{padding:0.01em 16px}.w3-panel{margin-top:16px;margin-bottom:16px}
|
||||||
|
.w3-grid{display:grid}.w3-grid-padding{display:grid;gap:16px}.w3-flex{display:flex}
|
||||||
|
.w3-text-center{text-align:center}.w3-text-bold,.w3-bold{font-weight:bold}.w3-text-italic,.w3-italic{font-style:italic}
|
||||||
|
.w3-code,.w3-codespan{font-family:Consolas,"courier new";font-size:16px}
|
||||||
|
.w3-code{width:auto;background-color:#fff;padding:8px 12px;border-left:4px solid #4CAF50;word-wrap:break-word}
|
||||||
|
.w3-codespan{color:crimson;background-color:#f1f1f1;padding-left:4px;padding-right:4px;font-size:110%}
|
||||||
|
.w3-card,.w3-card-2{box-shadow:0 2px 5px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12)}
|
||||||
|
.w3-card-4,.w3-hover-shadow:hover{box-shadow:0 4px 10px 0 rgba(0,0,0,0.2),0 4px 20px 0 rgba(0,0,0,0.19)}
|
||||||
|
.w3-spin{animation:w3-spin 2s infinite linear}@keyframes w3-spin{0%{transform:rotate(0deg)}100%{transform:rotate(359deg)}}
|
||||||
|
.w3-animate-fading{animation:fading 10s infinite}@keyframes fading{0%{opacity:0}50%{opacity:1}100%{opacity:0}}
|
||||||
|
.w3-animate-opacity{animation:opac 0.8s}@keyframes opac{from{opacity:0} to{opacity:1}}
|
||||||
|
.w3-animate-top{position:relative;animation:animatetop 0.4s}@keyframes animatetop{from{top:-300px;opacity:0} to{top:0;opacity:1}}
|
||||||
|
.w3-animate-left{position:relative;animation:animateleft 0.4s}@keyframes animateleft{from{left:-300px;opacity:0} to{left:0;opacity:1}}
|
||||||
|
.w3-animate-right{position:relative;animation:animateright 0.4s}@keyframes animateright{from{right:-300px;opacity:0} to{right:0;opacity:1}}
|
||||||
|
.w3-animate-bottom{position:relative;animation:animatebottom 0.4s}@keyframes animatebottom{from{bottom:-300px;opacity:0} to{bottom:0;opacity:1}}
|
||||||
|
.w3-animate-zoom {animation:animatezoom 0.6s}@keyframes animatezoom{from{transform:scale(0)} to{transform:scale(1)}}
|
||||||
|
.w3-animate-input{transition:width 0.4s ease-in-out}.w3-animate-input:focus{width:100%!important}
|
||||||
|
.w3-opacity,.w3-hover-opacity:hover{opacity:0.60}.w3-opacity-off,.w3-hover-opacity-off:hover{opacity:1}
|
||||||
|
.w3-opacity-max{opacity:0.25}.w3-opacity-min{opacity:0.75}
|
||||||
|
.w3-greyscale-max,.w3-grayscale-max,.w3-hover-greyscale:hover,.w3-hover-grayscale:hover{filter:grayscale(100%)}
|
||||||
|
.w3-greyscale,.w3-grayscale{filter:grayscale(75%)}.w3-greyscale-min,.w3-grayscale-min{filter:grayscale(50%)}
|
||||||
|
.w3-sepia{filter:sepia(75%)}.w3-sepia-max,.w3-hover-sepia:hover{filter:sepia(100%)}.w3-sepia-min{filter:sepia(50%)}
|
||||||
|
.w3-tiny{font-size:10px!important}.w3-small{font-size:12px!important}.w3-medium{font-size:15px!important}.w3-large{font-size:18px!important}
|
||||||
|
.w3-xlarge{font-size:24px!important}.w3-xxlarge{font-size:36px!important}.w3-xxxlarge{font-size:48px!important}.w3-jumbo{font-size:64px!important}
|
||||||
|
.w3-left-align{text-align:left!important}.w3-right-align{text-align:right!important}.w3-justify{text-align:justify!important}.w3-center{text-align:center!important}
|
||||||
|
.w3-border-0{border:0!important}.w3-border{border:1px solid #ccc!important}
|
||||||
|
.w3-border-top{border-top:1px solid #ccc!important}.w3-border-bottom{border-bottom:1px solid #ccc!important}
|
||||||
|
.w3-border-left{border-left:1px solid #ccc!important}.w3-border-right{border-right:1px solid #ccc!important}
|
||||||
|
.w3-topbar{border-top:6px solid #ccc!important}.w3-bottombar{border-bottom:6px solid #ccc!important}
|
||||||
|
.w3-leftbar{border-left:6px solid #ccc!important}.w3-rightbar{border-right:6px solid #ccc!important}
|
||||||
|
.w3-section,.w3-code{margin-top:16px!important;margin-bottom:16px!important}
|
||||||
|
.w3-margin{margin:16px!important}.w3-margin-top{margin-top:16px!important}.w3-margin-bottom{margin-bottom:16px!important}
|
||||||
|
.w3-margin-left{margin-left:16px!important}.w3-margin-right{margin-right:16px!important}
|
||||||
|
.w3-padding-small{padding:4px 8px!important}.w3-padding{padding:8px 16px!important}.w3-padding-large{padding:12px 24px!important}
|
||||||
|
.w3-padding-16{padding-top:16px!important;padding-bottom:16px!important}.w3-padding-24{padding-top:24px!important;padding-bottom:24px!important}
|
||||||
|
.w3-padding-32{padding-top:32px!important;padding-bottom:32px!important}.w3-padding-48{padding-top:48px!important;padding-bottom:48px!important}
|
||||||
|
.w3-padding-64{padding-top:64px!important;padding-bottom:64px!important}
|
||||||
|
.w3-padding-top-64{padding-top:64px!important}.w3-padding-top-48{padding-top:48px!important}
|
||||||
|
.w3-padding-top-32{padding-top:32px!important}.w3-padding-top-24{padding-top:24px!important}
|
||||||
|
.w3-left{float:left!important}.w3-right{float:right!important}
|
||||||
|
.w3-button:hover{color:#000!important;background-color:#ccc!important}
|
||||||
|
.w3-transparent,.w3-hover-none:hover{background-color:transparent!important}
|
||||||
|
.w3-hover-none:hover{box-shadow:none!important}
|
||||||
|
.w3-rtl{direction:rtl}.w3-ltr{direction:ltr}
|
||||||
|
/* Colors */
|
||||||
|
.w3-amber,.w3-hover-amber:hover{color:#000!important;background-color:#ffc107!important}
|
||||||
|
.w3-aqua,.w3-hover-aqua:hover{color:#000!important;background-color:#00ffff!important}
|
||||||
|
.w3-blue,.w3-hover-blue:hover{color:#fff!important;background-color:#2196F3!important}
|
||||||
|
.w3-light-blue,.w3-hover-light-blue:hover{color:#000!important;background-color:#87CEEB!important}
|
||||||
|
.w3-brown,.w3-hover-brown:hover{color:#fff!important;background-color:#795548!important}
|
||||||
|
.w3-cyan,.w3-hover-cyan:hover{color:#000!important;background-color:#00bcd4!important}
|
||||||
|
.w3-blue-grey,.w3-hover-blue-grey:hover,.w3-blue-gray,.w3-hover-blue-gray:hover{color:#fff!important;background-color:#607d8b!important}
|
||||||
|
.w3-green,.w3-hover-green:hover{color:#fff!important;background-color:#4CAF50!important}
|
||||||
|
.w3-light-green,.w3-hover-light-green:hover{color:#000!important;background-color:#8bc34a!important}
|
||||||
|
.w3-indigo,.w3-hover-indigo:hover{color:#fff!important;background-color:#3f51b5!important}
|
||||||
|
.w3-khaki,.w3-hover-khaki:hover{color:#000!important;background-color:#f0e68c!important}
|
||||||
|
.w3-lime,.w3-hover-lime:hover{color:#000!important;background-color:#cddc39!important}
|
||||||
|
.w3-orange,.w3-hover-orange:hover{color:#000!important;background-color:#ff9800!important}
|
||||||
|
.w3-deep-orange,.w3-hover-deep-orange:hover{color:#fff!important;background-color:#ff5722!important}
|
||||||
|
.w3-pink,.w3-hover-pink:hover{color:#fff!important;background-color:#e91e63!important}
|
||||||
|
.w3-purple,.w3-hover-purple:hover{color:#fff!important;background-color:#9c27b0!important}
|
||||||
|
.w3-deep-purple,.w3-hover-deep-purple:hover{color:#fff!important;background-color:#673ab7!important}
|
||||||
|
.w3-red,.w3-hover-red:hover{color:#fff!important;background-color:#f44336!important}
|
||||||
|
.w3-sand,.w3-hover-sand:hover{color:#000!important;background-color:#fdf5e6!important}
|
||||||
|
.w3-teal,.w3-hover-teal:hover{color:#fff!important;background-color:#009688!important}
|
||||||
|
.w3-yellow,.w3-hover-yellow:hover{color:#000!important;background-color:#ffeb3b!important}
|
||||||
|
.w3-white,.w3-hover-white:hover{color:#000!important;background-color:#fff!important}
|
||||||
|
.w3-black,.w3-hover-black:hover{color:#fff!important;background-color:#000!important}
|
||||||
|
.w3-grey,.w3-hover-grey:hover,.w3-gray,.w3-hover-gray:hover{color:#000!important;background-color:#9e9e9e!important}
|
||||||
|
.w3-light-grey,.w3-hover-light-grey:hover,.w3-light-gray,.w3-hover-light-gray:hover{color:#000!important;background-color:#f1f1f1!important}
|
||||||
|
.w3-dark-grey,.w3-hover-dark-grey:hover,.w3-dark-gray,.w3-hover-dark-gray:hover{color:#fff!important;background-color:#616161!important}
|
||||||
|
.w3-asphalt,.w3-hover-asphalt:hover{color:#fff!important;background-color:#343a40!important}
|
||||||
|
.w3-crimson,.w3-hover-crimson:hover{color:#fff!important;background-color:#a20025!important}
|
||||||
|
.w3-cobalt,w3-hover-cobalt:hover{color:#fff!important;background-color:#0050ef!important}
|
||||||
|
.w3-emerald,.w3-hover-emerald:hover{color:#fff!important;background-color:#008a00!important}
|
||||||
|
.w3-olive,.w3-hover-olive:hover{color:#fff!important;background-color:#6d8764!important}
|
||||||
|
.w3-paper,.w3-hover-paper:hover{color:#000!important;background-color:#f8f9fa!important}
|
||||||
|
.w3-sienna,.w3-hover-sienna:hover{color:#fff!important;background-color:#a0522d!important}
|
||||||
|
.w3-taupe,.w3-hover-taupe:hover{color:#fff!important;background-color:#87794e!important}
|
||||||
|
.w3-danger{color:#fff!important;background-color:#dd0000!important}
|
||||||
|
.w3-note{color:#000!important;background-color:#fff599!important}
|
||||||
|
.w3-info{color:#fff!important;background-color:#0a6fc2!important}
|
||||||
|
.w3-warning{color:#000!important;background-color:#ffb305!important}
|
||||||
|
.w3-success{color:#fff!important;background-color:#008a00!important}
|
||||||
|
.w3-pale-red,.w3-hover-pale-red:hover{color:#000!important;background-color:#ffdddd!important}
|
||||||
|
.w3-pale-green,.w3-hover-pale-green:hover{color:#000!important;background-color:#ddffdd!important}
|
||||||
|
.w3-pale-yellow,.w3-hover-pale-yellow:hover{color:#000!important;background-color:#ffffcc!important}
|
||||||
|
.w3-pale-blue,.w3-hover-pale-blue:hover{color:#000!important;background-color:#ddffff!important}
|
||||||
|
.w3-text-amber,.w3-hover-text-amber:hover{color:#ffc107!important}
|
||||||
|
.w3-text-aqua,.w3-hover-text-aqua:hover{color:#00ffff!important}
|
||||||
|
.w3-text-blue,.w3-hover-text-blue:hover{color:#2196F3!important}
|
||||||
|
.w3-text-light-blue,.w3-hover-text-light-blue:hover{color:#87CEEB!important}
|
||||||
|
.w3-text-brown,.w3-hover-text-brown:hover{color:#795548!important}
|
||||||
|
.w3-text-cyan,.w3-hover-text-cyan:hover{color:#00bcd4!important}
|
||||||
|
.w3-text-blue-grey,.w3-hover-text-blue-grey:hover,.w3-text-blue-gray,.w3-hover-text-blue-gray:hover{color:#607d8b!important}
|
||||||
|
.w3-text-green,.w3-hover-text-green:hover{color:#4CAF50!important}
|
||||||
|
.w3-text-light-green,.w3-hover-text-light-green:hover{color:#8bc34a!important}
|
||||||
|
.w3-text-indigo,.w3-hover-text-indigo:hover{color:#3f51b5!important}
|
||||||
|
.w3-text-khaki,.w3-hover-text-khaki:hover{color:#b4aa50!important}
|
||||||
|
.w3-text-lime,.w3-hover-text-lime:hover{color:#cddc39!important}
|
||||||
|
.w3-text-orange,.w3-hover-text-orange:hover{color:#ff9800!important}
|
||||||
|
.w3-text-deep-orange,.w3-hover-text-deep-orange:hover{color:#ff5722!important}
|
||||||
|
.w3-text-pink,.w3-hover-text-pink:hover{color:#e91e63!important}
|
||||||
|
.w3-text-purple,.w3-hover-text-purple:hover{color:#9c27b0!important}
|
||||||
|
.w3-text-deep-purple,.w3-hover-text-deep-purple:hover{color:#673ab7!important}
|
||||||
|
.w3-text-red,.w3-hover-text-red:hover{color:#f44336!important}
|
||||||
|
.w3-text-sand,.w3-hover-text-sand:hover{color:#fdf5e6!important}
|
||||||
|
.w3-text-teal,.w3-hover-text-teal:hover{color:#009688!important}
|
||||||
|
.w3-text-yellow,.w3-hover-text-yellow:hover{color:#d2be0e!important}
|
||||||
|
.w3-text-white,.w3-hover-text-white:hover{color:#fff!important}
|
||||||
|
.w3-text-black,.w3-hover-text-black:hover{color:#000!important}
|
||||||
|
.w3-text-grey,.w3-hover-text-grey:hover,.w3-text-gray,.w3-hover-text-gray:hover{color:#757575!important}
|
||||||
|
.w3-text-light-grey,.w3-hover-text-light-grey:hover,.w3-text-light-gray,.w3-hover-text-light-gray:hover{color:#f1f1f1!important}
|
||||||
|
.w3-text-dark-grey,.w3-hover-text-dark-grey:hover,.w3-text-dark-gray,.w3-hover-text-dark-gray:hover{color:#3a3a3a!important}
|
||||||
|
.w3-border-amber,.w3-hover-border-amber:hover{border-color:#ffc107!important}
|
||||||
|
.w3-border-aqua,.w3-hover-border-aqua:hover{border-color:#00ffff!important}
|
||||||
|
.w3-border-blue,.w3-hover-border-blue:hover{border-color:#2196F3!important}
|
||||||
|
.w3-border-light-blue,.w3-hover-border-light-blue:hover{border-color:#87CEEB!important}
|
||||||
|
.w3-border-brown,.w3-hover-border-brown:hover{border-color:#795548!important}
|
||||||
|
.w3-border-cyan,.w3-hover-border-cyan:hover{border-color:#00bcd4!important}
|
||||||
|
.w3-border-blue-grey,.w3-hover-border-blue-grey:hover,.w3-border-blue-gray,.w3-hover-border-blue-gray:hover{border-color:#607d8b!important}
|
||||||
|
.w3-border-green,.w3-hover-border-green:hover{border-color:#4CAF50!important}
|
||||||
|
.w3-border-light-green,.w3-hover-border-light-green:hover{border-color:#8bc34a!important}
|
||||||
|
.w3-border-indigo,.w3-hover-border-indigo:hover{border-color:#3f51b5!important}
|
||||||
|
.w3-border-khaki,.w3-hover-border-khaki:hover{border-color:#f0e68c!important}
|
||||||
|
.w3-border-lime,.w3-hover-border-lime:hover{border-color:#cddc39!important}
|
||||||
|
.w3-border-orange,.w3-hover-border-orange:hover{border-color:#ff9800!important}
|
||||||
|
.w3-border-deep-orange,.w3-hover-border-deep-orange:hover{border-color:#ff5722!important}
|
||||||
|
.w3-border-pink,.w3-hover-border-pink:hover{border-color:#e91e63!important}
|
||||||
|
.w3-border-purple,.w3-hover-border-purple:hover{border-color:#9c27b0!important}
|
||||||
|
.w3-border-deep-purple,.w3-hover-border-deep-purple:hover{border-color:#673ab7!important}
|
||||||
|
.w3-border-red,.w3-hover-border-red:hover{border-color:#f44336!important}
|
||||||
|
.w3-border-sand,.w3-hover-border-sand:hover{border-color:#fdf5e6!important}
|
||||||
|
.w3-border-teal,.w3-hover-border-teal:hover{border-color:#009688!important}
|
||||||
|
.w3-border-yellow,.w3-hover-border-yellow:hover{border-color:#ffeb3b!important}
|
||||||
|
.w3-border-white,.w3-hover-border-white:hover{border-color:#fff!important}
|
||||||
|
.w3-border-black,.w3-hover-border-black:hover{border-color:#000!important}
|
||||||
|
.w3-border-grey,.w3-hover-border-grey:hover,.w3-border-gray,.w3-hover-border-gray:hover{border-color:#9e9e9e!important}
|
||||||
|
.w3-border-light-grey,.w3-hover-border-light-grey:hover,.w3-border-light-gray,.w3-hover-border-light-gray:hover{border-color:#f1f1f1!important}
|
||||||
|
.w3-border-dark-grey,.w3-hover-border-dark-grey:hover,.w3-border-dark-gray,.w3-hover-border-dark-gray:hover{border-color:#616161!important}
|
||||||
|
.w3-border-pale-red,.w3-hover-border-pale-red:hover{border-color:#ffe7e7!important}.w3-border-pale-green,.w3-hover-border-pale-green:hover{border-color:#e7ffe7!important}
|
||||||
|
.w3-border-pale-yellow,.w3-hover-border-pale-yellow:hover{border-color:#ffffcc!important}.w3-border-pale-blue,.w3-hover-border-pale-blue:hover{border-color:#e7ffff!important}
|
||||||
|
After Width: | Height: | Size: 82 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 8.1 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
** custom.js
|
||||||
|
** GNU GENERAL PUBLIC LICENSE: (c) DD miraceti.net return document.querySelectorAll(id);
|
||||||
|
*/
|
||||||
|
let s = function(sel) { return document.querySelector(sel); };
|
||||||
|
let ss = function(sel) { return document.querySelectorAll(sel); };
|
||||||
|
let sId = function(sel) { return document.getElementById(sel); };
|
||||||
|
let isJsonObject = function(value) { return value !== undefined && value !== null && typeof value === 'object'; }
|
||||||
|
|
||||||
|
let sidebarOpen = function(width, left, right) { right.style.marginLeft=width; left.style.width=width; left.style.display="block"; };
|
||||||
|
let sidebarClose = function(left, right) { right.style.marginLeft="0"; left.style.display="none"; }
|
||||||
|
let sidebarAction = function(width, left, right) { (left.style.display==="none") ? sidebarOpen(width, left, right): sidebarClose(left, right); };
|
||||||
|
let goFullscreen = function() { if (!document.fullscreenElement) { document.documentElement.requestFullscreen(); } else { document.exitFullscreen(); } };
|
||||||
|
|
||||||
|
let uuidFromId = function(id) { return id.getAttribute('id').split('-')[1]; }
|
||||||
|
let strReplace = function(str, c) { return str.replace(/\s+g/, c); };
|
||||||
|
let rtrim = function(str, c) { return str.replace(/\s+$/, c); };
|
||||||
|
let ltrim = function(str, c) { return str.replace(/^\s+/, c); };
|
||||||
|
let lastString = function(str, c) { let n = str.split(c); return n[n.length - 1]; };
|
||||||
|
|
||||||
|
let toggleCheckboxesByName = function(name) {
|
||||||
|
const boxes = document.querySelectorAll(`input[type="checkbox"][name="${name}"]`);
|
||||||
|
const shouldCheck = Array.from(boxes).some(b => !b.checked);
|
||||||
|
boxes.forEach(b => b.checked = shouldCheck);
|
||||||
|
};
|
||||||
|
|
||||||
|
let toggleDisplay = function(el) {
|
||||||
|
const current = window.getComputedStyle(el).display;
|
||||||
|
el.style.display = (current === 'none') ? 'block': 'none';
|
||||||
|
};
|
||||||
|
|
||||||
|
function toLocalISOString(date) {
|
||||||
|
const offset = date.getTimezoneOffset() * 60000; // Convertir le décalage en millisecondes
|
||||||
|
const localDate = new Date(date.getTime() - offset);
|
||||||
|
return localDate.toISOString().slice(0, -1); // Retire le 'Z' final
|
||||||
|
}
|
||||||
|
|
||||||
|
function timestampToLocalISOString(timestamp) {
|
||||||
|
const date = new Date(timestamp);
|
||||||
|
return toLocalISOString(date);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,400 @@
|
|||||||
|
/* W3.JS 1.04 April 2019 by w3schools.com */
|
||||||
|
"use strict";
|
||||||
|
var w3 = {};
|
||||||
|
w3.hide = function (sel) {
|
||||||
|
w3.hideElements(w3.getElements(sel));
|
||||||
|
};
|
||||||
|
w3.hideElements = function (elements) {
|
||||||
|
var i, l = elements.length;
|
||||||
|
for (i = 0; i < l; i++) {
|
||||||
|
w3.hideElement(elements[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w3.hideElement = function (element) {
|
||||||
|
w3.styleElement(element, "display", "none");
|
||||||
|
};
|
||||||
|
w3.show = function (sel, a) {
|
||||||
|
var elements = w3.getElements(sel);
|
||||||
|
if (a) {w3.hideElements(elements);}
|
||||||
|
w3.showElements(elements);
|
||||||
|
};
|
||||||
|
w3.showElements = function (elements) {
|
||||||
|
var i, l = elements.length;
|
||||||
|
for (i = 0; i < l; i++) {
|
||||||
|
w3.showElement(elements[i]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w3.showElement = function (element) {
|
||||||
|
w3.styleElement(element, "display", "block");
|
||||||
|
};
|
||||||
|
w3.addStyle = function (sel, prop, val) {
|
||||||
|
w3.styleElements(w3.getElements(sel), prop, val);
|
||||||
|
};
|
||||||
|
w3.styleElements = function (elements, prop, val) {
|
||||||
|
var i, l = elements.length;
|
||||||
|
for (i = 0; i < l; i++) {
|
||||||
|
w3.styleElement(elements[i], prop, val);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w3.styleElement = function (element, prop, val) {
|
||||||
|
element.style.setProperty(prop, val);
|
||||||
|
};
|
||||||
|
w3.toggleShow = function (sel) {
|
||||||
|
var i, x = w3.getElements(sel), l = x.length;
|
||||||
|
for (i = 0; i < l; i++) {
|
||||||
|
if (x[i].style.display == "none") {
|
||||||
|
w3.styleElement(x[i], "display", "block");
|
||||||
|
} else {
|
||||||
|
w3.styleElement(x[i], "display", "none");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w3.addClass = function (sel, name) {
|
||||||
|
w3.addClassElements(w3.getElements(sel), name);
|
||||||
|
};
|
||||||
|
w3.addClassElements = function (elements, name) {
|
||||||
|
var i, l = elements.length;
|
||||||
|
for (i = 0; i < l; i++) {
|
||||||
|
w3.addClassElement(elements[i], name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w3.addClassElement = function (element, name) {
|
||||||
|
var i, arr1, arr2;
|
||||||
|
arr1 = element.className.split(" ");
|
||||||
|
arr2 = name.split(" ");
|
||||||
|
for (i = 0; i < arr2.length; i++) {
|
||||||
|
if (arr1.indexOf(arr2[i]) == -1) {element.className += " " + arr2[i];}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w3.removeClass = function (sel, name) {
|
||||||
|
w3.removeClassElements(w3.getElements(sel), name);
|
||||||
|
};
|
||||||
|
w3.removeClassElements = function (elements, name) {
|
||||||
|
var i, l = elements.length, arr1, arr2, j;
|
||||||
|
for (i = 0; i < l; i++) {
|
||||||
|
w3.removeClassElement(elements[i], name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w3.removeClassElement = function (element, name) {
|
||||||
|
var i, arr1, arr2;
|
||||||
|
arr1 = element.className.split(" ");
|
||||||
|
arr2 = name.split(" ");
|
||||||
|
for (i = 0; i < arr2.length; i++) {
|
||||||
|
while (arr1.indexOf(arr2[i]) > -1) {
|
||||||
|
arr1.splice(arr1.indexOf(arr2[i]), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
element.className = arr1.join(" ");
|
||||||
|
};
|
||||||
|
w3.toggleClass = function (sel, c1, c2) {
|
||||||
|
w3.toggleClassElements(w3.getElements(sel), c1, c2);
|
||||||
|
};
|
||||||
|
w3.toggleClassElements = function (elements, c1, c2) {
|
||||||
|
var i, l = elements.length;
|
||||||
|
for (i = 0; i < l; i++) {
|
||||||
|
w3.toggleClassElement(elements[i], c1, c2);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w3.toggleClassElement = function (element, c1, c2) {
|
||||||
|
var t1, t2, t1Arr, t2Arr, j, arr, allPresent;
|
||||||
|
t1 = (c1 || "");
|
||||||
|
t2 = (c2 || "");
|
||||||
|
t1Arr = t1.split(" ");
|
||||||
|
t2Arr = t2.split(" ");
|
||||||
|
arr = element.className.split(" ");
|
||||||
|
if (t2Arr.length == 0) {
|
||||||
|
allPresent = true;
|
||||||
|
for (j = 0; j < t1Arr.length; j++) {
|
||||||
|
if (arr.indexOf(t1Arr[j]) == -1) {allPresent = false;}
|
||||||
|
}
|
||||||
|
if (allPresent) {
|
||||||
|
w3.removeClassElement(element, t1);
|
||||||
|
} else {
|
||||||
|
w3.addClassElement(element, t1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
allPresent = true;
|
||||||
|
for (j = 0; j < t1Arr.length; j++) {
|
||||||
|
if (arr.indexOf(t1Arr[j]) == -1) {allPresent = false;}
|
||||||
|
}
|
||||||
|
if (allPresent) {
|
||||||
|
w3.removeClassElement(element, t1);
|
||||||
|
w3.addClassElement(element, t2);
|
||||||
|
} else {
|
||||||
|
w3.removeClassElement(element, t2);
|
||||||
|
w3.addClassElement(element, t1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w3.getElements = function (id) {
|
||||||
|
if (typeof id == "object") {
|
||||||
|
return [id];
|
||||||
|
} else {
|
||||||
|
return document.querySelectorAll(id);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w3.filterHTML = function(id, sel, filter) {
|
||||||
|
var a, b, c, i, ii, iii, hit;
|
||||||
|
a = w3.getElements(id);
|
||||||
|
for (i = 0; i < a.length; i++) {
|
||||||
|
b = a[i].querySelectorAll(sel);
|
||||||
|
for (ii = 0; ii < b.length; ii++) {
|
||||||
|
hit = 0;
|
||||||
|
if (b[ii].innerText.toUpperCase().indexOf(filter.toUpperCase()) > -1) {
|
||||||
|
hit = 1;
|
||||||
|
}
|
||||||
|
c = b[ii].getElementsByTagName("*");
|
||||||
|
for (iii = 0; iii < c.length; iii++) {
|
||||||
|
if (c[iii].innerText.toUpperCase().indexOf(filter.toUpperCase()) > -1) {
|
||||||
|
hit = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hit == 1) {
|
||||||
|
b[ii].style.display = "";
|
||||||
|
} else {
|
||||||
|
b[ii].style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w3.sortHTML = function(id, sel, sortvalue) {
|
||||||
|
var a, b, i, ii, y, bytt, v1, v2, cc, j;
|
||||||
|
a = w3.getElements(id);
|
||||||
|
for (i = 0; i < a.length; i++) {
|
||||||
|
for (j = 0; j < 2; j++) {
|
||||||
|
cc = 0;
|
||||||
|
y = 1;
|
||||||
|
while (y == 1) {
|
||||||
|
y = 0;
|
||||||
|
b = a[i].querySelectorAll(sel);
|
||||||
|
for (ii = 0; ii < (b.length - 1); ii++) {
|
||||||
|
bytt = 0;
|
||||||
|
if (sortvalue) {
|
||||||
|
v1 = b[ii].querySelector(sortvalue).innerText;
|
||||||
|
v2 = b[ii + 1].querySelector(sortvalue).innerText;
|
||||||
|
} else {
|
||||||
|
v1 = b[ii].innerText;
|
||||||
|
v2 = b[ii + 1].innerText;
|
||||||
|
}
|
||||||
|
v1 = v1.toLowerCase();
|
||||||
|
v2 = v2.toLowerCase();
|
||||||
|
if ((j == 0 && (v1 > v2)) || (j == 1 && (v1 < v2))) {
|
||||||
|
bytt = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (bytt == 1) {
|
||||||
|
b[ii].parentNode.insertBefore(b[ii + 1], b[ii]);
|
||||||
|
y = 1;
|
||||||
|
cc++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cc > 0) {break;}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w3.slideshow = function (sel, ms, func) {
|
||||||
|
var i, ss, x = w3.getElements(sel), l = x.length;
|
||||||
|
ss = {};
|
||||||
|
ss.current = 1;
|
||||||
|
ss.x = x;
|
||||||
|
ss.ondisplaychange = func;
|
||||||
|
if (!isNaN(ms) || ms == 0) {
|
||||||
|
ss.milliseconds = ms;
|
||||||
|
} else {
|
||||||
|
ss.milliseconds = 1000;
|
||||||
|
}
|
||||||
|
ss.start = function() {
|
||||||
|
ss.display(ss.current)
|
||||||
|
if (ss.ondisplaychange) {ss.ondisplaychange();}
|
||||||
|
if (ss.milliseconds > 0) {
|
||||||
|
window.clearTimeout(ss.timeout);
|
||||||
|
ss.timeout = window.setTimeout(ss.next, ss.milliseconds);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ss.next = function() {
|
||||||
|
ss.current += 1;
|
||||||
|
if (ss.current > ss.x.length) {ss.current = 1;}
|
||||||
|
ss.start();
|
||||||
|
};
|
||||||
|
ss.previous = function() {
|
||||||
|
ss.current -= 1;
|
||||||
|
if (ss.current < 1) {ss.current = ss.x.length;}
|
||||||
|
ss.start();
|
||||||
|
};
|
||||||
|
ss.display = function (n) {
|
||||||
|
w3.styleElements(ss.x, "display", "none");
|
||||||
|
w3.styleElement(ss.x[n - 1], "display", "block");
|
||||||
|
}
|
||||||
|
ss.start();
|
||||||
|
return ss;
|
||||||
|
};
|
||||||
|
w3.includeHTML = function(cb) {
|
||||||
|
var z, i, elmnt, file, xhttp;
|
||||||
|
z = document.getElementsByTagName("*");
|
||||||
|
for (i = 0; i < z.length; i++) {
|
||||||
|
elmnt = z[i];
|
||||||
|
file = elmnt.getAttribute("w3-include-html");
|
||||||
|
if (file) {
|
||||||
|
xhttp = new XMLHttpRequest();
|
||||||
|
xhttp.onreadystatechange = function() {
|
||||||
|
if (this.readyState == 4) {
|
||||||
|
if (this.status == 200) {elmnt.innerHTML = this.responseText;}
|
||||||
|
if (this.status == 404) {elmnt.innerHTML = "Page not found.";}
|
||||||
|
elmnt.removeAttribute("w3-include-html");
|
||||||
|
w3.includeHTML(cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhttp.open("GET", file, true);
|
||||||
|
xhttp.send();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cb) cb();
|
||||||
|
};
|
||||||
|
w3.getHttpData = function (file, func) {
|
||||||
|
w3.http(file, function () {
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
func(this.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
w3.getHttpObject = function (file, func) {
|
||||||
|
w3.http(file, function () {
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
func(JSON.parse(this.responseText));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
w3.displayHttp = function (id, file) {
|
||||||
|
w3.http(file, function () {
|
||||||
|
if (this.readyState == 4 && this.status == 200) {
|
||||||
|
w3.displayObject(id, JSON.parse(this.responseText));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
w3.http = function (target, readyfunc, xml, method) {
|
||||||
|
var httpObj;
|
||||||
|
if (!method) {method = "GET"; }
|
||||||
|
if (window.XMLHttpRequest) {
|
||||||
|
httpObj = new XMLHttpRequest();
|
||||||
|
} else if (window.ActiveXObject) {
|
||||||
|
httpObj = new ActiveXObject("Microsoft.XMLHTTP");
|
||||||
|
}
|
||||||
|
if (httpObj) {
|
||||||
|
if (readyfunc) {httpObj.onreadystatechange = readyfunc;}
|
||||||
|
httpObj.open(method, target, true);
|
||||||
|
httpObj.send(xml);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
w3.getElementsByAttribute = function (x, att) {
|
||||||
|
var arr = [], arrCount = -1, i, l, y = x.getElementsByTagName("*"), z = att.toUpperCase();
|
||||||
|
l = y.length;
|
||||||
|
for (i = -1; i < l; i += 1) {
|
||||||
|
if (i == -1) {y[i] = x;}
|
||||||
|
if (y[i].getAttribute(z) !== null) {arrCount += 1; arr[arrCount] = y[i];}
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
};
|
||||||
|
w3.dataObject = {},
|
||||||
|
w3.displayObject = function (id, data) {
|
||||||
|
var htmlObj, htmlTemplate, html, arr = [], a, l, rowClone, x, j, i, ii, cc, repeat, repeatObj, repeatX = "";
|
||||||
|
htmlObj = document.getElementById(id);
|
||||||
|
htmlTemplate = init_template(id, htmlObj);
|
||||||
|
html = htmlTemplate.cloneNode(true);
|
||||||
|
arr = w3.getElementsByAttribute(html, "w3-repeat");
|
||||||
|
l = arr.length;
|
||||||
|
for (j = (l - 1); j >= 0; j -= 1) {
|
||||||
|
cc = arr[j].getAttribute("w3-repeat").split(" ");
|
||||||
|
if (cc.length == 1) {
|
||||||
|
repeat = cc[0];
|
||||||
|
} else {
|
||||||
|
repeatX = cc[0];
|
||||||
|
repeat = cc[2];
|
||||||
|
}
|
||||||
|
arr[j].removeAttribute("w3-repeat");
|
||||||
|
repeatObj = data[repeat];
|
||||||
|
if (repeatObj && typeof repeatObj == "object" && repeatObj.length != "undefined") {
|
||||||
|
i = 0;
|
||||||
|
for (x in repeatObj) {
|
||||||
|
i += 1;
|
||||||
|
rowClone = arr[j];
|
||||||
|
rowClone = w3_replace_curly(rowClone, "element", repeatX, repeatObj[x]);
|
||||||
|
a = rowClone.attributes;
|
||||||
|
for (ii = 0; ii < a.length; ii += 1) {
|
||||||
|
a[ii].value = w3_replace_curly(a[ii], "attribute", repeatX, repeatObj[x]).value;
|
||||||
|
}
|
||||||
|
(i === repeatObj.length) ? arr[j].parentNode.replaceChild(rowClone, arr[j]) : arr[j].parentNode.insertBefore(rowClone, arr[j]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("w3-repeat must be an array. " + repeat + " is not an array.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html = w3_replace_curly(html, "element");
|
||||||
|
htmlObj.parentNode.replaceChild(html, htmlObj);
|
||||||
|
function init_template(id, obj) {
|
||||||
|
var template;
|
||||||
|
template = obj.cloneNode(true);
|
||||||
|
if (w3.dataObject.hasOwnProperty(id)) {return w3.dataObject[id];}
|
||||||
|
w3.dataObject[id] = template;
|
||||||
|
return template;
|
||||||
|
}
|
||||||
|
function w3_replace_curly(elmnt, typ, repeatX, x) {
|
||||||
|
var value, rowClone, pos1, pos2, originalHTML, lookFor, lookForARR = [], i, cc, r;
|
||||||
|
rowClone = elmnt.cloneNode(true);
|
||||||
|
pos1 = 0;
|
||||||
|
while (pos1 > -1) {
|
||||||
|
originalHTML = (typ == "attribute") ? rowClone.value : rowClone.innerHTML;
|
||||||
|
pos1 = originalHTML.indexOf("{{", pos1);
|
||||||
|
if (pos1 === -1) {break;}
|
||||||
|
pos2 = originalHTML.indexOf("}}", pos1 + 1);
|
||||||
|
lookFor = originalHTML.substring(pos1 + 2, pos2);
|
||||||
|
lookForARR = lookFor.split("||");
|
||||||
|
value = undefined;
|
||||||
|
for (i = 0; i < lookForARR.length; i += 1) {
|
||||||
|
lookForARR[i] = lookForARR[i].replace(/^\s+|\s+$/gm, ''); //trim
|
||||||
|
if (x) {value = x[lookForARR[i]];}
|
||||||
|
if (value == undefined && data) {value = data[lookForARR[i]];}
|
||||||
|
if (value == undefined) {
|
||||||
|
cc = lookForARR[i].split(".");
|
||||||
|
if (cc[0] == repeatX) {value = x[cc[1]]; }
|
||||||
|
}
|
||||||
|
if (value == undefined) {
|
||||||
|
if (lookForARR[i] == repeatX) {value = x;}
|
||||||
|
}
|
||||||
|
if (value == undefined) {
|
||||||
|
if (lookForARR[i].substr(0, 1) == '"') {
|
||||||
|
value = lookForARR[i].replace(/"/g, "");
|
||||||
|
} else if (lookForARR[i].substr(0,1) == "'") {
|
||||||
|
value = lookForARR[i].replace(/'/g, "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (value != undefined) {break;}
|
||||||
|
}
|
||||||
|
if (value != undefined) {
|
||||||
|
r = "{{" + lookFor + "}}";
|
||||||
|
if (typ == "attribute") {
|
||||||
|
rowClone.value = rowClone.value.replace(r, value);
|
||||||
|
} else {
|
||||||
|
w3_replace_html(rowClone, r, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pos1 = pos1 + 1;
|
||||||
|
}
|
||||||
|
return rowClone;
|
||||||
|
}
|
||||||
|
function w3_replace_html(a, r, result) {
|
||||||
|
var b, l, i, a, x, j;
|
||||||
|
if (a.hasAttributes()) {
|
||||||
|
b = a.attributes;
|
||||||
|
l = b.length;
|
||||||
|
for (i = 0; i < l; i += 1) {
|
||||||
|
if (b[i].value.indexOf(r) > -1) {b[i].value = b[i].value.replace(r, result);}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x = a.getElementsByTagName("*");
|
||||||
|
l = x.length;
|
||||||
|
a.innerHTML = a.innerHTML.replace(r, result);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
After Width: | Height: | Size: 675 KiB |
@@ -0,0 +1,803 @@
|
|||||||
|
<?xml version="1.0" standalone="no"?>
|
||||||
|
<!--
|
||||||
|
Font Awesome Free 5.10.2 by @fontawesome - https://fontawesome.com
|
||||||
|
License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License)
|
||||||
|
-->
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1">
|
||||||
|
<metadata>
|
||||||
|
Created by FontForge 20190801 at Thu Aug 22 14:41:09 2019
|
||||||
|
By Robert Madole
|
||||||
|
Copyright (c) Font Awesome
|
||||||
|
</metadata>
|
||||||
|
<defs>
|
||||||
|
<font id="FontAwesome5Free-Regular" horiz-adv-x="512" >
|
||||||
|
<font-face
|
||||||
|
font-family="Font Awesome 5 Free Regular"
|
||||||
|
font-weight="400"
|
||||||
|
font-stretch="normal"
|
||||||
|
units-per-em="512"
|
||||||
|
panose-1="2 0 5 3 0 0 0 0 0 0"
|
||||||
|
ascent="448"
|
||||||
|
descent="-64"
|
||||||
|
bbox="-0.0663408 -64.0662 640.01 448.1"
|
||||||
|
underline-thickness="25"
|
||||||
|
underline-position="-50"
|
||||||
|
unicode-range="U+0020-F5C8"
|
||||||
|
/>
|
||||||
|
<missing-glyph />
|
||||||
|
<glyph glyph-name="heart" unicode=""
|
||||||
|
d="M458.4 383.7c75.2998 -63.4004 64.0996 -166.601 10.5996 -221.3l-175.4 -178.7c-10 -10.2002 -23.2998 -15.7998 -37.5996 -15.7998c-14.2002 0 -27.5996 5.69922 -37.5996 15.8994l-175.4 178.7c-53.5996 54.7002 -64.5996 157.9 10.5996 221.2
|
||||||
|
c57.8008 48.7002 147.101 41.2998 202.4 -15c55.2998 56.2998 144.6 63.5996 202.4 15zM434.8 196.2c36.2002 36.8994 43.7998 107.7 -7.2998 150.8c-38.7002 32.5996 -98.7002 27.9004 -136.5 -10.5996l-35 -35.7002l-35 35.7002
|
||||||
|
c-37.5996 38.2998 -97.5996 43.1992 -136.5 10.5c-51.2002 -43.1006 -43.7998 -113.5 -7.2998 -150.7l175.399 -178.7c2.40039 -2.40039 4.40039 -2.40039 6.80078 0z" />
|
||||||
|
<glyph glyph-name="star" unicode="" horiz-adv-x="576"
|
||||||
|
d="M528.1 276.5c26.2002 -3.7998 36.7002 -36.0996 17.7002 -54.5996l-105.7 -103l25 -145.5c4.5 -26.3008 -23.1992 -45.9004 -46.3994 -33.7002l-130.7 68.7002l-130.7 -68.7002c-23.2002 -12.2998 -50.8994 7.39941 -46.3994 33.7002l25 145.5l-105.7 103
|
||||||
|
c-19 18.5 -8.5 50.7998 17.7002 54.5996l146.1 21.2998l65.2998 132.4c11.7998 23.8994 45.7002 23.5996 57.4004 0l65.2998 -132.4zM388.6 135.7l100.601 98l-139 20.2002l-62.2002 126l-62.2002 -126l-139 -20.2002l100.601 -98l-23.7002 -138.4l124.3 65.2998
|
||||||
|
l124.3 -65.2998z" />
|
||||||
|
<glyph glyph-name="user" unicode="" horiz-adv-x="448"
|
||||||
|
d="M313.6 144c74.2002 0 134.4 -60.2002 134.4 -134.4v-25.5996c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v25.5996c0 74.2002 60.2002 134.4 134.4 134.4c28.7998 0 42.5 -16 89.5996 -16s60.9004 16 89.5996 16zM400 -16v25.5996
|
||||||
|
c0 47.6006 -38.7998 86.4004 -86.4004 86.4004c-14.6992 0 -37.8994 -16 -89.5996 -16c-51.2998 0 -75 16 -89.5996 16c-47.6006 0 -86.4004 -38.7998 -86.4004 -86.4004v-25.5996h352zM224 160c-79.5 0 -144 64.5 -144 144s64.5 144 144 144s144 -64.5 144 -144
|
||||||
|
s-64.5 -144 -144 -144zM224 400c-52.9004 0 -96 -43.0996 -96 -96s43.0996 -96 96 -96s96 43.0996 96 96s-43.0996 96 -96 96z" />
|
||||||
|
<glyph glyph-name="clock" unicode=""
|
||||||
|
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM317.8 96.4004l-84.8994 61.6992
|
||||||
|
c-3.10059 2.30078 -4.90039 5.90039 -4.90039 9.7002v164.2c0 6.59961 5.40039 12 12 12h32c6.59961 0 12 -5.40039 12 -12v-141.7l66.7998 -48.5996c5.40039 -3.90039 6.5 -11.4004 2.60059 -16.7998l-18.8008 -25.9004c-3.89941 -5.2998 -11.3994 -6.5 -16.7998 -2.59961z
|
||||||
|
" />
|
||||||
|
<glyph glyph-name="list-alt" unicode=""
|
||||||
|
d="M464 416c26.5098 0 48 -21.4902 48 -48v-352c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h416zM458 16c3.31152 0 6 2.68848 6 6v340c0 3.31152 -2.68848 6 -6 6h-404c-3.31152 0 -6 -2.68848 -6 -6v-340
|
||||||
|
c0 -3.31152 2.68848 -6 6 -6h404zM416 108v-24c0 -6.62695 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h200c6.62695 0 12 -5.37305 12 -12zM416 204v-24c0 -6.62695 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37305 -12 12
|
||||||
|
v24c0 6.62695 5.37305 12 12 12h200c6.62695 0 12 -5.37305 12 -12zM416 300v-24c0 -6.62695 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h200c6.62695 0 12 -5.37305 12 -12zM164 288c0 -19.8818 -16.1182 -36 -36 -36
|
||||||
|
s-36 16.1182 -36 36s16.1182 36 36 36s36 -16.1182 36 -36zM164 192c0 -19.8818 -16.1182 -36 -36 -36s-36 16.1182 -36 36s16.1182 36 36 36s36 -16.1182 36 -36zM164 96c0 -19.8818 -16.1182 -36 -36 -36s-36 16.1182 -36 36s16.1182 36 36 36s36 -16.1182 36 -36z" />
|
||||||
|
<glyph glyph-name="flag" unicode=""
|
||||||
|
d="M336.174 368c35.4668 0 73.0195 12.6914 108.922 28.1797c31.6406 13.6514 66.9043 -9.65723 66.9043 -44.1162v-239.919c0 -16.1953 -8.1543 -31.3057 -21.7129 -40.1631c-26.5762 -17.3643 -70.0693 -39.9814 -128.548 -39.9814c-68.6084 0 -112.781 32 -161.913 32
|
||||||
|
c-56.5674 0 -89.957 -11.2803 -127.826 -28.5566v-83.4434c0 -8.83691 -7.16309 -16 -16 -16h-16c-8.83691 0 -16 7.16309 -16 16v406.438c-14.3428 8.2998 -24 23.7979 -24 41.5615c0 27.5693 23.2422 49.71 51.2012 47.8965
|
||||||
|
c22.9658 -1.49023 41.8662 -19.4717 44.4805 -42.3379c0.177734 -1.52441 0.321289 -4.00781 0.321289 -5.54199c0 -4.30176 -1.10352 -11.1035 -2.46289 -15.1846c22.418 8.68555 49.4199 15.168 80.7207 15.168c68.6084 0 112.781 -32 161.913 -32zM464 112v240
|
||||||
|
c-31.5059 -14.6338 -84.5547 -32 -127.826 -32c-59.9111 0 -101.968 32 -161.913 32c-41.4365 0 -80.4766 -16.5879 -102.261 -32v-232c31.4473 14.5967 84.4648 24 127.826 24c59.9111 0 101.968 -32 161.913 -32c41.4365 0 80.4775 16.5879 102.261 32z" />
|
||||||
|
<glyph glyph-name="bookmark" unicode="" horiz-adv-x="384"
|
||||||
|
d="M336 448c26.5098 0 48 -21.4902 48 -48v-464l-192 112l-192 -112v464c0 26.5098 21.4902 48 48 48h288zM336 19.5703v374.434c0 3.31348 -2.68555 5.99609 -6 5.99609h-276c-3.31152 0 -6 -2.68848 -6 -6v-374.43l144 84z" />
|
||||||
|
<glyph glyph-name="image" unicode=""
|
||||||
|
d="M464 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h416zM458 48c3.31152 0 6 2.68848 6 6v276c0 3.31152 -2.68848 6 -6 6h-404c-3.31152 0 -6 -2.68848 -6 -6v-276
|
||||||
|
c0 -3.31152 2.68848 -6 6 -6h404zM128 296c22.0908 0 40 -17.9092 40 -40s-17.9092 -40 -40 -40s-40 17.9092 -40 40s17.9092 40 40 40zM96 96v48l39.5137 39.5146c4.6875 4.68652 12.2852 4.68652 16.9717 0l39.5146 -39.5146l119.514 119.515
|
||||||
|
c4.6875 4.68652 12.2852 4.68652 16.9717 0l87.5146 -87.5146v-80h-320z" />
|
||||||
|
<glyph glyph-name="edit" unicode="" horiz-adv-x="576"
|
||||||
|
d="M402.3 103.1l32 32c5 5 13.7002 1.5 13.7002 -5.69922v-145.4c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h273.5c7.09961 0 10.7002 -8.59961 5.7002 -13.7002l-32 -32c-1.5 -1.5 -3.5 -2.2998 -5.7002 -2.2998h-241.5v-352h352
|
||||||
|
v113.5c0 2.09961 0.799805 4.09961 2.2998 5.59961zM558.9 304.9l-262.601 -262.601l-90.3994 -10c-26.2002 -2.89941 -48.5 19.2002 -45.6006 45.6006l10 90.3994l262.601 262.601c22.8994 22.8994 59.8994 22.8994 82.6992 0l43.2002 -43.2002
|
||||||
|
c22.9004 -22.9004 22.9004 -60 0.100586 -82.7998zM460.1 274l-58.0996 58.0996l-185.8 -185.899l-7.2998 -65.2998l65.2998 7.2998zM524.9 353.7l-43.2002 43.2002c-4.10059 4.09961 -10.7998 4.09961 -14.7998 0l-30.9004 -30.9004l58.0996 -58.0996l30.9004 30.8994
|
||||||
|
c4 4.2002 4 10.7998 -0.0996094 14.9004z" />
|
||||||
|
<glyph glyph-name="times-circle" unicode=""
|
||||||
|
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM357.8 254.2l-62.2002 -62.2002l62.2002 -62.2002
|
||||||
|
c4.7002 -4.7002 4.7002 -12.2998 0 -17l-22.5996 -22.5996c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-62.2002 62.2002l-62.2002 -62.2002c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-22.5996 22.5996c-4.7002 4.7002 -4.7002 12.2998 0 17l62.2002 62.2002l-62.2002 62.2002
|
||||||
|
c-4.7002 4.7002 -4.7002 12.2998 0 17l22.5996 22.5996c4.7002 4.7002 12.2998 4.7002 17 0l62.2002 -62.2002l62.2002 62.2002c4.7002 4.7002 12.2998 4.7002 17 0l22.5996 -22.5996c4.7002 -4.7002 4.7002 -12.2998 0 -17z" />
|
||||||
|
<glyph glyph-name="check-circle" unicode=""
|
||||||
|
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 392c-110.549 0 -200 -89.4678 -200 -200c0 -110.549 89.4678 -200 200 -200c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200z
|
||||||
|
M396.204 261.733c4.66699 -4.70508 4.63672 -12.3037 -0.0673828 -16.9717l-172.589 -171.204c-4.70508 -4.66797 -12.3027 -4.63672 -16.9697 0.0683594l-90.7812 91.5156c-4.66797 4.70605 -4.63672 12.3047 0.0683594 16.9717l22.7188 22.5361
|
||||||
|
c4.70508 4.66699 12.3027 4.63574 16.9697 -0.0693359l59.792 -60.2773l141.353 140.216c4.70508 4.66797 12.3027 4.6377 16.9697 -0.0673828z" />
|
||||||
|
<glyph glyph-name="question-circle" unicode=""
|
||||||
|
d="M256 440c136.957 0 248 -111.083 248 -248c0 -136.997 -111.043 -248 -248 -248s-248 111.003 -248 248c0 136.917 111.043 248 248 248zM256 -8c110.569 0 200 89.4697 200 200c0 110.529 -89.5088 200 -200 200c-110.528 0 -200 -89.5049 -200 -200
|
||||||
|
c0 -110.569 89.4678 -200 200 -200zM363.244 247.2c0 -67.0518 -72.4209 -68.084 -72.4209 -92.8633v-6.33691c0 -6.62695 -5.37305 -12 -12 -12h-45.6475c-6.62695 0 -12 5.37305 -12 12v8.65918c0 35.7451 27.1006 50.0342 47.5791 61.5156
|
||||||
|
c17.5615 9.84473 28.3242 16.541 28.3242 29.5791c0 17.2461 -21.999 28.6934 -39.7842 28.6934c-23.1885 0 -33.8936 -10.9775 -48.9424 -29.9697c-4.05664 -5.11914 -11.46 -6.07031 -16.666 -2.12402l-27.8232 21.0986
|
||||||
|
c-5.10742 3.87207 -6.25098 11.0654 -2.64453 16.3633c23.627 34.6934 53.7217 54.1846 100.575 54.1846c49.0713 0 101.45 -38.3037 101.45 -88.7998zM298 80c0 -23.1592 -18.8408 -42 -42 -42s-42 18.8408 -42 42s18.8408 42 42 42s42 -18.8408 42 -42z" />
|
||||||
|
<glyph glyph-name="eye" unicode="" horiz-adv-x="576"
|
||||||
|
d="M288 304c0.0927734 0 0.244141 0.000976562 0.336914 0.000976562c61.6641 0 111.71 -50.0469 111.71 -111.711c0 -61.6631 -50.0459 -111.71 -111.71 -111.71s-111.71 50.0469 -111.71 111.71c0 8.71289 1.95898 22.5781 4.37305 30.9502
|
||||||
|
c6.93066 -3.94141 19.0273 -7.18457 27 -7.24023c30.9121 0 56 25.0879 56 56c-0.0556641 7.97266 -3.29883 20.0693 -7.24023 27c8.42383 2.62207 22.4189 4.8623 31.2402 5zM572.52 206.6c1.9209 -3.79883 3.47949 -10.3379 3.47949 -14.5947
|
||||||
|
s-1.55859 -10.7959 -3.47949 -14.5947c-54.1992 -105.771 -161.59 -177.41 -284.52 -177.41s-230.29 71.5898 -284.52 177.4c-1.9209 3.79883 -3.47949 10.3379 -3.47949 14.5947s1.55859 10.7959 3.47949 14.5947c54.1992 105.771 161.59 177.41 284.52 177.41
|
||||||
|
s230.29 -71.5898 284.52 -177.4zM288 48c98.6602 0 189.1 55 237.93 144c-48.8398 89 -139.27 144 -237.93 144s-189.09 -55 -237.93 -144c48.8398 -89 139.279 -144 237.93 -144z" />
|
||||||
|
<glyph glyph-name="eye-slash" unicode="" horiz-adv-x="640"
|
||||||
|
d="M634 -23c3.31738 -2.65137 6.00977 -8.25098 6.00977 -12.498c0 -3.10449 -1.57715 -7.58984 -3.51953 -10.0117l-10 -12.4902c-2.65234 -3.31152 -8.24707 -6 -12.4902 -6c-3.09961 0 -7.58008 1.57227 -10 3.50977l-598 467.49
|
||||||
|
c-3.31738 2.65137 -6.00977 8.25098 -6.00977 12.498c0 3.10449 1.57715 7.58984 3.51953 10.0117l10 12.4902c2.65234 3.31152 8.24707 6 12.4902 6c3.09961 0 7.58008 -1.57227 10 -3.50977zM296.79 301.53c6.33496 1.35059 16.7324 2.45801 23.21 2.46973
|
||||||
|
c60.4805 0 109.36 -47.9102 111.58 -107.85zM343.21 82.46c-6.33496 -1.34375 -16.7334 -2.44629 -23.21 -2.45996c-60.4697 0 -109.35 47.9102 -111.58 107.84zM320 336c-19.8799 0 -39.2803 -2.7998 -58.2197 -7.09961l-46.4102 36.29
|
||||||
|
c32.9199 11.8096 67.9297 18.8096 104.63 18.8096c122.93 0 230.29 -71.5898 284.57 -177.4c1.91992 -3.79883 3.47949 -10.3379 3.47949 -14.5947s-1.55957 -10.7959 -3.47949 -14.5947c-11.7197 -22.7598 -35.4189 -56.4092 -52.9004 -75.1104l-37.7402 29.5
|
||||||
|
c14.333 15.0156 34.0449 41.9854 44 60.2002c-48.8398 89 -139.279 144 -237.93 144zM320 48c19.8896 0 39.2803 2.7998 58.2197 7.08984l46.4102 -36.2803c-32.9199 -11.7598 -67.9297 -18.8096 -104.63 -18.8096c-122.92 0 -230.28 71.5898 -284.51 177.4
|
||||||
|
c-1.9209 3.79883 -3.47949 10.3379 -3.47949 14.5947s1.55859 10.7959 3.47949 14.5947c11.7168 22.7568 35.4111 56.4014 52.8896 75.1006l37.7402 -29.5c-14.3467 -15.0107 -34.0811 -41.9756 -44.0498 -60.1904c48.8496 -89 139.279 -144 237.93 -144z" />
|
||||||
|
<glyph glyph-name="calendar-alt" unicode="" horiz-adv-x="448"
|
||||||
|
d="M148 160h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12zM256 172c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40
|
||||||
|
c6.59961 0 12 -5.40039 12 -12v-40zM352 172c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM256 76c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40
|
||||||
|
c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM160 76c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM352 76c0 -6.59961 -5.40039 -12 -12 -12h-40
|
||||||
|
c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM448 336v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40
|
||||||
|
c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||||
|
<glyph glyph-name="comment" unicode=""
|
||||||
|
d="M256 416c141.4 0 256 -93.0996 256 -208s-114.6 -208 -256 -208c-32.7998 0 -64 5.2002 -92.9004 14.2998c-29.0996 -20.5996 -77.5996 -46.2998 -139.1 -46.2998c-9.59961 0 -18.2998 5.7002 -22.0996 14.5c-3.80078 8.7998 -2 19 4.59961 26
|
||||||
|
c0.5 0.400391 31.5 33.7998 46.4004 73.2002c-33 35.0996 -52.9004 78.7002 -52.9004 126.3c0 114.9 114.6 208 256 208zM256 48c114.7 0 208 71.7998 208 160s-93.2998 160 -208 160s-208 -71.7998 -208 -160c0 -42.2002 21.7002 -74.0996 39.7998 -93.4004
|
||||||
|
l20.6006 -21.7998l-10.6006 -28.0996c-5.5 -14.5 -12.5996 -28.1006 -19.8994 -40.2002c23.5996 7.59961 43.1992 18.9004 57.5 29l19.5 13.7998l22.6992 -7.2002c25.3008 -8 51.7002 -12.0996 78.4004 -12.0996z" />
|
||||||
|
<glyph glyph-name="folder" unicode=""
|
||||||
|
d="M464 320c26.5098 0 48 -21.4902 48 -48v-224c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h146.74c8.49023 0 16.6299 -3.37012 22.6299 -9.37012l54.6299 -54.6299h192zM464 48v224h-198.62
|
||||||
|
c-8.49023 0 -16.6299 3.37012 -22.6299 9.37012l-54.6299 54.6299h-140.12v-288h416z" />
|
||||||
|
<glyph glyph-name="folder-open" unicode="" horiz-adv-x="576"
|
||||||
|
d="M527.9 224c37.6992 0 60.6992 -41.5 40.6992 -73.4004l-79.8994 -128c-8.7998 -14.0996 -24.2002 -22.5996 -40.7002 -22.5996h-400c-26.5 0 -48 21.5 -48 48v288c0 26.5 21.5 48 48 48h160l64 -64h160c26.5 0 48 -21.5 48 -48v-48h47.9004zM48 330v-233.4l62.9004 104.2
|
||||||
|
c8.69922 14.4004 24.2998 23.2002 41.0996 23.2002h280v42c0 3.2998 -2.7002 6 -6 6h-173.9l-64 64h-134.1c-3.2998 0 -6 -2.7002 -6 -6zM448 48l80 128h-378.8l-77.2002 -128h376z" />
|
||||||
|
<glyph glyph-name="chart-bar" unicode=""
|
||||||
|
d="M396.8 96c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v230.4c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-230.4c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004zM204.8 96
|
||||||
|
c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v198.4c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-198.4c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004zM300.8 96
|
||||||
|
c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v134.4c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-134.4c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004zM496 48c8.83984 0 16 -7.16016 16 -16v-16
|
||||||
|
c0 -8.83984 -7.16016 -16 -16 -16h-464c-17.6699 0 -32 14.3301 -32 32v336c0 8.83984 7.16016 16 16 16h16c8.83984 0 16 -7.16016 16 -16v-320h448zM108.8 96c-6.39941 0 -12.7998 6.40039 -12.7998 12.7998v70.4004c0 6.39941 6.40039 12.7998 12.7998 12.7998h22.4004
|
||||||
|
c6.39941 0 12.7998 -6.40039 12.7998 -12.7998v-70.4004c0 -6.39941 -6.40039 -12.7998 -12.7998 -12.7998h-22.4004z" />
|
||||||
|
<glyph glyph-name="comments" unicode="" horiz-adv-x="576"
|
||||||
|
d="M532 61.7998c15.2998 -30.7002 37.4004 -54.5 37.7998 -54.7998c6.2998 -6.7002 8 -16.5 4.40039 -25c-3.7002 -8.5 -12 -14 -21.2002 -14c-53.5996 0 -96.7002 20.2998 -125.2 38.7998c-19 -4.39941 -39 -6.7998 -59.7998 -6.7998
|
||||||
|
c-86.2002 0 -159.9 40.4004 -191.3 97.7998c-9.7002 1.2002 -19.2002 2.7998 -28.4004 4.90039c-28.5 -18.6006 -71.7002 -38.7998 -125.2 -38.7998c-9.19922 0 -17.5996 5.5 -21.1992 14c-3.7002 8.5 -1.90039 18.2998 4.39941 25
|
||||||
|
c0.400391 0.399414 22.4004 24.1992 37.7002 54.8994c-27.5 27.2002 -44 61.2002 -44 98.2002c0 88.4004 93.0996 160 208 160c86.2998 0 160.3 -40.5 191.8 -98.0996c99.7002 -11.8008 176.2 -77.9004 176.2 -157.9c0 -37.0996 -16.5 -71.0996 -44 -98.2002zM139.2 154.1
|
||||||
|
l19.7998 -4.5c16 -3.69922 32.5 -5.59961 49 -5.59961c86.7002 0 160 51.2998 160 112s-73.2998 112 -160 112s-160 -51.2998 -160 -112c0 -28.7002 16.2002 -50.5996 29.7002 -64l24.7998 -24.5l-15.5 -31.0996c-2.59961 -5.10059 -5.2998 -10.1006 -8 -14.8008
|
||||||
|
c14.5996 5.10059 29 12.3008 43.0996 21.4004zM498.3 96c13.5 13.4004 29.7002 35.2998 29.7002 64c0 49.2002 -48.2998 91.5 -112.7 106c0.299805 -3.2998 0.700195 -6.59961 0.700195 -10c0 -80.9004 -78 -147.5 -179.3 -158.3
|
||||||
|
c29.0996 -29.6006 77.2998 -49.7002 131.3 -49.7002c16.5 0 33 1.90039 49 5.59961l19.9004 4.60059l17.0996 -11.1006c14.0996 -9.09961 28.5 -16.2998 43.0996 -21.3994c-2.69922 4.7002 -5.39941 9.7002 -8 14.7998l-15.5 31.0996z" />
|
||||||
|
<glyph glyph-name="star-half" unicode="" horiz-adv-x="576"
|
||||||
|
d="M288 62.7002v-54.2998l-130.7 -68.6006c-23.3994 -12.2998 -50.8994 7.60059 -46.3994 33.7002l25 145.5l-105.7 103c-19 18.5 -8.5 50.7998 17.7002 54.5996l146.1 21.2002l65.2998 132.4c5.90039 11.8994 17.2998 17.7998 28.7002 17.7998v-68.0996l-62.2002 -126
|
||||||
|
l-139 -20.2002l100.601 -98l-23.7002 -138.4z" />
|
||||||
|
<glyph glyph-name="lemon" unicode=""
|
||||||
|
d="M484.112 420.111c28.1221 -28.123 35.9434 -68.0039 19.0215 -97.0547c-23.0576 -39.584 50.1436 -163.384 -82.3311 -295.86c-132.301 -132.298 -256.435 -59.3594 -295.857 -82.3291c-29.0459 -16.917 -68.9219 -9.11426 -97.0576 19.0205
|
||||||
|
c-28.1221 28.1221 -35.9434 68.0029 -19.0215 97.0547c23.0566 39.5859 -50.1436 163.386 82.3301 295.86c132.308 132.309 256.407 59.3496 295.862 82.332c29.0498 16.9219 68.9307 9.09863 97.0537 -19.0234zM461.707 347.217
|
||||||
|
c13.5166 23.2031 -27.7578 63.7314 -50.4883 50.4912c-66.6025 -38.7939 -165.646 45.5898 -286.081 -74.8457c-120.444 -120.445 -36.0449 -219.472 -74.8447 -286.08c-13.542 -23.2471 27.8145 -63.6953 50.4932 -50.4883
|
||||||
|
c66.6006 38.7949 165.636 -45.5996 286.076 74.8428c120.444 120.445 36.0449 219.472 74.8447 286.08zM291.846 338.481c1.37012 -10.96 -6.40332 -20.957 -17.3643 -22.3271c-54.8467 -6.85547 -135.779 -87.7871 -142.636 -142.636
|
||||||
|
c-1.37305 -10.9883 -11.3984 -18.7334 -22.3262 -17.3643c-10.9609 1.37012 -18.7344 11.3652 -17.3643 22.3262c9.16211 73.2852 104.167 168.215 177.364 177.364c10.9531 1.36816 20.9561 -6.40234 22.3262 -17.3633z" />
|
||||||
|
<glyph glyph-name="credit-card" unicode="" horiz-adv-x="576"
|
||||||
|
d="M527.9 416c26.5996 0 48.0996 -21.5 48.0996 -48v-352c0 -26.5 -21.5 -48 -48.0996 -48h-479.801c-26.5996 0 -48.0996 21.5 -48.0996 48v352c0 26.5 21.5 48 48.0996 48h479.801zM54.0996 368c-3.2998 0 -6 -2.7002 -6 -6v-42h479.801v42c0 3.2998 -2.7002 6 -6 6
|
||||||
|
h-467.801zM521.9 16c3.2998 0 6 2.7002 6 6v170h-479.801v-170c0 -3.2998 2.7002 -6 6 -6h467.801zM192 116v-40c0 -6.59961 -5.40039 -12 -12 -12h-72c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h72c6.59961 0 12 -5.40039 12 -12zM384 116v-40
|
||||||
|
c0 -6.59961 -5.40039 -12 -12 -12h-136c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h136c6.59961 0 12 -5.40039 12 -12z" />
|
||||||
|
<glyph glyph-name="hdd" unicode="" horiz-adv-x="576"
|
||||||
|
d="M567.403 212.358c5.59668 -8.04688 8.59668 -17.6113 8.59668 -27.4121v-136.946c0 -26.5098 -21.4902 -48 -48 -48h-480c-26.5098 0 -48 21.4902 -48 48v136.946c0 8.30957 3.85156 20.5898 8.59668 27.4121l105.08 151.053
|
||||||
|
c7.90625 11.3652 25.5596 20.5889 39.4033 20.5889h0.000976562h269.838h0.000976562c13.8438 0 31.4971 -9.22363 39.4033 -20.5889zM153.081 336l-77.9131 -112h425.664l-77.9131 112h-269.838zM528 48v128h-480v-128h480zM496 112c0 -17.6729 -14.3271 -32 -32 -32
|
||||||
|
s-32 14.3271 -32 32s14.3271 32 32 32s32 -14.3271 32 -32zM400 112c0 -17.6729 -14.3271 -32 -32 -32s-32 14.3271 -32 32s14.3271 32 32 32s32 -14.3271 32 -32z" />
|
||||||
|
<glyph glyph-name="hand-point-right" unicode=""
|
||||||
|
d="M428.8 310.4c45.0996 0 83.2002 -38.1016 83.2002 -83.2002c0 -45.6162 -37.7646 -83.2002 -83.2002 -83.2002h-35.6475c-1.41602 -6.36719 -4.96875 -16.252 -7.92969 -22.0645c2.50586 -22.0059 -3.50293 -44.9775 -15.9844 -62.791
|
||||||
|
c-1.14062 -52.4863 -37.3984 -91.1445 -99.9404 -91.1445h-21.2988c-60.0635 0 -98.5117 40 -127.2 40h-2.67871c-5.74707 -4.95215 -13.5361 -8 -22.1201 -8h-64c-17.6729 0 -32 12.8936 -32 28.7998v230.4c0 15.9062 14.3271 28.7998 32 28.7998h64.001
|
||||||
|
c8.58398 0 16.373 -3.04785 22.1201 -8h2.67871c6.96387 0 14.8623 6.19336 30.1816 23.6689l0.128906 0.148438l0.130859 0.145508c8.85645 9.93652 18.1162 20.8398 25.8506 33.2529c18.7051 30.2471 30.3936 78.7842 75.707 78.7842c56.9277 0 92 -35.2861 92 -83.2002
|
||||||
|
v-0.0839844c0 -6.21777 -0.974609 -16.2148 -2.17578 -22.3154h86.1768zM428.8 192c18.9756 0 35.2002 16.2246 35.2002 35.2002c0 18.7002 -16.7754 35.2002 -35.2002 35.2002h-158.399c0 17.3242 26.3994 35.1992 26.3994 70.3994c0 26.4004 -20.625 35.2002 -44 35.2002
|
||||||
|
c-8.79395 0 -20.4443 -32.7119 -34.9258 -56.0996c-9.07422 -14.5752 -19.5244 -27.2256 -30.7988 -39.875c-16.1094 -18.374 -33.8359 -36.6328 -59.0752 -39.5967v-176.753c42.79 -3.7627 74.5088 -39.6758 120 -39.6758h21.2988
|
||||||
|
c40.5244 0 57.124 22.1973 50.6006 61.3252c14.6113 8.00098 24.1514 33.9785 12.9248 53.625c19.3652 18.2246 17.7871 46.3809 4.9502 61.0498h91.0254zM88 64c0 13.2549 -10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24z" />
|
||||||
|
<glyph glyph-name="hand-point-left" unicode=""
|
||||||
|
d="M0 227.2c0 45.0986 38.1006 83.2002 83.2002 83.2002h86.1758c-1.3623 6.91016 -2.17578 14.374 -2.17578 22.3994c0 47.9141 35.0723 83.2002 92 83.2002c45.3135 0 57.002 -48.5371 75.7061 -78.7852c7.73438 -12.4121 16.9951 -23.3154 25.8506 -33.2529
|
||||||
|
l0.130859 -0.145508l0.128906 -0.148438c15.3213 -17.4746 23.2197 -23.668 30.1836 -23.668h2.67871c5.74707 4.95215 13.5361 8 22.1201 8h64c17.6729 0 32 -12.8936 32 -28.7998v-230.4c0 -15.9062 -14.3271 -28.7998 -32 -28.7998h-64
|
||||||
|
c-8.58398 0 -16.373 3.04785 -22.1201 8h-2.67871c-28.6885 0 -67.1367 -40 -127.2 -40h-21.2988c-62.542 0 -98.8008 38.6582 -99.9404 91.1445c-12.4814 17.8135 -18.4922 40.7852 -15.9844 62.791c-2.96094 5.8125 -6.51367 15.6973 -7.92969 22.0645h-35.6465
|
||||||
|
c-45.4355 0 -83.2002 37.584 -83.2002 83.2002zM48 227.2c0 -18.9756 16.2246 -35.2002 35.2002 -35.2002h91.0244c-12.8369 -14.6689 -14.415 -42.8252 4.9502 -61.0498c-11.2256 -19.6465 -1.68652 -45.624 12.9248 -53.625
|
||||||
|
c-6.52246 -39.1279 10.0771 -61.3252 50.6016 -61.3252h21.2988c45.4912 0 77.21 35.9131 120 39.6768v176.752c-25.2393 2.96289 -42.9658 21.2227 -59.0752 39.5967c-11.2744 12.6494 -21.7246 25.2998 -30.7988 39.875
|
||||||
|
c-14.4814 23.3877 -26.1318 56.0996 -34.9258 56.0996c-23.375 0 -44 -8.7998 -44 -35.2002c0 -35.2002 26.3994 -53.0752 26.3994 -70.3994h-158.399c-18.4248 0 -35.2002 -16.5 -35.2002 -35.2002zM448 88c-13.2549 0 -24 -10.7451 -24 -24s10.7451 -24 24 -24
|
||||||
|
s24 10.7451 24 24s-10.7451 24 -24 24z" />
|
||||||
|
<glyph glyph-name="hand-point-up" unicode="" horiz-adv-x="448"
|
||||||
|
d="M105.6 364.8c0 45.0996 38.1016 83.2002 83.2002 83.2002c45.6162 0 83.2002 -37.7646 83.2002 -83.2002v-35.6465c6.36719 -1.41602 16.252 -4.96875 22.0645 -7.92969c22.0059 2.50684 44.9775 -3.50293 62.791 -15.9844
|
||||||
|
c52.4863 -1.14062 91.1445 -37.3984 91.1445 -99.9404v-21.2988c0 -60.0635 -40 -98.5117 -40 -127.2v-2.67871c4.95215 -5.74707 8 -13.5361 8 -22.1201v-64c0 -17.6729 -12.8936 -32 -28.7998 -32h-230.4c-15.9062 0 -28.7998 14.3271 -28.7998 32v64
|
||||||
|
c0 8.58398 3.04785 16.373 8 22.1201v2.67871c0 6.96387 -6.19336 14.8623 -23.6689 30.1816l-0.148438 0.128906l-0.145508 0.130859c-9.93652 8.85645 -20.8398 18.1162 -33.2529 25.8506c-30.2471 18.7051 -78.7842 30.3936 -78.7842 75.707
|
||||||
|
c0 56.9277 35.2861 92 83.2002 92h0.0839844c6.21777 0 16.2148 -0.974609 22.3154 -2.17578v86.1768zM224 364.8c0 18.9756 -16.2246 35.2002 -35.2002 35.2002c-18.7002 0 -35.2002 -16.7754 -35.2002 -35.2002v-158.399c-17.3242 0 -35.1992 26.3994 -70.3994 26.3994
|
||||||
|
c-26.4004 0 -35.2002 -20.625 -35.2002 -44c0 -8.79395 32.7119 -20.4443 56.0996 -34.9258c14.5752 -9.07422 27.2256 -19.5244 39.875 -30.7988c18.374 -16.1094 36.6328 -33.8359 39.5967 -59.0752h176.753c3.7627 42.79 39.6758 74.5088 39.6758 120v21.2988
|
||||||
|
c0 40.5244 -22.1973 57.124 -61.3252 50.6006c-8.00098 14.6113 -33.9785 24.1514 -53.625 12.9248c-18.2246 19.3652 -46.3809 17.7871 -61.0498 4.9502v91.0254zM352 24c-13.2549 0 -24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24s-10.7451 24 -24 24z" />
|
||||||
|
<glyph glyph-name="hand-point-down" unicode="" horiz-adv-x="448"
|
||||||
|
d="M188.8 -64c-45.0986 0 -83.2002 38.1006 -83.2002 83.2002v86.1758c-6.91016 -1.3623 -14.374 -2.17578 -22.3994 -2.17578c-47.9141 0 -83.2002 35.0723 -83.2002 92c0 45.3135 48.5371 57.002 78.7852 75.707c12.4121 7.73438 23.3154 16.9951 33.2529 25.8506
|
||||||
|
l0.145508 0.130859l0.148438 0.128906c17.4746 15.3213 23.668 23.2197 23.668 30.1836v2.67871c-4.95215 5.74707 -8 13.5361 -8 22.1201v64c0 17.6729 12.8936 32 28.7998 32h230.4c15.9062 0 28.7998 -14.3271 28.7998 -32v-64.001
|
||||||
|
c0 -8.58398 -3.04785 -16.373 -8 -22.1201v-2.67871c0 -28.6885 40 -67.1367 40 -127.2v-21.2988c0 -62.542 -38.6582 -98.8008 -91.1445 -99.9404c-17.8135 -12.4814 -40.7852 -18.4922 -62.791 -15.9844c-5.8125 -2.96094 -15.6973 -6.51367 -22.0645 -7.92969v-35.6465
|
||||||
|
c0 -45.4355 -37.584 -83.2002 -83.2002 -83.2002zM188.8 -16c18.9756 0 35.2002 16.2246 35.2002 35.2002v91.0244c14.6689 -12.8369 42.8252 -14.415 61.0498 4.9502c19.6465 -11.2256 45.624 -1.68652 53.625 12.9248c39.1279 -6.52246 61.3252 10.0771 61.3252 50.6016
|
||||||
|
v21.2988c0 45.4912 -35.9131 77.21 -39.6768 120h-176.752c-2.96289 -25.2393 -21.2227 -42.9658 -39.5967 -59.0752c-12.6494 -11.2744 -25.2998 -21.7246 -39.875 -30.7988c-23.3877 -14.4814 -56.0996 -26.1318 -56.0996 -34.9258c0 -23.375 8.7998 -44 35.2002 -44
|
||||||
|
c35.2002 0 53.0752 26.3994 70.3994 26.3994v-158.399c0 -18.4248 16.5 -35.2002 35.2002 -35.2002zM328 384c0 -13.2549 10.7451 -24 24 -24s24 10.7451 24 24s-10.7451 24 -24 24s-24 -10.7451 -24 -24z" />
|
||||||
|
<glyph glyph-name="copy" unicode="" horiz-adv-x="448"
|
||||||
|
d="M433.941 382.059c7.75977 -7.75977 14.0586 -22.9658 14.0586 -33.9404v-268.118c0 -26.5098 -21.4902 -48 -48 -48h-80v-48c0 -26.5098 -21.4902 -48 -48 -48h-224c-26.5098 0 -48 21.4902 -48 48v320c0 26.5098 21.4902 48 48 48h80v48c0 26.5098 21.4902 48 48 48
|
||||||
|
h172.118c10.9746 0 26.1807 -6.29883 33.9404 -14.0586zM266 -16c3.31152 0 6 2.68848 6 6v42h-96c-26.5098 0 -48 21.4902 -48 48v224h-74c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h212zM394 80c3.31152 0 6 2.68848 6 6v202h-88
|
||||||
|
c-13.2549 0 -24 10.7451 -24 24v88h-106c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h212zM400 336v9.63184v0.000976562c0 1.37207 -0.787109 3.27246 -1.75684 4.24219l-48.3682 48.3682c-1.12598 1.125 -2.65234 1.75684 -4.24316 1.75684h-9.63184
|
||||||
|
v-64h64z" />
|
||||||
|
<glyph glyph-name="save" unicode="" horiz-adv-x="448"
|
||||||
|
d="M433.941 318.059c7.75977 -7.75977 14.0586 -22.9658 14.0586 -33.9404v-268.118c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h268.118c10.9746 0 26.1807 -6.29883 33.9404 -14.0586zM272 368h-128v-80h128v80
|
||||||
|
zM394 16c3.31152 0 6 2.68848 6 6v259.632v0.000976562c0 1.37207 -0.787109 3.27246 -1.75684 4.24219l-78.2432 78.2432v-100.118c0 -13.2549 -10.7451 -24 -24 -24h-176c-13.2549 0 -24 10.7451 -24 24v104h-42c-3.31152 0 -6 -2.68848 -6 -6v-340
|
||||||
|
c0 -3.31152 2.68848 -6 6 -6h340zM224 216c48.5234 0 88 -39.4766 88 -88s-39.4766 -88 -88 -88s-88 39.4766 -88 88s39.4766 88 88 88zM224 88c22.0557 0 40 17.9443 40 40s-17.9443 40 -40 40s-40 -17.9443 -40 -40s17.9443 -40 40 -40z" />
|
||||||
|
<glyph glyph-name="square" unicode="" horiz-adv-x="448"
|
||||||
|
d="M400 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h352zM394 16c3.2998 0 6 2.7002 6 6v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340z" />
|
||||||
|
<glyph glyph-name="envelope" unicode=""
|
||||||
|
d="M464 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h416zM464 336h-416v-40.8047c22.4248 -18.2627 58.1797 -46.6602 134.587 -106.49
|
||||||
|
c16.834 -13.2422 50.2051 -45.0762 73.4131 -44.7012c23.2119 -0.371094 56.5723 31.4541 73.4131 44.7012c76.4189 59.8389 112.165 88.2305 134.587 106.49v40.8047zM48 48h416v185.601c-22.915 -18.252 -55.4189 -43.8691 -104.947 -82.6523
|
||||||
|
c-22.5439 -17.748 -60.3359 -55.1787 -103.053 -54.9473c-42.9277 -0.231445 -81.2051 37.75 -103.062 54.9551c-49.5293 38.7842 -82.0244 64.3945 -104.938 82.6455v-185.602z" />
|
||||||
|
<glyph glyph-name="lightbulb" unicode="" horiz-adv-x="352"
|
||||||
|
d="M176 368c8.83984 0 16 -7.16016 16 -16s-7.16016 -16 -16 -16c-35.2803 0 -64 -28.7002 -64 -64c0 -8.83984 -7.16016 -16 -16 -16s-16 7.16016 -16 16c0 52.9404 43.0596 96 96 96zM96.0596 -11.1699l-0.0400391 43.1797h159.961l-0.0507812 -43.1797
|
||||||
|
c-0.00976562 -3.13965 -0.939453 -6.21973 -2.67969 -8.83984l-24.5098 -36.8398c-2.95996 -4.45996 -7.95996 -7.14062 -13.3203 -7.14062h-78.8496c-5.35059 0 -10.3506 2.68066 -13.3203 7.14062l-24.5098 36.8398c-1.75 2.62012 -2.68066 5.68945 -2.68066 8.83984z
|
||||||
|
M176 448c97.2002 0 176 -78.7998 176 -176c0 -44.3701 -16.4502 -84.8496 -43.5498 -115.79c-16.6406 -18.9795 -42.7402 -58.79 -52.4199 -92.1602v-0.0498047h-48v0.0996094c0.00390625 4.04199 0.999023 10.4482 2.21973 14.3008
|
||||||
|
c5.67969 17.9893 22.9902 64.8496 62.0996 109.46c20.4102 23.29 31.6504 53.1699 31.6504 84.1396c0 70.5801 -57.4199 128 -128 128c-68.2803 0 -128.15 -54.3604 -127.95 -128c0.0898438 -30.9902 11.0703 -60.71 31.6104 -84.1396
|
||||||
|
c39.3496 -44.9004 56.5801 -91.8604 62.1699 -109.67c1.42969 -4.56055 2.13965 -9.30078 2.15039 -14.0703v-0.120117h-48v0.0595703c-9.68066 33.3604 -35.7803 73.1709 -52.4209 92.1602c-27.1094 30.9307 -43.5596 71.4102 -43.5596 115.78
|
||||||
|
c0 93.0303 73.7197 176 176 176z" />
|
||||||
|
<glyph glyph-name="bell" unicode="" horiz-adv-x="448"
|
||||||
|
d="M439.39 85.71c6 -6.44043 8.66016 -14.1602 8.61035 -21.71c-0.0996094 -16.4004 -12.9805 -32 -32.0996 -32h-383.801c-19.1191 0 -31.9893 15.5996 -32.0996 32c-0.0498047 7.5498 2.61035 15.2598 8.61035 21.71c19.3193 20.7598 55.4697 51.9902 55.4697 154.29
|
||||||
|
c0 77.7002 54.4795 139.9 127.939 155.16v20.8398c0 17.6699 14.3203 32 31.9805 32s31.9805 -14.3301 31.9805 -32v-20.8398c73.46 -15.2598 127.939 -77.46 127.939 -155.16c0 -102.3 36.1504 -133.53 55.4697 -154.29zM67.5303 80h312.939
|
||||||
|
c-21.2197 27.96 -44.4199 74.3203 -44.5293 159.42c0 0.200195 0.0595703 0.379883 0.0595703 0.580078c0 61.8604 -50.1396 112 -112 112s-112 -50.1396 -112 -112c0 -0.200195 0.0595703 -0.379883 0.0595703 -0.580078
|
||||||
|
c-0.109375 -85.0898 -23.3096 -131.45 -44.5293 -159.42zM224 -64c-35.3203 0 -63.9697 28.6504 -63.9697 64h127.939c0 -35.3496 -28.6494 -64 -63.9697 -64z" />
|
||||||
|
<glyph glyph-name="hospital" unicode="" horiz-adv-x="448"
|
||||||
|
d="M128 204v40c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-40c0 -6.62695 -5.37305 -12 -12 -12h-40c-6.62695 0 -12 5.37305 -12 12zM268 192c-6.62695 0 -12 5.37305 -12 12v40c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-40
|
||||||
|
c0 -6.62695 -5.37305 -12 -12 -12h-40zM192 108c0 -6.62695 -5.37305 -12 -12 -12h-40c-6.62695 0 -12 5.37305 -12 12v40c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-40zM268 96c-6.62695 0 -12 5.37305 -12 12v40c0 6.62695 5.37305 12 12 12h40
|
||||||
|
c6.62695 0 12 -5.37305 12 -12v-40c0 -6.62695 -5.37305 -12 -12 -12h-40zM448 -28v-36h-448v36c0 6.62695 5.37305 12 12 12h19.5v378.965c0 11.6172 10.7451 21.0352 24 21.0352h88.5v40c0 13.2549 10.7451 24 24 24h112c13.2549 0 24 -10.7451 24 -24v-40h88.5
|
||||||
|
c13.2549 0 24 -9.41797 24 -21.0352v-378.965h19.5c6.62695 0 12 -5.37305 12 -12zM79.5 -15h112.5v67c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-67h112.5v351h-64.5v-24c0 -13.2549 -10.7451 -24 -24 -24h-112c-13.2549 0 -24 10.7451 -24 24v24
|
||||||
|
h-64.5v-351zM266 384h-26v26c0 3.31152 -2.68848 6 -6 6h-20c-3.31152 0 -6 -2.68848 -6 -6v-26h-26c-3.31152 0 -6 -2.68848 -6 -6v-20c0 -3.31152 2.68848 -6 6 -6h26v-26c0 -3.31152 2.68848 -6 6 -6h20c3.31152 0 6 2.68848 6 6v26h26c3.31152 0 6 2.68848 6 6v20
|
||||||
|
c0 3.31152 -2.68848 6 -6 6z" />
|
||||||
|
<glyph glyph-name="plus-square" unicode="" horiz-adv-x="448"
|
||||||
|
d="M352 208v-32c0 -6.59961 -5.40039 -12 -12 -12h-88v-88c0 -6.59961 -5.40039 -12 -12 -12h-32c-6.59961 0 -12 5.40039 -12 12v88h-88c-6.59961 0 -12 5.40039 -12 12v32c0 6.59961 5.40039 12 12 12h88v88c0 6.59961 5.40039 12 12 12h32c6.59961 0 12 -5.40039 12 -12
|
||||||
|
v-88h88c6.59961 0 12 -5.40039 12 -12zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340
|
||||||
|
c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||||
|
<glyph glyph-name="circle" unicode=""
|
||||||
|
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200z" />
|
||||||
|
<glyph glyph-name="smile" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
||||||
|
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM332 135.4c8.5 10.1992 23.7002 11.5 33.7998 3.09961c10.2002 -8.5 11.6006 -23.5996 3.10059 -33.7998
|
||||||
|
c-30 -36 -74.1006 -56.6006 -120.9 -56.6006s-90.9004 20.6006 -120.9 56.6006c-8.39941 10.2002 -7.09961 25.2998 3.10059 33.7998c10.0996 8.40039 25.2998 7.09961 33.7998 -3.09961c20.7998 -25.1006 51.5 -39.4004 84 -39.4004s63.2002 14.4004 84 39.4004z" />
|
||||||
|
<glyph glyph-name="frown" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
||||||
|
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM248 144c40.2002 0 78 -17.7002 103.8 -48.5996c8.40039 -10.2002 7.10059 -25.3008 -3.09961 -33.8008
|
||||||
|
c-10.7002 -8.7998 -25.7002 -6.59961 -33.7998 3.10059c-16.6006 20 -41 31.3994 -66.9004 31.3994s-50.2998 -11.5 -66.9004 -31.3994c-8.5 -10.2002 -23.5996 -11.5 -33.7998 -3.10059c-10.2002 8.5 -11.5996 23.6006 -3.09961 33.8008
|
||||||
|
c25.7998 30.8994 63.5996 48.5996 103.8 48.5996z" />
|
||||||
|
<glyph glyph-name="meh" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
||||||
|
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM336 128c13.2002 0 24 -10.7998 24 -24s-10.7998 -24 -24 -24h-176c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24h176z
|
||||||
|
" />
|
||||||
|
<glyph glyph-name="keyboard" unicode="" horiz-adv-x="576"
|
||||||
|
d="M528 384c26.5098 0 48 -21.4902 48 -48v-288c0 -26.5098 -21.4902 -48 -48 -48h-480c-26.5098 0 -48 21.4902 -48 48v288c0 26.5098 21.4902 48 48 48h480zM536 48v288c0 4.41113 -3.58887 8 -8 8h-480c-4.41113 0 -8 -3.58887 -8 -8v-288c0 -4.41113 3.58887 -8 8 -8
|
||||||
|
h480c4.41113 0 8 3.58887 8 8zM170 178c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM266 178c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28
|
||||||
|
c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM362 178c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM458 178c0 -6.62695 -5.37305 -12 -12 -12h-28
|
||||||
|
c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM122 96c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM506 96
|
||||||
|
c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM122 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28
|
||||||
|
c6.62695 0 12 -5.37305 12 -12v-28zM218 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM314 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28
|
||||||
|
c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM410 260c0 -6.62695 -5.37305 -12 -12 -12h-28c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM506 260c0 -6.62695 -5.37305 -12 -12 -12h-28
|
||||||
|
c-6.62695 0 -12 5.37305 -12 12v28c0 6.62695 5.37305 12 12 12h28c6.62695 0 12 -5.37305 12 -12v-28zM408 102c0 -6.62695 -5.37305 -12 -12 -12h-216c-6.62695 0 -12 5.37305 -12 12v16c0 6.62695 5.37305 12 12 12h216c6.62695 0 12 -5.37305 12 -12v-16z" />
|
||||||
|
<glyph glyph-name="calendar" unicode="" horiz-adv-x="448"
|
||||||
|
d="M400 384c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12
|
||||||
|
v-52h48zM394 -16c3.2998 0 6 2.7002 6 6v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340z" />
|
||||||
|
<glyph glyph-name="play-circle" unicode=""
|
||||||
|
d="M371.7 210c16.3994 -9.2002 16.3994 -32.9004 0 -42l-176 -101c-15.9004 -8.7998 -35.7002 2.59961 -35.7002 21v208c0 18.5 19.9004 29.7998 35.7002 21zM504 192c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248s248 -111 248 -248zM56 192
|
||||||
|
c0 -110.5 89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200z" />
|
||||||
|
<glyph glyph-name="minus-square" unicode="" horiz-adv-x="448"
|
||||||
|
d="M108 164c-6.59961 0 -12 5.40039 -12 12v32c0 6.59961 5.40039 12 12 12h232c6.59961 0 12 -5.40039 12 -12v-32c0 -6.59961 -5.40039 -12 -12 -12h-232zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h352
|
||||||
|
c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||||
|
<glyph glyph-name="check-square" unicode="" horiz-adv-x="448"
|
||||||
|
d="M400 416c26.5098 0 48 -21.4902 48 -48v-352c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h352zM400 16v352h-352v-352h352zM364.136 257.724l-172.589 -171.204
|
||||||
|
c-4.70508 -4.66699 -12.3027 -4.63672 -16.9697 0.0683594l-90.7812 91.5156c-4.66699 4.70508 -4.63672 12.3037 0.0693359 16.9717l22.7188 22.5361c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0693359l59.792 -60.2773l141.353 140.217
|
||||||
|
c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0683594l22.5361 -22.7178c4.66699 -4.70605 4.63672 -12.3047 -0.0683594 -16.9717z" />
|
||||||
|
<glyph glyph-name="share-square" unicode="" horiz-adv-x="576"
|
||||||
|
d="M561.938 289.94c18.75 -18.7402 18.75 -49.1406 0 -67.8809l-143.998 -144c-29.9727 -29.9727 -81.9404 -9.05273 -81.9404 33.9404v53.7998c-101.266 -7.83691 -99.625 -31.6406 -84.1104 -78.7598c14.2285 -43.0889 -33.4736 -79.248 -71.0195 -55.7402
|
||||||
|
c-51.6924 32.3057 -84.8701 83.0635 -84.8701 144.76c0 39.3408 12.2197 72.7402 36.3301 99.3008c19.8398 21.8398 47.7402 38.4697 82.9102 49.4199c36.7295 11.4395 78.3096 16.1094 120.76 17.9893v57.1982c0 42.9355 51.9258 63.9541 81.9404 33.9404zM384 112l144 144
|
||||||
|
l-144 144v-104.09c-110.86 -0.90332 -240 -10.5166 -240 -119.851c0 -52.1396 32.79 -85.6094 62.3096 -104.06c-39.8174 120.65 48.999 141.918 177.69 143.84v-103.84zM408.74 27.5068c6.14844 1.75684 15.5449 5.92383 20.9736 9.30273
|
||||||
|
c7.97656 4.95215 18.2861 -0.825195 18.2861 -10.2139v-42.5957c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h132c6.62695 0 12 -5.37305 12 -12v-4.48633c0 -4.91699 -2.9873 -9.36914 -7.56934 -11.1514
|
||||||
|
c-13.7021 -5.33105 -26.3955 -11.5371 -38.0498 -18.585c-1.59668 -0.974609 -4.41016 -1.77051 -6.28027 -1.77734h-86.1006c-3.31152 0 -6 -2.68848 -6 -6v-340c0 -3.31152 2.68848 -6 6 -6h340c3.31152 0 6 2.68848 6 6v25.9658c0 5.37012 3.5791 10.0596 8.74023 11.541
|
||||||
|
z" />
|
||||||
|
<glyph glyph-name="compass" unicode="" horiz-adv-x="496"
|
||||||
|
d="M347.94 318.14c16.6592 7.61035 33.8096 -9.54004 26.1992 -26.1992l-65.9697 -144.341c-2.73047 -5.97363 -9.7959 -13.0391 -15.7695 -15.7695l-144.341 -65.9697c-16.6592 -7.61035 -33.8096 9.5498 -26.1992 26.1992l65.9697 144.341
|
||||||
|
c2.73047 5.97363 9.7959 13.0391 15.7695 15.7695zM270.58 169.42c12.4697 12.4697 12.4697 32.6904 0 45.1602s-32.6904 12.4697 -45.1602 0s-12.4697 -32.6904 0 -45.1602s32.6904 -12.4697 45.1602 0zM248 440c136.97 0 248 -111.03 248 -248s-111.03 -248 -248 -248
|
||||||
|
s-248 111.03 -248 248s111.03 248 248 248zM248 -8c110.28 0 200 89.7197 200 200s-89.7197 200 -200 200s-200 -89.7197 -200 -200s89.7197 -200 200 -200z" />
|
||||||
|
<glyph glyph-name="caret-square-down" unicode="" horiz-adv-x="448"
|
||||||
|
d="M125.1 240h197.801c10.6992 0 16.0996 -13 8.5 -20.5l-98.9004 -98.2998c-4.7002 -4.7002 -12.2002 -4.7002 -16.9004 0l-98.8994 98.2998c-7.7002 7.5 -2.2998 20.5 8.39941 20.5zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
|
||||||
|
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||||
|
<glyph glyph-name="caret-square-up" unicode="" horiz-adv-x="448"
|
||||||
|
d="M322.9 144h-197.801c-10.6992 0 -16.0996 13 -8.5 20.5l98.9004 98.2998c4.7002 4.7002 12.2002 4.7002 16.9004 0l98.8994 -98.2998c7.7002 -7.5 2.2998 -20.5 -8.39941 -20.5zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
|
||||||
|
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||||
|
<glyph glyph-name="caret-square-right" unicode="" horiz-adv-x="448"
|
||||||
|
d="M176 93.0996v197.801c0 10.6992 13 16.0996 20.5 8.5l98.2998 -98.9004c4.7002 -4.7002 4.7002 -12.2002 0 -16.9004l-98.2998 -98.8994c-7.5 -7.7002 -20.5 -2.2998 -20.5 8.39941zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
|
||||||
|
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||||
|
<glyph glyph-name="file" unicode="" horiz-adv-x="384"
|
||||||
|
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
||||||
|
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416z" />
|
||||||
|
<glyph glyph-name="file-alt" unicode="" horiz-adv-x="384"
|
||||||
|
d="M288 200v-28c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12v28c0 6.59961 5.40039 12 12 12h168c6.59961 0 12 -5.40039 12 -12zM276 128c6.59961 0 12 -5.40039 12 -12v-28c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12
|
||||||
|
v28c0 6.59961 5.40039 12 12 12h168zM384 316.1v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996l83.9004 -83.9004c9 -8.90039 14.0996 -21.2002 14.0996 -33.9004z
|
||||||
|
M256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416h288z" />
|
||||||
|
<glyph glyph-name="thumbs-up" unicode=""
|
||||||
|
d="M466.27 161.31c4.6748 -22.6465 0.864258 -44.5371 -8.98926 -62.9893c2.95898 -23.8682 -4.02148 -48.5654 -17.3398 -66.9902c-0.954102 -55.9072 -35.8232 -95.3301 -112.94 -95.3301c-7 0 -15 0.00976562 -22.2197 0.00976562
|
||||||
|
c-102.742 0 -133.293 38.9395 -177.803 39.9404c-3.56934 -13.7764 -16.085 -23.9502 -30.9775 -23.9502h-64c-17.6729 0 -32 14.3271 -32 32v240c0 17.6729 14.3271 32 32 32h98.7598c19.1455 16.9531 46.0137 60.6533 68.7598 83.4004
|
||||||
|
c13.667 13.667 10.1533 108.6 71.7607 108.6c57.5801 0 95.2695 -31.9355 95.2695 -104.73c0 -18.4092 -3.92969 -33.7295 -8.84961 -46.5391h36.4795c48.6025 0 85.8203 -41.5654 85.8203 -85.5801c0 -19.1504 -4.95996 -34.9902 -13.7305 -49.8408zM404.52 107.48
|
||||||
|
c21.5811 20.3838 18.6992 51.0645 5.21094 65.6191c9.44922 0 22.3594 18.9102 22.2695 37.8105c-0.0898438 18.9102 -16.71 37.8203 -37.8203 37.8203h-103.989c0 37.8193 28.3594 55.3691 28.3594 94.5391c0 23.75 0 56.7305 -47.2695 56.7305
|
||||||
|
c-18.9102 -18.9102 -9.45996 -66.1797 -37.8203 -94.54c-26.5596 -26.5703 -66.1797 -97.46 -94.54 -97.46h-10.9199v-186.17c53.6113 0 100.001 -37.8203 171.64 -37.8203h37.8203c35.5117 0 60.8203 17.1201 53.1201 65.9004
|
||||||
|
c15.2002 8.16016 26.5 36.4395 13.9395 57.5703zM88 16c0 13.2549 -10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24s24 10.7451 24 24z" />
|
||||||
|
<glyph glyph-name="thumbs-down" unicode=""
|
||||||
|
d="M466.27 222.69c8.77051 -14.8506 13.7305 -30.6904 13.7305 -49.8408c0 -44.0146 -37.2178 -85.5801 -85.8203 -85.5801h-36.4795c4.91992 -12.8096 8.84961 -28.1299 8.84961 -46.5391c0 -72.7949 -37.6895 -104.73 -95.2695 -104.73
|
||||||
|
c-61.6074 0 -58.0938 94.9326 -71.7607 108.6c-22.7461 22.7471 -49.6133 66.4473 -68.7598 83.4004h-7.05176c-5.5332 -9.56152 -15.8662 -16 -27.708 -16h-64c-17.6729 0 -32 14.3271 -32 32v240c0 17.6729 14.3271 32 32 32h64c8.11328 0 15.5146 -3.02539 21.1553 -8
|
||||||
|
h10.8447c40.9971 0 73.1953 39.9902 176.78 39.9902c7.21973 0 15.2197 0.00976562 22.2197 0.00976562c77.1172 0 111.986 -39.4229 112.94 -95.3301c13.3184 -18.4248 20.2979 -43.1221 17.3398 -66.9902c9.85352 -18.4521 13.6641 -40.3428 8.98926 -62.9893zM64 152
|
||||||
|
c13.2549 0 24 10.7451 24 24s-10.7451 24 -24 24s-24 -10.7451 -24 -24s10.7451 -24 24 -24zM394.18 135.27c21.1104 0 37.7305 18.9102 37.8203 37.8203c0.0898438 18.9004 -12.8203 37.8105 -22.2695 37.8105c13.4883 14.5547 16.3701 45.2354 -5.21094 65.6191
|
||||||
|
c12.5605 21.1309 1.26074 49.4102 -13.9395 57.5703c7.7002 48.7803 -17.6084 65.9004 -53.1201 65.9004h-37.8203c-71.6387 0 -118.028 -37.8203 -171.64 -37.8203v-186.17h10.9199c28.3604 0 67.9805 -70.8896 94.54 -97.46
|
||||||
|
c28.3604 -28.3604 18.9102 -75.6299 37.8203 -94.54c47.2695 0 47.2695 32.9805 47.2695 56.7305c0 39.1699 -28.3594 56.7197 -28.3594 94.5391h103.989z" />
|
||||||
|
<glyph glyph-name="sun" unicode=""
|
||||||
|
d="M494.2 226.1c11.2002 -7.59961 17.7998 -20.0996 17.8994 -33.6992c0 -13.4004 -6.69922 -26 -17.7998 -33.5l-59.7998 -40.5l13.7002 -71c2.5 -13.2002 -1.60059 -26.8008 -11.1006 -36.3008s-22.8994 -13.7998 -36.2998 -11.0996l-70.8994 13.7002l-40.4004 -59.9004
|
||||||
|
c-7.5 -11.0996 -20.0996 -17.7998 -33.5 -17.7998s-26 6.7002 -33.5 17.9004l-40.4004 59.8994l-70.7998 -13.7002c-13.3994 -2.59961 -26.7998 1.60059 -36.2998 11.1006s-13.7002 23.0996 -11.0996 36.2998l13.6992 71l-59.7998 40.5
|
||||||
|
c-11.0996 7.5 -17.7998 20 -17.7998 33.5s6.59961 26 17.7998 33.5996l59.7998 40.5l-13.6992 71c-2.60059 13.2002 1.59961 26.7002 11.0996 36.3008c9.5 9.59961 23 13.6992 36.2998 11.1992l70.7998 -13.6992l40.4004 59.8994c15.0996 22.2998 51.9004 22.2998 67 0
|
||||||
|
l40.4004 -59.8994l70.8994 13.6992c13 2.60059 26.6006 -1.59961 36.2002 -11.0996c9.5 -9.59961 13.7002 -23.2002 11.0996 -36.4004l-13.6992 -71zM381.3 140.5l76.7998 52.0996l-76.7998 52l17.6006 91.1006l-91 -17.6006l-51.9004 76.9004l-51.7998 -76.7998
|
||||||
|
l-91 17.5996l17.5996 -91.2002l-76.7998 -52l76.7998 -52l-17.5996 -91.1992l90.8994 17.5996l51.9004 -77l51.9004 76.9004l91 -17.6006zM256 296c57.2998 0 104 -46.7002 104 -104s-46.7002 -104 -104 -104s-104 46.7002 -104 104s46.7002 104 104 104zM256 136
|
||||||
|
c30.9004 0 56 25.0996 56 56s-25.0996 56 -56 56s-56 -25.0996 -56 -56s25.0996 -56 56 -56z" />
|
||||||
|
<glyph glyph-name="moon" unicode=""
|
||||||
|
d="M279.135 -64c-141.424 0 -256 114.64 -256 256c0 141.425 114.641 256 256 256c13.0068 -0.00195312 33.9443 -1.91797 46.7354 -4.27734c44.0205 -8.13086 53.7666 -66.8691 15.0215 -88.9189c-41.374 -23.5439 -67.4336 -67.4121 -67.4336 -115.836
|
||||||
|
c0 -83.5234 75.9238 -146.475 158.272 -130.792c43.6904 8.32129 74.5186 -42.5693 46.248 -77.4004c-47.8613 -58.9717 -120.088 -94.7754 -198.844 -94.7754zM279.135 400c-114.875 0 -208 -93.125 -208 -208s93.125 -208 208 -208
|
||||||
|
c65.2314 0 123.439 30.0361 161.575 77.0244c-111.611 -21.2568 -215.252 64.0957 -215.252 177.943c0 67.5127 36.9326 126.392 91.6934 157.555c-12.3271 2.27637 -25.0312 3.47754 -38.0166 3.47754z" />
|
||||||
|
<glyph glyph-name="caret-square-left" unicode="" horiz-adv-x="448"
|
||||||
|
d="M272 290.9v-197.801c0 -10.6992 -13 -16.0996 -20.5 -8.5l-98.2998 98.9004c-4.7002 4.7002 -4.7002 12.2002 0 16.9004l98.2998 98.8994c7.5 7.7002 20.5 2.2998 20.5 -8.39941zM448 368v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352
|
||||||
|
c0 26.5 21.5 48 48 48h352c26.5 0 48 -21.5 48 -48zM400 22v340c0 3.2998 -2.7002 6 -6 6h-340c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||||
|
<glyph glyph-name="dot-circle" unicode=""
|
||||||
|
d="M256 392c-110.549 0 -200 -89.4678 -200 -200c0 -110.549 89.4678 -200 200 -200c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200zM256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248z
|
||||||
|
M256 272c44.1826 0 80 -35.8174 80 -80s-35.8174 -80 -80 -80s-80 35.8174 -80 80s35.8174 80 80 80z" />
|
||||||
|
<glyph glyph-name="building" unicode="" horiz-adv-x="448"
|
||||||
|
d="M128 300v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12zM268 288c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40
|
||||||
|
c0 -6.59961 -5.40039 -12 -12 -12h-40zM140 192c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40zM268 192c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40
|
||||||
|
c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40zM192 108c0 -6.59961 -5.40039 -12 -12 -12h-40c-6.59961 0 -12 5.40039 -12 12v40c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40zM268 96c-6.59961 0 -12 5.40039 -12 12v40
|
||||||
|
c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-40zM448 -28v-36h-448v36c0 6.59961 5.40039 12 12 12h19.5v440c0 13.2998 10.7002 24 24 24h337c13.2998 0 24 -10.7002 24 -24v-440h19.5
|
||||||
|
c6.59961 0 12 -5.40039 12 -12zM79.5 -15h112.5v67c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-67h112.5v414l-288.5 1z" />
|
||||||
|
<glyph glyph-name="file-pdf" unicode="" horiz-adv-x="384"
|
||||||
|
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
||||||
|
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM298.2 127.7c10.5 -10.5 8 -38.7002 -17.5 -38.7002c-14.7998 0 -36.9004 6.7998 -55.7998 17c-21.6006 -3.59961 -46 -12.7002 -68.4004 -20.0996c-50.0996 -86.4004 -79.4004 -47 -76.0996 -31.2002
|
||||||
|
c4 20 31 35.8994 51 46.2002c10.5 18.3994 25.3994 50.5 35.3994 74.3994c-7.39941 28.6006 -11.3994 51 -7 67.1006c4.7998 17.6992 38.4004 20.2998 42.6006 -5.90039c4.69922 -15.4004 -1.5 -39.9004 -5.40039 -56c8.09961 -21.2998 19.5996 -35.7998 36.7998 -46.2998
|
||||||
|
c17.4004 2.2002 52.2002 5.5 64.4004 -6.5zM100.1 49.9004c0 -0.700195 11.4004 4.69922 30.4004 35c-5.90039 -5.5 -25.2998 -21.3008 -30.4004 -35zM181.7 240.5c-2.5 0 -2.60059 -26.9004 1.7998 -40.7998c4.90039 8.7002 5.59961 40.7998 -1.7998 40.7998zM157.3 103.9
|
||||||
|
c15.9004 6.09961 34 14.8994 54.7998 19.1992c-11.1992 8.30078 -21.7998 20.4004 -30.0996 35.5c-6.7002 -17.6992 -15 -37.7998 -24.7002 -54.6992zM288.9 108.9c3.59961 2.39941 -2.2002 10.3994 -37.3008 7.7998c32.3008 -13.7998 37.3008 -7.7998 37.3008 -7.7998z" />
|
||||||
|
<glyph glyph-name="file-word" unicode="" horiz-adv-x="384"
|
||||||
|
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
||||||
|
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM268.1 192v0.200195h15.8008c7.7998 0 13.5 -7.2998 11.5996 -14.9004c-4.2998 -17 -13.7002 -54.0996 -34.5 -136c-1.2998 -5.39941 -6.09961 -9.09961 -11.5996 -9.09961h-24.7002
|
||||||
|
c-5.5 0 -10.2998 3.7998 -11.6006 9.09961c-5.2998 20.9004 -17.7998 71 -17.8994 71.4004l-2.90039 17.2998c-0.5 -5.2998 -1.5 -11.0996 -3 -17.2998l-17.8994 -71.4004c-1.30078 -5.39941 -6.10059 -9.09961 -11.6006 -9.09961h-25.2002
|
||||||
|
c-5.59961 0 -10.3994 3.7002 -11.6992 9.09961c-6.5 26.5 -25.2002 103.4 -33.2002 136c-1.7998 7.5 3.89941 14.7998 11.7002 14.7998h16.7998c5.7998 0 10.7002 -4.09961 11.7998 -9.69922c5 -25.7002 18.4004 -93.8008 19.0996 -99
|
||||||
|
c0.300781 -1.7002 0.400391 -3.10059 0.5 -4.2002c0.800781 7.5 0.400391 4.7002 24.8008 103.7c1.39941 5.2998 6.19922 9.09961 11.6992 9.09961h13.3008c5.59961 0 10.3994 -3.7998 11.6992 -9.2002c23.9004 -99.7002 22.8008 -94.3994 23.6006 -99.5
|
||||||
|
c0.299805 -1.7002 0.5 -3.09961 0.700195 -4.2998c0.599609 8.09961 0.399414 5.7998 21 103.5c1.09961 5.5 6 9.5 11.6992 9.5z" />
|
||||||
|
<glyph glyph-name="file-excel" unicode="" horiz-adv-x="384"
|
||||||
|
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
||||||
|
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM260 224c9.2002 0 15 -10 10.2998 -18c-16 -27.5 -45.5996 -76.9004 -46.2998 -78l46.4004 -78c4.59961 -8 -1.10059 -18 -10.4004 -18h-28.7998c-4.40039 0 -8.5 2.40039 -10.6006 6.2998
|
||||||
|
c-22.6992 41.7998 -13.6992 27.5 -28.5996 57.7002c-5.59961 -12.7002 -6.90039 -17.7002 -28.5996 -57.7002c-2.10059 -3.89941 -6.10059 -6.2998 -10.5 -6.2998h-28.9004c-9.2998 0 -15.0996 10 -10.4004 18l46.3008 78l-46.3008 78c-4.59961 8 1.10059 18 10.4004 18
|
||||||
|
h28.9004c4.39941 0 8.5 -2.40039 10.5996 -6.2998c21.7002 -40.4004 14.7002 -28.6006 28.5996 -57.7002c6.40039 15.2998 10.6006 24.5996 28.6006 57.7002c2.09961 3.89941 6.09961 6.2998 10.5 6.2998h28.7998z" />
|
||||||
|
<glyph glyph-name="file-powerpoint" unicode="" horiz-adv-x="384"
|
||||||
|
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
||||||
|
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM120 44v168c0 6.59961 5.40039 12 12 12h69.2002c36.7002 0 62.7998 -27 62.7998 -66.2998c0 -74.2998 -68.7002 -66.5 -95.5 -66.5v-47.2002c0 -6.59961 -5.40039 -12 -12 -12h-24.5c-6.59961 0 -12 5.40039 -12 12z
|
||||||
|
M168.5 131.4h23c7.90039 0 13.9004 2.39941 18.0996 7.19922c8.5 9.80078 8.40039 28.5 0.100586 37.8008c-4.10059 4.59961 -9.90039 7 -17.4004 7h-23.8994v-52h0.0996094z" />
|
||||||
|
<glyph glyph-name="file-image" unicode="" horiz-adv-x="384"
|
||||||
|
d="M369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM332.1 320l-76.0996 76.0996v-76.0996h76.0996zM48 -16h288v288
|
||||||
|
h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416zM80 32v64l39.5 39.5c4.7002 4.7002 12.2998 4.7002 17 0l39.5 -39.5l87.5 87.5c4.7002 4.7002 12.2998 4.7002 17 0l23.5 -23.5v-128h-224zM128 272c26.5 0 48 -21.5 48 -48s-21.5 -48 -48 -48s-48 21.5 -48 48
|
||||||
|
s21.5 48 48 48z" />
|
||||||
|
<glyph glyph-name="file-archive" unicode="" horiz-adv-x="384"
|
||||||
|
d="M128.3 288h32v-32h-32v32zM192.3 384v-32h-32v32h32zM128.3 352h32v-32h-32v32zM192.3 320v-32h-32v32h32zM369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1
|
||||||
|
c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-48.2998v-16h-32v16h-79.7002v-416h288zM194.2 182.3l17.2998 -87.7002c6.40039 -32.3994 -18.4004 -62.5996 -51.5 -62.5996
|
||||||
|
c-33.2002 0 -58 30.4004 -51.4004 62.9004l19.7002 97.0996v32h32v-32h22.1006c5.7998 0 10.6992 -4.09961 11.7998 -9.7002zM160.3 57.9004c17.9004 0 32.4004 12.0996 32.4004 27c0 14.8994 -14.5 27 -32.4004 27c-17.8994 0 -32.3994 -12.1006 -32.3994 -27
|
||||||
|
c0 -14.9004 14.5 -27 32.3994 -27zM192.3 256v-32h-32v32h32z" />
|
||||||
|
<glyph glyph-name="file-audio" unicode="" horiz-adv-x="384"
|
||||||
|
d="M369.941 350.059c7.75977 -7.75977 14.0586 -22.9658 14.0586 -33.9404v-332.118c0 -26.5098 -21.4902 -48 -48 -48h-288c-26.5098 0 -48 21.4902 -48 48v416c0 26.5098 21.4902 48 48 48h204.118c10.9746 0 26.1807 -6.29883 33.9404 -14.0586zM332.118 320
|
||||||
|
l-76.1182 76.1182v-76.1182h76.1182zM48 -16h288v288h-104c-13.2549 0 -24 10.7451 -24 24v104h-160v-416zM192 60.0244c0 -10.6914 -12.9258 -16.0459 -20.4854 -8.48535l-35.5146 35.9746h-28c-6.62695 0 -12 5.37305 -12 12v56c0 6.62695 5.37305 12 12 12h28
|
||||||
|
l35.5146 36.9473c7.56055 7.56055 20.4854 2.20605 20.4854 -8.48535v-135.951zM233.201 107.154c9.05078 9.29688 9.05957 24.1328 0.000976562 33.4385c-22.1494 22.752 12.2344 56.2461 34.3945 33.4814c27.1982 -27.9404 27.2119 -72.4443 0.000976562 -100.401
|
||||||
|
c-21.793 -22.3857 -56.9463 10.3154 -34.3965 33.4814z" />
|
||||||
|
<glyph glyph-name="file-video" unicode="" horiz-adv-x="384"
|
||||||
|
d="M369.941 350.059c7.75977 -7.75977 14.0586 -22.9658 14.0586 -33.9404v-332.118c0 -26.5098 -21.4902 -48 -48 -48h-288c-26.5098 0 -48 21.4902 -48 48v416c0 26.5098 21.4902 48 48 48h204.118c10.9746 0 26.1807 -6.29883 33.9404 -14.0586zM332.118 320
|
||||||
|
l-76.1182 76.1182v-76.1182h76.1182zM48 -16h288v288h-104c-13.2549 0 -24 10.7451 -24 24v104h-160v-416zM276.687 195.303c10.0049 10.0049 27.3135 2.99707 27.3135 -11.3135v-111.976c0 -14.2939 -17.2959 -21.332 -27.3135 -11.3135l-52.6865 52.6738v-37.374
|
||||||
|
c0 -11.0459 -8.9541 -20 -20 -20h-104c-11.0459 0 -20 8.9541 -20 20v104c0 11.0459 8.9541 20 20 20h104c11.0459 0 20 -8.9541 20 -20v-37.374z" />
|
||||||
|
<glyph glyph-name="file-code" unicode="" horiz-adv-x="384"
|
||||||
|
d="M149.9 98.9004c3.5 -3.30078 3.69922 -8.90039 0.399414 -12.4004l-17.3994 -18.5996c-1.60059 -1.80078 -4 -2.80078 -6.40039 -2.80078c-2.2002 0 -4.40039 0.900391 -6 2.40039l-57.7002 54.0996c-3.7002 3.40039 -3.7002 9.30078 0 12.8008l57.7002 54.0996
|
||||||
|
c3.40039 3.2998 9 3.2002 12.4004 -0.400391l17.3994 -18.5996l0.200195 -0.200195c3.2002 -3.59961 2.7998 -9.2002 -0.799805 -12.3994l-32.7998 -28.9004l32.7998 -28.9004zM369.9 350.1c9 -9 14.0996 -21.2998 14.0996 -34v-332.1c0 -26.5 -21.5 -48 -48 -48h-288
|
||||||
|
c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48.0996h204.1c12.7002 0 24.9004 -5.09961 33.9004 -14.0996zM256 396.1v-76.0996h76.0996zM336 -16v288h-104c-13.2998 0 -24 10.7002 -24 24v104h-160v-416h288zM209.6 234l24.4004 -7
|
||||||
|
c4.7002 -1.2998 7.40039 -6.2002 6 -10.9004l-54.7002 -188.199c-1.2998 -4.60059 -6.2002 -7.40039 -10.8994 -6l-24.4004 7.09961c-4.7002 1.2998 -7.40039 6.2002 -6 10.9004l54.7002 188.1c1.39941 4.7002 6.2002 7.40039 10.8994 6zM234.1 157.1
|
||||||
|
c-3.5 3.30078 -3.69922 8.90039 -0.399414 12.4004l17.3994 18.5996c3.30078 3.60059 8.90039 3.7002 12.4004 0.400391l57.7002 -54.0996c3.7002 -3.40039 3.7002 -9.30078 0 -12.8008l-57.7002 -54.0996c-3.5 -3.2998 -9.09961 -3.09961 -12.4004 0.400391
|
||||||
|
l-17.3994 18.5996l-0.200195 0.200195c-3.2002 3.59961 -2.7998 9.2002 0.799805 12.3994l32.7998 28.9004l-32.7998 28.9004z" />
|
||||||
|
<glyph glyph-name="life-ring" unicode=""
|
||||||
|
d="M256 -56c-136.967 0 -248 111.033 -248 248s111.033 248 248 248s248 -111.033 248 -248s-111.033 -248 -248 -248zM152.602 20.7197c63.2178 -38.3184 143.579 -38.3184 206.797 0l-53.4111 53.4111c-31.8467 -13.5215 -68.168 -13.5059 -99.9746 0zM336 192
|
||||||
|
c0 44.1123 -35.8877 80 -80 80s-80 -35.8877 -80 -80s35.8877 -80 80 -80s80 35.8877 80 80zM427.28 88.6016c38.3184 63.2178 38.3184 143.579 0 206.797l-53.4111 -53.4111c13.5215 -31.8467 13.5049 -68.168 0 -99.9746zM359.397 363.28
|
||||||
|
c-63.2168 38.3184 -143.578 38.3184 -206.796 0l53.4111 -53.4111c31.8457 13.5215 68.167 13.5049 99.9736 0zM84.7197 295.398c-38.3184 -63.2178 -38.3184 -143.579 0 -206.797l53.4111 53.4111c-13.5215 31.8467 -13.5059 68.168 0 99.9746z" />
|
||||||
|
<glyph glyph-name="paper-plane" unicode=""
|
||||||
|
d="M440 441.5c34.5996 19.9004 77.5996 -8.7998 71.5 -48.9004l-59.4004 -387.199c-2.2998 -14.5 -11.0996 -27.3008 -23.8994 -34.5c-7.2998 -4.10059 -15.4004 -6.2002 -23.6006 -6.2002c-6.19922 0 -12.3994 1.2002 -18.2998 3.59961l-111.899 46.2002l-43.8008 -59.0996
|
||||||
|
c-27.3994 -36.9004 -86.5996 -17.8008 -86.5996 28.5996v84.4004l-114.3 47.2998c-36.7998 15.0996 -40.1006 66 -5.7002 85.8994zM192 -16l36.5996 49.5l-36.5996 15.0996v-64.5996zM404.6 12.7002l59.4004 387.3l-416 -240l107.8 -44.5996l211.5 184.3
|
||||||
|
c14.2002 12.2998 34.4004 -5.7002 23.7002 -21.2002l-140.2 -202.3z" />
|
||||||
|
<glyph glyph-name="futbol" unicode="" horiz-adv-x="496"
|
||||||
|
d="M483.8 268.6c42.2998 -130.199 -29 -270.1 -159.2 -312.399c-25.5 -8.2998 -51.2998 -12.2002 -76.6992 -12.2002c-104.5 0 -201.7 66.5996 -235.7 171.4c-42.2998 130.199 29 270.1 159.2 312.399c25.5 8.2998 51.2998 12.2002 76.6992 12.2002
|
||||||
|
c104.5 0 201.7 -66.5996 235.7 -171.4zM409.3 74.9004c6.10059 8.39941 12.1006 16.8994 16.7998 26.1992c14.3008 28.1006 21.5 58.5 21.7002 89.2002l-38.8994 36.4004l-71.1006 -22.1006l-24.3994 -75.1992l43.6992 -60.9004zM409.3 310.3
|
||||||
|
c-24.5 33.4004 -58.7002 58.4004 -97.8994 71.4004l-47.4004 -26.2002v-73.7998l64.2002 -46.5l70.7002 22zM184.9 381.6c-39.9004 -13.2998 -73.5 -38.5 -97.8008 -71.8994l10.1006 -52.5l70.5996 -22l64.2002 46.5v73.7998zM139 68.5l43.5 61.7002l-24.2998 74.2998
|
||||||
|
l-71.1006 22.2002l-39 -36.4004c0.5 -55.7002 23.4004 -95.2002 37.8008 -115.3zM187.2 1.5c64.0996 -20.4004 115.5 -1.7998 121.7 0l22.3994 48.0996l-44.2998 61.7002h-78.5996l-43.6006 -61.7002z" />
|
||||||
|
<glyph glyph-name="newspaper" unicode="" horiz-adv-x="576"
|
||||||
|
d="M552 384c13.2549 0 24 -10.7451 24 -24v-336c0 -13.2549 -10.7451 -24 -24 -24h-496c-30.9277 0 -56 25.0723 -56 56v272c0 13.2549 10.7451 24 24 24h42.752c6.60547 18.623 24.3896 32 45.248 32h440zM48 56c0 -4.41113 3.58887 -8 8 -8s8 3.58887 8 8v248h-16v-248z
|
||||||
|
M528 48v288h-416v-280c0 -2.7168 -0.204102 -5.38574 -0.578125 -8h416.578zM172 168c-6.62695 0 -12 5.37305 -12 12v96c0 6.62695 5.37305 12 12 12h136c6.62695 0 12 -5.37305 12 -12v-96c0 -6.62695 -5.37305 -12 -12 -12h-136zM200 248v-40h80v40h-80zM160 108v24
|
||||||
|
c0 6.62695 5.37305 12 12 12h136c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-136c-6.62695 0 -12 5.37305 -12 12zM352 108v24c0 6.62695 5.37305 12 12 12h104c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-104
|
||||||
|
c-6.62695 0 -12 5.37305 -12 12zM352 252v24c0 6.62695 5.37305 12 12 12h104c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-104c-6.62695 0 -12 5.37305 -12 12zM352 180v24c0 6.62695 5.37305 12 12 12h104c6.62695 0 12 -5.37305 12 -12v-24
|
||||||
|
c0 -6.62695 -5.37305 -12 -12 -12h-104c-6.62695 0 -12 5.37305 -12 12z" />
|
||||||
|
<glyph glyph-name="bell-slash" unicode="" horiz-adv-x="640"
|
||||||
|
d="M633.99 -23.0195c6.91016 -5.52051 8.01953 -15.5908 2.5 -22.4902l-10 -12.4902c-5.53027 -6.88965 -15.5898 -8.00977 -22.4902 -2.49023l-598 467.51c-6.90039 5.52051 -8.01953 15.5908 -2.49023 22.4902l10 12.4902
|
||||||
|
c5.52051 6.90039 15.5898 8.00977 22.4902 2.49023zM163.53 80h182.84l61.3994 -48h-279.659c-19.1201 0 -31.9902 15.5996 -32.1006 32c-0.0498047 7.5498 2.61035 15.2598 8.61035 21.71c18.3701 19.7402 51.5703 49.6904 54.8398 140.42l45.4697 -35.5498
|
||||||
|
c-6.91992 -54.7803 -24.6895 -88.5498 -41.3994 -110.58zM320 352c-23.3496 0 -45 -7.17969 -62.9404 -19.4004l-38.1699 29.8408c19.6807 15.7793 43.1104 27.3096 69.1299 32.7197v20.8398c0 17.6699 14.3203 32 31.9805 32s31.9805 -14.3301 31.9805 -32v-20.8398
|
||||||
|
c73.46 -15.2598 127.939 -77.46 127.939 -155.16c0 -41.3604 6.03027 -70.7197 14.3398 -92.8496l-59.5293 46.54c-1.63086 13.96 -2.77051 28.8896 -2.79004 45.7295c0 0.200195 0.0595703 0.379883 0.0595703 0.580078c0 61.8604 -50.1396 112 -112 112zM320 -64
|
||||||
|
c-35.3203 0 -63.9697 28.6504 -63.9697 64h127.939c0 -35.3496 -28.6494 -64 -63.9697 -64z" />
|
||||||
|
<glyph glyph-name="copyright" unicode=""
|
||||||
|
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 -8c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200c-110.549 0 -200 -89.4688 -200 -200c0 -110.549 89.4678 -200 200 -200z
|
||||||
|
M363.351 93.0645c-9.61328 -9.71289 -45.5293 -41.3965 -104.064 -41.3965c-82.4297 0 -140.484 61.4248 -140.484 141.567c0 79.1514 60.2754 139.4 139.763 139.4c55.5303 0 88.7373 -26.6201 97.5928 -34.7783c2.13379 -1.96289 3.86523 -5.9082 3.86523 -8.80762
|
||||||
|
c0 -1.95508 -0.864258 -4.87402 -1.92969 -6.51465l-18.1543 -28.1133c-3.8418 -5.9502 -11.9668 -7.28223 -17.499 -2.9209c-8.5957 6.77637 -31.8145 22.5381 -61.708 22.5381c-48.3037 0 -77.916 -35.3301 -77.916 -80.082c0 -41.5889 26.8877 -83.6924 78.2764 -83.6924
|
||||||
|
c32.6572 0 56.8428 19.0391 65.7266 27.2256c5.26953 4.85645 13.5957 4.03906 17.8193 -1.73828l19.8652 -27.1699c1.28613 -1.74512 2.33008 -4.91992 2.33008 -7.08789c0 -2.72363 -1.56055 -6.5 -3.48242 -8.42969z" />
|
||||||
|
<glyph glyph-name="closed-captioning" unicode=""
|
||||||
|
d="M464 384c26.5 0 48 -21.5 48 -48v-288c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v288c0 26.5 21.5 48 48 48h416zM458 48c3.2998 0 6 2.7002 6 6v276c0 3.2998 -2.7002 6 -6 6h-404c-3.2998 0 -6 -2.7002 -6 -6v-276c0 -3.2998 2.7002 -6 6 -6h404z
|
||||||
|
M246.9 133.7c1.69922 -2.40039 1.5 -5.60059 -0.5 -7.7002c-53.6006 -56.7998 -172.801 -32.0996 -172.801 67.9004c0 97.2998 121.7 119.5 172.5 70.0996c2.10059 -2 2.5 -3.2002 1 -5.7002l-17.5 -30.5c-1.89941 -3.09961 -6.19922 -4 -9.09961 -1.7002
|
||||||
|
c-40.7998 32 -94.5996 14.9004 -94.5996 -31.1992c0 -48 51 -70.5 92.1992 -32.6006c2.80078 2.5 7.10059 2.10059 9.2002 -0.899414zM437.3 133.7c1.7002 -2.40039 1.5 -5.60059 -0.5 -7.7002c-53.5996 -56.9004 -172.8 -32.0996 -172.8 67.9004
|
||||||
|
c0 97.2998 121.7 119.5 172.5 70.0996c2.09961 -2 2.5 -3.2002 1 -5.7002l-17.5 -30.5c-1.90039 -3.09961 -6.2002 -4 -9.09961 -1.7002c-40.8008 32 -94.6006 14.9004 -94.6006 -31.1992c0 -48 51 -70.5 92.2002 -32.6006c2.7998 2.5 7.09961 2.10059 9.2002 -0.899414z
|
||||||
|
" />
|
||||||
|
<glyph glyph-name="object-group" unicode=""
|
||||||
|
d="M500 320h-12v-256h12c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v12h-320v-12c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h12v256h-12
|
||||||
|
c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-12h320v12c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12zM448 384v-32h32v32h-32zM32 384v-32h32v32h-32zM64 0v32
|
||||||
|
h-32v-32h32zM480 0v32h-32v-32h32zM440 64v256h-12c-6.62695 0 -12 5.37305 -12 12v12h-320v-12c0 -6.62695 -5.37305 -12 -12 -12h-12v-256h12c6.62695 0 12 -5.37305 12 -12v-12h320v12c0 6.62695 5.37305 12 12 12h12zM404 256c6.62695 0 12 -5.37207 12 -12v-168
|
||||||
|
c0 -6.62793 -5.37305 -12 -12 -12h-200c-6.62695 0 -12 5.37207 -12 12v52h-84c-6.62695 0 -12 5.37207 -12 12v168c0 6.62793 5.37305 12 12 12h200c6.62695 0 12 -5.37207 12 -12v-52h84zM136 280v-112h144v112h-144zM376 104v112h-56v-76
|
||||||
|
c0 -6.62793 -5.37305 -12 -12 -12h-76v-24h144z" />
|
||||||
|
<glyph glyph-name="object-ungroup" unicode="" horiz-adv-x="576"
|
||||||
|
d="M564 224h-12v-160h12c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v12h-224v-12c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h12v24h-88v-12
|
||||||
|
c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h12v160h-12c-6.62695 0 -12 5.37305 -12 12v72c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-12h224v12c0 6.62695 5.37305 12 12 12h72
|
||||||
|
c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-12v-24h88v12c0 6.62695 5.37305 12 12 12h72c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12zM352 384v-32h32v32h-32zM352 128v-32h32v32h-32zM64 96v32h-32v-32h32zM64 352v32
|
||||||
|
h-32v-32h32zM96 136h224v12c0 6.62695 5.37305 12 12 12h12v160h-12c-6.62695 0 -12 5.37305 -12 12v12h-224v-12c0 -6.62695 -5.37305 -12 -12 -12h-12v-160h12c6.62695 0 12 -5.37305 12 -12v-12zM224 0v32h-32v-32h32zM504 64v160h-12c-6.62695 0 -12 5.37305 -12 12v12
|
||||||
|
h-88v-88h12c6.62695 0 12 -5.37305 12 -12v-72c0 -6.62695 -5.37305 -12 -12 -12h-72c-6.62695 0 -12 5.37305 -12 12v12h-88v-24h12c6.62695 0 12 -5.37305 12 -12v-12h224v12c0 6.62695 5.37305 12 12 12h12zM544 0v32h-32v-32h32zM544 256v32h-32v-32h32z" />
|
||||||
|
<glyph glyph-name="sticky-note" unicode="" horiz-adv-x="448"
|
||||||
|
d="M448 99.8936c0 -10.9746 -6.29883 -26.1797 -14.0586 -33.9404l-83.8828 -83.8818c-7.75977 -7.76074 -22.9658 -14.0596 -33.9404 -14.0596h-268.118c-26.5098 0 -48 21.4902 -48 48v351.988c0 26.5098 21.4902 48 48 48h352c26.5098 0 48 -21.4902 48 -48v-268.106z
|
||||||
|
M320 19.8936l76.1182 76.1182h-76.1182v-76.1182zM400 368h-352v-351.988h224v104c0 13.2549 10.7451 24 24 24h104v223.988z" />
|
||||||
|
<glyph glyph-name="clone" unicode=""
|
||||||
|
d="M464 448c26.5098 0 48 -21.4902 48 -48v-320c0 -26.5098 -21.4902 -48 -48 -48h-48v-48c0 -26.5098 -21.4902 -48 -48 -48h-320c-26.5098 0 -48 21.4902 -48 48v320c0 26.5098 21.4902 48 48 48h48v48c0 26.5098 21.4902 48 48 48h320zM362 -16c3.31152 0 6 2.68848 6 6
|
||||||
|
v42h-224c-26.5098 0 -48 21.4902 -48 48v224h-42c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h308zM458 80c3.31152 0 6 2.68848 6 6v308c0 3.31152 -2.68848 6 -6 6h-308c-3.31152 0 -6 -2.68848 -6 -6v-308c0 -3.31152 2.68848 -6 6 -6h308z" />
|
||||||
|
<glyph glyph-name="hourglass" unicode="" horiz-adv-x="384"
|
||||||
|
d="M368 400c0 -80.0996 -31.8984 -165.619 -97.1797 -208c64.9912 -42.1934 97.1797 -127.436 97.1797 -208h4c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-360c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h4
|
||||||
|
c0 80.0996 31.8994 165.619 97.1797 208c-64.9912 42.1934 -97.1797 127.436 -97.1797 208h-4c-6.62695 0 -12 5.37305 -12 12v24c0 6.62695 5.37305 12 12 12h360c6.62695 0 12 -5.37305 12 -12v-24c0 -6.62695 -5.37305 -12 -12 -12h-4zM64 400
|
||||||
|
c0 -101.621 57.3066 -184 128 -184s128 82.3799 128 184h-256zM320 -16c0 101.62 -57.3076 184 -128 184s-128 -82.3799 -128 -184h256z" />
|
||||||
|
<glyph glyph-name="hand-rock" unicode=""
|
||||||
|
d="M408.864 368.948c48.8213 20.751 103.136 -15.0723 103.136 -67.9111v-114.443c0 -15.3955 -3.08887 -30.3906 -9.18262 -44.5674l-42.835 -99.6562c-4.99707 -11.625 -3.98242 -18.8574 -3.98242 -42.3701c0 -17.6729 -14.3271 -32 -32 -32h-252
|
||||||
|
c-17.6729 0 -32 14.3271 -32 32c0 27.3301 1.1416 29.2012 -3.11035 32.9033l-97.71 85.0811c-24.8994 21.6797 -39.1797 52.8926 -39.1797 85.6338v56.9531c0 47.4277 44.8457 82.0215 91.0459 71.1807c1.96094 55.751 63.5107 87.8262 110.671 60.8057
|
||||||
|
c29.1895 31.0713 78.8604 31.4473 108.334 -0.0214844c32.7051 18.6846 76.4121 10.3096 98.8135 -23.5879zM464 186.594v114.445c0 34.29 -52 33.8232 -52 0.676758c0 -8.83594 -7.16309 -16 -16 -16h-7c-8.83691 0 -16 7.16406 -16 16v26.751
|
||||||
|
c0 34.457 -52 33.707 -52 0.676758v-27.4287c0 -8.83594 -7.16309 -16 -16 -16h-7c-8.83691 0 -16 7.16406 -16 16v40.4658c0 34.3525 -52 33.8115 -52 0.677734v-41.1436c0 -8.83594 -7.16406 -16 -16 -16h-7c-8.83594 0 -16 7.16406 -16 16v26.751
|
||||||
|
c0 34.4023 -52 33.7744 -52 0.676758v-116.571c0 -8.83203 -7.16797 -16 -16 -16c-3.30664 0 -8.01367 1.7627 -10.5068 3.93359l-7 6.09473c-3.03223 2.64062 -5.49316 8.04688 -5.49316 12.0674v0v41.2275c0 34.2148 -52 33.8857 -52 0.677734v-56.9531
|
||||||
|
c0 -18.8555 8.27441 -36.874 22.7002 -49.4365l97.71 -85.0801c12.4502 -10.8398 19.5898 -26.4463 19.5898 -42.8164v-10.2861h220v7.07617c0 13.21 2.65332 26.0791 7.88281 38.25l42.835 99.6553c2.91602 6.75391 5.28223 18.207 5.28223 25.5635v0.0488281z" />
|
||||||
|
<glyph glyph-name="hand-paper" unicode="" horiz-adv-x="448"
|
||||||
|
d="M372.57 335.359c39.9062 5.63281 75.4297 -25.7393 75.4297 -66.3594v-131.564c-0.00195312 -12.7666 -2.33008 -33.2246 -5.19531 -45.666l-30.1836 -130.958c-3.34668 -14.5234 -16.2783 -24.8125 -31.1816 -24.8125h-222.897
|
||||||
|
c-9.10352 0 -20.7793 6.01758 -26.0615 13.4316l-119.97 168.415c-21.2441 29.8203 -14.8047 71.3574 14.5498 93.1533c18.7754 13.9395 42.1309 16.2979 62.083 8.87109v126.13c0 44.0547 41.125 75.5439 82.4053 64.9834c23.8926 48.1963 92.3535 50.2471 117.982 0.74707
|
||||||
|
c42.5186 11.1445 83.0391 -21.9346 83.0391 -65.5469v-10.8242zM399.997 137.437l-0.00195312 131.563c0 24.9492 -36.5703 25.5508 -36.5703 -0.691406v-76.3086c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v154.184
|
||||||
|
c0 25.501 -36.5703 26.3633 -36.5703 0.691406v-154.875c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v188.309c0 25.501 -36.5703 26.3545 -36.5703 0.691406v-189c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16
|
||||||
|
v153.309c0 25.501 -36.5713 26.3359 -36.5713 0.691406v-206.494c0 -15.5703 -20.0352 -21.9092 -29.0303 -9.2832l-27.1279 38.0791c-14.3711 20.1709 -43.833 -2.33496 -29.3945 -22.6045l115.196 -161.697h201.92l27.3252 118.551
|
||||||
|
c2.63086 11.417 3.96484 23.1553 3.96484 34.8857z" />
|
||||||
|
<glyph glyph-name="hand-scissors" unicode=""
|
||||||
|
d="M256 -32c-44.9561 0 -77.3428 43.2627 -64.0244 85.8535c-21.6484 13.71 -34.0156 38.7617 -30.3408 65.0068h-87.6348c-40.8037 0 -74 32.8105 -74 73.1406c0 40.3291 33.1963 73.1396 74 73.1396l94 -9.14062l-78.8496 18.6787
|
||||||
|
c-38.3076 14.7422 -57.04 57.4707 -41.9424 95.1123c15.0303 37.4736 57.7549 55.7803 95.6416 41.2012l144.929 -55.7568c24.9551 30.5566 57.8086 43.9932 92.2178 24.7324l97.999 -54.8525c20.9746 -11.7393 34.0049 -33.8457 34.0049 -57.6904v-205.702
|
||||||
|
c0 -30.7422 -21.4404 -57.5576 -51.7979 -64.5537l-118.999 -27.4268c-4.97168 -1.14648 -10.0889 -1.72949 -15.2031 -1.72949zM256 16.0127l70 -0.000976562c1.23633 0 3.21777 0.225586 4.42285 0.501953l119.001 27.4277
|
||||||
|
c8.58203 1.97754 14.5762 9.29102 14.5762 17.7812v205.701c0 6.4873 -3.62109 12.542 -9.44922 15.8047l-98 54.8545c-8.13965 4.55566 -18.668 2.61914 -24.4873 -4.50781l-21.7646 -26.6475c-2.65039 -3.24512 -8.20215 -5.87891 -12.3926 -5.87891
|
||||||
|
c-1.64062 0 -4.21484 0.477539 -5.74609 1.06738l-166.549 64.0908c-32.6543 12.5664 -50.7744 -34.5771 -19.2227 -46.7168l155.357 -59.7852c5.66016 -2.17773 10.2539 -8.86816 10.2539 -14.9326v0v-11.6328c0 -8.83691 -7.16309 -16 -16 -16h-182
|
||||||
|
c-34.375 0 -34.4297 -50.2803 0 -50.2803h182c8.83691 0 16 -7.16309 16 -16v-6.85645c0 -8.83691 -7.16309 -16 -16 -16h-28c-25.1221 0 -25.1592 -36.5674 0 -36.5674h28c8.83691 0 16 -7.16211 16 -16v-6.85547c0 -8.83691 -7.16309 -16 -16 -16
|
||||||
|
c-25.1201 0 -25.1602 -36.5674 0 -36.5674z" />
|
||||||
|
<glyph glyph-name="hand-lizard" unicode="" horiz-adv-x="576"
|
||||||
|
d="M556.686 157.458c12.6357 -19.4863 19.3145 -42.0615 19.3145 -65.2871v-124.171h-224v71.582l-99.751 38.7871c-2.7832 1.08203 -5.70996 1.63086 -8.69727 1.63086h-131.552c-30.8789 0 -56 25.1211 -56 56c0 48.5234 39.4766 88 88 88h113.709l18.333 48h-196.042
|
||||||
|
c-44.1123 0 -80 35.8877 -80 80v8c0 30.8779 25.1211 56 56 56h293.917c24.5 0 47.084 -12.2725 60.4111 -32.8291zM528 16v76.1709v0.0478516c0 11.7461 -5.19141 29.2734 -11.5879 39.124l-146.358 225.715c-4.44336 6.85254 -11.9707 10.9424 -20.1367 10.9424h-293.917
|
||||||
|
c-4.41113 0 -8 -3.58887 -8 -8v-8c0 -17.6445 14.3555 -32 32 -32h213.471c25.2021 0 42.626 -25.293 33.6299 -48.8457l-24.5518 -64.2812c-7.05371 -18.4658 -25.0732 -30.873 -44.8398 -30.873h-113.709c-22.0557 0 -40 -17.9443 -40 -40c0 -4.41113 3.58887 -8 8 -8
|
||||||
|
h131.552h0.0517578c7.44141 0 19.1074 -2.19238 26.041 -4.89355l99.752 -38.7881c18.5898 -7.22852 30.6035 -24.7881 30.6035 -44.7363v-23.582h128z" />
|
||||||
|
<glyph glyph-name="hand-spock" unicode=""
|
||||||
|
d="M21.0957 66.21c-26.9688 25.3818 -28.2471 67.7461 -2.87109 94.707c24.1982 25.7139 64.2881 28.2373 91.4824 5.72168l-31.04 136.509c-9.38379 41.2803 21.4336 81.0127 64.0713 81.8438c1.74414 28.9062 22.2656 54.4912 51.8818 61.2949
|
||||||
|
c36.001 8.27539 72.0176 -14.2266 80.3037 -50.2959l21.6748 -131.99l16.9014 105.25c9.02344 36.0947 45.4473 57.7021 81.25 48.75c27.3066 -6.82715 45.7061 -29.1357 49.8496 -53.9922c43.2285 0.212891 75.6436 -40.1133 65.5439 -82.5244l-31.7295 -133.41
|
||||||
|
c-0.938477 -3.94141 -1.41406 -7.99414 -1.41406 -12.0449v-36.8389v-0.00683594c0 -9.29102 -2.14355 -24.0596 -4.78516 -32.9668l-31.8145 -107.312c-4.02734 -13.585 -16.5107 -22.9043 -30.6807 -22.9043h-237.6c-7.00586 0 -16.8311 3.89648 -21.9316 8.69824z
|
||||||
|
M53.1641 128.021c-7.17969 -7.62891 -6.81543 -19.6777 0.813477 -26.8574l124.487 -117.164h219.311l28.4199 95.8613c1.86133 6.27637 2.80469 12.7793 2.80469 19.3281v36.8389c0.000976562 6.48047 1.21973 16.8574 2.71973 23.1621l31.7549 133.407
|
||||||
|
c5.83105 24.4893 -31.1445 33.25 -36.9658 8.80273l-26.9229 -113.105c-1.61523 -6.78711 -8.58887 -12.2949 -15.5645 -12.2949h-9.69434c-10.4072 0 -18.043 9.79199 -15.5225 19.8799l38.127 152.512c6.09766 24.376 -30.7607 33.6396 -36.8643 9.21777l-42.3721 -169.49
|
||||||
|
c-1.67285 -6.68945 -8.62695 -12.1191 -15.5225 -12.1191h-13.2168v0c-7.0332 0 -14.0195 5.5625 -15.5938 12.417l-45.2207 196.828c-5.64453 24.5684 -42.6572 15.9609 -37.0342 -8.50781l41.6191 -181.153c2.30078 -10.0156 -5.31738 -19.583 -15.5938 -19.583h-8.60352
|
||||||
|
h-0.000976562c-7.0498 0 -14.04 5.5791 -15.6025 12.4541l-30.3984 133.757c-5.55273 24.4395 -42.6504 16.1963 -37.0547 -8.4209l34.1299 -150.172c0.263672 -1.16309 0.397461 -2.35352 0.397461 -3.5459v-69.4795c0 -13.9941 -16.7754 -21.2432 -26.9658 -11.6523
|
||||||
|
l-53.0117 49.8936c-7.61523 7.16699 -19.6377 6.85938 -26.8564 -0.8125z" />
|
||||||
|
<glyph glyph-name="hand-pointer" unicode="" horiz-adv-x="448"
|
||||||
|
d="M358.182 268.639c43.1934 16.6348 89.8184 -15.7949 89.8184 -62.6387v-84c-0.000976562 -4.25 -0.775391 -11.0615 -1.72754 -15.2041l-27.4297 -118.999c-6.98242 -30.2969 -33.7549 -51.7969 -64.5566 -51.7969h-178.286c-21.2588 0 -41.3682 10.4102 -53.791 27.8457
|
||||||
|
l-109.699 154.001c-21.2432 29.8193 -14.8047 71.3574 14.5498 93.1523c18.8115 13.9658 42.1748 16.2822 62.083 8.87207v161.129c0 36.9443 29.7363 67 66.2861 67s66.2861 -30.0557 66.2861 -67v-73.6338c20.4131 2.85742 41.4678 -3.94238 56.5947 -19.6289
|
||||||
|
c27.1934 12.8467 60.3799 5.66992 79.8721 -19.0986zM80.9854 168.303c-14.4004 20.2119 -43.8008 -2.38281 -29.3945 -22.6055l109.712 -154c3.43457 -4.81934 8.92871 -7.69727 14.6973 -7.69727h178.285c8.49219 0 15.8037 5.99414 17.7822 14.5762l27.4297 119.001
|
||||||
|
c0.333008 1.44629 0.501953 2.93457 0.501953 4.42285v84c0 25.1602 -36.5713 25.1211 -36.5713 0c0 -8.83594 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16406 -16 16v21c0 25.1602 -36.5713 25.1201 -36.5713 0v-21c0 -8.83594 -7.16309 -16 -16 -16h-6.85938
|
||||||
|
c-8.83691 0 -16 7.16406 -16 16v35c0 25.1602 -36.5703 25.1201 -36.5703 0v-35c0 -8.83594 -7.16309 -16 -16 -16h-6.85742c-8.83691 0 -16 7.16406 -16 16v175c0 25.1602 -36.5713 25.1201 -36.5713 0v-241.493c0 -15.5703 -20.0352 -21.9092 -29.0303 -9.2832z
|
||||||
|
M176.143 48v96c0 8.83691 6.26855 16 14 16h6c7.73242 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26758 -16 -14 -16h-6c-7.73242 0 -14 7.16309 -14 16zM251.571 48v96c0 8.83691 6.26758 16 14 16h6c7.73145 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26855 -16 -14 -16h-6
|
||||||
|
c-7.73242 0 -14 7.16309 -14 16zM327 48v96c0 8.83691 6.26758 16 14 16h6c7.73242 0 14 -7.16309 14 -16v-96c0 -8.83691 -6.26758 -16 -14 -16h-6c-7.73242 0 -14 7.16309 -14 16z" />
|
||||||
|
<glyph glyph-name="hand-peace" unicode="" horiz-adv-x="448"
|
||||||
|
d="M362.146 256.024c42.5908 13.3184 85.8535 -19.0684 85.8535 -64.0244l-0.0117188 -70.001c-0.000976562 -4.25 -0.775391 -11.0615 -1.72949 -15.2031l-27.4268 -118.999c-6.99707 -30.3564 -33.8105 -51.7969 -64.5547 -51.7969h-205.702
|
||||||
|
c-23.8447 0 -45.9502 13.0303 -57.6904 34.0059l-54.8525 97.999c-19.2607 34.4092 -5.82422 67.2617 24.7324 92.2178l-55.7568 144.928c-14.5791 37.8867 3.72754 80.6113 41.2012 95.6416c37.6406 15.0977 80.3691 -3.63477 95.1123 -41.9424l18.6787 -78.8496
|
||||||
|
l-9.14062 94c0 40.8037 32.8096 74 73.1396 74s73.1406 -33.1963 73.1406 -74v-87.6348c26.2451 3.6748 51.2959 -8.69238 65.0068 -30.3408zM399.987 122l-0.000976562 70c0 25.1602 -36.5674 25.1201 -36.5674 0c0 -8.83691 -7.16309 -16 -16 -16h-6.85547
|
||||||
|
c-8.83789 0 -16 7.16309 -16 16v28c0 25.1592 -36.5674 25.1221 -36.5674 0v-28c0 -8.83691 -7.16309 -16 -16 -16h-6.85645c-8.83691 0 -16 7.16309 -16 16v182c0 34.4297 -50.2803 34.375 -50.2803 0v-182c0 -8.83691 -7.16309 -16 -16 -16h-11.6328v0
|
||||||
|
c-6.06445 0 -12.7549 4.59375 -14.9326 10.2539l-59.7842 155.357c-12.1396 31.5518 -59.2842 13.4326 -46.7168 -19.2227l64.0898 -166.549c0.589844 -1.53125 1.06738 -4.10547 1.06738 -5.74609c0 -4.19043 -2.63379 -9.74219 -5.87891 -12.3926l-26.6475 -21.7646
|
||||||
|
c-7.12695 -5.81934 -9.06445 -16.3467 -4.50781 -24.4873l54.8535 -98c3.26367 -5.82812 9.31934 -9.44922 15.8057 -9.44922h205.701c8.49121 0 15.8037 5.99414 17.7812 14.5762l27.4277 119.001c0.333008 1.44629 0.501953 2.93457 0.501953 4.42285z" />
|
||||||
|
<glyph glyph-name="registered" unicode=""
|
||||||
|
d="M256 440c136.967 0 248 -111.033 248 -248s-111.033 -248 -248 -248s-248 111.033 -248 248s111.033 248 248 248zM256 -8c110.549 0 200 89.4678 200 200c0 110.549 -89.4678 200 -200 200c-110.549 0 -200 -89.4688 -200 -200c0 -110.549 89.4678 -200 200 -200z
|
||||||
|
M366.442 73.791c4.40332 -7.99219 -1.37012 -17.791 -10.5107 -17.791h-42.8096h-0.0126953c-3.97559 0 -8.71582 2.84961 -10.5801 6.36035l-47.5156 89.3027h-31.958v-83.6631c0 -6.61719 -5.38281 -12 -12 -12h-38.5674c-6.61719 0 -12 5.38281 -12 12v248.304
|
||||||
|
c0 6.61719 5.38281 12 12 12h78.667c71.251 0 101.498 -32.749 101.498 -85.252c0 -31.6123 -15.2148 -59.2969 -39.4824 -73.1758c3.02148 -4.61719 0.225586 0.199219 53.2715 -96.085zM256.933 208.094c20.9131 0 32.4307 11.5186 32.4316 32.4316
|
||||||
|
c0 19.5752 -6.5127 31.709 -38.9297 31.709h-27.377v-64.1406h33.875z" />
|
||||||
|
<glyph glyph-name="calendar-plus" unicode="" horiz-adv-x="448"
|
||||||
|
d="M336 156v-24c0 -6.59961 -5.40039 -12 -12 -12h-76v-76c0 -6.59961 -5.40039 -12 -12 -12h-24c-6.59961 0 -12 5.40039 -12 12v76h-76c-6.59961 0 -12 5.40039 -12 12v24c0 6.59961 5.40039 12 12 12h76v76c0 6.59961 5.40039 12 12 12h24c6.59961 0 12 -5.40039 12 -12
|
||||||
|
v-76h76c6.59961 0 12 -5.40039 12 -12zM448 336v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40
|
||||||
|
c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||||
|
<glyph glyph-name="calendar-minus" unicode="" horiz-adv-x="448"
|
||||||
|
d="M124 120c-6.59961 0 -12 5.40039 -12 12v24c0 6.59961 5.40039 12 12 12h200c6.59961 0 12 -5.40039 12 -12v-24c0 -6.59961 -5.40039 -12 -12 -12h-200zM448 336v-352c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52
|
||||||
|
c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||||
|
<glyph glyph-name="calendar-times" unicode="" horiz-adv-x="448"
|
||||||
|
d="M311.7 73.2998l-17 -17c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-53.7002 53.7998l-53.7002 -53.6992c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-17 17c-4.7002 4.69922 -4.7002 12.2998 0 17l53.7002 53.6992l-53.7002 53.7002c-4.7002 4.7002 -4.7002 12.2998 0 17
|
||||||
|
l17 17c4.7002 4.7002 12.2998 4.7002 17 0l53.7002 -53.7002l53.7002 53.7002c4.7002 4.7002 12.2998 4.7002 17 0l17 -17c4.7002 -4.7002 4.7002 -12.2998 0 -17l-53.7998 -53.7998l53.6992 -53.7002c4.80078 -4.7002 4.80078 -12.2998 0.100586 -17zM448 336v-352
|
||||||
|
c0 -26.5 -21.5 -48 -48 -48h-352c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h48v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h128v52c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-52h48c26.5 0 48 -21.5 48 -48zM400 -10
|
||||||
|
v298h-352v-298c0 -3.2998 2.7002 -6 6 -6h340c3.2998 0 6 2.7002 6 6z" />
|
||||||
|
<glyph glyph-name="calendar-check" unicode="" horiz-adv-x="448"
|
||||||
|
d="M400 384c26.5098 0 48 -21.4902 48 -48v-352c0 -26.5098 -21.4902 -48 -48 -48h-352c-26.5098 0 -48 21.4902 -48 48v352c0 26.5098 21.4902 48 48 48h48v52c0 6.62695 5.37305 12 12 12h40c6.62695 0 12 -5.37305 12 -12v-52h128v52c0 6.62695 5.37305 12 12 12h40
|
||||||
|
c6.62695 0 12 -5.37305 12 -12v-52h48zM394 -16c3.31152 0 6 2.68848 6 6v298h-352v-298c0 -3.31152 2.68848 -6 6 -6h340zM341.151 184.65l-142.31 -141.169c-4.70508 -4.66699 -12.3027 -4.6377 -16.9707 0.0673828l-75.0908 75.6992
|
||||||
|
c-4.66699 4.70508 -4.6377 12.3027 0.0673828 16.9707l22.7197 22.5361c4.70508 4.66699 12.3027 4.63672 16.9697 -0.0693359l44.1035 -44.4609l111.072 110.182c4.70508 4.66699 12.3027 4.63672 16.9707 -0.0683594l22.5361 -22.7178
|
||||||
|
c4.66699 -4.70508 4.63672 -12.3027 -0.0683594 -16.9697z" />
|
||||||
|
<glyph glyph-name="map" unicode="" horiz-adv-x="576"
|
||||||
|
d="M560.02 416c8.4502 0 15.9805 -6.83008 15.9805 -16.0195v-346.32c0 -11.9609 -9.01367 -25.2705 -20.1201 -29.71l-151.83 -52.8105c-5.32617 -1.7334 -14.1953 -3.13965 -19.7969 -3.13965c-5.7373 0 -14.8105 1.47363 -20.2529 3.29004l-172 60.71l-170.05 -62.8398
|
||||||
|
c-1.99023 -0.790039 -4 -1.16016 -5.95996 -1.16016c-8.45996 0 -15.9902 6.83008 -15.9902 16.0195v346.32c0.00292969 11.959 9.0166 25.2686 20.1201 29.71l151.83 52.8105c6.43945 2.08984 13.1201 3.13965 19.8096 3.13965
|
||||||
|
c5.73242 -0.00195312 14.8008 -1.47168 20.2402 -3.28027l172 -60.7197h0.00976562l170.05 62.8398c1.98047 0.790039 4 1.16016 5.95996 1.16016zM224 357.58v-285.97l128 -45.1904v285.97zM48 29.9502l127.36 47.0801l0.639648 0.229492v286.2l-128 -44.5303v-288.979z
|
||||||
|
M528 65.0801v288.97l-127.36 -47.0693l-0.639648 -0.240234v-286.19z" />
|
||||||
|
<glyph glyph-name="comment-alt" unicode=""
|
||||||
|
d="M448 448c35.2998 0 64 -28.7002 64 -64v-288c0 -35.2998 -28.7002 -64 -64 -64h-144l-124.9 -93.5996c-2.19922 -1.7002 -4.69922 -2.40039 -7.09961 -2.40039c-6.2002 0 -12 4.90039 -12 12v84h-96c-35.2998 0 -64 28.7002 -64 64v288c0 35.2998 28.7002 64 64 64h384z
|
||||||
|
M464 96v288c0 8.7998 -7.2002 16 -16 16h-384c-8.7998 0 -16 -7.2002 -16 -16v-288c0 -8.7998 7.2002 -16 16 -16h144v-60l67.2002 50.4004l12.7998 9.59961h160c8.7998 0 16 7.2002 16 16z" />
|
||||||
|
<glyph glyph-name="pause-circle" unicode=""
|
||||||
|
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM352 272v-160c0 -8.7998 -7.2002 -16 -16 -16h-48
|
||||||
|
c-8.7998 0 -16 7.2002 -16 16v160c0 8.7998 7.2002 16 16 16h48c8.7998 0 16 -7.2002 16 -16zM240 272v-160c0 -8.7998 -7.2002 -16 -16 -16h-48c-8.7998 0 -16 7.2002 -16 16v160c0 8.7998 7.2002 16 16 16h48c8.7998 0 16 -7.2002 16 -16z" />
|
||||||
|
<glyph glyph-name="stop-circle" unicode=""
|
||||||
|
d="M504 192c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248s248 -111 248 -248zM56 192c0 -110.5 89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200zM352 272v-160c0 -8.7998 -7.2002 -16 -16 -16h-160
|
||||||
|
c-8.7998 0 -16 7.2002 -16 16v160c0 8.7998 7.2002 16 16 16h160c8.7998 0 16 -7.2002 16 -16z" />
|
||||||
|
<glyph glyph-name="handshake" unicode="" horiz-adv-x="640"
|
||||||
|
d="M519.2 320.1h120.8v-255.699h-64c-17.5 0 -31.7998 14.1992 -31.9004 31.6992h-57.8994c-1.7998 -8.19922 -5.2998 -16.0996 -10.9004 -23l-26.2002 -32.2998c-15.7998 -19.3994 -41.8994 -25.5 -64 -16.7998c-13.5 -16.5996 -30.5996 -24 -48.7998 -24
|
||||||
|
c-15.0996 0 -28.5996 5.09961 -41.0996 15.9004c-31.7998 -21.9004 -74.7002 -21.3008 -105.601 3.7998l-84.5996 76.3994h-9.09961c-0.100586 -17.5 -14.3008 -31.6992 -31.9004 -31.6992h-64v255.699h118l47.5996 47.6006c10.5 10.3994 24.8008 16.2998 39.6006 16.2998
|
||||||
|
h226.8v0c12.7812 0 30.5225 -7.30273 39.5996 -16.2998zM48 96.4004c8.7998 0 16 7.09961 16 16c0 8.7998 -7.2002 16 -16 16s-16 -7.2002 -16 -16c0 -8.80078 7.2002 -16 16 -16zM438 103.3c2.7002 3.40039 2.2002 8.5 -1.2002 11.2998l-108.2 87.8008l-8.19922 -7.5
|
||||||
|
c-40.3008 -36.8008 -86.7002 -11.8008 -101.5 4.39941c-26.7002 29 -25 74.4004 4.39941 101.3l38.7002 35.5h-56.7002c-2 -0.799805 -3.7002 -1.5 -5.7002 -2.2998l-61.6992 -61.5996h-41.9004v-128.101h27.7002l97.2998 -88
|
||||||
|
c16.0996 -13.0996 41.4004 -10.5 55.2998 6.60059l15.6006 19.2002l36.7998 -31.5c3 -2.40039 12 -4.90039 18 2.39941l30 36.5l23.8994 -19.3994c3.5 -2.80078 8.5 -2.2002 11.3008 1.19922zM544 144.1v128h-44.7002l-61.7002 61.6006
|
||||||
|
c-1.39941 1.5 -3.39941 2.2998 -5.5 2.2998l-83.6992 -0.200195c-10 0 -19.6006 -3.7002 -27 -10.5l-65.6006 -60.0996c-9.7002 -8.7998 -10.5 -24 -1.2002 -33.9004c8.90039 -9.39941 25.1006 -8.7002 34.6006 0l55.2002 50.6006c6.5 5.89941 16.5996 5.5 22.5996 -1
|
||||||
|
l10.9004 -11.7002c6 -6.5 5.5 -16.6006 -1 -22.6006l-12.5 -11.3994l102.699 -83.4004c2.80078 -2.2998 5.40039 -4.89941 7.7002 -7.7002h69.2002zM592 96.4004c8.7998 0 16 7.09961 16 16c0 8.7998 -7.2002 16 -16 16s-16 -7.2002 -16 -16c0 -8.80078 7.2002 -16 16 -16z
|
||||||
|
" />
|
||||||
|
<glyph glyph-name="envelope-open" unicode=""
|
||||||
|
d="M494.586 283.484c9.6123 -7.94824 17.4141 -24.5205 17.4141 -36.9932v-262.491c0 -26.5098 -21.4902 -48 -48 -48h-416c-26.5098 0 -48 21.4902 -48 48v262.515c0 12.5166 7.84668 29.1279 17.5146 37.0771c4.08008 3.35449 110.688 89.0996 135.15 108.549
|
||||||
|
c22.6992 18.1426 60.1299 55.8594 103.335 55.8594c43.4365 0 81.2314 -38.1914 103.335 -55.8594c23.5283 -18.707 130.554 -104.773 135.251 -108.656zM464 -10v253.632v0.00488281c0 1.5791 -0.996094 3.66602 -2.22363 4.6582
|
||||||
|
c-15.8633 12.8232 -108.793 87.5752 -132.366 106.316c-17.5527 14.0195 -49.7168 45.3887 -73.4102 45.3887c-23.6016 0 -55.2451 -30.8799 -73.4102 -45.3887c-23.5713 -18.7393 -116.494 -93.4795 -132.364 -106.293
|
||||||
|
c-1.40918 -1.13965 -2.22559 -2.85254 -2.22559 -4.66504v-253.653c0 -3.31152 2.68848 -6 6 -6h404c3.31152 0 6 2.68848 6 6zM432.009 177.704c4.24902 -5.15918 3.46484 -12.7949 -1.74512 -16.9814c-28.9746 -23.2822 -59.2734 -47.5967 -70.9287 -56.8623
|
||||||
|
c-22.6992 -18.1436 -60.1299 -55.8604 -103.335 -55.8604c-43.4521 0 -81.2871 38.2373 -103.335 55.8604c-11.2793 8.9668 -41.7441 33.4131 -70.9268 56.8643c-5.20996 4.1875 -5.99316 11.8223 -1.74512 16.9814l15.2578 18.5283
|
||||||
|
c4.17773 5.07227 11.6572 5.84277 16.7793 1.72559c28.6182 -23.001 58.5654 -47.0352 70.5596 -56.5713c17.5527 -14.0195 49.7168 -45.3887 73.4102 -45.3887c23.6016 0 55.2461 30.8799 73.4102 45.3887c11.9941 9.53516 41.9434 33.5703 70.5625 56.5684
|
||||||
|
c5.12207 4.11621 12.6016 3.3457 16.7783 -1.72656z" />
|
||||||
|
<glyph glyph-name="address-book" unicode="" horiz-adv-x="448"
|
||||||
|
d="M436 288h-20v-64h20c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-20v-64h20c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12h-20v-48c0 -26.5 -21.5 -48 -48 -48h-320c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48
|
||||||
|
h320c26.5 0 48 -21.5 48 -48v-48h20c6.59961 0 12 -5.40039 12 -12v-40c0 -6.59961 -5.40039 -12 -12 -12zM368 -16v416h-320v-416h320zM208 192c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64zM118.4 64
|
||||||
|
c-12.4004 0 -22.4004 8.59961 -22.4004 19.2002v19.2002c0 31.7998 30.0996 57.5996 67.2002 57.5996c11.3994 0 17.8994 -8 44.7998 -8c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996v-19.2002c0 -10.6006 -10 -19.2002 -22.4004 -19.2002
|
||||||
|
h-179.199z" />
|
||||||
|
<glyph glyph-name="address-card" unicode="" horiz-adv-x="576"
|
||||||
|
d="M528 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-480c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h480zM528 16v352h-480v-352h480zM208 192c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64z
|
||||||
|
M118.4 64c-12.4004 0 -22.4004 8.59961 -22.4004 19.2002v19.2002c0 31.7998 30.0996 57.5996 67.2002 57.5996c11.3994 0 17.8994 -8 44.7998 -8c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996v-19.2002
|
||||||
|
c0 -10.6006 -10 -19.2002 -22.4004 -19.2002h-179.199zM360 128c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 192c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112
|
||||||
|
c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 256c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112z" />
|
||||||
|
<glyph glyph-name="user-circle" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 344c53 0 96 -43 96 -96s-43 -96 -96 -96s-96 43 -96 96s43 96 96 96zM248 200c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8
|
||||||
|
c49.7002 0 95.0996 18.2998 130.1 48.4004c-14.8994 23 -40.3994 38.5 -69.5996 39.5c-20.7998 -6.5 -40.5996 -9.60059 -60.5 -9.60059s-39.7002 3.2002 -60.5 9.60059c-29.2002 -0.900391 -54.7002 -16.5 -69.5996 -39.5c35 -30.1006 80.3994 -48.4004 130.1 -48.4004z
|
||||||
|
M410.7 76.0996c23.3994 32.7002 37.2998 72.7002 37.2998 115.9c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200c0 -43.2002 13.9004 -83.2002 37.2998 -115.9c24.5 31.4004 62.2002 51.9004 105.101 51.9004c10.1992 0 26.0996 -9.59961 57.5996 -9.59961
|
||||||
|
c31.5996 0 47.4004 9.59961 57.5996 9.59961c43 0 80.7002 -20.5 105.101 -51.9004z" />
|
||||||
|
<glyph glyph-name="id-badge" unicode="" horiz-adv-x="384"
|
||||||
|
d="M336 448c26.5 0 48 -21.5 48 -48v-416c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v416c0 26.5 21.5 48 48 48h288zM336 -16v416h-288v-416h288zM144 336c-8.7998 0 -16 7.2002 -16 16s7.2002 16 16 16h96c8.7998 0 16 -7.2002 16 -16s-7.2002 -16 -16 -16
|
||||||
|
h-96zM192 160c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64zM102.4 32c-12.4004 0 -22.4004 8.59961 -22.4004 19.2002v19.2002c0 31.7998 30.0996 57.5996 67.2002 57.5996c11.3994 0 17.8994 -8 44.7998 -8
|
||||||
|
c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996v-19.2002c0 -10.6006 -10 -19.2002 -22.4004 -19.2002h-179.199z" />
|
||||||
|
<glyph glyph-name="id-card" unicode="" horiz-adv-x="576"
|
||||||
|
d="M528 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-480c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h480zM528 16v288h-480v-288h32.7998c-1 4.5 -0.799805 -3.59961 -0.799805 22.4004c0 31.7998 30.0996 57.5996 67.2002 57.5996
|
||||||
|
c11.3994 0 17.8994 -8 44.7998 -8c26.0996 0 34 8 44.7998 8c37.1006 0 67.2002 -25.7998 67.2002 -57.5996c0 -26 0.0996094 -17.9004 -0.799805 -22.4004h224.8zM360 96c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16
|
||||||
|
c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 160c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM360 224c-4.40039 0 -8 3.59961 -8 8v16c0 4.40039 3.59961 8 8 8h112
|
||||||
|
c4.40039 0 8 -3.59961 8 -8v-16c0 -4.40039 -3.59961 -8 -8 -8h-112zM192 128c-35.2998 0 -64 28.7002 -64 64s28.7002 64 64 64s64 -28.7002 64 -64s-28.7002 -64 -64 -64z" />
|
||||||
|
<glyph glyph-name="window-maximize" unicode=""
|
||||||
|
d="M464 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h416zM464 22v234h-416v-234c0 -3.2998 2.7002 -6 6 -6h404c3.2998 0 6 2.7002 6 6z" />
|
||||||
|
<glyph glyph-name="window-minimize" unicode=""
|
||||||
|
d="M480 -32h-448c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32h448c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32z" />
|
||||||
|
<glyph glyph-name="window-restore" unicode=""
|
||||||
|
d="M464 448c26.5 0 48 -21.5 48 -48v-320c0 -26.5 -21.5 -48 -48 -48h-48v-48c0 -26.5 -21.5 -48 -48 -48h-320c-26.5 0 -48 21.5 -48 48v320c0 26.5 21.5 48 48 48h48v48c0 26.5 21.5 48 48 48h320zM368 -16v208h-320v-208h320zM464 80v320h-320v-48h224
|
||||||
|
c26.5 0 48 -21.5 48 -48v-224h48z" />
|
||||||
|
<glyph glyph-name="snowflake" unicode="" horiz-adv-x="448"
|
||||||
|
d="M440.1 92.7998c7.60059 -4.39941 10.1006 -14.2002 5.5 -21.7002l-7.89941 -13.8994c-4.40039 -7.7002 -14 -10.2998 -21.5 -5.90039l-39.2002 23l9.09961 -34.7002c2.30078 -8.5 -2.69922 -17.2998 -11.0996 -19.5996l-15.2002 -4.09961
|
||||||
|
c-8.39941 -2.30078 -17.0996 2.7998 -19.2998 11.2998l-21.2998 81l-71.9004 42.2002v-84.5l58.2998 -59.3008c6.10059 -6.19922 6.10059 -16.3994 0 -22.5996l-11.0996 -11.2998c-6.09961 -6.2002 -16.0996 -6.2002 -22.2002 0l-24.8994 25.3994v-46.0996
|
||||||
|
c0 -8.7998 -7 -16 -15.7002 -16h-15.7002c-8.7002 0 -15.7002 7.2002 -15.7002 16v45.9004l-24.8994 -25.4004c-6.10059 -6.2002 -16.1006 -6.2002 -22.2002 0l-11.1006 11.2998c-6.09961 6.2002 -6.09961 16.4004 0 22.6006l58.3008 59.2998v84.5l-71.9004 -42.2002
|
||||||
|
l-21.2998 -81c-2.2998 -8.5 -10.9004 -13.5996 -19.2998 -11.2998l-15.2002 4.09961c-8.40039 2.2998 -13.2998 11.1006 -11.1006 19.6006l9.10059 34.6992l-39.2002 -23c-7.5 -4.39941 -17.2002 -1.7998 -21.5 5.90039l-7.90039 13.9004
|
||||||
|
c-4.2998 7.69922 -1.69922 17.5 5.80078 21.8994l39.1992 23l-34.0996 9.2998c-8.40039 2.30078 -13.2998 11.1006 -11.0996 19.6006l4.09961 15.5c2.2998 8.5 10.9004 13.5996 19.2998 11.2998l79.7002 -21.7002l71.9004 42.2002l-71.9004 42.2002l-79.7002 -21.7002
|
||||||
|
c-8.39941 -2.2998 -17.0996 2.7998 -19.2998 11.2998l-4.09961 15.5c-2.30078 8.5 2.69922 17.2998 11.0996 19.6006l34.0996 9.09961l-39.1992 23c-7.60059 4.5 -10.1006 14.2002 -5.80078 21.9004l7.90039 13.8994c4.40039 7.7002 14 10.2998 21.5 5.90039l39.2002 -23
|
||||||
|
l-9.10059 34.7002c-2.2998 8.5 2.7002 17.2998 11.1006 19.5996l15.2002 4.09961c8.39941 2.30078 17.0996 -2.7998 19.2998 -11.2998l21.2998 -81l71.9004 -42.2002v84.5l-58.3008 59.3008c-6.09961 6.19922 -6.09961 16.3994 0 22.5996l11.5 11.2998
|
||||||
|
c6.10059 6.2002 16.1006 6.2002 22.2002 0l24.9004 -25.3994v46.0996c0 8.7998 7 16 15.7002 16h15.6992c8.7002 0 15.7002 -7.2002 15.7002 -16v-45.9004l24.9004 25.4004c6.09961 6.2002 16.0996 6.2002 22.2002 0l11.0996 -11.2998
|
||||||
|
c6.09961 -6.2002 6.09961 -16.4004 0 -22.6006l-58.2998 -59.2998v-84.5l71.8994 42.2002l21.3008 81c2.2998 8.5 10.8994 13.5996 19.2998 11.2998l15.2002 -4.09961c8.39941 -2.2998 13.2998 -11.1006 11.0996 -19.6006l-9.09961 -34.6992l39.1992 23
|
||||||
|
c7.5 4.39941 17.2002 1.7998 21.5 -5.90039l7.90039 -13.9004c4.2998 -7.69922 1.7002 -17.5 -5.7998 -21.8994l-39.2002 -23l34.0996 -9.2998c8.40039 -2.30078 13.3008 -11.1006 11.1006 -19.6006l-4.10059 -15.5c-2.2998 -8.5 -10.8994 -13.5996 -19.2998 -11.2998
|
||||||
|
l-79.7002 21.7002l-71.8994 -42.2002l71.7998 -42.2002l79.7002 21.7002c8.39941 2.2998 17.0996 -2.7998 19.2998 -11.2998l4.09961 -15.5c2.30078 -8.5 -2.69922 -17.2998 -11.0996 -19.6006l-34.0996 -9.2998z" />
|
||||||
|
<glyph glyph-name="trash-alt" unicode="" horiz-adv-x="448"
|
||||||
|
d="M268 32c-6.62402 0 -12 5.37598 -12 12v216c0 6.62402 5.37598 12 12 12h24c6.62402 0 12 -5.37598 12 -12v-216c0 -6.62402 -5.37598 -12 -12 -12h-24zM432 368c8.83203 0 16 -7.16797 16 -16v-16c0 -8.83203 -7.16797 -16 -16 -16h-16v-336
|
||||||
|
c0 -26.4961 -21.5039 -48 -48 -48h-288c-26.4961 0 -48 21.5039 -48 48v336h-16c-8.83203 0 -16 7.16797 -16 16v16c0 8.83203 7.16797 16 16 16h82.4102l34.0195 56.7002c7.71875 12.8613 26.1572 23.2998 41.1572 23.2998h0.00292969h100.82h0.0224609
|
||||||
|
c15 0 33.4385 -10.4385 41.1572 -23.2998l34 -56.7002h82.4102zM171.84 397.09l-17.4502 -29.0898h139.221l-17.46 29.0898c-0.96582 1.60645 -3.26953 2.91016 -5.14355 2.91016h-0.00683594h-94h-0.0166016c-1.87402 0 -4.17871 -1.30371 -5.14355 -2.91016zM368 -16v336
|
||||||
|
h-288v-336h288zM156 32c-6.62402 0 -12 5.37598 -12 12v216c0 6.62402 5.37598 12 12 12h24c6.62402 0 12 -5.37598 12 -12v-216c0 -6.62402 -5.37598 -12 -12 -12h-24z" />
|
||||||
|
<glyph glyph-name="images" unicode="" horiz-adv-x="576"
|
||||||
|
d="M480 32v-16c0 -26.5098 -21.4902 -48 -48 -48h-384c-26.5098 0 -48 21.4902 -48 48v256c0 26.5098 21.4902 48 48 48h16v-48h-10c-3.31152 0 -6 -2.68848 -6 -6v-244c0 -3.31152 2.68848 -6 6 -6h372c3.31152 0 6 2.68848 6 6v10h48zM522 368h-372
|
||||||
|
c-3.31152 0 -6 -2.68848 -6 -6v-244c0 -3.31152 2.68848 -6 6 -6h372c3.31152 0 6 2.68848 6 6v244c0 3.31152 -2.68848 6 -6 6zM528 416c26.5098 0 48 -21.4902 48 -48v-256c0 -26.5098 -21.4902 -48 -48 -48h-384c-26.5098 0 -48 21.4902 -48 48v256
|
||||||
|
c0 26.5098 21.4902 48 48 48h384zM264 304c0 -22.0908 -17.9092 -40 -40 -40s-40 17.9092 -40 40s17.9092 40 40 40s40 -17.9092 40 -40zM192 208l39.5146 39.5146c4.68652 4.68652 12.2842 4.68652 16.9717 0l39.5137 -39.5146l103.515 103.515
|
||||||
|
c4.68652 4.68652 12.2842 4.68652 16.9717 0l71.5137 -71.5146v-80h-288v48z" />
|
||||||
|
<glyph glyph-name="clipboard" unicode="" horiz-adv-x="384"
|
||||||
|
d="M336 384c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-288c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h80c0 35.2998 28.7002 64 64 64s64 -28.7002 64 -64h80zM192 408c-13.2998 0 -24 -10.7002 -24 -24s10.7002 -24 24 -24s24 10.7002 24 24
|
||||||
|
s-10.7002 24 -24 24zM336 -10v340c0 3.2998 -2.7002 6 -6 6h-42v-36c0 -6.59961 -5.40039 -12 -12 -12h-168c-6.59961 0 -12 5.40039 -12 12v36h-42c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h276c3.2998 0 6 2.7002 6 6z" />
|
||||||
|
<glyph glyph-name="arrow-alt-circle-down" unicode=""
|
||||||
|
d="M256 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM256 -8c110.5 0 200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200zM224 308c0 6.59961 5.40039 12 12 12h40c6.59961 0 12 -5.40039 12 -12v-116
|
||||||
|
h67c10.7002 0 16.0996 -12.9004 8.5 -20.5l-99 -99c-4.7002 -4.7002 -12.2998 -4.7002 -17 0l-99 99c-7.5 7.59961 -2.2002 20.5 8.5 20.5h67v116z" />
|
||||||
|
<glyph glyph-name="arrow-alt-circle-left" unicode=""
|
||||||
|
d="M8 192c0 137 111 248 248 248s248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248zM456 192c0 110.5 -89.5 200 -200 200s-200 -89.5 -200 -200s89.5 -200 200 -200s200 89.5 200 200zM384 212v-40c0 -6.59961 -5.40039 -12 -12 -12h-116v-67
|
||||||
|
c0 -10.7002 -12.9004 -16 -20.5 -8.5l-99 99c-4.7002 4.7002 -4.7002 12.2998 0 17l99 99c7.59961 7.59961 20.5 2.2002 20.5 -8.5v-67h116c6.59961 0 12 -5.40039 12 -12z" />
|
||||||
|
<glyph glyph-name="arrow-alt-circle-right" unicode=""
|
||||||
|
d="M504 192c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248s248 -111 248 -248zM56 192c0 -110.5 89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200s-200 -89.5 -200 -200zM128 172v40c0 6.59961 5.40039 12 12 12h116v67
|
||||||
|
c0 10.7002 12.9004 16 20.5 8.5l99 -99c4.7002 -4.7002 4.7002 -12.2998 0 -17l-99 -99c-7.59961 -7.59961 -20.5 -2.2002 -20.5 8.5v67h-116c-6.59961 0 -12 5.40039 -12 12z" />
|
||||||
|
<glyph glyph-name="arrow-alt-circle-up" unicode=""
|
||||||
|
d="M256 -56c-137 0 -248 111 -248 248s111 248 248 248s248 -111 248 -248s-111 -248 -248 -248zM256 392c-110.5 0 -200 -89.5 -200 -200s89.5 -200 200 -200s200 89.5 200 200s-89.5 200 -200 200zM276 64h-40c-6.59961 0 -12 5.40039 -12 12v116h-67
|
||||||
|
c-10.7002 0 -16 12.9004 -8.5 20.5l99 99c4.7002 4.7002 12.2998 4.7002 17 0l99 -99c7.59961 -7.59961 2.2002 -20.5 -8.5 -20.5h-67v-116c0 -6.59961 -5.40039 -12 -12 -12z" />
|
||||||
|
<glyph glyph-name="gem" unicode="" horiz-adv-x="576"
|
||||||
|
d="M464 448c4.09961 0 7.7998 -2 10.0996 -5.40039l99.9004 -147.199c2.90039 -4.40039 2.59961 -10.1006 -0.700195 -14.2002l-276 -340.8c-4.7998 -5.90039 -13.7998 -5.90039 -18.5996 0l-276 340.8c-3.2998 4 -3.60059 9.7998 -0.700195 14.2002l100 147.199
|
||||||
|
c2.2002 3.40039 6 5.40039 10 5.40039h352zM444.7 400h-56.7998l51.6992 -96h68.4004zM242.6 400l-51.5996 -96h194l-51.7002 96h-90.7002zM131.3 400l-63.2998 -96h68.4004l51.6992 96h-56.7998zM88.2998 256l119.7 -160l-68.2998 160h-51.4004zM191.2 256l96.7998 -243.3
|
||||||
|
l96.7998 243.3h-193.6zM368 96l119.6 160h-51.3994z" />
|
||||||
|
<glyph glyph-name="money-bill-alt" unicode="" horiz-adv-x="640"
|
||||||
|
d="M320 304c53.0195 0 96 -50.1396 96 -112c0 -61.8701 -43 -112 -96 -112c-53.0195 0 -96 50.1504 -96 112c0 61.8604 42.9805 112 96 112zM360 136v16c0 4.41992 -3.58008 8 -8 8h-16v88c0 4.41992 -3.58008 8 -8 8h-13.5801h-0.000976562
|
||||||
|
c-4.01074 0 -9.97266 -1.80566 -13.3086 -4.03027l-15.3301 -10.2197c-1.96777 -1.30957 -3.56445 -4.29004 -3.56445 -6.65332c0 -1.33691 0.601562 -3.32422 1.34375 -4.43652l8.88086 -13.3105c1.30859 -1.9668 4.29004 -3.56445 6.65332 -3.56445
|
||||||
|
c1.33691 0 3.32422 0.602539 4.43652 1.34473l0.469727 0.310547v-55.4404h-16c-4.41992 0 -8 -3.58008 -8 -8v-16c0 -4.41992 3.58008 -8 8 -8h64c4.41992 0 8 3.58008 8 8zM608 384c17.6699 0 32 -14.3301 32 -32v-320c0 -17.6699 -14.3301 -32 -32 -32h-576
|
||||||
|
c-17.6699 0 -32 14.3301 -32 32v320c0 17.6699 14.3301 32 32 32h576zM592 112v160c-35.3496 0 -64 28.6504 -64 64h-416c0 -35.3496 -28.6504 -64 -64 -64v-160c35.3496 0 64 -28.6504 64 -64h416c0 35.3496 28.6504 64 64 64z" />
|
||||||
|
<glyph glyph-name="window-close" unicode=""
|
||||||
|
d="M464 416c26.5 0 48 -21.5 48 -48v-352c0 -26.5 -21.5 -48 -48 -48h-416c-26.5 0 -48 21.5 -48 48v352c0 26.5 21.5 48 48 48h416zM464 22v340c0 3.2998 -2.7002 6 -6 6h-404c-3.2998 0 -6 -2.7002 -6 -6v-340c0 -3.2998 2.7002 -6 6 -6h404c3.2998 0 6 2.7002 6 6z
|
||||||
|
M356.5 253.4l-61.4004 -61.4004l61.4004 -61.4004c4.59961 -4.59961 4.59961 -12.0996 0 -16.7998l-22.2998 -22.2998c-4.60059 -4.59961 -12.1006 -4.59961 -16.7998 0l-61.4004 61.4004l-61.4004 -61.4004c-4.59961 -4.59961 -12.0996 -4.59961 -16.7998 0
|
||||||
|
l-22.2998 22.2998c-4.59961 4.60059 -4.59961 12.1006 0 16.7998l61.4004 61.4004l-61.4004 61.4004c-4.59961 4.59961 -4.59961 12.0996 0 16.7998l22.2998 22.2998c4.60059 4.59961 12.1006 4.59961 16.7998 0l61.4004 -61.4004l61.4004 61.4004
|
||||||
|
c4.59961 4.59961 12.0996 4.59961 16.7998 0l22.2998 -22.2998c4.7002 -4.60059 4.7002 -12.1006 0 -16.7998z" />
|
||||||
|
<glyph glyph-name="comment-dots" unicode=""
|
||||||
|
d="M144 240c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM256 240c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM368 240c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32
|
||||||
|
s-32 14.2998 -32 32s14.2998 32 32 32zM256 416c141.4 0 256 -93.0996 256 -208s-114.6 -208 -256 -208c-32.7998 0 -64 5.2002 -92.9004 14.2998c-29.0996 -20.5996 -77.5996 -46.2998 -139.1 -46.2998c-9.59961 0 -18.2998 5.7002 -22.0996 14.5
|
||||||
|
c-3.80078 8.7998 -2 19 4.59961 26c0.5 0.400391 31.5 33.7998 46.4004 73.2002c-33 35.0996 -52.9004 78.7002 -52.9004 126.3c0 114.9 114.6 208 256 208zM256 48c114.7 0 208 71.7998 208 160s-93.2998 160 -208 160s-208 -71.7998 -208 -160
|
||||||
|
c0 -42.2002 21.7002 -74.0996 39.7998 -93.4004l20.6006 -21.7998l-10.6006 -28.0996c-5.5 -14.5 -12.5996 -28.1006 -19.8994 -40.2002c23.5996 7.59961 43.1992 18.9004 57.5 29l19.5 13.7998l22.6992 -7.2002c25.3008 -8 51.7002 -12.0996 78.4004 -12.0996z" />
|
||||||
|
<glyph glyph-name="smile-wink" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM365.8 138.4c10.2002 -8.5 11.6006 -23.6006 3.10059 -33.8008
|
||||||
|
c-30 -36 -74.1006 -56.5996 -120.9 -56.5996s-90.9004 20.5996 -120.9 56.5996c-8.39941 10.2002 -7.09961 25.3008 3.10059 33.8008c10.0996 8.39941 25.2998 7.09961 33.7998 -3.10059c20.7998 -25.0996 51.5 -39.3994 84 -39.3994s63.2002 14.3994 84 39.3994
|
||||||
|
c8.5 10.2002 23.5996 11.6006 33.7998 3.10059zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 268c25.7002 0 55.9004 -16.9004 59.7002 -42.0996c1.7998 -11.1006 -11.2998 -18.2002 -19.7998 -10.8008l-9.5 8.5
|
||||||
|
c-14.8008 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-8.30078 -7.39941 -21.5 -0.399414 -19.8008 10.8008c4 25.1992 34.2002 42.0996 59.9004 42.0996z" />
|
||||||
|
<glyph glyph-name="angry" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM248 136c33.5996 0 65.2002 -14.7998 86.7998 -40.5996
|
||||||
|
c8.40039 -10.2002 7.10059 -25.3008 -3.09961 -33.8008c-10.6006 -8.89941 -25.7002 -6.69922 -33.7998 3c-24.8008 29.7002 -75 29.7002 -99.8008 0c-8.5 -10.1992 -23.5996 -11.5 -33.7998 -3s-11.5996 23.6006 -3.09961 33.8008
|
||||||
|
c21.5996 25.7998 53.2002 40.5996 86.7998 40.5996zM200 208c0 -17.7002 -14.2998 -32.0996 -32 -32.0996s-32 14.2998 -32 32c0 6.19922 2.2002 11.6992 5.2998 16.5996l-28.2002 8.5c-12.6992 3.7998 -19.8994 17.2002 -16.0996 29.9004
|
||||||
|
c3.7998 12.6992 17.0996 20 29.9004 16.0996l80 -24c12.6992 -3.7998 19.8994 -17.2002 16.0996 -29.9004c-3.09961 -10.3994 -12.7002 -17.0996 -23 -17.0996zM399 262.9c3.7998 -12.7002 -3.40039 -26.1006 -16.0996 -29.8008l-28.2002 -8.5
|
||||||
|
c3.09961 -4.89941 5.2998 -10.3994 5.2998 -16.5996c0 -17.7002 -14.2998 -32 -32 -32s-32 14.2998 -32 32c-10.2998 0 -19.9004 6.7002 -23 17.0996c-3.7998 12.7002 3.40039 26.1006 16.0996 29.9004l80 24c12.8008 3.7998 26.1006 -3.40039 29.9004 -16.0996z" />
|
||||||
|
<glyph glyph-name="dizzy" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM214.2 209.9
|
||||||
|
c-7.90039 -7.90039 -20.5 -7.90039 -28.4004 -0.200195l-17.7998 17.7998l-17.7998 -17.7998c-7.7998 -7.7998 -20.5 -7.7998 -28.2998 0c-7.80078 7.7998 -7.80078 20.5 0 28.2998l17.8994 17.9004l-17.8994 17.8994c-7.80078 7.7998 -7.80078 20.5 0 28.2998
|
||||||
|
c7.7998 7.80078 20.5 7.80078 28.2998 0l17.7998 -17.7998l17.9004 17.9004c7.7998 7.7998 20.5 7.7998 28.2998 0s7.7998 -20.5 0 -28.2998l-17.9004 -17.9004l17.9004 -17.7998c7.7998 -7.7998 7.7998 -20.5 0 -28.2998zM374.2 302.1
|
||||||
|
c7.7002 -7.7998 7.7002 -20.3994 0 -28.1992l-17.9004 -17.9004l17.7998 -18c7.80078 -7.7998 7.80078 -20.5 0 -28.2998c-7.7998 -7.7998 -20.5 -7.7998 -28.2998 0l-17.7998 17.7998l-17.7998 -17.7998c-7.7998 -7.7998 -20.5 -7.7998 -28.2998 0
|
||||||
|
c-7.80078 7.7998 -7.80078 20.5 0 28.2998l17.8994 17.9004l-17.8994 17.8994c-7.80078 7.7998 -7.80078 20.5 0 28.2998c7.7998 7.80078 20.5 7.80078 28.2998 0l17.7998 -17.7998l17.9004 17.7998c7.7998 7.80078 20.5 7.80078 28.2998 0zM248 176
|
||||||
|
c35.2998 0 64 -28.7002 64 -64s-28.7002 -64 -64 -64s-64 28.7002 -64 64s28.7002 64 64 64z" />
|
||||||
|
<glyph glyph-name="flushed" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM344 304c44.2002 0 80 -35.7998 80 -80s-35.7998 -80 -80 -80
|
||||||
|
s-80 35.7998 -80 80s35.7998 80 80 80zM344 176c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM344 248c13.2998 0 24 -10.7002 24 -24s-10.7002 -24 -24 -24s-24 10.7002 -24 24s10.7002 24 24 24zM232 224c0 -44.2002 -35.7998 -80 -80 -80
|
||||||
|
s-80 35.7998 -80 80s35.7998 80 80 80s80 -35.7998 80 -80zM152 176c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM152 248c13.2998 0 24 -10.7002 24 -24s-10.7002 -24 -24 -24s-24 10.7002 -24 24s10.7002 24 24 24zM312 104
|
||||||
|
c13.2002 0 24 -10.7998 24 -24s-10.7998 -24 -24 -24h-128c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24h128z" />
|
||||||
|
<glyph glyph-name="frown-open" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM200 240c0 -17.7002 -14.2998 -32 -32 -32s-32 14.2998 -32 32
|
||||||
|
s14.2998 32 32 32s32 -14.2998 32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM248 160c35.5996 0 88.7998 -21.2998 95.7998 -61.2002c2 -11.7998 -9.09961 -21.5996 -20.5 -18.0996
|
||||||
|
c-31.2002 9.59961 -59.3994 15.2998 -75.2998 15.2998s-44.0996 -5.7002 -75.2998 -15.2998c-11.5 -3.40039 -22.5 6.2998 -20.5 18.0996c7 39.9004 60.2002 61.2002 95.7998 61.2002z" />
|
||||||
|
<glyph glyph-name="grimace" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
||||||
|
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM344 192c26.5 0 48 -21.5 48 -48v-32c0 -26.5 -21.5 -48 -48 -48h-192c-26.5 0 -48 21.5 -48 48v32c0 26.5 21.5 48 48 48
|
||||||
|
h192zM176 96v24h-40v-8c0 -8.7998 7.2002 -16 16 -16h24zM176 136v24h-24c-8.7998 0 -16 -7.2002 -16 -16v-8h40zM240 96v24h-48v-24h48zM240 136v24h-48v-24h48zM304 96v24h-48v-24h48zM304 136v24h-48v-24h48zM360 112v8h-40v-24h24c8.7998 0 16 7.2002 16 16zM360 136v8
|
||||||
|
c0 8.7998 -7.2002 16 -16 16h-24v-24h40z" />
|
||||||
|
<glyph glyph-name="grin" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
|
||||||
|
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.9004 -123.3 80c-1.7002 9.90039 7.7998 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
||||||
|
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32z" />
|
||||||
|
<glyph glyph-name="grin-alt" unicode="" horiz-adv-x="496"
|
||||||
|
d="M200.3 200c-7.5 -11.4004 -24.5996 -12 -32.7002 0c-12.3994 18.7002 -15.1992 37.2998 -15.6992 56c0.599609 18.7002 3.2998 37.2998 15.6992 56c7.60059 11.4004 24.7002 12 32.7002 0c12.4004 -18.7002 15.2002 -37.2998 15.7002 -56
|
||||||
|
c-0.599609 -18.7002 -3.2998 -37.2998 -15.7002 -56zM328.3 200c-7.5 -11.4004 -24.5996 -12 -32.7002 0c-12.3994 18.7002 -15.1992 37.2998 -15.6992 56c0.599609 18.7002 3.2998 37.2998 15.6992 56c7.60059 11.4004 24.7002 12 32.7002 0
|
||||||
|
c12.4004 -18.7002 15.2002 -37.2998 15.7002 -56c-0.599609 -18.7002 -3.2998 -37.2998 -15.7002 -56zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200
|
||||||
|
s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.8008 -123.3 80c-1.7002 10 7.7998 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006
|
||||||
|
s79.7002 4.7998 105.6 13.1006z" />
|
||||||
|
<glyph glyph-name="grin-beam" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
|
||||||
|
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.9004 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM117.7 216.3c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998
|
||||||
|
c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996
|
||||||
|
l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002zM277.7 216.3c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998
|
||||||
|
c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002z" />
|
||||||
|
<glyph glyph-name="grin-beam-sweat" unicode="" horiz-adv-x="496"
|
||||||
|
d="M440 288c-29.5 0 -53.2998 26.2998 -53.2998 58.7002c0 25 31.7002 75.5 46.2002 97.2998c3.5 5.2998 10.5996 5.2998 14.1992 0c14.5 -21.7998 46.2002 -72.2998 46.2002 -97.2998c0 -32.4004 -23.7998 -58.7002 -53.2998 -58.7002zM248 48
|
||||||
|
c-51.9004 0 -115.3 32.9004 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-8 -47.0996 -71.3994 -80 -123.3 -80zM378.3 216.3
|
||||||
|
c-3.09961 -0.899414 -7.2002 0.100586 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998
|
||||||
|
c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998zM483.6 269.2c8 -24.2998 12.4004 -50.2002 12.4004 -77.2002c0 -137 -111 -248 -248 -248s-248 111 -248 248s111 248 248 248
|
||||||
|
c45.7002 0 88.4004 -12.5996 125.2 -34.2002c-10.9004 -21.5996 -15.5 -36.2002 -17.2002 -45.7002c-31.2002 20.1006 -68.2002 31.9004 -108 31.9004c-110.3 0 -200 -89.7002 -200 -200s89.7002 -200 200 -200s200 89.7002 200 200
|
||||||
|
c0 22.5 -3.90039 44.0996 -10.7998 64.2998c0.399414 0 21.7998 -2.7998 46.3994 12.9004zM168 258.6c-12.2998 0 -23.7998 -7.7998 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998
|
||||||
|
c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996z" />
|
||||||
|
<glyph glyph-name="grin-hearts" unicode="" horiz-adv-x="496"
|
||||||
|
d="M353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.8008 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM200.8 192.3
|
||||||
|
l-70.2002 18.1006c-20.3994 5.2998 -31.8994 27 -24.1992 47.1992c6.69922 17.7002 26.6992 26.7002 44.8994 22l7.10059 -1.89941l2 7.09961c5.09961 18.1006 22.8994 30.9004 41.5 27.9004c21.3994 -3.40039 34.3994 -24.2002 28.7998 -44.5l-19.4004 -69.9004
|
||||||
|
c-1.2998 -4.5 -6 -7.2002 -10.5 -6zM389.6 257.6c7.7002 -20.1992 -3.7998 -41.7998 -24.1992 -47.0996l-70.2002 -18.2002c-4.60059 -1.2002 -9.2998 1.5 -10.5 6l-19.4004 69.9004c-5.59961 20.2998 7.40039 41.0996 28.7998 44.5c18.7002 3 36.5 -9.7998 41.5 -27.9004
|
||||||
|
l2 -7.09961l7.10059 1.89941c18.2002 4.7002 38.2002 -4.39941 44.8994 -22zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200
|
||||||
|
s89.7002 -200 200 -200z" />
|
||||||
|
<glyph glyph-name="grin-squint" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
|
||||||
|
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.9004 -123.3 80c-1.7002 9.90039 7.7998 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM118.9 184.2c-3.80078 4.39941 -3.90039 11 -0.100586 15.5l33.6006 40.2998
|
||||||
|
l-33.6006 40.2998c-3.7002 4.5 -3.7002 11 0.100586 15.5c3.89941 4.40039 10.1992 5.5 15.2998 2.5l80 -48c3.59961 -2.2002 5.7998 -6.09961 5.7998 -10.2998s-2.2002 -8.09961 -5.7998 -10.2998l-80 -48c-5.40039 -3.2002 -11.7002 -1.7002 -15.2998 2.5zM361.8 181.7
|
||||||
|
l-80 48c-3.59961 2.2002 -5.7998 6.09961 -5.7998 10.2998s2.2002 8.09961 5.7998 10.2998l80 48c5.10059 2.90039 11.5 1.90039 15.2998 -2.5c3.80078 -4.5 3.90039 -11 0.100586 -15.5l-33.6006 -40.2998l33.6006 -40.2998c3.7002 -4.5 3.7002 -11 -0.100586 -15.5
|
||||||
|
c-3.59961 -4.2002 -9.89941 -5.7002 -15.2998 -2.5z" />
|
||||||
|
<glyph glyph-name="grin-squint-tears" unicode=""
|
||||||
|
d="M117.1 63.9004c6.30078 0.899414 11.7002 -4.5 10.9004 -10.9004c-3.7002 -25.7998 -13.7002 -84 -30.5996 -100.9c-22 -21.8994 -57.9004 -21.5 -80.3008 0.900391c-22.3994 22.4004 -22.7998 58.4004 -0.899414 80.2998
|
||||||
|
c16.8994 16.9004 75.0996 26.9004 100.899 30.6006zM75.9004 105.6c-19.6006 -3.89941 -35.1006 -8.09961 -47.3008 -12.1992c-39.2998 90.5996 -22.0996 199.899 52 274c48.5 48.3994 111.9 72.5996 175.4 72.5996c38.9004 0 77.7998 -9.2002 113.2 -27.4004
|
||||||
|
c-4 -12.1992 -8.2002 -28 -12 -48.2998c-30.4004 17.9004 -65 27.7002 -101.2 27.7002c-53.4004 0 -103.6 -20.7998 -141.4 -58.5996c-61.5996 -61.5 -74.2998 -153.4 -38.6992 -227.801zM428.2 293.2c20.2998 3.89941 36.2002 8 48.5 12
|
||||||
|
c47.8994 -93.2002 32.8994 -210.5 -45.2002 -288.601c-48.5 -48.3994 -111.9 -72.5996 -175.4 -72.5996c-33.6992 0 -67.2998 7 -98.6992 20.5996c4.19922 12.2002 8.2998 27.7002 12.1992 47.2002c26.6006 -12.7998 55.9004 -19.7998 86.4004 -19.7998
|
||||||
|
c53.4004 0 103.6 20.7998 141.4 58.5996c65.6992 65.7002 75.7998 166 30.7998 242.601zM394.9 320.1c-6.30078 -0.899414 -11.7002 4.5 -10.9004 10.9004c3.7002 25.7998 13.7002 84 30.5996 100.9c22 21.8994 57.9004 21.5 80.3008 -0.900391
|
||||||
|
c22.3994 -22.4004 22.7998 -58.4004 0.899414 -80.2998c-16.8994 -16.9004 -75.0996 -26.9004 -100.899 -30.6006zM207.9 211.8c3 -3 4.19922 -7.2998 3.19922 -11.5l-22.5996 -90.5c-1.40039 -5.39941 -6.2002 -9.09961 -11.7002 -9.09961h-0.899414
|
||||||
|
c-5.80078 0.5 -10.5 5.09961 -11 10.8994l-4.80078 52.3008l-52.2998 4.7998c-5.7998 0.5 -10.3994 5.2002 -10.8994 11c-0.400391 5.89941 3.39941 11.2002 9.09961 12.5996l90.5 22.7002c4.2002 1 8.40039 -0.200195 11.4004 -3.2002zM247.6 236.9
|
||||||
|
c-0.0996094 0 -6.39941 -1.80078 -11.3994 3.19922c-3 3 -4.2002 7.30078 -3.2002 11.4004l22.5996 90.5c1.40039 5.7002 7 9.2002 12.6006 9.09961c5.7998 -0.5 10.5 -5.09961 11 -10.8994l4.7998 -52.2998l52.2998 -4.80078c5.7998 -0.5 10.4004 -5.19922 10.9004 -11
|
||||||
|
c0.399414 -5.89941 -3.40039 -11.1992 -9.10059 -12.5996zM299.6 148.4c29.1006 29.0996 53 59.5996 65.3008 83.7998c4.89941 9.2998 17.5996 9.89941 23.3994 1.7002c27.7002 -38.9004 6.10059 -106.9 -30.5996 -143.7s-104.8 -58.2998 -143.7 -30.6006
|
||||||
|
c-8.2998 5.90039 -7.5 18.6006 1.7002 23.4004c24.2002 12.5 54.7998 36.2998 83.8994 65.4004z" />
|
||||||
|
<glyph glyph-name="grin-stars" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM353.6 143.4c10 3.09961 19.3008 -5.5 17.7002 -15.3008
|
||||||
|
c-8 -47.0996 -71.2998 -80 -123.3 -80s-115.4 32.8008 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.3008c26 -8.30078 64.3994 -13.1006 105.6 -13.1006s79.7002 4.7998 105.6 13.1006zM125.7 200.9l6.09961 34.8994l-25.3994 24.6006
|
||||||
|
c-4.60059 4.59961 -1.90039 12.2998 4.2998 13.1992l34.8994 5l15.5 31.6006c2.90039 5.7998 11 5.7998 13.9004 0l15.5 -31.6006l34.9004 -5c6.19922 -1 8.7998 -8.69922 4.2998 -13.1992l-25.4004 -24.6006l6 -34.8994c1 -6.2002 -5.39941 -11 -11 -7.90039
|
||||||
|
l-31.2998 16.2998l-31.2998 -16.2998c-5.60059 -3.09961 -12 1.7002 -11 7.90039zM385.4 273.6c6.19922 -1 8.89941 -8.59961 4.39941 -13.1992l-25.3994 -24.6006l6 -34.8994c1 -6.2002 -5.40039 -11 -11 -7.90039l-31.3008 16.2998l-31.2998 -16.2998
|
||||||
|
c-5.59961 -3.09961 -12 1.7002 -11 7.90039l6 34.8994l-25.3994 24.6006c-4.60059 4.59961 -1.90039 12.2998 4.2998 13.1992l34.8994 5l15.5 31.6006c2.90039 5.7998 11 5.7998 13.9004 0l15.5 -31.6006z" />
|
||||||
|
<glyph glyph-name="grin-tears" unicode="" horiz-adv-x="640"
|
||||||
|
d="M117.1 191.9c6.30078 0.899414 11.7002 -4.5 10.9004 -10.9004c-3.7002 -25.7998 -13.7002 -84 -30.5996 -100.9c-22 -21.8994 -57.9004 -21.5 -80.3008 0.900391c-22.3994 22.4004 -22.7998 58.4004 -0.899414 80.2998c16.8994 16.9004 75.0996 26.9004 100.899 30.6006
|
||||||
|
zM623.8 161.3c21.9004 -21.8994 21.5 -57.8994 -0.799805 -80.2002c-22.4004 -22.3994 -58.4004 -22.7998 -80.2998 -0.899414c-16.9004 16.8994 -26.9004 75.0996 -30.6006 100.899c-0.899414 6.30078 4.5 11.7002 10.8008 10.8008
|
||||||
|
c25.7998 -3.7002 84 -13.7002 100.899 -30.6006zM497.2 99.5996c12.3994 -37.2998 25.0996 -43.7998 28.2998 -46.5c-44.5996 -65.7998 -120 -109.1 -205.5 -109.1s-160.9 43.2998 -205.5 109.1c3.09961 2.60059 15.7998 9.10059 28.2998 46.5
|
||||||
|
c33.4004 -63.8994 100.3 -107.6 177.2 -107.6s143.8 43.7002 177.2 107.6zM122.7 223.5c-2.40039 0.299805 -5 2.5 -49.5 -6.90039c12.3994 125.4 118.1 223.4 246.8 223.4s234.4 -98 246.8 -223.5c-44.2998 9.40039 -47.3994 7.2002 -49.5 7
|
||||||
|
c-15.2002 95.2998 -97.7998 168.5 -197.3 168.5s-182.1 -73.2002 -197.3 -168.5zM320 48c-51.9004 0 -115.3 32.9004 -123.3 80c-1.7002 10 7.89941 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996s79.7002 4.7998 105.6 13.0996
|
||||||
|
c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-8 -47.0996 -71.3994 -80 -123.3 -80zM450.3 216.3c-3.09961 -0.899414 -7.2002 0.100586 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17
|
||||||
|
c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998zM240 258.6
|
||||||
|
c-12.2998 0 -23.7998 -7.7998 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004
|
||||||
|
c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996z" />
|
||||||
|
<glyph glyph-name="grin-tongue" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM312 40h0.0996094v43.7998l-17.6992 8.7998c-15.1006 7.60059 -31.5 -1.69922 -34.9004 -16.5l-2.7998 -12.0996c-2.10059 -9.2002 -15.2002 -9.2002 -17.2998 0
|
||||||
|
l-2.80078 12.0996c-3.39941 14.8008 -19.8994 24 -34.8994 16.5l-17.7002 -8.7998v-42.7998c0 -35.2002 28 -64.5 63.0996 -65c35.8008 -0.5 64.9004 28.4004 64.9004 64zM340.2 14.7002c64 33.3994 107.8 100.3 107.8 177.3c0 110.3 -89.7002 200 -200 200
|
||||||
|
s-200 -89.7002 -200 -200c0 -77 43.7998 -143.9 107.8 -177.3c-2.2002 8.09961 -3.7998 16.5 -3.7998 25.2998v43.5c-14.2002 12.4004 -24.4004 27.5 -27.2998 44.5c-1.7002 10 7.7998 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996
|
||||||
|
s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-2.89941 -17 -13.0996 -32.0996 -27.2998 -44.5v-43.5c0 -8.7998 -1.59961 -17.2002 -3.7998 -25.2998zM168 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32
|
||||||
|
s14.2998 32 32 32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z" />
|
||||||
|
<glyph glyph-name="grin-tongue-squint" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM312 40h0.0996094v43.7998l-17.6992 8.7998c-15.1006 7.60059 -31.5 -1.69922 -34.9004 -16.5l-2.7998 -12.0996c-2.10059 -9.2002 -15.2002 -9.2002 -17.2998 0
|
||||||
|
l-2.80078 12.0996c-3.39941 14.8008 -19.8994 24 -34.8994 16.5l-17.7002 -8.7998v-42.7998c0 -35.2002 28 -64.5 63.0996 -65c35.8008 -0.5 64.9004 28.4004 64.9004 64zM340.2 14.7002c64 33.3994 107.8 100.3 107.8 177.3c0 110.3 -89.7002 200 -200 200
|
||||||
|
s-200 -89.7002 -200 -200c0 -77 43.7998 -143.9 107.8 -177.3c-2.2002 8.09961 -3.7998 16.5 -3.7998 25.2998v43.5c-14.2002 12.4004 -24.4004 27.5 -27.2998 44.5c-1.7002 10 7.7998 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996
|
||||||
|
s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998c-2.89941 -17 -13.0996 -32.0996 -27.2998 -44.5v-43.5c0 -8.7998 -1.59961 -17.2002 -3.7998 -25.2998zM377.1 295.8c3.80078 -4.39941 3.90039 -11 0.100586 -15.5l-33.6006 -40.2998
|
||||||
|
l33.6006 -40.2998c3.7002 -4.5 3.7002 -11 -0.100586 -15.5c-3.59961 -4.2002 -9.89941 -5.7002 -15.2998 -2.5l-80 48c-3.59961 2.2002 -5.7998 6.09961 -5.7998 10.2998s2.2002 8.09961 5.7998 10.2998l80 48c5 3 11.5 1.90039 15.2998 -2.5zM214.2 250.3
|
||||||
|
c3.59961 -2.2002 5.7998 -6.09961 5.7998 -10.2998s-2.2002 -8.09961 -5.7998 -10.2998l-80 -48c-5.40039 -3.2002 -11.7002 -1.7002 -15.2998 2.5c-3.80078 4.5 -3.90039 11 -0.100586 15.5l33.6006 40.2998l-33.6006 40.2998c-3.7002 4.5 -3.7002 11 0.100586 15.5
|
||||||
|
c3.89941 4.5 10.2998 5.5 15.2998 2.5z" />
|
||||||
|
<glyph glyph-name="grin-tongue-wink" unicode="" horiz-adv-x="496"
|
||||||
|
d="M152 268c25.7002 0 55.9004 -16.9004 59.7998 -42.0996c0.799805 -5 -1.7002 -10 -6.09961 -12.4004c-5.7002 -3.09961 -11.2002 -0.599609 -13.7002 1.59961l-9.5 8.5c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5
|
||||||
|
c-3.7998 -3.39941 -9.2998 -4 -13.7002 -1.59961c-4.39941 2.40039 -6.89941 7.40039 -6.09961 12.4004c3.89941 25.1992 34.0996 42.0996 59.7998 42.0996zM328 320c44.2002 0 80 -35.7998 80 -80s-35.7998 -80 -80 -80s-80 35.7998 -80 80s35.7998 80 80 80zM328 192
|
||||||
|
c26.5 0 48 21.5 48 48s-21.5 48 -48 48s-48 -21.5 -48 -48s21.5 -48 48 -48zM328 264c13.2998 0 24 -10.7002 24 -24s-10.7002 -24 -24 -24s-24 10.7002 -24 24s10.7002 24 24 24zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248z
|
||||||
|
M312 40h0.0996094v43.7998l-17.6992 8.7998c-15.1006 7.60059 -31.5 -1.69922 -34.9004 -16.5l-2.7998 -12.0996c-2.10059 -9.2002 -15.2002 -9.2002 -17.2998 0l-2.80078 12.0996c-3.39941 14.8008 -19.8994 24 -34.8994 16.5l-17.7002 -8.7998v-42.7998
|
||||||
|
c0 -35.2002 28 -64.5 63.0996 -65c35.8008 -0.5 64.9004 28.4004 64.9004 64zM340.2 14.7002c64 33.3994 107.8 100.3 107.8 177.3c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200c0 -77 43.7998 -143.9 107.8 -177.3
|
||||||
|
c-2.2002 8.09961 -3.7998 16.5 -3.7998 25.2998v43.5c-14.2002 12.4004 -24.4004 27.5 -27.2998 44.5c-1.7002 10 7.7998 18.4004 17.7002 15.2998c26 -8.2998 64.3994 -13.0996 105.6 -13.0996s79.7002 4.7998 105.6 13.0996c10 3.2002 19.4004 -5.39941 17.7002 -15.2998
|
||||||
|
c-2.89941 -17 -13.0996 -32.0996 -27.2998 -44.5v-43.5c0 -8.7998 -1.59961 -17.2002 -3.7998 -25.2998z" />
|
||||||
|
<glyph glyph-name="grin-wink" unicode="" horiz-adv-x="496"
|
||||||
|
d="M328 268c25.6904 0 55.8799 -16.9199 59.8701 -42.1201c1.72949 -11.0898 -11.3506 -18.2695 -19.8301 -10.8398l-9.5498 8.47949c-14.8105 13.1904 -46.1602 13.1904 -60.9707 0l-9.5498 -8.47949c-8.33008 -7.40039 -21.5801 -0.379883 -19.8301 10.8398
|
||||||
|
c3.98047 25.2002 34.1699 42.1201 59.8604 42.1201zM168 208c-17.6699 0 -32 14.3301 -32 32s14.3301 32 32 32s32 -14.3301 32 -32s-14.3301 -32 -32 -32zM353.55 143.36c10.04 3.13965 19.3906 -5.4502 17.71 -15.3408
|
||||||
|
c-7.92969 -47.1494 -71.3193 -80.0195 -123.26 -80.0195s-115.33 32.8701 -123.26 80.0195c-1.69043 9.9707 7.76953 18.4707 17.71 15.3408c25.9297 -8.31055 64.3994 -13.0605 105.55 -13.0605s79.6201 4.75977 105.55 13.0605zM248 440c136.97 0 248 -111.03 248 -248
|
||||||
|
s-111.03 -248 -248 -248s-248 111.03 -248 248s111.03 248 248 248zM248 -8c110.28 0 200 89.7197 200 200s-89.7197 200 -200 200s-200 -89.7197 -200 -200s89.7197 -200 200 -200z" />
|
||||||
|
<glyph glyph-name="kiss" unicode="" horiz-adv-x="496"
|
||||||
|
d="M168 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM304 140c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5
|
||||||
|
c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002
|
||||||
|
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM248 440c137 0 248 -111 248 -248
|
||||||
|
s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z
|
||||||
|
" />
|
||||||
|
<glyph glyph-name="kiss-beam" unicode="" horiz-adv-x="496"
|
||||||
|
d="M168 296c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.299805 -3.7998 -2 -7.19922 -5.59961 -8.2998c-3.10059 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996c-12.3008 0 -23.8008 -7.89941 -31.5 -21.5996l-9.5 -17
|
||||||
|
c-1.80078 -3.2002 -5.80078 -4.7002 -9.30078 -3.7002c-3.59961 1.10059 -5.89941 4.60059 -5.59961 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004zM248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8
|
||||||
|
c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM304 140c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5
|
||||||
|
c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002
|
||||||
|
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM328 296
|
||||||
|
c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.299805 -3.7998 -2 -7.19922 -5.59961 -8.2998c-3.10059 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996c-12.3008 0 -23.8008 -7.89941 -31.5 -21.5996l-9.5 -17
|
||||||
|
c-1.80078 -3.2002 -5.80078 -4.7002 -9.30078 -3.7002c-3.59961 1.10059 -5.89941 4.60059 -5.59961 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004z" />
|
||||||
|
<glyph glyph-name="kiss-wink-heart" unicode="" horiz-adv-x="504"
|
||||||
|
d="M304 139.5c0 -13 -13.4004 -27.2998 -35.0996 -36.4004c21.7998 -8.69922 35.1992 -23 35.1992 -36c0 -19.1992 -28.6992 -41.5 -71.5 -44h-0.5c-3.69922 0 -7 2.60059 -7.7998 6.2002c-0.899414 3.7998 1.10059 7.7002 4.7002 9.2002l17 7.2002
|
||||||
|
c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.2002c-6 2.59961 -5.7002 12.3994 0 14.7998l17 7.2002c12.9004 5.5 20.7002 13.5 20.7002 21.5s-7.7998 16 -20.7998 21.5l-16.9004 7.19922c-3.59961 1.5 -5.59961 5.40039 -4.7002 9.2002
|
||||||
|
c0.799805 3.7998 4.40039 6.60059 8.2002 6.2002c42.7002 -2.5 71.5 -24.7998 71.5 -44zM374.5 223c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-2.5 -2.2998 -7.90039 -4.7002 -13.7002 -1.59961c-4.39941 2.39941 -6.89941 7.39941 -6.09961 12.3994
|
||||||
|
c3.89941 25.2002 34.2002 42.1006 59.7998 42.1006s55.7998 -16.9004 59.7998 -42.1006c0.799805 -5 -1.7002 -10 -6.09961 -12.3994c-4.40039 -2.40039 -9.90039 -1.7002 -13.7002 1.59961zM136 239.5c0 17.7002 14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32
|
||||||
|
s-32 14.2998 -32 32zM501.1 45.5c9.2002 -23.9004 -4.39941 -49.4004 -28.5 -55.7002l-83 -21.5c-5.39941 -1.39941 -10.8994 1.7998 -12.3994 7.10059l-22.9004 82.5996c-6.59961 24 8.7998 48.5996 34 52.5996c22 3.5 43.1006 -11.5996 49 -33l2.2998 -8.39941
|
||||||
|
l8.40039 2.2002c21.5996 5.59961 45.0996 -5.10059 53.0996 -25.9004zM334 11.7002c17.7002 -64 10.9004 -39.5 13.4004 -46.7998c-30.5 -13.4004 -64 -20.9004 -99.4004 -20.9004c-137 0 -248 111 -248 248s111 248 248 248s248 -111 247.9 -248
|
||||||
|
c0 -31.7998 -6.2002 -62.0996 -17.1006 -90c-6 1.5 -12.2002 2.7998 -18.5996 2.90039c-5.60059 9.69922 -13.6006 17.5 -22.6006 23.8994c6.7002 19.9004 10.4004 41.1006 10.4004 63.2002c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200
|
||||||
|
c30.7998 0 59.9004 7.2002 86 19.7002z" />
|
||||||
|
<glyph glyph-name="laugh" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
|
||||||
|
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM328 224c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM168 224
|
||||||
|
c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM362.4 160c8.19922 0 14.5 -7 13.5 -15c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
|
||||||
|
<glyph glyph-name="laugh-beam" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
|
||||||
|
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM328 296c23.7998 0 52.7002 -29.2998 55.7998 -71.4004c0.700195 -8.5 -10.7998 -11.8994 -14.8994 -4.5
|
||||||
|
l-9.5 17c-7.7002 13.7002 -19.2002 21.6006 -31.5 21.6006c-12.3008 0 -23.8008 -7.90039 -31.5 -21.6006l-9.5 -17c-4.10059 -7.39941 -15.6006 -4.09961 -14.9004 4.5c3.2998 42.1006 32.2002 71.4004 56 71.4004zM127 220.1c-4.2002 -7.39941 -15.7002 -4 -15.0996 4.5
|
||||||
|
c3.2998 42.1006 32.1992 71.4004 56 71.4004c23.7998 0 52.6992 -29.2998 56 -71.4004c0.699219 -8.5 -10.8008 -11.8994 -14.9004 -4.5l-9.5 17c-7.7002 13.7002 -19.2002 21.6006 -31.5 21.6006s-23.7998 -7.90039 -31.5 -21.6006zM362.4 160c8.19922 0 14.5 -7 13.5 -15
|
||||||
|
c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
|
||||||
|
<glyph glyph-name="laugh-squint" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
|
||||||
|
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM343.6 252l33.6006 -40.2998c8.59961 -10.4004 -3.90039 -24.7998 -15.4004 -18l-80 48
|
||||||
|
c-7.7998 4.7002 -7.7998 15.8994 0 20.5996l80 48c11.6006 6.7998 24 -7.7002 15.4004 -18zM134.2 193.7c-11.6006 -6.7998 -24.1006 7.59961 -15.4004 18l33.6006 40.2998l-33.6006 40.2998c-8.59961 10.2998 3.7998 24.9004 15.4004 18l80 -48
|
||||||
|
c7.7998 -4.7002 7.7998 -15.8994 0 -20.5996zM362.4 160c8.19922 0 14.5 -7 13.5 -15c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
|
||||||
|
<glyph glyph-name="laugh-wink" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM389.4 50.5996c37.7998 37.8008 58.5996 88 58.5996 141.4s-20.7998 103.6 -58.5996 141.4c-37.8008 37.7998 -88 58.5996 -141.4 58.5996s-103.6 -20.7998 -141.4 -58.5996
|
||||||
|
c-37.7998 -37.8008 -58.5996 -88 -58.5996 -141.4s20.7998 -103.6 58.5996 -141.4c37.8008 -37.7998 88 -58.5996 141.4 -58.5996s103.6 20.7998 141.4 58.5996zM328 284c25.7002 0 55.9004 -16.9004 59.7002 -42.0996c1.7998 -11.1006 -11.2998 -18.2002 -19.7998 -10.8008
|
||||||
|
l-9.5 8.5c-14.8008 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5c-8.30078 -7.39941 -21.5 -0.399414 -19.8008 10.8008c4 25.1992 34.2002 42.0996 59.9004 42.0996zM168 224c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32s-14.2998 -32 -32 -32z
|
||||||
|
M362.4 160c8.19922 0 14.5 -7 13.5 -15c-7.5 -59.2002 -58.9004 -105 -121.101 -105h-13.5996c-62.2002 0 -113.601 45.7998 -121.101 105c-1 8 5.30078 15 13.5 15h228.801z" />
|
||||||
|
<glyph glyph-name="meh-blank" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM168 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32
|
||||||
|
s-32 14.2998 -32 32s14.2998 32 32 32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z" />
|
||||||
|
<glyph glyph-name="meh-rolling-eyes" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM336 296c39.7998 0 72 -32.2002 72 -72s-32.2002 -72 -72 -72
|
||||||
|
s-72 32.2002 -72 72s32.2002 72 72 72zM336 184c22.0996 0 40 17.9004 40 40c0 13.5996 -7.2998 25.0996 -17.7002 32.2998c1 -2.59961 1.7002 -5.39941 1.7002 -8.2998c0 -13.2998 -10.7002 -24 -24 -24s-24 10.7002 -24 24c0 3 0.700195 5.7002 1.7002 8.2998
|
||||||
|
c-10.4004 -7.2002 -17.7002 -18.7002 -17.7002 -32.2998c0 -22.0996 17.9004 -40 40 -40zM232 224c0 -39.7998 -32.2002 -72 -72 -72s-72 32.2002 -72 72s32.2002 72 72 72s72 -32.2002 72 -72zM120 224c0 -22.0996 17.9004 -40 40 -40s40 17.9004 40 40
|
||||||
|
c0 13.5996 -7.2998 25.0996 -17.7002 32.2998c1 -2.59961 1.7002 -5.39941 1.7002 -8.2998c0 -13.2998 -10.7002 -24 -24 -24s-24 10.7002 -24 24c0 3 0.700195 5.7002 1.7002 8.2998c-10.4004 -7.2002 -17.7002 -18.7002 -17.7002 -32.2998zM312 96
|
||||||
|
c13.2002 0 24 -10.7998 24 -24s-10.7998 -24 -24 -24h-128c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24h128z" />
|
||||||
|
<glyph glyph-name="sad-cry" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM392 53.5996c34.5996 35.9004 56 84.7002 56 138.4c0 110.3 -89.7002 200 -200 200s-200 -89.7002 -200 -200c0 -53.7002 21.4004 -102.4 56 -138.4v114.4
|
||||||
|
c0 13.2002 10.7998 24 24 24s24 -10.7998 24 -24v-151.4c28.5 -15.5996 61.2002 -24.5996 96 -24.5996s67.5 9 96 24.5996v151.4c0 13.2002 10.7998 24 24 24s24 -10.7998 24 -24v-114.4zM205.8 213.5c-5.7998 -3.2002 -11.2002 -0.700195 -13.7002 1.59961l-9.5 8.5
|
||||||
|
c-14.7998 13.2002 -46.1992 13.2002 -61 0l-9.5 -8.5c-3.7998 -3.39941 -9.2998 -4 -13.6992 -1.59961c-4.40039 2.40039 -6.90039 7.40039 -6.10059 12.4004c3.90039 25.1992 34.2002 42.0996 59.7998 42.0996c25.6006 0 55.8008 -16.9004 59.8008 -42.0996
|
||||||
|
c0.799805 -5 -1.7002 -10 -6.10059 -12.4004zM344 268c25.7002 0 55.9004 -16.9004 59.7998 -42.0996c0.799805 -5 -1.7002 -10 -6.09961 -12.4004c-5.7002 -3.09961 -11.2002 -0.599609 -13.7002 1.59961l-9.5 8.5c-14.7998 13.2002 -46.2002 13.2002 -61 0l-9.5 -8.5
|
||||||
|
c-3.7998 -3.39941 -9.2002 -4 -13.7002 -1.59961c-4.39941 2.40039 -6.89941 7.40039 -6.09961 12.4004c3.89941 25.1992 34.0996 42.0996 59.7998 42.0996zM248 176c30.9004 0 56 -28.7002 56 -64s-25.0996 -64 -56 -64s-56 28.7002 -56 64s25.0996 64 56 64z" />
|
||||||
|
<glyph glyph-name="sad-tear" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM256 144c38.0996 0 74 -16.7998 98.5 -46.0996
|
||||||
|
c8.5 -10.2002 7.09961 -25.3008 -3.09961 -33.8008c-10.6006 -8.7998 -25.7002 -6.69922 -33.8008 3.10059c-15.2998 18.2998 -37.7998 28.7998 -61.5996 28.7998c-13.2002 0 -24 10.7998 -24 24s10.7998 24 24 24zM168 208c-17.7002 0 -32 14.2998 -32 32s14.2998 32 32 32
|
||||||
|
s32 -14.2998 32 -32s-14.2998 -32 -32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32zM162.4 173.2c2.7998 3.7002 8.39941 3.7002 11.1992 0c11.4004 -15.2998 36.4004 -50.6006 36.4004 -68.1006
|
||||||
|
c0 -22.6992 -18.7998 -41.0996 -42 -41.0996s-42 18.4004 -42 41.0996c0 17.5 25 52.8008 36.4004 68.1006z" />
|
||||||
|
<glyph glyph-name="smile-beam" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM332 135.4c8.5 10.1992 23.5996 11.5 33.7998 3.09961
|
||||||
|
c10.2002 -8.5 11.6006 -23.5996 3.10059 -33.7998c-30 -36 -74.1006 -56.6006 -120.9 -56.6006s-90.9004 20.6006 -120.9 56.6006c-8.39941 10.2002 -7.09961 25.2998 3.10059 33.7998c10.2002 8.40039 25.2998 7.09961 33.7998 -3.09961
|
||||||
|
c20.7998 -25.1006 51.5 -39.4004 84 -39.4004s63.2002 14.4004 84 39.4004zM136.5 237l-9.5 -17c-1.90039 -3.2002 -5.90039 -4.7998 -9.2998 -3.7002c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004s52.7002 -29.2998 56 -71.4004
|
||||||
|
c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996zM328 296c23.7998 0 52.7002 -29.2998 56 -71.4004
|
||||||
|
c0.299805 -3.7998 -2.09961 -7.19922 -5.7002 -8.2998c-3.09961 -1 -7.2002 0 -9.2998 3.7002l-9.5 17c-7.7002 13.7002 -19.2002 21.5996 -31.5 21.5996s-23.7998 -7.89941 -31.5 -21.5996l-9.5 -17c-1.90039 -3.2002 -5.7998 -4.7998 -9.2998 -3.7002
|
||||||
|
c-3.60059 1.10059 -6 4.60059 -5.7002 8.2998c3.2998 42.1006 32.2002 71.4004 56 71.4004z" />
|
||||||
|
<glyph glyph-name="surprise" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM248 168c35.2998 0 64 -28.7002 64 -64s-28.7002 -64 -64 -64
|
||||||
|
s-64 28.7002 -64 64s28.7002 64 64 64zM200 240c0 -17.7002 -14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32s32 -14.2998 32 -32zM328 272c17.7002 0 32 -14.2998 32 -32s-14.2998 -32 -32 -32s-32 14.2998 -32 32s14.2998 32 32 32z" />
|
||||||
|
<glyph glyph-name="tired" unicode="" horiz-adv-x="496"
|
||||||
|
d="M248 440c137 0 248 -111 248 -248s-111 -248 -248 -248s-248 111 -248 248s111 248 248 248zM248 -8c110.3 0 200 89.7002 200 200s-89.7002 200 -200 200s-200 -89.7002 -200 -200s89.7002 -200 200 -200zM377.1 295.8c3.80078 -4.39941 3.90039 -11 0.100586 -15.5
|
||||||
|
l-33.6006 -40.2998l33.6006 -40.2998c3.7998 -4.5 3.7002 -11 -0.100586 -15.5c-3.5 -4.10059 -9.89941 -5.7002 -15.2998 -2.5l-80 48c-3.59961 2.2002 -5.7998 6.09961 -5.7998 10.2998s2.2002 8.09961 5.7998 10.2998l80 48c5 2.90039 11.5 1.90039 15.2998 -2.5z
|
||||||
|
M220 240c0 -4.2002 -2.2002 -8.09961 -5.7998 -10.2998l-80 -48c-5.40039 -3.2002 -11.7998 -1.60059 -15.2998 2.5c-3.80078 4.5 -3.90039 11 -0.100586 15.5l33.6006 40.2998l-33.6006 40.2998c-3.7998 4.5 -3.7002 11 0.100586 15.5
|
||||||
|
c3.7998 4.40039 10.2998 5.5 15.2998 2.5l80 -48c3.59961 -2.2002 5.7998 -6.09961 5.7998 -10.2998zM248 176c45.4004 0 100.9 -38.2998 107.8 -93.2998c1.5 -11.9004 -7 -21.6006 -15.5 -17.9004c-22.7002 9.7002 -56.2998 15.2002 -92.2998 15.2002
|
||||||
|
s-69.5996 -5.5 -92.2998 -15.2002c-8.60059 -3.7002 -17 6.10059 -15.5 17.9004c6.89941 55 62.3994 93.2998 107.8 93.2998z" />
|
||||||
|
</font>
|
||||||
|
</defs></svg>
|
||||||
|
After Width: | Height: | Size: 141 KiB |
|
After Width: | Height: | Size: 820 KiB |
@@ -0,0 +1,34 @@
|
|||||||
|
'''
|
||||||
|
Created on 23 janv. 2026
|
||||||
|
|
||||||
|
@author: denis
|
||||||
|
'''
|
||||||
|
from celery import shared_task
|
||||||
|
from django.core.mail import EmailMultiAlternatives
|
||||||
|
from .process import MqttProcess, mqttc
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task
|
||||||
|
def async_send_mail(subject, body, from_email, to=[], bcc=[], cc=[], html=None, fail_silently=False, attachments=[], connection=None):
|
||||||
|
msg = EmailMultiAlternatives(subject, body, from_email, to, bcc=bcc, cc=cc, connection=connection)
|
||||||
|
if html:
|
||||||
|
msg.attach_alternative(html, 'text/html')
|
||||||
|
for f in attachments:
|
||||||
|
msg.attach_file(f)
|
||||||
|
msg.send(fail_silently)
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task(bind=True)
|
||||||
|
def start_mqtt_worker(self):
|
||||||
|
mqttc.task = MqttProcess()
|
||||||
|
mqttc.task.start()
|
||||||
|
return {"status": "success", "message": f"MQTT Worker démarré."}
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task(bind=True)
|
||||||
|
def stop_mqtt_worker(self):
|
||||||
|
if mqttc.task:
|
||||||
|
mqttc.task.stop()
|
||||||
|
return {"status": "success", "message": f"MQTT Worker arrêté."}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
{% extends 'layout.html' %}
|
||||||
|
|
||||||
|
{% block slider %}
|
||||||
|
<div id="sidebar" class="w3-sidebar w3-bar-block w3-animate-left w3-dark-medium">
|
||||||
|
{% block sidebar %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block main %}
|
||||||
|
<div id="main">
|
||||||
|
{% block header %}{% endblock %}
|
||||||
|
<div class="content w3-dark-medium">
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% block footer %}{% endblock %}
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block js_footer %}
|
||||||
|
<script>
|
||||||
|
const widthSidebar = "350px";
|
||||||
|
const sidebar = sId("sidebar");
|
||||||
|
const main = sId("main");
|
||||||
|
function toggleSidebar() { sidebarAction(widthSidebar, sidebar, main); }
|
||||||
|
sidebarOpen(widthSidebar, sidebar, main);
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{% extends 'dashboard/base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block main_content %}
|
||||||
|
<div class="w3-black w3-border w3-div-center" style="margin: 10em; height: 20em">
|
||||||
|
{% block main-bar %}
|
||||||
|
<div class="w3-orange">
|
||||||
|
<div class="w3-bar">
|
||||||
|
<div class="w3-bar-item">{% block bar-title %}{% trans "Error: missing page." %}{% endblock %}</div>
|
||||||
|
<div class="w3-right">
|
||||||
|
<a href="/" class="w3-bar-item w3-button w3-right">×</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
<h4 class="w3-padding">
|
||||||
|
{% trans "This page does not exist.<br>Please re-enter a new address." %}
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{% extends 'dashboard/base.html' %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block main_content %}
|
||||||
|
<div class="w3-black w3-border w3-div-center" style="margin: 10em; height: 20em">
|
||||||
|
{% block main-bar %}
|
||||||
|
<div class="w3-orange">
|
||||||
|
<div class="w3-bar">
|
||||||
|
<div class="w3-bar-item">{% block bar-title %}{% trans "System error" %}{% endblock %}</div>
|
||||||
|
<div class="w3-right">
|
||||||
|
<a href="/" class="w3-bar-item w3-button w3-right">×</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
<h4 class="w3-padding">
|
||||||
|
{% trans "This page server can't run correctly.<br>Please contact the site administrator." %}
|
||||||
|
<h6 class="w3-margin">{{ error }}</h6>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
{% if messages %}
|
||||||
|
<div class="alert">
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="w3-bar {% if message.tags %}{{ message.tags }}{% endif %}" style="width: 100%" >
|
||||||
|
<div class="w3-bar-item">{{ message }}</div>
|
||||||
|
<div class="w3-bar-item w3-button w3-right" onclick="this.parentElement.style.display='none'">×</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>{% block title %}Automation{% endblock %}</title>
|
||||||
|
{% block metas %}
|
||||||
|
<meta name="description" content="{% block description %}{% endblock %}">
|
||||||
|
<meta name="author" content="<dnix-421">
|
||||||
|
<meta name="mobile-web-app-capable" content="yes">
|
||||||
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">
|
||||||
|
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
|
||||||
|
<link href="/static/img/logo.png" rel="shortcut icon">
|
||||||
|
{% endblock %}
|
||||||
|
<link href="/static/css/w3.css" rel="stylesheet">
|
||||||
|
<link href="/static/css/all.min.css" rel="stylesheet">
|
||||||
|
<link href="/static/css/w3-custom.css" rel="stylesheet">
|
||||||
|
{% block styles %}{% endblock %}
|
||||||
|
<script src="/static/js/w3-custom.js"></script>
|
||||||
|
{% block js_header %}{% endblock %}
|
||||||
|
</head>
|
||||||
|
<body id="top-body" class="w3-black" style="margin: 0; padding: 0;">
|
||||||
|
{% block main_content %}
|
||||||
|
{% block slider %}{% endblock %}
|
||||||
|
{% block main %}
|
||||||
|
{% block header %}{% endblock %}
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
{% block footer %}{% endblock %}
|
||||||
|
{% endblock %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block modal %}{% endblock %}
|
||||||
|
{% block js_footer %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
# encoding: utf-8
|
||||||
|
import time, json
|
||||||
|
from django import template
|
||||||
|
from django.utils.html import format_html #, escape
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def icon_name(obj, name=None):
|
||||||
|
if not name:
|
||||||
|
name = obj.name
|
||||||
|
color, icon = '#FF0000', ''
|
||||||
|
if obj.icon:
|
||||||
|
color, icon = obj.color, obj.icon.html
|
||||||
|
result = f"""<span style="color:{color}">{icon}</span><span> {name}</span>"""
|
||||||
|
return format_html(result)
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def x_range(start, end=None, step=1):
|
||||||
|
"""
|
||||||
|
Usage:
|
||||||
|
{% x_range 1 5 as my_range %}
|
||||||
|
ou
|
||||||
|
{% x_range 0 10 2 as my_range %}
|
||||||
|
Retourne une liste Python similaire à range(start, end, step).
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# convertir en entiers
|
||||||
|
if end is None:
|
||||||
|
# seul un argument passé -> range(0, start)
|
||||||
|
start = int(start)
|
||||||
|
seq = list(range(start))
|
||||||
|
else:
|
||||||
|
start = int(start)
|
||||||
|
end = int(end)
|
||||||
|
step = int(step)
|
||||||
|
seq = list(range(start, end, step))
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
seq = []
|
||||||
|
return seq
|
||||||
|
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def epoch(value):
|
||||||
|
try:
|
||||||
|
return int(time.mktime(value.timetuple())*1000)
|
||||||
|
except AttributeError:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def to_int(value):
|
||||||
|
return int(value)
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def math_inc(value):
|
||||||
|
return value + 1
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def math_dec(value):
|
||||||
|
return value - 1
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def math_sub(value, arg):
|
||||||
|
return value - arg
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def math_add(value, arg):
|
||||||
|
return value + arg
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def math_mul(value, arg):
|
||||||
|
return value * arg
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def math_div(value, arg):
|
||||||
|
return value / arg
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def define(val=None):
|
||||||
|
return val
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def concat(*args):
|
||||||
|
c = ""
|
||||||
|
for arg in args:
|
||||||
|
c += str(arg)
|
||||||
|
return c
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def nope(value):
|
||||||
|
try:
|
||||||
|
return not int(value)
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def dict_to_json(dictionary):
|
||||||
|
return json.dumps(dictionary)
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def from_dict(dictionary, key):
|
||||||
|
return dictionary.get(key)
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def from_list(lst, key):
|
||||||
|
try:
|
||||||
|
return lst[key]
|
||||||
|
except:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def from_choices(dictionary, key):
|
||||||
|
for k, v in dictionary:
|
||||||
|
if k == key:
|
||||||
|
return v
|
||||||
|
return ''
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def in_intlist(lst, key):
|
||||||
|
return key in lst
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def in_charlist(lst, key):
|
||||||
|
return str(key) in lst
|
||||||
|
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
"""
|
||||||
|
URL configuration for monitoring project.
|
||||||
|
|
||||||
|
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||||
|
https://docs.djangoproject.com/en/5.1/topics/http/urls/
|
||||||
|
Examples:
|
||||||
|
Function views
|
||||||
|
1. Add an import: from my_app import views
|
||||||
|
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
||||||
|
Class-based views
|
||||||
|
1. Add an import: from other_app.views import Home
|
||||||
|
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
||||||
|
Including another URLconf
|
||||||
|
1. Import the include() function: from django.urls import include, path
|
||||||
|
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
||||||
|
"""
|
||||||
|
from django.conf.urls.i18n import i18n_patterns
|
||||||
|
from django.contrib.auth import views as auth_views
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib import admin
|
||||||
|
from django.urls import path, re_path, include
|
||||||
|
from django.views.static import serve
|
||||||
|
from django.views.generic import RedirectView
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
handler404 = views.handler404
|
||||||
|
handler500 = views.handler500
|
||||||
|
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
path('i18n/', include('django.conf.urls.i18n')),
|
||||||
|
]
|
||||||
|
|
||||||
|
urlpatterns += i18n_patterns(
|
||||||
|
path('admin/', admin.site.urls),
|
||||||
|
path('login/', auth_views.LoginView.as_view(template_name='admin/login.html'), name='login'),
|
||||||
|
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
|
||||||
|
|
||||||
|
path('', RedirectView.as_view(url='/relay/dashboard/', permanent=True), name='redirect_to_dashboard'),
|
||||||
|
path('relay/', include('relay.urls', namespace='relay')),
|
||||||
|
)
|
||||||
|
|
||||||
|
if settings.DEBUG:
|
||||||
|
from django.conf.urls.static import static
|
||||||
|
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||||
|
urlpatterns += staticfiles_urlpatterns()
|
||||||
|
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
else:
|
||||||
|
urlpatterns += i18n_patterns(
|
||||||
|
re_path(r'^media/(?P<path>.*)$', serve,{'document_root': settings.MEDIA_ROOT}),
|
||||||
|
re_path(r'^static/(?P<path>.*)$', serve,{'document_root': settings.STATIC_ROOT}),
|
||||||
|
)
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#
|
||||||
|
# encoding: utf-8
|
||||||
|
from django.shortcuts import render
|
||||||
|
|
||||||
|
|
||||||
|
def handler404(request, *args, **argv):
|
||||||
|
return render(request, 'inc/404.html', status=404)
|
||||||
|
|
||||||
|
|
||||||
|
def handler500(request, *args, **argv):
|
||||||
|
return render(request, 'inc/500.html', status=500)
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
"""
|
||||||
|
WSGI config for home_automation project.
|
||||||
|
|
||||||
|
It exposes the WSGI callable as a module-level variable named ``application``.
|
||||||
|
|
||||||
|
For more information on this file, see
|
||||||
|
https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.wsgi import get_wsgi_application
|
||||||
|
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'home.settings')
|
||||||
|
|
||||||
|
application = get_wsgi_application()
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#!../.venv/bin/python
|
||||||
|
"""Django's command-line utility for administrative tasks."""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Run administrative tasks."""
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'home.settings')
|
||||||
|
try:
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
except ImportError as exc:
|
||||||
|
raise ImportError(
|
||||||
|
"Couldn't import Django. Are you sure it's installed and "
|
||||||
|
"available on your PYTHONPATH environment variable? Did you "
|
||||||
|
"forget to activate a virtual environment?"
|
||||||
|
) from exc
|
||||||
|
execute_from_command_line(sys.argv)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -0,0 +1,180 @@
|
|||||||
|
'''
|
||||||
|
Devices
|
||||||
|
|
||||||
|
Created on 23 août 2022
|
||||||
|
|
||||||
|
@author: denis@e-educ.fr
|
||||||
|
|
||||||
|
Flow and Frequency output of the YF-S201
|
||||||
|
|
||||||
|
Flow(L/H) Frequency(Hz)
|
||||||
|
120 16
|
||||||
|
240 32.5
|
||||||
|
360 49.3
|
||||||
|
480 65.5
|
||||||
|
600 82
|
||||||
|
720 90.2
|
||||||
|
|
||||||
|
F = 7.5 Q Q: l/mn
|
||||||
|
'''
|
||||||
|
import logging, threading, random
|
||||||
|
from modules import sensors as dev, utils, gpiolib as gpio
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
|
class YF_S201(dev.InputDevice):
|
||||||
|
waterflow_timeout = 2
|
||||||
|
pulse_counter = 0
|
||||||
|
start_counter = False
|
||||||
|
stop_counter = None
|
||||||
|
|
||||||
|
def __init__(self, pin, register=None, publish=None):
|
||||||
|
super().__init__(pin, register=register, callback=self.on_count_pulse, pull_up_down=gpio.IO_PULL_UP,)
|
||||||
|
self.publish = publish
|
||||||
|
threading.Thread(target=self.waterflow_process, args=()).start()
|
||||||
|
|
||||||
|
def waterflow_publish(self, flow=None):
|
||||||
|
if self.publish is not None:
|
||||||
|
self.publish(dict(
|
||||||
|
uuid=self.key,
|
||||||
|
topic="waterflow",
|
||||||
|
ts=utils.ts_now(),
|
||||||
|
flow=flow,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def on_count_pulse(self, channel):
|
||||||
|
if self.start_counter:
|
||||||
|
self.pulse_counter += 1
|
||||||
|
|
||||||
|
def wait_for_counts(self, timeout):
|
||||||
|
self.pulse_counter = 0
|
||||||
|
self.start_counter = True
|
||||||
|
threading.Event().wait(timeout)
|
||||||
|
self.start_counter = False
|
||||||
|
|
||||||
|
def waterflow_process(self):
|
||||||
|
self.stop_counter = threading.Event()
|
||||||
|
while not self.stop_counter.is_set():
|
||||||
|
self.wait_for_counts(self.waterflow_timeout)
|
||||||
|
flow = self.pulse_counter / 7.5
|
||||||
|
if flow:
|
||||||
|
logger.info(f'\nwaterflow_process flow = {flow}')
|
||||||
|
self.waterflow_publish(flow)
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self.stop_counter.set()
|
||||||
|
|
||||||
|
|
||||||
|
class Relay(dev.RelayFromShiftOut):
|
||||||
|
|
||||||
|
def __init__(self, shift_out_register, register=None, publish=None):
|
||||||
|
super().__init__(shift_out_register, register, relay_timeout=1.0)
|
||||||
|
self.publish = publish
|
||||||
|
self.start_time, self.end_time = 0, 0
|
||||||
|
self.started = False
|
||||||
|
self.duration_timer = threading.Event()
|
||||||
|
self.water_flow_timer = threading.Event()
|
||||||
|
|
||||||
|
self.flow, self.rate = 0.00, 0.00
|
||||||
|
self.flow_meter_start()
|
||||||
|
self.relay_publish('init', index=self.index, label=self.label, dev_type=self.dev_type)
|
||||||
|
|
||||||
|
def now(self):
|
||||||
|
return utils.ts_now_s()
|
||||||
|
|
||||||
|
def relay_publish(self, topic, **kwargs):
|
||||||
|
if self.publish is not None:
|
||||||
|
self.publish(topic, **dict(
|
||||||
|
uuid=self.key,
|
||||||
|
ts=utils.ts_now_s(),
|
||||||
|
relay_state=self.is_on(),
|
||||||
|
elapsed=self.time_elapsed(),
|
||||||
|
remaining=self.time_remaining(),
|
||||||
|
flow=self.flow,
|
||||||
|
rate=self.rate,
|
||||||
|
**kwargs
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
def time_elapsed(self):
|
||||||
|
elapsed = self.now() - self.start_time
|
||||||
|
if self.start_time <= 0 or elapsed <= 0:
|
||||||
|
elapsed = 0
|
||||||
|
return elapsed
|
||||||
|
|
||||||
|
def time_remaining(self):
|
||||||
|
remaining = self.end_time - self.now()
|
||||||
|
if remaining < 0:
|
||||||
|
remaining = 0
|
||||||
|
return remaining
|
||||||
|
|
||||||
|
def is_it_over(self, timeout):
|
||||||
|
elapsed = self.now() - self.start_time
|
||||||
|
if elapsed > timeout:
|
||||||
|
self.duration_timer.set()
|
||||||
|
|
||||||
|
def _open(self, timeout):
|
||||||
|
self.duration_timer = threading.Event()
|
||||||
|
self.started = True
|
||||||
|
while not self.duration_timer.is_set():
|
||||||
|
try:
|
||||||
|
if self.started:
|
||||||
|
self.is_it_over(timeout)
|
||||||
|
threading.Event().wait(1.0)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f'run error {e}')
|
||||||
|
self.start_time = 0
|
||||||
|
self.relay_stop()
|
||||||
|
|
||||||
|
def relay_start(self, duration=0):
|
||||||
|
self.start_time = self.now()
|
||||||
|
self.end_time = self.start_time + duration
|
||||||
|
self.open()
|
||||||
|
if duration > 0:
|
||||||
|
threading.Thread(target=self._open, args=(duration, )).start()
|
||||||
|
self.rate, self.flow = 0.00, 0.00
|
||||||
|
self.begin = self.now()
|
||||||
|
self.water_flow_timer.set()
|
||||||
|
self.relay_publish('start')
|
||||||
|
|
||||||
|
def relay_stop(self):
|
||||||
|
self.duration_timer.set()
|
||||||
|
self.close()
|
||||||
|
self.started = False
|
||||||
|
self.water_flow_timer.clear()
|
||||||
|
self.relay_publish('stop')
|
||||||
|
|
||||||
|
def relay_halt(self):
|
||||||
|
if self.is_on():
|
||||||
|
self.started = False
|
||||||
|
|
||||||
|
def relay_restart(self):
|
||||||
|
if self.is_on():
|
||||||
|
self.started = True
|
||||||
|
|
||||||
|
def relay_status(self):
|
||||||
|
self.relay_publish('status')
|
||||||
|
|
||||||
|
def _flow_meter(self):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
self.water_flow_timer.wait()
|
||||||
|
elapsed = (self.now() - self.begin)/60
|
||||||
|
self.flow = random.randint(1050, 1065)/100 * elapsed
|
||||||
|
self.rate = self.flow / elapsed if elapsed > 0 else 0.00
|
||||||
|
threading.Event().wait(1.0)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f'flow_meter_process error {e}')
|
||||||
|
threading.Event().wait(1.0)
|
||||||
|
|
||||||
|
def flow_meter_start(self):
|
||||||
|
self.begin = self.now()
|
||||||
|
threading.Thread(target=self._flow_meter).start()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
'''
|
||||||
|
Created on 21 août 2022
|
||||||
|
|
||||||
|
@author: denis
|
||||||
|
'''
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
import threading
|
||||||
|
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
if os.getenv('BOARD_DEVICE') == 'RPI':
|
||||||
|
print("found a RPI board")
|
||||||
|
import RPi.GPIO as GPIO
|
||||||
|
logger.info(GPIO.RPI_INFO) # @UndefinedVariable
|
||||||
|
GPIO.setmode(GPIO.BOARD) # @UndefinedVariable
|
||||||
|
|
||||||
|
elif os.getenv('BOARD_DEVICE') == 'RPI1B':
|
||||||
|
print("found a RPI 1B board")
|
||||||
|
import RPi.GPIO as GPIO # @Reimport
|
||||||
|
logger.info(GPIO.RPI_INFO) # @UndefinedVariable
|
||||||
|
GPIO.setmode(GPIO.BOARD) # @UndefinedVariable
|
||||||
|
|
||||||
|
elif os.getenv('BOARD_DEVICE') == 'OPIWIN+':
|
||||||
|
print("found an OPI WIN+ board")
|
||||||
|
import orangepi.winplus
|
||||||
|
from OPi import GPIO # @Reimport
|
||||||
|
GPIO.setmode(orangepi.winplus.BOARD)
|
||||||
|
|
||||||
|
elif os.getenv('BOARD_DEVICE') == 'OPIZERO':
|
||||||
|
print("found an OPI ZERO board")
|
||||||
|
import orangepi.zero
|
||||||
|
from OPi import GPIO # @Reimport
|
||||||
|
GPIO.setmode(orangepi.zero.BOARD)
|
||||||
|
|
||||||
|
GPIO.setwarnings(False) # @UndefinedVariable
|
||||||
|
|
||||||
|
IO_RISING = GPIO.RISING # @UndefinedVariable
|
||||||
|
IO_FALLING = GPIO.FALLING # @UndefinedVariable
|
||||||
|
IO_BOTH = GPIO.BOTH # @UndefinedVariable
|
||||||
|
IO_LOW = GPIO.LOW # @UndefinedVariable
|
||||||
|
IO_HIGH = GPIO.HIGH # @UndefinedVariable
|
||||||
|
IO_INPUT = GPIO.IN # @UndefinedVariable
|
||||||
|
IO_OUTPUT = GPIO.OUT # @UndefinedVariable
|
||||||
|
|
||||||
|
IO_PULL_UP = GPIO.PUD_UP
|
||||||
|
IO_PULL_DOWN = GPIO.PUD_DOWN
|
||||||
|
IO_PULL_OFF = GPIO.PUD_OFF
|
||||||
|
|
||||||
|
IO_CLEANUP = GPIO.cleanup # @UndefinedVariable
|
||||||
|
|
||||||
|
lock = threading.Lock()
|
||||||
|
|
||||||
|
|
||||||
|
def bitread(b, bitpos):
|
||||||
|
return (b>>bitpos) & 0x1
|
||||||
|
|
||||||
|
class Pin:
|
||||||
|
def __init__(self, channel, sens, initial=None, callback=None, edge=IO_FALLING, bouncetime=500, pull_up_down=GPIO.PUD_OFF):
|
||||||
|
self.channel = channel
|
||||||
|
self.sens = sens
|
||||||
|
|
||||||
|
lock.acquire()
|
||||||
|
if initial in [GPIO.LOW, GPIO.HIGH] and sens==GPIO.OUT:
|
||||||
|
GPIO.setup(channel, sens, initial=initial, pull_up_down=pull_up_down)
|
||||||
|
else:
|
||||||
|
GPIO.setup(channel, sens, pull_up_down=pull_up_down)
|
||||||
|
|
||||||
|
if callback is not None:
|
||||||
|
self.set_interrupt(edge, callback, bouncetime)
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
logger.info(f'Channel {self.channel} sens: {sens} initial: {initial}')
|
||||||
|
self.value = self.read() # initial value
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
lock.acquire()
|
||||||
|
GPIO.cleanup(self.channel)
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
|
||||||
|
def set_interrupt(self, edge, callback, bouncetime=None):
|
||||||
|
if callable(callback) and edge in [IO_RISING, IO_FALLING, IO_BOTH]:
|
||||||
|
GPIO.add_event_detect(self.channel, edge, callback=callback, bouncetime=bouncetime)
|
||||||
|
|
||||||
|
|
||||||
|
def remove_interrupt(self):
|
||||||
|
lock.acquire()
|
||||||
|
GPIO.remove_event_detect(self.channel)
|
||||||
|
lock.release()
|
||||||
|
|
||||||
|
|
||||||
|
def state(self):
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
lock.acquire()
|
||||||
|
self.value = GPIO.input(self.channel)
|
||||||
|
lock.release()
|
||||||
|
#logger.info(f'Read {self.channel} -> {self.value}')
|
||||||
|
return self.value
|
||||||
|
|
||||||
|
def write(self, value):
|
||||||
|
lock.acquire()
|
||||||
|
GPIO.output(self.channel, value)
|
||||||
|
lock.release()
|
||||||
|
#logger.info(f'Write {self.channel} <- {value}')
|
||||||
|
return self.read()
|
||||||
|
|
||||||
|
|
||||||
|
class ShiftInRegister74HC165():
|
||||||
|
lastState = 0;
|
||||||
|
currentState = 0;
|
||||||
|
|
||||||
|
def __init__(self, latch_pin, clock_pin, data_pin, number=1):
|
||||||
|
self.datalen = number * 8
|
||||||
|
self.latch_pin = Pin(latch_pin, IO_OUTPUT, initial=IO_LOW, pull_up_down=IO_PULL_DOWN)
|
||||||
|
self.clock_pin = Pin(clock_pin, IO_OUTPUT, initial=IO_LOW, pull_up_down=IO_PULL_DOWN)
|
||||||
|
self.data_pin = Pin(data_pin, IO_INPUT, initial=IO_LOW, pull_up_down=IO_PULL_DOWN)
|
||||||
|
threading.Event().wait(0.5)
|
||||||
|
|
||||||
|
def read(self):
|
||||||
|
self.lastState = self.currentState
|
||||||
|
result = 0
|
||||||
|
self.latch_pin.write(IO_HIGH)
|
||||||
|
for i in range(self.datalen):
|
||||||
|
value = self.data_pin.read()
|
||||||
|
result |= (value << ((self.datalen-1) - i))
|
||||||
|
self.clock_pin.write(IO_HIGH)
|
||||||
|
self.clock_pin.write(IO_LOW)
|
||||||
|
self.latch_pin.write(IO_LOW)
|
||||||
|
self.currentState = result
|
||||||
|
return result
|
||||||
|
|
||||||
|
def state(self, idx):
|
||||||
|
return bitread(self.currentState, idx)
|
||||||
|
|
||||||
|
def last(self, idx):
|
||||||
|
return bitread(self.lastState, idx)
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
return self.read()!=self.lastState
|
||||||
|
|
||||||
|
def hasChanged(self, idx=None):
|
||||||
|
return self.lastState!=self.currentState if idx is None else self.state(idx)!=self.last(idx)
|
||||||
|
|
||||||
|
def pressed(self, idx):
|
||||||
|
return not self.last(idx) and self.state(idx)
|
||||||
|
|
||||||
|
def released(self, idx):
|
||||||
|
return self.last(idx) and not self.state(idx)
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
self.latch_pin.cleanup()
|
||||||
|
self.clock_pin.cleanup()
|
||||||
|
self.data_pin.cleanup()
|
||||||
|
|
||||||
|
|
||||||
|
class ShiftOutRegister74HC595():
|
||||||
|
|
||||||
|
def __init__(self, latch_pin, clock_pin, data_pin, number=1):
|
||||||
|
self.datalen = number * 8
|
||||||
|
self.latch_pin = Pin(latch_pin, IO_OUTPUT, initial=IO_LOW)
|
||||||
|
self.clock_pin = Pin(clock_pin, IO_OUTPUT, initial=IO_LOW)
|
||||||
|
self.data_pin = Pin(data_pin, IO_OUTPUT, initial=IO_LOW)
|
||||||
|
self.set_low()
|
||||||
|
threading.Event().wait(0.5)
|
||||||
|
|
||||||
|
def set_low(self):
|
||||||
|
self.registers = [0] * self.datalen
|
||||||
|
self.write()
|
||||||
|
|
||||||
|
def write(self):
|
||||||
|
self.clock_pin.write(IO_LOW)
|
||||||
|
self.latch_pin.write(IO_LOW)
|
||||||
|
self.clock_pin.write(IO_HIGH)
|
||||||
|
#
|
||||||
|
#for i in range(self.datalen):
|
||||||
|
for bit in self.registers:
|
||||||
|
self.clock_pin.write(IO_LOW)
|
||||||
|
self.data_pin.write(int(bit))
|
||||||
|
self.clock_pin.write(IO_HIGH)
|
||||||
|
#
|
||||||
|
self.clock_pin.write(IO_LOW)
|
||||||
|
self.latch_pin.write(IO_HIGH)
|
||||||
|
self.clock_pin.write(IO_HIGH)
|
||||||
|
|
||||||
|
def set(self, index, state):
|
||||||
|
self.registers[index] = int(state)
|
||||||
|
self.write()
|
||||||
|
return int(state)
|
||||||
|
|
||||||
|
def get(self, index):
|
||||||
|
return self.registers[index]
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
self.set_low()
|
||||||
|
self.latch_pin.cleanup()
|
||||||
|
self.clock_pin.cleanup()
|
||||||
|
self.data_pin.cleanup()
|
||||||
|
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
'''
|
||||||
|
Created on 29 août 2022
|
||||||
|
|
||||||
|
@author: denis
|
||||||
|
'''
|
||||||
|
import logging
|
||||||
|
import threading
|
||||||
|
from RPLCD.i2c import CharLCD
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
#lcd = CharLCD(settings.LCD_EXPANDER, settings.LCD_ADDR, port=settings.LCD_PORT)
|
||||||
|
|
||||||
|
|
||||||
|
class LCD():
|
||||||
|
def __init__(self, lcd, timeout=None):
|
||||||
|
self.lcd = lcd
|
||||||
|
self.waiter = threading.Event()
|
||||||
|
self.cols = 16
|
||||||
|
self.timeout = timeout
|
||||||
|
self.screen_enabled = True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def screen_enabled(self):
|
||||||
|
return self._enabled
|
||||||
|
|
||||||
|
@screen_enabled.setter
|
||||||
|
def screen_enabled(self, v):
|
||||||
|
self.lcd.backlight_enabled = v
|
||||||
|
self._enabled = v
|
||||||
|
|
||||||
|
|
||||||
|
def create_char(self, pos, cc):
|
||||||
|
self.lcd.create_char(pos, cc)
|
||||||
|
|
||||||
|
|
||||||
|
# LCD display
|
||||||
|
def _display(self, event, msg, timeout):
|
||||||
|
self.screen_enabled = True
|
||||||
|
self.lcd.clear()
|
||||||
|
self.lcd.write_string(msg)
|
||||||
|
event.wait(timeout)
|
||||||
|
self.screen_enabled = False
|
||||||
|
|
||||||
|
|
||||||
|
def write_msg(self, msg, timeout=5):
|
||||||
|
if not self.waiter.is_set():
|
||||||
|
self.waiter.set()
|
||||||
|
self.waiter = threading.Event()
|
||||||
|
threading.Thread(target=self._display, args=(self.waiter, msg, timeout, )).start()
|
||||||
|
|
||||||
|
|
||||||
|
def _screen_enable(self, event, timeout):
|
||||||
|
self.screen_enabled = True
|
||||||
|
event.wait(timeout)
|
||||||
|
self.screen_enabled = False
|
||||||
|
|
||||||
|
|
||||||
|
def screen_disable(self):
|
||||||
|
if not self.waiter.is_set():
|
||||||
|
self.waiter.set()
|
||||||
|
self.screen_enabled = False
|
||||||
|
|
||||||
|
|
||||||
|
def screen_enable(self):
|
||||||
|
if self.timeout is not None:
|
||||||
|
if not self.waiter.is_set():
|
||||||
|
self.waiter.set()
|
||||||
|
self.waiter = threading.Event()
|
||||||
|
threading.Thread(target=self._screen_enable, args=(self.waiter, self.timeout, )).start()
|
||||||
|
else:
|
||||||
|
self.screen_enabled = True
|
||||||
|
|
||||||
|
|
||||||
|
def display(self, msg, pos=(0, 0), align=None, clear=True):
|
||||||
|
self.screen_enable()
|
||||||
|
|
||||||
|
if clear:
|
||||||
|
self.lcd.clear()
|
||||||
|
self.lcd.cursor_pos = pos
|
||||||
|
if align=='left':
|
||||||
|
self.lcd.write_string(msg.ljust(self.cols))
|
||||||
|
elif align=='right':
|
||||||
|
self.lcd.write_string(msg.rjust(self.cols))
|
||||||
|
else:
|
||||||
|
self.lcd.write_string(msg)
|
||||||
|
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
#
|
||||||
|
# mqtt service
|
||||||
|
#
|
||||||
|
import json, time, logging, ssl
|
||||||
|
import paho.mqtt.client as mqtt
|
||||||
|
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class MqttBase(object):
|
||||||
|
def __init__(self, **p):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.host = p.get('host')
|
||||||
|
self.port = p.get('port')
|
||||||
|
self.username = p.get('username')
|
||||||
|
self.password = p.get('password')
|
||||||
|
self.keepalive = p.get('keepalive')
|
||||||
|
self.use_ssl = p.get('use_ssl', False)
|
||||||
|
self.ca_cert = p.get('ca_cert')
|
||||||
|
self.tls_version = p.get('tls_version', ssl.PROTOCOL_TLSv1_2)
|
||||||
|
self.subscriptions = [(topic, qos) for topic, qos in p.get('topic_subs', [])]
|
||||||
|
self.unsubs = self.client_get_unsubs()
|
||||||
|
self.topic_base = p.get('topic_base', '')
|
||||||
|
|
||||||
|
self.on_message_callback = p.get('on_messages', self._on_message_callback)
|
||||||
|
self.on_bytes_callback = p.get('on_bytes', self._on_bytes_callback)
|
||||||
|
# mqtt Client
|
||||||
|
self.client = mqtt.Client()
|
||||||
|
if self.username:
|
||||||
|
self.client.username_pw_set(username=self.username, password=self.password)
|
||||||
|
if self.use_ssl and self.ca_cert:
|
||||||
|
self.client.tls_set(ca_certs=self.ca_cert, tls_version=self.tls_version)
|
||||||
|
|
||||||
|
self.client.on_connect = self._on_connect
|
||||||
|
self.client.on_disconnect = self._on_disconnect
|
||||||
|
self.client.on_message = self._on_message
|
||||||
|
self.client.on_log = self._on_log
|
||||||
|
|
||||||
|
|
||||||
|
def client_get_unsubs(self):
|
||||||
|
return [topic for topic, _ in self.subscriptions ]
|
||||||
|
|
||||||
|
|
||||||
|
def client_set_subscriptions(self):
|
||||||
|
self.client.unsubscribe(self.client_get_unsubs())
|
||||||
|
self.client.subscribe(self.subscriptions)
|
||||||
|
logger.info(f"\n client_set_subscription {self.subscriptions}")
|
||||||
|
|
||||||
|
|
||||||
|
def client_add_subscriptions(self, subs=[]):
|
||||||
|
self.subscriptions += subs
|
||||||
|
self.subscriptions = list(set(self.subscriptions))
|
||||||
|
|
||||||
|
|
||||||
|
def _publish_message(self, topic, **payload):
|
||||||
|
try:
|
||||||
|
qos = payload.pop('qos', 0)
|
||||||
|
retain = payload.pop('retain', False)
|
||||||
|
message = json.dumps(payload)
|
||||||
|
self.client.publish(topic, payload=message.encode('utf-8'), qos=qos, retain=retain)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
|
||||||
|
|
||||||
|
def _publish_bytes(self, topic, payload, **conf):
|
||||||
|
try:
|
||||||
|
qos = conf.pop('qos', 0)
|
||||||
|
retain = conf.pop('retain', False)
|
||||||
|
self.client.publish(topic, payload=payload, qos=qos, retain=retain)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"\n _publish_bytes error: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def _on_log(self, mqttc, obj, level, string): # @UnusedVariable
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _on_connect_info(self, info):
|
||||||
|
logger.info(info)
|
||||||
|
|
||||||
|
|
||||||
|
def _on_connect(self, client, userdata, flags, rc):
|
||||||
|
msg = f"Client mqtt\n {client._client_id} connected\n status {rc}\n host={self.host}:{self.port}\n username={self.username}"
|
||||||
|
try:
|
||||||
|
if rc:
|
||||||
|
raise
|
||||||
|
self.client_set_subscriptions()
|
||||||
|
self._on_connect_info(msg)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"\n _on_connect error {e}")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _on_disconnect(self, client, userdata, rc):
|
||||||
|
logger.info(f"Client mqtt\n Disconnected: {client._client_id} with status {rc}")
|
||||||
|
try:
|
||||||
|
j = 3
|
||||||
|
for i in range(j):
|
||||||
|
#client.unsubscribe(self.unsubs)
|
||||||
|
try:
|
||||||
|
client.reconnect()
|
||||||
|
break
|
||||||
|
except Exception as e:
|
||||||
|
if i < j:
|
||||||
|
logger.warn(e)
|
||||||
|
time.sleep(1)
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Client mqtt\n _on_disconnect error {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def _on_stop_mqtt(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _on_message_callback(self, topic, payload):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _on_bytes_callback(self, topic, payload):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _on_message(self, client, userdata, message):
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
payload = json.loads(message.payload.decode("utf-8"))
|
||||||
|
self.on_message_callback(message.topic, payload)
|
||||||
|
except:
|
||||||
|
self.on_bytes_callback(message.topic, message.payload)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"\n==== _on_message error {e}\n {message.topic} {message.payload[:80]}")
|
||||||
|
|
||||||
|
|
||||||
|
def connectMQTT(self):
|
||||||
|
self.client.connect_async(self.host, self.port, self.keepalive)
|
||||||
|
|
||||||
|
|
||||||
|
def loop_forever(self):
|
||||||
|
self.connectMQTT()
|
||||||
|
self.client.loop_forever()
|
||||||
|
|
||||||
|
|
||||||
|
def startMQTT(self):
|
||||||
|
self.connectMQTT()
|
||||||
|
self.client.loop_start()
|
||||||
|
|
||||||
|
|
||||||
|
def stopMQTT(self):
|
||||||
|
self._on_stop_mqtt()
|
||||||
|
self.client.loop_stop()
|
||||||
|
self.client.disconnect()
|
||||||
|
|
||||||
@@ -0,0 +1,193 @@
|
|||||||
|
'''
|
||||||
|
Created on 22 août 2022
|
||||||
|
|
||||||
|
@author: denis
|
||||||
|
'''
|
||||||
|
import logging
|
||||||
|
import threading
|
||||||
|
from . import gpiolib as gpio
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
class DeviceRegister:
|
||||||
|
|
||||||
|
def __init__(self, register:dict):
|
||||||
|
"""
|
||||||
|
register must contain
|
||||||
|
{'dev_type': 'None', 'index': 0, 'key': 'default', 'label': 'Default label', 'status': 0, 'active': 1}
|
||||||
|
"""
|
||||||
|
self.register = register.copy()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dev_type(self):
|
||||||
|
return self.register.get('dev_type')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def status(self):
|
||||||
|
return self.register.get('status')
|
||||||
|
|
||||||
|
@status.setter
|
||||||
|
def status(self, v):
|
||||||
|
self.register['status'] = int(v)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def active_pin(self):
|
||||||
|
return self.register.get('active')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def key(self):
|
||||||
|
return self.register.get('key')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def label(self):
|
||||||
|
return self.register.get('label')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def index(self):
|
||||||
|
return self.register.get('index')
|
||||||
|
|
||||||
|
class Device(DeviceRegister):
|
||||||
|
|
||||||
|
def __init__(self, pin, register=None, sens=gpio.IO_OUTPUT, initial=None, callback=None, edge=gpio.IO_FALLING, bouncetime=500, pull_up_down=None):
|
||||||
|
super().__init__(register)
|
||||||
|
|
||||||
|
self.pin = gpio.Pin(pin, sens=sens, initial=initial, callback=callback, edge=edge, bouncetime=bouncetime, pull_up_down=pull_up_down)
|
||||||
|
self.sens = sens
|
||||||
|
self.active = gpio.IO_HIGH if self.active_pin else gpio.IO_LOW
|
||||||
|
self.not_active = gpio.IO_LOW if self.active_pin else gpio.IO_HIGH
|
||||||
|
self.is_opened = self.is_on
|
||||||
|
self.is_closed = self.is_off
|
||||||
|
self.open = self.on
|
||||||
|
self.close = self.off
|
||||||
|
|
||||||
|
if self.sens == gpio.IO_OUTPUT:
|
||||||
|
if initial==gpio.IO_HIGH:
|
||||||
|
self.on()
|
||||||
|
elif initial==gpio.IO_LOW:
|
||||||
|
self.off()
|
||||||
|
|
||||||
|
def state(self):
|
||||||
|
return self.pin.read()
|
||||||
|
|
||||||
|
def on(self):
|
||||||
|
if self.sens == gpio.IO_OUTPUT:
|
||||||
|
return self.pin.write(self.active)
|
||||||
|
|
||||||
|
def off(self):
|
||||||
|
if self.sens == gpio.IO_OUTPUT:
|
||||||
|
return self.pin.write(self.not_active)
|
||||||
|
|
||||||
|
def is_on(self):
|
||||||
|
return self.state() == self.active
|
||||||
|
|
||||||
|
def is_off(self):
|
||||||
|
return self.state() == self.not_active
|
||||||
|
|
||||||
|
def toggle(self):
|
||||||
|
if self.is_on():
|
||||||
|
return self.off()
|
||||||
|
if self.is_off():
|
||||||
|
return self.on()
|
||||||
|
|
||||||
|
class Led(Device):
|
||||||
|
|
||||||
|
def __init__(self, pin, register=None, initial=gpio.IO_LOW):
|
||||||
|
super().__init__(pin, register=register, sens=gpio.IO_OUTPUT, initial=initial)
|
||||||
|
|
||||||
|
class Relay(Device):
|
||||||
|
|
||||||
|
def __init__(self, pin, register=None, initial=gpio.IO_LOW):
|
||||||
|
super().__init__(pin, register=register, sens=gpio.IO_OUTPUT, initial=initial)
|
||||||
|
|
||||||
|
class Switch(Device):
|
||||||
|
|
||||||
|
def __init__(self, pin, register=None, callback=None, edge=gpio.IO_BOTH):
|
||||||
|
super().__init__(pin, register=register, callback=callback, sens=gpio.IO_INPUT, edge=edge)
|
||||||
|
|
||||||
|
def on(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def off(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Button(Device):
|
||||||
|
|
||||||
|
def __init__(self, pin, register=None, callback=None, bouncetime=500):
|
||||||
|
super().__init__(pin, register=register, callback=callback, sens=gpio.IO_INPUT, edge=gpio.IO_FALLING, bouncetime=bouncetime)
|
||||||
|
self._state = self.not_active
|
||||||
|
|
||||||
|
def state(self):
|
||||||
|
return self._state
|
||||||
|
|
||||||
|
def on(self):
|
||||||
|
self._state = self.active
|
||||||
|
|
||||||
|
def off(self):
|
||||||
|
self._state = self.not_active
|
||||||
|
|
||||||
|
class InputDevice(Device):
|
||||||
|
|
||||||
|
def __init__(self, pin, register=None, callback=None, pull_up_down=gpio.IO_PULL_UP):
|
||||||
|
super().__init__(pin, register=register, callback=callback, sens=gpio.IO_INPUT, edge=gpio.IO_FALLING, pull_up_down=pull_up_down)
|
||||||
|
|
||||||
|
def on(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def off(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class RelayFromShiftOut(DeviceRegister):
|
||||||
|
|
||||||
|
def __init__(self, shift_out_register, register=None, relay_timeout=0, closed=True):
|
||||||
|
super().__init__(register)
|
||||||
|
self.shift_out_register = shift_out_register
|
||||||
|
|
||||||
|
self.max_index = shift_out_register.datalen
|
||||||
|
self.active = gpio.IO_HIGH if self.active_pin else gpio.IO_LOW
|
||||||
|
self.not_active = gpio.IO_LOW if self.active_pin else gpio.IO_HIGH
|
||||||
|
|
||||||
|
self.relay_timeout = 0
|
||||||
|
self.is_opened = self.is_on
|
||||||
|
self.is_closed = self.is_off
|
||||||
|
self.open = self.on
|
||||||
|
self.close = self.off
|
||||||
|
|
||||||
|
if closed:
|
||||||
|
self.off()
|
||||||
|
else:
|
||||||
|
self.on()
|
||||||
|
|
||||||
|
self.relay_timeout = relay_timeout
|
||||||
|
|
||||||
|
logger.info(f'RelayShiftOut Init index {self.index}')
|
||||||
|
|
||||||
|
def wait_after_event(self, timeout):
|
||||||
|
if timeout:
|
||||||
|
threading.Event().wait(timeout)
|
||||||
|
|
||||||
|
def on(self):
|
||||||
|
self.status = self.shift_out_register.set(self.index, self.active)
|
||||||
|
self.wait_after_event(self.relay_timeout) # wait after opening
|
||||||
|
logger.info(f'RelayShiftOut {self.index} on')
|
||||||
|
return self.status
|
||||||
|
|
||||||
|
def off(self):
|
||||||
|
self.status = self.shift_out_register.set(self.index, self.not_active)
|
||||||
|
self.wait_after_event(self.relay_timeout) # wait after closing
|
||||||
|
logger.info(f'RelayShiftOut {self.index} off')
|
||||||
|
return self.status
|
||||||
|
|
||||||
|
def is_on(self):
|
||||||
|
self.status = self.shift_out_register.get(self.index) == self.active
|
||||||
|
return self.status
|
||||||
|
|
||||||
|
def is_off(self):
|
||||||
|
self.status = self.shift_out_register.get(self.index) == self.not_active
|
||||||
|
return self.status
|
||||||
|
|
||||||
|
def toggle(self):
|
||||||
|
if self.is_on():
|
||||||
|
return self.off()
|
||||||
|
if self.is_off():
|
||||||
|
return self.on()
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
'''
|
||||||
|
Created on 3 févr. 2026
|
||||||
|
|
||||||
|
@author: denis
|
||||||
|
'''
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
# myapp/system_stats.py
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
import psutil
|
||||||
|
|
||||||
|
# intervale de mise à jour (secondes)
|
||||||
|
REFRESH_INTERVAL = 5
|
||||||
|
RAMDISK = settings.RAMDISK_DEVICE
|
||||||
|
|
||||||
|
_cache = {
|
||||||
|
"shm": [],
|
||||||
|
"cpu_info": {},
|
||||||
|
"memory_info": {},
|
||||||
|
"disk_info": {},
|
||||||
|
"ramdisk_info": {},
|
||||||
|
"updated_at": None
|
||||||
|
}
|
||||||
|
|
||||||
|
_lock = threading.Lock()
|
||||||
|
_timer = None
|
||||||
|
|
||||||
|
|
||||||
|
def _collect_once():
|
||||||
|
data = {}
|
||||||
|
|
||||||
|
# shm: liste /dev/shm si disponible
|
||||||
|
try:
|
||||||
|
path = "/dev/shm"
|
||||||
|
data["shm"] = os.listdir(path) if os.path.exists(path) and os.path.isdir(path) else []
|
||||||
|
except Exception as e:
|
||||||
|
data["shm_error"] = str(e)
|
||||||
|
|
||||||
|
|
||||||
|
# cpu_info
|
||||||
|
try:
|
||||||
|
cpu_times = psutil.cpu_times_percent(interval=None, percpu=False)._asdict()
|
||||||
|
data["cpu_info"] = {
|
||||||
|
"cpu_count": psutil.cpu_count(logical=True),
|
||||||
|
"cpu_count_physical": psutil.cpu_count(logical=False),
|
||||||
|
"cpu_percent": psutil.cpu_percent(interval=None),
|
||||||
|
"cpu_times_percent": cpu_times
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
data["cpu_info_error"] = str(e)
|
||||||
|
|
||||||
|
|
||||||
|
# memory_info
|
||||||
|
try:
|
||||||
|
vm = psutil.virtual_memory()._asdict()
|
||||||
|
sm = psutil.swap_memory()._asdict()
|
||||||
|
data["memory_info"] = {"virtual_memory": vm, "swap_memory": sm}
|
||||||
|
except Exception as e:
|
||||||
|
data["memory_info_error"] = str(e)
|
||||||
|
|
||||||
|
|
||||||
|
# disk_info (root and partitions)
|
||||||
|
# ex: if mountpoint == "/ramdisk" and fstype=="tmpfs" then usage.percent, usage.free, etc ...
|
||||||
|
try:
|
||||||
|
usage_root = psutil.disk_usage("/")._asdict()
|
||||||
|
parts = []
|
||||||
|
for p in psutil.disk_partitions(all=False):
|
||||||
|
try:
|
||||||
|
du = psutil.disk_usage(p.mountpoint)._asdict()
|
||||||
|
except Exception:
|
||||||
|
du = {}
|
||||||
|
parts.append({"device": p.device, "mountpoint": p.mountpoint, "fstype": p.fstype, "usage": du})
|
||||||
|
data["disk_info"] = {"root": usage_root, "partitions": parts}
|
||||||
|
except Exception as e:
|
||||||
|
data["disk_info_error"] = str(e)
|
||||||
|
|
||||||
|
# ramdisk
|
||||||
|
# ex: if mountpoint == "/ramdisk" and fstype=="tmpfs" then usage.percent, usage.free, etc ...
|
||||||
|
try:
|
||||||
|
for part in psutil.disk_partitions(all=True):
|
||||||
|
if part.mountpoint == RAMDISK and part.fstype.lower() == "tmpfs":
|
||||||
|
usage = psutil.disk_usage(part.mountpoint)
|
||||||
|
data["ramdisk_info"] = {
|
||||||
|
"percent": usage.percent,
|
||||||
|
"mount": part.mountpoint,
|
||||||
|
"device": part.device,
|
||||||
|
"fstype": part.fstype,
|
||||||
|
"total": usage.total,
|
||||||
|
"used": usage.used,
|
||||||
|
"free": usage.free,
|
||||||
|
}
|
||||||
|
except Exception as e:
|
||||||
|
data["ramdisk_info_error"] = str(e)
|
||||||
|
|
||||||
|
data["updated_at"] = time.time()
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def _update_cache():
|
||||||
|
global _timer
|
||||||
|
try:
|
||||||
|
new = _collect_once()
|
||||||
|
with _lock:
|
||||||
|
_cache.update(new)
|
||||||
|
finally:
|
||||||
|
# reprogrammer
|
||||||
|
_timer = threading.Timer(REFRESH_INTERVAL, _update_cache)
|
||||||
|
_timer.daemon = True
|
||||||
|
_timer.start()
|
||||||
|
|
||||||
|
|
||||||
|
def start_background_updater(interval_seconds: int = None):
|
||||||
|
global REFRESH_INTERVAL, _timer
|
||||||
|
if interval_seconds:
|
||||||
|
REFRESH_INTERVAL = interval_seconds
|
||||||
|
if _timer is not None:
|
||||||
|
return
|
||||||
|
# première collecte synchronisée
|
||||||
|
with _lock:
|
||||||
|
_cache.update(_collect_once())
|
||||||
|
_timer = threading.Timer(REFRESH_INTERVAL, _update_cache)
|
||||||
|
_timer.daemon = True
|
||||||
|
_timer.start()
|
||||||
|
|
||||||
|
|
||||||
|
def stop_background_updater():
|
||||||
|
global _timer
|
||||||
|
if _timer is not None:
|
||||||
|
_timer.cancel()
|
||||||
|
_timer = None
|
||||||
|
|
||||||
|
|
||||||
|
def get_cached_stats():
|
||||||
|
with _lock:
|
||||||
|
# retourner copie pour sécurité
|
||||||
|
return dict(_cache)
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
'''
|
||||||
|
Created on 20 avr. 2022
|
||||||
|
|
||||||
|
@author: denis
|
||||||
|
'''
|
||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
import time
|
||||||
|
import importlib
|
||||||
|
from datetime import datetime
|
||||||
|
import string, secrets
|
||||||
|
import uuid
|
||||||
|
from threading import Event, Thread
|
||||||
|
from urllib.parse import urlsplit
|
||||||
|
import asyncio
|
||||||
|
import mmap
|
||||||
|
import fcntl
|
||||||
|
import psutil
|
||||||
|
|
||||||
|
SHM_DIR = "/dev/shm"
|
||||||
|
|
||||||
|
def open_shm(name: str, size: int, create=True):
|
||||||
|
path = os.path.join(SHM_DIR, name)
|
||||||
|
flags = os.O_RDWR | (os.O_CREAT if create else 0)
|
||||||
|
fd = os.open(path, flags)
|
||||||
|
try:
|
||||||
|
if create:
|
||||||
|
os.ftruncate(fd, size)
|
||||||
|
mm = mmap.mmap(fd, size)
|
||||||
|
finally:
|
||||||
|
os.close(fd)
|
||||||
|
return mm, path
|
||||||
|
|
||||||
|
def read_shm(name: str, size: int):
|
||||||
|
mm, path = open_shm(name, size, create=False) # @UnusedVariable
|
||||||
|
try:
|
||||||
|
mm.seek(0)
|
||||||
|
data = mm.read(size)
|
||||||
|
return data.rstrip(b"\0")
|
||||||
|
finally:
|
||||||
|
mm.close()
|
||||||
|
|
||||||
|
def write_shm(name: str, size: int, data: bytes):
|
||||||
|
mm, path = open_shm(name, size, create=True)
|
||||||
|
fd = os.open(path, os.O_RDWR)
|
||||||
|
try:
|
||||||
|
fcntl.flock(fd, fcntl.LOCK_EX)
|
||||||
|
try:
|
||||||
|
mm.seek(0)
|
||||||
|
mm.write(data.ljust(size, b"\0")[:size])
|
||||||
|
mm.flush()
|
||||||
|
finally:
|
||||||
|
fcntl.flock(fd, fcntl.LOCK_UN)
|
||||||
|
finally:
|
||||||
|
mm.close()
|
||||||
|
os.close(fd)
|
||||||
|
|
||||||
|
def get_tmpfs_info(mount_point="/ramdisk"):
|
||||||
|
def sizeof(n):
|
||||||
|
for unit in ['B','KB','MB','GB','TB']:
|
||||||
|
if n < 1024:
|
||||||
|
return f"{n:.1f}{unit}"
|
||||||
|
n /= 1024
|
||||||
|
return f"{n:.1f}PB"
|
||||||
|
|
||||||
|
usage = None
|
||||||
|
for part in psutil.disk_partitions(all=True):
|
||||||
|
if part.mountpoint == mount_point and part.fstype.lower() == "tmpfs":
|
||||||
|
usage = psutil.disk_usage(part.mountpoint)
|
||||||
|
print(f"Mount: {part.mountpoint}")
|
||||||
|
print(f" Device: {part.device}")
|
||||||
|
print(f" Fstype: {part.fstype}")
|
||||||
|
print(f" Total: {usage.total} bytes ({sizeof(usage.total)})")
|
||||||
|
print(f" Used: {usage.used} bytes ({sizeof(usage.used)})")
|
||||||
|
print(f" Free: {usage.free} bytes ({sizeof(usage.free)})")
|
||||||
|
print(f" Percent used: {usage.percent}%")
|
||||||
|
break
|
||||||
|
return {
|
||||||
|
"percent": usage.percent,
|
||||||
|
"mount": part.mountpoint,
|
||||||
|
"device": part.device,
|
||||||
|
"fstype": part.fstype,
|
||||||
|
"total": usage.total,
|
||||||
|
"used": usage.used,
|
||||||
|
"free": usage.free,
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_cpu_info():
|
||||||
|
# cpu percent par coeur et moyennes load
|
||||||
|
return {
|
||||||
|
"cpu_percent_per_cpu": psutil.cpu_percent(interval=0.5, percpu=True),
|
||||||
|
"cpu_percent_total": psutil.cpu_percent(interval=None),
|
||||||
|
"load_avg": os.getloadavg(), # (1,5,15)
|
||||||
|
"cpu_count": psutil.cpu_count(logical=True),
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_memory_info():
|
||||||
|
vm = psutil.virtual_memory()
|
||||||
|
sm = psutil.swap_memory()
|
||||||
|
return {
|
||||||
|
"total": vm.total,
|
||||||
|
"available": vm.available,
|
||||||
|
"used": vm.used,
|
||||||
|
"free": vm.free,
|
||||||
|
"percent": vm.percent,
|
||||||
|
"swap_total": sm.total,
|
||||||
|
"swap_used": sm.used,
|
||||||
|
"swap_free": sm.free,
|
||||||
|
"swap_percent": sm.percent,
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_disk_info(path="/"):
|
||||||
|
du = psutil.disk_usage(path)
|
||||||
|
return {
|
||||||
|
"path": path,
|
||||||
|
"total": du.total,
|
||||||
|
"used": du.used,
|
||||||
|
"free": du.free,
|
||||||
|
"percent": du.percent,
|
||||||
|
}
|
||||||
|
|
||||||
|
def extract_host_port_path(url, default_port=None):
|
||||||
|
"""
|
||||||
|
Retoure (host, port, path) où:
|
||||||
|
- host: string (IP ou hostname) ou None
|
||||||
|
- port: int ou None (utilise default_port si fourni et aucun port explicite)
|
||||||
|
- path: string (chemin + query + fragment si présents), ou '' si absent
|
||||||
|
"""
|
||||||
|
parts = urlsplit(url if '://' in url else '//' + url, scheme='')
|
||||||
|
host = parts.hostname
|
||||||
|
port = parts.port or default_port
|
||||||
|
# Reconstruire path complet: path + ('?' + query) + ('#' + fragment)
|
||||||
|
path = parts.path or ''
|
||||||
|
if parts.query:
|
||||||
|
path += '?' + parts.query
|
||||||
|
if parts.fragment:
|
||||||
|
path += '#' + parts.fragment
|
||||||
|
return host, port, path
|
||||||
|
|
||||||
|
def image_path(imagefile):
|
||||||
|
image_path = imagefile.path
|
||||||
|
pdir = os.path.dirname(image_path)
|
||||||
|
os.makedirs(pdir, exist_ok=True)
|
||||||
|
return str(image_path)
|
||||||
|
|
||||||
|
def serialize_datetime(obj):
|
||||||
|
if isinstance(obj, datetime):
|
||||||
|
return obj.isoformat()
|
||||||
|
raise TypeError("Type not serializable")
|
||||||
|
|
||||||
|
def start_async():
|
||||||
|
loop = asyncio.new_event_loop()
|
||||||
|
Thread(target=loop.run_forever, daemon=True).start()
|
||||||
|
return loop
|
||||||
|
|
||||||
|
def stop_async(loop):
|
||||||
|
loop.call_soon_threadsafe(loop.stop)
|
||||||
|
|
||||||
|
def submit_async(loop, awaitable):
|
||||||
|
return asyncio.run_coroutine_threadsafe(awaitable, loop)
|
||||||
|
|
||||||
|
def to_choice(d):
|
||||||
|
choices = []
|
||||||
|
for k, v in d.items():
|
||||||
|
choices.append((k, v))
|
||||||
|
return choices
|
||||||
|
|
||||||
|
def get_instance_class(module):
|
||||||
|
modulename, classname = module.rsplit(".", 1)
|
||||||
|
return getattr(importlib.import_module(modulename), classname)
|
||||||
|
|
||||||
|
def wait_for(timeout):
|
||||||
|
Event().wait(timeout)
|
||||||
|
|
||||||
|
def yaml_load(f):
|
||||||
|
with open(f, 'r') as stream:
|
||||||
|
return yaml.safe_load(stream)
|
||||||
|
return {}
|
||||||
|
|
||||||
|
def yaml_save(f, context):
|
||||||
|
with open(f, 'w') as stream:
|
||||||
|
yaml.dump(context, stream, default_flow_style = False)
|
||||||
|
|
||||||
|
def get_uuid():
|
||||||
|
return str(hex(uuid.getnode()))[2:]
|
||||||
|
|
||||||
|
def millis():
|
||||||
|
return round(time.time() * 1000)
|
||||||
|
|
||||||
|
def now():
|
||||||
|
return datetime.now()
|
||||||
|
|
||||||
|
def ts_now():
|
||||||
|
# float second
|
||||||
|
return now().timestamp()
|
||||||
|
|
||||||
|
def ts_now_s():
|
||||||
|
return int(ts_now())
|
||||||
|
|
||||||
|
def ts_now_ms():
|
||||||
|
return int(ts_now()*1000)
|
||||||
|
|
||||||
|
def ts_now_us():
|
||||||
|
return int(ts_now()*1000000)
|
||||||
|
|
||||||
|
def random_num(n=16):
|
||||||
|
alphabet = string.digits
|
||||||
|
return ''.join(secrets.choice(alphabet) for i in range(n)) # @UnusedVariable
|
||||||
|
|
||||||
|
def random_chars(n=6):
|
||||||
|
alphabet = string.ascii_letters + string.digits
|
||||||
|
return ''.join(secrets.choice(alphabet) for i in range(n)) # @UnusedVariable
|
||||||
|
|
||||||
|
def get_apikey(n=32):
|
||||||
|
chars = 'abcdefgh01234ijklABCD4567EFGHIJKLmnopqrstuvwxyz0123456789MNOPQRS789TUVWXYZ'
|
||||||
|
return ''.join(secrets.choice(chars) for i in range(n)) # @UnusedVariable
|
||||||
|
|
||||||
|
def gen_keywords(s):
|
||||||
|
c = s.replace(',', ' ').replace('+', ' ')
|
||||||
|
return [ w.strip() for w in c.split(' ') if w]
|
||||||
|
|
||||||
|
def gen_device_uuid(n=19):
|
||||||
|
return hex(int(random_num(n)))[2:]
|
||||||
|
|
||||||
|
def get_device_uuid(n=19):
|
||||||
|
return f'0x{gen_device_uuid(n)}'
|
||||||
|
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.contrib import admin
|
||||||
|
from django_celery_beat.admin import PeriodicTaskAdmin, PeriodicTask
|
||||||
|
|
||||||
|
from .models import (Device, DeviceType)
|
||||||
|
|
||||||
|
class DeviceAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('label', 'uuid', 'image_tag', 'device_type__code', 'index', 'task', 'lifetime', 'task_d', 'active')
|
||||||
|
list_filter = ('device_type', 'active')
|
||||||
|
search_fields = ('label',)
|
||||||
|
readonly_fields = ('uuid',)
|
||||||
|
|
||||||
|
def task_e(self, instance):
|
||||||
|
if instance.task:
|
||||||
|
return instance.task.enabled
|
||||||
|
task_e.short_description = _('Activé')
|
||||||
|
|
||||||
|
def task_d(self, instance):
|
||||||
|
if instance.task:
|
||||||
|
return instance.task.description
|
||||||
|
task_d.short_description = _('Description')
|
||||||
|
|
||||||
|
def has_add_permission(self, request, obj=None):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceTypeAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ('name', 'code',)
|
||||||
|
search_fields = ('name', 'code')
|
||||||
|
|
||||||
|
|
||||||
|
class CustomPeriodicTaskAdmin(PeriodicTaskAdmin):
|
||||||
|
list_display = ('name', 'task', 'enabled', 'description', 'scheduler', 'interval',
|
||||||
|
'start_time', 'last_run_at', 'expires', 'one_off', 'total_run_count')
|
||||||
|
search_fields = ('name', 'task')
|
||||||
|
|
||||||
|
|
||||||
|
admin.site.unregister(PeriodicTask)
|
||||||
|
admin.site.register(PeriodicTask, CustomPeriodicTaskAdmin)
|
||||||
|
admin.site.register(DeviceType, DeviceTypeAdmin)
|
||||||
|
admin.site.register(Device, DeviceAdmin)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class RelayConfig(AppConfig):
|
||||||
|
name = 'relay'
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#
|
||||||
|
#from django.utils.translation import gettext_lazy as _
|
||||||
|
#from channels.layers import get_channel_layer
|
||||||
|
#from django.conf import settings
|
||||||
|
#import asyncio
|
||||||
|
#from asgiref.sync import sync_to_async
|
||||||
|
import json, logging
|
||||||
|
from channels.generic.websocket import AsyncWebsocketConsumer
|
||||||
|
#from modules import utils
|
||||||
|
|
||||||
|
#from .models import Relay
|
||||||
|
from .process import redisDB
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class RelayConsumer(AsyncWebsocketConsumer):
|
||||||
|
|
||||||
|
async def connect(self):
|
||||||
|
self.uuid = self.scope["url_route"]["kwargs"].get("uuid")
|
||||||
|
self.this_group = f"relay_{self.uuid}"
|
||||||
|
await self.channel_layer.group_add(self.this_group, self.channel_name)
|
||||||
|
await self.accept()
|
||||||
|
#logger.info(f"==== relay {self.uuid} is connected to {self.this_group} group")
|
||||||
|
|
||||||
|
|
||||||
|
async def disconnect(self, close_code):
|
||||||
|
await self.channel_layer.group_discard(self.this_group, self.channel_name)
|
||||||
|
logger.info( f"Disconnect from {self.this_group}")
|
||||||
|
|
||||||
|
|
||||||
|
# routage channels => type: relay.message
|
||||||
|
async def relay_message(self, event):
|
||||||
|
await self.send(text_data=json.dumps(event["text"]))
|
||||||
|
|
||||||
|
|
||||||
|
## Receive message from WebSocket
|
||||||
|
async def receive(self, text_data):
|
||||||
|
data = json.loads(text_data)
|
||||||
|
msg_type = data.get("type")
|
||||||
|
if msg_type == "relay":
|
||||||
|
redisDB.publish(f"{msg_type}_{self.uuid}", json.dumps(data))
|
||||||
|
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
|
||||||
|
import json
|
||||||
|
from datetime import timedelta
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django_resized import ResizedImageField
|
||||||
|
from django_celery_beat.models import PeriodicTask
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from django.utils.text import slugify
|
||||||
|
from django.utils.safestring import mark_safe
|
||||||
|
from django.db.models.signals import post_save
|
||||||
|
from django.db import models
|
||||||
|
from modules import utils
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceType(models.Model):
|
||||||
|
name = models.CharField(_("Nom du capteur"), max_length=64, null=True)
|
||||||
|
code = models.SlugField(_("Type de capteur"), help_text=_("Max 16 caractères"), unique=True, max_length=16, null=True, blank=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['name']
|
||||||
|
verbose_name = _("Type de capteur")
|
||||||
|
verbose_name_plural = _("Types de capteurs")
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
self.code = slugify(self.code)
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.name}'
|
||||||
|
|
||||||
|
|
||||||
|
class Device(models.Model):
|
||||||
|
label = models.CharField(_("Capteur"), max_length=100, null=True)
|
||||||
|
uuid = models.SlugField(_("Uuid"), help_text=_('Uuid iot clef unique'), unique=True, max_length=32, null=True, blank=True)
|
||||||
|
device_type = models.ForeignKey(DeviceType, verbose_name=_("Type de capteur"), on_delete=models.CASCADE, null=True, blank=True, )
|
||||||
|
index = models.SmallIntegerField(_("Index"), help_text=_("Numéro d'index"), default=0)
|
||||||
|
pin_active = models.BooleanField(_("Broche"), help_text=_("Broche active à l'initialisation"), default=True)
|
||||||
|
image = ResizedImageField(_("Image"), help_text=_("Image du capteur"), size=[320, 240], upload_to='devices/', null=True, blank=True, default = 'devices/vanne.png')
|
||||||
|
|
||||||
|
task = models.ForeignKey(
|
||||||
|
PeriodicTask,
|
||||||
|
verbose_name=_("Tâche périodique"),
|
||||||
|
help_text=_("Tâche de démarrage périodique de ce capteur (optionnel)"),
|
||||||
|
on_delete=models.CASCADE, null=True, blank=False
|
||||||
|
)
|
||||||
|
lifetime = models.DurationField(_("Durée"), help_text=_("Durée de l'évènement. Jours hh:mm:ss format"), blank=True, null=True, default=timedelta(hours=1, minutes=15))
|
||||||
|
heartbeat = models.IntegerField (_("Battement"), help_text=_("Interrogation du capteur en secondes"), default=1)
|
||||||
|
active = models.BooleanField(_("Actif"), default=True)
|
||||||
|
|
||||||
|
def image_tag(self):
|
||||||
|
return mark_safe(f'<img src="{self.image.url}" style="width: 45px; height:45px;">')
|
||||||
|
image_tag.short_description = _("Image")
|
||||||
|
image_tag.allow_tags = True
|
||||||
|
|
||||||
|
|
||||||
|
def to_register(self):
|
||||||
|
return dict(
|
||||||
|
dev_type=self.device_type.code if self.device_type else 'None',
|
||||||
|
index=self.index,
|
||||||
|
key=self.uuid,
|
||||||
|
label=self.label,
|
||||||
|
status=0,
|
||||||
|
active=1 if self.pin_active else 0,
|
||||||
|
)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['index', ]
|
||||||
|
verbose_name = _("Capteur")
|
||||||
|
verbose_name_plural = _("Capteurs")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def all_devices(cls):
|
||||||
|
return Device.objects.filter(active=True).all().order_by('index')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def all_devices_json(cls):
|
||||||
|
devices = Device.objects.filter(active=True).all().order_by('index')
|
||||||
|
buf = []
|
||||||
|
for dev in devices:
|
||||||
|
buf.append({
|
||||||
|
"uuid": dev.uuid,
|
||||||
|
"index": dev.index,
|
||||||
|
})
|
||||||
|
return json.dumps(buf)
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
if not self.uuid:
|
||||||
|
self.uuid = utils.get_device_uuid(12)
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return f'{self.label}'
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=Device)
|
||||||
|
def create_device(sender, instance, created, **kwargs):
|
||||||
|
name = f'{instance.uuid}'
|
||||||
|
|
||||||
|
t = PeriodicTask.objects.filter(name__exact=name).first()
|
||||||
|
if not t:
|
||||||
|
p = PeriodicTask.objects.create(
|
||||||
|
name=name,
|
||||||
|
task='relay status',
|
||||||
|
description=_('Pas encore programmé'),
|
||||||
|
interval_id=1,
|
||||||
|
args=json.dumps([instance.uuid])
|
||||||
|
)
|
||||||
|
instance.task_id = p.id
|
||||||
|
instance.save()
|
||||||
|
else:
|
||||||
|
PeriodicTask.objects.filter(id=instance.task.id).update(
|
||||||
|
name=name,
|
||||||
|
args=json.dumps([instance.uuid])
|
||||||
|
)
|
||||||
|
instance.task.save()
|
||||||
@@ -0,0 +1,169 @@
|
|||||||
|
'''
|
||||||
|
Created on 23 janv. 2026
|
||||||
|
|
||||||
|
@author: denis
|
||||||
|
'''
|
||||||
|
# process.py
|
||||||
|
#from django.utils.translation import gettext_lazy as _
|
||||||
|
import os
|
||||||
|
os.environ['BOARD_DEVICE']="RPI"
|
||||||
|
import json
|
||||||
|
from threading import Thread, Event
|
||||||
|
from asgiref.sync import async_to_sync #, sync_to_async
|
||||||
|
from channels.layers import get_channel_layer
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import transaction
|
||||||
|
|
||||||
|
from celery import Task
|
||||||
|
from celery.exceptions import Ignore
|
||||||
|
from celery.utils.log import get_task_logger
|
||||||
|
from redis import Redis
|
||||||
|
|
||||||
|
from modules import gpiolib as gpio, devices as dev
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
logger = get_task_logger(__name__)
|
||||||
|
redisDB = Redis(host=settings.REDIS_HOST, port=settings.REDIS_PORT, db=0, decode_responses=True)
|
||||||
|
|
||||||
|
class RelayManager:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.shift_out_register = gpio.ShiftOutRegister74HC595(
|
||||||
|
latch_pin=settings.CTL_LATCH_PIN,
|
||||||
|
clock_pin=settings.CTL_CLOCK_PIN,
|
||||||
|
data_pin=settings.CTL_DATA_PIN,
|
||||||
|
number=settings.CTL_NUMBER,
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_relay(self, device, publish=None):
|
||||||
|
return dev.Relay(self.shift_out_register, device.to_register(), publish=publish)
|
||||||
|
|
||||||
|
|
||||||
|
relay_manager = RelayManager()
|
||||||
|
|
||||||
|
|
||||||
|
class RelayProcess(Task):
|
||||||
|
|
||||||
|
def __init__(self, uuid):
|
||||||
|
super().__init__()
|
||||||
|
self.channel_layer = get_channel_layer()
|
||||||
|
self.uuid = uuid
|
||||||
|
self.group = f'relay_{uuid}'
|
||||||
|
self.stop_event = Event()
|
||||||
|
self.heartbeat = 10
|
||||||
|
self.relay = None
|
||||||
|
self.device = None
|
||||||
|
|
||||||
|
def __call__(self, uuid, *args, **kwargs):
|
||||||
|
self.uuid = uuid
|
||||||
|
return self.start(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def redis_pub(self, state, **msg):
|
||||||
|
async_to_sync(self.channel_layer.group_send)(
|
||||||
|
self.group, {
|
||||||
|
"type": 'relay.message',
|
||||||
|
"text": { 'topic': state, **msg }
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.mqtt_pub(state, **msg)
|
||||||
|
|
||||||
|
|
||||||
|
def mqtt_pub(self, state, **payload):
|
||||||
|
topic = f"relay/{self.uuid}/{state}"
|
||||||
|
payload.pop("uuid", None)
|
||||||
|
redisDB.publish('mqtt_pub', json.dumps({"type": "mqtt", "topic": topic, "payload": payload}))
|
||||||
|
#logger.info(f"mqtt_pub {topic}: {payload}")
|
||||||
|
|
||||||
|
|
||||||
|
def start(self, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
with transaction.atomic():
|
||||||
|
self.device = models.Device.objects.select_for_update().get(uuid=self.uuid)
|
||||||
|
self.stop_event.clear()
|
||||||
|
self.start_services()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Relay error {self.uuid}: {e}")
|
||||||
|
raise Ignore()
|
||||||
|
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
try:
|
||||||
|
self.redis_pub('state', stop="done")
|
||||||
|
self.stop_event.set()
|
||||||
|
logger.info(f"Relay {self.uuid} stopped.")
|
||||||
|
Event().wait(1.0)
|
||||||
|
finally:
|
||||||
|
self.stop_event.set()
|
||||||
|
gpio.IO_CLEANUP()
|
||||||
|
|
||||||
|
|
||||||
|
def start_services(self):
|
||||||
|
Thread(target=self._listen_to_redis, daemon=True).start()
|
||||||
|
Thread(target=self._relay_process, daemon=True).start()
|
||||||
|
|
||||||
|
|
||||||
|
def _listen_to_redis(self):
|
||||||
|
try:
|
||||||
|
logger.info(f"RelayProcess {self.group}: listen via redisDB")
|
||||||
|
pubsub = redisDB.pubsub()
|
||||||
|
pubsub.subscribe(f"{self.group}", "relay_broadcast", "mqtt_message")
|
||||||
|
try:
|
||||||
|
for message in pubsub.listen():
|
||||||
|
#logger.info(f"{message}")
|
||||||
|
if self.stop_event.is_set():
|
||||||
|
break
|
||||||
|
|
||||||
|
cmd = json.loads(str(message.get('data')))
|
||||||
|
if not isinstance(cmd, dict):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if cmd["type"]=="relay" or cmd["type"]=="mqtt":
|
||||||
|
topic = cmd["topic"]
|
||||||
|
|
||||||
|
if topic == "start":
|
||||||
|
duration = cmd.get("value", 0)
|
||||||
|
self.relay.relay_start(duration=duration)
|
||||||
|
|
||||||
|
elif topic == "stop":
|
||||||
|
self.relay.relay_stop()
|
||||||
|
|
||||||
|
elif topic in ["status", "init"]:
|
||||||
|
self.relay.relay_status()
|
||||||
|
|
||||||
|
elif topic == "halt":
|
||||||
|
self.relay.relay_halt()
|
||||||
|
|
||||||
|
elif topic == "restart":
|
||||||
|
self.relay.relay_restart()
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f'listen_to_redis: {e}')
|
||||||
|
finally:
|
||||||
|
pubsub.unsubscribe()
|
||||||
|
pubsub.close()
|
||||||
|
|
||||||
|
|
||||||
|
def _relay_process(self):
|
||||||
|
try:
|
||||||
|
logger.info(f"RelayProcess Start {self.uuid}")
|
||||||
|
self.relay = relay_manager.create_relay(self.device, publish=self.redis_pub)
|
||||||
|
self.relay.relay_stop()
|
||||||
|
|
||||||
|
while not self.stop_event.is_set():
|
||||||
|
try:
|
||||||
|
Event().wait(self.device.heartbeat)
|
||||||
|
self.relay.relay_status()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f'====> {e}')
|
||||||
|
Event().wait(1.0)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Relay {self.uuid}: {e}")
|
||||||
|
finally:
|
||||||
|
|
||||||
|
logger.info(f"End of relay process: {self.uuid}")
|
||||||
|
self.redis_pub('state', relay="stop")
|
||||||
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#
|
||||||
|
# routing.py
|
||||||
|
from django.urls import re_path
|
||||||
|
from . import consumers
|
||||||
|
|
||||||
|
|
||||||
|
websocket_urlpatterns = [
|
||||||
|
re_path(r"ws/relay/(?P<uuid>[^/]+)/?$", consumers.RelayConsumer.as_asgi()),
|
||||||
|
|
||||||
|
]
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#relay-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(var(--grid-columns, 3), 1fr);
|
||||||
|
gap: 0.51em;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
padding: 0.5em;
|
||||||
|
align-items: stretch;
|
||||||
|
justify-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relay-box {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
min-width: 320px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.relay-meta {
|
||||||
|
width: 100%;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
padding: .5em;
|
||||||
|
}
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
|
||||||
|
|
||||||
|
class RelayOverlay {
|
||||||
|
|
||||||
|
constructor(parent, relay) {
|
||||||
|
this.parent = parent;
|
||||||
|
this.relay = relay;
|
||||||
|
this.uuid = relay.uuid;
|
||||||
|
this.sockets = parent.sockets;
|
||||||
|
|
||||||
|
this.init_controls();
|
||||||
|
}
|
||||||
|
|
||||||
|
init_controls() {
|
||||||
|
this.duration_box = sId('duration-'+this.uuid);
|
||||||
|
this.start_box = sId('start-'+this.uuid);
|
||||||
|
this.stop_box = sId('stop-'+this.uuid);
|
||||||
|
this.flow_box = sId('flow-'+this.uuid);
|
||||||
|
this.ts_box = sId('ts-'+this.uuid);
|
||||||
|
this.rate_box = sId('rate-'+this.uuid);
|
||||||
|
this.remaining_box = sId('remaining-'+this.uuid);
|
||||||
|
this.duration_value = parseInt(this.duration_box.value);
|
||||||
|
this.relay_state = 0;
|
||||||
|
this.flow = 0.00;
|
||||||
|
|
||||||
|
this.start_box.onclick = () => {
|
||||||
|
this.start();
|
||||||
|
};
|
||||||
|
this.stop_box.onclick = () => {
|
||||||
|
this.stop();
|
||||||
|
};
|
||||||
|
this.duration_box.onchange = () => {
|
||||||
|
this.duration_value = parseInt(this.duration_box.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(payload) {
|
||||||
|
if (payload.topic === "status") {
|
||||||
|
this.relay_state = payload.relay_state;
|
||||||
|
this.flow = parseFloat(payload.flow.toFixed(2));
|
||||||
|
this.rate = parseFloat(payload.rate.toFixed(2));
|
||||||
|
|
||||||
|
this.start_box.disabled = this.relay_state === 1;
|
||||||
|
this.stop_box.disabled = this.relay_state === 0;
|
||||||
|
|
||||||
|
if (payload.remaining>0) {
|
||||||
|
this.remaining_box.textContent = `${payload.remaining} s restante(s)`;
|
||||||
|
} else {
|
||||||
|
this.remaining_box.textContent = "";
|
||||||
|
}
|
||||||
|
this.ts_box.textContent = new Date(payload.ts * 1000).toLocaleTimeString();
|
||||||
|
this.duration_box.value = this.duration_value;
|
||||||
|
this.flow_box.textContent = this.flow;
|
||||||
|
this.rate_box.textContent = this.rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start() { this._send({ type: 'relay', topic: "start", value: this.duration_value }); }
|
||||||
|
stop() { this._send({ type: 'relay', topic: "stop" }); }
|
||||||
|
status() { this._send({ type: 'relay', topic: "status" }); }
|
||||||
|
halt() { this._send({ type: 'relay', topic: "halt" }); }
|
||||||
|
restart() { this._send({ type: 'relay', topic: "restart" }); }
|
||||||
|
_send(message) { this.sockets[this.uuid].send(message); }
|
||||||
|
}
|
||||||
|
|
||||||
|
class RelayManager {
|
||||||
|
constructor(container, relay) {
|
||||||
|
this.container = container;
|
||||||
|
this.relay = relay;
|
||||||
|
this.overlays = {};
|
||||||
|
this.sockets = {};
|
||||||
|
this.init_controls();
|
||||||
|
}
|
||||||
|
|
||||||
|
init_controls() {
|
||||||
|
this.all_relay_state = 0;
|
||||||
|
this.startall_box = sId('start-all');
|
||||||
|
this.stopall_box = sId('stop-all');
|
||||||
|
this.flow_box = sId('flow-all');
|
||||||
|
|
||||||
|
this.startall_box.onclick = () => {
|
||||||
|
this.all_relay_state = 1;
|
||||||
|
this._broadcast({ type: 'relay-multi', action: "start" });
|
||||||
|
};
|
||||||
|
this.stopall_box.onclick = () => {
|
||||||
|
this.all_relay_state = 0;
|
||||||
|
this._broadcast({ type: 'relay-multi', action: "stop" });
|
||||||
|
};
|
||||||
|
this.update_button();
|
||||||
|
}
|
||||||
|
|
||||||
|
async start() {
|
||||||
|
for (const relay of this.relay) {
|
||||||
|
const overlay = new RelayOverlay(this, relay);
|
||||||
|
this.overlays[relay.uuid] = overlay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerSocket(uuid, socket) {
|
||||||
|
this.sockets[uuid] = socket;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_button() {
|
||||||
|
this.startall_box.disabled = this.all_relay_state === 1;
|
||||||
|
this.stopall_box.disabled = this.all_relay_state === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
flow_update() {
|
||||||
|
let total_flow = 0.00;
|
||||||
|
for (const relay of this.relay) {
|
||||||
|
const overlay = this.overlays[relay.uuid];
|
||||||
|
if (overlay) {
|
||||||
|
total_flow = total_flow + overlay.flow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.flow_box.textContent = total_flow.toFixed(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
update(uuid, payload) {
|
||||||
|
const overlay = this.overlays[uuid];
|
||||||
|
if (overlay) {
|
||||||
|
overlay.update(payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_broadcast(message) {
|
||||||
|
if (message.type === 'relay-multi') {
|
||||||
|
const action = message.action;
|
||||||
|
this.update_button();
|
||||||
|
for (const relay of this.relay) {
|
||||||
|
const overlay = this.overlays[relay.uuid];
|
||||||
|
overlay[action]();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MetadataSocket {
|
||||||
|
constructor(url, uuid) {
|
||||||
|
this.url = url;
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.ws = null;
|
||||||
|
this.manager = null;
|
||||||
|
this.reconnectDelay = 1000;
|
||||||
|
this.shouldReconnect = true;
|
||||||
|
this.reconnect = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setOverlayManager(manager) {
|
||||||
|
this.manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
connect() {
|
||||||
|
this.ws = new WebSocket(this.url);
|
||||||
|
|
||||||
|
this.ws.onmessage = (event) => {
|
||||||
|
const data = JSON.parse(event.data);
|
||||||
|
this.manager.update(this.uuid, data);
|
||||||
|
this.manager.flow_update();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onopen = (event) => {
|
||||||
|
const overlay = this.manager.overlays[this.uuid];
|
||||||
|
if (overlay && !this.reconnect)
|
||||||
|
overlay['status']();
|
||||||
|
this.reconnect = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.ws.onclose = () => {
|
||||||
|
console.warn(`WebSocket closed ${this.uuid}`);
|
||||||
|
if (this.shouldReconnect) {
|
||||||
|
this.reconnect = true;
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log("Reconnect WebSocket...");
|
||||||
|
this.connect();
|
||||||
|
}, this.reconnectDelay);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
send(obj) {
|
||||||
|
if (this.ws?.readyState === WebSocket.OPEN) {
|
||||||
|
this.ws.send(JSON.stringify(obj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
const cpu_used = sId('cpu-used');
|
||||||
|
const shm_used = sId('shm-used');
|
||||||
|
const mem_used = sId('mem-used');
|
||||||
|
const disk_used = sId('disk-used');
|
||||||
|
const ramdisk_used = sId('ramdisk-used');
|
||||||
|
|
||||||
|
let autoTimer = null;
|
||||||
|
|
||||||
|
async function fetchStats() {
|
||||||
|
try {
|
||||||
|
const r = await fetch(stats_endpoint, { credentials: 'same-origin' });
|
||||||
|
if (!r.ok) throw new Error('HTTP ' + r.status);
|
||||||
|
const j = await r.json();
|
||||||
|
//console.log(j);
|
||||||
|
const cpu_percent = j.cpu_info.cpu_percent+'%'; cpu_used.style.setProperty("--cpu-used", cpu_percent); cpu_used.title=`Cpu: ${cpu_percent}`;
|
||||||
|
const shm_length = j.shm.length; shm_used.style.setProperty("--shm_used", shm_length); shm_used.title= `Shm: ${shm_length}`;
|
||||||
|
const virtual_memory = j.memory_info.virtual_memory.percent+'%'; mem_used.style.setProperty("--mem-used", virtual_memory); mem_used.title=`Mem: ${virtual_memory}`;
|
||||||
|
const root_percent = j.disk_info.root.percent+'%'; disk_used.style.setProperty("--disk-used", root_percent); disk_used.title=`Disk: ${root_percent}`;
|
||||||
|
let ramdisk_percent = "0%";
|
||||||
|
if (! j.ramdisk_info) ramdisk_percent = j.ramdisk_info.percent+'%';
|
||||||
|
ramdisk_used.style.setProperty("--ramdisk-used", ramdisk_percent); ramdisk_used.title=`Ramdisk: ${ramdisk_percent}`;
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Error: ' + e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function auto_fetch_start() { fetchStats(); autoTimer = setInterval(fetchStats, 5000);}
|
||||||
|
function auto_fetch_stop() { clearInterval(autoTimer); autoTimer = null; }
|
||||||
|
|
||||||
|
auto_fetch_start();
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
# tasks.py
|
||||||
|
|
||||||
|
from celery import shared_task
|
||||||
|
from celery.utils.log import get_task_logger
|
||||||
|
from .process import RelayProcess
|
||||||
|
from .models import Device
|
||||||
|
|
||||||
|
logger = get_task_logger(__name__)
|
||||||
|
|
||||||
|
class RelayTaskManager:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.active_relay = {}
|
||||||
|
|
||||||
|
def start_relay(self, uuid):
|
||||||
|
if uuid not in self.active_relay:
|
||||||
|
relay = RelayProcess(uuid)
|
||||||
|
relay.start()
|
||||||
|
self.active_relay[uuid] = relay
|
||||||
|
else:
|
||||||
|
logger.info(f"Relay {uuid} already running!...")
|
||||||
|
|
||||||
|
def stop_relay(self, uuid):
|
||||||
|
if uuid in self.active_relay:
|
||||||
|
self.active_relay[uuid].stop()
|
||||||
|
del self.active_relay[uuid]
|
||||||
|
|
||||||
|
def stop_all_relay(self):
|
||||||
|
for _, relay in self.active_relay.items():
|
||||||
|
relay.stop()
|
||||||
|
self.active_relay.clear()
|
||||||
|
|
||||||
|
def start_all_relay(self):
|
||||||
|
all_relays = Device.all_devices()
|
||||||
|
for relay in all_relays:
|
||||||
|
self.start_relay(relay.uuid)
|
||||||
|
|
||||||
|
|
||||||
|
task_manager = RelayTaskManager()
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task(bind=True)
|
||||||
|
def relay_start(self, uuid):
|
||||||
|
task_manager.start_relay(uuid)
|
||||||
|
return f"Relai {uuid} démarré."
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task(bind=True)
|
||||||
|
def relay_stop(self, uuid):
|
||||||
|
task_manager.stop_relay(uuid)
|
||||||
|
return f"Relai {uuid} arrêté."
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task(bind=True)
|
||||||
|
def relay_stop_all(self):
|
||||||
|
task_manager.stop_all_relay()
|
||||||
|
return "Touts les Relais arrêtées."
|
||||||
|
|
||||||
|
|
||||||
|
@shared_task(bind=True)
|
||||||
|
def relay_start_all(self):
|
||||||
|
task_manager.start_all_relay()
|
||||||
|
return "Touts les Relais en cours de démarrage."
|
||||||
|
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
{% load i18n home_tags %}
|
||||||
|
{% block header %}
|
||||||
|
<div class="w3-bar w3-dark-light">
|
||||||
|
<a href="#" class="w3-bar-item w3-mobile w3-btn w3-hover-opacity w3-xlarge w3-text-yellow" onclick="toggleSidebar()" title="{% trans 'Barre de côté' %}">
|
||||||
|
<i class="fa-solid fa-right-left"></i>
|
||||||
|
</a>
|
||||||
|
<a href="#" class="w3-bar-item w3-mobile w3-btn w3-hover-opacity w3-right w3-xlarge w3-text-green" onclick="goFullscreen()" title="{% trans 'Ecran plein' %}">
|
||||||
|
<i class="fa-solid fa-maximize"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block sidebar %}
|
||||||
|
<div class="w3-dark-xlight w3-border-bottom">
|
||||||
|
<div class="w3-large w3-bold"><a href="/" class="w3-btn w3-hover-opacity w100 w3-left-align">{{ app_title }}</a></div>
|
||||||
|
<div class="w3-padding">
|
||||||
|
<span class="w3-padding">{{ request.user.username }}</span>
|
||||||
|
<form method="post" action="{% url 'logout' %}" class="w3-right">
|
||||||
|
{% csrf_token %}
|
||||||
|
<button class="w3-bar-item w3-btn w3-hover-opacity" type="submit" title="{% trans 'Déconnexion' %}">
|
||||||
|
<i class="fa-solid fa-right-from-bracket"></i>
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% block system %}
|
||||||
|
<div class="w3-light-blue w3-padding-large">
|
||||||
|
<div id="shm-used" class="w3-green w3-round" style="height:0.5em; width: var(--shm-used, 0%);" title="{% trans 'Mémoire partagée' %}"></div>
|
||||||
|
<div id="ramdisk-used" class="w3-purple w3-round" style="height:0.5em;width: var(--ramdisk-used, 0%); margin: 0.35em 0" title="{% trans 'Disque RAM' %}"></div>
|
||||||
|
<div id="mem-used" class="w3-deep-orange w3-round" style="height:0.5em;width: var(--mem-used, 0%); margin: 0.35em 0" title="{% trans 'Mémoire RAM' %}"></div>
|
||||||
|
<div id="cpu-used" class="w3-indigo w3-round" style="height:0.5em;width: var(--cpu-used, 0%); margin: 0.35em 0" title="{% trans 'Charge CPU' %}"></div>
|
||||||
|
<div id="disk-used" class="w3-amber w3-round" style="height:0.5em;width: var(--disk-used, 0%); margin: 0.35em 0" title="{% trans 'Disque /' %}"></div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block columns %}
|
||||||
|
<div class="w3-dark-light">
|
||||||
|
<div class=" w3-padding w3-border-bottom">
|
||||||
|
<span>{% trans "Grille" %}</span><br>
|
||||||
|
<span>
|
||||||
|
{% x_range 2 6 as cols %}
|
||||||
|
{% for c in cols %}
|
||||||
|
<button id="swap-{{ c }}" class="w3-btn w3-badge w3-padding-small w3-sand w3-tiny" onclick="setGridColumns({{ c }})">{{ c }}</button>
|
||||||
|
{% endfor %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
function updateActiveButton(n) {
|
||||||
|
document.querySelectorAll('[id^="swap-"]').forEach(btn => {
|
||||||
|
btn.classList.remove('w3-blue', 'w3-sand'); btn.classList.add('w3-sand');
|
||||||
|
});
|
||||||
|
const active = sId('swap-'+ n);
|
||||||
|
if (active) { active.classList.remove('w3-sand'); active.classList.add('w3-blue');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
{% block sidebar_list %}
|
||||||
|
<div class="w3-dark-light w3-padding-small">
|
||||||
|
<a href="{% url 'relay:dashboard' %}" class="w3-bar-item w3-btn w3-hover-opacity">
|
||||||
|
<i class="fa-solid fa-table-cells w3-text-green"></i> {% trans "Tableau de bord" %}
|
||||||
|
</a>
|
||||||
|
{% block sidebar_command %}{% endblock %}
|
||||||
|
|
||||||
|
<a href="{% url 'relay:admin' %}" class="w3-bar-item w3-btn w3-hover-opacity w3-margin-top-6">
|
||||||
|
<i class="fa-solid fa-gear w3-text-pink"></i> {% trans "Administration base de données" %}
|
||||||
|
</a>
|
||||||
|
<a href="{% url 'relay:supervisor' %}" class="w3-bar-item w3-btn w3-hover-opacity">
|
||||||
|
<i class="fa-solid fa-gears w3-text-purple"></i> {% trans "Supervisor" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}{% endblock %}
|
||||||
|
|
||||||
|
{% block js_footer %}
|
||||||
|
{{ block.super }}
|
||||||
|
<script>
|
||||||
|
const stats_endpoint = "{% url 'relay:api_stats' %}";
|
||||||
|
</script>
|
||||||
|
<script src="/static/relay/js/stats.js"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
{% extends 'relay/base.html' %}
|
||||||
|
{% load i18n home_tags %}
|
||||||
|
|
||||||
|
{% block styles %}
|
||||||
|
{{ block.super }}
|
||||||
|
<link href="/static/relay/css/relay.css" rel="stylesheet">
|
||||||
|
{% endblock %}
|
||||||
|
{% block sidebar_command %}
|
||||||
|
<div class="w3-row w3-border w3-margin-top">
|
||||||
|
<div class="w3-third w3-center">
|
||||||
|
<button id="start-all" class="w3-btn w3-blue w3-round w3-margin-2 w3-hover-opacity w3-block" title="{% trans "Tout démarrer" %}">
|
||||||
|
{% trans "Marche" %}
|
||||||
|
</button>
|
||||||
|
<button id="stop-all" class="w3-btn w3-pink w3-round w3-margin-2 w3-hover-opacity w3-block w3-margin-top" title="{% trans "Tout arrêter" %}">
|
||||||
|
{% trans "Arrêt" %}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="w3-twothird">
|
||||||
|
<div class="w3-center">{% trans "Débit total" %}</div>
|
||||||
|
<div class="w3-dark-xlight w3-border w3-padding w3-margin w3-right-align">
|
||||||
|
<div id="flow-all" class="w3-wide w3-bold">0.00</div><div>litres</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<div id="relay-grid" class="w3-black">
|
||||||
|
{% for dev in devices %}
|
||||||
|
<div id="box-{{ dev.uuid }}" class="relay-box w3-border w3-round w3-round-large">
|
||||||
|
<div class="w3-row-padding">
|
||||||
|
<div class="w3-col s4 w3-center">
|
||||||
|
<div class="w3-padding-small">{{ dev.label }}</div>
|
||||||
|
<img src="{{ dev.image.url }}" class="w3-circle" style="width:64px;">
|
||||||
|
<select id="duration-{{ dev.uuid }}">
|
||||||
|
<option value="0" selected>{% trans 'Sans délai' %}</option>
|
||||||
|
<option value="30">30 s</option>
|
||||||
|
<option value="60">1 mn</option>
|
||||||
|
<option value="120">2 mn</option>
|
||||||
|
<option value="300">5 mn</option>
|
||||||
|
<option value="600">10 mn</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="w3-col s3">
|
||||||
|
<div id="ts-{{ dev.uuid }}" class="w3-small w3-padding-small"></div>
|
||||||
|
<button id="start-{{ dev.uuid }}" class="w3-btn w3-blue w3-round w3-margin-2 w3-hover-opacity w3-block w3-padding-small">
|
||||||
|
{% trans "Marche" %}
|
||||||
|
</button>
|
||||||
|
<button id="stop-{{ dev.uuid }}" class="w3-btn w3-pink w3-round w3-margin-2 w3-hover-opacity w3-block w3-padding-small">
|
||||||
|
{% trans "Arrêt" %}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="w3-col s5">
|
||||||
|
<div class="w3-padding-small">{% trans "Débit" %}: <span id="rate-{{ dev.uuid }}" class="w3-small"></span> l/mn</div>
|
||||||
|
<div class="w3-dark-xlight w3-border w3-padding w3-right-align w100">
|
||||||
|
<div id="flow-{{ dev.uuid }}" class="w3-wide w3-bold"></div><div>litres</div>
|
||||||
|
</div>
|
||||||
|
<div id="remaining-{{ dev.uuid }}" class="w3-small"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js_footer %}
|
||||||
|
{{ block.super }}
|
||||||
|
<script src="/static/relay/js/relay.js"></script>
|
||||||
|
<script>
|
||||||
|
const container = sId("relay-grid");
|
||||||
|
const ws_route = "{{ ws_route }}";
|
||||||
|
const columns = "{{ columns }}";
|
||||||
|
const devices = {{ relay|safe }};
|
||||||
|
|
||||||
|
function setGridColumns(col) {
|
||||||
|
container.style.setProperty("--grid-columns", col);
|
||||||
|
updateActiveButton(col);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Point d'entrée ----
|
||||||
|
(async () => {
|
||||||
|
const manager = new RelayManager(container, devices);
|
||||||
|
await manager.start();
|
||||||
|
|
||||||
|
const protocol = location.protocol === "https:" ? "wss" : "ws";
|
||||||
|
for (const uuid in manager.overlays) {
|
||||||
|
const wsUrl = `${protocol}://${location.host}/${ws_route}/${uuid}`;
|
||||||
|
|
||||||
|
const socket = new MetadataSocket(wsUrl, uuid);
|
||||||
|
socket.setOverlayManager(manager);
|
||||||
|
socket.connect();
|
||||||
|
manager.registerSocket(uuid, socket);
|
||||||
|
}
|
||||||
|
setGridColumns(columns);
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{% extends 'relay/base.html' %}
|
||||||
|
{% block columns %}{% endblock %}
|
||||||
|
{% block content %}
|
||||||
|
<iframe width="100%" src="{{ link }}" style="border:none; height:90vh;display:block;"></iframe>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
# Create your tests here.
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
from django.urls import path
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
app_name = "relay"
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
|
||||||
|
path('dashboard/', views.dashboard_view, name='dashboard'),
|
||||||
|
path('relay/admin/', views.admin_view, name='admin'),
|
||||||
|
path('relay/supervisor/', views.supervisor_view, name='supervisor'),
|
||||||
|
path('api/stats/', views.stats_view, name='api_stats'),
|
||||||
|
|
||||||
|
]
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
from django.shortcuts import render
|
||||||
|
from django.http import JsonResponse
|
||||||
|
from django.views.decorators.http import require_GET
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.conf import settings
|
||||||
|
from modules.system_stats import get_cached_stats, start_background_updater
|
||||||
|
|
||||||
|
from . import models
|
||||||
|
|
||||||
|
start_background_updater()
|
||||||
|
|
||||||
|
|
||||||
|
@require_GET
|
||||||
|
def stats_view(request):
|
||||||
|
"""
|
||||||
|
Retourne tout le cache (shm, cpu_info, memory_info, disk_info, updated_at)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
data = get_cached_stats()
|
||||||
|
return JsonResponse(data, safe=False)
|
||||||
|
except Exception as e:
|
||||||
|
return JsonResponse({"error": str(e)}, status=500)
|
||||||
|
|
||||||
|
|
||||||
|
def global_context(request, **ctx):
|
||||||
|
return dict(
|
||||||
|
app_title=settings.APP_TITLE,
|
||||||
|
app_sub_title=settings.APP_SUB_TITLE,
|
||||||
|
**ctx
|
||||||
|
)
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def dashboard_view(request):
|
||||||
|
ctx = dict(
|
||||||
|
devices=models.Device.all_devices(),
|
||||||
|
relay=models.Device.all_devices_json(),
|
||||||
|
ws_route=settings.RELAY_WEBSOCKET_ROUTE,
|
||||||
|
columns=3,
|
||||||
|
|
||||||
|
)
|
||||||
|
return render(request, "relay/dashboard.html", context=global_context(request, **ctx))
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def admin_view(request):
|
||||||
|
return render(request, "relay/iframe.html", context=global_context(request, link='/admin/'))
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def supervisor_view(request):
|
||||||
|
return render(request, "relay/iframe.html", context=global_context(request, link='http://relay.local:9001/'))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
cd /home/rpi4/workspace/django-relay-controller/relaycontroller
|
||||||
|
./manage.py runserver --insecure 0.0.0.0:8020
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{% extends "admin/base.html" %}
|
||||||
|
|
||||||
|
{% block title %}
|
||||||
|
{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block branding %}
|
||||||
|
<div id="site-name">
|
||||||
|
<a href="{% url 'admin:index' %}">
|
||||||
|
{{ site_header|default:_('Django administration') }}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% if user.is_anonymous %}
|
||||||
|
{% include "admin/color_theme_toggle.html" %}
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block nav-global %}{% endblock %}
|
||||||
|
|
||||||
|
{% block usertools %}{% endblock %}
|
||||||