Port code from Github to Pagure
27
.coveragerc
Executable file
|
|
@ -0,0 +1,27 @@
|
|||
# .coveragerc to control coverage.py
|
||||
[run]
|
||||
include = happinesspackets/*
|
||||
|
||||
[report]
|
||||
exclude_lines =
|
||||
pragma: no cover
|
||||
|
||||
# Don't complain about missing debug-only code:
|
||||
def __unicode__
|
||||
def __repr__
|
||||
if self\.debug
|
||||
|
||||
# Don't complain if tests don't hit defensive assertion code:
|
||||
raise AssertionError
|
||||
raise NotImplementedError
|
||||
|
||||
# Don't complain if non-runnable code isn't run:
|
||||
if 0:
|
||||
if __name__ == .__main__.:
|
||||
|
||||
omit =
|
||||
happinesspackets/settings/*
|
||||
happinesspackets/*/migrations/*
|
||||
happinesspackets/urls.py
|
||||
|
||||
show_missing = True
|
||||
21
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# automatically created files:
|
||||
.DS_Store
|
||||
|
||||
virtualenv/
|
||||
.idea/workspace.xml
|
||||
|
||||
# other
|
||||
static
|
||||
build
|
||||
.idea
|
||||
_build
|
||||
.coverage
|
||||
htmlcov
|
||||
celery.pid
|
||||
selenium-screenshots/
|
||||
|
||||
syntax: glob
|
||||
/media
|
||||
*.pyc
|
||||
*.swp
|
||||
*.sqlite3
|
||||
202
LICENSE
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2016, Erik Romijn & Mikey Ariel
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
41
README.rst
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
Open-source Happiness Packets
|
||||
=============================
|
||||
|
||||
The Open-Source Happiness Packets project was created by `Sasha
|
||||
Romijn <https://twitter.com/mxsash>`__ and `Mikey
|
||||
Ariel <https://twitter.com/thatdocslady>`__ in March 2016. The idea came
|
||||
about while we were building our `Healthy Minds in a Healthy
|
||||
Community <https://github.com/erikr/well-being/>`__ presentation for
|
||||
`Djangocon Europe 2016 <https://2016.djangocon.eu/speakers/13>`__. One
|
||||
of the issues we wanted to address in the presentation was that many
|
||||
people are unaware of how loved, appreciated, or admired they are by
|
||||
their peers, since our culture seems to discourage positive feedback and
|
||||
amplify negative feedback. With this project, we wanted to provide a
|
||||
platform for people to send positive feedback, thanks, or just a kind
|
||||
word to their peers, with hope to make it easier and more acceptable for
|
||||
people to spread happiness, gratitude and appreciation in open-source
|
||||
communities.
|
||||
|
||||
The structure and format of the site is basic, and contributions are
|
||||
welcome!
|
||||
|
||||
To run this project or the tests, you need to set up a virtualenv, install the dev requirements and set
|
||||
the correct ``DJANGO_SETTINGS_MODULE``, for example with::
|
||||
|
||||
virtualenv --no-site-packages --prompt='(happinesspackets)' virtualenv/
|
||||
source virtualenv/bin/activate
|
||||
pip install -r requirements/dev.txt
|
||||
export DJANGO_SETTINGS_MODULE=happinesspackets.settings.dev
|
||||
./t
|
||||
|
||||
The ``t`` command is a very short shell script that runs the tests with the correct settings and reports on coverage.
|
||||
|
||||
To run the integration tests::
|
||||
|
||||
./manage.py test -v 2 -p integration_test*.py --settings=happinesspackets.settings.tsting
|
||||
|
||||
This repository contains some documentation directly related to the code, built with Sphinx. To build the docs::
|
||||
|
||||
cd docs
|
||||
make html
|
||||
open _build/html/index.html
|
||||
BIN
artwork/envelope-square.png
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
1745
artwork/envelope.ai
Normal file
2094
artwork/happiness-circle-inverted.pdf
Normal file
2094
artwork/happiness-circle.pdf
Normal file
2153
artwork/happiness-square-inverted.pdf
Normal file
2048
artwork/happiness-square.pdf
Normal file
BIN
artwork/logo-square-invert.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
artwork/logo-square.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
artwork/logo-white.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
1888
artwork/logo.ai
Normal file
BIN
artwork/logo.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
347
assets/bootstrap/css/bootstrap-theme.css
vendored
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
/*!
|
||||
* Bootstrap v3.1.1 (http://getbootstrap.com)
|
||||
* Copyright 2011-2014 Twitter, Inc.
|
||||
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
||||
*/
|
||||
|
||||
.btn-default,
|
||||
.btn-primary,
|
||||
.btn-success,
|
||||
.btn-info,
|
||||
.btn-warning,
|
||||
.btn-danger {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, .2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.btn-default:active,
|
||||
.btn-primary:active,
|
||||
.btn-success:active,
|
||||
.btn-info:active,
|
||||
.btn-warning:active,
|
||||
.btn-danger:active,
|
||||
.btn-default.active,
|
||||
.btn-primary.active,
|
||||
.btn-success.active,
|
||||
.btn-info.active,
|
||||
.btn-warning.active,
|
||||
.btn-danger.active {
|
||||
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
|
||||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125);
|
||||
}
|
||||
.btn:active,
|
||||
.btn.active {
|
||||
background-image: none;
|
||||
}
|
||||
.btn-default {
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
|
||||
background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dbdbdb;
|
||||
border-color: #ccc;
|
||||
}
|
||||
.btn-default:hover,
|
||||
.btn-default:focus {
|
||||
background-color: #e0e0e0;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-default:active,
|
||||
.btn-default.active {
|
||||
background-color: #e0e0e0;
|
||||
border-color: #dbdbdb;
|
||||
}
|
||||
.btn-primary {
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #2d6ca2 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #2d6ca2 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff2d6ca2', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #2b669a;
|
||||
}
|
||||
.btn-primary:hover,
|
||||
.btn-primary:focus {
|
||||
background-color: #2d6ca2;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-primary:active,
|
||||
.btn-primary.active {
|
||||
background-color: #2d6ca2;
|
||||
border-color: #2b669a;
|
||||
}
|
||||
.btn-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #3e8f3e;
|
||||
}
|
||||
.btn-success:hover,
|
||||
.btn-success:focus {
|
||||
background-color: #419641;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-success:active,
|
||||
.btn-success.active {
|
||||
background-color: #419641;
|
||||
border-color: #3e8f3e;
|
||||
}
|
||||
.btn-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #28a4c9;
|
||||
}
|
||||
.btn-info:hover,
|
||||
.btn-info:focus {
|
||||
background-color: #2aabd2;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-info:active,
|
||||
.btn-info.active {
|
||||
background-color: #2aabd2;
|
||||
border-color: #28a4c9;
|
||||
}
|
||||
.btn-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #e38d13;
|
||||
}
|
||||
.btn-warning:hover,
|
||||
.btn-warning:focus {
|
||||
background-color: #eb9316;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-warning:active,
|
||||
.btn-warning.active {
|
||||
background-color: #eb9316;
|
||||
border-color: #e38d13;
|
||||
}
|
||||
.btn-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #b92c28;
|
||||
}
|
||||
.btn-danger:hover,
|
||||
.btn-danger:focus {
|
||||
background-color: #c12e2a;
|
||||
background-position: 0 -15px;
|
||||
}
|
||||
.btn-danger:active,
|
||||
.btn-danger.active {
|
||||
background-color: #c12e2a;
|
||||
border-color: #b92c28;
|
||||
}
|
||||
.thumbnail,
|
||||
.img-thumbnail {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.dropdown-menu > li > a:hover,
|
||||
.dropdown-menu > li > a:focus {
|
||||
background-color: #e8e8e8;
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.dropdown-menu > .active > a,
|
||||
.dropdown-menu > .active > a:hover,
|
||||
.dropdown-menu > .active > a:focus {
|
||||
background-color: #357ebd;
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.navbar-default {
|
||||
background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%);
|
||||
background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.navbar-default .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f3f3f3 100%);
|
||||
background-image: linear-gradient(to bottom, #ebebeb 0%, #f3f3f3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff3f3f3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.navbar-brand,
|
||||
.navbar-nav > li > a {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, .25);
|
||||
}
|
||||
.navbar-inverse {
|
||||
background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
|
||||
background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.navbar-inverse .navbar-nav > .active > a {
|
||||
background-image: -webkit-linear-gradient(top, #222 0%, #282828 100%);
|
||||
background-image: linear-gradient(to bottom, #222 0%, #282828 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff282828', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
-webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
|
||||
box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25);
|
||||
}
|
||||
.navbar-inverse .navbar-brand,
|
||||
.navbar-inverse .navbar-nav > li > a {
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, .25);
|
||||
}
|
||||
.navbar-static-top,
|
||||
.navbar-fixed-top,
|
||||
.navbar-fixed-bottom {
|
||||
border-radius: 0;
|
||||
}
|
||||
.alert {
|
||||
text-shadow: 0 1px 0 rgba(255, 255, 255, .2);
|
||||
-webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05);
|
||||
}
|
||||
.alert-success {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #b2dba1;
|
||||
}
|
||||
.alert-info {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #9acfea;
|
||||
}
|
||||
.alert-warning {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #f5e79e;
|
||||
}
|
||||
.alert-danger {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dca7a7;
|
||||
}
|
||||
.progress {
|
||||
background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
|
||||
background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar {
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #3071a9 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-success {
|
||||
background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
|
||||
background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-info {
|
||||
background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
|
||||
background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-warning {
|
||||
background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
|
||||
background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.progress-bar-danger {
|
||||
background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
|
||||
background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.list-group {
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .075);
|
||||
}
|
||||
.list-group-item.active,
|
||||
.list-group-item.active:hover,
|
||||
.list-group-item.active:focus {
|
||||
text-shadow: 0 -1px 0 #3071a9;
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #3278b3 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #3278b3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3278b3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #3278b3;
|
||||
}
|
||||
.panel {
|
||||
-webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .05);
|
||||
}
|
||||
.panel-default > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
|
||||
background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-primary > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #428bca 0%, #357ebd 100%);
|
||||
background-image: linear-gradient(to bottom, #428bca 0%, #357ebd 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff357ebd', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-success > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
|
||||
background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-info > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
|
||||
background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-warning > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
|
||||
background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.panel-danger > .panel-heading {
|
||||
background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
|
||||
background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
.well {
|
||||
background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
|
||||
background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #dcdcdc;
|
||||
-webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
|
||||
box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1);
|
||||
}
|
||||
/*# sourceMappingURL=bootstrap-theme.css.map */
|
||||
1
assets/bootstrap/css/bootstrap-theme.css.map
Normal file
7
assets/bootstrap/css/bootstrap-theme.min.css
vendored
Normal file
5785
assets/bootstrap/css/bootstrap.css
vendored
Normal file
1
assets/bootstrap/css/bootstrap.css.map
Normal file
7
assets/bootstrap/css/bootstrap.min.css
vendored
Normal file
BIN
assets/bootstrap/fonts/glyphicons-halflings-regular.eot
Normal file
229
assets/bootstrap/fonts/glyphicons-halflings-regular.svg
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
<?xml version="1.0" standalone="no"?>
|
||||
<!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">
|
||||
<metadata></metadata>
|
||||
<defs>
|
||||
<font id="glyphicons_halflingsregular" horiz-adv-x="1200" >
|
||||
<font-face units-per-em="1200" ascent="960" descent="-240" />
|
||||
<missing-glyph horiz-adv-x="500" />
|
||||
<glyph />
|
||||
<glyph />
|
||||
<glyph unicode="
" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode="*" d="M100 500v200h259l-183 183l141 141l183 -183v259h200v-259l183 183l141 -141l-183 -183h259v-200h-259l183 -183l-141 -141l-183 183v-259h-200v259l-183 -183l-141 141l183 183h-259z" />
|
||||
<glyph unicode="+" d="M0 400v300h400v400h300v-400h400v-300h-400v-400h-300v400h-400z" />
|
||||
<glyph unicode=" " />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="652" />
|
||||
<glyph unicode=" " horiz-adv-x="1304" />
|
||||
<glyph unicode=" " horiz-adv-x="434" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="217" />
|
||||
<glyph unicode=" " horiz-adv-x="163" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="72" />
|
||||
<glyph unicode=" " horiz-adv-x="260" />
|
||||
<glyph unicode=" " horiz-adv-x="326" />
|
||||
<glyph unicode="€" d="M100 500l100 100h113q0 47 5 100h-218l100 100h135q37 167 112 257q117 141 297 141q242 0 354 -189q60 -103 66 -209h-181q0 55 -25.5 99t-63.5 68t-75 36.5t-67 12.5q-24 0 -52.5 -10t-62.5 -32t-65.5 -67t-50.5 -107h379l-100 -100h-300q-6 -46 -6 -100h406l-100 -100 h-300q9 -74 33 -132t52.5 -91t62 -54.5t59 -29t46.5 -7.5q29 0 66 13t75 37t63.5 67.5t25.5 96.5h174q-31 -172 -128 -278q-107 -117 -274 -117q-205 0 -324 158q-36 46 -69 131.5t-45 205.5h-217z" />
|
||||
<glyph unicode="−" d="M200 400h900v300h-900v-300z" />
|
||||
<glyph unicode="◼" horiz-adv-x="500" d="M0 0z" />
|
||||
<glyph unicode="☁" d="M-14 494q0 -80 56.5 -137t135.5 -57h750q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5z" />
|
||||
<glyph unicode="✉" d="M0 100l400 400l200 -200l200 200l400 -400h-1200zM0 300v600l300 -300zM0 1100l600 -603l600 603h-1200zM900 600l300 300v-600z" />
|
||||
<glyph unicode="✏" d="M-13 -13l333 112l-223 223zM187 403l214 -214l614 614l-214 214zM887 1103l214 -214l99 92q13 13 13 32.5t-13 33.5l-153 153q-15 13 -33 13t-33 -13z" />
|
||||
<glyph unicode="" d="M0 1200h1200l-500 -550v-550h300v-100h-800v100h300v550z" />
|
||||
<glyph unicode="" d="M14 84q18 -55 86 -75.5t147 5.5q65 21 109 69t44 90v606l600 155v-521q-64 16 -138 -7q-79 -26 -122.5 -83t-25.5 -111q18 -55 86 -75.5t147 4.5q70 23 111.5 63.5t41.5 95.5v881q0 10 -7 15.5t-17 2.5l-752 -193q-10 -3 -17 -12.5t-7 -19.5v-689q-64 17 -138 -7 q-79 -25 -122.5 -82t-25.5 -112z" />
|
||||
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233z" />
|
||||
<glyph unicode="" d="M100 784q0 64 28 123t73 100.5t104.5 64t119 20.5t120 -38.5t104.5 -104.5q48 69 109.5 105t121.5 38t118.5 -20.5t102.5 -64t71 -100.5t27 -123q0 -57 -33.5 -117.5t-94 -124.5t-126.5 -127.5t-150 -152.5t-146 -174q-62 85 -145.5 174t-149.5 152.5t-126.5 127.5 t-94 124.5t-33.5 117.5z" />
|
||||
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1z" />
|
||||
<glyph unicode="" d="M-72 800h479l146 400h2l146 -400h472l-382 -278l145 -449l-384 275l-382 -275l146 447zM168 71l2 1zM237 700l196 -142l-73 -226l192 140l195 -141l-74 229l193 140h-235l-77 211l-78 -211h-239z" />
|
||||
<glyph unicode="" d="M0 0v143l400 257v100q-37 0 -68.5 74.5t-31.5 125.5v200q0 124 88 212t212 88t212 -88t88 -212v-200q0 -51 -31.5 -125.5t-68.5 -74.5v-100l400 -257v-143h-1200z" />
|
||||
<glyph unicode="" d="M0 0v1100h1200v-1100h-1200zM100 100h100v100h-100v-100zM100 300h100v100h-100v-100zM100 500h100v100h-100v-100zM100 700h100v100h-100v-100zM100 900h100v100h-100v-100zM300 100h600v400h-600v-400zM300 600h600v400h-600v-400zM1000 100h100v100h-100v-100z M1000 300h100v100h-100v-100zM1000 500h100v100h-100v-100zM1000 700h100v100h-100v-100zM1000 900h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M0 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM0 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400 q-21 0 -35.5 14.5t-14.5 35.5zM600 50v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5zM600 650v400q0 21 14.5 35.5t35.5 14.5h400q21 0 35.5 -14.5t14.5 -35.5v-400 q0 -21 -14.5 -35.5t-35.5 -14.5h-400q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200 q-21 0 -35.5 14.5t-14.5 35.5zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 450v200q0 21 14.5 35.5t35.5 14.5h200 q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM800 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM0 450q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v200q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5 t-14.5 -35.5v-200zM0 850v200q0 21 14.5 35.5t35.5 14.5h200q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5zM400 50v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5 t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 450v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5zM400 850v200q0 21 14.5 35.5t35.5 14.5h700q21 0 35.5 -14.5t14.5 -35.5 v-200q0 -21 -14.5 -35.5t-35.5 -14.5h-700q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M29 454l419 -420l818 820l-212 212l-607 -607l-206 207z" />
|
||||
<glyph unicode="" d="M106 318l282 282l-282 282l212 212l282 -282l282 282l212 -212l-282 -282l282 -282l-212 -212l-282 282l-282 -282z" />
|
||||
<glyph unicode="" d="M23 693q0 200 142 342t342 142t342 -142t142 -342q0 -142 -78 -261l300 -300q7 -8 7 -18t-7 -18l-109 -109q-8 -7 -18 -7t-18 7l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 693q0 -136 97 -233t234 -97t233.5 96.5t96.5 233.5t-96.5 233.5t-233.5 96.5 t-234 -97t-97 -233zM300 600v200h100v100h200v-100h100v-200h-100v-100h-200v100h-100z" />
|
||||
<glyph unicode="" d="M23 694q0 200 142 342t342 142t342 -142t142 -342q0 -141 -78 -262l300 -299q7 -7 7 -18t-7 -18l-109 -109q-8 -8 -18 -8t-18 8l-300 300q-119 -78 -261 -78q-200 0 -342 142t-142 342zM176 694q0 -136 97 -233t234 -97t233.5 97t96.5 233t-96.5 233t-233.5 97t-234 -97 t-97 -233zM300 601h400v200h-400v-200z" />
|
||||
<glyph unicode="" d="M23 600q0 183 105 331t272 210v-166q-103 -55 -165 -155t-62 -220q0 -177 125 -302t302 -125t302 125t125 302q0 120 -62 220t-165 155v166q167 -62 272 -210t105 -331q0 -118 -45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5 zM500 750q0 -21 14.5 -35.5t35.5 -14.5h100q21 0 35.5 14.5t14.5 35.5v400q0 21 -14.5 35.5t-35.5 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-400z" />
|
||||
<glyph unicode="" d="M100 1h200v300h-200v-300zM400 1v500h200v-500h-200zM700 1v800h200v-800h-200zM1000 1v1200h200v-1200h-200z" />
|
||||
<glyph unicode="" d="M26 601q0 -33 6 -74l151 -38l2 -6q14 -49 38 -93l3 -5l-80 -134q45 -59 105 -105l133 81l5 -3q45 -26 94 -39l5 -2l38 -151q40 -5 74 -5q27 0 74 5l38 151l6 2q46 13 93 39l5 3l134 -81q56 44 104 105l-80 134l3 5q24 44 39 93l1 6l152 38q5 40 5 74q0 28 -5 73l-152 38 l-1 6q-16 51 -39 93l-3 5l80 134q-44 58 -104 105l-134 -81l-5 3q-45 25 -93 39l-6 1l-38 152q-40 5 -74 5q-27 0 -74 -5l-38 -152l-5 -1q-50 -14 -94 -39l-5 -3l-133 81q-59 -47 -105 -105l80 -134l-3 -5q-25 -47 -38 -93l-2 -6l-151 -38q-6 -48 -6 -73zM385 601 q0 88 63 151t152 63t152 -63t63 -151q0 -89 -63 -152t-152 -63t-152 63t-63 152z" />
|
||||
<glyph unicode="" d="M100 1025v50q0 10 7.5 17.5t17.5 7.5h275v100q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5v-100h275q10 0 17.5 -7.5t7.5 -17.5v-50q0 -11 -7 -18t-18 -7h-1050q-11 0 -18 7t-7 18zM200 100v800h900v-800q0 -41 -29.5 -71t-70.5 -30h-700q-41 0 -70.5 30 t-29.5 71zM300 100h100v700h-100v-700zM500 100h100v700h-100v-700zM500 1100h300v100h-300v-100zM700 100h100v700h-100v-700zM900 100h100v700h-100v-700z" />
|
||||
<glyph unicode="" d="M1 601l656 644l644 -644h-200v-600h-300v400h-300v-400h-300v600h-200z" />
|
||||
<glyph unicode="" d="M100 25v1150q0 11 7 18t18 7h475v-500h400v-675q0 -11 -7 -18t-18 -7h-850q-11 0 -18 7t-7 18zM700 800v300l300 -300h-300z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 500v400h100 v-300h200v-100h-300z" />
|
||||
<glyph unicode="" d="M-100 0l431 1200h209l-21 -300h162l-20 300h208l431 -1200h-538l-41 400h-242l-40 -400h-539zM488 500h224l-27 300h-170z" />
|
||||
<glyph unicode="" d="M0 0v400h490l-290 300h200v500h300v-500h200l-290 -300h490v-400h-1100zM813 200h175v100h-175v-100z" />
|
||||
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM188 600q0 -170 121 -291t291 -121t291 121t121 291t-121 291t-291 121 t-291 -121t-121 -291zM350 600h150v300h200v-300h150l-250 -300z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM350 600l250 300 l250 -300h-150v-300h-200v300h-150z" />
|
||||
<glyph unicode="" d="M0 25v475l200 700h800l199 -700l1 -475q0 -11 -7 -18t-18 -7h-1150q-11 0 -18 7t-7 18zM200 500h200l50 -200h300l50 200h200l-97 500h-606z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM500 397v401 l297 -200z" />
|
||||
<glyph unicode="" d="M23 600q0 -118 45.5 -224.5t123 -184t184 -123t224.5 -45.5t224.5 45.5t184 123t123 184t45.5 224.5h-150q0 -177 -125 -302t-302 -125t-302 125t-125 302t125 302t302 125q136 0 246 -81l-146 -146h400v400l-145 -145q-157 122 -355 122q-118 0 -224.5 -45.5t-184 -123 t-123 -184t-45.5 -224.5z" />
|
||||
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5q198 0 355 -122l145 145v-400h-400l147 147q-112 80 -247 80q-177 0 -302 -125t-125 -302h-150zM100 0v400h400l-147 -147q112 -80 247 -80q177 0 302 125t125 302h150q0 -118 -45.5 -224.5t-123 -184t-184 -123 t-224.5 -45.5q-198 0 -355 122z" />
|
||||
<glyph unicode="" d="M100 0h1100v1200h-1100v-1200zM200 100v900h900v-900h-900zM300 200v100h100v-100h-100zM300 400v100h100v-100h-100zM300 600v100h100v-100h-100zM300 800v100h100v-100h-100zM500 200h500v100h-500v-100zM500 400v100h500v-100h-500zM500 600v100h500v-100h-500z M500 800v100h500v-100h-500z" />
|
||||
<glyph unicode="" d="M0 100v600q0 41 29.5 70.5t70.5 29.5h100v200q0 82 59 141t141 59h300q82 0 141 -59t59 -141v-200h100q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-900q-41 0 -70.5 29.5t-29.5 70.5zM400 800h300v150q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-150z" />
|
||||
<glyph unicode="" d="M100 0v1100h100v-1100h-100zM300 400q60 60 127.5 84t127.5 17.5t122 -23t119 -30t110 -11t103 42t91 120.5v500q-40 -81 -101.5 -115.5t-127.5 -29.5t-138 25t-139.5 40t-125.5 25t-103 -29.5t-65 -115.5v-500z" />
|
||||
<glyph unicode="" d="M0 275q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 127 70.5 231.5t184.5 161.5t245 57t245 -57t184.5 -161.5t70.5 -231.5v-300q0 -11 7 -18t18 -7h50q11 0 18 7t7 18v300q0 116 -49.5 227t-131 192.5t-192.5 131t-227 49.5t-227 -49.5t-192.5 -131t-131 -192.5 t-49.5 -227v-300zM200 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14zM800 20v460q0 8 6 14t14 6h160q8 0 14 -6t6 -14v-460q0 -8 -6 -14t-14 -6h-160q-8 0 -14 6t-6 14z" />
|
||||
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM688 459l141 141l-141 141l71 71l141 -141l141 141l71 -71l-141 -141l141 -141l-71 -71l-141 141l-141 -141z" />
|
||||
<glyph unicode="" d="M0 400h300l300 -200v800l-300 -200h-300v-400zM700 857l69 53q111 -135 111 -310q0 -169 -106 -302l-67 54q86 110 86 248q0 146 -93 257z" />
|
||||
<glyph unicode="" d="M0 401v400h300l300 200v-800l-300 200h-300zM702 858l69 53q111 -135 111 -310q0 -170 -106 -303l-67 55q86 110 86 248q0 145 -93 257zM889 951l7 -8q123 -151 123 -344q0 -189 -119 -339l-7 -8l81 -66l6 8q142 178 142 405q0 230 -144 408l-6 8z" />
|
||||
<glyph unicode="" d="M0 0h500v500h-200v100h-100v-100h-200v-500zM0 600h100v100h400v100h100v100h-100v300h-500v-600zM100 100v300h300v-300h-300zM100 800v300h300v-300h-300zM200 200v100h100v-100h-100zM200 900h100v100h-100v-100zM500 500v100h300v-300h200v-100h-100v-100h-200v100 h-100v100h100v200h-200zM600 0v100h100v-100h-100zM600 1000h100v-300h200v-300h300v200h-200v100h200v500h-600v-200zM800 800v300h300v-300h-300zM900 0v100h300v-100h-300zM900 900v100h100v-100h-100zM1100 200v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M0 200h100v1000h-100v-1000zM100 0v100h300v-100h-300zM200 200v1000h100v-1000h-100zM500 0v91h100v-91h-100zM500 200v1000h200v-1000h-200zM700 0v91h100v-91h-100zM800 200v1000h100v-1000h-100zM900 0v91h200v-91h-200zM1000 200v1000h200v-1000h-200z" />
|
||||
<glyph unicode="" d="M0 700l1 475q0 10 7.5 17.5t17.5 7.5h474l700 -700l-500 -500zM148 953q0 -42 29 -71q30 -30 71.5 -30t71.5 30q29 29 29 71t-29 71q-30 30 -71.5 30t-71.5 -30q-29 -29 -29 -71z" />
|
||||
<glyph unicode="" d="M1 700l1 475q0 11 7 18t18 7h474l700 -700l-500 -500zM148 953q0 -42 30 -71q29 -30 71 -30t71 30q30 29 30 71t-30 71q-29 30 -71 30t-71 -30q-30 -29 -30 -71zM701 1200h100l700 -700l-500 -500l-50 50l450 450z" />
|
||||
<glyph unicode="" d="M100 0v1025l175 175h925v-1000l-100 -100v1000h-750l-100 -100h750v-1000h-900z" />
|
||||
<glyph unicode="" d="M200 0l450 444l450 -443v1150q0 20 -14.5 35t-35.5 15h-800q-21 0 -35.5 -15t-14.5 -35v-1151z" />
|
||||
<glyph unicode="" d="M0 100v700h200l100 -200h600l100 200h200v-700h-200v200h-800v-200h-200zM253 829l40 -124h592l62 124l-94 346q-2 11 -10 18t-18 7h-450q-10 0 -18 -7t-10 -18zM281 24l38 152q2 10 11.5 17t19.5 7h500q10 0 19.5 -7t11.5 -17l38 -152q2 -10 -3.5 -17t-15.5 -7h-600 q-10 0 -15.5 7t-3.5 17z" />
|
||||
<glyph unicode="" d="M0 200q0 -41 29.5 -70.5t70.5 -29.5h1000q41 0 70.5 29.5t29.5 70.5v600q0 41 -29.5 70.5t-70.5 29.5h-150q-4 8 -11.5 21.5t-33 48t-53 61t-69 48t-83.5 21.5h-200q-41 0 -82 -20.5t-70 -50t-52 -59t-34 -50.5l-12 -20h-150q-41 0 -70.5 -29.5t-29.5 -70.5v-600z M356 500q0 100 72 172t172 72t172 -72t72 -172t-72 -172t-172 -72t-172 72t-72 172zM494 500q0 -44 31 -75t75 -31t75 31t31 75t-31 75t-75 31t-75 -31t-31 -75zM900 700v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M53 0h365v66q-41 0 -72 11t-49 38t1 71l92 234h391l82 -222q16 -45 -5.5 -88.5t-74.5 -43.5v-66h417v66q-34 1 -74 43q-18 19 -33 42t-21 37l-6 13l-385 998h-93l-399 -1006q-24 -48 -52 -75q-12 -12 -33 -25t-36 -20l-15 -7v-66zM416 521l178 457l46 -140l116 -317h-340 z" />
|
||||
<glyph unicode="" d="M100 0v89q41 7 70.5 32.5t29.5 65.5v827q0 28 -1 39.5t-5.5 26t-15.5 21t-29 14t-49 14.5v71l471 -1q120 0 213 -88t93 -228q0 -55 -11.5 -101.5t-28 -74t-33.5 -47.5t-28 -28l-12 -7q8 -3 21.5 -9t48 -31.5t60.5 -58t47.5 -91.5t21.5 -129q0 -84 -59 -156.5t-142 -111 t-162 -38.5h-500zM400 200h161q89 0 153 48.5t64 132.5q0 90 -62.5 154.5t-156.5 64.5h-159v-400zM400 700h139q76 0 130 61.5t54 138.5q0 82 -84 130.5t-239 48.5v-379z" />
|
||||
<glyph unicode="" d="M200 0v57q77 7 134.5 40.5t65.5 80.5l173 849q10 56 -10 74t-91 37q-6 1 -10.5 2.5t-9.5 2.5v57h425l2 -57q-33 -8 -62 -25.5t-46 -37t-29.5 -38t-17.5 -30.5l-5 -12l-128 -825q-10 -52 14 -82t95 -36v-57h-500z" />
|
||||
<glyph unicode="" d="M-75 200h75v800h-75l125 167l125 -167h-75v-800h75l-125 -167zM300 900v300h150h700h150v-300h-50q0 29 -8 48.5t-18.5 30t-33.5 15t-39.5 5.5t-50.5 1h-200v-850l100 -50v-100h-400v100l100 50v850h-200q-34 0 -50.5 -1t-40 -5.5t-33.5 -15t-18.5 -30t-8.5 -48.5h-49z " />
|
||||
<glyph unicode="" d="M33 51l167 125v-75h800v75l167 -125l-167 -125v75h-800v-75zM100 901v300h150h700h150v-300h-50q0 29 -8 48.5t-18 30t-33.5 15t-40 5.5t-50.5 1h-200v-650l100 -50v-100h-400v100l100 50v650h-200q-34 0 -50.5 -1t-39.5 -5.5t-33.5 -15t-18.5 -30t-8 -48.5h-50z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 350q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM0 650q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1000q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 950q0 -20 14.5 -35t35.5 -15h600q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-600q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM0 650q0 -20 14.5 -35t35.5 -15h1100q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5 v-100zM200 350q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM200 950q0 -20 14.5 -35t35.5 -15h700q21 0 35.5 15t14.5 35v100q0 21 -14.5 35.5t-35.5 14.5h-700q-21 0 -35.5 -14.5 t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM100 650v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1000q-21 0 -35.5 15 t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM500 950v100q0 21 14.5 35.5t35.5 14.5h600q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-600 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h1100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-1100 q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M0 50v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 350v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM0 650v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15t-14.5 35zM0 950v100q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-100q-21 0 -35.5 15 t-14.5 35zM300 50v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 350v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800 q-21 0 -35.5 15t-14.5 35zM300 650v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15h-800q-21 0 -35.5 15t-14.5 35zM300 950v100q0 21 14.5 35.5t35.5 14.5h800q21 0 35.5 -14.5t14.5 -35.5v-100q0 -20 -14.5 -35t-35.5 -15 h-800q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M-101 500v100h201v75l166 -125l-166 -125v75h-201zM300 0h100v1100h-100v-1100zM500 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35 v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 650q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM500 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100 q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100z" />
|
||||
<glyph unicode="" d="M1 50q0 -20 14.5 -35t35.5 -15h600q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-600q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 350q0 -20 14.5 -35t35.5 -15h300q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-300q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 650 q0 -20 14.5 -35t35.5 -15h500q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-500q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM1 950q0 -20 14.5 -35t35.5 -15h100q20 0 35 15t15 35v100q0 21 -15 35.5t-35 14.5h-100q-21 0 -35.5 -14.5t-14.5 -35.5v-100zM801 0v1100h100v-1100 h-100zM934 550l167 -125v75h200v100h-200v75z" />
|
||||
<glyph unicode="" d="M0 275v650q0 31 22 53t53 22h750q31 0 53 -22t22 -53v-650q0 -31 -22 -53t-53 -22h-750q-31 0 -53 22t-22 53zM900 600l300 300v-600z" />
|
||||
<glyph unicode="" d="M0 44v1012q0 18 13 31t31 13h1112q19 0 31.5 -13t12.5 -31v-1012q0 -18 -12.5 -31t-31.5 -13h-1112q-18 0 -31 13t-13 31zM100 263l247 182l298 -131l-74 156l293 318l236 -288v500h-1000v-737zM208 750q0 56 39 95t95 39t95 -39t39 -95t-39 -95t-95 -39t-95 39t-39 95z " />
|
||||
<glyph unicode="" d="M148 745q0 124 60.5 231.5t165 172t226.5 64.5q123 0 227 -63t164.5 -169.5t60.5 -229.5t-73 -272q-73 -114 -166.5 -237t-150.5 -189l-57 -66q-10 9 -27 26t-66.5 70.5t-96 109t-104 135.5t-100.5 155q-63 139 -63 262zM342 772q0 -107 75.5 -182.5t181.5 -75.5 q107 0 182.5 75.5t75.5 182.5t-75.5 182t-182.5 75t-182 -75.5t-75 -181.5z" />
|
||||
<glyph unicode="" d="M1 600q0 122 47.5 233t127.5 191t191 127.5t233 47.5t233 -47.5t191 -127.5t127.5 -191t47.5 -233t-47.5 -233t-127.5 -191t-191 -127.5t-233 -47.5t-233 47.5t-191 127.5t-127.5 191t-47.5 233zM173 600q0 -177 125.5 -302t301.5 -125v854q-176 0 -301.5 -125 t-125.5 -302z" />
|
||||
<glyph unicode="" d="M117 406q0 94 34 186t88.5 172.5t112 159t115 177t87.5 194.5q21 -71 57.5 -142.5t76 -130.5t83 -118.5t82 -117t70 -116t50 -125.5t18.5 -136q0 -89 -39 -165.5t-102 -126.5t-140 -79.5t-156 -33.5q-114 6 -211.5 53t-161.5 139t-64 210zM243 414q14 -82 59.5 -136 t136.5 -80l16 98q-7 6 -18 17t-34 48t-33 77q-15 73 -14 143.5t10 122.5l9 51q-92 -110 -119.5 -185t-12.5 -156z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5q366 -6 397 -14l-186 -186h-311q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v125l200 200v-225q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM436 341l161 50l412 412l-114 113l-405 -405zM995 1015l113 -113l113 113l-21 85l-92 28z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h261l2 -80q-133 -32 -218 -120h-145q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5l200 153v-53q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5 zM423 524q30 38 81.5 64t103 35.5t99 14t77.5 3.5l29 -1v-209l360 324l-359 318v-216q-7 0 -19 -1t-48 -8t-69.5 -18.5t-76.5 -37t-76.5 -59t-62 -88t-39.5 -121.5z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q61 0 127 -23l-178 -177h-349q-41 0 -70.5 -29.5t-29.5 -70.5v-500q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v69l200 200v-169q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5 t-117.5 282.5zM342 632l283 -284l567 567l-137 137l-430 -431l-146 147z" />
|
||||
<glyph unicode="" d="M0 603l300 296v-198h200v200h-200l300 300l295 -300h-195v-200h200v198l300 -296l-300 -300v198h-200v-200h195l-295 -300l-300 300h200v200h-200v-198z" />
|
||||
<glyph unicode="" d="M200 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-1100l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M0 50v1000q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-437l500 487v-487l500 487v-1100l-500 488v-488l-500 488v-438q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5z" />
|
||||
<glyph unicode="" d="M136 550l564 550v-487l500 487v-1100l-500 488v-488z" />
|
||||
<glyph unicode="" d="M200 0l900 550l-900 550v-1100z" />
|
||||
<glyph unicode="" d="M200 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200q-21 0 -35.5 -14.5t-14.5 -35.5v-800zM600 150q0 -21 14.5 -35.5t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v800q0 21 -14.5 35.5t-35.5 14.5h-200 q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||
<glyph unicode="" d="M200 150q0 -20 14.5 -35t35.5 -15h800q21 0 35.5 15t14.5 35v800q0 21 -14.5 35.5t-35.5 14.5h-800q-21 0 -35.5 -14.5t-14.5 -35.5v-800z" />
|
||||
<glyph unicode="" d="M0 0v1100l500 -487v487l564 -550l-564 -550v488z" />
|
||||
<glyph unicode="" d="M0 0v1100l500 -487v487l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438l-500 -488v488z" />
|
||||
<glyph unicode="" d="M300 0v1100l500 -487v437q0 21 14.5 35.5t35.5 14.5h100q21 0 35.5 -14.5t14.5 -35.5v-1000q0 -21 -14.5 -35.5t-35.5 -14.5h-100q-21 0 -35.5 14.5t-14.5 35.5v438z" />
|
||||
<glyph unicode="" d="M100 250v100q0 21 14.5 35.5t35.5 14.5h1000q21 0 35.5 -14.5t14.5 -35.5v-100q0 -21 -14.5 -35.5t-35.5 -14.5h-1000q-21 0 -35.5 14.5t-14.5 35.5zM100 500h1100l-550 564z" />
|
||||
<glyph unicode="" d="M185 599l592 -592l240 240l-353 353l353 353l-240 240z" />
|
||||
<glyph unicode="" d="M272 194l353 353l-353 353l241 240l572 -571l21 -22l-1 -1v-1l-592 -591z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h200v-200h200v200h200v200h-200v200h-200v-200h-200v-200z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM300 500h600v200h-600v-200z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM246 459l213 -213l141 142l141 -142l213 213l-142 141l142 141l-213 212l-141 -141l-141 142l-212 -213l141 -141 z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM270 551l276 -277l411 411l-175 174l-236 -236l-102 102z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM364 700h143q4 0 11.5 -1t11 -1t6.5 3t3 9t1 11t3.5 8.5t3.5 6t5.5 4t6.5 2.5t9 1.5t9 0.5h11.5h12.5 q19 0 30 -10t11 -26q0 -22 -4 -28t-27 -22q-5 -1 -12.5 -3t-27 -13.5t-34 -27t-26.5 -46t-11 -68.5h200q5 3 14 8t31.5 25.5t39.5 45.5t31 69t14 94q0 51 -17.5 89t-42 58t-58.5 32t-58.5 15t-51.5 3q-50 0 -90.5 -12t-75 -38.5t-53.5 -74.5t-19 -114zM500 300h200v100h-200 v-100z" />
|
||||
<glyph unicode="" d="M3 600q0 162 80 299.5t217.5 217.5t299.5 80t299.5 -80t217.5 -217.5t80 -299.5t-80 -299.5t-217.5 -217.5t-299.5 -80t-299.5 80t-217.5 217.5t-80 299.5zM400 300h400v100h-100v300h-300v-100h100v-200h-100v-100zM500 800h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 500v200h195q31 125 98.5 199.5t206.5 100.5v200h200v-200q54 -20 113 -60t112.5 -105.5t71.5 -134.5h203v-200h-203q-25 -102 -116.5 -186t-180.5 -117v-197h-200v197q-140 27 -208 102.5t-98 200.5h-194zM290 500q24 -73 79.5 -127.5t130.5 -78.5v206h200v-206 q149 48 201 206h-201v200h200q-25 74 -75.5 127t-124.5 77v-204h-200v203q-75 -23 -130 -77t-79 -126h209v-200h-210z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM356 465l135 135 l-135 135l109 109l135 -135l135 135l109 -109l-135 -135l135 -135l-109 -109l-135 135l-135 -135z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM322 537l141 141 l87 -87l204 205l142 -142l-346 -345z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -115 62 -215l568 567q-100 62 -216 62q-171 0 -292.5 -121.5t-121.5 -292.5zM391 245q97 -59 209 -59q171 0 292.5 121.5t121.5 292.5 q0 112 -59 209z" />
|
||||
<glyph unicode="" d="M0 547l600 453v-300h600v-300h-600v-301z" />
|
||||
<glyph unicode="" d="M0 400v300h600v300l600 -453l-600 -448v301h-600z" />
|
||||
<glyph unicode="" d="M204 600l450 600l444 -600h-298v-600h-300v600h-296z" />
|
||||
<glyph unicode="" d="M104 600h296v600h300v-600h298l-449 -600z" />
|
||||
<glyph unicode="" d="M0 200q6 132 41 238.5t103.5 193t184 138t271.5 59.5v271l600 -453l-600 -448v301q-95 -2 -183 -20t-170 -52t-147 -92.5t-100 -135.5z" />
|
||||
<glyph unicode="" d="M0 0v400l129 -129l294 294l142 -142l-294 -294l129 -129h-400zM635 777l142 -142l294 294l129 -129v400h-400l129 -129z" />
|
||||
<glyph unicode="" d="M34 176l295 295l-129 129h400v-400l-129 130l-295 -295zM600 600v400l129 -129l295 295l142 -141l-295 -295l129 -130h-400z" />
|
||||
<glyph unicode="" d="M23 600q0 118 45.5 224.5t123 184t184 123t224.5 45.5t224.5 -45.5t184 -123t123 -184t45.5 -224.5t-45.5 -224.5t-123 -184t-184 -123t-224.5 -45.5t-224.5 45.5t-184 123t-123 184t-45.5 224.5zM456 851l58 -302q4 -20 21.5 -34.5t37.5 -14.5h54q20 0 37.5 14.5 t21.5 34.5l58 302q4 20 -8 34.5t-32 14.5h-207q-21 0 -33 -14.5t-8 -34.5zM500 300h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 800h100v-200h400v300h200v-300h400v200h100v100h-111q1 1 1 6.5t-1.5 15t-3.5 17.5l-34 172q-11 39 -41.5 63t-69.5 24q-32 0 -61 -17l-239 -144q-22 -13 -40 -35q-19 24 -40 36l-238 144q-33 18 -62 18q-39 0 -69.5 -23t-40.5 -61l-35 -177q-2 -8 -3 -18t-1 -15v-6 h-111v-100zM100 0h400v400h-400v-400zM200 900q-3 0 14 48t36 96l18 47l213 -191h-281zM700 0v400h400v-400h-400zM731 900l202 197q5 -12 12 -32.5t23 -64t25 -72t7 -28.5h-269z" />
|
||||
<glyph unicode="" d="M0 -22v143l216 193q-9 53 -13 83t-5.5 94t9 113t38.5 114t74 124q47 60 99.5 102.5t103 68t127.5 48t145.5 37.5t184.5 43.5t220 58.5q0 -189 -22 -343t-59 -258t-89 -181.5t-108.5 -120t-122 -68t-125.5 -30t-121.5 -1.5t-107.5 12.5t-87.5 17t-56.5 7.5l-99 -55z M238.5 300.5q19.5 -6.5 86.5 76.5q55 66 367 234q70 38 118.5 69.5t102 79t99 111.5t86.5 148q22 50 24 60t-6 19q-7 5 -17 5t-26.5 -14.5t-33.5 -39.5q-35 -51 -113.5 -108.5t-139.5 -89.5l-61 -32q-369 -197 -458 -401q-48 -111 -28.5 -117.5z" />
|
||||
<glyph unicode="" d="M111 408q0 -33 5 -63q9 -56 44 -119.5t105 -108.5q31 -21 64 -16t62 23.5t57 49.5t48 61.5t35 60.5q32 66 39 184.5t-13 157.5q79 -80 122 -164t26 -184q-5 -33 -20.5 -69.5t-37.5 -80.5q-10 -19 -14.5 -29t-12 -26t-9 -23.5t-3 -19t2.5 -15.5t11 -9.5t19.5 -5t30.5 2.5 t42 8q57 20 91 34t87.5 44.5t87 64t65.5 88.5t47 122q38 172 -44.5 341.5t-246.5 278.5q22 -44 43 -129q39 -159 -32 -154q-15 2 -33 9q-79 33 -120.5 100t-44 175.5t48.5 257.5q-13 -8 -34 -23.5t-72.5 -66.5t-88.5 -105.5t-60 -138t-8 -166.5q2 -12 8 -41.5t8 -43t6 -39.5 t3.5 -39.5t-1 -33.5t-6 -31.5t-13.5 -24t-21 -20.5t-31 -12q-38 -10 -67 13t-40.5 61.5t-15 81.5t10.5 75q-52 -46 -83.5 -101t-39 -107t-7.5 -85z" />
|
||||
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5t145.5 -23.5t132.5 -59t116.5 -83.5t97 -90t74.5 -85.5t49 -63.5t20 -30l26 -40l-26 -40q-6 -10 -20 -30t-49 -63.5t-74.5 -85.5t-97 -90t-116.5 -83.5t-132.5 -59t-145.5 -23.5 t-145.5 23.5t-132.5 59t-116.5 83.5t-97 90t-74.5 85.5t-49 63.5t-20 30zM120 600q7 -10 40.5 -58t56 -78.5t68 -77.5t87.5 -75t103 -49.5t125 -21.5t123.5 20t100.5 45.5t85.5 71.5t66.5 75.5t58 81.5t47 66q-1 1 -28.5 37.5t-42 55t-43.5 53t-57.5 63.5t-58.5 54 q49 -74 49 -163q0 -124 -88 -212t-212 -88t-212 88t-88 212q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l105 105q-37 24 -75 72t-57 84l-20 36z" />
|
||||
<glyph unicode="" d="M-61 600l26 40q6 10 20 30t49 63.5t74.5 85.5t97 90t116.5 83.5t132.5 59t145.5 23.5q61 0 121 -17l37 142h148l-314 -1200h-148l37 143q-82 21 -165 71.5t-140 102t-109.5 112t-72 88.5t-29.5 43zM120 600q210 -282 393 -336l37 141q-107 18 -178.5 101.5t-71.5 193.5 q0 85 46 158q-102 -87 -226 -258zM377 656q49 -124 154 -191l47 47l23 87q-30 28 -59 69t-44 68l-14 26zM780 161l38 145q22 15 44.5 34t46 44t40.5 44t41 50.5t33.5 43.5t33 44t24.5 34q-97 127 -140 175l39 146q67 -54 131.5 -125.5t87.5 -103.5t36 -52l26 -40l-26 -40 q-7 -12 -25.5 -38t-63.5 -79.5t-95.5 -102.5t-124 -100t-146.5 -79z" />
|
||||
<glyph unicode="" d="M-97.5 34q13.5 -34 50.5 -34h1294q37 0 50.5 35.5t-7.5 67.5l-642 1056q-20 34 -48 36.5t-48 -29.5l-642 -1066q-21 -32 -7.5 -66zM155 200l445 723l445 -723h-345v100h-200v-100h-345zM500 600l100 -300l100 300v100h-200v-100z" />
|
||||
<glyph unicode="" d="M100 262v41q0 20 11 44.5t26 38.5l363 325v339q0 62 44 106t106 44t106 -44t44 -106v-339l363 -325q15 -14 26 -38.5t11 -44.5v-41q0 -20 -12 -26.5t-29 5.5l-359 249v-263q100 -91 100 -113v-64q0 -20 -13 -28.5t-32 0.5l-94 78h-222l-94 -78q-19 -9 -32 -0.5t-13 28.5 v64q0 22 100 113v263l-359 -249q-17 -12 -29 -5.5t-12 26.5z" />
|
||||
<glyph unicode="" d="M0 50q0 -20 14.5 -35t35.5 -15h1000q21 0 35.5 15t14.5 35v750h-1100v-750zM0 900h1100v150q0 21 -14.5 35.5t-35.5 14.5h-150v100h-100v-100h-500v100h-100v-100h-150q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 100v100h100v-100h-100zM100 300v100h100v-100h-100z M100 500v100h100v-100h-100zM300 100v100h100v-100h-100zM300 300v100h100v-100h-100zM300 500v100h100v-100h-100zM500 100v100h100v-100h-100zM500 300v100h100v-100h-100zM500 500v100h100v-100h-100zM700 100v100h100v-100h-100zM700 300v100h100v-100h-100zM700 500 v100h100v-100h-100zM900 100v100h100v-100h-100zM900 300v100h100v-100h-100zM900 500v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M0 200v200h259l600 600h241v198l300 -295l-300 -300v197h-159l-600 -600h-341zM0 800h259l122 -122l141 142l-181 180h-341v-200zM678 381l141 142l122 -123h159v198l300 -295l-300 -300v197h-241z" />
|
||||
<glyph unicode="" d="M0 400v600q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-600q0 -41 -29.5 -70.5t-70.5 -29.5h-596l-304 -300v300h-100q-41 0 -70.5 29.5t-29.5 70.5z" />
|
||||
<glyph unicode="" d="M100 600v200h300v-250q0 -113 6 -145q17 -92 102 -117q39 -11 92 -11q37 0 66.5 5.5t50 15.5t36 24t24 31.5t14 37.5t7 42t2.5 45t0 47v25v250h300v-200q0 -42 -3 -83t-15 -104t-31.5 -116t-58 -109.5t-89 -96.5t-129 -65.5t-174.5 -25.5t-174.5 25.5t-129 65.5t-89 96.5 t-58 109.5t-31.5 116t-15 104t-3 83zM100 900v300h300v-300h-300zM800 900v300h300v-300h-300z" />
|
||||
<glyph unicode="" d="M-30 411l227 -227l352 353l353 -353l226 227l-578 579z" />
|
||||
<glyph unicode="" d="M70 797l580 -579l578 579l-226 227l-353 -353l-352 353z" />
|
||||
<glyph unicode="" d="M-198 700l299 283l300 -283h-203v-400h385l215 -200h-800v600h-196zM402 1000l215 -200h381v-400h-198l299 -283l299 283h-200v600h-796z" />
|
||||
<glyph unicode="" d="M18 939q-5 24 10 42q14 19 39 19h896l38 162q5 17 18.5 27.5t30.5 10.5h94q20 0 35 -14.5t15 -35.5t-15 -35.5t-35 -14.5h-54l-201 -961q-2 -4 -6 -10.5t-19 -17.5t-33 -11h-31v-50q0 -20 -14.5 -35t-35.5 -15t-35.5 15t-14.5 35v50h-300v-50q0 -20 -14.5 -35t-35.5 -15 t-35.5 15t-14.5 35v50h-50q-21 0 -35.5 15t-14.5 35q0 21 14.5 35.5t35.5 14.5h535l48 200h-633q-32 0 -54.5 21t-27.5 43z" />
|
||||
<glyph unicode="" d="M0 0v800h1200v-800h-1200zM0 900v100h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-100h-1200z" />
|
||||
<glyph unicode="" d="M1 0l300 700h1200l-300 -700h-1200zM1 400v600h200q0 41 29.5 70.5t70.5 29.5h300q41 0 70.5 -29.5t29.5 -70.5h500v-200h-1000z" />
|
||||
<glyph unicode="" d="M302 300h198v600h-198l298 300l298 -300h-198v-600h198l-298 -300z" />
|
||||
<glyph unicode="" d="M0 600l300 298v-198h600v198l300 -298l-300 -297v197h-600v-197z" />
|
||||
<glyph unicode="" d="M0 100v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM31 400l172 739q5 22 23 41.5t38 19.5h672q19 0 37.5 -22.5t23.5 -45.5l172 -732h-1138zM800 100h100v100h-100v-100z M1000 100h100v100h-100v-100z" />
|
||||
<glyph unicode="" d="M-101 600v50q0 24 25 49t50 38l25 13v-250l-11 5.5t-24 14t-30 21.5t-24 27.5t-11 31.5zM100 500v250v8v8v7t0.5 7t1.5 5.5t2 5t3 4t4.5 3.5t6 1.5t7.5 0.5h200l675 250v-850l-675 200h-38l47 -276q2 -12 -3 -17.5t-11 -6t-21 -0.5h-8h-83q-20 0 -34.5 14t-18.5 35 q-55 337 -55 351zM1100 200v850q0 21 14.5 35.5t35.5 14.5q20 0 35 -14.5t15 -35.5v-850q0 -20 -15 -35t-35 -15q-21 0 -35.5 15t-14.5 35z" />
|
||||
<glyph unicode="" d="M74 350q0 21 13.5 35.5t33.5 14.5h18l117 173l63 327q15 77 76 140t144 83l-18 32q-6 19 3 32t29 13h94q20 0 29 -10.5t3 -29.5q-18 -36 -18 -37q83 -19 144 -82.5t76 -140.5l63 -327l118 -173h17q20 0 33.5 -14.5t13.5 -35.5q0 -20 -13 -40t-31 -27q-8 -3 -23 -8.5 t-65 -20t-103 -25t-132.5 -19.5t-158.5 -9q-125 0 -245.5 20.5t-178.5 40.5l-58 20q-18 7 -31 27.5t-13 40.5zM497 110q12 -49 40 -79.5t63 -30.5t63 30.5t39 79.5q-48 -6 -102 -6t-103 6z" />
|
||||
<glyph unicode="" d="M21 445l233 -45l-78 -224l224 78l45 -233l155 179l155 -179l45 233l224 -78l-78 224l234 45l-180 155l180 156l-234 44l78 225l-224 -78l-45 233l-155 -180l-155 180l-45 -233l-224 78l78 -225l-233 -44l179 -156z" />
|
||||
<glyph unicode="" d="M0 200h200v600h-200v-600zM300 275q0 -75 100 -75h61q124 -100 139 -100h250q46 0 83 57l238 344q29 31 29 74v100q0 44 -30.5 84.5t-69.5 40.5h-328q28 118 28 125v150q0 44 -30.5 84.5t-69.5 40.5h-50q-27 0 -51 -20t-38 -48l-96 -198l-145 -196q-20 -26 -20 -63v-400z M400 300v375l150 213l100 212h50v-175l-50 -225h450v-125l-250 -375h-214l-136 100h-100z" />
|
||||
<glyph unicode="" d="M0 400v600h200v-600h-200zM300 525v400q0 75 100 75h61q124 100 139 100h250q46 0 83 -57l238 -344q29 -31 29 -74v-100q0 -44 -30.5 -84.5t-69.5 -40.5h-328q28 -118 28 -125v-150q0 -44 -30.5 -84.5t-69.5 -40.5h-50q-27 0 -51 20t-38 48l-96 198l-145 196 q-20 26 -20 63zM400 525l150 -212l100 -213h50v175l-50 225h450v125l-250 375h-214l-136 -100h-100v-375z" />
|
||||
<glyph unicode="" d="M8 200v600h200v-600h-200zM308 275v525q0 17 14 35.5t28 28.5l14 9l362 230q14 6 25 6q17 0 29 -12l109 -112q14 -14 14 -34q0 -18 -11 -32l-85 -121h302q85 0 138.5 -38t53.5 -110t-54.5 -111t-138.5 -39h-107l-130 -339q-7 -22 -20.5 -41.5t-28.5 -19.5h-341 q-7 0 -90 81t-83 94zM408 289l100 -89h293l131 339q6 21 19.5 41t28.5 20h203q16 0 25 15t9 36q0 20 -9 34.5t-25 14.5h-457h-6.5h-7.5t-6.5 0.5t-6 1t-5 1.5t-5.5 2.5t-4 4t-4 5.5q-5 12 -5 20q0 14 10 27l147 183l-86 83l-339 -236v-503z" />
|
||||
<glyph unicode="" d="M-101 651q0 72 54 110t139 38l302 -1l-85 121q-11 16 -11 32q0 21 14 34l109 113q13 12 29 12q11 0 25 -6l365 -230q7 -4 17 -10.5t26.5 -26t16.5 -36.5v-526q0 -13 -86 -93.5t-94 -80.5h-341q-16 0 -29.5 20t-19.5 41l-130 339h-107q-84 0 -139 39t-55 111zM-1 601h222 q15 0 28.5 -20.5t19.5 -40.5l131 -339h293l107 89v502l-343 237l-87 -83l145 -184q10 -11 10 -26q0 -11 -5 -20q-1 -3 -3.5 -5.5l-4 -4t-5 -2.5t-5.5 -1.5t-6.5 -1t-6.5 -0.5h-7.5h-6.5h-476v-100zM1000 201v600h200v-600h-200z" />
|
||||
<glyph unicode="" d="M97 719l230 -363q4 -6 10.5 -15.5t26 -25t36.5 -15.5h525q13 0 94 83t81 90v342q0 15 -20 28.5t-41 19.5l-339 131v106q0 84 -39 139t-111 55t-110 -53.5t-38 -138.5v-302l-121 84q-15 12 -33.5 11.5t-32.5 -13.5l-112 -110q-22 -22 -6 -53zM172 739l83 86l183 -146 q22 -18 47 -5q3 1 5.5 3.5l4 4t2.5 5t1.5 5.5t1 6.5t0.5 6.5v7.5v6.5v456q0 22 25 31t50 -0.5t25 -30.5v-202q0 -16 20 -29.5t41 -19.5l339 -130v-294l-89 -100h-503zM400 0v200h600v-200h-600z" />
|
||||
<glyph unicode="" d="M2 585q-16 -31 6 -53l112 -110q13 -13 32 -13.5t34 10.5l121 85q0 -51 -0.5 -153.5t-0.5 -148.5q0 -84 38.5 -138t110.5 -54t111 55t39 139v106l339 131q20 6 40.5 19.5t20.5 28.5v342q0 7 -81 90t-94 83h-525q-17 0 -35.5 -14t-28.5 -28l-10 -15zM77 565l236 339h503 l89 -100v-294l-340 -130q-20 -6 -40 -20t-20 -29v-202q0 -22 -25 -31t-50 0t-25 31v456v14.5t-1.5 11.5t-5 12t-9.5 7q-24 13 -46 -5l-184 -146zM305 1104v200h600v-200h-600z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM298 701l2 -201h300l-2 -194l402 294l-402 298v-197h-300z" />
|
||||
<glyph unicode="" d="M0 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t231.5 47.5q122 0 232.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-218 -217.5t-300 -80t-299.5 80t-217.5 217.5t-80 299.5zM200 600l402 -294l-2 194h300l2 201h-300v197z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600h200v-300h200v300h200l-300 400z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q162 0 299.5 -80t217.5 -218t80 -300t-80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM300 600l300 -400l300 400h-200v300h-200v-300h-200z" />
|
||||
<glyph unicode="" d="M5 597q0 122 47.5 232.5t127.5 190.5t190.5 127.5t232.5 47.5q121 0 231.5 -47.5t190.5 -127.5t127.5 -190.5t47.5 -232.5q0 -162 -80 -299.5t-217.5 -217.5t-299.5 -80t-300 80t-218 217.5t-80 299.5zM254 780q-8 -33 5.5 -92.5t7.5 -87.5q0 -9 17 -44t16 -60 q12 0 23 -5.5t23 -15t20 -13.5q24 -12 108 -42q22 -8 53 -31.5t59.5 -38.5t57.5 -11q8 -18 -15 -55t-20 -57q42 -71 87 -80q0 -6 -3 -15.5t-3.5 -14.5t4.5 -17q104 -3 221 112q30 29 47 47t34.5 49t20.5 62q-14 9 -37 9.5t-36 7.5q-14 7 -49 15t-52 19q-9 0 -39.5 -0.5 t-46.5 -1.5t-39 -6.5t-39 -16.5q-50 -35 -66 -12q-4 2 -3.5 25.5t0.5 25.5q-6 13 -26.5 17t-24.5 7q2 22 -2 41t-16.5 28t-38.5 -20q-23 -25 -42 4q-19 28 -8 58q6 16 22 22q6 -1 26 -1.5t33.5 -4t19.5 -13.5q12 -19 32 -37.5t34 -27.5l14 -8q0 3 9.5 39.5t5.5 57.5 q-4 23 14.5 44.5t22.5 31.5q5 14 10 35t8.5 31t15.5 22.5t34 21.5q-6 18 10 37q8 0 23.5 -1.5t24.5 -1.5t20.5 4.5t20.5 15.5q-10 23 -30.5 42.5t-38 30t-49 26.5t-43.5 23q11 39 2 44q31 -13 58 -14.5t39 3.5l11 4q7 36 -16.5 53.5t-64.5 28.5t-56 23q-19 -3 -37 0 q-15 -12 -36.5 -21t-34.5 -12t-44 -8t-39 -6q-15 -3 -45.5 0.5t-45.5 -2.5q-21 -7 -52 -26.5t-34 -34.5q-3 -11 6.5 -22.5t8.5 -18.5q-3 -34 -27.5 -90.5t-29.5 -79.5zM518 916q3 12 16 30t16 25q10 -10 18.5 -10t14 6t14.5 14.5t16 12.5q0 -24 17 -66.5t17 -43.5 q-9 2 -31 5t-36 5t-32 8t-30 14zM692 1003h1h-1z" />
|
||||
<glyph unicode="" d="M0 164.5q0 21.5 15 37.5l600 599q-33 101 6 201.5t135 154.5q164 92 306 -9l-259 -138l145 -232l251 126q13 -175 -151 -267q-123 -70 -253 -23l-596 -596q-15 -16 -36.5 -16t-36.5 16l-111 110q-15 15 -15 36.5z" />
|
||||
<glyph unicode="" horiz-adv-x="1220" d="M0 196v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 596v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000 q-41 0 -70.5 29.5t-29.5 70.5zM0 996v100q0 41 29.5 70.5t70.5 29.5h1000q41 0 70.5 -29.5t29.5 -70.5v-100q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM600 596h500v100h-500v-100zM800 196h300v100h-300v-100zM900 996h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M100 1100v100h1000v-100h-1000zM150 1000h900l-350 -500v-300l-200 -200v500z" />
|
||||
<glyph unicode="" d="M0 200v200h1200v-200q0 -41 -29.5 -70.5t-70.5 -29.5h-1000q-41 0 -70.5 29.5t-29.5 70.5zM0 500v400q0 41 29.5 70.5t70.5 29.5h300v100q0 41 29.5 70.5t70.5 29.5h200q41 0 70.5 -29.5t29.5 -70.5v-100h300q41 0 70.5 -29.5t29.5 -70.5v-400h-500v100h-200v-100h-500z M500 1000h200v100h-200v-100z" />
|
||||
<glyph unicode="" d="M0 0v400l129 -129l200 200l142 -142l-200 -200l129 -129h-400zM0 800l129 129l200 -200l142 142l-200 200l129 129h-400v-400zM729 329l142 142l200 -200l129 129v-400h-400l129 129zM729 871l200 200l-129 129h400v-400l-129 129l-200 -200z" />
|
||||
<glyph unicode="" d="M0 596q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 596q0 -172 121.5 -293t292.5 -121t292.5 121t121.5 293q0 171 -121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM291 655 q0 23 15.5 38.5t38.5 15.5t39 -16t16 -38q0 -23 -16 -39t-39 -16q-22 0 -38 16t-16 39zM400 850q0 22 16 38.5t39 16.5q22 0 38 -16t16 -39t-16 -39t-38 -16q-23 0 -39 16.5t-16 38.5zM514 609q0 32 20.5 56.5t51.5 29.5l122 126l1 1q-9 14 -9 28q0 22 16 38.5t39 16.5 q22 0 38 -16t16 -39t-16 -39t-38 -16q-14 0 -29 10l-55 -145q17 -22 17 -51q0 -36 -25.5 -61.5t-61.5 -25.5t-61.5 25.5t-25.5 61.5zM800 655q0 22 16 38t39 16t38.5 -15.5t15.5 -38.5t-16 -39t-38 -16q-23 0 -39 16t-16 39z" />
|
||||
<glyph unicode="" d="M-40 375q-13 -95 35 -173q35 -57 94 -89t129 -32q63 0 119 28q33 16 65 40.5t52.5 45.5t59.5 64q40 44 57 61l394 394q35 35 47 84t-3 96q-27 87 -117 104q-20 2 -29 2q-46 0 -78.5 -16.5t-67.5 -51.5l-389 -396l-7 -7l69 -67l377 373q20 22 39 38q23 23 50 23 q38 0 53 -36q16 -39 -20 -75l-547 -547q-52 -52 -125 -52q-55 0 -100 33t-54 96q-5 35 2.5 66t31.5 63t42 50t56 54q24 21 44 41l348 348q52 52 82.5 79.5t84 54t107.5 26.5q25 0 48 -4q95 -17 154 -94.5t51 -175.5q-7 -101 -98 -192l-252 -249l-253 -256l7 -7l69 -60 l517 511q67 67 95 157t11 183q-16 87 -67 154t-130 103q-69 33 -152 33q-107 0 -197 -55q-40 -24 -111 -95l-512 -512q-68 -68 -81 -163z" />
|
||||
<glyph unicode="" d="M80 784q0 131 98.5 229.5t230.5 98.5q143 0 241 -129q103 129 246 129q129 0 226 -98.5t97 -229.5q0 -46 -17.5 -91t-61 -99t-77 -89.5t-104.5 -105.5q-197 -191 -293 -322l-17 -23l-16 23q-43 58 -100 122.5t-92 99.5t-101 100q-71 70 -104.5 105.5t-77 89.5t-61 99 t-17.5 91zM250 784q0 -27 30.5 -70t61.5 -75.5t95 -94.5l22 -22q93 -90 190 -201q82 92 195 203l12 12q64 62 97.5 97t64.5 79t31 72q0 71 -48 119.5t-105 48.5q-74 0 -132 -83l-118 -171l-114 174q-51 80 -123 80q-60 0 -109.5 -49.5t-49.5 -118.5z" />
|
||||
<glyph unicode="" d="M57 353q0 -95 66 -159l141 -142q68 -66 159 -66q93 0 159 66l283 283q66 66 66 159t-66 159l-141 141q-8 9 -19 17l-105 -105l212 -212l-389 -389l-247 248l95 95l-18 18q-46 45 -75 101l-55 -55q-66 -66 -66 -159zM269 706q0 -93 66 -159l141 -141q7 -7 19 -17l105 105 l-212 212l389 389l247 -247l-95 -96l18 -17q47 -49 77 -100l29 29q35 35 62.5 88t27.5 96q0 93 -66 159l-141 141q-66 66 -159 66q-95 0 -159 -66l-283 -283q-66 -64 -66 -159z" />
|
||||
<glyph unicode="" d="M200 100v953q0 21 30 46t81 48t129 38t163 15t162 -15t127 -38t79 -48t29 -46v-953q0 -41 -29.5 -70.5t-70.5 -29.5h-600q-41 0 -70.5 29.5t-29.5 70.5zM300 300h600v700h-600v-700zM496 150q0 -43 30.5 -73.5t73.5 -30.5t73.5 30.5t30.5 73.5t-30.5 73.5t-73.5 30.5 t-73.5 -30.5t-30.5 -73.5z" />
|
||||
<glyph unicode="" d="M0 0l303 380l207 208l-210 212h300l267 279l-35 36q-15 14 -15 35t15 35q14 15 35 15t35 -15l283 -282q15 -15 15 -36t-15 -35q-14 -15 -35 -15t-35 15l-36 35l-279 -267v-300l-212 210l-208 -207z" />
|
||||
<glyph unicode="" d="M295 433h139q5 -77 48.5 -126.5t117.5 -64.5v335q-6 1 -15.5 4t-11.5 3q-46 14 -79 26.5t-72 36t-62.5 52t-40 72.5t-16.5 99q0 92 44 159.5t109 101t144 40.5v78h100v-79q38 -4 72.5 -13.5t75.5 -31.5t71 -53.5t51.5 -84t24.5 -118.5h-159q-8 72 -35 109.5t-101 50.5 v-307l64 -14q34 -7 64 -16.5t70 -31.5t67.5 -52t47.5 -80.5t20 -112.5q0 -139 -89 -224t-244 -96v-77h-100v78q-152 17 -237 104q-40 40 -52.5 93.5t-15.5 139.5zM466 889q0 -29 8 -51t16.5 -34t29.5 -22.5t31 -13.5t38 -10q7 -2 11 -3v274q-61 -8 -97.5 -37.5t-36.5 -102.5 zM700 237q170 18 170 151q0 64 -44 99.5t-126 60.5v-311z" />
|
||||
<glyph unicode="" d="M100 600v100h166q-24 49 -44 104q-10 26 -14.5 55.5t-3 72.5t25 90t68.5 87q97 88 263 88q129 0 230 -89t101 -208h-153q0 52 -34 89.5t-74 51.5t-76 14q-37 0 -79 -14.5t-62 -35.5q-41 -44 -41 -101q0 -28 16.5 -69.5t28 -62.5t41.5 -72h241v-100h-197q8 -50 -2.5 -115 t-31.5 -94q-41 -59 -99 -113q35 11 84 18t70 7q33 1 103 -16t103 -17q76 0 136 30l50 -147q-41 -25 -80.5 -36.5t-59 -13t-61.5 -1.5q-23 0 -128 33t-155 29q-39 -4 -82 -17t-66 -25l-24 -11l-55 145l16.5 11t15.5 10t13.5 9.5t14.5 12t14.5 14t17.5 18.5q48 55 54 126.5 t-30 142.5h-221z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM602 900l298 300l298 -300h-198v-900h-200v900h-198z" />
|
||||
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v200h100v-100h200v-100h-300zM700 400v100h300v-200h-99v-100h-100v100h99v100h-200zM700 700v500h300v-500h-100v100h-100v-100h-100zM801 900h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300h198v900h200v-900h198l-298 -300zM700 0v500h300v-500h-100v100h-100v-100h-100zM700 700v200h100v-100h200v-100h-300zM700 1100v100h300v-200h-99v-100h-100v100h99v100h-200zM801 200h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 100v400h300v-500h-100v100h-200zM800 1100v100h200v-500h-100v400h-100zM901 200h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM800 400v100h200v-500h-100v400h-100zM800 800v400h300v-500h-100v100h-200zM901 900h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h500v-200h-500zM700 400v200h400v-200h-400zM700 700v200h300v-200h-300zM700 1000v200h200v-200h-200z" />
|
||||
<glyph unicode="" d="M2 300l298 -300l298 300h-198v900h-200v-900h-198zM700 100v200h200v-200h-200zM700 400v200h300v-200h-300zM700 700v200h400v-200h-400zM700 1000v200h500v-200h-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q162 0 281 -118.5t119 -281.5v-300q0 -165 -118.5 -282.5t-281.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 163 119 281.5t281 118.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-163 0 -281.5 117.5t-118.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM400 300l333 250l-333 250v-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 163 117.5 281.5t282.5 118.5h300q163 0 281.5 -119t118.5 -281v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-300q-165 0 -282.5 117.5t-117.5 282.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 700l250 -333l250 333h-500z" />
|
||||
<glyph unicode="" d="M0 400v300q0 165 117.5 282.5t282.5 117.5h300q165 0 282.5 -117.5t117.5 -282.5v-300q0 -162 -118.5 -281t-281.5 -119h-300q-165 0 -282.5 118.5t-117.5 281.5zM200 300q0 -41 29.5 -70.5t70.5 -29.5h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5 h-500q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM300 400h500l-250 333z" />
|
||||
<glyph unicode="" d="M0 400v300h300v200l400 -350l-400 -350v200h-300zM500 0v200h500q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-500v200h400q165 0 282.5 -117.5t117.5 -282.5v-300q0 -165 -117.5 -282.5t-282.5 -117.5h-400z" />
|
||||
<glyph unicode="" d="M217 519q8 -19 31 -19h302q-155 -438 -160 -458q-5 -21 4 -32l9 -8h9q14 0 26 15q11 13 274.5 321.5t264.5 308.5q14 19 5 36q-8 17 -31 17l-301 -1q1 4 78 219.5t79 227.5q2 15 -5 27l-9 9h-9q-15 0 -25 -16q-4 -6 -98 -111.5t-228.5 -257t-209.5 -237.5q-16 -19 -6 -41 z" />
|
||||
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q47 0 100 15v185h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h500v185q-14 4 -114 7.5t-193 5.5l-93 2q-165 0 -282.5 -117.5t-117.5 -282.5v-300zM600 400v300h300v200l400 -350l-400 -350v200h-300z " />
|
||||
<glyph unicode="" d="M0 400q0 -165 117.5 -282.5t282.5 -117.5h300q163 0 281.5 117.5t118.5 282.5v98l-78 73l-122 -123v-148q0 -41 -29.5 -70.5t-70.5 -29.5h-500q-41 0 -70.5 29.5t-29.5 70.5v500q0 41 29.5 70.5t70.5 29.5h156l118 122l-74 78h-100q-165 0 -282.5 -117.5t-117.5 -282.5 v-300zM496 709l353 342l-149 149h500v-500l-149 149l-342 -353z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM406 600 q0 80 57 137t137 57t137 -57t57 -137t-57 -137t-137 -57t-137 57t-57 137z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 800l445 -500l450 500h-295v400h-300v-400h-300zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 700h300v-300h300v300h295l-445 500zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 705l305 -305l596 596l-154 155l-442 -442l-150 151zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM100 988l97 -98l212 213l-97 97zM200 400l697 1l3 699l-250 -239l-149 149l-212 -212l149 -149zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M0 0v275q0 11 7 18t18 7h1048q11 0 19 -7.5t8 -17.5v-275h-1100zM200 612l212 -212l98 97l-213 212zM300 1200l239 -250l-149 -149l212 -212l149 148l249 -237l-1 697zM900 150h100v50h-100v-50z" />
|
||||
<glyph unicode="" d="M23 415l1177 784v-1079l-475 272l-310 -393v416h-392zM494 210l672 938l-672 -712v-226z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-850q0 -21 -15 -35.5t-35 -14.5h-150v400h-700v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-218l-276 -275l-120 120l-126 -127h-378v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM581 306l123 123l120 -120l353 352l123 -123l-475 -476zM600 1000h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-269l-103 -103l-170 170l-298 -298h-329v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 1000h100v200h-100v-200zM700 133l170 170l-170 170l127 127l170 -170l170 170l127 -128l-170 -169l170 -170 l-127 -127l-170 170l-170 -170z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-300h-400v-200h-500v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300l300 -300l300 300h-200v300h-200v-300h-200zM600 1000v200h100v-200h-100z" />
|
||||
<glyph unicode="" d="M0 150v1000q0 20 14.5 35t35.5 15h250v-300h500v300h100l200 -200v-402l-200 200l-298 -298h-402v-400h-150q-21 0 -35.5 14.5t-14.5 35.5zM600 300h200v-300h200v300h200l-300 300zM600 1000v200h100v-200h-100z" />
|
||||
<glyph unicode="" d="M0 250q0 -21 14.5 -35.5t35.5 -14.5h1100q21 0 35.5 14.5t14.5 35.5v550h-1200v-550zM0 900h1200v150q0 21 -14.5 35.5t-35.5 14.5h-1100q-21 0 -35.5 -14.5t-14.5 -35.5v-150zM100 300v200h400v-200h-400z" />
|
||||
<glyph unicode="" d="M0 400l300 298v-198h400v-200h-400v-198zM100 800v200h100v-200h-100zM300 800v200h100v-200h-100zM500 800v200h400v198l300 -298l-300 -298v198h-400zM800 300v200h100v-200h-100zM1000 300h100v200h-100v-200z" />
|
||||
<glyph unicode="" d="M100 700v400l50 100l50 -100v-300h100v300l50 100l50 -100v-300h100v300l50 100l50 -100v-400l-100 -203v-447q0 -21 -14.5 -35.5t-35.5 -14.5h-200q-21 0 -35.5 14.5t-14.5 35.5v447zM800 597q0 -29 10.5 -55.5t25 -43t29 -28.5t25.5 -18l10 -5v-397q0 -21 14.5 -35.5 t35.5 -14.5h200q21 0 35.5 14.5t14.5 35.5v1106q0 31 -18 40.5t-44 -7.5l-276 -116q-25 -17 -43.5 -51.5t-18.5 -65.5v-359z" />
|
||||
<glyph unicode="" d="M100 0h400v56q-75 0 -87.5 6t-12.5 44v394h500v-394q0 -38 -12.5 -44t-87.5 -6v-56h400v56q-4 0 -11 0.5t-24 3t-30 7t-24 15t-11 24.5v888q0 22 25 34.5t50 13.5l25 2v56h-400v-56q75 0 87.5 -6t12.5 -44v-394h-500v394q0 38 12.5 44t87.5 6v56h-400v-56q4 0 11 -0.5 t24 -3t30 -7t24 -15t11 -24.5v-888q0 -22 -25 -34.5t-50 -13.5l-25 -2v-56z" />
|
||||
<glyph unicode="" d="M0 300q0 -41 29.5 -70.5t70.5 -29.5h300q41 0 70.5 29.5t29.5 70.5v500q0 41 -29.5 70.5t-70.5 29.5h-300q-41 0 -70.5 -29.5t-29.5 -70.5v-500zM100 100h400l200 200h105l295 98v-298h-425l-100 -100h-375zM100 300v200h300v-200h-300zM100 600v200h300v-200h-300z M100 1000h400l200 -200v-98l295 98h105v200h-425l-100 100h-375zM700 402v163l400 133v-163z" />
|
||||
<glyph unicode="" d="M16.5 974.5q0.5 -21.5 16 -90t46.5 -140t104 -177.5t175 -208q103 -103 207.5 -176t180 -103.5t137 -47t92.5 -16.5l31 1l163 162q17 18 13.5 41t-22.5 37l-192 136q-19 14 -45 12t-42 -19l-118 -118q-142 101 -268 227t-227 268l118 118q17 17 20 41.5t-11 44.5 l-139 194q-14 19 -36.5 22t-40.5 -14l-162 -162q-1 -11 -0.5 -32.5z" />
|
||||
<glyph unicode="" d="M0 50v212q0 20 10.5 45.5t24.5 39.5l365 303v50q0 4 1 10.5t12 22.5t30 28.5t60 23t97 10.5t97 -10t60 -23.5t30 -27.5t12 -24l1 -10v-50l365 -303q14 -14 24.5 -39.5t10.5 -45.5v-212q0 -21 -14.5 -35.5t-35.5 -14.5h-1100q-20 0 -35 14.5t-15 35.5zM0 712 q0 -21 14.5 -33.5t34.5 -8.5l202 33q20 4 34.5 21t14.5 38v146q141 24 300 24t300 -24v-146q0 -21 14.5 -38t34.5 -21l202 -33q20 -4 34.5 8.5t14.5 33.5v200q-6 8 -19 20.5t-63 45t-112 57t-171 45t-235 20.5q-92 0 -175 -10.5t-141.5 -27t-108.5 -36.5t-81.5 -40 t-53.5 -36.5t-31 -27.5l-9 -10v-200z" />
|
||||
<glyph unicode="" d="M100 0v100h1100v-100h-1100zM175 200h950l-125 150v250l100 100v400h-100v-200h-100v200h-200v-200h-100v200h-200v-200h-100v200h-100v-400l100 -100v-250z" />
|
||||
<glyph unicode="" d="M100 0h300v400q0 41 -29.5 70.5t-70.5 29.5h-100q-41 0 -70.5 -29.5t-29.5 -70.5v-400zM500 0v1000q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-1000h-300zM900 0v700q0 41 29.5 70.5t70.5 29.5h100q41 0 70.5 -29.5t29.5 -70.5v-700h-300z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h100v200h100v-200h100v500h-100v-200h-100v200h-100v-500zM600 300h200v100h100v300h-100v100h-200v-500 zM700 400v300h100v-300h-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v100h-200v300h200v100h-300v-500zM600 300h300v100h-200v300h200v100h-300v-500z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 550l300 -150v300zM600 400l300 150l-300 150v-300z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300v500h700v-500h-700zM300 400h130q41 0 68 42t27 107t-28.5 108t-66.5 43h-130v-300zM575 549 q0 -65 27 -107t68 -42h130v300h-130q-38 0 -66.5 -43t-28.5 -108z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v300h-200v100h200v100h-300v-300h200v-100h-200v-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 300h300v400h-200v100h-100v-500zM301 400v200h100v-200h-100zM601 300h100v100h-100v-100zM700 700h100 v-400h100v500h-200v-100z" />
|
||||
<glyph unicode="" d="M-100 300v500q0 124 88 212t212 88h700q124 0 212 -88t88 -212v-500q0 -124 -88 -212t-212 -88h-700q-124 0 -212 88t-88 212zM100 200h900v700h-900v-700zM200 700v100h300v-300h-99v-100h-100v100h99v200h-200zM201 300v100h100v-100h-100zM601 300v100h100v-100h-100z M700 700v100h200v-500h-100v400h-100z" />
|
||||
<glyph unicode="" d="M4 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM186 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 500v200 l100 100h300v-100h-300v-200h300v-100h-300z" />
|
||||
<glyph unicode="" d="M0 600q0 162 80 299t217 217t299 80t299 -80t217 -217t80 -299t-80 -299t-217 -217t-299 -80t-299 80t-217 217t-80 299zM182 600q0 -171 121.5 -292.5t292.5 -121.5t292.5 121.5t121.5 292.5t-121.5 292.5t-292.5 121.5t-292.5 -121.5t-121.5 -292.5zM400 400v400h300 l100 -100v-100h-100v100h-200v-100h200v-100h-200v-100h-100zM700 400v100h100v-100h-100z" />
|
||||
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h222v300h400v-300h128q120 0 205 86.5t85 207.5t-85 207t-205 86q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200h200v300h200v-300h200 l-300 -300z" />
|
||||
<glyph unicode="" d="M-14 494q0 -80 56.5 -137t135.5 -57h8l414 414l403 -403q94 26 154.5 104.5t60.5 178.5q0 120 -85 206.5t-205 86.5q-46 0 -90 -14q-44 97 -134.5 156.5t-200.5 59.5q-152 0 -260 -107.5t-108 -260.5q0 -25 2 -37q-66 -14 -108.5 -67.5t-42.5 -122.5zM300 200l300 300 l300 -300h-200v-300h-200v300h-200z" />
|
||||
<glyph unicode="" d="M100 200h400v-155l-75 -45h350l-75 45v155h400l-270 300h170l-270 300h170l-300 333l-300 -333h170l-270 -300h170z" />
|
||||
<glyph unicode="" d="M121 700q0 -53 28.5 -97t75.5 -65q-4 -16 -4 -38q0 -74 52.5 -126.5t126.5 -52.5q56 0 100 30v-306l-75 -45h350l-75 45v306q46 -30 100 -30q74 0 126.5 52.5t52.5 126.5q0 24 -9 55q50 32 79.5 83t29.5 112q0 90 -61.5 155.5t-150.5 71.5q-26 89 -99.5 145.5 t-167.5 56.5q-116 0 -197.5 -81.5t-81.5 -197.5q0 -4 1 -11.5t1 -11.5q-14 2 -23 2q-74 0 -126.5 -52.5t-52.5 -126.5z" />
|
||||
</font>
|
||||
</defs></svg>
|
||||
|
After Width: | Height: | Size: 62 KiB |
BIN
assets/bootstrap/fonts/glyphicons-halflings-regular.ttf
Normal file
BIN
assets/bootstrap/fonts/glyphicons-halflings-regular.woff
Normal file
1951
assets/bootstrap/js/bootstrap.js
vendored
Normal file
6
assets/bootstrap/js/bootstrap.min.js
vendored
Normal file
220
assets/css/bootstrap-ie7.css
vendored
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12,.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12,.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12,.input-group,.row,.content{box-sizing:border-box;behavior:url(/js/boxsizing.htc)}
|
||||
audio,canvas,video{display:inline;zoom:1}
|
||||
html{font-size:100%}
|
||||
img{width:auto;height:auto;-ms-interpolation-mode:bicubic}
|
||||
button,input{overflow:visible}
|
||||
.container{zoom:1}
|
||||
.row{zoom:1}
|
||||
.dl-horizontal{zoom:1}
|
||||
input[type="radio"],input[type="checkbox"]{margin-top:0}
|
||||
.help-block{display:inline;zoom:1}
|
||||
.form-horizontal .form-group{zoom:1}
|
||||
.dropdown-toggle{margin-bottom:-3px}
|
||||
.dropdown-menu .divider{width:100%;margin:-5px 0 5px}
|
||||
.list-group{margin-left:0}
|
||||
ul .list-group-item{list-style:none}
|
||||
.sr-only{clip:rect(0 0 0 0)}
|
||||
.list-inline > li{display:inline;zoom:1}
|
||||
.glyphicon{text-decoration:inherit;line-height:normal}
|
||||
.glyphicon-adjust{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-align-center{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-align-justify{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-align-left{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-align-right{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-arrow-down{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-arrow-left{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-arrow-right{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-arrow-up{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-asterisk{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='*')}
|
||||
.glyphicon-backward{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-ban-circle{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-barcode{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-bell{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-bold{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-book{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-bookmark{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-briefcase{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-bullhorn{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-calendar{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-camera{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-certificate{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-check{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-chevron-down{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-chevron-left{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-chevron-right{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-chevron-up{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-circle-arrow-down{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-circle-arrow-left{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-circle-arrow-right{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-circle-arrow-up{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-cloud{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='☁')}
|
||||
.glyphicon-cloud-download{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-cloud-upload{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-cog{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-collapse{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-collapse-down{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-collapse-top{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-collapse-up{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-comment{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-compressed{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-copyright-mark{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-credit-card{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-cutlery{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-dashboard{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-download{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-download-alt{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-earphone{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-edit{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-eject{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-envelope{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='✉')}
|
||||
.glyphicon-euro{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='€')}
|
||||
.glyphicon-exclamation-sign{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-expand{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-export{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-eye-close{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-eye-open{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-facetime-video{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-fast-backward{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-fast-forward{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-file{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-film{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-filter{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-fire{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-flag{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-flash{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-floppy-disk{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-floppy-open{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-floppy-remove{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-floppy-save{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-floppy-saved{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-folder-close{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-folder-open{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-font{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-forward{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-fullscreen{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-gbp{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-gift{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-glass{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-globe{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-hand-down{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-hand-left{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-hand-right{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-hand-up{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-hdd{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-hd-video{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-header{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-headphones{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-heart{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-heart-empty{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-home{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-import{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-inbox{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-indent-left{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-indent-right{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-info-sign{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-italic{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-leaf{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-link{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-list{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-list-alt{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-lock{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-log-in{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-log-out{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-magnet{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-map-marker{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-minus{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='−')}
|
||||
.glyphicon-minus-sign{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-move{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-music{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-new-window{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-off{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-ok{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-ok-circle{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-ok-sign{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-open{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-paperclip{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-pause{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-pencil{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='✏')}
|
||||
.glyphicon-phone{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-phone-alt{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-picture{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-plane{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-play{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-play-circle{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-plus{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='+')}
|
||||
.glyphicon-plus-sign{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-print{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-pushpin{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-qrcode{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-question-sign{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-random{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-record{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-refresh{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-registration-mark{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-remove{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-remove-circle{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-remove-sign{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-repeat{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-resize-full{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-resize-horizontal{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-resize-small{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-resize-vertical{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-retweet{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-road{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-save{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-saved{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-screenshot{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-sd-video{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-search{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-send{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-share{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-share-alt{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-shopping-cart{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-signal{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-sort{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-sort-by-alphabet{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-sort-by-alphabet-alt{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-sort-by-attributes{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-sort-by-attributes-alt{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-sort-by-order{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-sort-by-order-alt{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-sound-5-1{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-sound-6-1{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-sound-7-1{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-sound-dolby{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-sound-stereo{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-star{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-star-empty{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-stats{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-step-backward{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-step-forward{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-stop{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-subtitles{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-tag{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-tags{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-tasks{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-text-height{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-text-width{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-th{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-th-large{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-th-list{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-thumbs-down{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-thumbs-up{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-time{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-tint{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-tower{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-transfer{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-trash{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-tree-conifer{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-tree-deciduous{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-unchecked{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-upload{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-usd{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-user{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-volume-down{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-volume-off{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-volume-up{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-warning-sign{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-wrench{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-zoom-in{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
.glyphicon-zoom-out{zoom:expression(this.runtimeStyle['zoom']='1',this.innerHTML='')}
|
||||
159
assets/css/custom.css
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
body {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
line-height: 1.8em;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: 'Lora', serif;
|
||||
font-style: italic;
|
||||
margin-top: 1.4em;
|
||||
}
|
||||
|
||||
a, a:hover {
|
||||
color: #F64747;
|
||||
}
|
||||
|
||||
aside {
|
||||
background: #F64747;
|
||||
margin: -20px 0 0 0;
|
||||
}
|
||||
|
||||
aside .sidebar {
|
||||
padding: 30px 15px;
|
||||
text-align: center;
|
||||
color: white;
|
||||
}
|
||||
|
||||
aside .sidebar a {
|
||||
color: white;
|
||||
font-family: Lora, sans-serif;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
aside .sidebar a:hover {
|
||||
text-decoration: underline;
|
||||
background: none;
|
||||
}
|
||||
|
||||
aside .sidebar .logo {
|
||||
max-height: 140px;
|
||||
margin: 30px 0;
|
||||
}
|
||||
|
||||
main {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
footer {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
fieldset legend {
|
||||
font-family: 'Lora', serif;
|
||||
font-style: italic;
|
||||
border-bottom: 0px;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
border-left: 0px;
|
||||
font-size: 16px;
|
||||
color: rgba(0, 0, 0, 0.7);
|
||||
background: url(/static/images/loveletter.png) no-repeat;
|
||||
background-size: 20%;
|
||||
background-position: 0 20px;
|
||||
padding-left: calc(20% + 20px);
|
||||
min-height: 120px;
|
||||
}
|
||||
|
||||
.centered {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: white;
|
||||
border: 1px solid #F64747;
|
||||
color: #F64747;
|
||||
text-transform: uppercase;
|
||||
padding: 0.9em 1.3em;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #F64747;
|
||||
color: white;
|
||||
border: 1px solid #F64747;
|
||||
}
|
||||
|
||||
.row.content {
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.lead {
|
||||
line-height: 1.8em;
|
||||
}
|
||||
|
||||
.asteriskField {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#div_id_hp {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#faq h3 {
|
||||
margin-top: 2em;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
aside {
|
||||
width: 25%;
|
||||
height: calc(100% + 20px);
|
||||
position: fixed;
|
||||
background: -moz-linear-gradient(top, #F23030 0%, #f64747 27%, #f64747 27%, #F23030 100%);
|
||||
background: -webkit-linear-gradient(top, #F23030 0%,#f64747 27%,#f64747 27%,#F23030 100%);
|
||||
background: linear-gradient(to bottom, #F23030 0%,#f64747 27%,#f64747 27%,#F23030 100%);
|
||||
}
|
||||
|
||||
aside .sidebar {
|
||||
max-width: 300px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
aside .sidebar .logo {
|
||||
max-width: 90%;
|
||||
max-height: 300px;
|
||||
}
|
||||
|
||||
main {
|
||||
margin-left: 25%;
|
||||
}
|
||||
|
||||
main .container {
|
||||
padding: 0px 50px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
min-height: 130px;
|
||||
}
|
||||
|
||||
.row.content {
|
||||
min-height: 500px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1530px) {
|
||||
blockquote {
|
||||
min-height: 170px;
|
||||
}
|
||||
}
|
||||
|
||||
.emoji {
|
||||
vertical-align: initial;
|
||||
}
|
||||
182
assets/css/datepicker.css
Executable file
|
|
@ -0,0 +1,182 @@
|
|||
/*!
|
||||
* Datepicker for Bootstrap
|
||||
*
|
||||
* Copyright 2012 Stefan Petre
|
||||
* Licensed under the Apache License v2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*/
|
||||
.datepicker {
|
||||
top: 0;
|
||||
left: 0;
|
||||
padding: 4px;
|
||||
margin-top: 1px;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
/*.dow {
|
||||
border-top: 1px solid #ddd !important;
|
||||
}*/
|
||||
|
||||
}
|
||||
.datepicker:before {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
border-left: 7px solid transparent;
|
||||
border-right: 7px solid transparent;
|
||||
border-bottom: 7px solid #ccc;
|
||||
border-bottom-color: rgba(0, 0, 0, 0.2);
|
||||
position: absolute;
|
||||
top: -7px;
|
||||
left: 6px;
|
||||
}
|
||||
.datepicker:after {
|
||||
content: '';
|
||||
display: inline-block;
|
||||
border-left: 6px solid transparent;
|
||||
border-right: 6px solid transparent;
|
||||
border-bottom: 6px solid #ffffff;
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
left: 7px;
|
||||
}
|
||||
.datepicker > div {
|
||||
display: none;
|
||||
}
|
||||
.datepicker table {
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
.datepicker td,
|
||||
.datepicker th {
|
||||
text-align: center;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.datepicker td.day:hover {
|
||||
background: #eeeeee;
|
||||
cursor: pointer;
|
||||
}
|
||||
.datepicker td.day.disabled {
|
||||
color: #eeeeee;
|
||||
}
|
||||
.datepicker td.old,
|
||||
.datepicker td.new {
|
||||
color: #999999;
|
||||
}
|
||||
.datepicker td.active,
|
||||
.datepicker td.active:hover {
|
||||
color: #ffffff;
|
||||
background-color: #006dcc;
|
||||
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
|
||||
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: linear-gradient(to bottom, #0088cc, #0044cc);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);
|
||||
border-color: #0044cc #0044cc #002a80;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
*background-color: #0044cc;
|
||||
/* Darken IE7 buttons by default so they stand out more given they won't have borders */
|
||||
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.datepicker td.active:hover,
|
||||
.datepicker td.active:hover:hover,
|
||||
.datepicker td.active:focus,
|
||||
.datepicker td.active:hover:focus,
|
||||
.datepicker td.active:active,
|
||||
.datepicker td.active:hover:active,
|
||||
.datepicker td.active.active,
|
||||
.datepicker td.active:hover.active,
|
||||
.datepicker td.active.disabled,
|
||||
.datepicker td.active:hover.disabled,
|
||||
.datepicker td.active[disabled],
|
||||
.datepicker td.active:hover[disabled] {
|
||||
color: #ffffff;
|
||||
background-color: #0044cc;
|
||||
*background-color: #003bb3;
|
||||
}
|
||||
.datepicker td.active:active,
|
||||
.datepicker td.active:hover:active,
|
||||
.datepicker td.active.active,
|
||||
.datepicker td.active:hover.active {
|
||||
background-color: #003399 \9;
|
||||
}
|
||||
.datepicker td span {
|
||||
display: block;
|
||||
width: 47px;
|
||||
height: 54px;
|
||||
line-height: 54px;
|
||||
float: left;
|
||||
margin: 2px;
|
||||
cursor: pointer;
|
||||
-webkit-border-radius: 4px;
|
||||
-moz-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.datepicker td span:hover {
|
||||
background: #eeeeee;
|
||||
}
|
||||
.datepicker td span.active {
|
||||
color: #ffffff;
|
||||
background-color: #006dcc;
|
||||
background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
|
||||
background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: -o-linear-gradient(top, #0088cc, #0044cc);
|
||||
background-image: linear-gradient(to bottom, #0088cc, #0044cc);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);
|
||||
border-color: #0044cc #0044cc #002a80;
|
||||
border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
|
||||
*background-color: #0044cc;
|
||||
/* Darken IE7 buttons by default so they stand out more given they won't have borders */
|
||||
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
|
||||
color: #fff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
.datepicker td span.active:hover,
|
||||
.datepicker td span.active:focus,
|
||||
.datepicker td span.active:active,
|
||||
.datepicker td span.active.active,
|
||||
.datepicker td span.active.disabled,
|
||||
.datepicker td span.active[disabled] {
|
||||
color: #ffffff;
|
||||
background-color: #0044cc;
|
||||
*background-color: #003bb3;
|
||||
}
|
||||
.datepicker td span.active:active,
|
||||
.datepicker td span.active.active {
|
||||
background-color: #003399 \9;
|
||||
}
|
||||
.datepicker td span.old {
|
||||
color: #999999;
|
||||
}
|
||||
.datepicker th.switch {
|
||||
width: 145px;
|
||||
}
|
||||
.datepicker th.next,
|
||||
.datepicker th.prev {
|
||||
font-size: 21px;
|
||||
}
|
||||
.datepicker thead tr:first-child th {
|
||||
cursor: pointer;
|
||||
}
|
||||
.datepicker thead tr:first-child th:hover {
|
||||
background: #eeeeee;
|
||||
}
|
||||
.input-append.date .add-on i,
|
||||
.input-prepend.date .add-on i {
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
BIN
assets/images/emoji/loveletter.png
Normal file
|
After Width: | Height: | Size: 239 B |
BIN
assets/images/favicon.ico
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
assets/images/logo.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/images/loveletter.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
474
assets/js/vendor/bootstrap-datepicker.js
vendored
Executable file
|
|
@ -0,0 +1,474 @@
|
|||
/* =========================================================
|
||||
* bootstrap-datepicker.js
|
||||
* http://www.eyecon.ro/bootstrap-datepicker
|
||||
* =========================================================
|
||||
* Copyright 2012 Stefan Petre
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ========================================================= */
|
||||
|
||||
!function( $ ) {
|
||||
|
||||
// Picker object
|
||||
|
||||
var Datepicker = function(element, options){
|
||||
this.element = $(element);
|
||||
this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||'mm/dd/yyyy');
|
||||
this.picker = $(DPGlobal.template)
|
||||
.appendTo('body')
|
||||
.on({
|
||||
click: $.proxy(this.click, this)//,
|
||||
//mousedown: $.proxy(this.mousedown, this)
|
||||
});
|
||||
this.isInput = this.element.is('input');
|
||||
this.component = this.element.is('.date') ? this.element.find('.add-on') : false;
|
||||
|
||||
if (this.isInput) {
|
||||
this.element.on({
|
||||
focus: $.proxy(this.show, this),
|
||||
//blur: $.proxy(this.hide, this),
|
||||
keyup: $.proxy(this.update, this)
|
||||
});
|
||||
} else {
|
||||
if (this.component){
|
||||
this.component.on('click', $.proxy(this.show, this));
|
||||
} else {
|
||||
this.element.on('click', $.proxy(this.show, this));
|
||||
}
|
||||
}
|
||||
|
||||
this.minViewMode = options.minViewMode||this.element.data('date-minviewmode')||0;
|
||||
if (typeof this.minViewMode === 'string') {
|
||||
switch (this.minViewMode) {
|
||||
case 'months':
|
||||
this.minViewMode = 1;
|
||||
break;
|
||||
case 'years':
|
||||
this.minViewMode = 2;
|
||||
break;
|
||||
default:
|
||||
this.minViewMode = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.viewMode = options.viewMode||this.element.data('date-viewmode')||0;
|
||||
if (typeof this.viewMode === 'string') {
|
||||
switch (this.viewMode) {
|
||||
case 'months':
|
||||
this.viewMode = 1;
|
||||
break;
|
||||
case 'years':
|
||||
this.viewMode = 2;
|
||||
break;
|
||||
default:
|
||||
this.viewMode = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.startViewMode = this.viewMode;
|
||||
this.weekStart = options.weekStart||this.element.data('date-weekstart')||0;
|
||||
this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
|
||||
this.onRender = options.onRender;
|
||||
this.fillDow();
|
||||
this.fillMonths();
|
||||
this.update();
|
||||
this.showMode();
|
||||
};
|
||||
|
||||
Datepicker.prototype = {
|
||||
constructor: Datepicker,
|
||||
|
||||
show: function(e) {
|
||||
this.picker.show();
|
||||
this.height = this.component ? this.component.outerHeight() : this.element.outerHeight();
|
||||
this.place();
|
||||
$(window).on('resize', $.proxy(this.place, this));
|
||||
if (e ) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
}
|
||||
if (!this.isInput) {
|
||||
}
|
||||
var that = this;
|
||||
$(document).on('mousedown', function(ev){
|
||||
if ($(ev.target).closest('.datepicker').length == 0) {
|
||||
that.hide();
|
||||
}
|
||||
});
|
||||
this.element.trigger({
|
||||
type: 'show',
|
||||
date: this.date
|
||||
});
|
||||
},
|
||||
|
||||
hide: function(){
|
||||
this.picker.hide();
|
||||
$(window).off('resize', this.place);
|
||||
this.viewMode = this.startViewMode;
|
||||
this.showMode();
|
||||
if (!this.isInput) {
|
||||
$(document).off('mousedown', this.hide);
|
||||
}
|
||||
//this.set();
|
||||
this.element.trigger({
|
||||
type: 'hide',
|
||||
date: this.date
|
||||
});
|
||||
},
|
||||
|
||||
set: function() {
|
||||
var formated = DPGlobal.formatDate(this.date, this.format);
|
||||
if (!this.isInput) {
|
||||
if (this.component){
|
||||
this.element.find('input').prop('value', formated);
|
||||
}
|
||||
this.element.data('date', formated);
|
||||
} else {
|
||||
this.element.prop('value', formated);
|
||||
}
|
||||
},
|
||||
|
||||
setValue: function(newDate) {
|
||||
if (typeof newDate === 'string') {
|
||||
this.date = DPGlobal.parseDate(newDate, this.format);
|
||||
} else {
|
||||
this.date = new Date(newDate);
|
||||
}
|
||||
this.set();
|
||||
this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0);
|
||||
this.fill();
|
||||
},
|
||||
|
||||
place: function(){
|
||||
var offset = this.component ? this.component.offset() : this.element.offset();
|
||||
this.picker.css({
|
||||
top: offset.top + this.height,
|
||||
left: offset.left
|
||||
});
|
||||
},
|
||||
|
||||
update: function(newDate){
|
||||
this.date = DPGlobal.parseDate(
|
||||
typeof newDate === 'string' ? newDate : (this.isInput ? this.element.prop('value') : this.element.data('date')),
|
||||
this.format
|
||||
);
|
||||
this.viewDate = new Date(this.date.getFullYear(), this.date.getMonth(), 1, 0, 0, 0, 0);
|
||||
this.fill();
|
||||
},
|
||||
|
||||
fillDow: function(){
|
||||
var dowCnt = this.weekStart;
|
||||
var html = '<tr>';
|
||||
while (dowCnt < this.weekStart + 7) {
|
||||
html += '<th class="dow">'+DPGlobal.dates.daysMin[(dowCnt++)%7]+'</th>';
|
||||
}
|
||||
html += '</tr>';
|
||||
this.picker.find('.datepicker-days thead').append(html);
|
||||
},
|
||||
|
||||
fillMonths: function(){
|
||||
var html = '';
|
||||
var i = 0
|
||||
while (i < 12) {
|
||||
html += '<span class="month">'+DPGlobal.dates.monthsShort[i++]+'</span>';
|
||||
}
|
||||
this.picker.find('.datepicker-months td').append(html);
|
||||
},
|
||||
|
||||
fill: function() {
|
||||
var d = new Date(this.viewDate),
|
||||
year = d.getFullYear(),
|
||||
month = d.getMonth(),
|
||||
currentDate = this.date.valueOf();
|
||||
this.picker.find('.datepicker-days th:eq(1)')
|
||||
.text(DPGlobal.dates.months[month]+' '+year);
|
||||
var prevMonth = new Date(year, month-1, 28,0,0,0,0),
|
||||
day = DPGlobal.getDaysInMonth(prevMonth.getFullYear(), prevMonth.getMonth());
|
||||
prevMonth.setDate(day);
|
||||
prevMonth.setDate(day - (prevMonth.getDay() - this.weekStart + 7)%7);
|
||||
var nextMonth = new Date(prevMonth);
|
||||
nextMonth.setDate(nextMonth.getDate() + 42);
|
||||
nextMonth = nextMonth.valueOf();
|
||||
var html = [];
|
||||
var clsName,
|
||||
prevY,
|
||||
prevM;
|
||||
while(prevMonth.valueOf() < nextMonth) {
|
||||
if (prevMonth.getDay() === this.weekStart) {
|
||||
html.push('<tr>');
|
||||
}
|
||||
clsName = this.onRender(prevMonth);
|
||||
prevY = prevMonth.getFullYear();
|
||||
prevM = prevMonth.getMonth();
|
||||
if ((prevM < month && prevY === year) || prevY < year) {
|
||||
clsName += ' old';
|
||||
} else if ((prevM > month && prevY === year) || prevY > year) {
|
||||
clsName += ' new';
|
||||
}
|
||||
if (prevMonth.valueOf() === currentDate) {
|
||||
clsName += ' active';
|
||||
}
|
||||
html.push('<td class="day '+clsName+'">'+prevMonth.getDate() + '</td>');
|
||||
if (prevMonth.getDay() === this.weekEnd) {
|
||||
html.push('</tr>');
|
||||
}
|
||||
prevMonth.setDate(prevMonth.getDate()+1);
|
||||
}
|
||||
this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
|
||||
var currentYear = this.date.getFullYear();
|
||||
|
||||
var months = this.picker.find('.datepicker-months')
|
||||
.find('th:eq(1)')
|
||||
.text(year)
|
||||
.end()
|
||||
.find('span').removeClass('active');
|
||||
if (currentYear === year) {
|
||||
months.eq(this.date.getMonth()).addClass('active');
|
||||
}
|
||||
|
||||
html = '';
|
||||
year = parseInt(year/10, 10) * 10;
|
||||
var yearCont = this.picker.find('.datepicker-years')
|
||||
.find('th:eq(1)')
|
||||
.text(year + '-' + (year + 9))
|
||||
.end()
|
||||
.find('td');
|
||||
year -= 1;
|
||||
for (var i = -1; i < 11; i++) {
|
||||
html += '<span class="year'+(i === -1 || i === 10 ? ' old' : '')+(currentYear === year ? ' active' : '')+'">'+year+'</span>';
|
||||
year += 1;
|
||||
}
|
||||
yearCont.html(html);
|
||||
},
|
||||
|
||||
click: function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
var target = $(e.target).closest('span, td, th');
|
||||
if (target.length === 1) {
|
||||
switch(target[0].nodeName.toLowerCase()) {
|
||||
case 'th':
|
||||
switch(target[0].className) {
|
||||
case 'switch':
|
||||
this.showMode(1);
|
||||
break;
|
||||
case 'prev':
|
||||
case 'next':
|
||||
this.viewDate['set'+DPGlobal.modes[this.viewMode].navFnc].call(
|
||||
this.viewDate,
|
||||
this.viewDate['get'+DPGlobal.modes[this.viewMode].navFnc].call(this.viewDate) +
|
||||
DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1)
|
||||
);
|
||||
this.fill();
|
||||
this.set();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'span':
|
||||
if (target.is('.month')) {
|
||||
var month = target.parent().find('span').index(target);
|
||||
this.viewDate.setMonth(month);
|
||||
} else {
|
||||
var year = parseInt(target.text(), 10)||0;
|
||||
this.viewDate.setFullYear(year);
|
||||
}
|
||||
if (this.viewMode !== 0) {
|
||||
this.date = new Date(this.viewDate);
|
||||
this.element.trigger({
|
||||
type: 'changeDate',
|
||||
date: this.date,
|
||||
viewMode: DPGlobal.modes[this.viewMode].clsName
|
||||
});
|
||||
}
|
||||
this.showMode(-1);
|
||||
this.fill();
|
||||
this.set();
|
||||
break;
|
||||
case 'td':
|
||||
if (target.is('.day') && !target.is('.disabled')){
|
||||
var day = parseInt(target.text(), 10)||1;
|
||||
var month = this.viewDate.getMonth();
|
||||
if (target.is('.old')) {
|
||||
month -= 1;
|
||||
} else if (target.is('.new')) {
|
||||
month += 1;
|
||||
}
|
||||
var year = this.viewDate.getFullYear();
|
||||
this.date = new Date(year, month, day,0,0,0,0);
|
||||
this.viewDate = new Date(year, month, Math.min(28, day),0,0,0,0);
|
||||
this.fill();
|
||||
this.set();
|
||||
this.element.trigger({
|
||||
type: 'changeDate',
|
||||
date: this.date,
|
||||
viewMode: DPGlobal.modes[this.viewMode].clsName
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
mousedown: function(e){
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
},
|
||||
|
||||
showMode: function(dir) {
|
||||
if (dir) {
|
||||
this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
|
||||
}
|
||||
this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show();
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.datepicker = function ( option, val ) {
|
||||
return this.each(function () {
|
||||
var $this = $(this),
|
||||
data = $this.data('datepicker'),
|
||||
options = typeof option === 'object' && option;
|
||||
if (!data) {
|
||||
$this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.datepicker.defaults,options))));
|
||||
}
|
||||
if (typeof option === 'string') data[option](val);
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.datepicker.defaults = {
|
||||
onRender: function(date) {
|
||||
return '';
|
||||
}
|
||||
};
|
||||
$.fn.datepicker.Constructor = Datepicker;
|
||||
|
||||
var DPGlobal = {
|
||||
modes: [
|
||||
{
|
||||
clsName: 'days',
|
||||
navFnc: 'Month',
|
||||
navStep: 1
|
||||
},
|
||||
{
|
||||
clsName: 'months',
|
||||
navFnc: 'FullYear',
|
||||
navStep: 1
|
||||
},
|
||||
{
|
||||
clsName: 'years',
|
||||
navFnc: 'FullYear',
|
||||
navStep: 10
|
||||
}],
|
||||
dates:{
|
||||
days: ["Zondag", "Maandag", "Dinsdag", "Woensdag", "Donderdag", "Vrijdag", "Zaterdag", "Zondag"],
|
||||
daysShort: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"],
|
||||
daysMin: ["Zo", "Ma", "Di", "Wo", "Do", "Vr", "Za", "Zo"],
|
||||
months: ["Januari", "Februari", "Maart", "April", "Mei", "Jun", "Jul", "Augustus", "September", "Oktober", "November", "December"],
|
||||
monthsShort: ["Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Aug", "Sep", "Okt", "Nov", "Dec"]
|
||||
},
|
||||
isLeapYear: function (year) {
|
||||
return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0))
|
||||
},
|
||||
getDaysInMonth: function (year, month) {
|
||||
return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]
|
||||
},
|
||||
parseFormat: function(format){
|
||||
var separator = format.match(/[.\/\-\s].*?/),
|
||||
parts = format.split(/\W+/);
|
||||
if (!separator || !parts || parts.length === 0){
|
||||
throw new Error("Invalid date format.");
|
||||
}
|
||||
return {separator: separator, parts: parts};
|
||||
},
|
||||
parseDate: function(date, format) {
|
||||
var parts = date.split(format.separator),
|
||||
date = new Date(),
|
||||
val;
|
||||
date.setHours(0);
|
||||
date.setMinutes(0);
|
||||
date.setSeconds(0);
|
||||
date.setMilliseconds(0);
|
||||
if (parts.length === format.parts.length) {
|
||||
var year = date.getFullYear(), day = date.getDate(), month = date.getMonth();
|
||||
for (var i=0, cnt = format.parts.length; i < cnt; i++) {
|
||||
val = parseInt(parts[i], 10)||1;
|
||||
switch(format.parts[i]) {
|
||||
case 'dd':
|
||||
case 'd':
|
||||
day = val;
|
||||
date.setDate(val);
|
||||
break;
|
||||
case 'mm':
|
||||
case 'm':
|
||||
month = val - 1;
|
||||
date.setMonth(val - 1);
|
||||
break;
|
||||
case 'yy':
|
||||
year = 2000 + val;
|
||||
date.setFullYear(2000 + val);
|
||||
break;
|
||||
case 'yyyy':
|
||||
year = val;
|
||||
date.setFullYear(val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
date = new Date(year, month, day, 0 ,0 ,0);
|
||||
}
|
||||
return date;
|
||||
},
|
||||
formatDate: function(date, format){
|
||||
var val = {
|
||||
d: date.getDate(),
|
||||
m: date.getMonth() + 1,
|
||||
yy: date.getFullYear().toString().substring(2),
|
||||
yyyy: date.getFullYear()
|
||||
};
|
||||
val.dd = (val.d < 10 ? '0' : '') + val.d;
|
||||
val.mm = (val.m < 10 ? '0' : '') + val.m;
|
||||
var date = [];
|
||||
for (var i=0, cnt = format.parts.length; i < cnt; i++) {
|
||||
date.push(val[format.parts[i]]);
|
||||
}
|
||||
return date.join(format.separator);
|
||||
},
|
||||
headTemplate: '<thead>'+
|
||||
'<tr>'+
|
||||
'<th class="prev">‹</th>'+
|
||||
'<th colspan="5" class="switch"></th>'+
|
||||
'<th class="next">›</th>'+
|
||||
'</tr>'+
|
||||
'</thead>',
|
||||
contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>'
|
||||
};
|
||||
DPGlobal.template = '<div class="datepicker dropdown-menu">'+
|
||||
'<div class="datepicker-days">'+
|
||||
'<table class=" table-condensed">'+
|
||||
DPGlobal.headTemplate+
|
||||
'<tbody></tbody>'+
|
||||
'</table>'+
|
||||
'</div>'+
|
||||
'<div class="datepicker-months">'+
|
||||
'<table class="table-condensed">'+
|
||||
DPGlobal.headTemplate+
|
||||
DPGlobal.contTemplate+
|
||||
'</table>'+
|
||||
'</div>'+
|
||||
'<div class="datepicker-years">'+
|
||||
'<table class="table-condensed">'+
|
||||
DPGlobal.headTemplate+
|
||||
DPGlobal.contTemplate+
|
||||
'</table>'+
|
||||
'</div>'+
|
||||
'</div>';
|
||||
|
||||
}( window.jQuery );
|
||||
28
assets/js/vendor/flashcanvas.js
vendored
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* FlashCanvas
|
||||
*
|
||||
* Copyright (c) 2009 Tim Cameron Ryan
|
||||
* Copyright (c) 2009-2011 FlashCanvas Project
|
||||
* Released under the MIT/X License
|
||||
*/
|
||||
window.ActiveXObject&&!window.CanvasRenderingContext2D&&function(h,j){function D(a){this.code=a;this.message=T[a]}function U(a){this.width=a}function E(a){this.id=a.C++}function t(a){this.G=a;this.id=a.C++}function u(a,b){this.canvas=a;this.B=b;this.d=a.uniqueID;this.D();this.C=0;this.t="";var c=this;setInterval(function(){n[c.d]===0&&c.e()},30)}function A(){if(j.readyState==="complete"){j.detachEvent(F,A);for(var a=j.getElementsByTagName(r),b=0,c=a.length;b<c;++b)B.initElement(a[b])}}function G(){var a=
|
||||
event.srcElement,b=a.parentNode;a.blur();b.focus()}function H(){var a=event.propertyName;if(a==="width"||a==="height"){var b=event.srcElement,c=b[a],d=parseInt(c,10);if(isNaN(d)||d<0)d=a==="width"?300:150;if(c===d){b.style[a]=d+"px";b.getContext("2d").I(b.width,b.height)}else b[a]=d}}function I(){h.detachEvent(J,I);for(var a in s){var b=s[a],c=b.firstChild,d;for(d in c)if(typeof c[d]==="function")c[d]=k;for(d in b)if(typeof b[d]==="function")b[d]=k;c.detachEvent(K,G);b.detachEvent(L,H)}h[M]=k;h[N]=
|
||||
k;h[O]=k;h[C]=k;h[P]=k}function V(){var a=j.getElementsByTagName("script");a=a[a.length-1];return j.documentMode>=8?a.src:a.getAttribute("src",4)}function v(a){return(""+a).replace(/&/g,"&").replace(/</g,"<")}function W(a){return a.toLowerCase()}function i(a){throw new D(a);}function Q(a){var b=parseInt(a.width,10),c=parseInt(a.height,10);if(isNaN(b)||b<0)b=300;if(isNaN(c)||c<0)c=150;a.width=b;a.height=c}var k=null,r="canvas",M="CanvasRenderingContext2D",N="CanvasGradient",O="CanvasPattern",
|
||||
C="FlashCanvas",P="G_vmlCanvasManager",K="onfocus",L="onpropertychange",F="onreadystatechange",J="onunload",w=((h[C+"Options"]||{}).swfPath||V().replace(/[^\/]+$/,""))+"flashcanvas.swf",e=new function(a){for(var b=0,c=a.length;b<c;b++)this[a[b]]=b}(["toDataURL","save","restore","scale","rotate","translate","transform","setTransform","globalAlpha","globalCompositeOperation","strokeStyle","fillStyle","createLinearGradient","createRadialGradient","createPattern","lineWidth","lineCap","lineJoin","miterLimit",
|
||||
"shadowOffsetX","shadowOffsetY","shadowBlur","shadowColor","clearRect","fillRect","strokeRect","beginPath","closePath","moveTo","lineTo","quadraticCurveTo","bezierCurveTo","arcTo","rect","arc","fill","stroke","clip","isPointInPath","font","textAlign","textBaseline","fillText","strokeText","measureText","drawImage","createImageData","getImageData","putImageData","addColorStop","direction","resize"]),x={},n={},s={},y={};u.prototype={save:function(){this.b();this.c();this.m();this.l();this.z();this.w();
|
||||
this.F.push([this.f,this.g,this.A,this.u,this.j,this.h,this.i,this.k,this.p,this.q,this.n,this.o,this.v,this.r,this.s]);this.a.push(e.save)},restore:function(){var a=this.F;if(a.length){a=a.pop();this.globalAlpha=a[0];this.globalCompositeOperation=a[1];this.strokeStyle=a[2];this.fillStyle=a[3];this.lineWidth=a[4];this.lineCap=a[5];this.lineJoin=a[6];this.miterLimit=a[7];this.shadowOffsetX=a[8];this.shadowOffsetY=a[9];this.shadowBlur=a[10];this.shadowColor=a[11];this.font=a[12];this.textAlign=a[13];
|
||||
this.textBaseline=a[14]}this.a.push(e.restore)},scale:function(a,b){this.a.push(e.scale,a,b)},rotate:function(a){this.a.push(e.rotate,a)},translate:function(a,b){this.a.push(e.translate,a,b)},transform:function(a,b,c,d,f,g){this.a.push(e.transform,a,b,c,d,f,g)},setTransform:function(a,b,c,d,f,g){this.a.push(e.setTransform,a,b,c,d,f,g)},b:function(){var a=this.a;if(this.f!==this.globalAlpha){this.f=this.globalAlpha;a.push(e.globalAlpha,this.f)}if(this.g!==this.globalCompositeOperation){this.g=this.globalCompositeOperation;
|
||||
a.push(e.globalCompositeOperation,this.g)}},m:function(){if(this.A!==this.strokeStyle){var a=this.A=this.strokeStyle;this.a.push(e.strokeStyle,typeof a==="object"?a.id:a)}},l:function(){if(this.u!==this.fillStyle){var a=this.u=this.fillStyle;this.a.push(e.fillStyle,typeof a==="object"?a.id:a)}},createLinearGradient:function(a,b,c,d){isFinite(a)&&isFinite(b)&&isFinite(c)&&isFinite(d)||i(9);this.a.push(e.createLinearGradient,a,b,c,d);return new t(this)},createRadialGradient:function(a,b,c,d,f,g){isFinite(a)&&
|
||||
isFinite(b)&&isFinite(c)&&isFinite(d)&&isFinite(f)&&isFinite(g)||i(9);if(c<0||g<0)i(1);this.a.push(e.createRadialGradient,a,b,c,d,f,g);return new t(this)},createPattern:function(a,b){a||i(17);var c=a.tagName,d,f=this.d;if(c){c=c.toLowerCase();if(c==="img")d=a.getAttribute("src",2);else if(c===r||c==="video")return;else i(17)}else if(a.src)d=a.src;else i(17);b==="repeat"||b==="no-repeat"||b==="repeat-x"||b==="repeat-y"||b===""||b===k||i(12);this.a.push(e.createPattern,v(d),b);if(x[f]){this.e();++n[f]}return new E(this)},
|
||||
z:function(){var a=this.a;if(this.j!==this.lineWidth){this.j=this.lineWidth;a.push(e.lineWidth,this.j)}if(this.h!==this.lineCap){this.h=this.lineCap;a.push(e.lineCap,this.h)}if(this.i!==this.lineJoin){this.i=this.lineJoin;a.push(e.lineJoin,this.i)}if(this.k!==this.miterLimit){this.k=this.miterLimit;a.push(e.miterLimit,this.k)}},c:function(){var a=this.a;if(this.p!==this.shadowOffsetX){this.p=this.shadowOffsetX;a.push(e.shadowOffsetX,this.p)}if(this.q!==this.shadowOffsetY){this.q=this.shadowOffsetY;
|
||||
a.push(e.shadowOffsetY,this.q)}if(this.n!==this.shadowBlur){this.n=this.shadowBlur;a.push(e.shadowBlur,this.n)}if(this.o!==this.shadowColor){this.o=this.shadowColor;a.push(e.shadowColor,this.o)}},clearRect:function(a,b,c,d){this.a.push(e.clearRect,a,b,c,d)},fillRect:function(a,b,c,d){this.b();this.c();this.l();this.a.push(e.fillRect,a,b,c,d)},strokeRect:function(a,b,c,d){this.b();this.c();this.m();this.z();this.a.push(e.strokeRect,a,b,c,d)},beginPath:function(){this.a.push(e.beginPath)},closePath:function(){this.a.push(e.closePath)},
|
||||
moveTo:function(a,b){this.a.push(e.moveTo,a,b)},lineTo:function(a,b){this.a.push(e.lineTo,a,b)},quadraticCurveTo:function(a,b,c,d){this.a.push(e.quadraticCurveTo,a,b,c,d)},bezierCurveTo:function(a,b,c,d,f,g){this.a.push(e.bezierCurveTo,a,b,c,d,f,g)},arcTo:function(a,b,c,d,f){f<0&&isFinite(f)&&i(1);this.a.push(e.arcTo,a,b,c,d,f)},rect:function(a,b,c,d){this.a.push(e.rect,a,b,c,d)},arc:function(a,b,c,d,f,g){c<0&&isFinite(c)&&i(1);this.a.push(e.arc,a,b,c,d,f,g?1:0)},fill:function(){this.b();this.c();
|
||||
this.l();this.a.push(e.fill)},stroke:function(){this.b();this.c();this.m();this.z();this.a.push(e.stroke)},clip:function(){this.a.push(e.clip)},w:function(){var a=this.a;if(this.v!==this.font)try{var b=y[this.d];b.style.font=this.v=this.font;var c=b.currentStyle;a.push(e.font,[c.fontStyle,c.fontWeight,b.offsetHeight,c.fontFamily].join(" "))}catch(d){}if(this.r!==this.textAlign){this.r=this.textAlign;a.push(e.textAlign,this.r)}if(this.s!==this.textBaseline){this.s=this.textBaseline;a.push(e.textBaseline,
|
||||
this.s)}if(this.t!==this.canvas.currentStyle.direction){this.t=this.canvas.currentStyle.direction;a.push(e.direction,this.t)}},fillText:function(a,b,c,d){this.b();this.l();this.c();this.w();this.a.push(e.fillText,v(a),b,c,d===void 0?Infinity:d)},strokeText:function(a,b,c,d){this.b();this.m();this.c();this.w();this.a.push(e.strokeText,v(a),b,c,d===void 0?Infinity:d)},measureText:function(a){var b=y[this.d];try{b.style.font=this.font}catch(c){}b.innerText=a.replace(/[ \n\f\r]/g,"\t");return new U(b.offsetWidth)},
|
||||
drawImage:function(a,b,c,d,f,g,o,l,z){a||i(17);var p=a.tagName,m,q=arguments.length,R=this.d;if(p){p=p.toLowerCase();if(p==="img")m=a.getAttribute("src",2);else if(p===r||p==="video")return;else i(17)}else if(a.src)m=a.src;else i(17);this.b();this.c();m=v(m);if(q===3)this.a.push(e.drawImage,q,m,b,c);else if(q===5)this.a.push(e.drawImage,q,m,b,c,d,f);else if(q===9){if(d===0||f===0)i(1);this.a.push(e.drawImage,q,m,b,c,d,f,g,o,l,z)}else return;if(x[R]){this.e();++n[R]}},D:function(){this.globalAlpha=
|
||||
this.f=1;this.globalCompositeOperation=this.g="source-over";this.fillStyle=this.u=this.strokeStyle=this.A="#000000";this.lineWidth=this.j=1;this.lineCap=this.h="butt";this.lineJoin=this.i="miter";this.miterLimit=this.k=10;this.shadowBlur=this.n=this.shadowOffsetY=this.q=this.shadowOffsetX=this.p=0;this.shadowColor=this.o="rgba(0, 0, 0, 0.0)";this.font=this.v="10px sans-serif";this.textAlign=this.r="start";this.textBaseline=this.s="alphabetic";this.a=[];this.F=[]},H:function(){var a=this.a;this.a=
|
||||
[];return a},e:function(){var a=this.H();if(a.length>0)return eval(this.B.CallFunction('<invoke name="executeCommand" returntype="javascript"><arguments><string>'+a.join("�")+"</string></arguments></invoke>"))},I:function(a,b){this.e();this.D();if(a>0)this.B.width=a;if(b>0)this.B.height=b;this.a.push(e.resize,a,b)}};t.prototype={addColorStop:function(a,b){if(isNaN(a)||a<0||a>1)i(1);this.G.a.push(e.addColorStop,this.id,a,b)}};D.prototype=Error();var T={1:"INDEX_SIZE_ERR",9:"NOT_SUPPORTED_ERR",11:"INVALID_STATE_ERR",
|
||||
12:"SYNTAX_ERR",17:"TYPE_MISMATCH_ERR",18:"SECURITY_ERR"},B={initElement:function(a){if(a.getContext)return a;var b=a.uniqueID,c="external"+b;x[b]=false;n[b]=1;Q(a);a.innerHTML='<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+location.protocol+'//fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="100%" height="100%" id="'+c+'"><param name="allowScriptAccess" value="always"><param name="flashvars" value="id='+c+'"><param name="wmode" value="transparent"></object><span style="margin:0;padding:0;border:0;display:inline-block;position:static;height:1em;overflow:visible;white-space:nowrap"></span>';
|
||||
s[b]=a;var d=a.firstChild;y[b]=a.lastChild;var f=j.body.contains;if(f(a))d.movie=w;else var g=setInterval(function(){if(f(a)){clearInterval(g);d.movie=w}},0);if(j.compatMode==="BackCompat"||!h.XMLHttpRequest)y[b].style.overflow="hidden";var o=new u(a,d);a.getContext=function(l){return l==="2d"?o:k};a.toDataURL=function(l,z){(""+l).replace(/[A-Z]+/g,W)==="image/jpeg"?o.a.push(e.toDataURL,l,typeof z==="number"?z:""):o.a.push(e.toDataURL,l);return o.e()};d.attachEvent(K,G);return a},saveImage:function(a){a.firstChild.saveImage()},
|
||||
setOptions:function(){},trigger:function(a,b){s[a].fireEvent("on"+b)},unlock:function(a,b){n[a]&&--n[a];if(b){var c=s[a],d=c.firstChild,f,g;Q(c);f=c.width;g=c.height;c.style.width=f+"px";c.style.height=g+"px";if(f>0)d.width=f;if(g>0)d.height=g;d.resize(f,g);c.attachEvent(L,H);x[a]=true}}};j.createElement(r);j.createStyleSheet().cssText=r+"{display:inline-block;overflow:hidden;width:300px;height:150px}";j.readyState==="complete"?A():j.attachEvent(F,A);h.attachEvent(J,I);if(w.indexOf(location.protocol+
|
||||
"//"+location.host+"/")===0){var S=new ActiveXObject("Microsoft.XMLHTTP");S.open("GET",w,false);S.send(k)}h[M]=u;h[N]=t;h[O]=E;h[C]=B;h[P]={init:function(){},init_:function(){},initElement:B.initElement};keep=u.measureText}(window,document);
|
||||
BIN
assets/js/vendor/flashcanvas.swf
vendored
Executable file
6
assets/js/vendor/jquery-1.10.1.min.js
vendored
Normal file
278
assets/js/vendor/jquery.dependent-selects.js
vendored
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
// Generated by CoffeeScript 1.6.3
|
||||
/*
|
||||
# jQuery Dependent Selects v1.2.2
|
||||
# Copyright 2012 Mark J Smith, Simpleweb
|
||||
# Details on http://github.com/simpleweb/jquery-dependent-selects
|
||||
*/
|
||||
|
||||
(function($) {
|
||||
return $.fn.dependentSelects = function(options) {
|
||||
var clearAllSelectsByParent, createNewSelect, createSelectId, findSelectParent, hideSelect, insertLabel, insertPlaceholderSelect, labelAtDepth, placeholderOptionAtDepth, placeholderSelectAtDepth, prepareSelect, selectChange, selectPreSelected, selectedOption, showSelect, splitOptionName;
|
||||
if (options == null) {
|
||||
options = {};
|
||||
}
|
||||
options = $.extend({
|
||||
'separator': ' > ',
|
||||
'placeholderOption': '',
|
||||
'placeholderSelect': false,
|
||||
'class': false,
|
||||
'labels': false
|
||||
}, options);
|
||||
createSelectId = function() {
|
||||
var int;
|
||||
int = parseInt(Math.random() * 1000);
|
||||
if ($("[data-dependent-id='" + int + "']").length > 0) {
|
||||
return createSelectId();
|
||||
} else {
|
||||
return int;
|
||||
}
|
||||
};
|
||||
splitOptionName = function($option) {
|
||||
var array, i, item, _i, _len;
|
||||
array = $.map($option.text().split(options.separator), function(valuePart) {
|
||||
return $.trim(valuePart);
|
||||
});
|
||||
i = 0;
|
||||
for (_i = 0, _len = array.length; _i < _len; _i++) {
|
||||
item = array[_i];
|
||||
if (item === '') {
|
||||
array.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return array;
|
||||
};
|
||||
placeholderSelectAtDepth = function(depth, $select) {
|
||||
var placeholder, text;
|
||||
depth--;
|
||||
placeholder = options.placeholderSelect;
|
||||
if (placeholder) {
|
||||
if (placeholder === true) {
|
||||
placeholder = $select.data('dependent-select-placeholders');
|
||||
}
|
||||
if (typeof placeholder === 'object') {
|
||||
if (placeholder[depth]) {
|
||||
text = placeholder[depth];
|
||||
} else {
|
||||
text = placeholder[placeholder.length - 1];
|
||||
}
|
||||
} else {
|
||||
text = placeholder;
|
||||
}
|
||||
return $("<select disabled><option>" + text + "</option></select>").attr({
|
||||
'data-dependent-depth': depth + 1,
|
||||
'data-dependent-placeholder': true,
|
||||
'data-dependent-id': $select.attr('data-dependent-id')
|
||||
}).addClass(options["class"]);
|
||||
}
|
||||
};
|
||||
placeholderOptionAtDepth = function(depth) {
|
||||
var placeholder, text;
|
||||
depth--;
|
||||
placeholder = options.placeholderOption;
|
||||
if (typeof placeholder === 'object') {
|
||||
if (placeholder[depth]) {
|
||||
text = placeholder[depth];
|
||||
} else {
|
||||
text = placeholder[placeholder.length - 1];
|
||||
}
|
||||
} else {
|
||||
text = placeholder;
|
||||
}
|
||||
return $("<option>" + text + "</option>");
|
||||
};
|
||||
labelAtDepth = function(depth, $select) {
|
||||
var labels;
|
||||
depth--;
|
||||
labels = options.labels;
|
||||
if (labels) {
|
||||
if (labels === true) {
|
||||
labels = $select.data('dependent-labels');
|
||||
}
|
||||
if (labels[depth]) {
|
||||
return labels[depth];
|
||||
} else {
|
||||
return labels[labels.length - 1];
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
hideSelect = function($select) {
|
||||
var label, placeholder_select, select_depth, select_id;
|
||||
select_id = $select.attr('data-dependent-id');
|
||||
select_depth = $select.attr('data-dependent-depth');
|
||||
placeholder_select = $("select[data-dependent-placeholder][data-dependent-id='" + select_id + "'][data-dependent-depth='" + select_depth + "']");
|
||||
label = $("label[data-dependent-id='" + select_id + "'][data-dependent-depth='" + select_depth + "']").hide();
|
||||
if (placeholder_select.length > 0) {
|
||||
placeholder_select.show();
|
||||
label.show();
|
||||
}
|
||||
return $select.hide();
|
||||
};
|
||||
showSelect = function($select) {
|
||||
var label, placeholder_select, select_depth, select_id;
|
||||
select_id = $select.attr('data-dependent-id');
|
||||
select_depth = $select.attr('data-dependent-depth');
|
||||
placeholder_select = $("select[data-dependent-placeholder][data-dependent-id='" + select_id + "'][data-dependent-depth='" + select_depth + "']");
|
||||
label = $("label[data-dependent-id='" + select_id + "'][data-dependent-depth='" + select_depth + "']").show();
|
||||
if (placeholder_select.length > 0) {
|
||||
placeholder_select.hide();
|
||||
}
|
||||
return $select.show();
|
||||
};
|
||||
insertLabel = function($select, $parent) {
|
||||
var $label, label, select_depth, select_id;
|
||||
if (label = labelAtDepth($select.attr('data-dependent-depth'), $select)) {
|
||||
select_id = $select.attr('data-dependent-id');
|
||||
select_depth = $select.attr('data-dependent-depth');
|
||||
$label = $("<label>" + label + "</label>").attr({
|
||||
'data-dependent-id': select_id,
|
||||
'data-dependent-depth': select_depth
|
||||
});
|
||||
if (!($("label[data-dependent-id='" + select_id + "'][data-dependent-depth='" + select_depth + "']").length > 0)) {
|
||||
if ($parent) {
|
||||
return $parent.after($label);
|
||||
} else {
|
||||
return $select.before($label);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
insertPlaceholderSelect = function($select, $parent) {
|
||||
var $placeholderSelect, depth, select_id;
|
||||
if ($placeholderSelect = placeholderSelectAtDepth($select.attr('data-dependent-depth'), $select)) {
|
||||
select_id = $select.attr('data-dependent-id');
|
||||
depth = $select.attr('data-dependent-depth');
|
||||
if (!($("select[data-dependent-placeholder][data-dependent-id='" + select_id + "'][data-dependent-depth='" + depth + "']").length > 0)) {
|
||||
return $select.before($placeholderSelect);
|
||||
}
|
||||
}
|
||||
};
|
||||
clearAllSelectsByParent = function($parent) {
|
||||
return $(".dependent-sub[data-dependent-id='" + ($parent.attr('data-dependent-id')) + "']").each(function() {
|
||||
if (parseInt($(this).attr('data-dependent-depth')) > parseInt($parent.attr('data-dependent-depth'))) {
|
||||
$(this).find('option:first').attr('selected', 'selected');
|
||||
return hideSelect($(this));
|
||||
}
|
||||
});
|
||||
};
|
||||
createNewSelect = function(name, $select, depth) {
|
||||
var $currentSelect, $labels, $newSelect, select_id;
|
||||
select_id = $select.attr('data-dependent-id');
|
||||
if (($currentSelect = $("select[data-dependent-parent='" + name + "'][data-dependent-id='" + select_id + "']")).length > 0) {
|
||||
return $currentSelect;
|
||||
}
|
||||
$newSelect = $('<select class="dependent-sub"/>').attr('data-dependent-parent', name).attr('data-dependent-depth', depth).attr('data-dependent-input-name', $select.attr('data-dependent-input-name')).attr('data-dependent-id', select_id).addClass(options["class"]).append(placeholderOptionAtDepth(depth));
|
||||
if (options.labels === true) {
|
||||
$newSelect.attr('data-dependent-labels', $select.attr('data-dependent-labels'));
|
||||
}
|
||||
if (options.placeholderSelect === true) {
|
||||
$newSelect.attr('data-dependent-select-placeholders', $select.attr('data-dependent-select-placeholders'));
|
||||
}
|
||||
if (($labels = $("label[data-dependent-id='" + select_id + "'][data-dependent-depth='" + depth + "']")).length > 0) {
|
||||
$newSelect.insertAfter($labels);
|
||||
} else {
|
||||
$newSelect.insertAfter($select);
|
||||
}
|
||||
insertLabel($newSelect, $select);
|
||||
insertPlaceholderSelect($newSelect, $select);
|
||||
return hideSelect($newSelect);
|
||||
};
|
||||
selectChange = function($select) {
|
||||
var $sub, select_id, val, valName;
|
||||
$("select[data-dependent-id='" + ($select.attr('data-dependent-id')) + "'][name]").removeAttr('name');
|
||||
valName = $select.find(':selected').html();
|
||||
val = $select.val();
|
||||
select_id = $select.attr('data-dependent-id');
|
||||
clearAllSelectsByParent($select);
|
||||
if (($sub = $(".dependent-sub[data-dependent-parent='" + valName + "'][data-dependent-id='" + select_id + "']")).length > 0) {
|
||||
showSelect($sub);
|
||||
return $sub.attr('name', $select.attr('data-dependent-input-name'));
|
||||
} else {
|
||||
return $select.attr('name', $select.attr('data-dependent-input-name'));
|
||||
}
|
||||
};
|
||||
selectedOption = function($select) {
|
||||
var $selectedOption, val;
|
||||
$selectedOption = $select.find('option:selected');
|
||||
val = $selectedOption.val();
|
||||
if (!(val === '' || val === placeholderOptionAtDepth($select.attr('data-dependent-depth')).val())) {
|
||||
return $select.attr('data-dependent-selected-id', val);
|
||||
}
|
||||
};
|
||||
findSelectParent = function($select) {
|
||||
var $all_options, $selects;
|
||||
$selects = $("select[data-dependent-id='" + ($select.attr('data-dependent-id')) + "']");
|
||||
$all_options = $selects.find('option');
|
||||
return $selects.filter(function() {
|
||||
var vals;
|
||||
vals = [];
|
||||
$(this).find('option').each(function() {
|
||||
return vals.push($(this).html() === $select.attr('data-dependent-parent'));
|
||||
});
|
||||
return $.inArray(true, vals) > -1;
|
||||
});
|
||||
};
|
||||
selectPreSelected = function($select) {
|
||||
var $all_options, $current_select, $selected_option, $selected_select, $selects, current_option_text, i, selected_id, _i, _ref;
|
||||
if ((selected_id = $select.attr('data-dependent-selected-id'))) {
|
||||
$selects = $("select[data-dependent-id='" + ($select.attr('data-dependent-id')) + "']");
|
||||
$all_options = $selects.find('option');
|
||||
$selected_option = $all_options.filter("[value='" + selected_id + "']");
|
||||
$selected_select = $selected_option.closest('select');
|
||||
$current_select = $selected_select;
|
||||
current_option_text = $selected_option.html();
|
||||
for (i = _i = _ref = parseInt($selected_select.attr('data-dependent-depth')); _ref <= 0 ? _i <= 0 : _i >= 0; i = _ref <= 0 ? ++_i : --_i) {
|
||||
$current_select.find('option').each(function() {
|
||||
if ($(this).html() === current_option_text) {
|
||||
return $(this).attr('selected', 'selected');
|
||||
} else {
|
||||
return $(this).removeAttr('selected');
|
||||
}
|
||||
});
|
||||
showSelect($current_select);
|
||||
current_option_text = $current_select.attr('data-dependent-parent');
|
||||
$current_select = findSelectParent($current_select);
|
||||
}
|
||||
return $selected_select.trigger('change');
|
||||
}
|
||||
};
|
||||
prepareSelect = function($select, depth, select_id) {
|
||||
var $options, name;
|
||||
$select.attr('data-dependent-depth', depth).attr('data-dependent-id', select_id);
|
||||
$options = $select.children('option');
|
||||
$options.each(function() {
|
||||
var $newOption, $option, $subSelect, name, val;
|
||||
$option = $(this);
|
||||
name = splitOptionName($option);
|
||||
val = $option.val();
|
||||
if (name.length > 1) {
|
||||
$subSelect = createNewSelect(name[0], $select, depth + 1);
|
||||
$newOption = $option.clone();
|
||||
$newOption.html($.trim(splitOptionName($newOption).slice(1).join(options.separator)));
|
||||
$subSelect.append($newOption);
|
||||
$option.val('').html(name[0]).attr('data-dependent-name', name[0]);
|
||||
if ($options.parent().find("[data-dependent-name='" + name[0] + "']").length > 1) {
|
||||
$option.remove();
|
||||
}
|
||||
return prepareSelect($subSelect, depth + 1, select_id);
|
||||
}
|
||||
});
|
||||
name = $select.attr('name');
|
||||
selectChange($select);
|
||||
return $select.off('change').on('change', function() {
|
||||
return selectChange($select);
|
||||
});
|
||||
};
|
||||
return this.each(function() {
|
||||
var $select;
|
||||
$select = $(this);
|
||||
$select.attr('data-dependent-input-name', $select.attr('name'));
|
||||
selectedOption($select);
|
||||
prepareSelect($select, 0, createSelectId());
|
||||
return selectPreSelected($select);
|
||||
});
|
||||
};
|
||||
})(jQuery);
|
||||
14
assets/js/vendor/jquery.signaturepad.min.js
vendored
Executable file
28
assets/js/vendor/json2.min.js
vendored
Executable file
|
|
@ -0,0 +1,28 @@
|
|||
if(!this.JSON){this.JSON={};}
|
||||
(function(){function f(n){return n<10?'0'+n:n;}
|
||||
if(typeof Date.prototype.toJSON!=='function'){Date.prototype.toJSON=function(key){return isFinite(this.valueOf())?this.getUTCFullYear()+'-'+
|
||||
f(this.getUTCMonth()+1)+'-'+
|
||||
f(this.getUTCDate())+'T'+
|
||||
f(this.getUTCHours())+':'+
|
||||
f(this.getUTCMinutes())+':'+
|
||||
f(this.getUTCSeconds())+'Z':null;};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf();};}
|
||||
var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={'\b':'\\b','\t':'\\t','\n':'\\n','\f':'\\f','\r':'\\r','"':'\\"','\\':'\\\\'},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==='string'?c:'\\u'+('0000'+a.charCodeAt(0).toString(16)).slice(-4);})+'"':'"'+string+'"';}
|
||||
function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==='object'&&typeof value.toJSON==='function'){value=value.toJSON(key);}
|
||||
if(typeof rep==='function'){value=rep.call(holder,key,value);}
|
||||
switch(typeof value){case'string':return quote(value);case'number':return isFinite(value)?String(value):'null';case'boolean':case'null':return String(value);case'object':if(!value){return'null';}
|
||||
gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==='[object Array]'){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||'null';}
|
||||
v=partial.length===0?'[]':gap?'[\n'+gap+
|
||||
partial.join(',\n'+gap)+'\n'+
|
||||
mind+']':'['+partial.join(',')+']';gap=mind;return v;}
|
||||
if(rep&&typeof rep==='object'){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==='string'){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?': ':':')+v);}}}}
|
||||
v=partial.length===0?'{}':gap?'{\n'+gap+partial.join(',\n'+gap)+'\n'+
|
||||
mind+'}':'{'+partial.join(',')+'}';gap=mind;return v;}}
|
||||
if(typeof JSON.stringify!=='function'){JSON.stringify=function(value,replacer,space){var i;gap='';indent='';if(typeof space==='number'){for(i=0;i<space;i+=1){indent+=' ';}}else if(typeof space==='string'){indent=space;}
|
||||
rep=replacer;if(replacer&&typeof replacer!=='function'&&(typeof replacer!=='object'||typeof replacer.length!=='number')){throw new Error('JSON.stringify');}
|
||||
return str('',{'':value});};}
|
||||
if(typeof JSON.parse!=='function'){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==='object'){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v;}else{delete value[k];}}}}
|
||||
return reviver.call(holder,key,value);}
|
||||
cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return'\\u'+
|
||||
('0000'+a.charCodeAt(0).toString(16)).slice(-4);});}
|
||||
if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,'@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').replace(/(?:^|:|,)(?:\s*\[)+/g,''))){j=eval('('+text+')');return typeof reviver==='function'?walk({'':j},''):j;}
|
||||
throw new SyntaxError('JSON.parse');};}}());
|
||||
9
assets/js/vendor/leaflet.js
vendored
Normal file
3
assets/js/vendor/proj4js-compressed.js
vendored
Normal file
271
assets/js/vendor/proj4leaflet.js
vendored
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
(function (factory) {
|
||||
var L, proj4;
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD
|
||||
define(['leaflet', 'proj4'], factory);
|
||||
} else if (typeof module !== 'undefined') {
|
||||
// Node/CommonJS
|
||||
L = require('leaflet');
|
||||
proj4 = require('proj4');
|
||||
module.exports = factory(L, proj4);
|
||||
} else {
|
||||
// Browser globals
|
||||
if (typeof window.L === 'undefined' || typeof window.proj4 === 'undefined')
|
||||
throw 'Leaflet and proj4 must be loaded first';
|
||||
factory(window.L, window.proj4);
|
||||
}
|
||||
}(function (L, proj4) {
|
||||
|
||||
L.Proj = {};
|
||||
|
||||
L.Proj._isProj4Obj = function(a) {
|
||||
return (typeof a.inverse !== 'undefined' &&
|
||||
typeof a.forward !== 'undefined');
|
||||
};
|
||||
|
||||
L.Proj.ScaleDependantTransformation = function(scaleTransforms) {
|
||||
this.scaleTransforms = scaleTransforms;
|
||||
};
|
||||
|
||||
L.Proj.ScaleDependantTransformation.prototype.transform = function(point, scale) {
|
||||
return this.scaleTransforms[scale].transform(point, scale);
|
||||
};
|
||||
|
||||
L.Proj.ScaleDependantTransformation.prototype.untransform = function(point, scale) {
|
||||
return this.scaleTransforms[scale].untransform(point, scale);
|
||||
};
|
||||
|
||||
L.Proj.Projection = L.Class.extend({
|
||||
initialize: function(a, def) {
|
||||
if (L.Proj._isProj4Obj(a)) {
|
||||
this._proj = a;
|
||||
} else {
|
||||
var code = a;
|
||||
if (def) {
|
||||
proj4.defs(code, def);
|
||||
} else if (proj4.defs[code] === undefined) {
|
||||
var urn = code.split(':');
|
||||
if (urn.length > 3) {
|
||||
code = urn[urn.length - 3] + ':' + urn[urn.length - 1];
|
||||
}
|
||||
if (proj4.defs[code] === undefined) {
|
||||
throw 'No projection definition for code ' + code;
|
||||
}
|
||||
}
|
||||
this._proj = proj4(code);
|
||||
}
|
||||
},
|
||||
|
||||
project: function (latlng) {
|
||||
var point = this._proj.forward([latlng.lng, latlng.lat]);
|
||||
return new L.Point(point[0], point[1]);
|
||||
},
|
||||
|
||||
unproject: function (point, unbounded) {
|
||||
var point2 = this._proj.inverse([point.x, point.y]);
|
||||
return new L.LatLng(point2[1], point2[0], unbounded);
|
||||
}
|
||||
});
|
||||
|
||||
L.Proj.CRS = L.Class.extend({
|
||||
includes: L.CRS,
|
||||
|
||||
options: {
|
||||
transformation: new L.Transformation(1, 0, -1, 0)
|
||||
},
|
||||
|
||||
initialize: function(a, b, c) {
|
||||
var code, proj, def, options;
|
||||
|
||||
if (L.Proj._isProj4Obj(a)) {
|
||||
proj = a;
|
||||
code = proj.srsCode;
|
||||
options = b || {};
|
||||
|
||||
this.projection = new L.Proj.Projection(proj);
|
||||
} else {
|
||||
code = a;
|
||||
def = b;
|
||||
options = c || {};
|
||||
this.projection = new L.Proj.Projection(code, def);
|
||||
}
|
||||
|
||||
L.Util.setOptions(this, options);
|
||||
this.code = code;
|
||||
this.transformation = this.options.transformation;
|
||||
|
||||
if (this.options.origin) {
|
||||
this.transformation =
|
||||
new L.Transformation(1, -this.options.origin[0],
|
||||
-1, this.options.origin[1]);
|
||||
}
|
||||
|
||||
if (this.options.scales) {
|
||||
this._scales = this.options.scales;
|
||||
} else if (this.options.resolutions) {
|
||||
this._scales = [];
|
||||
for (var i = this.options.resolutions.length - 1; i >= 0; i--) {
|
||||
if (this.options.resolutions[i]) {
|
||||
this._scales[i] = 1 / this.options.resolutions[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.scale = function(zoom) {
|
||||
return this._scales[zoom];
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
L.Proj.CRS.TMS = L.Proj.CRS.extend({
|
||||
options: {
|
||||
tileSize: 256
|
||||
},
|
||||
|
||||
initialize: function(a, b, c, d) {
|
||||
var code,
|
||||
def,
|
||||
proj,
|
||||
projectedBounds,
|
||||
options;
|
||||
|
||||
if (L.Proj._isProj4Obj(a)) {
|
||||
proj = a;
|
||||
projectedBounds = b;
|
||||
options = c || {};
|
||||
options.origin = [projectedBounds[0], projectedBounds[3]];
|
||||
L.Proj.CRS.prototype.initialize.call(this, proj, options);
|
||||
} else {
|
||||
code = a;
|
||||
def = b;
|
||||
projectedBounds = c;
|
||||
options = d || {};
|
||||
options.origin = [projectedBounds[0], projectedBounds[3]];
|
||||
L.Proj.CRS.prototype.initialize.call(this, code, def, options);
|
||||
}
|
||||
|
||||
this.projectedBounds = projectedBounds;
|
||||
|
||||
this._sizes = this._calculateSizes();
|
||||
},
|
||||
|
||||
_calculateSizes: function() {
|
||||
var sizes = [],
|
||||
crsBounds = this.projectedBounds,
|
||||
projectedTileSize,
|
||||
upperY,
|
||||
i;
|
||||
for (i = this._scales.length - 1; i >= 0; i--) {
|
||||
if (this._scales[i]) {
|
||||
projectedTileSize = this.options.tileSize / this._scales[i];
|
||||
upperY = crsBounds[1] + Math.ceil((crsBounds[3] - crsBounds[1]) /
|
||||
projectedTileSize) * projectedTileSize;
|
||||
sizes[i] = L.point((crsBounds[2] - crsBounds[0]) / this._scales[i],
|
||||
(upperY - crsBounds[1]) * this._scales[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return sizes;
|
||||
},
|
||||
|
||||
getSize: function(zoom) {
|
||||
return this._sizes[zoom];
|
||||
}
|
||||
});
|
||||
|
||||
L.Proj.TileLayer = {};
|
||||
|
||||
// Note: deprecated and not necessary since 0.7, will be removed
|
||||
L.Proj.TileLayer.TMS = L.TileLayer.extend({
|
||||
options: {
|
||||
continuousWorld: true
|
||||
},
|
||||
|
||||
initialize: function(urlTemplate, crs, options) {
|
||||
var boundsMatchesGrid = true,
|
||||
scaleTransforms,
|
||||
upperY,
|
||||
crsBounds,
|
||||
i;
|
||||
|
||||
if (!(crs instanceof L.Proj.CRS.TMS)) {
|
||||
throw 'CRS is not L.Proj.CRS.TMS.';
|
||||
}
|
||||
|
||||
L.TileLayer.prototype.initialize.call(this, urlTemplate, options);
|
||||
this.crs = crs;
|
||||
crsBounds = this.crs.projectedBounds;
|
||||
|
||||
// Verify grid alignment
|
||||
for (i = this.options.minZoom; i < this.options.maxZoom && boundsMatchesGrid; i++) {
|
||||
var gridHeight = (crsBounds[3] - crsBounds[1]) /
|
||||
this._projectedTileSize(i);
|
||||
boundsMatchesGrid = Math.abs(gridHeight - Math.round(gridHeight)) > 1e-3;
|
||||
}
|
||||
|
||||
if (!boundsMatchesGrid) {
|
||||
scaleTransforms = {};
|
||||
for (i = this.options.minZoom; i < this.options.maxZoom; i++) {
|
||||
upperY = crsBounds[1] + Math.ceil((crsBounds[3] - crsBounds[1]) /
|
||||
this._projectedTileSize(i)) * this._projectedTileSize(i);
|
||||
scaleTransforms[this.crs.scale(i)] = new L.Transformation(1, -crsBounds[0], -1, upperY);
|
||||
}
|
||||
|
||||
this.crs = new L.Proj.CRS.TMS(this.crs.projection._proj, crsBounds, this.crs.options);
|
||||
this.crs.transformation = new L.Proj.ScaleDependantTransformation(scaleTransforms);
|
||||
}
|
||||
},
|
||||
|
||||
getTileUrl: function(tilePoint) {
|
||||
var zoom = this._map.getZoom(),
|
||||
gridHeight = Math.ceil(
|
||||
(this.crs.projectedBounds[3] - this.crs.projectedBounds[1]) /
|
||||
this._projectedTileSize(zoom));
|
||||
|
||||
return L.Util.template(this._url, L.Util.extend({
|
||||
s: this._getSubdomain(tilePoint),
|
||||
z: this._getZoomForUrl(),
|
||||
x: tilePoint.x,
|
||||
y: gridHeight - tilePoint.y - 1
|
||||
}, this.options));
|
||||
},
|
||||
|
||||
_projectedTileSize: function(zoom) {
|
||||
return (this.options.tileSize / this.crs.scale(zoom));
|
||||
}
|
||||
});
|
||||
|
||||
L.Proj.GeoJSON = L.GeoJSON.extend({
|
||||
initialize: function(geojson, options) {
|
||||
if (geojson.crs && geojson.crs.type === 'name') {
|
||||
var crs = new L.Proj.CRS(geojson.crs.properties.name);
|
||||
options = options || {};
|
||||
options.coordsToLatLng = function(coords) {
|
||||
var point = L.point(coords[0], coords[1]);
|
||||
return crs.projection.unproject(point);
|
||||
};
|
||||
}
|
||||
L.GeoJSON.prototype.initialize.call(this, geojson, options);
|
||||
}
|
||||
});
|
||||
|
||||
L.Proj.geoJson = function(geojson, options) {
|
||||
return new L.Proj.GeoJSON(geojson, options);
|
||||
};
|
||||
|
||||
if (typeof L.CRS !== 'undefined') {
|
||||
// This is left here for backwards compatibility
|
||||
L.CRS.proj4js = (function () {
|
||||
return function (code, def, transformation, options) {
|
||||
options = options || {};
|
||||
if (transformation) {
|
||||
options.transformation = transformation;
|
||||
}
|
||||
|
||||
return new L.Proj.CRS(code, def, options);
|
||||
};
|
||||
}());
|
||||
}
|
||||
|
||||
return L.Proj;
|
||||
}));
|
||||
656
assets/js/vendor/pwstrength.js
vendored
Executable file
|
|
@ -0,0 +1,656 @@
|
|||
/*!
|
||||
* jQuery Password Strength plugin for Twitter Bootstrap
|
||||
*
|
||||
* Copyright (c) 2008-2013 Tane Piper
|
||||
* Copyright (c) 2013 Alejandro Blanco
|
||||
* Dual licensed under the MIT and GPL licenses.
|
||||
*/
|
||||
|
||||
(function (jQuery) {
|
||||
// Source: src/rules.js
|
||||
|
||||
|
||||
|
||||
|
||||
var rulesEngine = {};
|
||||
|
||||
try {
|
||||
if (!jQuery && module && module.exports) {
|
||||
var jQuery = require("jquery"),
|
||||
jsdom = require("jsdom").jsdom;
|
||||
jQuery = jQuery(jsdom().parentWindow);
|
||||
}
|
||||
} catch (ignore) {}
|
||||
|
||||
(function ($, rulesEngine) {
|
||||
"use strict";
|
||||
var validation = {};
|
||||
|
||||
rulesEngine.forbiddenSequences = [
|
||||
"0123456789", "abcdefghijklmnopqrstuvxywz", "qwertyuiop", "asdfghjkl",
|
||||
"zxcvbnm", "!@#$%^&*()_+"
|
||||
];
|
||||
|
||||
validation.wordNotEmail = function (options, word, score) {
|
||||
if (word.match(/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i)) {
|
||||
options.instances.errors.push(options.ui.spanError(options, "email_as_password"));
|
||||
return score;
|
||||
}
|
||||
};
|
||||
|
||||
validation.wordLength = function (options, word, score) {
|
||||
var wordlen = word.length,
|
||||
lenScore = Math.pow(wordlen, options.rules.raisePower);
|
||||
if (wordlen < options.common.minChar) {
|
||||
lenScore = (lenScore + score);
|
||||
options.instances.errors.push(options.ui.spanError(options, "password_too_short"));
|
||||
}
|
||||
return lenScore;
|
||||
};
|
||||
|
||||
validation.wordSimilarToUsername = function (options, word, score) {
|
||||
var username = $(options.common.usernameField).val();
|
||||
if (username && word.toLowerCase().match(username.toLowerCase())) {
|
||||
options.instances.errors.push(options.ui.spanError(options, "same_as_username"));
|
||||
return score;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
validation.wordTwoCharacterClasses = function (options, word, score) {
|
||||
if (word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) ||
|
||||
(word.match(/([a-zA-Z])/) && word.match(/([0-9])/)) ||
|
||||
(word.match(/(.[!,@,#,$,%,\^,&,*,?,_,~])/) && word.match(/[a-zA-Z0-9_]/))) {
|
||||
return score;
|
||||
}
|
||||
options.instances.errors.push(options.ui.spanError(options, "two_character_classes"));
|
||||
return false;
|
||||
};
|
||||
|
||||
validation.wordRepetitions = function (options, word, score) {
|
||||
if (word.match(/(.)\1\1/)) {
|
||||
options.instances.errors.push(options.ui.spanError(options, "repeated_character"));
|
||||
return score;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
validation.wordSequences = function (options, word, score) {
|
||||
var found = false,
|
||||
j;
|
||||
if (word.length > 2) {
|
||||
$.each(rulesEngine.forbiddenSequences, function (idx, seq) {
|
||||
var sequences = [seq, seq.split('').reverse().join('')];
|
||||
$.each(sequences, function (idx, sequence) {
|
||||
for (j = 0; j < (word.length - 2); j += 1) { // iterate the word trough a sliding window of size 3:
|
||||
if (sequence.indexOf(word.toLowerCase().substring(j, j + 3)) > -1) {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
if (found) {
|
||||
options.instances.errors.push(options.ui.spanError(options, "sequence_found"));
|
||||
return score;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
validation.wordLowercase = function (options, word, score) {
|
||||
return word.match(/[a-z]/) && score;
|
||||
};
|
||||
|
||||
validation.wordUppercase = function (options, word, score) {
|
||||
return word.match(/[A-Z]/) && score;
|
||||
};
|
||||
|
||||
validation.wordOneNumber = function (options, word, score) {
|
||||
return word.match(/\d+/) && score;
|
||||
};
|
||||
|
||||
validation.wordThreeNumbers = function (options, word, score) {
|
||||
return word.match(/(.*[0-9].*[0-9].*[0-9])/) && score;
|
||||
};
|
||||
|
||||
validation.wordOneSpecialChar = function (options, word, score) {
|
||||
return word.match(/.[!,@,#,$,%,\^,&,*,?,_,~]/) && score;
|
||||
};
|
||||
|
||||
validation.wordTwoSpecialChar = function (options, word, score) {
|
||||
return word.match(/(.*[!,@,#,$,%,\^,&,*,?,_,~].*[!,@,#,$,%,\^,&,*,?,_,~])/) && score;
|
||||
};
|
||||
|
||||
validation.wordUpperLowerCombo = function (options, word, score) {
|
||||
return word.match(/([a-z].*[A-Z])|([A-Z].*[a-z])/) && score;
|
||||
};
|
||||
|
||||
validation.wordLetterNumberCombo = function (options, word, score) {
|
||||
return word.match(/([a-zA-Z])/) && word.match(/([0-9])/) && score;
|
||||
};
|
||||
|
||||
validation.wordLetterNumberCharCombo = function (options, word, score) {
|
||||
return word.match(/([a-zA-Z0-9].*[!,@,#,$,%,\^,&,*,?,_,~])|([!,@,#,$,%,\^,&,*,?,_,~].*[a-zA-Z0-9])/) && score;
|
||||
};
|
||||
|
||||
rulesEngine.validation = validation;
|
||||
|
||||
rulesEngine.executeRules = function (options, word) {
|
||||
var totalScore = 0;
|
||||
|
||||
$.each(options.rules.activated, function (rule, active) {
|
||||
if (active) {
|
||||
var score = options.rules.scores[rule],
|
||||
funct = rulesEngine.validation[rule],
|
||||
result;
|
||||
|
||||
if (!$.isFunction(funct)) {
|
||||
funct = options.rules.extra[rule];
|
||||
}
|
||||
|
||||
if ($.isFunction(funct)) {
|
||||
result = funct(options, word, score);
|
||||
if (result) {
|
||||
totalScore += result;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return totalScore;
|
||||
};
|
||||
}(jQuery, rulesEngine));
|
||||
|
||||
try {
|
||||
if (module && module.exports) {
|
||||
module.exports = rulesEngine;
|
||||
}
|
||||
} catch (ignore) {}
|
||||
|
||||
// Source: src/options.js
|
||||
|
||||
|
||||
|
||||
|
||||
var defaultOptions = {};
|
||||
|
||||
defaultOptions.common = {};
|
||||
defaultOptions.common.minChar = 6;
|
||||
defaultOptions.common.usernameField = "#username";
|
||||
defaultOptions.common.userInputs = [
|
||||
// Selectors for input fields with user input
|
||||
];
|
||||
defaultOptions.common.onLoad = undefined;
|
||||
defaultOptions.common.onKeyUp = undefined;
|
||||
defaultOptions.common.zxcvbn = false;
|
||||
defaultOptions.common.debug = false;
|
||||
|
||||
defaultOptions.rules = {};
|
||||
defaultOptions.rules.extra = {};
|
||||
defaultOptions.rules.scores = {
|
||||
wordNotEmail: -100,
|
||||
wordLength: -50,
|
||||
wordSimilarToUsername: -100,
|
||||
wordSequences: -50,
|
||||
wordTwoCharacterClasses: 2,
|
||||
wordRepetitions: -25,
|
||||
wordLowercase: 1,
|
||||
wordUppercase: 3,
|
||||
wordOneNumber: 3,
|
||||
wordThreeNumbers: 5,
|
||||
wordOneSpecialChar: 3,
|
||||
wordTwoSpecialChar: 5,
|
||||
wordUpperLowerCombo: 2,
|
||||
wordLetterNumberCombo: 2,
|
||||
wordLetterNumberCharCombo: 2
|
||||
};
|
||||
defaultOptions.rules.activated = {
|
||||
wordNotEmail: true,
|
||||
wordLength: true,
|
||||
wordSimilarToUsername: true,
|
||||
wordSequences: true,
|
||||
wordTwoCharacterClasses: false,
|
||||
wordRepetitions: false,
|
||||
wordLowercase: true,
|
||||
wordUppercase: true,
|
||||
wordOneNumber: true,
|
||||
wordThreeNumbers: true,
|
||||
wordOneSpecialChar: true,
|
||||
wordTwoSpecialChar: true,
|
||||
wordUpperLowerCombo: true,
|
||||
wordLetterNumberCombo: true,
|
||||
wordLetterNumberCharCombo: true
|
||||
};
|
||||
defaultOptions.rules.raisePower = 1.4;
|
||||
|
||||
defaultOptions.ui = {};
|
||||
defaultOptions.ui.bootstrap2 = false;
|
||||
defaultOptions.ui.showProgressBar = true;
|
||||
defaultOptions.ui.showPopover = false;
|
||||
defaultOptions.ui.showStatus = false;
|
||||
defaultOptions.ui.spanError = function (options, key) {
|
||||
"use strict";
|
||||
var text = options.ui.errorMessages[key];
|
||||
return '<span style="color: #d52929">' + text + '</span>';
|
||||
};
|
||||
defaultOptions.ui.errorMessages = {
|
||||
password_too_short: "Your password is too short",
|
||||
email_as_password: "Do not use your email as your password",
|
||||
same_as_username: "Your password cannot contain your username",
|
||||
two_character_classes: "Use different character classes",
|
||||
repeated_character: "Too many repetitions",
|
||||
sequence_found: "Your password contains sequences"
|
||||
};
|
||||
defaultOptions.ui.verdicts = ["Weak", "Normal", "Medium", "Strong", "Very Strong"];
|
||||
defaultOptions.ui.showVerdicts = true;
|
||||
defaultOptions.ui.showVerdictsInsideProgressBar = false;
|
||||
defaultOptions.ui.showErrors = false;
|
||||
defaultOptions.ui.container = undefined;
|
||||
defaultOptions.ui.viewports = {
|
||||
progress: undefined,
|
||||
verdict: undefined,
|
||||
errors: undefined
|
||||
};
|
||||
defaultOptions.ui.scores = [14, 26, 38, 50];
|
||||
|
||||
// Source: src/ui.js
|
||||
|
||||
|
||||
|
||||
|
||||
var ui = {};
|
||||
|
||||
(function ($, ui) {
|
||||
"use strict";
|
||||
|
||||
var barClasses = ["danger", "warning", "success"],
|
||||
statusClasses = ["error", "warning", "success"];
|
||||
|
||||
ui.getContainer = function (options, $el) {
|
||||
var $container;
|
||||
|
||||
$container = $(options.ui.container);
|
||||
if (!($container && $container.length === 1)) {
|
||||
$container = $el.parent();
|
||||
}
|
||||
return $container;
|
||||
};
|
||||
|
||||
ui.findElement = function ($container, viewport, cssSelector) {
|
||||
if (viewport) {
|
||||
return $container.find(viewport).find(cssSelector);
|
||||
}
|
||||
return $container.find(cssSelector);
|
||||
};
|
||||
|
||||
ui.getUIElements = function (options, $el) {
|
||||
var $container, result;
|
||||
|
||||
if (options.instances.viewports) {
|
||||
return options.instances.viewports;
|
||||
}
|
||||
|
||||
$container = ui.getContainer(options, $el);
|
||||
|
||||
result = {};
|
||||
result.$progressbar = ui.findElement($container, options.ui.viewports.progress, "div.progress");
|
||||
if (options.ui.showVerdictsInsideProgressBar) {
|
||||
result.$verdict = result.$progressbar.find("span.password-verdict");
|
||||
}
|
||||
|
||||
if (!options.ui.showPopover) {
|
||||
if (!options.ui.showVerdictsInsideProgressBar) {
|
||||
result.$verdict = ui.findElement($container, options.ui.viewports.verdict, "span.password-verdict");
|
||||
}
|
||||
result.$errors = ui.findElement($container, options.ui.viewports.errors, "ul.error-list");
|
||||
}
|
||||
|
||||
options.instances.viewports = result;
|
||||
return result;
|
||||
};
|
||||
|
||||
ui.initProgressBar = function (options, $el) {
|
||||
var $container = ui.getContainer(options, $el),
|
||||
progressbar = "<div class='progress'><div class='";
|
||||
|
||||
if (!options.ui.bootstrap2) {
|
||||
progressbar += "progress-";
|
||||
}
|
||||
progressbar += "bar'>";
|
||||
if (options.ui.showVerdictsInsideProgressBar) {
|
||||
progressbar += "<span class='password-verdict'></span>";
|
||||
}
|
||||
progressbar += "</div></div>";
|
||||
|
||||
if (options.ui.viewports.progress) {
|
||||
$container.find(options.ui.viewports.progress).append(progressbar);
|
||||
} else {
|
||||
$(progressbar).insertAfter($el);
|
||||
}
|
||||
};
|
||||
|
||||
ui.initHelper = function (options, $el, html, viewport) {
|
||||
var $container = ui.getContainer(options, $el);
|
||||
if (viewport) {
|
||||
$container.find(viewport).append(html);
|
||||
} else {
|
||||
$(html).insertAfter($el);
|
||||
}
|
||||
};
|
||||
|
||||
ui.initVerdict = function (options, $el) {
|
||||
ui.initHelper(options, $el, "<span class='password-verdict'></span>",
|
||||
options.ui.viewports.verdict);
|
||||
};
|
||||
|
||||
ui.initErrorList = function (options, $el) {
|
||||
ui.initHelper(options, $el, "<ul class='error-list'></ul>",
|
||||
options.ui.viewports.errors);
|
||||
};
|
||||
|
||||
ui.initPopover = function (options, $el) {
|
||||
$el.popover("destroy");
|
||||
$el.popover({
|
||||
html: true,
|
||||
placement: "bottom",
|
||||
trigger: "manual",
|
||||
content: " "
|
||||
});
|
||||
};
|
||||
|
||||
ui.initUI = function (options, $el) {
|
||||
if (options.ui.showPopover) {
|
||||
ui.initPopover(options, $el);
|
||||
} else {
|
||||
if (options.ui.showErrors) { ui.initErrorList(options, $el); }
|
||||
if (options.ui.showVerdicts && !options.ui.showVerdictsInsideProgressBar) {
|
||||
ui.initVerdict(options, $el);
|
||||
}
|
||||
}
|
||||
if (options.ui.showProgressBar) {
|
||||
ui.initProgressBar(options, $el);
|
||||
}
|
||||
};
|
||||
|
||||
ui.possibleProgressBarClasses = ["danger", "warning", "success"];
|
||||
|
||||
ui.updateProgressBar = function (options, $el, cssClass, percentage) {
|
||||
var $progressbar = ui.getUIElements(options, $el).$progressbar,
|
||||
$bar = $progressbar.find(".progress-bar"),
|
||||
cssPrefix = "progress-";
|
||||
|
||||
if (options.ui.bootstrap2) {
|
||||
$bar = $progressbar.find(".bar");
|
||||
cssPrefix = "";
|
||||
}
|
||||
|
||||
$.each(ui.possibleProgressBarClasses, function (idx, value) {
|
||||
$bar.removeClass(cssPrefix + "bar-" + value);
|
||||
});
|
||||
$bar.addClass(cssPrefix + "bar-" + barClasses[cssClass]);
|
||||
$bar.css("width", percentage + '%');
|
||||
};
|
||||
|
||||
ui.updateVerdict = function (options, $el, text) {
|
||||
var $verdict = ui.getUIElements(options, $el).$verdict;
|
||||
$verdict.text(text);
|
||||
};
|
||||
|
||||
ui.updateErrors = function (options, $el) {
|
||||
var $errors = ui.getUIElements(options, $el).$errors,
|
||||
html = "";
|
||||
$.each(options.instances.errors, function (idx, err) {
|
||||
html += "<li>" + err + "</li>";
|
||||
});
|
||||
$errors.html(html);
|
||||
};
|
||||
|
||||
ui.updatePopover = function (options, $el, verdictText) {
|
||||
var popover = $el.data("bs.popover"),
|
||||
html = "",
|
||||
hide = true;
|
||||
|
||||
if (options.ui.showVerdicts &&
|
||||
!options.ui.showVerdictsInsideProgressBar &&
|
||||
verdictText.length > 0) {
|
||||
html = "<h5><span class='password-verdict'>" + verdictText +
|
||||
"</span></h5>";
|
||||
hide = false;
|
||||
}
|
||||
if (options.ui.showErrors) {
|
||||
html += "<div>Errors:<ul class='error-list' style='margin-bottom: 0;'>";
|
||||
$.each(options.instances.errors, function (idx, err) {
|
||||
html += "<li>" + err + "</li>";
|
||||
hide = false;
|
||||
});
|
||||
html += "</ul></div>";
|
||||
}
|
||||
|
||||
if (hide) {
|
||||
$el.popover("hide");
|
||||
return;
|
||||
}
|
||||
|
||||
if (options.ui.bootstrap2) { popover = $el.data("popover"); }
|
||||
|
||||
if (popover.$arrow && popover.$arrow.parents("body").length > 0) {
|
||||
$el.find("+ .popover .popover-content").html(html);
|
||||
} else {
|
||||
// It's hidden
|
||||
popover.options.content = html;
|
||||
$el.popover("show");
|
||||
}
|
||||
};
|
||||
|
||||
ui.updateFieldStatus = function (options, $el, cssClass) {
|
||||
var targetClass = options.ui.bootstrap2 ? ".control-group" : ".form-group",
|
||||
$container = $el.parents(targetClass).first();
|
||||
|
||||
$.each(statusClasses, function (idx, css) {
|
||||
if (!options.ui.bootstrap2) { css = "has-" + css; }
|
||||
$container.removeClass(css);
|
||||
});
|
||||
|
||||
cssClass = statusClasses[cssClass];
|
||||
if (!options.ui.bootstrap2) { cssClass = "has-" + cssClass; }
|
||||
$container.addClass(cssClass);
|
||||
};
|
||||
|
||||
ui.percentage = function (score, maximun) {
|
||||
var result = Math.floor(100 * score / maximun);
|
||||
result = result < 0 ? 0 : result;
|
||||
result = result > 100 ? 100 : result;
|
||||
return result;
|
||||
};
|
||||
|
||||
ui.getVerdictAndCssClass = function (options, score) {
|
||||
var cssClass, verdictText, level;
|
||||
|
||||
if (score <= 0) {
|
||||
cssClass = 0;
|
||||
level = -1;
|
||||
verdictText = options.ui.verdicts[0];
|
||||
} else if (score < options.ui.scores[0]) {
|
||||
cssClass = 0;
|
||||
level = 0;
|
||||
verdictText = options.ui.verdicts[0];
|
||||
} else if (score < options.ui.scores[1]) {
|
||||
cssClass = 0;
|
||||
level = 1;
|
||||
verdictText = options.ui.verdicts[1];
|
||||
} else if (score < options.ui.scores[2]) {
|
||||
cssClass = 1;
|
||||
level = 2;
|
||||
verdictText = options.ui.verdicts[2];
|
||||
} else if (score < options.ui.scores[3]) {
|
||||
cssClass = 1;
|
||||
level = 3;
|
||||
verdictText = options.ui.verdicts[3];
|
||||
} else {
|
||||
cssClass = 2;
|
||||
level = 4;
|
||||
verdictText = options.ui.verdicts[4];
|
||||
}
|
||||
|
||||
return [verdictText, cssClass, level];
|
||||
};
|
||||
|
||||
ui.updateUI = function (options, $el, score) {
|
||||
var cssClass, barPercentage, verdictText;
|
||||
|
||||
cssClass = ui.getVerdictAndCssClass(options, score);
|
||||
verdictText = cssClass[0];
|
||||
cssClass = cssClass[1];
|
||||
|
||||
if (options.ui.showProgressBar) {
|
||||
barPercentage = ui.percentage(score, options.ui.scores[3]);
|
||||
ui.updateProgressBar(options, $el, cssClass, barPercentage);
|
||||
if (options.ui.showVerdictsInsideProgressBar) {
|
||||
ui.updateVerdict(options, $el, verdictText);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.ui.showStatus) {
|
||||
ui.updateFieldStatus(options, $el, cssClass);
|
||||
}
|
||||
|
||||
if (options.ui.showPopover) {
|
||||
ui.updatePopover(options, $el, verdictText);
|
||||
} else {
|
||||
if (options.ui.showVerdicts && !options.ui.showVerdictsInsideProgressBar) {
|
||||
ui.updateVerdict(options, $el, verdictText);
|
||||
}
|
||||
if (options.ui.showErrors) {
|
||||
ui.updateErrors(options, $el);
|
||||
}
|
||||
}
|
||||
};
|
||||
}(jQuery, ui));
|
||||
|
||||
// Source: src/methods.js
|
||||
|
||||
|
||||
|
||||
|
||||
var methods = {};
|
||||
|
||||
(function ($, methods) {
|
||||
"use strict";
|
||||
var onKeyUp, applyToAll;
|
||||
|
||||
onKeyUp = function (event) {
|
||||
var $el = $(event.target),
|
||||
options = $el.data("pwstrength-bootstrap"),
|
||||
word = $el.val(),
|
||||
userInputs,
|
||||
verdictText,
|
||||
verdictLevel,
|
||||
score;
|
||||
|
||||
options.instances.errors = [];
|
||||
if (options.common.zxcvbn) {
|
||||
score = zxcvbn(word, options.common.userInputs).entropy;
|
||||
} else {
|
||||
score = rulesEngine.executeRules(options, word);
|
||||
}
|
||||
ui.updateUI(options, $el, score);
|
||||
verdictText = ui.getVerdictAndCssClass(options, score);
|
||||
verdictLevel = verdictText[2];
|
||||
verdictText = verdictText[0];
|
||||
|
||||
if (options.common.debug) { console.log(score + ' - ' + verdictText); }
|
||||
|
||||
if ($.isFunction(options.common.onKeyUp)) {
|
||||
options.common.onKeyUp(event, {
|
||||
score: score,
|
||||
verdictText: verdictText,
|
||||
verdictLevel: verdictLevel
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
methods.init = function (settings) {
|
||||
this.each(function (idx, el) {
|
||||
// Make it deep extend (first param) so it extends too the
|
||||
// rules and other inside objects
|
||||
var clonedDefaults = $.extend(true, {}, defaultOptions),
|
||||
localOptions = $.extend(true, clonedDefaults, settings),
|
||||
$el = $(el);
|
||||
|
||||
localOptions.instances = {};
|
||||
$el.data("pwstrength-bootstrap", localOptions);
|
||||
$el.on("keyup", onKeyUp);
|
||||
$el.on("change", onKeyUp);
|
||||
$el.on("onpaste", onKeyUp);
|
||||
|
||||
ui.initUI(localOptions, $el);
|
||||
if ($.trim($el.val())) { // Not empty, calculate the strength
|
||||
$el.trigger("keyup");
|
||||
}
|
||||
|
||||
if ($.isFunction(localOptions.common.onLoad)) {
|
||||
localOptions.common.onLoad();
|
||||
}
|
||||
});
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
methods.destroy = function () {
|
||||
this.each(function (idx, el) {
|
||||
var $el = $(el),
|
||||
options = $el.data("pwstrength-bootstrap"),
|
||||
elements = ui.getUIElements(options, $el);
|
||||
elements.$progressbar.remove();
|
||||
elements.$verdict.remove();
|
||||
elements.$errors.remove();
|
||||
$el.removeData("pwstrength-bootstrap");
|
||||
});
|
||||
};
|
||||
|
||||
methods.forceUpdate = function () {
|
||||
this.each(function (idx, el) {
|
||||
var event = { target: el };
|
||||
onKeyUp(event);
|
||||
});
|
||||
};
|
||||
|
||||
methods.addRule = function (name, method, score, active) {
|
||||
this.each(function (idx, el) {
|
||||
var options = $(el).data("pwstrength-bootstrap");
|
||||
|
||||
options.rules.activated[name] = active;
|
||||
options.rules.scores[name] = score;
|
||||
options.rules.extra[name] = method;
|
||||
});
|
||||
};
|
||||
|
||||
applyToAll = function (rule, prop, value) {
|
||||
this.each(function (idx, el) {
|
||||
$(el).data("pwstrength-bootstrap").rules[prop][rule] = value;
|
||||
});
|
||||
};
|
||||
|
||||
methods.changeScore = function (rule, score) {
|
||||
applyToAll.call(this, rule, "scores", score);
|
||||
};
|
||||
|
||||
methods.ruleActive = function (rule, active) {
|
||||
applyToAll.call(this, rule, "activated", active);
|
||||
};
|
||||
|
||||
$.fn.pwstrength = function (method) {
|
||||
var result;
|
||||
|
||||
if (methods[method]) {
|
||||
result = methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
||||
} else if (typeof method === "object" || !method) {
|
||||
result = methods.init.apply(this, arguments);
|
||||
} else {
|
||||
$.error("Method " + method + " does not exist on jQuery.pwstrength-bootstrap");
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}(jQuery, methods));
|
||||
}(jQuery));
|
||||
1
assets/js/vendor/zxcvbn-async.js
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
(function(){var a;a=function(){var a,b;b=document.createElement("script");b.src="/static/js/vendor/zxcvbn.js";b.type="text/javascript";b.async=!0;a=document.getElementsByTagName("script")[0];return a.parentNode.insertBefore(b,a)};null!=window.attachEvent?window.attachEvent("onload",a):window.addEventListener("load",a,!1)}).call(this);
|
||||
44
assets/js/vendor/zxcvbn.js
vendored
Normal file
36
circle.yml
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
machine:
|
||||
services:
|
||||
- rabbitmq-server
|
||||
environment:
|
||||
EMAIL_USER: notused
|
||||
EMAIL_PASSWORD: notused
|
||||
MESSAGEBIRD_USERNAME: notused
|
||||
MESSAGEBIRD_KEY: notused
|
||||
DB_NAME: circle_test
|
||||
DB_USERNAME: ubuntu
|
||||
DB_PASSWORD:
|
||||
DJANGO_HOSTNAME: localhost:8000
|
||||
DJANGO_ALLOWED_HOSTS: '*'
|
||||
DJANGO_LOGFILE: /tmp/django.log
|
||||
SECRET_KEY: 'integration-test-only'
|
||||
DJANGO_SETTINGS_MODULE: happinesspackets.settings.ci
|
||||
PORTAL_CELERY_TASK_QUEUE: celery
|
||||
PYTHONUNBUFFERED: x
|
||||
|
||||
dependencies:
|
||||
override:
|
||||
- pip install -U --exists-action=s -r requirements/ci.txt || (echo 'Retrying pip'; pip install -U --exists-action=s -r requirements/ci.txt) || (echo 'Retrying pip 2'; pip install -U --exists-action=s -r requirements/ci.txt)
|
||||
|
||||
test:
|
||||
pre:
|
||||
- ./manage.py collectstatic --noinput:
|
||||
parallel: true
|
||||
override:
|
||||
- ./run_ci_tests.bash:
|
||||
parallel: true
|
||||
timeout: 600
|
||||
|
||||
general:
|
||||
artifacts:
|
||||
- "selenium-screenshots"
|
||||
- "htmlcov"
|
||||
1
happinesspackets/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
__author__ = 'erik'
|
||||
1
happinesspackets/messaging/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
__author__ = 'erik'
|
||||
103
happinesspackets/messaging/forms.py
Normal file
|
|
@ -0,0 +1,103 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
|
||||
from crispy_forms.helper import FormHelper
|
||||
from crispy_forms.layout import Submit, Layout, Fieldset, HTML
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db.models import Q
|
||||
from django.utils import timezone
|
||||
|
||||
from .models import Message, strip_email
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def validate_email(email):
|
||||
timeframe = timezone.now() - timedelta(hours=24)
|
||||
stripped_email = strip_email(email)
|
||||
recent_message_count = Message.objects.filter(Q(sender_email_stripped=stripped_email) | Q(recipient_email_stripped=stripped_email), created__gte=timeframe).count()
|
||||
if recent_message_count > settings.MAX_MESSAGES:
|
||||
raise forms.ValidationError("We can't send emails to this address at this time. You can try again in 24 hours.")
|
||||
|
||||
|
||||
class MessageSendForm(forms.ModelForm):
|
||||
hp = forms.CharField(label="do not fill", required=False)
|
||||
|
||||
class Meta:
|
||||
model = Message
|
||||
fields = ['sender_name', 'sender_email', 'recipient_name', 'recipient_email', 'message',
|
||||
'sender_named', 'sender_approved_public', 'sender_approved_public_named']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MessageSendForm, self).__init__(*args, **kwargs)
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_class = 'form-horizontal'
|
||||
self.helper.label_class = 'col-md-3'
|
||||
self.helper.field_class = 'col-md-8'
|
||||
|
||||
self.fields['sender_name'].label = 'Name'
|
||||
self.fields['sender_email'].label = 'Email'
|
||||
self.fields['sender_email'].help_text = "We'll send you a confirmation link before sending your message out."
|
||||
self.fields['sender_email'].validators = [validate_email]
|
||||
self.fields['recipient_name'].label = 'Name'
|
||||
self.fields['recipient_email'].label = 'Email'
|
||||
self.fields['recipient_email'].validators = [validate_email]
|
||||
self.fields['message'].help_text = 'Writer\'s block? Check out our <a href="%s">message inspiration</a>.' % reverse('messaging:inspiration')
|
||||
self.fields['sender_named'].label = 'I agree to share my name and email address with the recipient.'
|
||||
self.fields['sender_approved_public'].label = "I agree to publish this message and display it publicly in the Happiness Archive."
|
||||
self.fields['sender_approved_public_named'].label = "... and I agree to display our names publicly too."
|
||||
self.fields['sender_approved_public_named'].help_text = "Note: We only publish information if both the sender and the recipients agree."
|
||||
|
||||
self.helper.layout = Layout(
|
||||
Fieldset('This Happiness Packet is from...', 'sender_name', 'sender_email', 'hp'),
|
||||
Fieldset("Send this Happiness Packet to...", 'recipient_name', 'recipient_email'),
|
||||
Fieldset("Your message is...", 'message'),
|
||||
Fieldset("Privacy and permissions", 'sender_named', 'sender_approved_public', 'sender_approved_public_named'),
|
||||
HTML("<br>"),
|
||||
Submit('submit', 'Send some happiness', css_class='btn-lg centered'),
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
super(MessageSendForm, self).clean()
|
||||
if self.cleaned_data.get('hp'):
|
||||
raise forms.ValidationError('')
|
||||
if self.cleaned_data.get('sender_approved_public_named') and not self.cleaned_data.get('sender_approved_public'):
|
||||
self.add_error('sender_approved_public_named', "If you want us to publish the message including your names, "
|
||||
"you must also check 'I agree to publish this message and"
|
||||
"display it publicly in the Happiness Archive'")
|
||||
|
||||
|
||||
class MessageRecipientForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Message
|
||||
fields = ['recipient_approved_public', 'recipient_approved_public_named']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MessageRecipientForm, self).__init__(*args, **kwargs)
|
||||
self.helper = FormHelper()
|
||||
self.helper.form_class = 'form-horizontal'
|
||||
self.helper.label_class = 'col-md-3'
|
||||
self.helper.field_class = 'col-md-8'
|
||||
|
||||
self.fields['recipient_approved_public'].label = "I agree to publish this message and display it publicly in the Happiness Archive."
|
||||
self.fields['recipient_approved_public_named'].label = "... and I agree to display our names publicly too."
|
||||
self.fields['recipient_approved_public_named'].help_text = "Note: We only publish information if both the sender and the recipients agree."
|
||||
|
||||
self.helper.layout = Layout(
|
||||
Fieldset("Privacy and permissions", 'recipient_approved_public', 'recipient_approved_public_named'),
|
||||
HTML("<br>"),
|
||||
Submit('submit', 'Save privacy choices', css_class='btn-lg centered'),
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
super(MessageRecipientForm, self).clean()
|
||||
if self.cleaned_data.get('recipient_approved_public_named') and not self.cleaned_data.get('recipient_approved_public'):
|
||||
self.add_error('recipient_approved_public_named', "If you want us to publish the message including your "
|
||||
"names, you must also check 'I agree to publish this "
|
||||
"message and display it publicly in the Happiness "
|
||||
"Archive.'")
|
||||
44
happinesspackets/messaging/migrations/0001_initial.py
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.2 on 2016-03-06 15:10
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
import model_utils.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Message',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
|
||||
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
|
||||
('identifier', models.CharField(db_index=True, max_length=255)),
|
||||
('status', models.CharField(choices=[('pending_sender_confirmation', 'pending_sender_confirmation'), ('sent', 'sent'), ('read', 'read')], default='pending_sender_confirmation', max_length=255)),
|
||||
('sender_name', models.CharField(max_length=255)),
|
||||
('sender_email', models.EmailField(max_length=254)),
|
||||
('sender_email_token', models.CharField(db_index=True, max_length=255)),
|
||||
('sender_ip', models.GenericIPAddressField()),
|
||||
('recipient_name', models.CharField(max_length=255)),
|
||||
('recipient_email', models.EmailField(max_length=254)),
|
||||
('recipient_email_token', models.CharField(db_index=True, max_length=255)),
|
||||
('message', models.TextField()),
|
||||
('sender_named', models.BooleanField(default=False)),
|
||||
('sender_approved_public', models.BooleanField(default=False)),
|
||||
('sender_approved_public_named', models.BooleanField(default=False)),
|
||||
('recipient_approved_public', models.BooleanField(default=False)),
|
||||
('recipient_approved_public_named', models.BooleanField(default=False)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.2 on 2016-03-18 08:43
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import django.utils.timezone
|
||||
import model_utils.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('messaging', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='BlacklistedEmail',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created', model_utils.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, verbose_name='created')),
|
||||
('modified', model_utils.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, verbose_name='modified')),
|
||||
('email', models.EmailField(max_length=254)),
|
||||
('confirmation_ip', models.GenericIPAddressField()),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.2 on 2016-04-03 09:49
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('messaging', '0002_blacklistedemail'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='blacklistedemail',
|
||||
name='stripped_email',
|
||||
field=models.CharField(default=1, max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.2 on 2016-04-03 15:42
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('messaging', '0003_blacklistedemail_stripped_email'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='message',
|
||||
name='recipient_email_stripped',
|
||||
field=models.CharField(default='', max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='message',
|
||||
name='sender_email_stripped',
|
||||
field=models.CharField(default='', max_length=255),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.9.2 on 2016-04-23 17:36
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('messaging', '0004_auto_20160403_1742'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='message',
|
||||
options={'ordering': ['-created']},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='message',
|
||||
name='admin_approved_public',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
1
happinesspackets/messaging/migrations/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
__author__ = 'erik'
|
||||
116
happinesspackets/messaging/models.py
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
import re
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.crypto import salted_hmac
|
||||
from model_utils import Choices
|
||||
from model_utils.models import TimeStampedModel
|
||||
|
||||
from happinesspackets.utils.misc import readable_random_token, send_html_mail
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
BLACKLIST_HMAC_SALT = 'happinesspackets.messaging.views.BlacklistEmailView'
|
||||
|
||||
|
||||
class Message(TimeStampedModel):
|
||||
STATUS = Choices(
|
||||
'pending_sender_confirmation',
|
||||
'sent',
|
||||
'read',
|
||||
)
|
||||
|
||||
identifier = models.CharField(max_length=255, db_index=True)
|
||||
status = models.CharField(choices=STATUS, default=STATUS.pending_sender_confirmation, max_length=255)
|
||||
|
||||
sender_name = models.CharField(max_length=255)
|
||||
sender_email = models.EmailField()
|
||||
sender_email_stripped = models.CharField(max_length=255)
|
||||
sender_email_token = models.CharField(max_length=255, db_index=True)
|
||||
sender_ip = models.GenericIPAddressField()
|
||||
|
||||
recipient_name = models.CharField(max_length=255)
|
||||
recipient_email = models.EmailField()
|
||||
recipient_email_stripped = models.CharField(max_length=255)
|
||||
recipient_email_token = models.CharField(max_length=255, db_index=True)
|
||||
|
||||
message = models.TextField()
|
||||
|
||||
sender_named = models.BooleanField(default=False)
|
||||
sender_approved_public = models.BooleanField(default=False)
|
||||
sender_approved_public_named = models.BooleanField(default=False)
|
||||
recipient_approved_public = models.BooleanField(default=False)
|
||||
recipient_approved_public_named = models.BooleanField(default=False)
|
||||
|
||||
admin_approved_public = models.BooleanField(default=False)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-created']
|
||||
|
||||
def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
|
||||
self.sender_email_stripped = strip_email(self.sender_email)
|
||||
self.recipient_email_stripped = strip_email(self.recipient_email)
|
||||
if not self.pk or force_insert:
|
||||
self.identifier = readable_random_token(alphanumeric=True)
|
||||
while Message.objects.filter(identifier=self.identifier).count():
|
||||
self.identifier = readable_random_token(alphanumeric=True) # pragma: no cover
|
||||
return super(Message, self).save(force_insert, force_update, using, update_fields)
|
||||
|
||||
def send_sender_confirmation(self, use_https, domain):
|
||||
stripped_email = strip_email(self.sender_email)
|
||||
if BlacklistedEmail.objects.filter(stripped_email=stripped_email).count():
|
||||
return
|
||||
|
||||
blacklist_digest = salted_hmac(BLACKLIST_HMAC_SALT, self.sender_email).hexdigest()
|
||||
blacklist_url = reverse('messaging:blacklist_email', kwargs={'email': self.sender_email, 'digest': blacklist_digest})
|
||||
self.sender_email_token = readable_random_token(alphanumeric=True)
|
||||
context = {
|
||||
'message': self,
|
||||
'protocol': 'https' if use_https else 'http',
|
||||
'domain': domain,
|
||||
'recipient': self.sender_email,
|
||||
'blacklist_url': blacklist_url,
|
||||
}
|
||||
subject = render_to_string('messaging/sender_confirmation_subject.txt', context)
|
||||
subject = ' '.join(subject.splitlines())
|
||||
body_txt = render_to_string('messaging/sender_confirmation_mail.txt', context)
|
||||
body_html = render_to_string('messaging/sender_confirmation_mail.html', context)
|
||||
send_html_mail(subject, body_txt, body_html, self.sender_email)
|
||||
self.save()
|
||||
|
||||
def send_to_recipient(self, use_https, domain):
|
||||
stripped_email = strip_email(self.recipient_email)
|
||||
if BlacklistedEmail.objects.filter(stripped_email=stripped_email).count():
|
||||
return
|
||||
|
||||
blacklist_digest = salted_hmac(BLACKLIST_HMAC_SALT, self.recipient_email).hexdigest()
|
||||
blacklist_url = reverse('messaging:blacklist_email', kwargs={'email': self.recipient_email, 'digest': blacklist_digest})
|
||||
self.recipient_email_token = readable_random_token(alphanumeric=True)
|
||||
self.status = Message.STATUS.sent
|
||||
context = {
|
||||
'message': self,
|
||||
'protocol': 'https' if use_https else 'http',
|
||||
'domain': domain,
|
||||
'recipient': self.recipient_email,
|
||||
'blacklist_url': blacklist_url,
|
||||
}
|
||||
subject = render_to_string('messaging/recipient_subject.txt', context)
|
||||
subject = ' '.join(subject.splitlines())
|
||||
body_txt = render_to_string('messaging/recipient_mail.txt', context)
|
||||
body_html = render_to_string('messaging/recipient_mail.html', context)
|
||||
send_html_mail(subject, body_txt, body_html, self.recipient_email)
|
||||
self.save()
|
||||
|
||||
|
||||
class BlacklistedEmail(TimeStampedModel):
|
||||
email = models.EmailField()
|
||||
stripped_email = models.CharField(max_length=255)
|
||||
confirmation_ip = models.GenericIPAddressField()
|
||||
|
||||
|
||||
def strip_email(email):
|
||||
return re.sub('[^@\w]', '', re.sub('\+\w+', '', email.lower()))
|
||||
1
happinesspackets/messaging/tests/__init__.py
Normal file
|
|
@ -0,0 +1 @@
|
|||
__author__ = 'erik'
|
||||
32
happinesspackets/messaging/tests/test_models.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import factory
|
||||
from django.test import TestCase
|
||||
|
||||
|
||||
class MessageModelFactory(factory.DjangoModelFactory):
|
||||
class Meta:
|
||||
model = 'messaging.Message'
|
||||
|
||||
sender_name = 'Sender sender'
|
||||
sender_email = 'sendersender@null'
|
||||
recipient_name = 'Recipient recipient'
|
||||
recipient_email = 'recipientrecipient+foo@null'
|
||||
sender_ip = '127.0.0.1'
|
||||
message = 'message content'
|
||||
|
||||
|
||||
class BlacklistedEmailFactory(factory.DjangoModelFactory):
|
||||
class Meta:
|
||||
model = 'messaging.BlacklistedEmail'
|
||||
|
||||
email = 'emailemail@null'
|
||||
confirmation_ip = '127.0.0.1'
|
||||
|
||||
|
||||
class MessageModelTest(TestCase):
|
||||
def test_unique_identifier(self):
|
||||
obj1 = MessageModelFactory()
|
||||
obj2 = MessageModelFactory()
|
||||
self.assertNotEqual(obj1.identifier, obj2.identifier)
|
||||
297
happinesspackets/messaging/tests/test_views.py
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.core import mail
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test import TestCase
|
||||
from django.utils.crypto import salted_hmac
|
||||
|
||||
from .test_models import MessageModelFactory, BlacklistedEmailFactory
|
||||
from ..models import Message, BLACKLIST_HMAC_SALT, BlacklistedEmail
|
||||
|
||||
|
||||
class StartViewTest(TestCase):
|
||||
url = reverse('messaging:start')
|
||||
|
||||
def test_renders(self):
|
||||
MessageModelFactory(sender_approved_public=True, sender_approved_public_named=False,
|
||||
recipient_approved_public=True, recipient_approved_public_named=True,
|
||||
admin_approved_public=True)
|
||||
msg = MessageModelFactory(sender_approved_public=True, sender_approved_public_named=True,
|
||||
recipient_approved_public=True, recipient_approved_public_named=False,
|
||||
admin_approved_public=True)
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertNotContains(response, msg.sender_name)
|
||||
self.assertNotContains(response, msg.recipient_name)
|
||||
self.assertContains(response, msg.message)
|
||||
self.assertNotContains(response, msg.sender_email)
|
||||
self.assertNotContains(response, msg.recipient_email)
|
||||
|
||||
|
||||
class FaqViewTest(TestCase):
|
||||
url = reverse('messaging:faq')
|
||||
|
||||
def test_renders(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
class InspirationViewTest(TestCase):
|
||||
url = reverse('messaging:inspiration')
|
||||
|
||||
def test_renders(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
class ArchiveViewTest(TestCase):
|
||||
url = reverse('messaging:archive')
|
||||
|
||||
def test_renders_no_public_messages(self):
|
||||
MessageModelFactory(sender_approved_public=True, sender_approved_public_named=True,
|
||||
recipient_approved_public=True, recipient_approved_public_named=True,
|
||||
admin_approved_public=False)
|
||||
MessageModelFactory(sender_approved_public=False, sender_approved_public_named=True,
|
||||
recipient_approved_public=True, recipient_approved_public_named=True,
|
||||
admin_approved_public=True)
|
||||
MessageModelFactory(sender_approved_public=True, sender_approved_public_named=True,
|
||||
recipient_approved_public=False, recipient_approved_public_named=True,
|
||||
admin_approved_public=True)
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertFalse(response.context['message_list'].count())
|
||||
|
||||
def test_renders_named_messages(self):
|
||||
msg = MessageModelFactory(sender_approved_public=True, sender_approved_public_named=True,
|
||||
recipient_approved_public=True, recipient_approved_public_named=True,
|
||||
admin_approved_public=True)
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, msg.sender_name)
|
||||
self.assertContains(response, msg.recipient_name)
|
||||
self.assertContains(response, msg.message)
|
||||
self.assertNotContains(response, msg.sender_email)
|
||||
self.assertNotContains(response, msg.recipient_email)
|
||||
|
||||
def test_renders_unnamed_messages(self):
|
||||
MessageModelFactory(sender_approved_public=True, sender_approved_public_named=False,
|
||||
recipient_approved_public=True, recipient_approved_public_named=True,
|
||||
admin_approved_public=True)
|
||||
msg = MessageModelFactory(sender_approved_public=True, sender_approved_public_named=True,
|
||||
recipient_approved_public=True, recipient_approved_public_named=False,
|
||||
admin_approved_public=True)
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertNotContains(response, msg.sender_name)
|
||||
self.assertNotContains(response, msg.recipient_name)
|
||||
self.assertContains(response, msg.message)
|
||||
self.assertNotContains(response, msg.sender_email)
|
||||
self.assertNotContains(response, msg.recipient_email)
|
||||
|
||||
|
||||
class BlacklistViewTest(TestCase):
|
||||
url_name = 'messaging:blacklist_email'
|
||||
|
||||
def setUp(self):
|
||||
self.message = MessageModelFactory()
|
||||
self.correct_digest = salted_hmac(BLACKLIST_HMAC_SALT, self.message.recipient_email).hexdigest()
|
||||
self.url_kwargs = {'email': self.message.recipient_email, 'digest': self.correct_digest}
|
||||
self.url = reverse(self.url_name, kwargs=self.url_kwargs)
|
||||
|
||||
def test_renders(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_confirm(self):
|
||||
response = self.client.post(self.url)
|
||||
self.assertRedirects(response, reverse('messaging:start'))
|
||||
obj = BlacklistedEmail.objects.get()
|
||||
self.assertEqual(obj.email, self.message.recipient_email)
|
||||
self.assertEqual(obj.stripped_email, 'recipientrecipient@null')
|
||||
|
||||
def test_validates_digest(self):
|
||||
self.url_kwargs['email'] = self.message.sender_email
|
||||
self.url = reverse(self.url_name, kwargs=self.url_kwargs)
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
response = self.client.post(self.url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
self.assertFalse(BlacklistedEmail.objects.count())
|
||||
|
||||
|
||||
class SendViewTest(TestCase):
|
||||
url = reverse('messaging:send')
|
||||
|
||||
def setUp(self):
|
||||
super(SendViewTest, self).setUp()
|
||||
self.post_data = {
|
||||
'sender_name': 'sender name',
|
||||
'sender_email': 'SEN.DER+FOOBAR@erik.io',
|
||||
'recipient_name': 'recipient name',
|
||||
'recipient_email': 'recipient@erik.io',
|
||||
'message': 'message',
|
||||
'sender_named': True,
|
||||
'sender_approved_public': True,
|
||||
'sender_approved_public_named': True,
|
||||
}
|
||||
|
||||
def test_renders(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_post_valid(self):
|
||||
response = self.client.post(self.url, self.post_data)
|
||||
self.assertRedirects(response, reverse('messaging:sender_confirmation_sent'))
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
message = Message.objects.get()
|
||||
self.assertEqual(message.status, Message.STATUS.pending_sender_confirmation)
|
||||
self.assertEqual(mail.outbox[0].recipients(), [message.sender_email])
|
||||
self.assertTrue(message.identifier in mail.outbox[0].body)
|
||||
self.assertTrue(message.sender_email_token in mail.outbox[0].body)
|
||||
|
||||
def test_post_invalid_conflicting_publicity(self):
|
||||
self.post_data['sender_approved_public'] = False
|
||||
response = self.client.post(self.url, self.post_data)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.context['form'].errors), 1)
|
||||
self.assertEqual(len(mail.outbox), 0)
|
||||
|
||||
def test_post_blacklisted_sender(self):
|
||||
BlacklistedEmailFactory(email='sender@erik.io', stripped_email='sender@erikio')
|
||||
response = self.client.post(self.url, self.post_data)
|
||||
self.assertRedirects(response, reverse('messaging:sender_confirmation_sent'))
|
||||
self.assertEqual(len(mail.outbox), 0)
|
||||
|
||||
def test_post_ratelimited_sender(self):
|
||||
for i in range(settings.MAX_MESSAGES + 1):
|
||||
MessageModelFactory(sender_email='sender@erik.io', sender_email_stripped='sender@erikio')
|
||||
response = self.client.post(self.url, self.post_data)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.context['form'].errors), 1)
|
||||
self.assertEqual(len(mail.outbox), 0)
|
||||
|
||||
def test_post_ratelimited_recipient(self):
|
||||
for i in range(settings.MAX_MESSAGES + 1):
|
||||
MessageModelFactory(recipient_email='sender@erik.io', recipient_email_stripped='recipient@erikio')
|
||||
response = self.client.post(self.url, self.post_data)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.context['form'].errors), 1)
|
||||
self.assertEqual(len(mail.outbox), 0)
|
||||
|
||||
|
||||
class MessageSentViewTest(TestCase):
|
||||
url = reverse('messaging:sender_confirmation_sent')
|
||||
|
||||
def test_renders(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
class MessageSenderConfirmationView(TestCase):
|
||||
url_name = 'messaging:sender_confirm'
|
||||
|
||||
def setUp(self):
|
||||
self.message = MessageModelFactory(sender_email_token='a-b-c', status=Message.STATUS.pending_sender_confirmation)
|
||||
url_kwargs = {'identifier': self.message.identifier, 'token': self.message.sender_email_token}
|
||||
self.url = reverse(self.url_name, kwargs=url_kwargs)
|
||||
|
||||
def test_confirm_anonymous(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertRedirects(response, reverse('messaging:sender_confirmed'))
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.message.refresh_from_db()
|
||||
self.assertEqual(self.message.status, Message.STATUS.sent)
|
||||
self.assertEqual(mail.outbox[0].recipients(), [self.message.recipient_email])
|
||||
self.assertFalse(self.message.sender_name in mail.outbox[0].body)
|
||||
self.assertFalse(self.message.sender_email in mail.outbox[0].body)
|
||||
self.assertTrue(self.message.identifier in mail.outbox[0].body)
|
||||
self.assertTrue(self.message.recipient_email_token in mail.outbox[0].body)
|
||||
|
||||
def test_confirm_named(self):
|
||||
self.message.sender_named = True
|
||||
self.message.save()
|
||||
response = self.client.get(self.url)
|
||||
self.assertRedirects(response, reverse('messaging:sender_confirmed'))
|
||||
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
self.message.refresh_from_db()
|
||||
self.assertTrue(mail.outbox[0].recipients(), [self.message.recipient_email])
|
||||
self.assertTrue(self.message.sender_name in mail.outbox[0].body)
|
||||
self.assertTrue(self.message.identifier in mail.outbox[0].body)
|
||||
|
||||
def test_bad_token(self):
|
||||
self.message.sender_email_token = 'o-t-h-e-r'
|
||||
self.message.recipient_email_token = 'a-b-c'
|
||||
self.message.save()
|
||||
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTrue(response.context['not_found'])
|
||||
|
||||
def test_bad_status(self):
|
||||
self.message.status = Message.STATUS.sent
|
||||
self.message.save()
|
||||
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertTrue(response.context['already_confirmed'])
|
||||
|
||||
def test_confirm_blacklisted_recipient(self):
|
||||
BlacklistedEmailFactory(email='recipient@erik.io', stripped_email='recipientrecipient@null')
|
||||
response = self.client.get(self.url)
|
||||
self.assertRedirects(response, reverse('messaging:sender_confirmed'))
|
||||
self.assertEqual(len(mail.outbox), 0)
|
||||
|
||||
|
||||
class MessageSenderConfirmedView(TestCase):
|
||||
url = reverse('messaging:sender_confirmed')
|
||||
|
||||
def test_renders(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
|
||||
class MessageRecipientMessageUpdate(TestCase):
|
||||
url_name = 'messaging:recipient_message_update'
|
||||
|
||||
def setUp(self):
|
||||
self.message = MessageModelFactory(recipient_email_token='a-b-c', status=Message.STATUS.sent)
|
||||
url_kwargs = {'identifier': self.message.identifier, 'token': self.message.recipient_email_token}
|
||||
self.url = reverse(self.url_name, kwargs=url_kwargs)
|
||||
|
||||
def test_confirm(self):
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_post_valid(self):
|
||||
self.assertFalse(self.message.recipient_approved_public)
|
||||
response = self.client.post(self.url, {'recipient_approved_public': True})
|
||||
self.assertRedirects(response, self.url)
|
||||
self.message.refresh_from_db()
|
||||
self.assertTrue(self.message.recipient_approved_public)
|
||||
|
||||
def test_post_invalid(self):
|
||||
self.assertFalse(self.message.recipient_approved_public_named)
|
||||
response = self.client.post(self.url, {'recipient_approved_public_named': True})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.message.refresh_from_db()
|
||||
self.assertFalse(self.message.recipient_approved_public_named)
|
||||
|
||||
def test_bad_token(self):
|
||||
self.message.sender_email_token = 'a-b-c'
|
||||
self.message.recipient_email_token = 'o-t-h-e-r'
|
||||
self.message.save()
|
||||
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_bad_status(self):
|
||||
self.message.status = Message.STATUS.pending_sender_confirmation
|
||||
self.message.save()
|
||||
|
||||
response = self.client.get(self.url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
20
happinesspackets/messaging/urls.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf.urls import url
|
||||
|
||||
from .views import (StartView, MessageSendView, MessageSenderConfirmationSentView, MessageSenderConfirmationView,
|
||||
MessageSenderConfirmedView, MessageRecipientMessageUpdate, FaqView, ArchiveView, InspirationView,
|
||||
BlacklistEmailView)
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', StartView.as_view(), name='start'),
|
||||
url(r'^faq/$', FaqView.as_view(), name='faq'),
|
||||
url(r'^archive/$', ArchiveView.as_view(), name='archive'),
|
||||
url(r'^inspiration/$', InspirationView.as_view(), name='inspiration'),
|
||||
url(r'^blacklist-email/(?P<email>[\w\.@\+-]+)/(?P<digest>\w+)/$', BlacklistEmailView.as_view(), name='blacklist_email'),
|
||||
url(r'^send/$', MessageSendView.as_view(), name='send'),
|
||||
url(r'^send/confirmation-sent/$', MessageSenderConfirmationSentView.as_view(), name='sender_confirmation_sent'),
|
||||
url(r'^send/confirmation/(?P<identifier>[\w-]+)/(?P<token>[\w-]+)/$', MessageSenderConfirmationView.as_view(), name='sender_confirm'),
|
||||
url(r'^send/confirmed/$', MessageSenderConfirmedView.as_view(), name='sender_confirmed'),
|
||||
url(r'^recipient/(?P<identifier>[\w-]+)/(?P<token>[\w-]+)/$', MessageRecipientMessageUpdate.as_view(), name='recipient_message_update'),
|
||||
]
|
||||
131
happinesspackets/messaging/views.py
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import logging
|
||||
|
||||
from django.contrib import messages
|
||||
from django.core.urlresolvers import reverse, reverse_lazy
|
||||
from django.http import HttpResponseRedirect, Http404
|
||||
from django.utils.crypto import salted_hmac, constant_time_compare
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.html import format_html
|
||||
from django.views.decorators.debug import sensitive_post_parameters
|
||||
from django.views.generic import FormView, TemplateView, UpdateView, ListView
|
||||
|
||||
from .forms import MessageSendForm, MessageRecipientForm
|
||||
from .models import Message, BLACKLIST_HMAC_SALT, BlacklistedEmail, strip_email
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ArchiveListView(ListView):
|
||||
model = Message
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = super(ArchiveListView, self).get_queryset()
|
||||
return queryset.filter(sender_approved_public=True, recipient_approved_public=True, admin_approved_public=True)
|
||||
|
||||
|
||||
class StartView(ArchiveListView):
|
||||
template_name = 'messaging/start.html'
|
||||
|
||||
def get_queryset(self):
|
||||
return super(StartView, self).get_queryset().order_by('?')[:2]
|
||||
|
||||
|
||||
class FaqView(TemplateView):
|
||||
template_name = 'messaging/faq.html'
|
||||
|
||||
|
||||
class ArchiveView(ArchiveListView):
|
||||
template_name = 'messaging/archive.html'
|
||||
|
||||
|
||||
class InspirationView(TemplateView):
|
||||
template_name = 'messaging/inspiration.html'
|
||||
|
||||
|
||||
class BlacklistEmail(object):
|
||||
pass
|
||||
|
||||
|
||||
class BlacklistEmailView(TemplateView):
|
||||
success_url = reverse_lazy('messaging:start')
|
||||
template_name = 'messaging/blacklist_email.html'
|
||||
|
||||
def get_email(self):
|
||||
expected_digest = salted_hmac(BLACKLIST_HMAC_SALT, self.kwargs['email'])
|
||||
if not constant_time_compare(expected_digest.hexdigest(), self.kwargs['digest']):
|
||||
raise Http404
|
||||
return self.kwargs['email']
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(BlacklistEmailView, self).get_context_data(**kwargs)
|
||||
context['email'] = self.get_email()
|
||||
return context
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
email = self.get_email()
|
||||
stripped_email = strip_email(email)
|
||||
BlacklistedEmail.objects.create(email=email, stripped_email=stripped_email, confirmation_ip=self.request.META['REMOTE_ADDR'])
|
||||
message = format_html("We've blacklisted your address and will never email <em>{0}</em> again. Sorry to have bothered you!", email)
|
||||
messages.success(self.request, message)
|
||||
return HttpResponseRedirect(self.success_url)
|
||||
|
||||
|
||||
class MessageSendView(FormView):
|
||||
template_name = 'messaging/message_send_form.html'
|
||||
form_class = MessageSendForm
|
||||
|
||||
@method_decorator(sensitive_post_parameters('message'))
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(MessageSendView, self).dispatch(*args, **kwargs)
|
||||
|
||||
def form_valid(self, form):
|
||||
message = form.save(commit=False)
|
||||
message.sender_ip = self.request.META['REMOTE_ADDR']
|
||||
message.save()
|
||||
message.send_sender_confirmation(self.request.is_secure(), self.request.get_host())
|
||||
return HttpResponseRedirect(reverse('messaging:sender_confirmation_sent'))
|
||||
|
||||
|
||||
class MessageSenderConfirmationSentView(TemplateView):
|
||||
template_name = 'messaging/message_sender_confirmation_sent.html'
|
||||
|
||||
|
||||
class MessageSenderConfirmationView(TemplateView):
|
||||
template_name = 'messaging/message_sender_confirmation_failed.html'
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
try:
|
||||
message = Message.objects.get(identifier=kwargs['identifier'], sender_email_token=kwargs['token'])
|
||||
except Message.DoesNotExist:
|
||||
return self.render_to_response({'not_found': True})
|
||||
|
||||
if message.status != Message.STATUS.pending_sender_confirmation:
|
||||
return self.render_to_response({'already_confirmed': True})
|
||||
|
||||
message.send_to_recipient(self.request.is_secure(), self.request.get_host())
|
||||
return HttpResponseRedirect(reverse('messaging:sender_confirmed'))
|
||||
|
||||
|
||||
class MessageSenderConfirmedView(TemplateView):
|
||||
template_name = 'messaging/message_sender_confirmed.html'
|
||||
|
||||
|
||||
class MessageRecipientMessageUpdate(UpdateView):
|
||||
model = Message
|
||||
form_class = MessageRecipientForm
|
||||
template_name = 'messaging/message_recipient_form.html'
|
||||
slug_field = 'identifier'
|
||||
slug_url_kwarg = 'identifier'
|
||||
|
||||
def get_queryset(self):
|
||||
message = super(MessageRecipientMessageUpdate, self).get_queryset()
|
||||
valid_status = [Message.STATUS.sent, Message.STATUS.read]
|
||||
return message.filter(recipient_email_token=self.kwargs['token'], status__in=valid_status)
|
||||
|
||||
def form_valid(self, form):
|
||||
form.save()
|
||||
messages.success(self.request, "Your choices have been saved.")
|
||||
return HttpResponseRedirect(self.request.path)
|
||||
0
happinesspackets/settings/__init__.py
Normal file
178
happinesspackets/settings/base.py
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
import os
|
||||
|
||||
from django.contrib.messages import constants as messages
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from unipath import Path
|
||||
|
||||
PROJECT_DIR = Path(__file__).ancestor(3)
|
||||
|
||||
# For clean_pyc to work without complaining
|
||||
BASE_DIR = PROJECT_DIR
|
||||
|
||||
DEBUG = False
|
||||
|
||||
ADMINS = (
|
||||
('Sasha Romijn', 'github@mxsasha.eu'),
|
||||
)
|
||||
SERVER_EMAIL = ADMINS[0][1]
|
||||
|
||||
DEFAULT_FROM_EMAIL = "Happiness Packets <info@happinesspackets.io>"
|
||||
|
||||
EMAIL_SUBJECT_PREFIX = "[happinesspackets] "
|
||||
|
||||
DOGSLOW_TIMER = 15
|
||||
DOGSLOW_LOG_TO_FILE = False
|
||||
DOGSLOW_LOGGER = 'dogslow'
|
||||
|
||||
TIME_ZONE = 'Europe/Amsterdam'
|
||||
LANGUAGE_CODE = 'en-GB'
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
USE_TZ = True
|
||||
DATE_FORMAT = 'j F Y'
|
||||
|
||||
CRISPY_TEMPLATE_PACK = 'bootstrap3'
|
||||
|
||||
SECURE_SSL_REDIRECT = True
|
||||
SESSION_COOKIE_SECURE = True
|
||||
CSRF_COOKIE_SECURE = True
|
||||
CSRF_COOKIE_HTTPONLY = True
|
||||
SESSION_COOKIE_NAME = "PHPSESSID"
|
||||
CSRF_COOKIE_NAME = "JSESSIONID"
|
||||
|
||||
ADMIN_ENABLED = False
|
||||
MAX_MESSAGES = 20
|
||||
|
||||
MESSAGE_STORAGE = 'django.contrib.messages.storage.session.SessionStorage'
|
||||
MESSAGE_TAGS = {
|
||||
messages.ERROR: 'danger',
|
||||
}
|
||||
|
||||
|
||||
MEDIA_ROOT = PROJECT_DIR.child('media')
|
||||
MEDIA_URL = '/media/'
|
||||
STATIC_ROOT = PROJECT_DIR.child('static')
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
STATICFILES_DIRS = (
|
||||
PROJECT_DIR.child('assets'),
|
||||
)
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
MIDDLEWARE_CLASSES = [
|
||||
'happinesspackets.utils.middleware.SetRemoteAddrFromForwardedFor',
|
||||
'opbeat.contrib.django.middleware.OpbeatAPMMiddleware',
|
||||
'dogslow.WatchdogMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'happinesspackets.urls'
|
||||
|
||||
# Python dotted path to the WSGI application used by Django's runserver.
|
||||
WSGI_APPLICATION = 'happinesspackets.wsgi.application'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [
|
||||
PROJECT_DIR.child('templates'),
|
||||
],
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
"django.template.context_processors.debug",
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.template.context_processors.i18n",
|
||||
"django.template.context_processors.media",
|
||||
"django.template.context_processors.static",
|
||||
"django.template.context_processors.tz",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
'loaders': [
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
|
||||
'django.contrib.admin',
|
||||
'django.contrib.humanize',
|
||||
|
||||
'django_extensions',
|
||||
'crispy_forms',
|
||||
'happinesspackets.messaging',
|
||||
]
|
||||
|
||||
|
||||
LOGGING = {
|
||||
'version': 1,
|
||||
'disable_existing_loggers': False,
|
||||
'formatters': {
|
||||
'verbose': {
|
||||
'format': '%(asctime)s gunicorn[%(process)d]: %(levelname)s %(name)s: %(message)s'
|
||||
},
|
||||
'simple': {
|
||||
'format': '%(levelname)s %(name)s: %(message)s'
|
||||
},
|
||||
},
|
||||
'filters': {
|
||||
'require_debug_false': {
|
||||
'()': 'django.utils.log.RequireDebugFalse'
|
||||
},
|
||||
'require_debug_true': {
|
||||
'()': 'django.utils.log.RequireDebugTrue'
|
||||
},
|
||||
},
|
||||
'handlers': {
|
||||
'null': {
|
||||
'level': 'DEBUG',
|
||||
'class': 'logging.NullHandler',
|
||||
},
|
||||
'console': {
|
||||
'level': 'INFO',
|
||||
'filters': ['require_debug_true'],
|
||||
'class': 'logging.StreamHandler',
|
||||
'formatter': 'simple'
|
||||
},
|
||||
'mail_admins': {
|
||||
'level': 'ERROR',
|
||||
'filters': ['require_debug_false'],
|
||||
'class': 'django.utils.log.AdminEmailHandler',
|
||||
}
|
||||
},
|
||||
'loggers': {
|
||||
'requests.packages.urllib3.connectionpool': {
|
||||
'handlers': ['null'],
|
||||
'propagate': False,
|
||||
},
|
||||
'stripe': {
|
||||
'handlers': ['null'],
|
||||
'propagate': False,
|
||||
},
|
||||
'': {
|
||||
'handlers': ['console', 'mail_admins'],
|
||||
'level': 'DEBUG',
|
||||
'propagate': True,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def get_env_variable(var_name):
|
||||
""" Get the environment variable or return exception """
|
||||
try:
|
||||
return os.environ[var_name]
|
||||
except KeyError:
|
||||
error_msg = "Set the %s environment variable" % var_name
|
||||
raise ImproperlyConfigured(error_msg)
|
||||
19
happinesspackets/settings/ci.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# noinspection PyUnresolvedReferences
|
||||
from .deployment import * # noqa
|
||||
|
||||
# This is intended to mimic production as close as possible regarding databases and such.
|
||||
|
||||
# Use the same database for tests as live, used for celery interactions
|
||||
DATABASES['default']['TEST'] = DATABASES['default']
|
||||
|
||||
SECURE_SSL_REDIRECT = False
|
||||
SESSION_COOKIE_SECURE = False
|
||||
CSRF_COOKIE_SECURE = False
|
||||
|
||||
PASSWORD_HASHERS = (
|
||||
'django.contrib.auth.hashers.MD5PasswordHasher',
|
||||
)
|
||||
|
||||
DATABASES['default']['CONN_MAX_AGE'] = 0
|
||||
|
||||
SELENIUM_SCREENSHOT_DIR = PROJECT_DIR.child('selenium-screenshots')
|
||||
53
happinesspackets/settings/deployment.py
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
# noinspection PyUnresolvedReferences
|
||||
from .base import * # noqa
|
||||
|
||||
SECRET_KEY = get_env_variable("SECRET_KEY")
|
||||
|
||||
SESSION_COOKIE_AGE = 3600 * 2
|
||||
|
||||
ALLOWED_HOSTS = get_env_variable('DJANGO_ALLOWED_HOSTS').split(',')
|
||||
|
||||
ADMIN_ENABLED = True
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': get_env_variable("DB_NAME"),
|
||||
'USER': get_env_variable("DB_USERNAME"),
|
||||
'PASSWORD': get_env_variable("DB_PASSWORD"),
|
||||
'ATOMIC_REQUESTS': True,
|
||||
'CONN_MAX_AGE': 300,
|
||||
}
|
||||
}
|
||||
|
||||
INSTALLED_APPS.append('opbeat.contrib.django')
|
||||
|
||||
TEMPLATES[0]['OPTIONS']['loaders'] = (
|
||||
('django.template.loaders.cached.Loader', (
|
||||
'django.template.loaders.filesystem.Loader',
|
||||
'django.template.loaders.app_directories.Loader',
|
||||
)),
|
||||
)
|
||||
|
||||
SESSION_ENGINE = "django.contrib.sessions.backends.cached_db"
|
||||
|
||||
CACHES = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
|
||||
'LOCATION': '127.0.0.1:11211',
|
||||
}
|
||||
}
|
||||
|
||||
LOGGING['handlers']['file'] = {
|
||||
'level': 'INFO',
|
||||
'class': 'logging.handlers.WatchedFileHandler',
|
||||
'formatter': 'verbose',
|
||||
'filename': get_env_variable("DJANGO_LOGFILE"),
|
||||
}
|
||||
|
||||
LOGGING['loggers']['']['handlers'].append('file')
|
||||
|
||||
EMAIL_HOST = 'in.mailjet.com'
|
||||
EMAIL_HOST_USER = get_env_variable('EMAIL_USER')
|
||||
EMAIL_HOST_PASSWORD = get_env_variable('EMAIL_PASSWORD')
|
||||
EMAIL_USE_TLS = True
|
||||
43
happinesspackets/settings/dev.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# noinspection PyUnresolvedReferences
|
||||
from .base import * # noqa
|
||||
|
||||
DEBUG = True
|
||||
TEMPLATES[0]['OPTIONS']['debug'] = True
|
||||
CRISPY_FAIL_SILENTLY = False
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': PROJECT_DIR.child('db.sqlite3'),
|
||||
}
|
||||
}
|
||||
|
||||
# EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
|
||||
EMAIL_HOST = 'localhost'
|
||||
EMAIL_PORT = 2525
|
||||
SECRET_KEY = 'only-for-testing'
|
||||
|
||||
INTERNAL_IPS = ('127.0.0.1',)
|
||||
|
||||
SECURE_SSL_REDIRECT = False
|
||||
SESSION_COOKIE_SECURE = False
|
||||
CSRF_COOKIE_SECURE = False
|
||||
|
||||
ADMIN_ENABLED = True
|
||||
|
||||
MIDDLEWARE_CLASSES = [
|
||||
'happinesspackets.utils.middleware.SetRemoteAddrFromForwardedFor',
|
||||
'dogslow.WatchdogMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.csrf.CsrfViewMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'debug_toolbar.middleware.DebugToolbarMiddleware',
|
||||
]
|
||||
|
||||
INSTALLED_APPS += (
|
||||
'debug_toolbar',
|
||||
)
|
||||
|
||||
SELENIUM_SCREENSHOT_DIR = PROJECT_DIR.child('selenium-screenshots')
|
||||
11
happinesspackets/settings/tsting.py
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# noinspection PyUnresolvedReferences
|
||||
|
||||
# This file is intentionally named tsting instead of testing, as otherwise it would be
|
||||
# imported during test discovery by the test runner, thereby accidentally activating the
|
||||
# dev settings.
|
||||
|
||||
from .dev import * # noqa
|
||||
|
||||
PASSWORD_HASHERS = (
|
||||
'django.contrib.auth.hashers.MD5PasswordHasher',
|
||||
)
|
||||
16
happinesspackets/urls.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
import django
|
||||
from django.conf import settings
|
||||
from django.conf.urls import include, url
|
||||
from django.contrib import admin
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^', include('happinesspackets.messaging.urls', namespace="messaging")),
|
||||
]
|
||||
|
||||
if settings.ADMIN_ENABLED or settings.DEBUG:
|
||||
urlpatterns.append(url(r'^drunken-octo-lama/', include(admin.site.urls)))
|
||||
|
||||
if settings.DEBUG:
|
||||
urlpatterns.append(url(r'^media/(?P<path>.*)$', django.views.static.serve, {'document_root': settings.MEDIA_ROOT}))
|
||||
2
happinesspackets/utils/__init__.py
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
from __future__ import unicode_literals
|
||||
__author__ = 'erik'
|
||||
26
happinesspackets/utils/middleware.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
class SetRemoteAddrFromForwardedFor(object):
|
||||
"""
|
||||
Middleware that sets REMOTE_ADDR based on HTTP_X_FORWARDED_FOR, if the
|
||||
latter is set. This is useful if you're sitting behind a reverse proxy that
|
||||
causes each request's REMOTE_ADDR to be set to 127.0.0.1.
|
||||
|
||||
Note that this does NOT validate HTTP_X_FORWARDED_FOR. If you're not behind
|
||||
a reverse proxy that sets HTTP_X_FORWARDED_FOR automatically, do not use
|
||||
this middleware. Anybody can spoof the value of HTTP_X_FORWARDED_FOR, and
|
||||
because this sets REMOTE_ADDR based on HTTP_X_FORWARDED_FOR, that means
|
||||
anybody can "fake" their IP address. Only use this when you can absolutely
|
||||
trust the value of HTTP_X_FORWARDED_FOR.
|
||||
"""
|
||||
def process_request(self, request):
|
||||
try:
|
||||
real_ip = request.META['HTTP_X_FORWARDED_FOR']
|
||||
except KeyError:
|
||||
return None
|
||||
else: # pragma: no cover
|
||||
# HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs. The
|
||||
# client's IP will be the first one.
|
||||
real_ip = real_ip.split(",")[0].strip()
|
||||
request.META['REMOTE_ADDR'] = real_ip
|
||||
47
happinesspackets/utils/misc.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from email.mime.image import MIMEImage
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.mail import EmailMultiAlternatives
|
||||
from django.utils.crypto import get_random_string
|
||||
|
||||
|
||||
def readable_random_token(alphanumeric=False, add_spaces=False, short_token=False, long_token=False):
|
||||
"""
|
||||
Generate a random token that is also reasonably readable.
|
||||
|
||||
Generates 4 segments of 4 characters, seperated by dashes. Can either use digits only (default),
|
||||
or non-confusing letters and digits (alphanumeric=True). If add_spaces is set, spaces are added
|
||||
around the groups. This is intended to prevent mobile phones that see e.g. "-3" as an emoticon.
|
||||
If short_token is set, the token is two segments of four characters.
|
||||
"""
|
||||
segments = 4
|
||||
if short_token:
|
||||
segments = 2
|
||||
if long_token:
|
||||
segments = 8
|
||||
if alphanumeric:
|
||||
allowed_chars = "BCDFGHJLKMNPQRSTVWXYZ23456789"
|
||||
else:
|
||||
allowed_chars = "1234567890"
|
||||
elements = [get_random_string(length=4, allowed_chars=allowed_chars) for i in range(segments)]
|
||||
join_str = "-"
|
||||
if add_spaces:
|
||||
join_str = " - "
|
||||
return join_str.join(elements)
|
||||
|
||||
|
||||
def send_html_mail(subject, body_txt, body_html, recipient):
|
||||
message = EmailMultiAlternatives(subject, body_txt, settings.DEFAULT_FROM_EMAIL, [recipient])
|
||||
message.attach_alternative(body_html, 'text/html')
|
||||
message.mixed_subtype = 'related'
|
||||
|
||||
logo_file = open(settings.STATIC_ROOT.child('images').child('logo.png'))
|
||||
logo_mime = MIMEImage(logo_file.read())
|
||||
logo_file.close()
|
||||
logo_mime.add_header('Content-ID', '<logo.png@happinesspackets.io>')
|
||||
logo_mime.add_header('Content-Disposition', 'attachment')
|
||||
|
||||
message.attach(logo_mime)
|
||||
message.send()
|
||||
14
happinesspackets/utils/mixins.py
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
from __future__ import unicode_literals
|
||||
from axes.decorators import watch_login
|
||||
from django.utils.decorators import method_decorator
|
||||
|
||||
|
||||
class AxesControlledMixin(object):
|
||||
"""
|
||||
Wrap this view in django-axes' watch-login. Must only be applied to form views.
|
||||
Every form submission failure counts towards the AXES_LOGIN_FAILURE_LIMIT,
|
||||
so do not apply this to all forms - only those sensitive to bruteforcing.
|
||||
"""
|
||||
@method_decorator(watch_login)
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
return super(AxesControlledMixin, self).dispatch(request, *args, **kwargs)
|
||||
2
happinesspackets/utils/tests/__init__.py
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
from __future__ import unicode_literals
|
||||
__author__ = 'erik'
|
||||
19
happinesspackets/utils/tests/test_misc.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
from __future__ import unicode_literals
|
||||
from unittest import TestCase
|
||||
|
||||
from ..misc import readable_random_token
|
||||
|
||||
|
||||
class ReadableRandomTokenTest(TestCase):
|
||||
def test_random_token(self):
|
||||
token1 = readable_random_token()
|
||||
token2 = readable_random_token()
|
||||
self.assertNotEqual(token1, token2)
|
||||
self.assertTrue('-' in token1)
|
||||
self.assertFalse(' ' in token1)
|
||||
self.assertTrue(' - ' in readable_random_token(add_spaces=True))
|
||||
self.assertFalse('1' in readable_random_token(alphanumeric=True))
|
||||
|
||||
self.assertEqual(len(token1), 19)
|
||||
self.assertEqual(len(readable_random_token(short_token=True)), 9)
|
||||
self.assertEqual(len(readable_random_token(long_token=True)), 39)
|
||||
32
happinesspackets/wsgi.py
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
"""
|
||||
WSGI config for happinesspackets project.
|
||||
|
||||
This module contains the WSGI application used by Django's development server
|
||||
and any production WSGI deployments. It should expose a module-level variable
|
||||
named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
|
||||
this application via the ``WSGI_APPLICATION`` setting.
|
||||
|
||||
Usually you will have the standard Django WSGI application here, but it also
|
||||
might make sense to replace the whole Django WSGI application with a custom one
|
||||
that later delegates to the Django one. For example, you could introduce WSGI
|
||||
middleware here, or combine a Django application with an application of another
|
||||
framework.
|
||||
|
||||
"""
|
||||
import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
# We defer to a DJANGO_SETTINGS_MODULE already in the environment. This breaks
|
||||
# if running multiple sites in the same mod_wsgi process. To fix this, use
|
||||
# mod_wsgi daemon mode with each site in its own daemon process, or use
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "happinesspackets.settings")
|
||||
|
||||
# This application object is used by any WSGI server configured to use this
|
||||
# file. This includes Django's development server, if the WSGI_APPLICATION
|
||||
# setting points here.
|
||||
application = get_wsgi_application()
|
||||
|
||||
# Apply WSGI middleware here.
|
||||
# from helloworld.wsgi import HelloWorldApplication
|
||||
# application = HelloWorldApplication(application)
|
||||
10
manage.py
Executable file
|
|
@ -0,0 +1,10 @@
|
|||
#!/usr/bin/env python
|
||||
import os
|
||||
import sys
|
||||
|
||||
if __name__ == "__main__":
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "happinesspackets.settings")
|
||||
|
||||
from django.core.management import execute_from_command_line
|
||||
|
||||
execute_from_command_line(sys.argv)
|
||||
34
requirements/base.txt
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
Django==1.11.5
|
||||
|
||||
# Basic Django extensions
|
||||
django-extensions==1.6.1
|
||||
django-braces==1.8.1
|
||||
django-crispy-forms==1.6.0
|
||||
django-model-utils==2.4
|
||||
dogslow==0.9.7 # For logging details about very slow requests
|
||||
six==1.10.0 # Dependency of django-extensions
|
||||
|
||||
# Basic Python libraries
|
||||
Unipath==1.1 # Better path handling
|
||||
wsgiref==0.1.2 # ???
|
||||
pytz==2015.7 # Timezone data
|
||||
ipython==4.1.1 # Prettier python prompt
|
||||
gnureadline==6.3.3 # Dependency of ipython
|
||||
|
||||
# For generating docs - sphinx and dependencies
|
||||
Sphinx==1.3.6
|
||||
Jinja2==2.8
|
||||
MarkupSafe==0.23
|
||||
Pygments==2.1.2
|
||||
docutils==0.12
|
||||
|
||||
# PEP8 validation with dependencies
|
||||
flake8==2.5.4
|
||||
mccabe==0.4.0
|
||||
pyflakes==1.0.0
|
||||
pep8==1.7.0
|
||||
|
||||
# Misc
|
||||
python-dateutil==2.5.0
|
||||
factory-boy==2.9.2
|
||||
opbeat==3.3
|
||||
5
requirements/ci.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
-r production.txt
|
||||
coverage==4.0.3
|
||||
django-coverage==1.2.4
|
||||
mock==1.3.0
|
||||
selenium==2.52.0
|
||||
7
requirements/dev.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
-r base.txt
|
||||
coverage==4.0.3
|
||||
django-coverage==1.2.4
|
||||
django-debug-toolbar==1.4
|
||||
mock==1.3.0
|
||||
selenium==2.52
|
||||
sqlparse==0.1.18 # Dependency of debug-toolbar
|
||||
4
requirements/production.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
-r base.txt
|
||||
psycopg2==2.6.1
|
||||
gunicorn==19.4.1
|
||||
python-memcached==1.57
|
||||
21
run_ci_tests.bash
Executable file
|
|
@ -0,0 +1,21 @@
|
|||
#!/bin/bash -x
|
||||
# This is a simple script to run our integration tests in parallel on CircleCI. This will be called from circle.yml.
|
||||
# At this time, the script only works for having two nodes.
|
||||
|
||||
ret=0
|
||||
|
||||
case $CIRCLE_NODE_INDEX in
|
||||
0)
|
||||
coverage run ./manage.py test -v 2 --noinput && coverage html --fail-under=90 || ret=$?
|
||||
;;
|
||||
|
||||
1)
|
||||
flake8 happinesspackets || ret=$?
|
||||
./manage.py makemigrations --dry-run --noinput | grep -i 'no changes detected' || ret=$?
|
||||
;;
|
||||
esac
|
||||
|
||||
exit $ret
|
||||
|
||||
|
||||
|
||||
3
setup.cfg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[flake8]
|
||||
exclude=happinesspackets/*/migrations/*
|
||||
ignore=E124,E201,E128,E501
|
||||
3
t
Executable file
|
|
@ -0,0 +1,3 @@
|
|||
export DJANGO_SETTINGS_MODULE=happinesspackets.settings.tsting &&
|
||||
OPBEAT_DISABLE_SEND=true coverage run ./manage.py test $@ &&
|
||||
coverage report --fail-under=100
|
||||
17
templates/404.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h1>Page not found</h1>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
We couldn't find this page.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<a href="/">Back to the front page.</a>
|
||||
</p>
|
||||
|
||||
{% endblock content %}
|
||||
13
templates/500.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h1>Server error</h1>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
Unfortunately, something broke on our side. We've been notified automatically.
|
||||
</p>
|
||||
|
||||
{% endblock content %}
|
||||
7
templates/_email_footer.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
Have a happy day!
|
||||
|
||||
Open-Source Happiness Packets is an open-source project by Sasha Romijn
|
||||
and Mikey Ariel. Need help? Email us at info@happinesspackets.io
|
||||
|
||||
Never want to receive email from us again? Block {{ recipient }}:
|
||||
{{ protocol }}://{{ domain }}{{ blacklist_url }}
|
||||
72
templates/base.html
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
{% load static from staticfiles %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Open-source Happiness Packets</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="https://fonts.googleapis.com/css?family=Lora:400,400italic,700,700italic|Roboto:400,300,300italic,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
|
||||
<link href="{% static 'bootstrap/css/bootstrap.min.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/datepicker.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'css/custom.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'images/favicon.ico' %}" rel="icon" type="image/x-icon">
|
||||
|
||||
<!--[if lt IE 8]>
|
||||
<link href="{% static 'css/bootstrap-ie7.css' %}" rel="stylesheet">
|
||||
<![endif]-->
|
||||
{% block extra_head %}{% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<aside>
|
||||
<div class="sidebar">
|
||||
{% url 'messaging:start' as url %}
|
||||
<a href="{{ url }}"><img src="{% static 'images/logo.png' %}" alt="Open-Source Happiness Packets" class="logo"/></a>
|
||||
<ul class="nav nav-stacked">
|
||||
{% url 'messaging:send' as url %}
|
||||
<li role="presentation" {% if url in request.path %}class="active"{% endif %}><a href="{{ url }}">Send some happiness!</a></li>
|
||||
{% url 'messaging:start' as url %}
|
||||
<li role="presentation" {% if url in request.path %}class="active"{% endif %}><a href="{{ url }}">What are Happiness Packets?</a></li>
|
||||
{% url 'messaging:inspiration' as url %}
|
||||
<li role="presentation" {% if url in request.path %}class="active"{% endif %}><a href="{{ url }}">Get inspired</a></li>
|
||||
{% url 'messaging:faq' as url %}
|
||||
<li role="presentation" {% if url in request.path %}class="active"{% endif %}><a href="{{ url }}">FAQ</a></li>
|
||||
{% url 'messaging:archive' as url %}
|
||||
<li role="presentation" {% if url in request.path %}class="active"{% endif %}><a href="{{ url }}">Happiness Archive</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
<main>
|
||||
<div class="container">
|
||||
<div class="row content">
|
||||
<div class="col-md-10">
|
||||
{% for django_message in messages %}
|
||||
<br>
|
||||
<div class="alert {% if django_message.tags %} alert-{{ django_message.tags }}{% endif %}">
|
||||
{{ django_message }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
</div>
|
||||
<footer><small>
|
||||
<hr>
|
||||
<a href="https://twitter.com/happinesspacket" class="twitter-follow-button" data-show-count="false" data-size="large" data-dnt="true">Follow @happinesspacket</a>
|
||||
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
|
||||
<br>
|
||||
Open-Source Happiness Packets is an
|
||||
<a href="https://github.com/mxsasha/happinesspackets/">open-source project</a> by
|
||||
<a href="https://twitter.com/mxsash">Sasha Romijn</a> and
|
||||
<a href="https://twitter.com/thatdocslady">Mikey Ariel</a>.
|
||||
<br>
|
||||
Design and artwork by <a href="https://twitter.com/olasitarska">Ola Sitarska</a>.
|
||||
<br>
|
||||
Need help? <a href="mailto:info@happinesspackets.io">info@happinesspackets.io</a>
|
||||
<img class="emoji" src="{% static 'images/emoji/loveletter.png' %}" alt="💌" title="Love letter" aria-label="Emoji: Love letter" style="vertical-align: text-bottom">
|
||||
|
||||
</small></footer>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
36
templates/base_email.html
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="nl">
|
||||
<head>
|
||||
<title>Open-Source Happiness Packets</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="https://fonts.googleapis.com/css?family=Lora:400,400italic,700,700italic|Roboto:400,300,300italic,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
|
||||
</head>
|
||||
|
||||
<body style="background-color: #F23030;font-family: 'Roboto', sans-serif;font-size: 16px;line-height: 1.8em;">
|
||||
<div style="text-align: center;padding: 20px;">
|
||||
<img src="cid:logo.png@happinesspackets.io" alt="Open-source Happiness Packets" style="max-width: 400px; padding: 30px">
|
||||
</div>
|
||||
<div style="margin: auto;background-color: white;max-width: 600px;padding: 30px">
|
||||
{% block content %}{% endblock %}
|
||||
<footer style="line-height: 1.2em;"><small>
|
||||
<hr>
|
||||
<p>
|
||||
Open-source happiness packets is an
|
||||
<a href="https://github.com/erikr/happinesspackets/" style="color: #F64747;">open-source project</a> by
|
||||
<a href="https://twitter.com/mxsash" style="color: #F64747;">Sasha Romijn</a> and
|
||||
<a href="https://twitter.com/thatdocslady" style="color: #F64747;">Mikey Ariel</a>.
|
||||
Design and artwork by <a href="https://twitter.com/olasitarska" style="color: #F64747;">Ola Sitarska</a>.
|
||||
<br>
|
||||
Need help? <a href="mailto:info@happinesspackets.io" style="color: #F64747;">info@happinesspackets.io</a>
|
||||
</p>
|
||||
<p>
|
||||
Never want to receive email from us again?<br>
|
||||
<a href="{{ protocol }}://{{ domain }}{{ blacklist_url }}" style="color: #F64747;">Block {{ recipient }}</a>
|
||||
</p>
|
||||
</small></footer>
|
||||
</div>
|
||||
<br><br>
|
||||
</body>
|
||||
</html>
|
||||
12
templates/messaging/_message_list.html
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
{% for message in message_list %}
|
||||
<h4>
|
||||
{% if message.sender_approved_public_named and message.recipient_approved_public_named %}
|
||||
From {{ message.sender_name }} to {{ message.recipient_name }}
|
||||
{% else %}
|
||||
Anonymous message
|
||||
{% endif %}
|
||||
</h4>
|
||||
<blockquote>
|
||||
{{ message.message|linebreaksbr }}
|
||||
</blockquote>
|
||||
{% endfor %}
|
||||
17
templates/messaging/archive.html
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h2>Happiness Archive</h2>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
When you send a Happiness Packet, you can agree to display your message publicly on
|
||||
this website. If both sender and recipient select this option, the message is published
|
||||
on this page as a part of our Happiness Archive.
|
||||
</p>
|
||||
|
||||
{% include 'messaging/_message_list.html' %}
|
||||
|
||||
{% endblock content %}
|
||||
24
templates/messaging/blacklist_email.html
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h2>Block e-mail address</h2>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
If you don't want to receive e-mail messages to <em>{{ email }}</em> ever again, confirm by
|
||||
clicking the <b>Never email me again</b> button. If anyone tries to use this email address
|
||||
for a sender or recipient, we will silently discard the email.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
You might still receive Happiness Packets that were already sent before you blocked
|
||||
your email address.
|
||||
</p>
|
||||
|
||||
<form method="post" >{% csrf_token %}
|
||||
<input type="submit" name="submit" value="Never email me again" class="btn btn-primary btn-lg centered" id="submit-id-submit">
|
||||
</form>
|
||||
|
||||
{% endblock content %}
|
||||
91
templates/messaging/faq.html
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div id="faq">
|
||||
<div class="page-header">
|
||||
<h2>Frequently Asked Questions</h2>
|
||||
</div>
|
||||
|
||||
<h3>Who made this and why?</h3>
|
||||
<p>
|
||||
The Open-Source Happiness Packets project was created by <a href="https://twitter.com/mxsash">Sasha Romijn</a> and
|
||||
<a href="https://twitter.com/thatdocslady">Mikey Ariel</a> in March 2016.
|
||||
The idea came about while we were building our
|
||||
<a href="https://2016.djangocon.eu/speakers/13">Healthy Minds in a Healthy Community</a> presentation
|
||||
for Djangocon Europe 2016. One of the issues we wanted to address in the presentation was that many
|
||||
people are unaware of how loved, appreciated, or admired they are by their peers, since our culture seems
|
||||
to discourage positive feedback and amplify negative feedback. With this project, we wanted to provide a platform
|
||||
for people to send positive feedback, thanks, or just a kind word to their peers, with hope to make it
|
||||
easier and more acceptable for people to spread happiness, gratitude and appreciation in open-source communities.
|
||||
</p>
|
||||
|
||||
<h3>Isn't it weird to send these notes to other people?</h3>
|
||||
<p>
|
||||
Many of us come from a culture where it's sometimes more acceptable to complain about the negative than to
|
||||
acknowledge the positive things. Therefore, it might feel a little awkward to communicate positive feedback
|
||||
directly to others. However, in our personal experience, once you take that first step, any awkwardness
|
||||
is quickly replaced by feeling good about helping someone else feel good.
|
||||
</p>
|
||||
|
||||
<h3>Can I send anything I want?</h3>
|
||||
<p>
|
||||
We don't screen the content of messages. However, all messages must meet the
|
||||
<a href="https://www.djangoproject.com/conduct/">Django Project Code of Conduct</a>.
|
||||
Notably, harassment, insults and other exclusionary behavior are never acceptable.
|
||||
</p>
|
||||
<p>
|
||||
Violations of this can result in blocking you from using the service. Your message might also be shared with
|
||||
the Django Code of Conduct committee, who reserve the right to take further action of their own. If you're a member
|
||||
of another open-source community, your message might be shared with any code of conduct committee or similar group
|
||||
from that community.
|
||||
</p>
|
||||
|
||||
<h3>Should I reply when I get a Happiness Packet from someone?</h3>
|
||||
<p>
|
||||
You are under no obligation to respond to the sender of the Happiness Packet. But if you are inspired by what
|
||||
you received, you are welcome to respond or send your own Happiness Packet. We always encourage sending more
|
||||
messages, but only if they are sincere.
|
||||
</p>
|
||||
<p>
|
||||
Note: if the sender selected to remain anonymous, you cannot reply to their message.
|
||||
</p>
|
||||
|
||||
<h3>Are my Happiness Packets private?</h3>
|
||||
<p>
|
||||
By default, we only send your message with the recipient. They will get an e-mail with your message
|
||||
and can view it online. We only share your name and email address with the recipient if you choose this option.
|
||||
We may analyse messages and their metadata for statistical analysis.
|
||||
</p>
|
||||
<p>
|
||||
In case of suspected abuse or Code of Conduct violations, the service administrators might view and read
|
||||
your message to determine further processing.
|
||||
</p>
|
||||
|
||||
<h3>What happens if I choose to display my message publicly?</h3>
|
||||
<p>
|
||||
If both the sender and the recipient of the message agree to publish the message on the website,
|
||||
the message will be displayed in the <a href="{% url 'messaging:archive' %}">Happiness Archive</a>.
|
||||
We encourage you to share your messages with the community,
|
||||
but the choice is yours and you are not obligated to choose this option if you do not feel comfortable with it.
|
||||
You can also choose to publish the message but keep the sender and recipient names private.
|
||||
</p>
|
||||
<p>
|
||||
Note: we cannot modify the content of the message after it is sent, so if the message includes personally-identifying
|
||||
information or references to third parties, they will be published even if you choose to hide the sender and
|
||||
recipient names.
|
||||
</p>
|
||||
|
||||
<h3>I received an abusive message, what should I do?</h3>
|
||||
<p>
|
||||
Please report this to <a href="mailto:info@happinesspackets.io">info@happinesspackets.io</a>, preferably by
|
||||
forwarding the original email that contains the message.
|
||||
</p>
|
||||
|
||||
<h3>I don't want to receive any email from you</h3>
|
||||
<p>
|
||||
Every email we sent includes a link to stop receiving all future e-mail messages. If you follow the link
|
||||
and confirm, your email address will not be able to be used anywhere on the site.
|
||||
Note: if you select to block your email address, you will not be able to send Happiness Packets yourself.
|
||||
</p>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
43
templates/messaging/inspiration.html
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h2>Get inspired!</h2>
|
||||
</div>
|
||||
|
||||
<em>
|
||||
Want to send some happiness but having a writer's block? Check out some of these sample messages
|
||||
for inspiration. These are not actual messages that were sent with the system, just some ideas that
|
||||
you can use. Our <a href="{% url 'messaging:archive' %}">Happiness Archive</a> contains more messages from
|
||||
others that may help inspire you.
|
||||
</em>
|
||||
|
||||
<h4>This message was sent to the Django: Under the Hood team</h4>
|
||||
<blockquote>
|
||||
<p>
|
||||
I feel totally overwhelmed, surprised and very, very grateful. Thank you for caring. You are unbelievable.
|
||||
You are a bunch of craziest, the most positive people I've met. You inspire me to give back to community
|
||||
even more. I wish I could express properly what I'm feeling right now...
|
||||
</p>
|
||||
|
||||
<p>
|
||||
May it always rain stroopwafels on you. But not all the time, that could be inconvenient. Only when you
|
||||
feel like having stroopwafels. Or someone that you like feels like having stroopwafels. Or you just want
|
||||
to make it rain stroopwafels.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Sending hugs, you crazy, amazing people!
|
||||
</p>
|
||||
</blockquote>
|
||||
|
||||
<h4>Another contributed message</h4>
|
||||
<blockquote>
|
||||
Thank you for writing such a great article. I’ve seen some of your other writing and ideas and you seem
|
||||
to capture difficult concepts very well. I’m really happy that you’re part of our community, and aspire
|
||||
to be as great in some of these things as you are some day :)
|
||||
</blockquote>
|
||||
|
||||
|
||||
{% endblock content %}
|
||||
22
templates/messaging/message_recipient_form.html
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h2>You received an Open-Source Happiness Packet!</h2>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
{% if message.sender_named %}
|
||||
You received a Happiness Packet from {{ message.sender_name }} ({{ message.sender_email }}).
|
||||
{% else %}
|
||||
The sender of this message asked to remain anonymous.
|
||||
{% endif %}
|
||||
Your Happiness Packet contains:
|
||||
</p>
|
||||
|
||||
<blockquote>{{ message.message|linebreaksbr }}</blockquote>
|
||||
|
||||
{% crispy form %}
|
||||
{% endblock content %}
|
||||
11
templates/messaging/message_send_form.html
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h2>Send a happiness packet to someone!</h2>
|
||||
</div>
|
||||
|
||||
{% crispy form %}
|
||||
{% endblock content %}
|
||||
19
templates/messaging/message_sender_confirmation_failed.html
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h2>Link not valid</h2>
|
||||
</div>
|
||||
|
||||
{% if not_found %}
|
||||
<div class="alert alert-danger">
|
||||
We couldn't find this message. Make sure that the URL is complete.
|
||||
</div>
|
||||
{% elif already_confirmed %}
|
||||
<div class="alert alert-info">
|
||||
You already confirmed this message.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock content %}
|
||||
13
templates/messaging/message_sender_confirmation_sent.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h2>Check your email</h2>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
We sent you a confirmation link to your email address. Follow the link to finalize sending your message.
|
||||
</p>
|
||||
|
||||
{% endblock content %}
|
||||
13
templates/messaging/message_sender_confirmed.html
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="page-header">
|
||||
<h2>Happiness Packet sent</h2>
|
||||
</div>
|
||||
|
||||
<div class="alert alert-success">
|
||||
Your Happiness Packet is on the way to the recipient. Have a happy day!
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||